Commit 62d953338b9c4723e73fa142f24217b1893340e1

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent 371f6365

Add TimePattern to parse Hue schedule times.

include/hueplusplus/TimePattern.h 0 → 100644
  1 +/**
  2 + \file TimePattern.h
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#ifndef INCLUDE_HUEPLUSPLUS_TIME_PATTERN
  23 +#define INCLUDE_HUEPLUSPLUS_TIME_PATTERN
  24 +
  25 +#include <chrono>
  26 +#include <string>
  27 +
  28 +namespace hueplusplus
  29 +{
  30 +namespace time
  31 +{
  32 +std::string timepointToTimestamp(std::chrono::system_clock::time_point time);
  33 +std::chrono::system_clock::time_point parseTimestamp(const std::string& timestamp);
  34 +
  35 +std::string durationTo_hh_mm_ss(std::chrono::system_clock::duration duration);
  36 +std::chrono::system_clock::duration parseDuration(const std::string& hourMinSec);
  37 +
  38 +class AbsoluteTime
  39 +{
  40 + using clock = std::chrono::system_clock;
  41 +
  42 +public:
  43 + explicit AbsoluteTime(clock::time_point baseTime, clock::duration variation = std::chrono::seconds(0));
  44 +
  45 + clock::time_point getBaseTime();
  46 + clock::duration getRandomVariation();
  47 +
  48 + std::string toString();
  49 +
  50 +private:
  51 + clock::time_point base;
  52 + clock::duration variation;
  53 +};
  54 +class Weekdays
  55 +{
  56 +public:
  57 + Weekdays() : bitmask(0) {}
  58 + explicit Weekdays(int num) : bitmask(1 << num) {}
  59 +
  60 + bool isNone() const;
  61 + bool isAll() const;
  62 + bool isMonday() const;
  63 + bool isTuesday() const;
  64 + bool isWednesday() const;
  65 + bool isThursday() const;
  66 + bool isFriday() const;
  67 + bool isSaturday() const;
  68 + bool isSunday() const;
  69 +
  70 + Weekdays unionWith(Weekdays other) const;
  71 + Weekdays operator|(Weekdays other) const { return unionWith(other); }
  72 +
  73 + std::string toString() const;
  74 +
  75 + static Weekdays none();
  76 + static Weekdays all();
  77 + static Weekdays monday();
  78 + static Weekdays tuesday();
  79 + static Weekdays wednesday();
  80 + static Weekdays thursday();
  81 + static Weekdays friday();
  82 + static Weekdays saturday();
  83 + static Weekdays sunday();
  84 +
  85 + static Weekdays parse(const std::string& s);
  86 +private:
  87 + int bitmask;
  88 +};
  89 +class RecurringTime
  90 +{
  91 + using clock = std::chrono::system_clock;
  92 +
  93 +public:
  94 + explicit RecurringTime(clock::duration daytime, Weekdays days, clock::duration variation = std::chrono::seconds(0));
  95 +
  96 + clock::duration getDaytime() const;
  97 + clock::duration getRandomVariation() const;
  98 + Weekdays getWeekdays() const;
  99 +
  100 + std::string toString() const;
  101 +
  102 +private:
  103 + clock::duration time;
  104 + clock::duration variation;
  105 + Weekdays days;
  106 +};
  107 +class TimeInterval
  108 +{
  109 + using clock = std::chrono::system_clock;
  110 +
  111 +public:
  112 + TimeInterval(clock::duration start, clock::duration end, Weekdays days = Weekdays::all());
  113 +
  114 + clock::duration getStartTime() const;
  115 + clock::duration getEndTime() const;
  116 + Weekdays getWeekdays() const;
  117 +
  118 + std::string toString() const;
  119 +
  120 +private:
  121 + clock::duration start;
  122 + clock::duration end;
  123 + Weekdays days;
  124 +};
  125 +class Timer
  126 +{
  127 + using clock = std::chrono::system_clock;
  128 +
  129 +public:
  130 + Timer(clock::duration duration, clock::duration variation = std::chrono::seconds(0));
  131 + Timer(clock::duration duration, int numExecutions, clock::duration variation = std::chrono::seconds(0));
  132 +
  133 + bool isRecurring() const;
  134 + int getNumberOfExecutions() const;
  135 + clock::duration getExpiryTime() const;
  136 + clock::duration getRandomVariation() const;
  137 +
  138 + std::string toString() const;
  139 +
  140 +private:
  141 + clock::duration expires;
  142 + clock::duration variation;
  143 + int numExecutions;
  144 +};
  145 +
  146 +class TimePattern
  147 +{
  148 +public:
  149 + enum class Type
  150 + {
  151 + undefined,
  152 + absolute,
  153 + recurring,
  154 + interval,
  155 + timer
  156 + };
  157 +
  158 + TimePattern();
  159 + ~TimePattern();
  160 + explicit TimePattern(const AbsoluteTime& absolute);
  161 + explicit TimePattern(const RecurringTime& recurring);
  162 + explicit TimePattern(const TimeInterval& interval);
  163 + explicit TimePattern(const Timer& timer);
  164 +
  165 + TimePattern(const TimePattern& other);
  166 +
  167 + TimePattern& operator=(const TimePattern& other);
  168 +
  169 + Type getType() const;
  170 +
  171 + AbsoluteTime asAbsolute() const;
  172 +
  173 + RecurringTime asRecurring() const;
  174 +
  175 + TimeInterval asInterval() const;
  176 +
  177 + Timer asTimer() const;
  178 +
  179 + static TimePattern parse(const std::string& s);
  180 +
  181 +private:
  182 + void destroy();
  183 +
  184 +private:
  185 + Type type;
  186 + union
  187 + {
  188 + nullptr_t undefined;
  189 + AbsoluteTime absolute;
  190 + RecurringTime recurring;
  191 + TimeInterval interval;
  192 + Timer timer;
  193 + };
  194 +};
  195 +} // namespace time
  196 +} // namespace hueplusplus
  197 +
  198 +#endif
0 199 \ No newline at end of file
... ...
src/CMakeLists.txt
... ... @@ -12,9 +12,10 @@ set(hueplusplus_SOURCES
12 12 SimpleBrightnessStrategy.cpp
13 13 SimpleColorHueStrategy.cpp
14 14 SimpleColorTemperatureStrategy.cpp
  15 + StateTransaction.cpp
  16 + "TimePattern.cpp"
15 17 UPnP.cpp
16   - Utils.cpp
17   - StateTransaction.cpp)
  18 + Utils.cpp)
18 19  
19 20 # on windows we want to compile the WinHttpHandler
20 21 if(WIN32)
... ...
src/TimePattern.cpp 0 → 100644
  1 +/**
  2 + \file TimePattern.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#include <ctime>
  23 +
  24 +#include <hueplusplus/HueExceptionMacro.h>
  25 +#include <hueplusplus/TimePattern.h>
  26 +
  27 +namespace hueplusplus
  28 +{
  29 +namespace time
  30 +{
  31 +
  32 +using clock = std::chrono::system_clock;
  33 +std::string timepointToTimestamp(clock::time_point time)
  34 +{
  35 + using namespace std::chrono;
  36 + std::time_t ctime = clock::to_time_t(time);
  37 +
  38 + std::tm localtime = *std::localtime(&ctime);
  39 + char buf[32];
  40 +
  41 + std::size_t result = std::strftime(buf, sizeof(buf), "%FT%T", &localtime);
  42 + if (result == 0)
  43 + {
  44 + throw HueException(CURRENT_FILE_INFO, "strftime failed");
  45 + }
  46 + return std::string(buf);
  47 +}
  48 +
  49 +clock::time_point parseTimestamp(const std::string& timestamp)
  50 +{
  51 + std::tm tm;
  52 + tm.tm_year = std::stoi(timestamp.substr(0, 4));
  53 + tm.tm_mon = std::stoi(timestamp.substr(5, 2));
  54 + tm.tm_mday = std::stoi(timestamp.substr(8, 2));
  55 + tm.tm_hour = std::stoi(timestamp.substr(11, 2));
  56 + tm.tm_min = std::stoi(timestamp.substr(14, 2));
  57 + tm.tm_sec = std::stoi(timestamp.substr(17, 2));
  58 + // Auto detect daylight savings time
  59 + tm.tm_isdst = -1;
  60 + std::time_t ctime = std::mktime(&tm);
  61 + return clock::from_time_t(ctime);
  62 +}
  63 +
  64 +std::string durationTo_hh_mm_ss(clock::duration duration)
  65 +{
  66 + using namespace std::chrono;
  67 + if (duration > hours(24))
  68 + {
  69 + throw HueException(CURRENT_FILE_INFO, "Duration parameter longer than 1 day");
  70 + }
  71 + int numH = static_cast<int>(duration_cast<hours>(duration).count());
  72 + duration -= hours(numH);
  73 + int numM = static_cast<int>(duration_cast<minutes>(duration).count());
  74 + duration -= minutes(numM);
  75 + int numS = static_cast<int>(duration_cast<seconds>(duration).count());
  76 +
  77 + char result[9];
  78 + std::sprintf(result, "%02d:%02d:%02d", numH, numM, numS);
  79 + return std::string(result);
  80 +}
  81 +
  82 +clock::duration parseDuration(const std::string& s)
  83 +{
  84 + using namespace std::chrono;
  85 + return hours(std::stoi(s.substr(0, 2))) + minutes(std::stoi(s.substr(3, 2))) + seconds(std::stoi(s.substr(7, 2)));
  86 +}
  87 +
  88 +AbsoluteTime::AbsoluteTime(clock::time_point baseTime, clock::duration variation) : base(baseTime), variation(variation)
  89 +{}
  90 +
  91 +clock::time_point AbsoluteTime::getBaseTime()
  92 +{
  93 + return base;
  94 +}
  95 +clock::duration AbsoluteTime::getRandomVariation()
  96 +{
  97 + return variation;
  98 +}
  99 +std::string AbsoluteTime::toString()
  100 +{
  101 + std::string result = timepointToTimestamp(base);
  102 + if (variation.count() != 0)
  103 + {
  104 + result.push_back('A');
  105 + result.append(durationTo_hh_mm_ss(variation));
  106 + }
  107 + return result;
  108 +}
  109 +
  110 +bool Weekdays::isNone() const
  111 +{
  112 + return bitmask == 0;
  113 +}
  114 +
  115 +bool Weekdays::isAll() const
  116 +{
  117 + // Check all 7 bits are set
  118 + return bitmask == (1 << 7) - 1;
  119 +}
  120 +
  121 +bool Weekdays::isMonday() const
  122 +{
  123 + return (bitmask & 1) != 0;
  124 +}
  125 +
  126 +bool Weekdays::isTuesday() const
  127 +{
  128 + return (bitmask & 2) != 0;
  129 +}
  130 +
  131 +bool Weekdays::isWednesday() const
  132 +{
  133 + return (bitmask & 4) != 0;
  134 +}
  135 +
  136 +bool Weekdays::isThursday() const
  137 +{
  138 + return (bitmask & 8) != 0;
  139 +}
  140 +
  141 +bool Weekdays::isFriday() const
  142 +{
  143 + return (bitmask & 16) != 0;
  144 +}
  145 +
  146 +bool Weekdays::isSaturday() const
  147 +{
  148 + return (bitmask & 32) != 0;
  149 +}
  150 +
  151 +bool Weekdays::isSunday() const
  152 +{
  153 + return (bitmask & 64) != 0;
  154 +}
  155 +
  156 +std::string Weekdays::toString() const
  157 +{
  158 + std::string result = std::to_string(bitmask);
  159 + if (result.size() < 3)
  160 + {
  161 + result.insert(0, 3 - result.size(), '0');
  162 + }
  163 + return result;
  164 +}
  165 +
  166 +Weekdays Weekdays::unionWith(Weekdays other) const
  167 +{
  168 + other.bitmask |= bitmask;
  169 + return other;
  170 +}
  171 +
  172 +Weekdays Weekdays::none()
  173 +{
  174 + return Weekdays();
  175 +}
  176 +
  177 +Weekdays Weekdays::all()
  178 +{
  179 + Weekdays result;
  180 + result.bitmask = (1 << 7) - 1;
  181 + return result;
  182 +}
  183 +
  184 +Weekdays Weekdays::monday()
  185 +{
  186 + return Weekdays(0);
  187 +}
  188 +
  189 +Weekdays Weekdays::tuesday()
  190 +{
  191 + return Weekdays(1);
  192 +}
  193 +
  194 +Weekdays Weekdays::wednesday()
  195 +{
  196 + return Weekdays(2);
  197 +}
  198 +
  199 +Weekdays Weekdays::thursday()
  200 +{
  201 + return Weekdays(3);
  202 +}
  203 +
  204 +Weekdays Weekdays::friday()
  205 +{
  206 + return Weekdays(4);
  207 +}
  208 +
  209 +Weekdays Weekdays::saturday()
  210 +{
  211 + return Weekdays(5);
  212 +}
  213 +
  214 +Weekdays Weekdays::sunday()
  215 +{
  216 + return Weekdays(6);
  217 +}
  218 +
  219 +Weekdays Weekdays::parse(const std::string& s)
  220 +{
  221 + Weekdays result;
  222 + result.bitmask = std::stoi(s);
  223 + return result;
  224 +}
  225 +
  226 +RecurringTime::RecurringTime(clock::duration daytime, Weekdays days, clock::duration variation)
  227 + : time(daytime), days(days), variation(variation)
  228 +{}
  229 +
  230 +clock::duration RecurringTime::getDaytime() const
  231 +{
  232 + return time;
  233 +}
  234 +
  235 +clock::duration RecurringTime::getRandomVariation() const
  236 +{
  237 + return variation;
  238 +}
  239 +
  240 +Weekdays RecurringTime::getWeekdays() const
  241 +{
  242 + return days;
  243 +}
  244 +
  245 +std::string RecurringTime::toString() const
  246 +{
  247 + std::string result = "W";
  248 + result.append(days.toString());
  249 + result.append("/");
  250 + result.append(durationTo_hh_mm_ss(time));
  251 + if (variation.count() != 0)
  252 + {
  253 + result.push_back('A');
  254 + result.append(durationTo_hh_mm_ss(variation));
  255 + }
  256 + return std::string();
  257 +}
  258 +
  259 +TimeInterval::TimeInterval(clock::duration start, clock::duration end, Weekdays days)
  260 + : start(start), end(end), days(days)
  261 +{}
  262 +
  263 +clock::duration TimeInterval::getStartTime() const
  264 +{
  265 + return start;
  266 +}
  267 +
  268 +clock::duration TimeInterval::getEndTime() const
  269 +{
  270 + return end;
  271 +}
  272 +
  273 +Weekdays TimeInterval::getWeekdays() const
  274 +{
  275 + return days;
  276 +}
  277 +
  278 +std::string TimeInterval::toString() const
  279 +{
  280 + std::string result;
  281 + if (!days.isAll())
  282 + {
  283 + result.append("W");
  284 + result.append(days.toString());
  285 + result.append("/");
  286 + }
  287 + result.push_back('T');
  288 + result.append(durationTo_hh_mm_ss(start));
  289 + result.append("/T");
  290 + result.append(durationTo_hh_mm_ss(end));
  291 +
  292 + return result;
  293 +}
  294 +
  295 +Timer::Timer(clock::duration duration, clock::duration variation)
  296 + : expires(duration), numExecutions(1), variation(variation)
  297 +{}
  298 +
  299 +Timer::Timer(clock::duration duration, int numExecutions, clock::duration variation)
  300 + : expires(duration), numExecutions(numExecutions), variation(variation)
  301 +{}
  302 +
  303 +bool Timer::isRecurring() const
  304 +{
  305 + return numExecutions != 1;
  306 +}
  307 +
  308 +int Timer::getNumberOfExecutions() const
  309 +{
  310 + return numExecutions;
  311 +}
  312 +
  313 +clock::duration Timer::getExpiryTime() const
  314 +{
  315 + return expires;
  316 +}
  317 +
  318 +clock::duration Timer::getRandomVariation() const
  319 +{
  320 + return variation;
  321 +}
  322 +
  323 +std::string Timer::toString() const
  324 +{
  325 + std::string result;
  326 + if (numExecutions != 1)
  327 + {
  328 + result.push_back('R');
  329 + if (numExecutions != 0)
  330 + {
  331 + std::string s = std::to_string(numExecutions);
  332 + // Pad to two digits
  333 + if (s.size() < 2)
  334 + {
  335 + result.push_back('0');
  336 + }
  337 + result.append(s);
  338 + }
  339 + result.push_back('/');
  340 + }
  341 + result.append("PT");
  342 + result.append(durationTo_hh_mm_ss(expires));
  343 + if (variation.count() != 0)
  344 + {
  345 + result.push_back('A');
  346 + result.append(durationTo_hh_mm_ss(variation));
  347 + }
  348 + return result;
  349 +}
  350 +
  351 +TimePattern::TimePattern() : type(Type::undefined), undefined(nullptr) {}
  352 +
  353 +TimePattern::~TimePattern()
  354 +{
  355 + destroy();
  356 +}
  357 +
  358 +TimePattern::TimePattern(const AbsoluteTime& absolute) : type(Type::absolute)
  359 +{
  360 + new (&this->absolute) AbsoluteTime(absolute);
  361 +}
  362 +
  363 +TimePattern::TimePattern(const RecurringTime& recurring) : type(Type::recurring)
  364 +{
  365 + new (&this->recurring) RecurringTime(recurring);
  366 +}
  367 +
  368 +TimePattern::TimePattern(const TimeInterval& interval) : type(Type::interval)
  369 +{
  370 + new (&this->interval) TimeInterval(interval);
  371 +}
  372 +
  373 +TimePattern::TimePattern(const Timer& timer) : type(Type::timer)
  374 +{
  375 + new (&this->timer) Timer(timer);
  376 +}
  377 +
  378 +TimePattern::TimePattern(const TimePattern& other) : type(Type::undefined), undefined(nullptr)
  379 +{
  380 + *this = other;
  381 +}
  382 +
  383 +TimePattern& TimePattern::operator=(const TimePattern& other)
  384 +{
  385 + if (this == &other)
  386 + {
  387 + return *this;
  388 + }
  389 + destroy();
  390 + try
  391 + {
  392 + type = other.type;
  393 + switch (type)
  394 + {
  395 + case Type::undefined:
  396 + undefined = nullptr;
  397 + break;
  398 + case Type::absolute:
  399 + new (&absolute) AbsoluteTime(other.absolute);
  400 + break;
  401 + case Type::recurring:
  402 + new (&recurring) RecurringTime(other.recurring);
  403 + break;
  404 + case Type::interval:
  405 + new (&interval) TimeInterval(other.interval);
  406 + break;
  407 + case Type::timer:
  408 + new (&timer) Timer(other.timer);
  409 + break;
  410 + }
  411 + }
  412 + catch (...)
  413 + {
  414 + // Catch any throws from constructors to stay in valid state
  415 + type = Type::undefined;
  416 + undefined = nullptr;
  417 + throw;
  418 + }
  419 + return *this;
  420 +}
  421 +
  422 +TimePattern::Type TimePattern::getType() const
  423 +{
  424 + return type;
  425 +}
  426 +
  427 +AbsoluteTime TimePattern::asAbsolute() const
  428 +{
  429 + return absolute;
  430 +}
  431 +
  432 +RecurringTime TimePattern::asRecurring() const
  433 +{
  434 + return recurring;
  435 +}
  436 +
  437 +TimeInterval TimePattern::asInterval() const
  438 +{
  439 + return interval;
  440 +}
  441 +
  442 +Timer TimePattern::asTimer() const
  443 +{
  444 + return timer;
  445 +}
  446 +
  447 +TimePattern TimePattern::parse(const std::string& s)
  448 +{
  449 + if (s.empty() || s == "none")
  450 + {
  451 + return TimePattern();
  452 + }
  453 + else if (std::isdigit(s.front()))
  454 + {
  455 + // Absolute time
  456 + clock::time_point time = parseTimestamp(s);
  457 + clock::duration variation {0};
  458 + if (s.size() > 19 && s[19] == 'A')
  459 + {
  460 + // Random variation
  461 + variation = parseDuration(s.substr(20));
  462 + }
  463 + return TimePattern(AbsoluteTime(time, variation));
  464 + }
  465 + else if (s.front() == 'R' || s.front() == 'P')
  466 + {
  467 + // (Recurring) timer
  468 + int numRepetitions = 1;
  469 + if (s.front() == 'R')
  470 + {
  471 + if (s.at(1) == '/')
  472 + {
  473 + // Infinite
  474 + numRepetitions = -1;
  475 + }
  476 + else
  477 + {
  478 + numRepetitions = std::stoi(s.substr(1, 2));
  479 + }
  480 + }
  481 + std::size_t start = s.find('T') + 1;
  482 + std::size_t randomStart = s.find('A');
  483 + clock::duration expires = parseDuration(s.substr(start, randomStart - start));
  484 + clock::duration variance = std::chrono::seconds(0);
  485 + if (randomStart != std::string::npos)
  486 + {
  487 + variance = parseDuration(s.substr(randomStart));
  488 + }
  489 + return TimePattern(Timer(expires, numRepetitions, variance));
  490 + }
  491 + else if (s.front() == 'W' && std::count(s.begin(), s.end(), '/') == 1)
  492 + {
  493 + // Recurring time
  494 + Weekdays days = Weekdays::parse(s.substr(1, 3));
  495 + clock::duration time = parseDuration(s.substr(6));
  496 + clock::duration variation {0};
  497 + if (s.size() > 14)
  498 + {
  499 + variation = parseDuration(s.substr(15));
  500 + }
  501 + return TimePattern(RecurringTime(time, days, variation));
  502 + }
  503 + else if (s.front() == 'T' || s.front() == 'W')
  504 + {
  505 + Weekdays days = Weekdays::all();
  506 + if (s.front() == 'W')
  507 + {
  508 + // Time interval with weekdays
  509 + days = Weekdays::parse(s.substr(1, 3));
  510 + }
  511 + // Time interval
  512 + std::size_t start = s.find('T') + 1;
  513 + std::size_t end = s.find('/', start);
  514 + clock::duration startTime = parseDuration(s.substr(start, end - start));
  515 + clock::duration endTime = parseDuration(s.substr(end + 2));
  516 + return TimePattern(TimeInterval(startTime, endTime, days));
  517 + }
  518 + throw HueException(CURRENT_FILE_INFO, "Unable to parse time string: " + s);
  519 +}
  520 +
  521 +void TimePattern::destroy()
  522 +{
  523 + switch (type)
  524 + {
  525 + case Type::absolute:
  526 + absolute.~AbsoluteTime();
  527 + break;
  528 + case Type::recurring:
  529 + recurring.~RecurringTime();
  530 + break;
  531 + case Type::interval:
  532 + interval.~TimeInterval();
  533 + break;
  534 + case Type::timer:
  535 + timer.~Timer();
  536 + break;
  537 + default:
  538 + break;
  539 + }
  540 + type = Type::undefined;
  541 + undefined = nullptr;
  542 +}
  543 +
  544 +} // namespace time
  545 +} // namespace hueplusplus
... ...
test/CMakeLists.txt
... ... @@ -44,7 +44,8 @@ set(TEST_SOURCES
44 44 test_SimpleColorHueStrategy.cpp
45 45 test_SimpleColorTemperatureStrategy.cpp
46 46 test_UPnP.cpp
47   - test_StateTransaction.cpp)
  47 + test_StateTransaction.cpp
  48 + test_TimePattern.cpp)
48 49  
49 50 set(HuePlusPlus_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include")
50 51  
... ...
test/test_TimePattern.cpp 0 → 100644
  1 +/**
  2 + \file test_TimePattern.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#include <gtest/gtest.h>
  23 +#include <hueplusplus/TimePattern.h>
  24 +
  25 +using namespace hueplusplus::time;
  26 +using std::chrono::system_clock;
  27 +using namespace std::chrono_literals;
  28 +
  29 +TEST(AbsoluteTime, Constructor)
  30 +{
  31 + system_clock::time_point now = system_clock::now();
  32 + {
  33 + AbsoluteTime time(now);
  34 + EXPECT_EQ(now, time.getBaseTime());
  35 + EXPECT_EQ(0s, time.getRandomVariation());
  36 + }
  37 + system_clock::duration variation = 4h + 2min;
  38 + {
  39 + AbsoluteTime time(now, variation);
  40 + EXPECT_EQ(now, time.getBaseTime());
  41 + EXPECT_EQ(variation, time.getRandomVariation());
  42 + }
  43 +}
  44 +
  45 +TEST(AbsoluteTime, toString)
  46 +{
  47 + std::tm time {};
  48 + time.tm_year = 2020 - 1900;
  49 + time.tm_mon = 2;
  50 + time.tm_mday = 3;
  51 + time.tm_hour = 20;
  52 + time.tm_min = 53;
  53 + time.tm_sec = 3;
  54 + std::time_t ctime = std::mktime(&time);
  55 + const system_clock::time_point timePoint = system_clock::from_time_t(ctime);
  56 +
  57 + EXPECT_EQ("2020-03-03T20:53:03", AbsoluteTime(timePoint).toString());
  58 +
  59 + const system_clock::duration noVariation = 0s;
  60 + EXPECT_EQ("2020-03-03T20:53:03", AbsoluteTime(timePoint, noVariation).toString());
  61 +
  62 + const system_clock::duration variation = 1h + 2min + 1s;
  63 + EXPECT_EQ("2020-03-03T20:53:03A01:02:01", AbsoluteTime(timePoint, variation).toString());
  64 +}
  65 +
  66 +TEST(Weekdays, Constructor)
  67 +{
  68 + EXPECT_TRUE(Weekdays().isNone());
  69 + EXPECT_TRUE(Weekdays(0).isMonday());
  70 + EXPECT_TRUE(Weekdays(6).isSunday());
  71 +}
  72 +
  73 +TEST(Weekdays, isXXX)
  74 +{
  75 + Weekdays none = Weekdays::none();
  76 + EXPECT_TRUE(none.isNone());
  77 + EXPECT_FALSE(none.isAll());
  78 + EXPECT_FALSE(none.isMonday());
  79 + EXPECT_FALSE(none.isTuesday());
  80 + EXPECT_FALSE(none.isWednesday());
  81 + EXPECT_FALSE(none.isThursday());
  82 + EXPECT_FALSE(none.isFriday());
  83 + EXPECT_FALSE(none.isSaturday());
  84 + EXPECT_FALSE(none.isSunday());
  85 +
  86 + Weekdays all = Weekdays::all();
  87 + EXPECT_FALSE(all.isNone());
  88 + EXPECT_TRUE(all.isAll());
  89 + EXPECT_TRUE(all.isMonday());
  90 + EXPECT_TRUE(all.isTuesday());
  91 + EXPECT_TRUE(all.isWednesday());
  92 + EXPECT_TRUE(all.isThursday());
  93 + EXPECT_TRUE(all.isFriday());
  94 + EXPECT_TRUE(all.isSaturday());
  95 + EXPECT_TRUE(all.isSunday());
  96 +
  97 + // Test that for all days, only their own isXXX function is true
  98 + std::vector<Weekdays> days {Weekdays::monday(), Weekdays::tuesday(), Weekdays::wednesday(), Weekdays::thursday(),
  99 + Weekdays::friday(), Weekdays::saturday(), Weekdays::sunday()};
  100 + using BoolGetter = bool (Weekdays::*)() const;
  101 + std::vector<BoolGetter> getters {&Weekdays::isMonday, &Weekdays::isTuesday, &Weekdays::isWednesday,
  102 + &Weekdays::isThursday, &Weekdays::isFriday, &Weekdays::isSaturday, &Weekdays::isSunday};
  103 + for (int i = 0; i < days.size(); ++i)
  104 + {
  105 + Weekdays day = days[i];
  106 + EXPECT_FALSE(day.isNone());
  107 + EXPECT_FALSE(day.isAll());
  108 + for (int j = 0; j < getters.size(); ++j)
  109 + {
  110 + EXPECT_EQ(j == i, (day.*getters[j])()) << "on Day " << i << ": getter for day " << j << " has wrong result";
  111 + }
  112 + }
  113 +}
  114 +
  115 +TEST(Weekdays, unionWith)
  116 +{
  117 + Weekdays day = Weekdays::monday().unionWith(Weekdays::saturday());
  118 + EXPECT_TRUE(day.isMonday());
  119 + EXPECT_TRUE(day.isSaturday());
  120 +
  121 + day = Weekdays::monday() | Weekdays::tuesday() | Weekdays::all();
  122 + EXPECT_TRUE(day.isAll());
  123 +}
  124 +
  125 +TEST(Weekdays, toString)
  126 +{
  127 + EXPECT_EQ("001", Weekdays(0).toString());
  128 + EXPECT_EQ("064", Weekdays(6).toString());
  129 + EXPECT_EQ("112", (Weekdays(6) | Weekdays(5) | Weekdays(4)).toString());
  130 +}
... ...