Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions testing/testrunner/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")

package(
default_testonly = True,
default_visibility = ["//visibility:public"],
)

licenses(["notice"])

cc_library(
name = "cel_test_context",
hdrs = ["cel_test_context.h"],
deps = [
"//compiler",
"//eval/public:cel_expression",
"//runtime",
"@com_google_absl//absl/base:nullability",
"@com_google_absl//absl/memory",
"@com_google_cel_spec//proto/cel/expr:checked_cc_proto",
],
)

cc_library(
name = "runner_lib",
srcs = ["runner_lib.cc"],
hdrs = ["runner_lib.h"],
deps = [
":cel_test_context",
"//common:ast",
"//common:ast_proto",
"//common:value",
"//common/internal:value_conversion",
"//eval/public:activation",
"//eval/public:cel_expression",
"//eval/public:cel_value",
"//eval/public:transform_utility",
"//internal:status_macros",
"//internal:testing_no_main",
"//runtime",
"//runtime:activation",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings:string_view",
"@com_google_cel_spec//proto/cel/expr/conformance/test:suite_cc_proto",
"@com_google_protobuf//:differencer",
"@com_google_protobuf//:protobuf",
],
)

cc_library(
name = "cel_test_factories",
hdrs = ["cel_test_factories.h"],
deps = [
":cel_test_context",
"@com_google_absl//absl/base:no_destructor",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/status:statusor",
"@com_google_cel_spec//proto/cel/expr/conformance/test:suite_cc_proto",
],
)

cc_test(
name = "runner_lib_test",
srcs = ["runner_lib_test.cc"],
deps = [
":cel_test_context",
":runner_lib",
"//checker:type_checker_builder",
"//checker:validation_result",
"//common:ast_proto",
"//common:decl",
"//common:type",
"//compiler",
"//compiler:compiler_factory",
"//compiler:standard_library",
"//eval/public:builtin_func_registrar",
"//eval/public:cel_expr_builder_factory",
"//eval/public:cel_expression",
"//internal:status_macros",
"//internal:testing",
"//internal:testing_descriptor_pool",
"//runtime",
"//runtime:runtime_builder",
"//runtime:standard_runtime_builder_factory",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/status:status_matchers",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings:string_view",
"@com_google_cel_spec//proto/cel/expr/conformance/proto3:test_all_types_cc_proto",
"@com_google_protobuf//:protobuf",
],
)

cc_library(
name = "runner",
srcs = ["runner_bin.cc"],
deps = [
":cel_test_context",
":cel_test_factories",
":runner_lib",
"//internal:testing_no_main",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_cel_spec//proto/cel/expr/conformance/test:suite_cc_proto",
"@com_google_protobuf//:protobuf",
"@com_google_protobuf//src/google/protobuf/io",
],
alwayslink = True,
)
70 changes: 70 additions & 0 deletions testing/testrunner/cel_cc_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Rules for triggering the cc impl of the CEL test runner."""

load("@rules_cc//cc:cc_test.bzl", "cc_test")

def cel_cc_test(
name,
test_suite = "",
filegroup = "",
deps = [],
test_data_path = "",
data = []):
"""trigger the cc impl of the CEL test runner.

This rule will generate a cc_test rule. This rule will be used to trigger
the cc impl of the cel_test rule.

