LCOV - code coverage report
Current view: top level - backend/engine/semantic - eval_expr_test.cc (source / functions) Coverage Total Hit
Test: _coverage_report.dat Lines: 100.0 % 159 159
Test Date: 2026-07-02 21:01:18 Functions: 100.0 % 22 22

            Line data    Source code
       1              : // Tests for `EvalExpr` (core expression forms).
       2              : 
       3              : #include "backend/engine/semantic/error.h"
       4              : #include "backend/engine/semantic/eval_expr_test_fixture.h"
       5              : #include "backend/engine/semantic/value.h"
       6              : 
       7              : namespace bigquery_emulator {
       8              : namespace backend {
       9              : namespace engine {
      10              : namespace semantic {
      11              : 
      12            1 : TEST_F(EvalExprTest, LiteralInt64) {
      13            1 :   const auto* expr = AnalyzeExpr("42");
      14            1 :   ASSERT_NE(expr, nullptr);
      15            1 :   auto v = EvalExpr(*expr, EvalContext{});
      16            2 :   ASSERT_TRUE(v.ok()) << v.status();
      17            1 :   EXPECT_EQ(v->int64_value(), 42);
      18            1 : }
      19              : 
      20            1 : TEST_F(EvalExprTest, LiteralStringRoundTrips) {
      21            1 :   const auto* expr = AnalyzeExpr("'hello'");
      22            1 :   ASSERT_NE(expr, nullptr);
      23            1 :   auto v = EvalExpr(*expr, EvalContext{});
      24            2 :   ASSERT_TRUE(v.ok()) << v.status();
      25            1 :   EXPECT_EQ(v->string_value(), "hello");
      26            1 : }
      27              : 
      28            1 : TEST_F(EvalExprTest, AdditionInt64) {
      29            1 :   const auto* expr = AnalyzeExpr("1 + 2");
      30            1 :   ASSERT_NE(expr, nullptr);
      31            1 :   auto v = EvalExpr(*expr, EvalContext{});
      32            2 :   ASSERT_TRUE(v.ok()) << v.status();
      33            1 :   EXPECT_EQ(v->int64_value(), 3);
      34            1 : }
      35              : 
      36            1 : TEST_F(EvalExprTest, AdditionNullOperandIsNull) {
      37            1 :   const auto* expr = AnalyzeExpr("CAST(NULL AS INT64) + 1");
      38            1 :   ASSERT_NE(expr, nullptr);
      39            1 :   auto v = EvalExpr(*expr, EvalContext{});
      40            2 :   ASSERT_TRUE(v.ok()) << v.status();
      41            1 :   EXPECT_TRUE(v->is_null());
      42            1 : }
      43              : 
      44            1 : TEST_F(EvalExprTest, Int64OverflowSurfacesAsSemanticError) {
      45            1 :   const auto* expr = AnalyzeExpr("9223372036854775807 + 1");
      46            1 :   ASSERT_NE(expr, nullptr);
      47            1 :   auto v = EvalExpr(*expr, EvalContext{});
      48            1 :   ASSERT_FALSE(v.ok());
      49            1 :   EXPECT_EQ(GetSemanticErrorReason(v.status()), SemanticErrorReason::kOverflow);
      50            1 : }
      51              : 
      52            1 : TEST_F(EvalExprTest, DivisionByZeroFloat64SurfacesReason) {
      53            1 :   const auto* expr = AnalyzeExpr("CAST(1 AS FLOAT64) / 0");
      54            1 :   ASSERT_NE(expr, nullptr);
      55            1 :   auto v = EvalExpr(*expr, EvalContext{});
      56            1 :   ASSERT_FALSE(v.ok());
      57            1 :   EXPECT_EQ(GetSemanticErrorReason(v.status()),
      58            1 :             SemanticErrorReason::kDivisionByZero);
      59            1 : }
      60              : 
      61            1 : TEST_F(EvalExprTest, ComparisonLessThan) {
      62            1 :   const auto* expr = AnalyzeExpr("1 < 2");
      63            1 :   ASSERT_NE(expr, nullptr);
      64            1 :   auto v = EvalExpr(*expr, EvalContext{});
      65            2 :   ASSERT_TRUE(v.ok()) << v.status();
      66            1 :   EXPECT_TRUE(v->bool_value());
      67            1 : }
      68              : 
      69            1 : TEST_F(EvalExprTest, ComparisonNullOperandIsNull) {
      70            1 :   const auto* expr = AnalyzeExpr("CAST(NULL AS INT64) = 1");
      71            1 :   ASSERT_NE(expr, nullptr);
      72            1 :   auto v = EvalExpr(*expr, EvalContext{});
      73            2 :   ASSERT_TRUE(v.ok()) << v.status();
      74            1 :   EXPECT_TRUE(v->is_null());
      75            1 : }
      76              : 
      77            1 : TEST_F(EvalExprTest, LogicalAndShortCircuitOnFalse) {
      78            1 :   const auto* expr = AnalyzeExpr("FALSE AND CAST(NULL AS BOOL)");
      79            1 :   ASSERT_NE(expr, nullptr);
      80            1 :   auto v = EvalExpr(*expr, EvalContext{});
      81            2 :   ASSERT_TRUE(v.ok()) << v.status();
      82            1 :   EXPECT_FALSE(v->bool_value());
      83            1 : }
      84              : 
      85            1 : TEST_F(EvalExprTest, LogicalOrShortCircuitOnTrue) {
      86            1 :   const auto* expr = AnalyzeExpr("TRUE OR CAST(NULL AS BOOL)");
      87            1 :   ASSERT_NE(expr, nullptr);
      88            1 :   auto v = EvalExpr(*expr, EvalContext{});
      89            2 :   ASSERT_TRUE(v.ok()) << v.status();
      90            1 :   EXPECT_TRUE(v->bool_value());
      91            1 : }
      92              : 
      93            1 : TEST_F(EvalExprTest, IfReturnsThenBranchOnTrue) {
      94            1 :   const auto* expr = AnalyzeExpr("IF(1 < 2, 'yes', 'no')");
      95            1 :   ASSERT_NE(expr, nullptr);
      96            1 :   auto v = EvalExpr(*expr, EvalContext{});
      97            2 :   ASSERT_TRUE(v.ok()) << v.status();
      98            1 :   EXPECT_EQ(v->string_value(), "yes");
      99            1 : }
     100              : 
     101            1 : TEST_F(EvalExprTest, IfReturnsElseBranchOnFalse) {
     102            1 :   const auto* expr = AnalyzeExpr("IF(1 > 2, 'yes', 'no')");
     103            1 :   ASSERT_NE(expr, nullptr);
     104            1 :   auto v = EvalExpr(*expr, EvalContext{});
     105            2 :   ASSERT_TRUE(v.ok()) << v.status();
     106            1 :   EXPECT_EQ(v->string_value(), "no");
     107            1 : }
     108              : 
     109            1 : TEST_F(EvalExprTest, CoalescePicksFirstNonNull) {
     110            1 :   const auto* expr = AnalyzeExpr("COALESCE(CAST(NULL AS INT64), 2, 3)");
     111            1 :   ASSERT_NE(expr, nullptr);
     112            1 :   auto v = EvalExpr(*expr, EvalContext{});
     113            2 :   ASSERT_TRUE(v.ok()) << v.status();
     114            1 :   EXPECT_EQ(v->int64_value(), 2);
     115            1 : }
     116              : 
     117            1 : TEST_F(EvalExprTest, CoalesceAllNullProducesNull) {
     118            1 :   const auto* expr =
     119            1 :       AnalyzeExpr("COALESCE(CAST(NULL AS INT64), CAST(NULL AS INT64))");
     120            1 :   ASSERT_NE(expr, nullptr);
     121            1 :   auto v = EvalExpr(*expr, EvalContext{});
     122            2 :   ASSERT_TRUE(v.ok()) << v.status();
     123            1 :   EXPECT_TRUE(v->is_null());
     124            1 : }
     125              : 
     126            1 : TEST_F(EvalExprTest, IfNullReturnsFallbackOnNull) {
     127            1 :   const auto* expr = AnalyzeExpr("IFNULL(CAST(NULL AS INT64), 7)");
     128            1 :   ASSERT_NE(expr, nullptr);
     129            1 :   auto v = EvalExpr(*expr, EvalContext{});
     130            2 :   ASSERT_TRUE(v.ok()) << v.status();
     131            1 :   EXPECT_EQ(v->int64_value(), 7);
     132            1 : }
     133              : 
     134            1 : TEST_F(EvalExprTest, NullIfReturnsNullWhenEqual) {
     135            1 :   const auto* expr = AnalyzeExpr("NULLIF(1, 1)");
     136            1 :   ASSERT_NE(expr, nullptr);
     137            1 :   auto v = EvalExpr(*expr, EvalContext{});
     138            2 :   ASSERT_TRUE(v.ok()) << v.status();
     139            1 :   EXPECT_TRUE(v->is_null());
     140            1 : }
     141              : 
     142            1 : TEST_F(EvalExprTest, NullIfReturnsFirstWhenDifferent) {
     143            1 :   const auto* expr = AnalyzeExpr("NULLIF(1, 2)");
     144            1 :   ASSERT_NE(expr, nullptr);
     145            1 :   auto v = EvalExpr(*expr, EvalContext{});
     146            2 :   ASSERT_TRUE(v.ok()) << v.status();
     147            1 :   EXPECT_EQ(v->int64_value(), 1);
     148            1 : }
     149              : 
     150            1 : TEST_F(EvalExprTest, CaseWhenBranchesEvaluate) {
     151            1 :   const auto* expr =
     152            1 :       AnalyzeExpr("CASE WHEN 1 = 1 THEN 'a' WHEN 2 = 2 THEN 'b' ELSE 'c' END");
     153            1 :   ASSERT_NE(expr, nullptr);
     154            1 :   auto v = EvalExpr(*expr, EvalContext{});
     155            2 :   ASSERT_TRUE(v.ok()) << v.status();
     156            1 :   EXPECT_EQ(v->string_value(), "a");
     157            1 : }
     158              : 
     159            1 : TEST_F(EvalExprTest, CaseWithValueBranchesEvaluate) {
     160            1 :   const auto* expr =
     161            1 :       AnalyzeExpr("CASE 2 WHEN 1 THEN 'a' WHEN 2 THEN 'b' ELSE 'c' END");
     162            1 :   ASSERT_NE(expr, nullptr);
     163            1 :   auto v = EvalExpr(*expr, EvalContext{});
     164            2 :   ASSERT_TRUE(v.ok()) << v.status();
     165            1 :   EXPECT_EQ(v->string_value(), "b");
     166            1 : }
     167              : 
     168            1 : TEST_F(EvalExprTest, CaseFallsThroughToElseOnNoMatch) {
     169            1 :   const auto* expr =
     170            1 :       AnalyzeExpr("CASE WHEN 1 = 2 THEN 'a' WHEN 1 = 3 THEN 'b' ELSE 'c' END");
     171            1 :   ASSERT_NE(expr, nullptr);
     172            1 :   auto v = EvalExpr(*expr, EvalContext{});
     173            2 :   ASSERT_TRUE(v.ok()) << v.status();
     174            1 :   EXPECT_EQ(v->string_value(), "c");
     175            1 : }
     176              : 
     177            1 : TEST_F(EvalExprTest, SafeAddOverflowProducesNull) {
     178            1 :   const auto* expr = AnalyzeExpr("SAFE_ADD(9223372036854775807, 1)");
     179            1 :   ASSERT_NE(expr, nullptr);
     180            1 :   auto v = EvalExpr(*expr, EvalContext{});
     181            2 :   ASSERT_TRUE(v.ok()) << v.status();
     182            1 :   EXPECT_TRUE(v->is_null());
     183            1 : }
     184              : 
     185            1 : TEST_F(EvalExprTest, SafeDivideByZeroProducesNull) {
     186            1 :   const auto* expr = AnalyzeExpr("SAFE_DIVIDE(1, 0)");
     187            1 :   ASSERT_NE(expr, nullptr);
     188            1 :   auto v = EvalExpr(*expr, EvalContext{});
     189            2 :   ASSERT_TRUE(v.ok()) << v.status();
     190            1 :   EXPECT_TRUE(v->is_null());
     191            1 : }
     192              : 
     193              : }  // namespace semantic
     194              : }  // namespace engine
     195              : }  // namespace backend
     196              : }  // namespace bigquery_emulator
        

Generated by: LCOV version 2.0-1