-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce Issue and IssueCollector types for collecting issues encoun…
…tered during expression planning. PiperOrigin-RevId: 576634566
- Loading branch information
1 parent
08a4fe0
commit 43ab587
Showing
5 changed files
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright 2023 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_RUNTIME_INTERNAL_ISSUE_COLLECTOR_H_ | ||
#define THIRD_PARTY_CEL_CPP_RUNTIME_INTERNAL_ISSUE_COLLECTOR_H_ | ||
|
||
#include <utility> | ||
#include <vector> | ||
|
||
#include "absl/status/status.h" | ||
#include "absl/types/span.h" | ||
#include "runtime/runtime_issue.h" | ||
|
||
namespace cel::runtime_internal { | ||
|
||
// IssueCollector collects issues and reports absl::Status according to the | ||
// configured severity limit. | ||
class IssueCollector { | ||
public: | ||
// Args: | ||
// severity: inclusive limit for issues to return as non-ok absl::Status. | ||
explicit IssueCollector(RuntimeIssue::Severity severity_limit) | ||
: severity_limit_(severity_limit) {} | ||
|
||
// move-only. | ||
IssueCollector(const IssueCollector&) = delete; | ||
IssueCollector& operator=(const IssueCollector&) = delete; | ||
IssueCollector(IssueCollector&&) = default; | ||
IssueCollector& operator=(IssueCollector&&) = default; | ||
|
||
// Collect an Issue. | ||
// Returns a status according to the IssueCollector's policy and the given | ||
// Issue. | ||
// The Issue is always added to issues, regardless of whether AddIssue returns | ||
// a non-ok status. | ||
absl::Status AddIssue(RuntimeIssue issue) { | ||
issues_.push_back(std::move(issue)); | ||
if (issues_.back().severity() >= severity_limit_) { | ||
return issues_.back().ToStatus(); | ||
} | ||
return absl::OkStatus(); | ||
} | ||
|
||
absl::Span<const RuntimeIssue> issues() const { return issues_; } | ||
std::vector<RuntimeIssue> ExtractIssues() { return std::move(issues_); } | ||
|
||
private: | ||
RuntimeIssue::Severity severity_limit_; | ||
std::vector<RuntimeIssue> issues_; | ||
}; | ||
|
||
} // namespace cel::runtime_internal | ||
|
||
#endif // THIRD_PARTY_CEL_CPP_RUNTIME_INTERNAL_ISSUE_COLLECTOR_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2023 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. | ||
#include "runtime/internal/issue_collector.h" | ||
|
||
#include "absl/status/status.h" | ||
#include "internal/testing.h" | ||
#include "runtime/runtime_issue.h" | ||
|
||
namespace cel::runtime_internal { | ||
namespace { | ||
|
||
using testing::ElementsAre; | ||
using testing::Truly; | ||
using cel::internal::StatusIs; | ||
|
||
template <typename Matcher, typename T> | ||
bool ApplyMatcher(Matcher m, const T& t) { | ||
return static_cast<testing::Matcher<T>>(m).Matches(t); | ||
} | ||
|
||
TEST(IssueCollector, CollectsIssues) { | ||
IssueCollector issue_collector(RuntimeIssue::Severity::kError); | ||
|
||
EXPECT_THAT(issue_collector.AddIssue( | ||
RuntimeIssue::CreateError(absl::InvalidArgumentError("e1"))), | ||
StatusIs(absl::StatusCode::kInvalidArgument, "e1")); | ||
ASSERT_OK(issue_collector.AddIssue(RuntimeIssue::CreateWarning( | ||
absl::InvalidArgumentError("w1"), | ||
RuntimeIssue::ErrorCode::kNoMatchingOverload))); | ||
|
||
EXPECT_THAT( | ||
issue_collector.issues(), | ||
ElementsAre( | ||
Truly([](const RuntimeIssue& issue) { | ||
return issue.severity() == RuntimeIssue::Severity::kError && | ||
issue.error_code() == RuntimeIssue::ErrorCode::kOther && | ||
ApplyMatcher( | ||
StatusIs(absl::StatusCode::kInvalidArgument, "e1"), | ||
issue.ToStatus()); | ||
}), | ||
Truly([](const RuntimeIssue& issue) { | ||
return issue.severity() == RuntimeIssue::Severity::kWarning && | ||
issue.error_code() == | ||
RuntimeIssue::ErrorCode::kNoMatchingOverload && | ||
ApplyMatcher( | ||
StatusIs(absl::StatusCode::kInvalidArgument, "w1"), | ||
issue.ToStatus()); | ||
}))); | ||
} | ||
|
||
TEST(IssueCollector, ReturnsStatusAtLimit) { | ||
IssueCollector issue_collector(RuntimeIssue::Severity::kWarning); | ||
|
||
EXPECT_THAT(issue_collector.AddIssue( | ||
RuntimeIssue::CreateError(absl::InvalidArgumentError("e1"))), | ||
StatusIs(absl::StatusCode::kInvalidArgument, "e1")); | ||
|
||
EXPECT_THAT(issue_collector.AddIssue(RuntimeIssue::CreateWarning( | ||
absl::InvalidArgumentError("w1"), | ||
RuntimeIssue::ErrorCode::kNoMatchingOverload)), | ||
StatusIs(absl::StatusCode::kInvalidArgument, "w1")); | ||
|
||
EXPECT_THAT( | ||
issue_collector.issues(), | ||
ElementsAre( | ||
Truly([](const RuntimeIssue& issue) { | ||
return issue.severity() == RuntimeIssue::Severity::kError && | ||
issue.error_code() == RuntimeIssue::ErrorCode::kOther && | ||
ApplyMatcher( | ||
StatusIs(absl::StatusCode::kInvalidArgument, "e1"), | ||
issue.ToStatus()); | ||
}), | ||
Truly([](const RuntimeIssue& issue) { | ||
return issue.severity() == RuntimeIssue::Severity::kWarning && | ||
issue.error_code() == | ||
RuntimeIssue::ErrorCode::kNoMatchingOverload && | ||
ApplyMatcher( | ||
StatusIs(absl::StatusCode::kInvalidArgument, "w1"), | ||
issue.ToStatus()); | ||
}))); | ||
} | ||
} // namespace | ||
} // namespace cel::runtime_internal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Copyright 2023 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_RUNTIME_RUNTIME_ISSUE_H_ | ||
#define THIRD_PARTY_CEL_CPP_RUNTIME_RUNTIME_ISSUE_H_ | ||
|
||
#include <utility> | ||
|
||
#include "absl/status/status.h" | ||
|
||
namespace cel { | ||
|
||
// Represents an issue with a given CEL expression. | ||
// | ||
// The error details are represented as an absl::Status for compatibility | ||
// reasons, but users should not depend on this. | ||
class RuntimeIssue { | ||
public: | ||
// Severity of the RuntimeIssue. | ||
// | ||
// Can be used to determine whether to continue program planning or return | ||
// early. | ||
enum class Severity { | ||
// The issue may lead to runtime errors in evaluation. | ||
kWarning = 0, | ||
// The expression is invalid or unsupported. | ||
kError = 1, | ||
// Arbitrary max value above Error. | ||
kNotForUseWithExhaustiveSwitchStatements = 15 | ||
}; | ||
|
||
// Code for well-known runtime error kinds. | ||
enum class ErrorCode { | ||
// Overload not provided for given function call signature. | ||
kNoMatchingOverload, | ||
// Field access refers to unknown field for given type. | ||
kNoSuchField, | ||
// Other error outside the canonical set. | ||
kOther, | ||
}; | ||
|
||
static RuntimeIssue CreateError(absl::Status status, | ||
ErrorCode error_code = ErrorCode::kOther) { | ||
return RuntimeIssue(std::move(status), Severity::kError, error_code); | ||
} | ||
|
||
static RuntimeIssue CreateWarning(absl::Status status, | ||
ErrorCode error_code = ErrorCode::kOther) { | ||
return RuntimeIssue(std::move(status), Severity::kWarning, error_code); | ||
} | ||
|
||
RuntimeIssue(const RuntimeIssue& other) = default; | ||
RuntimeIssue& operator=(const RuntimeIssue& other) = default; | ||
RuntimeIssue(RuntimeIssue&& other) = default; | ||
RuntimeIssue& operator=(RuntimeIssue&& other) = default; | ||
|
||
Severity severity() const { return severity_; } | ||
|
||
ErrorCode error_code() const { return error_code_; } | ||
|
||
const absl::Status& ToStatus() const& { return status_; } | ||
absl::Status ToStatus() && { return std::move(status_); } | ||
|
||
private: | ||
RuntimeIssue(absl::Status status, Severity severity, ErrorCode error_code) | ||
: status_(std::move(status)), | ||
error_code_(error_code), | ||
severity_(severity) {} | ||
|
||
absl::Status status_; | ||
ErrorCode error_code_; | ||
Severity severity_; | ||
}; | ||
|
||
} // namespace cel | ||
|
||
#endif // THIRD_PARTY_CEL_CPP_RUNTIME_RUNTIME_ISSUE_H_ |