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
7 changes: 2 additions & 5 deletions src/compiler/default_compiler_draft4.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <algorithm> // std::sort, std::any_of, std::all_of, std::find_if, std::none_of
#include <cassert> // assert
#include <set> // std::set
#include <sstream> // std::ostringstream
#include <utility> // std::move

#include "compile_helpers.h"
Expand All @@ -20,10 +19,8 @@ static auto parse_regex(const std::string &pattern,
-> sourcemeta::core::Regex {
const auto result{sourcemeta::core::to_regex(pattern)};
if (!result.has_value()) {
std::ostringstream message;
message << "Invalid regular expression: " << pattern;
throw sourcemeta::blaze::CompilerError(base, to_pointer(schema_location),
message.str());
throw sourcemeta::blaze::CompilerInvalidRegexError(
base, to_pointer(schema_location), pattern);
}

return result.value();
Expand Down
62 changes: 55 additions & 7 deletions src/compiler/include/sourcemeta/blaze/compiler_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,20 @@ namespace sourcemeta::blaze {
class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerError : public std::exception {
public:
CompilerError(sourcemeta::core::URI base,
sourcemeta::core::Pointer schema_location, std::string message)
sourcemeta::core::Pointer schema_location, const char *message)
: base_{std::move(base)}, schema_location_{std::move(schema_location)},
message_{std::move(message)} {}
message_{message} {}
CompilerError(sourcemeta::core::URI base,
sourcemeta::core::Pointer schema_location,
std::string message) = delete;
CompilerError(sourcemeta::core::URI base,
sourcemeta::core::Pointer schema_location,
std::string &&message) = delete;
CompilerError(sourcemeta::core::URI base,
sourcemeta::core::Pointer schema_location,
std::string_view message) = delete;
[[nodiscard]] auto what() const noexcept -> const char * override {
return this->message_.c_str();
return this->message_;
}

[[nodiscard]] auto base() const noexcept -> const sourcemeta::core::URI & {
Expand All @@ -46,7 +55,40 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerError : public std::exception {
private:
sourcemeta::core::URI base_;
sourcemeta::core::Pointer schema_location_;
std::string message_;
const char *message_;
};

/// @ingroup jsonschema
/// An error that represents an invalid regular expression during compilation
class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerInvalidRegexError
: public std::exception {
public:
CompilerInvalidRegexError(sourcemeta::core::URI base,
sourcemeta::core::Pointer schema_location,
std::string regex)
: base_{std::move(base)}, schema_location_{std::move(schema_location)},
regex_{std::move(regex)} {}
[[nodiscard]] auto what() const noexcept -> const char * override {
return "Invalid regular expression";
}

[[nodiscard]] auto base() const noexcept -> const sourcemeta::core::URI & {
return this->base_;
}

[[nodiscard]] auto location() const noexcept
-> const sourcemeta::core::Pointer & {
return this->schema_location_;
}

[[nodiscard]] auto regex() const noexcept -> const std::string & {
return this->regex_;
}

private:
sourcemeta::core::URI base_;
sourcemeta::core::Pointer schema_location_;
std::string regex_;
};

/// @ingroup jsonschema
Expand Down Expand Up @@ -84,11 +126,17 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerInvalidEntryPoint
: public std::exception {
public:
CompilerInvalidEntryPoint(const std::string_view entrypoint,
const std::string_view message)
const char *message)
: identifier_{entrypoint}, message_{message} {}
CompilerInvalidEntryPoint(const std::string_view entrypoint,
std::string message) = delete;
CompilerInvalidEntryPoint(const std::string_view entrypoint,
std::string &&message) = delete;
CompilerInvalidEntryPoint(const std::string_view entrypoint,
std::string_view message) = delete;

[[nodiscard]] auto what() const noexcept -> const char * override {
return this->message_.c_str();
return this->message_;
}

[[nodiscard]] auto identifier() const noexcept -> const std::string & {
Expand All @@ -97,7 +145,7 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerInvalidEntryPoint

private:
std::string identifier_;
std::string message_;
const char *message_;
};

#if defined(_MSC_VER)
Expand Down
15 changes: 9 additions & 6 deletions src/evaluator/include/sourcemeta/blaze/evaluator_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
#include <sourcemeta/blaze/evaluator_export.h>
#endif

#include <exception> // std::exception
#include <string> // std::string
#include <utility> // std::move
#include <exception> // std::exception
#include <string> // std::string
#include <string_view> // std::string_view

namespace sourcemeta::blaze {

Expand All @@ -23,13 +23,16 @@ namespace sourcemeta::blaze {
class SOURCEMETA_BLAZE_EVALUATOR_EXPORT EvaluationError
: public std::exception {
public:
EvaluationError(std::string message) : message_{std::move(message)} {}
EvaluationError(const char *message) : message_{message} {}
EvaluationError(std::string message) = delete;
EvaluationError(std::string &&message) = delete;
EvaluationError(std::string_view message) = delete;
[[nodiscard]] auto what() const noexcept -> const char * override {
return this->message_.c_str();
return this->message_;
}

private:
std::string message_;
const char *message_;
};

#if defined(_MSC_VER)
Expand Down
40 changes: 36 additions & 4 deletions src/linter/include/sourcemeta/blaze/linter_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@ class SOURCEMETA_BLAZE_LINTER_EXPORT LinterMissingNameError
class SOURCEMETA_BLAZE_LINTER_EXPORT LinterInvalidNameError
: public std::exception {
public:
LinterInvalidNameError(const std::string_view identifier,
const std::string_view message)
LinterInvalidNameError(const std::string_view identifier, const char *message)
: identifier_{identifier}, message_{message} {}
LinterInvalidNameError(const std::string_view identifier,
std::string message) = delete;
LinterInvalidNameError(const std::string_view identifier,
std::string &&message) = delete;
LinterInvalidNameError(const std::string_view identifier,
std::string_view message) = delete;

[[nodiscard]] auto what() const noexcept -> const char * override {
return this->message_.c_str();
return this->message_;
}

[[nodiscard]] auto identifier() const noexcept -> const std::string & {
Expand All @@ -48,7 +53,34 @@ class SOURCEMETA_BLAZE_LINTER_EXPORT LinterInvalidNameError

private:
std::string identifier_;
std::string message_;
const char *message_;
};

/// @ingroup linter
/// An error that represents a schema rule name that does not match
/// the required pattern
class SOURCEMETA_BLAZE_LINTER_EXPORT LinterInvalidNamePatternError
: public std::exception {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LinterInvalidNamePatternError isn’t a LinterInvalidNameError, so code catching LinterInvalidNameError won’t handle pattern violations anymore. If this is an intentional API-surface change, it may need explicit documentation or a shared base for “invalid name” errors.

Severity: medium

Other Locations
  • src/linter/schema.cc:28

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

public:
LinterInvalidNamePatternError(const std::string_view identifier,
const std::string_view regex)
: identifier_{identifier}, regex_{regex} {}

[[nodiscard]] auto what() const noexcept -> const char * override {
return "The schema rule name does not match the required pattern";
}

[[nodiscard]] auto identifier() const noexcept -> const std::string & {
return this->identifier_;
}

[[nodiscard]] auto regex() const noexcept -> const std::string & {
return this->regex_;
}

private:
std::string identifier_;
std::string regex_;
};

#if defined(_MSC_VER)
Expand Down
4 changes: 1 addition & 3 deletions src/linter/schema.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ static auto validate_name(const std::string_view name) -> void {
}

if (!sourcemeta::core::matches(pattern.value(), std::string{name})) {
std::string message{"The schema rule name must match "};
message += NAME_PATTERN;
throw LinterInvalidNameError(name, message);
throw LinterInvalidNamePatternError(name, NAME_PATTERN);
}
}

Expand Down
28 changes: 20 additions & 8 deletions src/test/include/sourcemeta/blaze/test_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

#include <sourcemeta/core/jsonpointer.h>

#include <cstdint> // std::uint64_t
#include <stdexcept> // std::runtime_error
#include <string> // std::string
#include <utility> // std::move
#include <cstdint> // std::uint64_t
#include <exception> // std::exception
#include <string> // std::string
#include <string_view> // std::string_view
#include <utility> // std::move

namespace sourcemeta::blaze {

Expand All @@ -23,12 +24,22 @@ namespace sourcemeta::blaze {

/// @ingroup test
/// An error that occurs when parsing a test file
class SOURCEMETA_BLAZE_TEST_EXPORT TestParseError : public std::runtime_error {
class SOURCEMETA_BLAZE_TEST_EXPORT TestParseError : public std::exception {
public:
TestParseError(const std::string &message, sourcemeta::core::Pointer location,
TestParseError(const char *message, sourcemeta::core::Pointer location,
std::uint64_t line, std::uint64_t column)
: std::runtime_error{message}, location_{std::move(location)},
line_{line}, column_{column} {}
: message_{message}, location_{std::move(location)}, line_{line},
column_{column} {}
TestParseError(std::string message, sourcemeta::core::Pointer location,
std::uint64_t line, std::uint64_t column) = delete;
TestParseError(std::string &&message, sourcemeta::core::Pointer location,
std::uint64_t line, std::uint64_t column) = delete;
TestParseError(std::string_view message, sourcemeta::core::Pointer location,
std::uint64_t line, std::uint64_t column) = delete;

[[nodiscard]] auto what() const noexcept -> const char * override {
return this->message_;
}

[[nodiscard]] auto location() const noexcept
-> const sourcemeta::core::Pointer & {
Expand All @@ -44,6 +55,7 @@ class SOURCEMETA_BLAZE_TEST_EXPORT TestParseError : public std::runtime_error {
}

private:
const char *message_;
sourcemeta::core::Pointer location_;
std::uint64_t line_;
std::uint64_t column_;
Expand Down
51 changes: 29 additions & 22 deletions test/evaluator/evaluator_draft4_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1049,8 +1049,15 @@ TEST(Evaluator_draft4, ref_14) {

const sourcemeta::core::JSON instance{true};
sourcemeta::blaze::Evaluator evaluator;
EXPECT_THROW(evaluator.validate(compiled_schema, instance),
sourcemeta::blaze::EvaluationError);
try {
evaluator.validate(compiled_schema, instance);
FAIL();
} catch (const sourcemeta::blaze::EvaluationError &error) {
EXPECT_STREQ(error.what(), "The evaluation path depth limit was reached "
"likely due to infinite recursion");
} catch (...) {
FAIL();
}
}

TEST(Evaluator_draft4, ref_15) {
Expand Down Expand Up @@ -2027,14 +2034,14 @@ TEST(Evaluator_draft4, pattern_4) {
sourcemeta::blaze::default_schema_compiler);
// The pattern might succeed in some standard library implementations
SUCCEED();
} catch (const sourcemeta::blaze::CompilerError &error) {
EXPECT_STREQ(error.what(),
"Invalid regular expression: ^[a-zA-Z0-9\\/\\_]{1,32}$");
} catch (const sourcemeta::blaze::CompilerInvalidRegexError &error) {
EXPECT_STREQ(error.what(), "Invalid regular expression");
EXPECT_EQ(error.regex(), "^[a-zA-Z0-9\\/\\_]{1,32}$");
EXPECT_EQ(error.location(), sourcemeta::core::Pointer({"pattern"}));
EXPECT_EQ(error.base().recompose(), "");
SUCCEED();
} catch (const std::exception &) {
FAIL() << "The compile function was expected to throw a schema error";
} catch (...) {
FAIL();
}
}

Expand All @@ -2054,15 +2061,15 @@ TEST(Evaluator_draft4, pattern_5) {
sourcemeta::blaze::default_schema_compiler);
// The pattern might succeed in some standard library implementations
SUCCEED();
} catch (const sourcemeta::blaze::CompilerError &error) {
EXPECT_STREQ(error.what(),
"Invalid regular expression: ^[a-zA-Z0-9\\/\\_]{1,32}$");
} catch (const sourcemeta::blaze::CompilerInvalidRegexError &error) {
EXPECT_STREQ(error.what(), "Invalid regular expression");
EXPECT_EQ(error.regex(), "^[a-zA-Z0-9\\/\\_]{1,32}$");
EXPECT_EQ(error.location(),
sourcemeta::core::Pointer({"properties", "foo", "pattern"}));
EXPECT_EQ(error.base().recompose(), "");
SUCCEED();
} catch (const std::exception &) {
FAIL() << "The compile function was expected to throw a schema error";
} catch (...) {
FAIL();
}
}

Expand All @@ -2083,14 +2090,14 @@ TEST(Evaluator_draft4, pattern_6) {
sourcemeta::blaze::default_schema_compiler);
// The pattern might succeed in some standard library implementations
SUCCEED();
} catch (const sourcemeta::blaze::CompilerError &error) {
EXPECT_STREQ(error.what(),
"Invalid regular expression: ^[a-zA-Z0-9\\/\\_]{1,32}$");
} catch (const sourcemeta::blaze::CompilerInvalidRegexError &error) {
EXPECT_STREQ(error.what(), "Invalid regular expression");
EXPECT_EQ(error.regex(), "^[a-zA-Z0-9\\/\\_]{1,32}$");
EXPECT_EQ(error.location(), sourcemeta::core::Pointer({"pattern"}));
EXPECT_EQ(error.base().recompose(), "https://nested.com");
SUCCEED();
} catch (const std::exception &) {
FAIL() << "The compile function was expected to throw a schema error";
} catch (...) {
FAIL();
}
}

Expand Down Expand Up @@ -2391,15 +2398,15 @@ TEST(Evaluator_draft4, patternProperties_9) {
sourcemeta::blaze::default_schema_compiler);
// The pattern might succeed in some standard library implementations
SUCCEED();
} catch (const sourcemeta::blaze::CompilerError &error) {
EXPECT_STREQ(error.what(),
"Invalid regular expression: ^[a-zA-Z0-9\\_\\.\\-]*$");
} catch (const sourcemeta::blaze::CompilerInvalidRegexError &error) {
EXPECT_STREQ(error.what(), "Invalid regular expression");
EXPECT_EQ(error.regex(), "^[a-zA-Z0-9\\_\\.\\-]*$");
EXPECT_EQ(error.location(),
sourcemeta::core::Pointer({"patternProperties"}));
EXPECT_EQ(error.base().recompose(), "");
SUCCEED();
} catch (const std::exception &) {
FAIL() << "The compile function was expected to throw a schema error";
} catch (...) {
FAIL();
}
}

Expand Down
Loading