Skip to content

Commit e69ed66

Browse files
CEL Dev Teamcopybara-github
authored andcommitted
[NaaS] Register CEL extension provided string functions in evaluator.
PiperOrigin-RevId: 773278978
1 parent e50662e commit e69ed66

File tree

4 files changed

+103
-3
lines changed

4 files changed

+103
-3
lines changed

extensions/BUILD

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ cc_library(
175175
srcs = ["regex_functions.cc"],
176176
hdrs = ["regex_functions.h"],
177177
deps = [
178+
"//checker:type_checker_builder",
179+
"//common:decl",
180+
"//common:type",
178181
"//common:value",
179182
"//eval/public:cel_function_registry",
180183
"//eval/public:cel_options",
@@ -215,8 +218,12 @@ cc_test(
215218
],
216219
deps = [
217220
":regex_functions",
221+
"//checker:standard_library",
222+
"//checker:validation_result",
218223
"//common:value",
219224
"//common:value_testing",
225+
"//compiler",
226+
"//compiler:compiler_factory",
220227
"//extensions/protobuf:runtime_adapter",
221228
"//internal:status_macros",
222229
"//internal:testing",

extensions/regex_functions.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#include "absl/status/status.h"
2424
#include "absl/status/statusor.h"
2525
#include "absl/strings/string_view.h"
26+
#include "checker/type_checker_builder.h"
27+
#include "common/decl.h"
28+
#include "common/type.h"
2629
#include "common/value.h"
2730
#include "eval/public/cel_function_registry.h"
2831
#include "eval/public/cel_options.h"
@@ -164,6 +167,30 @@ absl::Status RegisterRegexFunctions(FunctionRegistry& registry) {
164167
return absl::OkStatus();
165168
}
166169

170+
absl::Status RegisterRegexDecls(TypeCheckerBuilder& builder) {
171+
CEL_ASSIGN_OR_RETURN(
172+
FunctionDecl regex_extract_decl,
173+
MakeFunctionDecl(
174+
std::string(kRegexExtract),
175+
MakeOverloadDecl("regex_extract", StringType(), StringType(),
176+
StringType(), StringType())));
177+
CEL_RETURN_IF_ERROR(builder.AddFunction(regex_extract_decl));
178+
179+
CEL_ASSIGN_OR_RETURN(
180+
FunctionDecl regex_capture_decl,
181+
MakeFunctionDecl(std::string(kRegexCapture),
182+
MakeOverloadDecl("regex_capture", StringType(),
183+
StringType(), StringType())));
184+
CEL_RETURN_IF_ERROR(builder.AddFunction(regex_capture_decl));
185+
186+
CEL_ASSIGN_OR_RETURN(
187+
FunctionDecl regex_capture_n_decl,
188+
MakeFunctionDecl(std::string(kRegexCaptureN),
189+
MakeOverloadDecl("regex_capture", MapType(),
190+
StringType(), StringType())));
191+
return builder.AddFunction(regex_capture_n_decl);
192+
}
193+
167194
} // namespace
168195

169196
absl::Status RegisterRegexFunctions(FunctionRegistry& registry,
@@ -182,4 +209,8 @@ absl::Status RegisterRegexFunctions(CelFunctionRegistry* registry,
182209
return absl::OkStatus();
183210
}
184211

212+
CheckerLibrary RegexCheckerLibrary() {
213+
return {.id = "regex", .configure = RegisterRegexDecls};
214+
}
215+
185216
} // namespace cel::extensions

extensions/regex_functions.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,17 @@
1717

1818
#include "absl/status/status.h"
1919
#include "absl/strings/string_view.h"
20+
#include "checker/type_checker_builder.h"
2021
#include "eval/public/cel_function_registry.h"
2122
#include "eval/public/cel_options.h"
2223
#include "runtime/function_registry.h"
2324
#include "runtime/runtime_options.h"
2425

2526
namespace cel::extensions {
2627

27-
constexpr absl::string_view kRegexExtract = "re.extract";
28-
constexpr absl::string_view kRegexCapture = "re.capture";
29-
constexpr absl::string_view kRegexCaptureN = "re.captureN";
28+
inline constexpr absl::string_view kRegexExtract = "re.extract";
29+
inline constexpr absl::string_view kRegexCapture = "re.capture";
30+
inline constexpr absl::string_view kRegexCaptureN = "re.captureN";
3031

3132
// Register Extract and Capture Functions for RE2
3233
// Requires options.enable_regex to be true
@@ -36,5 +37,8 @@ absl::Status RegisterRegexFunctions(
3637
absl::Status RegisterRegexFunctions(FunctionRegistry& registry,
3738
const RuntimeOptions& options);
3839

40+
// Declarations for the regex extension library.
41+
CheckerLibrary RegexCheckerLibrary();
42+
3943
} // namespace cel::extensions
4044
#endif // THIRD_PARTY_CEL_CPP_EXTENSIONS_REGEX_FUNCTIONS_H_

extensions/regex_functions_test.cc

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@
2323
#include "absl/status/status.h"
2424
#include "absl/status/status_matchers.h"
2525
#include "absl/status/statusor.h"
26+
#include "checker/standard_library.h"
27+
#include "checker/validation_result.h"
2628
#include "common/value.h"
2729
#include "common/value_testing.h"
30+
#include "compiler/compiler.h"
31+
#include "compiler/compiler_factory.h"
2832
#include "extensions/protobuf/runtime_adapter.h"
2933
#include "internal/status_macros.h"
3034
#include "internal/testing.h"
@@ -226,6 +230,60 @@ TEST_P(RegexFunctionsTest, RegexFunctionsTests) {
226230
INSTANTIATE_TEST_SUITE_P(RegexFunctionsTest, RegexFunctionsTest,
227231
ValuesIn(createParams()));
228232

233+
struct RegexCheckerTestCase {
234+
const std::string expr_string;
235+
bool is_valid;
236+
};
237+
238+
class RegexCheckerLibraryTest
239+
: public ::testing::TestWithParam<RegexCheckerTestCase> {
240+
public:
241+
void SetUp() override {
242+
// Arrange: Configure the compiler.
243+
// Add the regex checker library to the compiler builder.
244+
ASSERT_OK_AND_ASSIGN(std::unique_ptr<CompilerBuilder> compiler_builder,
245+
NewCompilerBuilder(descriptor_pool_));
246+
ASSERT_THAT(compiler_builder->AddLibrary(StandardCheckerLibrary()), IsOk());
247+
ASSERT_THAT(compiler_builder->AddLibrary(RegexCheckerLibrary()), IsOk());
248+
ASSERT_OK_AND_ASSIGN(compiler_, std::move(*compiler_builder).Build());
249+
}
250+
251+
const google::protobuf::DescriptorPool* descriptor_pool_ =
252+
internal::GetTestingDescriptorPool();
253+
std::unique_ptr<Compiler> compiler_;
254+
};
255+
256+
TEST_P(RegexCheckerLibraryTest, RegexFunctionsTypeCheckerSuccess) {
257+
// Act & Assert: Compile the expression and validate the result.
258+
ASSERT_OK_AND_ASSIGN(ValidationResult result,
259+
compiler_->Compile(GetParam().expr_string));
260+
EXPECT_EQ(result.IsValid(), GetParam().is_valid);
261+
}
262+
263+
// Returns a vector of test cases for the RegexCheckerLibraryTest.
264+
// Returns both positive and negative test cases for the regex functions.
265+
std::vector<RegexCheckerTestCase> createRegexCheckerParams() {
266+
return {
267+
{R"(re.extract('testuser@google.com', '(.*)@([^.]*)', '\\2!\\1'))", true},
268+
{R"(re.extract('testuser@google.com', '(.*)@([^.]*)', 2))", false},
269+
{R"(re.extract('testuser@google.com', false, '\\2!\\1'))", false},
270+
{R"(re.extract(['foo', 'bar'], '(.*)@([^.]*)', '\\2!\\1'))", false},
271+
{R"(re.captureN(
272+
'The user testuser belongs to testdomain',
273+
'The (user|domain) (?P<Username>.*) belongs to (?P<Domain>.*)'
274+
))",
275+
true},
276+
{R"(re.captureN('testuser@', '(?P<username>.*)@'))", true},
277+
{R"(re.captureN('testuser@', 2))", false},
278+
{R"(re.captureN(['foo', 'bar'], '(?P<username>.*)@'))", false},
279+
{R"(re.capture('foo', 'fo(o)'))", true},
280+
{R"(re.capture('foo', 2))", false},
281+
{R"(re.capture(true, 'fo(o)'))", false}};
282+
}
283+
284+
INSTANTIATE_TEST_SUITE_P(RegexCheckerLibraryTest, RegexCheckerLibraryTest,
285+
ValuesIn(createRegexCheckerParams()));
286+
229287
} // namespace
230288

231289
} // namespace cel::extensions

0 commit comments

Comments
 (0)