18
18
#include < functional>
19
19
#include < ios>
20
20
#include < memory>
21
+ #include < sstream>
21
22
#include < string>
22
- #include < string_view>
23
23
#include < utility>
24
24
25
+ #include " cel/expr/checked.pb.h"
25
26
#include " absl/flags/flag.h"
26
27
#include " absl/log/absl_check.h"
27
28
#include " absl/log/absl_log.h"
28
29
#include " absl/status/status.h"
29
30
#include " absl/status/statusor.h"
31
+ #include " absl/strings/match.h"
30
32
#include " absl/strings/str_cat.h"
33
+ #include " absl/strings/string_view.h"
34
+ #include " internal/status_macros.h"
31
35
#include " internal/testing.h"
36
+ #include " testing/testrunner/cel_expression_source.h"
32
37
#include " testing/testrunner/cel_test_context.h"
33
38
#include " testing/testrunner/cel_test_factories.h"
34
39
#include " testing/testrunner/runner_lib.h"
35
40
#include " cel/expr/conformance/test/suite.pb.h"
36
- #include " google/protobuf/io/zero_copy_stream_impl.h"
37
41
#include " google/protobuf/text_format.h"
38
42
39
43
ABSL_FLAG (std::string, test_suite_path, " " ,
40
44
" The path to the file containing the test suite to run." );
45
+ ABSL_FLAG (std::string, expr_source, " " ,
46
+ " The kind of expression source: 'raw', 'file', or 'checked'." );
47
+ ABSL_FLAG (std::string, cel_expression, " " ,
48
+ " The value of the CEL expression source. For 'raw', it's the "
49
+ " expression string. For 'file' and 'checked', it's the file path." );
41
50
42
51
namespace {
43
52
44
53
using ::cel::expr::conformance::test::TestCase;
45
54
using ::cel::expr::conformance::test::TestSuite;
55
+ using ::cel::test::CelExpressionSource;
56
+ using ::cel::test::CelTestContextOptions;
46
57
using ::cel::test::TestRunner;
58
+ using ::cel::expr::CheckedExpr;
47
59
48
60
class CelTest : public testing ::Test {
49
61
public:
@@ -73,21 +85,65 @@ absl::Status RegisterTests(const TestSuite& test_suite,
73
85
return absl::OkStatus ();
74
86
}
75
87
76
- TestSuite ReadTestSuiteFromPath (std::string_view test_suite_path) {
77
- TestSuite test_suite;
78
- {
79
- std::ifstream in;
80
- in.open (std::string (test_suite_path),
81
- std::ios_base::in | std::ios_base::binary);
82
- if (!in.is_open ()) {
83
- ABSL_LOG (FATAL) << " failed to open file: " << test_suite_path;
84
- }
85
- google::protobuf::io::IstreamInputStream stream (&in);
86
- if (!google::protobuf::TextFormat::Parse (&stream, &test_suite)) {
87
- ABSL_LOG (FATAL) << " failed to parse file: " << test_suite_path;
88
- }
88
+ absl::StatusOr<std::string> ReadFileToString (absl::string_view file_path) {
89
+ std::ifstream file_stream{std::string (file_path)};
90
+ if (!file_stream.is_open ()) {
91
+ return absl::NotFoundError (
92
+ absl::StrCat (" Unable to open file: " , file_path));
93
+ }
94
+ std::stringstream buffer;
95
+ buffer << file_stream.rdbuf ();
96
+ return buffer.str ();
97
+ }
98
+
99
+ template <typename T>
100
+ absl::StatusOr<T> ReadTextProtoFromFile (absl::string_view file_path) {
101
+ CEL_ASSIGN_OR_RETURN (std::string contents, ReadFileToString (file_path));
102
+ T message;
103
+ if (!google::protobuf::TextFormat::ParseFromString (contents, &message)) {
104
+ return absl::InternalError (absl::StrCat (
105
+ " Failed to parse text-format proto from file: " , file_path));
89
106
}
90
- return test_suite;
107
+ return message;
108
+ }
109
+
110
+ absl::StatusOr<CheckedExpr> ReadBinaryProtoFromFile (
111
+ absl::string_view file_path) {
112
+ CheckedExpr message;
113
+ std::ifstream file_stream{std::string (file_path), std::ios::binary};
114
+ if (!file_stream.is_open ()) {
115
+ return absl::NotFoundError (
116
+ absl::StrCat (" Unable to open file: " , file_path));
117
+ }
118
+ if (!message.ParseFromIstream (&file_stream)) {
119
+ return absl::InternalError (
120
+ absl::StrCat (" Failed to parse binary proto from file: " , file_path));
121
+ }
122
+ return message;
123
+ }
124
+
125
+ TestSuite ReadTestSuiteFromPath (absl::string_view test_suite_path) {
126
+ absl::StatusOr<TestSuite> test_suite_or =
127
+ ReadTextProtoFromFile<TestSuite>(test_suite_path);
128
+
129
+ if (!test_suite_or.ok ()) {
130
+ ABSL_LOG (FATAL) << " Failed to load test suite from " << test_suite_path
131
+ << " : " << test_suite_or.status ();
132
+ }
133
+ return *std::move (test_suite_or);
134
+ }
135
+
136
+ absl::StatusOr<CheckedExpr> ReadCheckedExprFromFile (
137
+ absl::string_view file_path) {
138
+ if (absl::EndsWith (file_path, " .textproto" )) {
139
+ return ReadTextProtoFromFile<CheckedExpr>(file_path);
140
+ }
141
+ if (absl::EndsWith (file_path, " .binarypb" )) {
142
+ return ReadBinaryProtoFromFile (file_path);
143
+ }
144
+ return absl::InvalidArgumentError (absl::StrCat (
145
+ " Unknown file extension for checked expression. " ,
146
+ " Please use .textproto, .textpb, .pb, or .binarypb: " , file_path));
91
147
}
92
148
93
149
TestSuite GetTestSuite () {
@@ -108,21 +164,61 @@ TestSuite GetTestSuite() {
108
164
}
109
165
return test_suite_factory ();
110
166
}
167
+
168
+ absl::StatusOr<CelTestContextOptions> GetExpressionSourceOptions () {
169
+ CelTestContextOptions options;
170
+ if (absl::GetFlag (FLAGS_expr_source).empty ()) {
171
+ return options;
172
+ }
173
+
174
+ std::string kind = absl::GetFlag (FLAGS_expr_source);
175
+ std::string value = absl::GetFlag (FLAGS_cel_expression);
176
+
177
+ if (kind == " raw" ) {
178
+ options.expression_source = CelExpressionSource::FromRawExpression (value);
179
+ } else if (kind == " file" ) {
180
+ options.expression_source = CelExpressionSource::FromCelFile (value);
181
+ } else if (kind == " checked" ) {
182
+ CEL_ASSIGN_OR_RETURN (CheckedExpr checked_expr,
183
+ ReadCheckedExprFromFile (value));
184
+ options.expression_source =
185
+ CelExpressionSource::FromCheckedExpr (std::move (checked_expr));
186
+ } else {
187
+ ABSL_LOG (FATAL) << " Unknown expression kind: " << kind;
188
+ }
189
+ return options;
190
+ }
191
+
111
192
} // namespace
112
193
113
194
int main (int argc, char ** argv) {
114
195
testing::InitGoogleTest (&argc, argv);
115
-
196
+ absl::StatusOr<CelTestContextOptions> test_context_options =
197
+ GetExpressionSourceOptions ();
198
+ if (!test_context_options.ok ()) {
199
+ ABSL_LOG (FATAL) << " Failed to get expression source options: "
200
+ << test_context_options.status ();
201
+ }
116
202
// Create a test context using the factory function returned by the global
117
203
// factory function provider which was initialized by the user.
118
- absl::StatusOr<std::unique_ptr<cel::test::CelTestContext>> cel_test_context =
119
- cel::test::internal::GetCelTestContextFactory ()();
120
- if (!cel_test_context .ok ()) {
121
- ABSL_LOG (FATAL) << " Failed to create CEL test context: "
122
- << cel_test_context .status ();
204
+ absl::StatusOr<std::unique_ptr<cel::test::CelTestContext>>
205
+ cel_test_context_or = cel::test::internal::GetCelTestContextFactory ()();
206
+ if (!cel_test_context_or .ok ()) {
207
+ ABSL_LOG (FATAL) << " Failed to create CEL test context from factory : "
208
+ << cel_test_context_or .status ();
123
209
}
124
- auto test_runner =
125
- std::make_shared<TestRunner>(std::move (cel_test_context.value ()));
210
+ std::unique_ptr<cel::test::CelTestContext> cel_test_context =
211
+ std::move (cel_test_context_or.value ());
212
+
213
+ // Inject the expression source from the flags into the context
214
+ // using the SetExpressionSource() method if expression source is
215
+ // provided via bzl macro.
216
+ if (test_context_options->expression_source .has_value ()) {
217
+ cel_test_context->SetExpressionSource (
218
+ std::move (*test_context_options->expression_source ));
219
+ }
220
+
221
+ auto test_runner = std::make_shared<TestRunner>(std::move (cel_test_context));
126
222
ABSL_CHECK_OK (RegisterTests (GetTestSuite (), test_runner));
127
223
128
224
return RUN_ALL_TESTS ();
0 commit comments