While CEL doesn't provide execution order guarantees per se, short circuiting operators are treated specially to evaluate to user expectations. These behaviors aren't easily observable since the flat expression doesn't expose any details about the program after building, so a lot of setup is needed to simulate what the expression builder does.
| 102 | // expose any details about the program after building, so a lot of setup is |
| 103 | // needed to simulate what the expression builder does. |
| 104 | TEST_F(UpdatedConstantFoldingTest, SkipsTernary) { |
| 105 | // Arrange |
| 106 | ASSERT_OK_AND_ASSIGN(std::unique_ptr<cel::Ast> ast, |
| 107 | ParseFromCel("true ? true : false")); |
| 108 | |
| 109 | const Expr& call = ast->root_expr(); |
| 110 | const Expr& condition = call.call_expr().args()[0]; |
| 111 | const Expr& true_branch = call.call_expr().args()[1]; |
| 112 | const Expr& false_branch = call.call_expr().args()[2]; |
| 113 | |
| 114 | ProgramBuilder program_builder; |
| 115 | program_builder.EnterSubexpression(&call); |
| 116 | // condition |
| 117 | program_builder.EnterSubexpression(&condition); |
| 118 | ASSERT_OK_AND_ASSIGN(auto step, |
| 119 | CreateConstValueStep(cel::BoolValue(true), -1)); |
| 120 | program_builder.AddStep(std::move(step)); |
| 121 | program_builder.ExitSubexpression(&condition); |
| 122 | |
| 123 | // true |
| 124 | program_builder.EnterSubexpression(&true_branch); |
| 125 | ASSERT_OK_AND_ASSIGN(step, CreateConstValueStep(cel::BoolValue(true), -1)); |
| 126 | program_builder.AddStep(std::move(step)); |
| 127 | program_builder.ExitSubexpression(&true_branch); |
| 128 | |
| 129 | // false |
| 130 | program_builder.EnterSubexpression(&false_branch); |
| 131 | ASSERT_OK_AND_ASSIGN(step, CreateConstValueStep(cel::BoolValue(true), -1)); |
| 132 | program_builder.AddStep(std::move(step)); |
| 133 | program_builder.ExitSubexpression(&false_branch); |
| 134 | |
| 135 | // ternary. |
| 136 | ASSERT_OK_AND_ASSIGN(step, CreateConstValueStep(cel::NullValue(), -1)); |
| 137 | program_builder.AddStep(std::move(step)); |
| 138 | program_builder.ExitSubexpression(&call); |
| 139 | |
| 140 | std::shared_ptr<google::protobuf::Arena> arena; |
| 141 | PlannerContext context(env_, resolver_, options_, |
| 142 | type_registry_.GetComposedTypeProvider(), |
| 143 | issue_collector_, program_builder, arena); |
| 144 | |
| 145 | ProgramOptimizerFactory constant_folder_factory = |
| 146 | CreateConstantFoldingOptimizer(); |
| 147 | |
| 148 | // Act |
| 149 | // Issue the visitation calls. |
| 150 | ASSERT_OK_AND_ASSIGN(std::unique_ptr<ProgramOptimizer> constant_folder, |
| 151 | constant_folder_factory(context, *ast)); |
| 152 | ASSERT_OK(constant_folder->OnPreVisit(context, call)); |
| 153 | ASSERT_OK(constant_folder->OnPreVisit(context, condition)); |
| 154 | ASSERT_OK(constant_folder->OnPostVisit(context, condition)); |
| 155 | ASSERT_OK(constant_folder->OnPreVisit(context, true_branch)); |
| 156 | ASSERT_OK(constant_folder->OnPostVisit(context, true_branch)); |
| 157 | ASSERT_OK(constant_folder->OnPreVisit(context, false_branch)); |
| 158 | ASSERT_OK(constant_folder->OnPostVisit(context, false_branch)); |
| 159 | ASSERT_OK(constant_folder->OnPostVisit(context, call)); |
| 160 | |
| 161 | // Assert |
nothing calls this directly
no test coverage detected