Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localize ParseControlErrorInfo. #521

Merged
merged 5 commits into from
May 25, 2022
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
16 changes: 14 additions & 2 deletions include/vcpkg/base/messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ namespace vcpkg
struct LocalizedString
{
LocalizedString() = default;
operator StringView() const { return m_data; }
const std::string& data() const { return m_data; }
operator StringView() const noexcept { return m_data; }
const std::string& data() const noexcept { return m_data; }
std::string extract_data() { return std::exchange(m_data, ""); }

static LocalizedString from_raw(std::string&& s) { return LocalizedString(std::move(s)); }
Expand Down Expand Up @@ -336,4 +336,16 @@ namespace vcpkg::msg
{
println_error(format(m, args...));
}

template<class Message, class... Ts, class = typename Message::is_message_type>
LocalizedString format_warning(Message m, Ts... args)
{
return format(msgWarningMessage).append(m, args...);
}

template<class Message, class... Ts, class = typename Message::is_message_type>
LocalizedString format_error(Message m, Ts... args)
{
return format(msgErrorMessage).append(m, args...);
}
}
8 changes: 6 additions & 2 deletions include/vcpkg/base/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ namespace vcpkg
const std::string line;
const std::string message;

std::string format() const;
const std::string& get_message() const;
std::string to_string() const;
};
} // namespace vcpkg

VCPKG_FORMAT_WITH_TO_STRING(vcpkg::ParseError);

namespace vcpkg
{
struct SourceLoc
{
Unicode::Utf8Decoder it;
Expand Down
11 changes: 6 additions & 5 deletions include/vcpkg/base/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ namespace vcpkg
"Cannot convert incompatible ranges");
}

constexpr iterator begin() const { return m_ptr; }
constexpr iterator end() const { return m_ptr + m_count; }
constexpr iterator begin() const noexcept { return m_ptr; }
constexpr iterator end() const noexcept { return m_ptr + m_count; }

constexpr reference operator[](size_t i) const { return m_ptr[i]; }
constexpr pointer data() const { return m_ptr; }
constexpr size_t size() const { return m_count; }
constexpr reference operator[](size_t i) const noexcept { return m_ptr[i]; }
constexpr pointer data() const noexcept { return m_ptr; }
constexpr size_t size() const noexcept { return m_count; }
constexpr bool empty() const noexcept { return m_count == 0; }

private:
pointer m_ptr;
Expand Down
12 changes: 9 additions & 3 deletions include/vcpkg/paragraphparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ namespace vcpkg
struct ParseControlErrorInfo
{
std::string name;
std::map<std::string, std::vector<std::string>> missing_fields;
std::map<std::string, std::vector<std::string>> extra_fields;
std::vector<std::string> missing_fields;
std::vector<std::string> extra_fields;
std::map<std::string, std::string> expected_types;
std::map<std::string, std::vector<std::string>> mutually_exclusive_fields;
std::vector<std::string> other_errors;
std::string error;

Expand All @@ -34,8 +33,15 @@ namespace vcpkg
}

static std::string format_errors(View<std::unique_ptr<ParseControlErrorInfo>> errors);
void to_string(std::string& target) const;
std::string to_string() const;
};
} // namespace vcpkg

VCPKG_FORMAT_WITH_TO_STRING(vcpkg::ParseControlErrorInfo);