Args:
name: str name for the generated artifact
test_suite: str label of a file containing a test suite. The file should have a
.textproto extension.
filegroup: str label of a filegroup containing the test suite, the config and the checked
expression.
deps: list of dependencies for the cc_test rule.
data: list of data dependencies for the cc_test rule.
test_data_path: absolute path of the directory containing the test files. This is needed only
if the test files are not located in the same directory as the BUILD file.
"""
data, test_data_path = _update_data_with_test_files(data, filegroup, test_data_path, test_suite)
args = []

test_data_path = test_data_path.lstrip("/")

if test_suite != "":
test_suite = test_data_path + "/" + test_suite
args.append("--test_suite_path=" + test_suite)

cc_test(
name = name,
data = data,
args = args,
deps = ["//testing/testrunner:runner"] + deps,
)

def _update_data_with_test_files(data, filegroup, test_data_path, test_suite):
"""Updates the data with the test files."""

if filegroup != "":
data = data + [filegroup]
elif test_data_path != "" and test_data_path != native.package_name():
if test_suite != "":
data = data + [test_data_path + ":" + test_suite]
else:
test_data_path = native.package_name()
if test_suite != "":
data = data + [test_suite]
return data, test_data_path
135 changes: 135 additions & 0 deletions testing/testrunner/cel_test_context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef THIRD_PARTY_CEL_CPP_TOOLS_TESTRUNNER_CEL_TEST_CONTEXT_H_
#define THIRD_PARTY_CEL_CPP_TOOLS_TESTRUNNER_CEL_TEST_CONTEXT_H_

#include <memory>
#include <optional>
#include <utility>

#include "cel/expr/checked.pb.h"
#include "absl/base/nullability.h"
#include "absl/memory/memory.h"
#include "compiler/compiler.h"
#include "eval/public/cel_expression.h"
#include "runtime/runtime.h"

namespace cel::test {

// Struct to hold optional parameters for `CelTestContext`.
struct CelTestContextOptions {
// The primary compiled CEL expression to be evaluated by the test.
std::optional<cel::expr::CheckedExpr> checked_expr;

// An optional CEL compiler. This is only required for test cases where
// input or output values are themselves CEL expressions that need to be
// resolved at runtime.
std::unique_ptr<const cel::Compiler> compiler = nullptr;
};

// The context class for a CEL test, holding configurations needed to evaluate
// compiled CEL expressions.
class CelTestContext {
public:
// Creates a CelTestContext using a `CelExpressionBuilder`.
//
// The `CelExpressionBuilder` helps in setting up the environment for
// building the CEL expression.
//
// Example usage:
//
// CEL_REGISTER_TEST_CONTEXT_FACTORY(
// []() -> absl::StatusOr<std::unique_ptr<CelTestContext>> {
// // SAFE: This setup code now runs when the lambda is invoked at
// runtime,
// // long after all static initializations are complete.
// auto cel_expression_builder =
// google::api::expr::runtime::CreateCelExpressionBuilder();
// CelTestContextOptions options;
// return CelTestContext::CreateFromCelExpressionBuilder(
// std::move(cel_expression_builder), std::move(options));
// });
static std::unique_ptr<CelTestContext> CreateFromCelExpressionBuilder(
std::unique_ptr<google::api::expr::runtime::CelExpressionBuilder>
cel_expression_builder,
CelTestContextOptions options) {
return absl::WrapUnique(new CelTestContext(
std::move(cel_expression_builder), std::move(options)));
}

// Creates a CelTestContext using a `cel::Runtime`.
//
// The `cel::Runtime` is used to evaluate the CEL expression by managing
// the state needed to generate Program.
static std::unique_ptr<CelTestContext> CreateFromRuntime(
std::unique_ptr<const cel::Runtime> runtime,
CelTestContextOptions options) {
return absl::WrapUnique(
new CelTestContext(std::move(runtime), std::move(options)));
}

const cel::Runtime* absl_nullable runtime() const { return runtime_.get(); }

const google::api::expr::runtime::CelExpressionBuilder* absl_nullable
cel_expression_builder() const {
return cel_expression_builder_.get();
}

const cel::Compiler* absl_nullable compiler() const {
return cel_test_context_options_.compiler.get();
}

std::optional<cel::expr::CheckedExpr> checked_expr() const {
return cel_test_context_options_.checked_expr;
}

private:
// Delete copy and move constructors.
CelTestContext(const CelTestContext&) = delete;
CelTestContext& operator=(const CelTestContext&) = delete;
CelTestContext(CelTestContext&&) = delete;
CelTestContext& operator=(CelTestContext&&) = delete;

// Make the constructors private to enforce the use of the factory methods.
CelTestContext(
std::unique_ptr<google::api::expr::runtime::CelExpressionBuilder>
cel_expression_builder,
CelTestContextOptions options)
: cel_test_context_options_(std::move(options)),
cel_expression_builder_(std::move(cel_expression_builder)) {}

CelTestContext(std::unique_ptr<const cel::Runtime> runtime,
CelTestContextOptions options)
: cel_test_context_options_(std::move(options)),
runtime_(std::move(runtime)) {}

// Configuration for the expression to be executed.
CelTestContextOptions cel_test_context_options_;

// This helps in setting up the environment for building the CEL
// expression. Users should either provide a runtime, or the
// CelExpressionBuilder.
std::unique_ptr<google::api::expr::runtime::CelExpressionBuilder>
cel_expression_builder_;

// The runtime is used to evaluate the CEL expression by managing the state
// needed to generate Program. Users should either provide a runtime, or the
// CelExpressionBuilder.
std::unique_ptr<const cel::Runtime> runtime_;
};

} // namespace cel::test

#endif // THIRD_PARTY_CEL_CPP_TOOLS_TESTRUNNER_CEL_TEST_CONTEXT_H_
Loading