mirror of
https://github.com/PerMalmberg/libcron.git
synced 2025-04-22 08:23:04 -05:00
Validation of days vs. months with more tests.
This commit is contained in:
parent
f7442f6972
commit
cb6a7958e8
@ -1,5 +1,8 @@
|
|||||||
|
#include <date.h>
|
||||||
#include "CronData.h"
|
#include "CronData.h"
|
||||||
|
|
||||||
|
using namespace date;
|
||||||
|
|
||||||
namespace libcron
|
namespace libcron
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -33,6 +36,7 @@ namespace libcron
|
|||||||
valid &= validate_numeric<DayOfMonth>(match[4], day_of_month);
|
valid &= validate_numeric<DayOfMonth>(match[4], day_of_month);
|
||||||
valid &= validate_literal<Months>(match[5], months, month_names);
|
valid &= validate_literal<Months>(match[5], months, month_names);
|
||||||
valid &= validate_literal<DayOfWeek>(match[6], day_of_week, day_names);
|
valid &= validate_literal<DayOfWeek>(match[6], day_of_week, day_names);
|
||||||
|
valid &= validate_date_vs_months();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,11 +63,52 @@ namespace libcron
|
|||||||
return !s.empty()
|
return !s.empty()
|
||||||
&& std::find_if(s.begin(), s.end(),
|
&& std::find_if(s.begin(), s.end(),
|
||||||
[](char c)
|
[](char c)
|
||||||
{ return !std::isdigit(c); }) == s.end();
|
{
|
||||||
|
return !std::isdigit(c);
|
||||||
|
}) == s.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CronData::is_between(int32_t value, int32_t low_limit, int32_t high_limt)
|
bool CronData::is_between(int32_t value, int32_t low_limit, int32_t high_limt)
|
||||||
{
|
{
|
||||||
return value >= low_limit && value <= high_limt;
|
return value >= low_limit && value <= high_limt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CronData::validate_date_vs_months() const
|
||||||
|
{
|
||||||
|
bool res = true;
|
||||||
|
|
||||||
|
// Verify that the available dates are possible based on the given months
|
||||||
|
if (months.find(static_cast<Months>(2)) != months.end())
|
||||||
|
{
|
||||||
|
// February allowed, make sure that the allowed date(s) includes 29 and below.
|
||||||
|
res = has_any_in_range(day_of_month, 1, 29);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(res)
|
||||||
|
{
|
||||||
|
// Make sure that if the days contains only 31, at least one month allows that date.
|
||||||
|
if(day_of_month.size() == 1 && day_of_month.find(DayOfMonth::Last) != day_of_month.end())
|
||||||
|
{
|
||||||
|
std::vector<int32_t> months_with_31;
|
||||||
|
for (int32_t i = 1; i <= 12; ++i)
|
||||||
|
{
|
||||||
|
auto ymd = 2018_y / i / date::last;
|
||||||
|
if (unsigned(ymd.day()) == 31)
|
||||||
|
{
|
||||||
|
months_with_31.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = false;
|
||||||
|
for(size_t i = 0; !res && i < months_with_31.size(); ++i)
|
||||||
|
{
|
||||||
|
auto month = months_with_31[i];
|
||||||
|
res = months.find(static_cast<Months>(month)) != months.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
@ -101,6 +101,18 @@ namespace libcron
|
|||||||
return static_cast<uint8_t>(t);
|
return static_cast<uint8_t>(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static bool has_any_in_range(const std::set<T>& set, uint8_t low, uint8_t high)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (auto i = low; !found && i <= high; ++i)
|
||||||
|
{
|
||||||
|
found |= set.find(static_cast<T>(i)) != set.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void parse(const std::string& cron_expression);
|
void parse(const std::string& cron_expression);
|
||||||
@ -134,6 +146,8 @@ namespace libcron
|
|||||||
|
|
||||||
bool is_between(int32_t value, int32_t low_limit, int32_t high_limit);
|
bool is_between(int32_t value, int32_t low_limit, int32_t high_limit);
|
||||||
|
|
||||||
|
bool validate_date_vs_months() const;
|
||||||
|
|
||||||
std::set<Seconds> seconds{};
|
std::set<Seconds> seconds{};
|
||||||
std::set<Minutes> minutes{};
|
std::set<Minutes> minutes{};
|
||||||
std::set<Hours> hours{};
|
std::set<Hours> hours{};
|
||||||
|
@ -53,14 +53,10 @@ SCENARIO("Calculating next runtime")
|
|||||||
REQUIRE(test("0 0 10 * FEB 1", DT(2017_y / 12 / 31, hours{23}, minutes{59}, seconds{58}), DT(year_month_day{2018_y/2/mon[1]}, hours{10})));
|
REQUIRE(test("0 0 10 * FEB 1", DT(2017_y / 12 / 31, hours{23}, minutes{59}, seconds{58}), DT(year_month_day{2018_y/2/mon[1]}, hours{10})));
|
||||||
REQUIRE(test("0 0 10 * FEB 6", DT(2017_y / 12 / 31, hours{23}, minutes{59}, seconds{58}), DT(year_month_day{2018_y/2/sat[1]}, hours{10})));
|
REQUIRE(test("0 0 10 * FEB 6", DT(2017_y / 12 / 31, hours{23}, minutes{59}, seconds{58}), DT(year_month_day{2018_y/2/sat[1]}, hours{10})));
|
||||||
REQUIRE(test("* * * 10-12 NOV *", DT(2018_y / 11 / 11, hours{10}, minutes{11}, seconds{12}), DT(year_month_day{2018_y/11/11}, hours{10}, minutes{11}, seconds{12})));
|
REQUIRE(test("* * * 10-12 NOV *", DT(2018_y / 11 / 11, hours{10}, minutes{11}, seconds{12}), DT(year_month_day{2018_y/11/11}, hours{10}, minutes{11}, seconds{12})));
|
||||||
|
REQUIRE(test("0 0 * 31 APR,MAY *", DT(2017_y / 6 / 1), DT(2018_y / may / 31)));
|
||||||
}
|
}
|
||||||
|
|
||||||
SCENARIO("Leap year")
|
SCENARIO("Leap year")
|
||||||
{
|
{
|
||||||
REQUIRE(test("0 0 * 29 FEB *", DT(2018_y / 1 / 1), DT(2020_y / 2 / 29)));
|
REQUIRE(test("0 0 * 29 FEB *", DT(2018_y / 1 / 1), DT(2020_y / 2 / 29)));
|
||||||
}
|
}
|
||||||
|
|
||||||
SCENARIO("Date that does not exist")
|
|
||||||
{
|
|
||||||
//REQUIRE_FALSE(test("0 0 * 30 FEB *", DT(2018_y / 1 / 1), DT(2020_y / 2 / 29)));
|
|
||||||
}
|
|
@ -21,17 +21,7 @@ bool has_value_range(const std::set<T>& set, uint8_t low, uint8_t high)
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool has_any_in_range(const std::set<T>& set, uint8_t low, uint8_t high)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (auto i = low; !found && i <= high; ++i)
|
|
||||||
{
|
|
||||||
found |= set.find(static_cast<T>(i)) != set.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
SCENARIO("Numerical inputs")
|
SCENARIO("Numerical inputs")
|
||||||
{
|
{
|
||||||
@ -159,7 +149,7 @@ SCENARIO("Literal input")
|
|||||||
auto c = CronData::create("* * * * JAN-MAR,DEC *");
|
auto c = CronData::create("* * * * JAN-MAR,DEC *");
|
||||||
REQUIRE(c.is_valid());
|
REQUIRE(c.is_valid());
|
||||||
REQUIRE(has_value_range(c.get_months(), 1, 3));
|
REQUIRE(has_value_range(c.get_months(), 1, 3));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_months(), 4, 11));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_months(), 4, 11));
|
||||||
REQUIRE(has_value_range(c.get_months(), 12, 12));
|
REQUIRE(has_value_range(c.get_months(), 12, 12));
|
||||||
}
|
}
|
||||||
AND_THEN("Range is valid")
|
AND_THEN("Range is valid")
|
||||||
@ -167,14 +157,14 @@ SCENARIO("Literal input")
|
|||||||
auto c = CronData::create("* * * * JAN-MAR,DEC FRI,MON,THU");
|
auto c = CronData::create("* * * * JAN-MAR,DEC FRI,MON,THU");
|
||||||
REQUIRE(c.is_valid());
|
REQUIRE(c.is_valid());
|
||||||
REQUIRE(has_value_range(c.get_months(), 1, 3));
|
REQUIRE(has_value_range(c.get_months(), 1, 3));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_months(), 4, 11));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_months(), 4, 11));
|
||||||
REQUIRE(has_value_range(c.get_months(), 12, 12));
|
REQUIRE(has_value_range(c.get_months(), 12, 12));
|
||||||
REQUIRE(has_value_range(c.get_day_of_week(), 5, 5));
|
REQUIRE(has_value_range(c.get_day_of_week(), 5, 5));
|
||||||
REQUIRE(has_value_range(c.get_day_of_week(), 1, 1));
|
REQUIRE(has_value_range(c.get_day_of_week(), 1, 1));
|
||||||
REQUIRE(has_value_range(c.get_day_of_week(), 4, 4));
|
REQUIRE(has_value_range(c.get_day_of_week(), 4, 4));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_day_of_week(), 0, 0));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_day_of_week(), 0, 0));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_day_of_week(), 2, 3));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_day_of_week(), 2, 3));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_day_of_week(), 6, 6));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_day_of_week(), 6, 6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AND_WHEN("Using backward range")
|
AND_WHEN("Using backward range")
|
||||||
@ -185,7 +175,7 @@ SCENARIO("Literal input")
|
|||||||
REQUIRE(c.is_valid());
|
REQUIRE(c.is_valid());
|
||||||
REQUIRE(has_value_range(c.get_months(), 4, 12));
|
REQUIRE(has_value_range(c.get_months(), 4, 12));
|
||||||
REQUIRE(has_value_range(c.get_months(), 1, 1));
|
REQUIRE(has_value_range(c.get_months(), 1, 1));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_months(), 2, 3));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_months(), 2, 3));
|
||||||
}
|
}
|
||||||
AND_THEN("Range is valid")
|
AND_THEN("Range is valid")
|
||||||
{
|
{
|
||||||
@ -193,7 +183,7 @@ SCENARIO("Literal input")
|
|||||||
REQUIRE(c.is_valid());
|
REQUIRE(c.is_valid());
|
||||||
REQUIRE(has_value_range(c.get_day_of_week(), 6, 6)); // Has saturday
|
REQUIRE(has_value_range(c.get_day_of_week(), 6, 6)); // Has saturday
|
||||||
REQUIRE(has_value_range(c.get_day_of_week(), 0, 3)); // Has sun, mon, tue, wed
|
REQUIRE(has_value_range(c.get_day_of_week(), 0, 3)); // Has sun, mon, tue, wed
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_day_of_week(), 4, 5)); // Does not have thu or fri.
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_day_of_week(), 4, 5)); // Does not have thu or fri.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,15 +205,25 @@ SCENARIO("Using step syntax")
|
|||||||
REQUIRE(has_value_range(c.get_months(), 7, 7));
|
REQUIRE(has_value_range(c.get_months(), 7, 7));
|
||||||
REQUIRE(has_value_range(c.get_months(), 9, 9));
|
REQUIRE(has_value_range(c.get_months(), 9, 9));
|
||||||
REQUIRE(has_value_range(c.get_months(), 11, 11));
|
REQUIRE(has_value_range(c.get_months(), 11, 11));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_months(), 2, 2));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_months(), 2, 2));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_months(), 4, 4));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_months(), 4, 4));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_months(), 6, 6));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_months(), 6, 6));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_months(), 8, 8));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_months(), 8, 8));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_months(), 10, 10));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_months(), 10, 10));
|
||||||
REQUIRE_FALSE(has_any_in_range(c.get_months(), 12, 12));
|
REQUIRE_FALSE(CronData::has_any_in_range(c.get_months(), 12, 12));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCENARIO("Dates that does not exist")
|
||||||
|
{
|
||||||
|
REQUIRE_FALSE(CronData::create("0 0 * 30 FEB *").is_valid());
|
||||||
|
REQUIRE_FALSE(CronData::create("0 0 * 31 APR *").is_valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("Date that exist in one of the months")
|
||||||
|
{
|
||||||
|
REQUIRE(CronData::create("0 0 * 31 APR,MAY *").is_valid());
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user