Line data Source code
1 : // Unit tests for the BigQuery conditional polyfill macros.
2 : //
3 : // Each test drives the macro directly against an in-process DuckDB
4 : // connection and exercises both the common path and the
5 : // BigQuery-specific edge case the wrapper exists to pin.
6 :
7 : #include <cstdint>
8 : #include <string>
9 :
10 : #include "absl/status/status.h"
11 : #include "backend/engine/duckdb/udf/registrar.h"
12 : #include "duckdb.h"
13 : #include "gtest/gtest.h"
14 :
15 : namespace bigquery_emulator {
16 : namespace backend {
17 : namespace engine {
18 : namespace duckdb {
19 : namespace udf {
20 : namespace {
21 :
22 : class ConditionalMacrosTest : public ::testing::Test {
23 : protected:
24 4 : void SetUp() override {
25 4 : ASSERT_EQ(::duckdb_open(nullptr, &db_), ::DuckDBSuccess);
26 4 : ASSERT_EQ(::duckdb_connect(db_, &conn_), ::DuckDBSuccess);
27 4 : absl::Status reg = RegisterAll(conn_);
28 8 : ASSERT_TRUE(reg.ok()) << reg;
29 4 : }
30 :
31 4 : void TearDown() override {
32 4 : if (conn_ != nullptr) ::duckdb_disconnect(&conn_);
33 4 : if (db_ != nullptr) ::duckdb_close(&db_);
34 4 : }
35 :
36 3 : int64_t RunInt64(const std::string& sql) {
37 3 : ::duckdb_result result;
38 3 : auto rc = ::duckdb_query(conn_, sql.c_str(), &result);
39 6 : EXPECT_EQ(rc, ::DuckDBSuccess) << "DuckDB rejected: "
40 6 : << (::duckdb_result_error(&result) == nullptr
41 6 : ? "(no error)"
42 6 : : ::duckdb_result_error(&result))
43 6 : << " (sql=" << sql << ")";
44 3 : int64_t v = ::duckdb_value_int64(&result, 0, 0);
45 3 : ::duckdb_destroy_result(&result);
46 3 : return v;
47 3 : }
48 :
49 2 : bool RunIsNull(const std::string& sql) {
50 2 : ::duckdb_result result;
51 2 : auto rc = ::duckdb_query(conn_, sql.c_str(), &result);
52 4 : EXPECT_EQ(rc, ::DuckDBSuccess) << "DuckDB rejected: " << sql;
53 2 : bool v = ::duckdb_value_is_null(&result, 0, 0);
54 2 : ::duckdb_destroy_result(&result);
55 2 : return v;
56 2 : }
57 :
58 : ::duckdb_database db_ = nullptr;
59 : ::duckdb_connection conn_ = nullptr;
60 : };
61 :
62 : // --- bq_if -------------------------------------------------------
63 :
64 1 : TEST_F(ConditionalMacrosTest, IfTrueReturnsThen) {
65 1 : EXPECT_EQ(RunInt64("SELECT bq_if(TRUE, 1, 2)"), 1);
66 1 : }
67 :
68 1 : TEST_F(ConditionalMacrosTest, IfFalseReturnsElse) {
69 1 : EXPECT_EQ(RunInt64("SELECT bq_if(FALSE, 1, 2)"), 2);
70 1 : }
71 :
72 1 : TEST_F(ConditionalMacrosTest, IfNullCondFallsThroughToElse) {
73 : // BigQuery edge case pinned: a NULL condition does NOT select the
74 : // THEN branch; it falls through to ELSE. A regression that
75 : // mapped IF to `CASE cond WHEN TRUE THEN ... END` (BOOLEAN
76 : // equality semantics) would surface here as NULL.
77 1 : EXPECT_EQ(RunInt64("SELECT bq_if(NULL::BOOLEAN, 1, 2)"), 2);
78 1 : }
79 :
80 1 : TEST_F(ConditionalMacrosTest, IfPreservesNullResults) {
81 : // The THEN / ELSE arms preserve NULL when chosen.
82 1 : EXPECT_TRUE(RunIsNull("SELECT bq_if(TRUE, NULL::BIGINT, 2)"));
83 1 : EXPECT_TRUE(RunIsNull("SELECT bq_if(FALSE, 1, NULL::BIGINT)"));
84 1 : }
85 :
86 : } // namespace
87 : } // namespace udf
88 : } // namespace duckdb
89 : } // namespace engine
90 : } // namespace backend
91 : } // namespace bigquery_emulator
|