namespace vcpkg
{
template<class P>
using ParseExpected = vcpkg::ExpectedT<std::unique_ptr<P>, std::unique_ptr<ParseControlErrorInfo>>;

Expand Down
5 changes: 5 additions & 0 deletions locales/messages.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@
"NoRegistryForPort": "no registry configured for port {package_name}",
"NoteMessage": "note: ",
"ObjectStorageToolFailed": "{tool_name} failed with exit code: {exit_code}",
"ParseControlErrorInfoInvalidFields": "The following fields were not expected:",
"ParseControlErrorInfoMissingFields": "The following fields were missing:",
"ParseControlErrorInfoTypesEntry": "{value} was expected to be {expected}",
"ParseControlErrorInfoWhileLoading": "while loading {path}:",
"ParseControlErrorInfoWrongTypeFields": "The following fields had the wrong types:",
"PortNotInBaseline": "the baseline does not contain an entry for port {package_name}",
"ProcessorArchitectureMalformed": "Failed to parse %PROCESSOR_ARCHITECTURE% ({arch}) as a valid CPU architecture.",
"ProcessorArchitectureMissing": "The required environment variable %PROCESSOR_ARCHITECTURE% is missing.",
Expand Down
7 changes: 7 additions & 0 deletions locales/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,13 @@
"NoteMessage": "note: ",
"ObjectStorageToolFailed": "{tool_name} failed with exit code: {exit_code}",
"_ObjectStorageToolFailed.comment": "An example of {exit_code} is 127. An example of {tool_name} is aria2.",
"ParseControlErrorInfoInvalidFields": "The following fields were not expected:",
"ParseControlErrorInfoMissingFields": "The following fields were missing:",
"ParseControlErrorInfoTypesEntry": "{value} was expected to be {expected}",
"_ParseControlErrorInfoTypesEntry.comment": "{value} is the name of a field in an on-disk file, {expected} is a short description of what it should be like 'a non-negative integer' (which isn't localized yet)",
"ParseControlErrorInfoWhileLoading": "while loading {path}:",
"_ParseControlErrorInfoWhileLoading.comment": "Error messages are is printed after this. An example of {path} is /foo/bar.",
"ParseControlErrorInfoWrongTypeFields": "The following fields had the wrong types:",
"PortNotInBaseline": "the baseline does not contain an entry for port {package_name}",
"_PortNotInBaseline.comment": "An example of {package_name} is zlib.",
"ProcessorArchitectureMalformed": "Failed to parse %PROCESSOR_ARCHITECTURE% ({arch}) as a valid CPU architecture.",
Expand Down
2 changes: 1 addition & 1 deletion src/vcpkg-fuzz/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ namespace
auto res = Json::parse(text);
if (!res)
{
Checks::exit_with_message(VCPKG_LINE_INFO, res.error()->format());
Checks::exit_with_message(VCPKG_LINE_INFO, res.error()->to_string());
}

Checks::exit_success(VCPKG_LINE_INFO);
Expand Down
44 changes: 15 additions & 29 deletions src/vcpkg-test/ci-baseline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,87 +201,73 @@ static void check_error(const std::string& input, const std::string& expected_er
auto actual = parse_ci_baseline(input, "test", m);
CHECK(actual.empty());
CHECK(m.warnings.empty());
CHECK(m.error->format() == expected_error);
CHECK(m.error->to_string() == expected_error);
}

TEST_CASE ("Parse Errors", "[ci-baseline]")
{
check_error("hello", R"(test:1:6: error: expected ':' here
on expression: hello
^
)");
^)");

check_error("hello\n:", R"(test:1:6: error: expected ':' here
on expression: hello
^
)");
^)");

check_error("?example:x64-windows=fail", R"(test:1:1: error: expected a port name here
on expression: ?example:x64-windows=fail
^
)");
^)");

check_error("x64-windows:", R"(test:1:13: error: expected a triplet name here
on expression: x64-windows:
^
)");
^)");

check_error("x64-windows:\nport:x64-windows=skip", R"(test:1:13: error: expected a triplet name here
on expression: x64-windows:
^
)");
^)");

check_error("x64-windows:#", R"(test:1:13: error: expected a triplet name here
on expression: x64-windows:#
^
)");
^)");

// clang-format off
check_error(" \tx64-windows:", R"(test:1:21: error: expected a triplet name here
on expression: )" "\t" R"(x64-windows:
)" "\t" R"( ^
)");
)" "\t" R"( ^)");
// clang-format on

check_error("port:x64-windows\n=fail", R"(test:1:17: error: expected '=' here
on expression: port:x64-windows
^
)");
^)");

check_error("example:x64-windows = \n fail", R"(test:1:26: error: expected 'fail' or 'skip' here
on expression: example:x64-windows =
^
)");
^)");

check_error("example:x64-windows = pass", R"(test:1:28: error: expected 'fail' or 'skip' here
on expression: example:x64-windows = pass
^
)");
^)");

// note that there is 'fail' but doesn't end on a word boundary:
check_error("example:x64-windows = fails", R"(test:1:28: error: expected 'fail' or 'skip' here
on expression: example:x64-windows = fails
^
)");
^)");

check_error("example:x64-windows = fail extra stuff",
R"(test:1:33: error: unrecognizable baseline entry; expected 'port:triplet=(fail|skip)'
on expression: example:x64-windows = fail extra stuff
^
)");
^)");

check_error("example:x64-windows = fail example:x64-windows = fail",
R"(test:1:33: error: unrecognizable baseline entry; expected 'port:triplet=(fail|skip)'
on expression: example:x64-windows = fail example:x64-windows = fail
^
)");
^)");

check_error("example:x64-windows = fail # extra stuff\n"
"example:x64-uwp=skip extra stuff\n",
R"(test:2:22: error: unrecognizable baseline entry; expected 'port:triplet=(fail|skip)'
on expression: example:x64-uwp=skip extra stuff
^
)");
^)");
}

TEST_CASE ("Applies Skips and Fails", "[ci-baseline]")
Expand Down
2 changes: 1 addition & 1 deletion src/vcpkg-test/configmetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static Json::Object parse_json_object(StringView sv)
}
else
{
Checks::exit_with_message(VCPKG_LINE_INFO, json.error()->format());
Checks::exit_with_message(VCPKG_LINE_INFO, json.error()->to_string());
}
}

