diff --git a/policy/BUILD b/policy/BUILD index 6a204d07c..9b7fe4202 100644 --- a/policy/BUILD +++ b/policy/BUILD @@ -225,7 +225,6 @@ cc_test( cc_library( name = "test_util", - testonly = True, srcs = ["test_util.cc"], hdrs = ["test_util.h"], copts = ["-fexceptions"], diff --git a/policy/test_util.cc b/policy/test_util.cc index 9fe1e43d1..a567e3862 100644 --- a/policy/test_util.cc +++ b/policy/test_util.cc @@ -10,9 +10,9 @@ #include "policy/test_util.h" #include +#include #include #include -#include #include "cel/expr/eval.pb.h" #include "cel/expr/value.pb.h" @@ -131,6 +131,73 @@ absl::Status ParseTestOutput(const YAML::Node& node, return YamlToExprValue(node, output->mutable_result_value()); } +absl::Status ParseTestCaseNode( + const YAML::Node& test_node, + cel::expr::conformance::test::TestCase* test_case) { + if (test_node.IsNull()) { + return absl::OkStatus(); + } + if (!test_node.IsMap()) { + return absl::InvalidArgumentError("Test case must be a YAML mapping"); + } + if (test_node["name"].IsDefined()) { + test_case->set_name(test_node["name"].as()); + } + if (test_node["description"].IsDefined()) { + test_case->set_description(test_node["description"].as()); + } + if (test_node["expr"].IsDefined()) { + test_case->set_expr(test_node["expr"].as()); + } + if (test_node["context_expr"].IsDefined()) { + test_case->mutable_input_context()->set_context_expr( + test_node["context_expr"].as()); + } else if (test_node["input_context"].IsDefined() && + test_node["input_context"].IsMap() && + test_node["input_context"]["context_expr"].IsDefined()) { + test_case->mutable_input_context()->set_context_expr( + test_node["input_context"]["context_expr"].as()); + } + if (test_node["disable_check"].IsDefined()) { + test_case->set_disable_check(test_node["disable_check"].as()); + } + + YAML::Node input_node = test_node["input"]; + if (input_node.IsDefined() && input_node.IsMap()) { + auto* input_map = test_case->mutable_input(); + for (auto it = input_node.begin(); it != input_node.end(); ++it) { + std::string var_name = it->first.as(); + cel::expr::conformance::test::InputValue input_val; + CEL_RETURN_IF_ERROR(ParseInputValue(it->second, &input_val)); + (*input_map)[var_name] = std::move(input_val); + } + } + + YAML::Node output_node = test_node["output"]; + if (output_node.IsDefined()) { + CEL_RETURN_IF_ERROR( + ParseTestOutput(output_node, test_case->mutable_output())); + } + return absl::OkStatus(); +} + +absl::StatusOr ParseTestCaseYamlImpl( + absl::string_view yaml_content) { + if (yaml_content.empty()) { + return cel::expr::conformance::test::TestCase(); + } + YAML::Node test_node; + try { + test_node = YAML::Load(std::string(yaml_content)); + } catch (const std::exception& e) { + return absl::InvalidArgumentError( + absl::StrCat("Failed to parse YAML: ", e.what())); + } + cel::expr::conformance::test::TestCase test_case; + CEL_RETURN_IF_ERROR(ParseTestCaseNode(test_node, &test_case)); + return test_case; +} + absl::StatusOr ParsePolicyTestSuiteYamlImpl(absl::string_view yaml_content) { YAML::Node tests_node; @@ -174,33 +241,7 @@ ParsePolicyTestSuiteYamlImpl(absl::string_view yaml_content) { for (const auto& test_node : tests) { auto* test_case = section->add_tests(); - if (test_node["name"].IsDefined()) { - test_case->set_name(test_node["name"].as()); - } - if (test_node["description"].IsDefined()) { - test_case->set_description(test_node["description"].as()); - } - if (test_node["context_expr"].IsDefined()) { - test_case->mutable_input_context()->set_context_expr( - test_node["context_expr"].as()); - } - - YAML::Node input_node = test_node["input"]; - if (input_node.IsDefined() && input_node.IsMap()) { - auto* input_map = test_case->mutable_input(); - for (auto it = input_node.begin(); it != input_node.end(); ++it) { - std::string var_name = it->first.as(); - cel::expr::conformance::test::InputValue input_val; - CEL_RETURN_IF_ERROR(ParseInputValue(it->second, &input_val)); - (*input_map)[var_name] = std::move(input_val); - } - } - - YAML::Node output_node = test_node["output"]; - if (output_node.IsDefined()) { - CEL_RETURN_IF_ERROR( - ParseTestOutput(output_node, test_case->mutable_output())); - } + CEL_RETURN_IF_ERROR(ParseTestCaseNode(test_node, test_case)); } } @@ -218,4 +259,16 @@ ParsePolicyTestSuiteYaml(absl::string_view yaml_content) { } } +absl::StatusOr ParseTestCaseYaml( + absl::string_view yaml_content) { + try { + return ParseTestCaseYamlImpl(yaml_content); + } catch (const std::exception& e) { + return absl::InvalidArgumentError( + absl::StrCat("Failed to parse YAML: ", e.what())); + } catch (...) { + return absl::InvalidArgumentError("Failed to parse YAML"); + } +} + } // namespace cel::test diff --git a/policy/test_util.h b/policy/test_util.h index 5fe306050..c917a2581 100644 --- a/policy/test_util.h +++ b/policy/test_util.h @@ -28,6 +28,11 @@ namespace cel::test { absl::StatusOr ParsePolicyTestSuiteYaml(absl::string_view yaml_content); +// Parses a YAML string representing an individual test case and adapts it to +// the cel.expr.conformance.test.TestCase protobuf message. +absl::StatusOr ParseTestCaseYaml( + absl::string_view yaml_content); + } // namespace cel::test #endif // THIRD_PARTY_CEL_CPP_POLICY_TEST_UTIL_H_