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

[libc++] Improve diagnostic when failing to parse the tzdb #122125

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
20 changes: 15 additions & 5 deletions libcxx/src/experimental/tzdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html

#include <__assert>
#include <algorithm>
#include <cctype>
#include <chrono>
Expand Down Expand Up @@ -97,14 +98,23 @@ static void __skip(istream& __input, string_view __suffix) {
}

static void __matches(istream& __input, char __expected) {
if (std::tolower(__input.get()) != __expected)
std::__throw_runtime_error((string("corrupt tzdb: expected character '") + __expected + '\'').c_str());
_LIBCPP_ASSERT_INTERNAL(!std::isalpha(__expected) || std::islower(__expected), "lowercase characters only here!");
char __c = __input.get();
if (std::tolower(__c) != __expected)
std::__throw_runtime_error(
(string("corrupt tzdb: expected character '") + __expected + "', got '" + __c + "' instead").c_str());
}

static void __matches(istream& __input, string_view __expected) {
for (auto __c : __expected)
if (std::tolower(__input.get()) != __c)
std::__throw_runtime_error((string("corrupt tzdb: expected string '") + string(__expected) + '\'').c_str());
for (auto __c : __expected) {
_LIBCPP_ASSERT_INTERNAL(!std::isalpha(__c) || std::islower(__c), "lowercase strings only here!");
char __actual = __input.get();
if (std::tolower(__actual) != __c)
std::__throw_runtime_error(
(string("corrupt tzdb: expected character '") + __c + "' from string '" + string(__expected) + "', got '" +
__actual + "' instead")
.c_str());
}
}

[[nodiscard]] static string __parse_string(istream& __input) {
Expand Down
15 changes: 10 additions & 5 deletions libcxx/test/libcxx/time/time.zone/time.zone.db/rules.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
// ADDITIONAL_COMPILE_FLAGS: -I %{libcxx-dir}/src/experimental/include

#include <chrono>
#include <cstdio>
#include <fstream>
#include <string>
#include <string_view>
#include <string>
#include <variant>

#include "assert_macros.h"
Expand Down Expand Up @@ -96,7 +97,7 @@ static void test_invalid() {
test_exception("R r 0 mix", "corrupt tzdb: expected whitespace");
test_exception("R r 0 1", "corrupt tzdb: expected whitespace");

test_exception("R r 0 1 X", "corrupt tzdb: expected character '-'");
test_exception("R r 0 1 X", "corrupt tzdb: expected character '-', got 'X' instead");

test_exception("R r 0 1 -", "corrupt tzdb: expected whitespace");

Expand All @@ -106,13 +107,17 @@ static void test_invalid() {

test_exception("R r 0 1 - Ja +", "corrupt tzdb weekday: invalid name");
test_exception("R r 0 1 - Ja 32", "corrupt tzdb day: value too large");
test_exception("R r 0 1 - Ja l", "corrupt tzdb: expected string 'last'");
test_exception(
"R r 0 1 - Ja l",
std::string{"corrupt tzdb: expected character 'a' from string 'last', got '"} + (char)EOF + "' instead");
test_exception("R r 0 1 - Ja last", "corrupt tzdb weekday: invalid name");
test_exception("R r 0 1 - Ja lastS", "corrupt tzdb weekday: invalid name");
test_exception("R r 0 1 - Ja S", "corrupt tzdb weekday: invalid name");
test_exception("R r 0 1 - Ja Su", "corrupt tzdb on: expected '>=' or '<='");
test_exception("R r 0 1 - Ja Su>", "corrupt tzdb: expected character '='");
test_exception("R r 0 1 - Ja Su<", "corrupt tzdb: expected character '='");
test_exception(
"R r 0 1 - Ja Su>", std::string{"corrupt tzdb: expected character '=', got '"} + (char)EOF + "' instead");
test_exception(
"R r 0 1 - Ja Su<", std::string{"corrupt tzdb: expected character '=', got '"} + (char)EOF + "' instead");
test_exception("R r 0 1 - Ja Su>=+", "corrupt tzdb: expected a non-zero digit");
test_exception("R r 0 1 - Ja Su>=0", "corrupt tzdb: expected a non-zero digit");
test_exception("R r 0 1 - Ja Su>=32", "corrupt tzdb day: value too large");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
// This is not part of the public tzdb interface.

#include <chrono>
#include <cstdio>
#include <fstream>
#include <string>
#include <string_view>
#include <string>

#include "assert_macros.h"
#include "concat_macros.h"
Expand Down Expand Up @@ -60,7 +61,7 @@ static void test_exception(std::string_view input, [[maybe_unused]] std::string_
}

int main(int, const char**) {
test_exception("", "corrupt tzdb: expected character '#'");
test_exception("", std::string{"corrupt tzdb: expected character '#', got '"} + (char)EOF + "' instead");
test_exception("#version", "corrupt tzdb: expected whitespace");
test("#version \t ABCD", "ABCD");
test("#Version \t ABCD", "ABCD");
Expand Down
Loading