Expand Down
27 changes: 11 additions & 16 deletions src/vcpkg-test/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ TEST_CASE ("JSON parse full file", "[json]")
auto res = Json::parse(json);
if (!res)
{
std::cerr << res.error()->format() << '\n';
std::cerr << res.error()->to_string() << '\n';
}
REQUIRE(res);
}
Expand All @@ -234,52 +234,47 @@ TEST_CASE ("JSON track newlines", "[json]")
{
auto res = Json::parse("{\n,", "filename");
REQUIRE(!res);
REQUIRE(res.error()->format() ==
REQUIRE(res.error()->to_string() ==
R"(filename:2:1: error: Unexpected character; expected property name
on expression: ,
^
)");
^)");
}

TEST_CASE ("JSON duplicated object keys", "[json]")
{
auto res = Json::parse("{\"name\": 1, \"name\": 2}", "filename");
REQUIRE(!res);
REQUIRE(res.error()->format() ==
REQUIRE(res.error()->to_string() ==
R"(filename:1:13: error: Duplicated key "name" in an object
on expression: {"name": 1, "name": 2}
^
)");
^)");
}

TEST_CASE ("JSON support unicode characters in errors", "[json]")
{
// unicode characters w/ bytes >1
auto res = Json::parse(R"json("Δx/Δt" "")json", "filename");
REQUIRE(!res);
CHECK(res.error()->format() ==
CHECK(res.error()->to_string() ==
R"(filename:1:9: error: Unexpected character; expected EOF
on expression: "Δx/Δt" ""
^
)");
^)");

// full width unicode characters
// note that the A is full width
res = Json::parse(R"json("姐姐aA" "")json", "filename");
REQUIRE(!res);
CHECK(res.error()->format() ==
CHECK(res.error()->to_string() ==
R"(filename:1:8: error: Unexpected character; expected EOF
on expression: "姐姐aA" ""
^
)");
^)");

// incorrect errors in the face of combining characters
// (this test should be fixed once the underlying bug is fixed)
res = Json::parse(R"json("é" "")json", "filename");
REQUIRE(!res);
CHECK(res.error()->format() ==
CHECK(res.error()->to_string() ==
R"(filename:1:6: error: Unexpected character; expected EOF
on expression: "é" ""
^
)");
^)");
}
22 changes: 9 additions & 13 deletions src/vcpkg-test/manifests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static Json::Object parse_json_object(StringView sv)
{
INFO("Error found while parsing JSON document:");
INFO(sv.to_string());
FAIL(json.error()->format());
FAIL(json.error()->to_string());
return Json::Object{};
}
}
Expand Down Expand Up @@ -1050,35 +1050,31 @@ TEST_CASE ("license error messages", "[manifests][license]")
ParseMessages messages;
parse_spdx_license_expression("", messages);
REQUIRE(messages.error);
CHECK(messages.error->format() == R"(<license string>:1:1: error: SPDX license expression was empty.
CHECK(messages.error->to_string() == R"(<license string>:1:1: error: SPDX license expression was empty.
on expression:
^
)");
^)");

parse_spdx_license_expression("MIT ()", messages);
REQUIRE(messages.error);
CHECK(messages.error->format() ==
CHECK(messages.error->to_string() ==
R"(<license string>:1:5: error: Expected a compound or the end of the string, found a parenthesis.
on expression: MIT ()
^
)");
^)");

parse_spdx_license_expression("MIT +", messages);
REQUIRE(messages.error);
CHECK(
messages.error->format() ==
messages.error->to_string() ==
R"(<license string>:1:5: error: SPDX license expression contains an extra '+'. These are only allowed directly after a license identifier.
on expression: MIT +
^
)");
^)");

parse_spdx_license_expression("MIT AND", messages);
REQUIRE(messages.error);
CHECK(messages.error->format() ==
CHECK(messages.error->to_string() ==
R"(<license string>:1:8: error: Expected a license name, found the end of the string.
on expression: MIT AND
^
)");
^)");

parse_spdx_license_expression("MIT AND unknownlicense", messages);
CHECK(!messages.error);
Expand Down
2 changes: 1 addition & 1 deletion src/vcpkg/base/git.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ namespace vcpkg

if (auto error = parser.get_error())
{
return msg::format(msgGitUnexpectedCommandOutput).append_raw(error->format());
return msg::format(msgGitUnexpectedCommandOutput).append_raw('\n').append_raw(error->to_string());
}

return results;
Expand Down
2 changes: 1 addition & 1 deletion src/vcpkg/base/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@ namespace vcpkg::Json
else if (!ret)
{
msg::println_error(msgJsonErrorFailedToParse, msg::path = json_file);
msg::write_unlocalized_text_to_stdout(Color::error, ret.error()->format());
msg::write_unlocalized_text_to_stdout(Color::error, ret.error()->to_string());
msg::println();
Checks::exit_fail(li);
}
Expand Down
Loading