mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-09-18 10:28:09 +08:00
fix: Merge branch 'check-datetime'
Briefly check if a given date and time is valid
This commit is contained in:
@@ -17,6 +17,11 @@ BOOST_AUTO_TEST_CASE(test_time)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.99", toml::local_time(7, 32, 0, 990, 0));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.999", toml::local_time(7, 32, 0, 999, 0));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.999999", toml::local_time(7, 32, 0, 999, 999));
|
||||
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "00:00:00.000000", toml::local_time( 0, 0, 0, 0, 0));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "23:59:59.999999", toml::local_time(23, 59, 59, 999, 999));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "23:59:60.999999", toml::local_time(23, 59, 60, 999, 999)); // leap second
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_time_value)
|
||||
@@ -25,17 +30,125 @@ BOOST_AUTO_TEST_CASE(test_time_value)
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.99", toml::value(toml::local_time(7, 32, 0, 990, 0)));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.999", toml::value(toml::local_time(7, 32, 0, 999, 0)));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.999999", toml::value(toml::local_time(7, 32, 0, 999, 999)));
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "00:00:00.000000", toml::value(toml::local_time( 0, 0, 0, 0, 0)));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "23:59:59.999999", toml::value(toml::local_time(23, 59, 59, 999, 999)));
|
||||
|
||||
std::istringstream stream1(std::string("invalid-datetime = 24:00:00"));
|
||||
std::istringstream stream2(std::string("invalid-datetime = 00:60:00"));
|
||||
std::istringstream stream3(std::string("invalid-datetime = 00:00:61"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream3), toml::syntax_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_date)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "1979-05-27",
|
||||
toml::local_date(1979, toml::month_t::May, 27));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "1979-05-27", toml::local_date(1979, toml::month_t::May, 27));
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-01-01", toml::local_date(2000, toml::month_t::Jan, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-01-31", toml::local_date(2000, toml::month_t::Jan, 31));
|
||||
std::istringstream stream1_1(std::string("invalid-datetime = 2000-01-00"));
|
||||
std::istringstream stream1_2(std::string("invalid-datetime = 2000-01-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream1_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream1_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-02-01", toml::local_date(2000, toml::month_t::Feb, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-02-29", toml::local_date(2000, toml::month_t::Feb, 29));
|
||||
std::istringstream stream2_1(std::string("invalid-datetime = 2000-02-00"));
|
||||
std::istringstream stream2_2(std::string("invalid-datetime = 2000-02-30"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2001-02-28", toml::local_date(2001, toml::month_t::Feb, 28));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2004-02-29", toml::local_date(2004, toml::month_t::Feb, 29));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2100-02-28", toml::local_date(2100, toml::month_t::Feb, 28));
|
||||
std::istringstream stream2_3(std::string("invalid-datetime = 2001-02-29"));
|
||||
std::istringstream stream2_4(std::string("invalid-datetime = 2004-02-30"));
|
||||
std::istringstream stream2_5(std::string("invalid-datetime = 2100-02-29"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_3), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_4), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_5), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-03-01", toml::local_date(2000, toml::month_t::Mar, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-03-31", toml::local_date(2000, toml::month_t::Mar, 31));
|
||||
std::istringstream stream3_1(std::string("invalid-datetime = 2000-03-00"));
|
||||
std::istringstream stream3_2(std::string("invalid-datetime = 2000-03-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream3_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream3_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-04-01", toml::local_date(2000, toml::month_t::Apr, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-04-30", toml::local_date(2000, toml::month_t::Apr, 30));
|
||||
std::istringstream stream4_1(std::string("invalid-datetime = 2000-04-00"));
|
||||
std::istringstream stream4_2(std::string("invalid-datetime = 2000-04-31"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream4_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream4_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-05-01", toml::local_date(2000, toml::month_t::May, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-05-31", toml::local_date(2000, toml::month_t::May, 31));
|
||||
std::istringstream stream5_1(std::string("invalid-datetime = 2000-05-00"));
|
||||
std::istringstream stream5_2(std::string("invalid-datetime = 2000-05-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream5_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream5_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-06-01", toml::local_date(2000, toml::month_t::Jun, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-06-30", toml::local_date(2000, toml::month_t::Jun, 30));
|
||||
std::istringstream stream6_1(std::string("invalid-datetime = 2000-06-00"));
|
||||
std::istringstream stream6_2(std::string("invalid-datetime = 2000-06-31"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream6_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream6_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-07-01", toml::local_date(2000, toml::month_t::Jul, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-07-31", toml::local_date(2000, toml::month_t::Jul, 31));
|
||||
std::istringstream stream7_1(std::string("invalid-datetime = 2000-07-00"));
|
||||
std::istringstream stream7_2(std::string("invalid-datetime = 2000-07-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream7_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream7_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-08-01", toml::local_date(2000, toml::month_t::Aug, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-08-31", toml::local_date(2000, toml::month_t::Aug, 31));
|
||||
std::istringstream stream8_1(std::string("invalid-datetime = 2000-08-00"));
|
||||
std::istringstream stream8_2(std::string("invalid-datetime = 2000-08-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream8_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream8_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-09-01", toml::local_date(2000, toml::month_t::Sep, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-09-30", toml::local_date(2000, toml::month_t::Sep, 30));
|
||||
std::istringstream stream9_1(std::string("invalid-datetime = 2000-09-00"));
|
||||
std::istringstream stream9_2(std::string("invalid-datetime = 2000-09-31"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream9_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream9_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-10-01", toml::local_date(2000, toml::month_t::Oct, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-10-31", toml::local_date(2000, toml::month_t::Oct, 31));
|
||||
std::istringstream stream10_1(std::string("invalid-datetime = 2000-10-00"));
|
||||
std::istringstream stream10_2(std::string("invalid-datetime = 2000-10-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream10_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream10_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-11-01", toml::local_date(2000, toml::month_t::Nov, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-11-30", toml::local_date(2000, toml::month_t::Nov, 30));
|
||||
std::istringstream stream11_1(std::string("invalid-datetime = 2000-11-00"));
|
||||
std::istringstream stream11_2(std::string("invalid-datetime = 2000-11-31"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream11_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream11_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-12-01", toml::local_date(2000, toml::month_t::Dec, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-12-31", toml::local_date(2000, toml::month_t::Dec, 31));
|
||||
std::istringstream stream12_1(std::string("invalid-datetime = 2000-12-00"));
|
||||
std::istringstream stream12_2(std::string("invalid-datetime = 2000-12-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream12_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream12_2), toml::syntax_error);
|
||||
|
||||
std::istringstream stream13_1(std::string("invalid-datetime = 2000-13-01"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream13_1), toml::syntax_error);
|
||||
std::istringstream stream0_1(std::string("invalid-datetime = 2000-00-01"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream0_1), toml::syntax_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_date_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27",
|
||||
value(toml::local_date(1979, toml::month_t::May, 27)));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27", value(toml::local_date(1979, toml::month_t::May, 27)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_datetime)
|
||||
@@ -107,6 +220,11 @@ BOOST_AUTO_TEST_CASE(test_offset_datetime)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_offset_datetime, "1979-05-27T07:32:00.999999+09:00",
|
||||
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||
toml::local_time(7, 32, 0, 999, 999), toml::time_offset(9, 0)));
|
||||
|
||||
std::istringstream stream1(std::string("invalid-datetime = 2000-01-01T00:00:00+24:00"));
|
||||
std::istringstream stream2(std::string("invalid-datetime = 2000-01-01T00:00:00+00:60"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2), toml::syntax_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_offset_datetime_value)
|
||||
|
@@ -736,11 +736,28 @@ parse_local_date(location& loc)
|
||||
const auto month = static_cast<std::int8_t >(from_string<int>(m.unwrap().str(), 0));
|
||||
const auto day = static_cast<std::int8_t >(from_string<int>(d.unwrap().str(), 0));
|
||||
|
||||
// this could be improved a bit more, but is it ... really ... needed?
|
||||
if(31 < day)
|
||||
// We briefly check whether the input date is valid or not. But here, we
|
||||
// only check if the RFC3339 compliance.
|
||||
// Actually there are several special date that does not exist,
|
||||
// because of historical reasons, such as 1582/10/5-1582/10/14 (only in
|
||||
// several countries). But here, we do not care about such a complicated
|
||||
// rule. It makes the code complicated and there is only low probability
|
||||
// that such a specific date is needed in practice. If someone need to
|
||||
// validate date accurately, that means that the one need a specialized
|
||||
// library for their purpose in a different layer.
|
||||
{
|
||||
throw syntax_error(format_underline("toml::parse_date: invalid date",
|
||||
{{source_location(loc), "here"}}), source_location(loc));
|
||||
const bool is_leap = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
|
||||
const auto max_day = (month == 2) ? (is_leap ? 29 : 28) :
|
||||
((month == 4 || month == 6 || month == 9 || month == 11) ? 30 : 31);
|
||||
|
||||
if((month < 1 || 12 < month) || (day < 1 || max_day < day))
|
||||
{
|
||||
throw syntax_error(format_underline("toml::parse_date: "
|
||||
"invalid date: it does not conform RFC3339.", {{
|
||||
source_location(loc), "month should be 01-12, day should be"
|
||||
" 01-28,29,30,31, depending on month/year."
|
||||
}}), source_location(inner_loc));
|
||||
}
|
||||
}
|
||||
return ok(std::make_pair(local_date(year, static_cast<month_t>(month - 1), day),
|
||||
token.unwrap()));
|
||||
@@ -787,10 +804,22 @@ parse_local_time(location& loc)
|
||||
{{source_location(inner_loc), "here"}}),
|
||||
source_location(inner_loc));
|
||||
}
|
||||
local_time time(
|
||||
from_string<int>(h.unwrap().str(), 0),
|
||||
from_string<int>(m.unwrap().str(), 0),
|
||||
from_string<int>(s.unwrap().str(), 0), 0, 0);
|
||||
|
||||
const int hour = from_string<int>(h.unwrap().str(), 0);
|
||||
const int minute = from_string<int>(m.unwrap().str(), 0);
|
||||
const int second = from_string<int>(s.unwrap().str(), 0);
|
||||
|
||||
if((hour < 0 || 23 < hour) || (minute < 0 || 59 < minute) ||
|
||||
(second < 0 || 60 < second)) // it may be leap second
|
||||
{
|
||||
throw syntax_error(format_underline("toml::parse_time: "
|
||||
"invalid time: it does not conform RFC3339.", {{
|
||||
source_location(loc), "hour should be 00-23, minute should be"
|
||||
" 00-59, second should be 00-60 (depending on the leap"
|
||||
" second rules.)"}}), source_location(inner_loc));
|
||||
}
|
||||
|
||||
local_time time(hour, minute, second, 0, 0);
|
||||
|
||||
const auto before_secfrac = inner_loc.iter();
|
||||
if(const auto secfrac = lex_time_secfrac::invoke(inner_loc))
|
||||
@@ -904,15 +933,26 @@ parse_offset_datetime(location& loc)
|
||||
if(const auto ofs = lex_time_numoffset::invoke(inner_loc))
|
||||
{
|
||||
const auto str = ofs.unwrap().str();
|
||||
|
||||
const auto hour = from_string<int>(str.substr(1,2), 0);
|
||||
const auto minute = from_string<int>(str.substr(4,2), 0);
|
||||
|
||||
if((hour < 0 || 23 < hour) || (minute < 0 || 59 < minute))
|
||||
{
|
||||
throw syntax_error(format_underline("toml::parse_offset_datetime: "
|
||||
"invalid offset: it does not conform RFC3339.", {{
|
||||
source_location(loc), "month should be 01-12, day should be"
|
||||
" 01-28,29,30,31, depending on month/year."
|
||||
}}), source_location(inner_loc));
|
||||
}
|
||||
|
||||
if(str.front() == '+')
|
||||
{
|
||||
offset = time_offset(from_string<int>(str.substr(1,2), 0),
|
||||
from_string<int>(str.substr(4,2), 0));
|
||||
offset = time_offset(hour, minute);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = time_offset(-from_string<int>(str.substr(1,2), 0),
|
||||
-from_string<int>(str.substr(4,2), 0));
|
||||
offset = time_offset(-hour, -minute);
|
||||
}
|
||||
}
|
||||
else if(*inner_loc.iter() != 'Z' && *inner_loc.iter() != 'z')
|
||||
|
Reference in New Issue
Block a user