lib/core/unittest/CTimeUtilsTest.cc (464 lines of code) (raw):

/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the following additional limitation. Functionality enabled by the * files subject to the Elastic License 2.0 may only be used in production when * invoked by an Elasticsearch process with a license key installed that permits * use of machine learning features. You may not use this file except in * compliance with the Elastic License 2.0 and the foregoing additional * limitation. */ #include <core/CCTimeR.h> #include <core/CLogger.h> #include <core/CTimeUtils.h> #include <core/CTimezone.h> #include <boost/test/unit_test.hpp> #include <chrono> #include <ctime> #include <thread> BOOST_AUTO_TEST_SUITE(CTimeUtilsTest) BOOST_AUTO_TEST_CASE(testNow) { ml::core_t::TTime t1(ml::core::CTimeUtils::now()); std::int64_t t1Ms(ml::core::CTimeUtils::nowMs()); std::this_thread::sleep_for(std::chrono::milliseconds(1001)); ml::core_t::TTime t2(ml::core::CTimeUtils::now()); std::int64_t t2Ms(ml::core::CTimeUtils::nowMs()); BOOST_TEST_REQUIRE(t2 > t1); BOOST_TEST_REQUIRE(t2Ms > t1Ms); } BOOST_AUTO_TEST_CASE(testToIso8601) { // These tests assume UK time. In case they're ever run outside the UK, // we'll explicitly set the timezone for the purpose of these tests. BOOST_TEST_REQUIRE(ml::core::CTimezone::setTimezone("Europe/London")); { ml::core_t::TTime t(1227710437); std::string expected("2008-11-26T14:40:37+0000"); const std::string strRep = ml::core::CTimeUtils::toIso8601(t); BOOST_REQUIRE_EQUAL(expected, strRep); } { ml::core_t::TTime t(1207925624); std::string expected("2008-04-11T15:53:44+0100"); const std::string strRep = ml::core::CTimeUtils::toIso8601(t); BOOST_REQUIRE_EQUAL(expected, strRep); } } BOOST_AUTO_TEST_CASE(testToLocal) { // These tests assume UK time. In case they're ever run outside the UK, // we'll explicitly set the timezone for the purpose of these tests. BOOST_TEST_REQUIRE(ml::core::CTimezone::setTimezone("Europe/London")); { ml::core_t::TTime t(1227710437); std::string expected("Wed Nov 26 14:40:37 2008"); const std::string strRep = ml::core::CTimeUtils::toLocalString(t); BOOST_REQUIRE_EQUAL(expected, strRep); } { ml::core_t::TTime t(1207925624); std::string expected("Fri Apr 11 15:53:44 2008"); const std::string strRep = ml::core::CTimeUtils::toLocalString(t); BOOST_REQUIRE_EQUAL(expected, strRep); } { ml::core_t::TTime t(1207925624); std::string expected("15:53:44"); const std::string strRep = ml::core::CTimeUtils::toTimeString(t); BOOST_REQUIRE_EQUAL(expected, strRep); } } BOOST_AUTO_TEST_CASE(testToEpochMs) { BOOST_REQUIRE_EQUAL(1000, ml::core::CTimeUtils::toEpochMs(ml::core_t::TTime(1))); BOOST_REQUIRE_EQUAL(-1000, ml::core::CTimeUtils::toEpochMs(ml::core_t::TTime(-1))); BOOST_REQUIRE_EQUAL(1521035866000, ml::core::CTimeUtils::toEpochMs(ml::core_t::TTime(1521035866))); BOOST_REQUIRE_EQUAL(-1521035866000, ml::core::CTimeUtils::toEpochMs(ml::core_t::TTime(-1521035866))); } BOOST_AUTO_TEST_CASE(testStrptime) { // These tests assume UK time. In case they're ever run outside the UK, // we'll explicitly set the timezone for the purpose of these tests. BOOST_TEST_REQUIRE(ml::core::CTimezone::setTimezone("Europe/London")); { // This time is deliberately chosen to be during daylight saving time std::string dateTime("1122334455"); std::string format("%s"); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); #ifndef Windows // This fails on Windows unless the operating system timezone is set to UK time. // This means that using %s as a time format doesn't work on Windows. The reason // is that the underlying strptime() returns a struct tm, so the seemingly most // simple conversion gets round-tripped through an intermediate step that relies // on timezone functionality. A fix would be non-trivial, and since this problem // doesn't affect production code it's not worth the effort. In the production // code all date parsing is done in the Java code. Date parsing is only used in // the C++ code when running a program for test/debug purposes with the // --timeformat option. Generally we'd be doing this on macOS or Linux, but even // if someone did want to do testing/debugging on Windows by simply not specifying // the --timeformat option the time is assumed to be in epoch format and converted // by a simple string to number conversion rather than using strptime(). So it // really would be a waste of effort getting %s to work on Windows at this time. ml::core_t::TTime expected(1122334455); BOOST_REQUIRE_EQUAL(expected, actual); #endif } { std::string dateTime("2008-11-26 14:40:37"); std::string format("%Y-%m-%d %H:%M:%S"); ml::core_t::TTime expected(1227710437); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); std::string badDateTime("2008-11-26 25:40:37"); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::strptime(format, badDateTime, actual)); } { std::string dateTime("10/31/2008 3:15:00 AM"); std::string format("%m/%d/%Y %I:%M:%S %p"); ml::core_t::TTime expected(1225422900); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); LOG_DEBUG(<< actual); } { std::string dateTime("Fri Oct 31 3:15:00 AM GMT 08"); std::string format("%a %b %d %I:%M:%S %p %Z %y"); ml::core_t::TTime expected(1225422900); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); LOG_DEBUG(<< actual); } { std::string dateTime("Tue Jun 23 17:24:55 2009"); std::string format("%a %b %d %T %Y"); ml::core_t::TTime expected(1245774295); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); LOG_DEBUG(<< actual); } { std::string dateTime("Tue Jun 23 17:24:55 BST 2009"); std::string format("%a %b %d %T %Z %Y"); ml::core_t::TTime expected(1245774295); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); LOG_DEBUG(<< actual); } { // This time is in summer, but explicitly specifies a GMT offset of 0, // so we should get 1245777895 instead of 1245774295 std::string dateTime("Tue Jun 23 17:24:55 2009 +0000"); std::string format("%a %b %d %T %Y %z"); ml::core_t::TTime expected(1245777895); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); LOG_DEBUG(<< actual); std::string badDateTime1("Tue Jun 23 17:24:55 2009"); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::strptime(format, badDateTime1, actual)); std::string badDateTime2("Tue Jun 23 17:24:55 2009 0000"); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::strptime(format, badDateTime2, actual)); } { // Test what happens when no year is given std::string dateTime("Jun 23 17:24:55"); std::string format("%b %d %T"); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); LOG_DEBUG(<< actual); // This test is only approximate (assuming leap year with leap second), so // print a warning too BOOST_TEST_REQUIRE(actual >= ml::core::CTimeUtils::now() - 366 * 24 * 60 * 60 - 1); char buf[128] = {'\0'}; LOG_WARN(<< "If the following date is not within the last year then something is wrong: " << ml::core::CCTimeR::cTimeR(&actual, buf)); // Allow small tolerance in case of clock discrepancies between machines BOOST_TEST_REQUIRE(actual <= ml::core::CTimeUtils::now() + ml::core::CTimeUtils::MAX_CLOCK_DISCREPANCY); } { // Test what happens when no year is given std::string dateTime("Jan 01 01:24:55"); std::string format("%b %d %T"); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); LOG_DEBUG(<< actual); // This test is only approximate (assuming leap year with leap second), so // print a warning too BOOST_TEST_REQUIRE(actual >= ml::core::CTimeUtils::now() - 366 * 24 * 60 * 60 - 1); char buf[128] = {'\0'}; LOG_WARN(<< "If the following date is not within the last year then something is wrong: " << ml::core::CCTimeR::cTimeR(&actual, buf)); // Allow small tolerance in case of clock discrepancies between machines BOOST_TEST_REQUIRE(actual <= ml::core::CTimeUtils::now() + ml::core::CTimeUtils::MAX_CLOCK_DISCREPANCY); } { // Test what happens when no year is given std::string dateTime("Dec 31 23:24:55"); std::string format("%b %d %T"); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); LOG_DEBUG(<< actual); // This test is only approximate (assuming leap year with leap second), so // print a warning too BOOST_TEST_REQUIRE(actual >= ml::core::CTimeUtils::now() - 366 * 24 * 60 * 60 - 1); char buf[128] = {'\0'}; LOG_WARN(<< "If the following date is not within the last year then something is wrong: " << ml::core::CCTimeR::cTimeR(&actual, buf)); // Allow small tolerance in case of clock discrepancies between machines BOOST_TEST_REQUIRE(actual <= ml::core::CTimeUtils::now() + ml::core::CTimeUtils::MAX_CLOCK_DISCREPANCY); } } BOOST_AUTO_TEST_CASE(testTimezone) { static const ml::core_t::TTime SECONDS_PER_HOUR = 3600; // These convert the same date/time to a Unix time, but in a variety of // different timezones. Since Unix times represent seconds since the epoch // UTC, the timezone will change the results. std::string format("%Y-%m-%d %H:%M:%S"); std::string dateTime("2008-11-26 14:40:37"); // Additionally, for each timezone, we'll try converting the same time, // but with UTC explicitly specified. This should always come up with // the utcExpected time. Also, to exercise the time convertor, we'll // explicitly specify 2 hours behind GMT (although it's unlikely this // would ever occur in a real log file). std::string formatExplicit("%Y-%m-%d %H:%M:%S %z"); std::string dateTimeUtc("2008-11-26 14:40:37 +0000"); ml::core_t::TTime utcExpected(1227710437); std::string dateTimeTwoHoursBehindUtc("2008-11-26 14:40:37 -0200"); ml::core_t::TTime twoHoursBehindUtc(utcExpected + 2 * SECONDS_PER_HOUR); // UK first BOOST_TEST_REQUIRE(ml::core::CTimezone::setTimezone("Europe/London")); { ml::core_t::TTime expected(utcExpected); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(formatExplicit, dateTimeUtc, actual)); BOOST_REQUIRE_EQUAL(utcExpected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime( formatExplicit, dateTimeTwoHoursBehindUtc, actual)); BOOST_REQUIRE_EQUAL(twoHoursBehindUtc, actual); } // US eastern time: 5 hours behind the UK (except during daylight saving // time switchover) BOOST_TEST_REQUIRE(ml::core::CTimezone::setTimezone("America/New_York")); { // The Unix time is in UTC, and UTC will be 5 hours ahead of US eastern // time at this time of the year (UTC is only 4 hours ahead in summer). ml::core_t::TTime expected(utcExpected + 5 * SECONDS_PER_HOUR); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(formatExplicit, dateTimeUtc, actual)); BOOST_REQUIRE_EQUAL(utcExpected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime( formatExplicit, dateTimeTwoHoursBehindUtc, actual)); BOOST_REQUIRE_EQUAL(twoHoursBehindUtc, actual); } // US Pacific time: 8 hours behind the UK (except during daylight saving // time switchover) BOOST_TEST_REQUIRE(ml::core::CTimezone::setTimezone("America/Los_Angeles")); { ml::core_t::TTime expected(utcExpected + 8 * SECONDS_PER_HOUR); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(formatExplicit, dateTimeUtc, actual)); BOOST_REQUIRE_EQUAL(utcExpected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime( formatExplicit, dateTimeTwoHoursBehindUtc, actual)); BOOST_REQUIRE_EQUAL(twoHoursBehindUtc, actual); } // Australian central time: 9.5 hours ahead of GMT all year around in the // Northern Territory; in South Australia, 9.5 hours ahead of GMT in the // (southern hemisphere) winter and 10.5 hours ahead of GMT in the (southern // hemisphere) summer. // Northern Territory first BOOST_TEST_REQUIRE(ml::core::CTimezone::setTimezone("Australia/Darwin")); { ml::core_t::TTime expected( utcExpected - static_cast<ml::core_t::TTime>(9.5 * SECONDS_PER_HOUR)); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(formatExplicit, dateTimeUtc, actual)); BOOST_REQUIRE_EQUAL(utcExpected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime( formatExplicit, dateTimeTwoHoursBehindUtc, actual)); BOOST_REQUIRE_EQUAL(twoHoursBehindUtc, actual); } // Now South Australia - remember, 26th November is summer in Australia, // so daylight saving is in force BOOST_TEST_REQUIRE(ml::core::CTimezone::setTimezone("Australia/Adelaide")); { ml::core_t::TTime expected( utcExpected - static_cast<ml::core_t::TTime>(10.5 * SECONDS_PER_HOUR)); ml::core_t::TTime actual(0); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(format, dateTime, actual)); BOOST_REQUIRE_EQUAL(expected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime(formatExplicit, dateTimeUtc, actual)); BOOST_REQUIRE_EQUAL(utcExpected, actual); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::strptime( formatExplicit, dateTimeTwoHoursBehindUtc, actual)); BOOST_REQUIRE_EQUAL(twoHoursBehindUtc, actual); } // Set the timezone back to nothing, i.e. let the operating system decide // what to use BOOST_TEST_REQUIRE(ml::core::CTimezone::setTimezone("")); } BOOST_AUTO_TEST_CASE(testDateWords) { // These tests assume they're being run in an English speaking country LOG_DEBUG(<< "Checking day of week abbreviations"); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Mon")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Tue")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Wed")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Thu")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Fri")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Sat")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Sun")); LOG_DEBUG(<< "Checking full days of week"); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Monday")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Tuesday")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Wednesday")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Thursday")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Friday")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Saturday")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Sunday")); LOG_DEBUG(<< "Checking non-days of week"); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Money")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Tues")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Wedding")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Thug")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Fried")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Satanic")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Sunburn")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Ml")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Dave")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Hello")); LOG_DEBUG(<< "Checking month abbreviations"); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Jan")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Feb")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Mar")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Apr")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("May")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Jun")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Jul")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Aug")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Sep")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Oct")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Nov")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("Dec")); LOG_DEBUG(<< "Checking full months"); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("January")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("February")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("March")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("April")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("May")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("June")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("July")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("August")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("September")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("October")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("November")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("December")); LOG_DEBUG(<< "Checking non-months"); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Jane")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Febrile")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Market")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Apricot")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Maybe")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Junk")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Juliet")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Augment")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Separator")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Octet")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Novel")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Decadent")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Table")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Chair")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("Laptop")); LOG_DEBUG(<< "Checking time zones"); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("GMT")); BOOST_TEST_REQUIRE(ml::core::CTimeUtils::isDateWord("UTC")); LOG_DEBUG(<< "Checking space"); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord(" ")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord("\t")); BOOST_TEST_REQUIRE(!ml::core::CTimeUtils::isDateWord(" \t")); } BOOST_AUTO_TEST_CASE(testDurationToString) { ml::core_t::TTime s = 1; ml::core_t::TTime m = 60 * s; ml::core_t::TTime h = 60 * m; ml::core_t::TTime d = 24 * h; BOOST_REQUIRE_EQUAL("0s", ml::core::CTimeUtils::durationToString(0)); BOOST_REQUIRE_EQUAL("1s", ml::core::CTimeUtils::durationToString(s)); BOOST_REQUIRE_EQUAL("1m", ml::core::CTimeUtils::durationToString(m)); BOOST_REQUIRE_EQUAL("1h", ml::core::CTimeUtils::durationToString(h)); BOOST_REQUIRE_EQUAL("1d", ml::core::CTimeUtils::durationToString(d)); BOOST_REQUIRE_EQUAL("1m1s", ml::core::CTimeUtils::durationToString(m + s)); BOOST_REQUIRE_EQUAL("1h1m", ml::core::CTimeUtils::durationToString(h + m)); BOOST_REQUIRE_EQUAL("1h1s", ml::core::CTimeUtils::durationToString(h + s)); BOOST_REQUIRE_EQUAL("1h1m1s", ml::core::CTimeUtils::durationToString(h + m + s)); BOOST_REQUIRE_EQUAL("1d1h1m1s", ml::core::CTimeUtils::durationToString(d + h + m + s)); BOOST_REQUIRE_EQUAL("7d12h", ml::core::CTimeUtils::durationToString(7 * d + 12 * h)); BOOST_REQUIRE_EQUAL("365d5h48m46s", ml::core::CTimeUtils::durationToString( 365 * d + 5 * h + 48 * m + 46 * s)); } BOOST_AUTO_TEST_CASE(testTimeDurationStringToSeconds) { bool parsedOk{false}; ml::core_t::TTime durationSeconds{0}; const ml::core_t::TTime defaultValue{1}; { // All valid and specifying a whole number of seconds std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("14d", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(1209600, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("14D", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(1209600, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("24h", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(86400, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("24H", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(86400, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("15m", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(900, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("15M", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(900, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("30s", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(30, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("30S", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(30, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("2000ms", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(2, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("2000MS", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(2, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("3000000micros", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(3, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("3000000MICROS", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(3, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("3000000MiCrOs", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(3, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("4000000000nanos", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(4, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("4000000000NANOS", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(4, durationSeconds); } { // Valid and equating to a fractional number of seconds. We expect the returned value to be rounded // down to the nearest whole number of seconds std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("2500ms", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(2, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("3800000micros", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(3, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("4900000000nanos", defaultValue); BOOST_TEST_REQUIRE(parsedOk); BOOST_REQUIRE_EQUAL(4, durationSeconds); } { // All invalid formats std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("2w", defaultValue); BOOST_TEST_REQUIRE(!parsedOk); BOOST_REQUIRE_EQUAL(1, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("14days", defaultValue); BOOST_TEST_REQUIRE(!parsedOk); BOOST_REQUIRE_EQUAL(1, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("24hrs", defaultValue); BOOST_TEST_REQUIRE(!parsedOk); BOOST_REQUIRE_EQUAL(1, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("15minutes", defaultValue); BOOST_TEST_REQUIRE(!parsedOk); BOOST_REQUIRE_EQUAL(1, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("30seconds", defaultValue); BOOST_TEST_REQUIRE(!parsedOk); BOOST_REQUIRE_EQUAL(1, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("2.5s", defaultValue); BOOST_TEST_REQUIRE(!parsedOk); BOOST_REQUIRE_EQUAL(1, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds("2000millis", defaultValue); BOOST_TEST_REQUIRE(!parsedOk); BOOST_REQUIRE_EQUAL(1, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds( "3000000Microseconds", defaultValue); BOOST_TEST_REQUIRE(!parsedOk); BOOST_REQUIRE_EQUAL(1, durationSeconds); std::tie(durationSeconds, parsedOk) = ml::core::CTimeUtils::timeDurationStringToSeconds( "4000000000nanoseconds", defaultValue); BOOST_TEST_REQUIRE(!parsedOk); BOOST_REQUIRE_EQUAL(1, durationSeconds); } } BOOST_AUTO_TEST_SUITE_END()