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

            Line data    Source code
       1              : // Unit tests for the shared `semantic::FrameStack` primitive.
       2              : //
       3              : // `FrameStack` is the foundation shared between the script driver
       4              : // (BEGIN..END variables) and the UDF / TVF invocation surface
       5              : // (argument bindings). Tests pin the frame semantics callers
       6              : // depend on: push/pop, innermost-binding wins, redeclaration in
       7              : // the same frame is rejected, redeclaration in a nested frame is
       8              : // allowed, and case-insensitive identifier matching.
       9              : //
      10              : // The script-statement / UDF-statement tests assert the
      11              : // `kAlreadyExists` / `kNotFound` error surfaces translate into the
      12              : // matching BigQuery REST envelope on top of this primitive's
      13              : // `absl::Status` codes.
      14              : 
      15              : #include "backend/engine/semantic/frame_stack.h"
      16              : 
      17              : #include "absl/status/status.h"
      18              : #include "backend/engine/semantic/value.h"
      19              : #include "googlesql/public/value.h"
      20              : #include "gtest/gtest.h"
      21              : 
      22              : namespace bigquery_emulator {
      23              : namespace backend {
      24              : namespace engine {
      25              : namespace semantic {
      26              : namespace {
      27              : 
      28            1 : TEST(FrameStackTest, NewStackHasOuterFrame) {
      29            1 :   FrameStack stack;
      30            1 :   EXPECT_EQ(stack.frame_count(), 1u);
      31            1 :   EXPECT_FALSE(stack.Has("x"));
      32            1 : }
      33              : 
      34            1 : TEST(FrameStackTest, DeclareAndLookupRoundTrips) {
      35            1 :   FrameStack stack;
      36            1 :   ASSERT_TRUE(stack.Declare("x", Value::Int64(42)).ok());
      37            1 :   ASSERT_TRUE(stack.Has("x"));
      38            1 :   auto got = stack.Lookup("x");
      39            2 :   ASSERT_TRUE(got.ok()) << got.status();
      40            1 :   EXPECT_EQ(got->int64_value(), 42);
      41            1 : }
      42              : 
      43            1 : TEST(FrameStackTest, IdentifierMatchIsCaseInsensitive) {
      44            1 :   FrameStack stack;
      45            1 :   ASSERT_TRUE(stack.Declare("FooBar", Value::Int64(1)).ok());
      46            1 :   EXPECT_TRUE(stack.Has("foobar"));
      47            1 :   EXPECT_TRUE(stack.Has("FOOBAR"));
      48            1 :   auto got = stack.Lookup("foobar");
      49            1 :   ASSERT_TRUE(got.ok());
      50            1 :   EXPECT_EQ(got->int64_value(), 1);
      51            1 :   ASSERT_TRUE(stack.Set("FOOBAR", Value::Int64(2)).ok());
      52            1 :   got = stack.Lookup("FooBar");
      53            1 :   ASSERT_TRUE(got.ok());
      54            1 :   EXPECT_EQ(got->int64_value(), 2);
      55            1 : }
      56              : 
      57            1 : TEST(FrameStackTest, RedeclareSameFrameRejected) {
      58            1 :   FrameStack stack;
      59            1 :   ASSERT_TRUE(stack.Declare("x", Value::Int64(1)).ok());
      60            1 :   auto status = stack.Declare("x", Value::Int64(2));
      61            2 :   EXPECT_EQ(status.code(), absl::StatusCode::kAlreadyExists) << status;
      62            1 : }
      63              : 
      64            1 : TEST(FrameStackTest, SetWithoutDeclareReturnsNotFound) {
      65            1 :   FrameStack stack;
      66            1 :   auto status = stack.Set("missing", Value::Int64(0));
      67            2 :   EXPECT_EQ(status.code(), absl::StatusCode::kNotFound) << status;
      68            1 : }
      69              : 
      70            1 : TEST(FrameStackTest, LookupMissingReturnsNotFound) {
      71            1 :   FrameStack stack;
      72            1 :   auto got = stack.Lookup("missing");
      73            1 :   ASSERT_FALSE(got.ok());
      74            1 :   EXPECT_EQ(got.status().code(), absl::StatusCode::kNotFound);
      75            1 : }
      76              : 
      77            1 : TEST(FrameStackTest, NestedFrameInnerBindingWins) {
      78            1 :   FrameStack stack;
      79            1 :   ASSERT_TRUE(stack.Declare("x", Value::Int64(1)).ok());
      80            1 :   stack.PushFrame();
      81            1 :   EXPECT_EQ(stack.frame_count(), 2u);
      82            1 :   ASSERT_TRUE(stack.Declare("x", Value::Int64(2)).ok());
      83            1 :   auto got = stack.Lookup("x");
      84            1 :   ASSERT_TRUE(got.ok());
      85            1 :   EXPECT_EQ(got->int64_value(), 2);
      86            1 :   ASSERT_TRUE(stack.PopFrame().ok());
      87            1 :   EXPECT_EQ(stack.frame_count(), 1u);
      88            1 :   got = stack.Lookup("x");
      89            1 :   ASSERT_TRUE(got.ok());
      90            1 :   EXPECT_EQ(got->int64_value(), 1);
      91            1 : }
      92              : 
      93            1 : TEST(FrameStackTest, SetUpdatesInnermostBinding) {
      94            1 :   FrameStack stack;
      95            1 :   ASSERT_TRUE(stack.Declare("x", Value::Int64(1)).ok());
      96            1 :   stack.PushFrame();
      97            1 :   ASSERT_TRUE(stack.Declare("x", Value::Int64(2)).ok());
      98            1 :   ASSERT_TRUE(stack.Set("x", Value::Int64(20)).ok());
      99            1 :   auto inner = stack.Lookup("x");
     100            1 :   ASSERT_TRUE(inner.ok());
     101            1 :   EXPECT_EQ(inner->int64_value(), 20);
     102            1 :   ASSERT_TRUE(stack.PopFrame().ok());
     103              :   // The outer frame's binding is unchanged: `Set` updated only the
     104              :   // innermost binding, not every frame's copy.
     105            1 :   auto outer = stack.Lookup("x");
     106            1 :   ASSERT_TRUE(outer.ok());
     107            1 :   EXPECT_EQ(outer->int64_value(), 1);
     108            1 : }
     109              : 
     110            1 : TEST(FrameStackTest, SetReachesOuterFrame) {
     111            1 :   FrameStack stack;
     112            1 :   ASSERT_TRUE(stack.Declare("x", Value::Int64(1)).ok());
     113            1 :   stack.PushFrame();
     114              :   // Inner frame has no `x` binding; `Set` walks up and finds the
     115              :   // outer frame's binding.
     116            1 :   ASSERT_TRUE(stack.Set("x", Value::Int64(99)).ok());
     117            1 :   ASSERT_TRUE(stack.PopFrame().ok());
     118            1 :   auto got = stack.Lookup("x");
     119            1 :   ASSERT_TRUE(got.ok());
     120            1 :   EXPECT_EQ(got->int64_value(), 99);
     121            1 : }
     122              : 
     123            1 : TEST(FrameStackTest, PopOuterFrameRejected) {
     124            1 :   FrameStack stack;
     125            1 :   auto status = stack.PopFrame();
     126            2 :   EXPECT_EQ(status.code(), absl::StatusCode::kFailedPrecondition) << status;
     127            1 : }
     128              : 
     129              : }  // namespace
     130              : }  // namespace semantic
     131              : }  // namespace engine
     132              : }  // namespace backend
     133              : }  // namespace bigquery_emulator
        

Generated by: LCOV version 2.0-1