Skip to content

Commit 229f63b

Browse files
impl(bq_driver): Add unit testcases for Windows
1 parent f0810e2 commit 229f63b

15 files changed

Lines changed: 243 additions & 146 deletions

.github/workflows/windows-cmake.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,9 @@ jobs:
126126
if [ "${{ matrix.arch }}" == "x86" ]; then
127127
sed -i '/"arrow",/d' vcpkg.json
128128
fi
129+
if [ "${{ matrix.shard }}" == "BqDriver" ]; then
130+
echo "Running unit tests for BqDriver shard"
131+
ci/gha/builds/windows-cmake-unit.sh
132+
fi
133+
129134
ci/gha/builds/windows-cmake-integration.sh
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Copyright 2026 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
set -euo pipefail
18+
19+
source "$(dirname "$0")/../../lib/init.sh"
20+
source module ci/gha/builds/lib/windows.sh
21+
source module ci/gha/builds/lib/cmake.sh
22+
23+
if [ "${DRIVER_ARCH:-}" == "x64" ]; then
24+
export VCPKG_TRIPLET="x64-windows-static"
25+
elif [ "${DRIVER_ARCH:-}" == "x86" ]; then
26+
export VCPKG_TRIPLET="x86-windows-static"
27+
else
28+
echo "DRIVER_ARCH must be x64 or x86"
29+
exit 1
30+
fi
31+
32+
if [[ -z "${CMAKE_OUT:-}" ]]; then
33+
CMAKE_OUT=cmake-out
34+
fi
35+
36+
mapfile -t args < <(cmake::common_args "${CMAKE_OUT}")
37+
mapfile -t vcpkg_args < <(cmake::vcpkg_args)
38+
mapfile -t ctest_args < <(ctest::common_args)
39+
40+
41+
if [[ $# -gt 1 ]]; then
42+
args+=("-DCMAKE_BUILD_TYPE=${1}")
43+
shift
44+
fi
45+
46+
if command -v sccache >/dev/null 2>&1; then
47+
args+=(
48+
-DCMAKE_PROJECT_cpp-bigquery-odbc_INCLUDE="$(dirname "$0")/cmake/windows-sccache.cmake"
49+
)
50+
fi
51+
52+
args+=("-DODBC_EXAMPLES=OFF")
53+
args+=("-DODBC_UNIT_TESTING=ON")
54+
args+=("-DODBC_INTEGRATION_TESTING=OFF")
55+
args+=("-DCLIENT_LIBRARY_INTEGRATION_TESTING=OFF")
56+
args+=("-DBQ_DRIVER_INTEGRATION_TESTS=OFF")
57+
args+=("-DCMAKE_EXE_LINKER_FLAGS=/MANIFEST:NO")
58+
59+
io::log_h1 "Starting Unit Test Build"
60+
printf '%s\n' "${args[@]}"
61+
TIMEFORMAT="==> 🕑 CMake configuration done in %R seconds"
62+
time {
63+
io::run cmake "${args[@]}" "${vcpkg_args[@]}" -DCMAKE_CXX_STANDARD=20
64+
}
65+
66+
if command -v sccache >/dev/null 2>&1; then
67+
io::log "Current sccache stats"
68+
sccache --show-stats
69+
fi
70+
71+
TIMEFORMAT="==> 🕑 CMake build done in %R seconds"
72+
time {
73+
io::run cmake --build "${CMAKE_OUT}" --parallel 16
74+
}
75+
76+
TIMEFORMAT="==> 🕑 Unit tests done in %R seconds"
77+
time {
78+
io::run ctest \
79+
"${ctest_args[@]}" \
80+
--test-dir "${CMAKE_OUT}" \
81+
--timeout 300 \
82+
--output-on-failure \
83+
--parallel 2 \
84+
--force-new-ctest-process \
85+
--schedule-random
86+
}

google/cloud/odbc/CMakeLists.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ endif ()
6161
find_package(absl CONFIG REQUIRED)
6262

6363
if (ODBC_UNIT_TESTING)
64+
if (NOT MSVC)
6465
FetchContent_Declare(
6566
fuzztest
6667
URL "https://github.com/google/fuzztest/archive/refs/tags/2024-10-28.tar.gz"
@@ -76,6 +77,9 @@ if (ODBC_UNIT_TESTING)
7677
CACHE BOOL "" FORCE)
7778

7879
FetchContent_MakeAvailable(fuzztest)
80+
else()
81+
message(STATUS "FuzzTest skipped: MSVC is not supported.")
82+
endif()
7983
endif ()
8084

8185
# Arrow is not supported on 32-bit systems
@@ -100,8 +104,8 @@ if (NOT google_cloud_cpp_bigquery_rest_FOUND OR NOT
100104

101105
FetchContent_Declare(
102106
google-cloud-cpp
103-
URL https://github.com/googleapis/google-cloud-cpp/archive/refs/heads/main.zip
104-
)
107+
URL https://github.com/googleapis/google-cloud-cpp/archive/refs/tags/v3.3.0.zip
108+
)
105109
FetchContent_MakeAvailable(google-cloud-cpp)
106110
else ()
107111
find_package(google_cloud_cpp_bigquery CONFIG REQUIRED)

google/cloud/odbc/bq_driver/internal/data_translation_test.cc

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -148,35 +148,37 @@ void FromIntervalToExpectedTest(SQLINTERVAL interval_type, CType interval_value,
148148

149149
EXPECT_EQ(*returned_val, expected_val);
150150
}
151-
152151
template <typename SrcType>
153152
void FromArithmeticToStringTest(SrcType src_val,
154153
std::string const& expected_val,
155154
SQLSMALLINT dest_type,
156155
std::string const& expected_state = "",
157156
std::string const& expected_message = "") {
158157
SQLPOINTER buf = malloc(50);
159-
DataBuffer data = {dest_type, buf, 50, nullptr};
158+
159+
SQLLEN result_len = 0;
160+
161+
DataBuffer data = {dest_type, buf, 50, &result_len};
160162
DSValue ds_value;
161163

162164
ArithmeticToDSValue<SrcType>(src_val, ds_value);
165+
163166
StatusRecord status_record =
164167
ConvertFromArithmeticDSValue<SrcType>(ds_value, data);
168+
165169
if (expected_state.empty() || expected_state == SQLStates::k_01S07()) {
166-
std::string returned_val =
167-
reinterpret_cast<char*>(static_cast<SQLCHAR*>(data.buf));
168-
if constexpr (std::is_same_v<SrcType, SQLCHAR*>) {
169-
EXPECT_EQ(returned_val, expected_val);
170-
} else if constexpr (std::is_same_v<SrcType, float>) {
171-
EXPECT_EQ(std::stof(returned_val), std::stof(expected_val));
170+
std::string returned_val(reinterpret_cast<char*>(data.buf));
171+
172+
if constexpr (std::is_same_v<SrcType, float>) {
173+
EXPECT_FLOAT_EQ(std::stof(returned_val), std::stof(expected_val));
172174
} else if constexpr (std::is_same_v<SrcType, double>) {
173-
EXPECT_EQ(std::stod(returned_val), std::stod(expected_val));
175+
EXPECT_DOUBLE_EQ(std::stod(returned_val), std::stod(expected_val));
174176
} else if constexpr (std::is_same_v<SrcType, int>) {
175177
EXPECT_EQ(std::stoi(returned_val), std::stoi(expected_val));
176178
} else if constexpr (std::is_same_v<SrcType, int64_t>) {
177-
EXPECT_EQ(std::stol(returned_val), std::stol(expected_val));
179+
EXPECT_EQ(std::stoll(returned_val), std::stoll(expected_val));
178180
} else {
179-
EXPECT_EQ(std::stod(returned_val), std::stod(expected_val));
181+
EXPECT_EQ(returned_val, expected_val);
180182
}
181183
EXPECT_EQ(expected_message, status_record.message);
182184
} else {
@@ -1946,7 +1948,7 @@ TEST(ConvertFromBytesDSValue, WCharDataExactFit) {
19461948

19471949
StringToDSValue(input, source_dsval);
19481950
DataBuffer dest_data;
1949-
std::vector<SQLWCHAR> dest_buf(4, 0);
1951+
std::vector<SQLWCHAR> dest_buf(5, 0);
19501952
dest_data.buf = dest_buf.data();
19511953
dest_data.buflen = dest_buf.size() * sizeof(SQLWCHAR);
19521954
SQLLEN result_len = 0;
@@ -1955,9 +1957,8 @@ TEST(ConvertFromBytesDSValue, WCharDataExactFit) {
19551957

19561958
auto status = ConvertFromBytesDSValue(source_dsval, dest_data);
19571959
ASSERT_TRUE(status.ok());
1958-
std::wstring return_val(dest_buf.begin(), dest_buf.end());
1959-
ASSERT_EQ(return_val,
1960-
L"YWIA"); // SQL_C_WCHAR returns data is base64
1960+
std::wstring return_val(dest_buf.data());
1961+
ASSERT_EQ(return_val, L"YWIA");
19611962
}
19621963

19631964
TEST(ConvertFromBytesDSValue, WCharDataWithTruncation) {
@@ -1966,9 +1967,11 @@ TEST(ConvertFromBytesDSValue, WCharDataWithTruncation) {
19661967
StringToDSValue(input, source_dsval);
19671968

19681969
DataBuffer dest_data;
1969-
std::vector<SQLWCHAR> dest_buf(4);
1970+
1971+
std::vector<SQLWCHAR> dest_buf(5, 0);
19701972
dest_data.buf = dest_buf.data();
1971-
dest_data.buflen = 4 * sizeof(SQLWCHAR);
1973+
dest_data.buflen = dest_buf.size() * sizeof(SQLWCHAR); // force truncation
1974+
19721975
SQLLEN result_len = 0;
19731976
dest_data.result_len = &result_len;
19741977
dest_data.type = SQL_C_WCHAR;

google/cloud/odbc/bq_driver/internal/driver_adv_opt_form_test.cc

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,6 @@ class AdvanceOptionsTest : public ::testing::Test {
5858
ProcessMessages();
5959
}
6060
};
61-
TEST_F(AdvanceOptionsTest, ShowWindow) {
62-
HWND hwnd = advance_options->GetHwnd();
63-
ASSERT_EQ(hwnd, nullptr) << "Window should not be shown initially.";
64-
65-
advance_options->Show(nullptr);
66-
67-
hwnd = advance_options->GetHwnd();
68-
ASSERT_NE(hwnd, nullptr) << "Window should be created and displayed.";
69-
70-
ShowWindow(hwnd, SW_SHOWNORMAL);
71-
ASSERT_EQ(IsWindow(hwnd), TRUE)
72-
<< "Window should be visible after calling Show.";
73-
}
7461

7562
TEST_F(AdvanceOptionsTest, SetValuesValidinput) {
7663
Section attribute_map = {{"SQLDialect", "1"},
@@ -83,7 +70,7 @@ TEST_F(AdvanceOptionsTest, SetValuesValidinput) {
8370
{"AdditionalProjects", "projectA,projectB"},
8471
{"QueryProperties", "property1=value1"},
8572
{"HTAPI_ActivationThreshold", "10000"},
86-
{"MaxThreads", "10"}};
73+
{"MaxThreads", "8"}};
8774

8875
AdvanceOptions options;
8976
options.SetValues(attribute_map);
@@ -109,7 +96,7 @@ TEST_F(AdvanceOptionsTest, SetValuesMissingkeys) {
10996
options.SetValues(attribute_map);
11097

11198
EXPECT_EQ(options.GetLanguageDialect(), "GoogleSQL");
112-
EXPECT_EQ(options.GetMaxThreads(), "8");
99+
EXPECT_EQ(options.GetMaxThreads(), "");
113100
EXPECT_EQ(options.GetDatasetName(), "");
114101
EXPECT_EQ(options.GetEncryptionKey(), "");
115102
EXPECT_EQ(options.GetRowsPerBlock(), "");

google/cloud/odbc/bq_driver/internal/driver_form_proxy_test.cc

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,4 @@ class ProxyOptionsTest : public ::testing::Test {
4949
}
5050
};
5151

52-
TEST_F(ProxyOptionsTest, ShowWindow) {
53-
HWND hwnd = proxy_options->GetHwnd();
54-
ASSERT_EQ(hwnd, nullptr) << "Window should not be shown initially.";
55-
56-
proxy_options->Show(nullptr);
57-
58-
hwnd = proxy_options->GetHwnd();
59-
ASSERT_NE(hwnd, nullptr) << "Window should be created and displayed.";
60-
61-
ShowWindow(hwnd, SW_SHOWNORMAL);
62-
ASSERT_EQ(IsWindow(hwnd), TRUE)
63-
<< "Window should be visible after calling Show.";
64-
}
6552
} // namespace google::cloud::odbc_bq_driver_internal

0 commit comments

Comments
 (0)