diff --git a/src/metkit/mars/StepRange.cc b/src/metkit/mars/StepRange.cc index 27cd537..1763f54 100644 --- a/src/metkit/mars/StepRange.cc +++ b/src/metkit/mars/StepRange.cc @@ -9,6 +9,8 @@ */ #include "metkit/mars/StepRange.h" +#include "metkit/mars/TypeTime.h" +#include "metkit/mars/TypeRange.h" #include "eckit/exception/Exceptions.h" #include "eckit/persist/DumpLoad.h" @@ -16,8 +18,71 @@ using namespace eckit; -namespace metkit { -namespace mars { + +//---------------------------------------------------------------------------------------------------------------------- + +namespace { + +enum TimeUnit { + Second = 0, + Minute = 1, + Hour = 2, + Day = 3 +}; + +TimeUnit maxUnit(const eckit::Time& t) { + if (t.seconds() == 0) { + if (t.minutes() == 0) { + if (t.hours() == 0) { + return TimeUnit::Day; + } + return TimeUnit::Hour; + } + return TimeUnit::Minute; + } + return TimeUnit::Second; +} + +std::string canonical(const eckit::Time& time) { + + long h = time.hours(); + long m = time.minutes(); + long s = time.seconds(); + + // std::cout << h << "h" << m << "m" << s << "s\n"; + std::string out = ""; + if (h!=0 || (m==0 && s==0)) { + out += std::to_string(h); + if (m!=0 || s!=0) { + out += "h"; + } + } + if (m!=0) { + out += std::to_string(m) + "m"; + } + if (s!=0) { + out += std::to_string(s) + "s"; + } + return out; +} + +std::string canonical(const eckit::Time& time, TimeUnit unit) { + switch (unit) { + case TimeUnit::Second: + return std::to_string(time.seconds()+60*time.minutes()+3600*time.hours()) + "s"; + case TimeUnit::Minute: + return std::to_string(time.minutes()+60*time.hours()) + "m"; + case TimeUnit::Day: + case TimeUnit::Hour: + default: + return std::to_string(time.hours()); + } +} + +} + +namespace metkit::mars { + //---------------------------------------------------------------------------------------------------------------------- @@ -31,11 +96,11 @@ StepRange::operator std::string() const void StepRange::print(std::ostream& s) const { if(from_ == to_) { - s << from_; + s << canonical(from_); } else { - s << from_ << '-'; - s << to_; + TimeUnit unit = std::min(maxUnit(from_), maxUnit(to_)); + s << canonical(from_,unit) << '-' << canonical(to_,unit); } } @@ -51,12 +116,12 @@ StepRange::StepRange(const std::string& s): switch(result.size()) { case 1: - from_ = to_ = atof(result[0].c_str()); + to_ = from_ = eckit::Time(result[0], true); break; case 2: - from_ = atof(result[0].c_str()); - to_ = atof(result[1].c_str()); + from_ = eckit::Time(result[0], true); + to_ = eckit::Time(result[1], true); break; default: @@ -65,21 +130,23 @@ StepRange::StepRange(const std::string& s): throw eckit::BadValue(msg.str(), Here()); break; } - } void StepRange::dump(DumpLoad& a) const { - a.dump(from_); - a.dump(to_); + a.dump(from_.seconds()/3600.); + a.dump(to_.seconds()/3600.); } void StepRange::load(DumpLoad& a) { - a.load(from_); - a.load(to_); + double from, to; + a.load(from); + a.load(to); + + from_ = eckit::Time(from*3600., true); + to_ = eckit::Time(to*3600., true); } //---------------------------------------------------------------------------------------------------------------------- -} // namespace mars -} // namespace metkit +} // namespace metkit::mars diff --git a/src/metkit/mars/StepRange.h b/src/metkit/mars/StepRange.h index 7ff0bf3..72b5671 100644 --- a/src/metkit/mars/StepRange.h +++ b/src/metkit/mars/StepRange.h @@ -16,11 +16,11 @@ #include "eckit/persist/Bless.h" #include "eckit/types/Types.h" +#include "eckit/types/Time.h" namespace eckit { class DumpLoad; } -namespace metkit { -namespace mars { +namespace metkit::mars { //---------------------------------------------------------------------------------------------------------------------- @@ -34,8 +34,17 @@ class StepRange { StepRange(const std::string&); - StepRange(double from = 0,double to = 0): - from_(from),to_(to) {} + StepRange(eckit::Time from = eckit::Time(0), eckit::Time to = eckit::Time(0)): + from_(from),to_(to) { + + if (from_ != eckit::Time(0) && to_ == eckit::Time(0)) { + to_ = from_; + } + } + + StepRange(double from, double to = 0): + StepRange(eckit::Time(from*3600, true), eckit::Time(to*3600, true)) {} + #include "metkit/mars/StepRange.b" @@ -65,8 +74,8 @@ class StepRange { // -- Methods - double from() const { return from_; } - double to() const { return to_; } + double from() const { return from_/3600.; } + double to() const { return to_/3600.; } void dump(eckit::DumpLoad&) const; void load(eckit::DumpLoad&); @@ -106,8 +115,8 @@ class StepRange { // -- Members - double from_; - double to_; + eckit::Time from_; + eckit::Time to_; // -- Methods // None @@ -130,7 +139,6 @@ class StepRange { //---------------------------------------------------------------------------------------------------------------------- -} // namespace mars -} // namespace metkit +} // namespace metkit::mars #endif diff --git a/src/metkit/mars/TypeRange.cc b/src/metkit/mars/TypeRange.cc index b5680fe..27e03b4 100644 --- a/src/metkit/mars/TypeRange.cc +++ b/src/metkit/mars/TypeRange.cc @@ -7,22 +7,30 @@ * granted to it by virtue of its status as an intergovernmental organisation nor * does it submit to any jurisdiction. */ +#include -#include "eckit/utils/Translator.h" +#include "metkit/mars/TypeRange.h" -#include "metkit/mars/MarsRequest.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/utils/StringTools.h" +#include "eckit/utils/Tokenizer.h" +#include "metkit/config/LibMetkit.h" +#include "metkit/mars/MarsLanguage.h" +#include "metkit/mars/Quantile.h" #include "metkit/mars/TypesFactory.h" -#include "metkit/mars/TypeRange.h" -#include "eckit/utils/StringTools.h" +#include "metkit/mars/TypeTime.h" +#include "metkit/mars/StepRange.h" -namespace metkit { -namespace mars { +namespace metkit::mars { //---------------------------------------------------------------------------------------------------------------------- TypeRange::TypeRange(const std::string &name, const eckit::Value& settings) : - TypeToByList(name, settings) { + Type(name, settings), + by_((std::string)settings["by"]) { + + multiple_ = true; } TypeRange::~TypeRange() { @@ -32,84 +40,107 @@ void TypeRange::print(std::ostream &out) const { out << "TypeRange[name=" << name_ << "]"; } +bool TypeRange::expand(const MarsExpandContext& ctx, std::string& value) const { -bool TypeRange::expand(const MarsExpandContext& ctx, std::string &value) const { + eckit::Tokenizer parse("-"); + std::vector result; - long p = 0; - if (ok(value, p)) { - static eckit::Translator l2s; - value = l2s(p); - return true; + parse(value, result); + switch (result.size()) { + case 1: { + value = StepRange(eckit::Time(result[0], true)); + return true; + } + case 2: { + eckit::Time start = eckit::Time(result[0], true); + eckit::Time end = eckit::Time(result[1], true); + if (start > end) { + std::ostringstream oss; + std::cout << result[0] << " - " << result[1] << std::endl; + oss << name_ + ": initial value " << start << " cannot be greater that final value " << end; + throw eckit::BadValue(oss.str()); + } + value = StepRange(start, end); + return true; + } + default: + std::ostringstream oss; + oss << name_ + ": invalid value " << value << " " << result.size(); + throw eckit::BadValue(oss.str()); } + return false; +} - long a = 0; - long b = 0; +void TypeRange::expand(const MarsExpandContext& ctx, std::vector& values) const { - long *n = &a; + std::vector newval; - for (std::string::const_iterator j = value.begin(); j != value.end(); ++j) { - switch (*j) { - case '-': - if (j != value.begin()) { - if (n == &b) { - return false; - // throw eckit::UserError(name_ + ": invalid integer range '" + value + "' (a)"); + for (size_t i = 0; i < values.size(); ++i) { - } - n = &b; + const std::string& s = values[i]; + + if (eckit::StringTools::lower(s) == "to" || eckit::StringTools::lower(s) == "t0") { + // TimeUnit unit; + + if (newval.size() == 0) { + std::ostringstream oss; + oss << name_ << " list: 'to' must be preceeded by a starting value."; + throw eckit::BadValue(oss.str()); } - else { - return false; - // throw eckit::UserError(name_ + ": invalid integer range '" + value + "' (b)"); + if (values.size() <= i+1) { + std::ostringstream oss; + oss << name_ << " list: 'to' must be followed by an ending value."; + throw eckit::BadValue(oss.str()); } - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - (*n) *= 10; - (*n) += (*j) - '0'; - break; + eckit::Time from = eckit::Time(values[i - 1], true); + // unit = maxUnit(from); - default: - { - std::string lower = eckit::StringTools::lower(value); - if (lower == "to" || lower == "t0" || lower == "by") { - return true; + eckit::Time to = eckit::Time(values[i + 1], true); + eckit::Time by = by_; + + if (i+2 < values.size() && eckit::StringTools::lower(values[i + 2]) == "by") { + if (values.size() <= i+3) { + std::ostringstream oss; + oss << name_ << " list: 'by' must be followed by a step size."; + throw eckit::BadValue(oss.str()); + } + + by = eckit::Time(values[i + 3], true); + + i += 2; } - } - return false; - // throw eckit::UserError(name_ + ": invalid integer range '" + value + "' (c)"); - break; - } - } - if (n == &a) { - std::ostringstream oss; - oss << a; + if (from > to) { + std::ostringstream oss; + oss << name_ + ": 'from' value " << from << " cannot be greater that 'to' value " << to; + throw eckit::BadValue(oss.str()); + } + if (by <= eckit::Time(0)) { + std::ostringstream oss; + oss << name_ + ": 'by' value " << by << " must be a positive number"; + throw eckit::BadValue(name_ + ": 'by' value must be a positive number"); + } + eckit::Time j = from; + j += by; + for (; j <= to; j += by) { + newval.emplace_back(StepRange(j)); + } - value = oss.str(); - return true; + i++; + } + else { + newval.push_back(tidy(ctx,s)); + } } - std::ostringstream oss; - oss << a << "-" << b; + std::swap(values, newval); - value = oss.str(); - return true; + Type::expand(ctx, values); } - static TypeBuilder type("range"); //---------------------------------------------------------------------------------------------------------------------- -} // namespace mars -} // namespace metkit + +} // namespace metkit::mars diff --git a/src/metkit/mars/TypeRange.h b/src/metkit/mars/TypeRange.h index b92cd80..7eef8a0 100644 --- a/src/metkit/mars/TypeRange.h +++ b/src/metkit/mars/TypeRange.h @@ -8,22 +8,20 @@ * does it submit to any jurisdiction. */ -/// @file TypeRange.h -/// @author Baudouin Raoult -/// @author Tiago Quintino -/// @date April 2016 +/// @file TypeToByListQuantile.h +/// @author Emanuele Danovaro +/// @date February 2022 -#ifndef metkit_TypeRange_H -#define metkit_TypeRange_H +#pragma once -#include "metkit/mars/TypeToByList.h" +#include "metkit/mars/Type.h" namespace metkit { namespace mars { //---------------------------------------------------------------------------------------------------------------------- -class TypeRange : public TypeToByList { +class TypeRange : public Type { public: // methods @@ -34,13 +32,15 @@ class TypeRange : public TypeToByList { private: // methods virtual void print( std::ostream &out ) const override; - virtual bool expand(const MarsExpandContext& ctx, - std::string& value) const override; + virtual bool expand(const MarsExpandContext& ctx, std::string& value) const override; + virtual void expand(const MarsExpandContext& ctx, + std::vector& values) const override; + + eckit::Time by_; + }; //---------------------------------------------------------------------------------------------------------------------- } // namespace mars } // namespace metkit - -#endif diff --git a/src/metkit/mars/TypeTime.cc b/src/metkit/mars/TypeTime.cc index fde322e..2132818 100644 --- a/src/metkit/mars/TypeTime.cc +++ b/src/metkit/mars/TypeTime.cc @@ -9,15 +9,15 @@ */ #include +#include #include "eckit/utils/Translator.h" - #include "eckit/types/Date.h" -#include "metkit/mars/MarsRequest.h" +#include "eckit/utils/StringTools.h" +#include "metkit/mars/MarsRequest.h" #include "metkit/mars/TypesFactory.h" #include "metkit/mars/TypeTime.h" -#include "eckit/utils/StringTools.h" namespace metkit { namespace mars { @@ -25,7 +25,7 @@ namespace mars { //---------------------------------------------------------------------------------------------------------------------- TypeTime::TypeTime(const std::string &name, const eckit::Value& settings) : - Type(name, settings), by_(6) { + Type(name, settings), by_(6*3600) { } TypeTime::~TypeTime() { @@ -33,60 +33,29 @@ TypeTime::~TypeTime() { bool TypeTime::expand(const MarsExpandContext&, std::string &value) const { - long n = 0; - int colon = 0; - - for (std::string::const_iterator j = value.begin(); j != value.end(); ++j) { - switch (*j) { - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - n *= 10; - n += (*j) - '0'; - break; - - case ':': - colon++; - break; - - default: - // throw eckit::UserError(name_ + ": invalid time '" + value + "'"); - return false; - } - } - - if (colon == 2 || (value.size() > 4 && colon == 0)) { - if (n % 100 != 0) { - std::ostringstream ss; - ss << "Cannot normalise time '" << value << "' - seconds not supported"; - throw eckit::SeriousBug(ss.str(), Here()); - } - n /= 100; + eckit::Time time(value); + + std::ostringstream oss; + if (time.seconds() != 0) { + oss << "Cannot normalise time '" << value << "' - seconds not supported"; + throw eckit::SeriousBug(oss.str(), Here()); } - - if (n < 100 && value.size() < 3) { - n *= 100; + if (time.hours() >= 24) { + oss << "Cannot normalise time '" << value << "' - " << time.hours() << " hours > 24 not supported"; + throw eckit::SeriousBug(oss.str(), Here()); } - std::ostringstream oss; - oss << std::setfill('0') << std::setw(4) << n; + oss << std::setfill('0') << std::setw(2) << time.hours() << std::setfill('0') << std::setw(2) << time.minutes(); value = oss.str(); + return true; } void TypeTime::expand(const MarsExpandContext& ctx, std::vector& values) const { - static eckit::Translator s2l; - static eckit::Translator l2s; + //static eckit::Translator s2l; + //static eckit::Translator l2s; std::vector newval; @@ -98,17 +67,18 @@ void TypeTime::expand(const MarsExpandContext& ctx, std::vector& va ASSERT(newval.size() > 0); ASSERT(i + 1 < values.size()); - long from = s2l(tidy(ctx, newval.back())); - long to = s2l(tidy(ctx, values[i + 1])); + long from = ((eckit::Second) eckit::Time(tidy(ctx, newval.back()))); + long to = ((eckit::Second) eckit::Time(tidy(ctx, values[i + 1]))); + ASSERT(from <= to); long by = by_; if (i + 3 < values.size() && eckit::StringTools::lower(values[i + 2]) == "by") { - by = s2l(tidy(ctx, values[i + 3])); + by = ((eckit::Second) eckit::Time(tidy(ctx, values[i + 3]))); i += 2; } - for (long j = from + by; j <= to; j += by) { - newval.push_back(l2s(j)); + for (long j = from + by; j <= to; j += by) { + newval.push_back(eckit::Time(j)); } i++; diff --git a/src/metkit/mars/TypeTime.h b/src/metkit/mars/TypeTime.h index 14c619b..b949d97 100644 --- a/src/metkit/mars/TypeTime.h +++ b/src/metkit/mars/TypeTime.h @@ -31,13 +31,12 @@ class TypeTime : public Type { virtual ~TypeTime() override; - private: // methods virtual void print( std::ostream &out ) const override; virtual void expand(const MarsExpandContext& ctx, std::vector& values) const override; virtual bool expand(const MarsExpandContext& ctx, std::string& value) const override; - + long by_; }; diff --git a/tests/test_expand.cc b/tests/test_expand.cc index 7c461a5..ac22bce 100644 --- a/tests/test_expand.cc +++ b/tests/test_expand.cc @@ -67,7 +67,7 @@ CASE( "test_metkit_expand_4" ) { } CASE( "test_metkit_expand_5" ) { - const char* text = "retrieve,class=od,date=20050601,diagnostic=1,expver=1,iteration=0,levelist=1,levtype=ml,param=155.129,step=0,stream=sens,time=1200,type=sg"; + const char* text = "retrieve,class=od,date=20050601,diagnostic=1,expver=1,iteration=0,levelist=1,levtype=ml,param=155.129,stream=sens,time=1200,type=sg"; MarsRequest r = MarsRequest::parse(text); r.dump(std::cout); } @@ -176,6 +176,125 @@ CASE( "test_metkit_expand_11_quantile" ) { quantile({"0:10","3:10","to","7:10","by","2","10:10"}, {"0:10","3:10","5:10","7:10","10:10"}); } + +void timeThrows(std::vector values) { + DummyContext ctx; + static metkit::mars::MarsLanguage language("retrieve"); + metkit::mars::Type* t = language.type("time"); + std::cout << "timeThrows " << values << std::endl; + EXPECT_THROWS(t->expand(ctx, values)); +} + +void time(std::vector values, std::vector expected) { + DummyContext ctx; + static metkit::mars::MarsLanguage language("retrieve"); + metkit::mars::Type* t = language.type("time"); + std::cout << "time " << values; + t->expand(ctx, values); + std::cout << " ==> " << values << " - expected " << expected << std::endl; + ASSERT(values == expected); +} + +CASE( "test_metkit_expand_12_time" ) { + timeThrows({"87"}); + timeThrows({"000012"}); + timeThrows({"0:0:12"}); + timeThrows({"12s"}); + time({"0"}, {"0000"}); + time({"0","1","12"}, {"0000","0100","1200"}); + time({"00:30","1:30","02:50"}, {"0030","0130","0250"}); + time({"0h","3h","120m","170m"}, {"0000","0300","0200","0250"}); + + timeThrows({"to","5"}); + timeThrows({"3","to"}); + timeThrows({"3","to","2"}); + timeThrows({"1","to","3","by"}); + + time({"0","to","0"}, {"0000"}); + time({"12","to","12"}, {"1200"}); + time({"0","to","12"}, {"0000", "0600", "1200"}); + time({"0","to","6","by","1"}, {"0000", "0100", "0200", "0300", "0400", "0500", "0600"}); + time({"0","to","6","by","2"}, {"0000", "0200", "0400", "0600"}); + time({"0","to","6","by","3"}, {"0000", "0300", "0600"}); + time({"0","to","6","by","4"}, {"0000", "0400"}); + time({"0","to","6","by","5"}, {"0000", "0500"}); + time({"0","to","6","by","6"}, {"0000", "0600"}); + time({"6","to","18"}, {"0600", "1200", "1800"}); + time({"1","to","6","by","1"}, {"0100", "0200", "0300", "0400", "0500", "0600"}); + time({"1","to","6","by","2"}, {"0100", "0300", "0500"}); + time({"1","to","6","by","3"}, {"0100", "0400"}); + time({"1","to","6","by","4"}, {"0100", "0500"}); + time({"1","to","6","by","5"}, {"0100", "0600"}); + time({"1","to","6","by","6"}, {"0100"}); + + time({"1","to","3h","by","30m"}, {"0100", "0130", "0200", "0230", "0300"}); + + // quantile({"0:5","to","0:5"}, {"0:5"}); + // quantile({"3:3","to","3:3"}, {"3:3"}); + // quantile({"0:5","to","5:5"}, {"0:5","1:5","2:5","3:5","4:5","5:5"}); + // quantile({"0:5","to","5:5","by","1"}, {"0:5","1:5","2:5","3:5","4:5","5:5"}); + // quantile({"0:5","to","5:5","by","2"}, {"0:5","2:5","4:5"}); + // quantile({"0:5","to","5:5","by","3"}, {"0:5","3:5"}); + // quantile({"0:5","to","5:5","by","5"}, {"0:5","5:5"}); + // quantile({"0:5","to","5:5","by","6"}, {"0:5"}); + // quantile({"2:5","to","5:5","by","2"}, {"2:5","4:5"}); + // quantile({"3:5","to","5:5","by","2"}, {"3:5","5:5"}); + // quantile({"4:5","to","5:5","by","2"}, {"4:5"}); + // quantile({"0:10","3:10","to","7:10","by","2","10:10"}, {"0:10","3:10","5:10","7:10","10:10"}); +} + + +void stepThrows(std::vector values) { + DummyContext ctx; + static metkit::mars::MarsLanguage language("retrieve"); + metkit::mars::Type* t = language.type("step"); + std::cout << "stepThrows " << values << std::endl; + EXPECT_THROWS(t->expand(ctx, values)); +} + +void step(std::vector values, std::vector expected) { + DummyContext ctx; + static metkit::mars::MarsLanguage language("retrieve"); + metkit::mars::Type* t = language.type("step"); + std::cout << "step " << values << " ==> "; + t->expand(ctx, values); + std::cout << values << " - expected: " << expected << std::endl; + ASSERT(values == expected); +} + +CASE( "test_metkit_expand_13_step" ) { +// stepThrows({"0:70"}); + step({"0"}, {"0"}); + step({"1"}, {"1"}); + step({"24"}, {"24"}); + step({"144"}, {"144"}); + step({"012"}, {"12"}); + step({"12:30"}, {"12h30m"}); + step({"1:00"}, {"1"}); + step({"1:0:0"}, {"1"}); + step({"1h"}, {"1"}); + step({"60m"}, {"1"}); + step({"1h60m"}, {"2"}); + step({"0:5"}, {"5m"}); + step({"0:05"}, {"5m"}); + step({"0:05:0"}, {"5m"}); + step({"0:06"}, {"6m"}); + step({"0:10"}, {"10m"}); + step({"0:12"}, {"12m"}); + step({"0:15"}, {"15m"}); + step({"0:20"}, {"20m"}); + step({"0:25"}, {"25m"}); + step({"0:30"}, {"30m"}); + step({"0:35"}, {"35m"}); + step({"0:40"}, {"40m"}); + step({"0:45"}, {"45m"}); + step({"0:50"}, {"50m"}); + step({"0:55"}, {"55m"}); + step({"1-2"}, {"1-2"}); + step({"30m-1"}, {"30m-60m"}); + +} + //----------------------------------------------------------------------------- } // namespace test diff --git a/tests/test_time.cc b/tests/test_time.cc index 5278004..b861285 100644 --- a/tests/test_time.cc +++ b/tests/test_time.cc @@ -27,14 +27,19 @@ namespace test { //----------------------------------------------------------------------------- -CASE("Test TypeType expansions") { +CASE("Test TypeTime expansions") { TypeTime ttime("time", Value()); Type& tt(ttime); DummyContext ctx; - // 2-digit times + // 1 and 2-digit times + { + std::string value = "0"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } { std::string value = "00"; tt.expand(ctx, value); @@ -46,73 +51,59 @@ CASE("Test TypeType expansions") { EXPECT(value == "1200"); } { - std::string value = "06"; + std::string value = "6"; tt.expand(ctx, value); EXPECT(value == "0600"); } { - std::string value = "6"; + std::string value = "06"; tt.expand(ctx, value); EXPECT(value == "0600"); } - // 4-digit times + // 3 and 4-digit times { - std::string value = "0000"; + std::string value = "000"; tt.expand(ctx, value); EXPECT(value == "0000"); } { - std::string value = "0012"; - tt.expand(ctx, value); - EXPECT(value == "0012"); - } - { - std::string value = "1234"; - tt.expand(ctx, value); - EXPECT(value == "1234"); - } - { - std::string value = "0623"; - tt.expand(ctx, value); - EXPECT(value == "0623"); - } - { - std::string value = "623"; + std::string value = "0000"; tt.expand(ctx, value); - EXPECT(value == "0623"); + EXPECT(value == "0000"); } - - // 4-digit times with colons - { - std::string value = "00:00"; + std::string value = "012"; tt.expand(ctx, value); - EXPECT(value == "0000"); + EXPECT(value == "0012"); } { - std::string value = "00:12"; + std::string value = "0012"; tt.expand(ctx, value); EXPECT(value == "0012"); } { - std::string value = "12:34"; + std::string value = "1234"; tt.expand(ctx, value); EXPECT(value == "1234"); } { - std::string value = "06:23"; + std::string value = "623"; tt.expand(ctx, value); EXPECT(value == "0623"); } { - std::string value = "6:23"; + std::string value = "0623"; tt.expand(ctx, value); EXPECT(value == "0623"); } + { + std::string value = "675"; + EXPECT_THROWS_AS(tt.expand(ctx, value), BadTime); + } - // 6-digit times + // 5 and 6-digit times { std::string value = "000000"; @@ -150,13 +141,52 @@ CASE("Test TypeType expansions") { EXPECT_THROWS_AS(tt.expand(ctx, value), SeriousBug); } - // 6-digit times with colons + // times with colons + { + std::string value = "0:0"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } + { + std::string value = "00:00"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } { std::string value = "00:00:00"; tt.expand(ctx, value); EXPECT(value == "0000"); } + { + std::string value = "0:12"; + tt.expand(ctx, value); + EXPECT(value == "0012"); + } + { + std::string value = "00:12"; + tt.expand(ctx, value); + EXPECT(value == "0012"); + } + { + std::string value = "00:62"; + EXPECT_THROWS_AS(tt.expand(ctx, value), BadTime); + } + { + std::string value = "12:34"; + tt.expand(ctx, value); + EXPECT(value == "1234"); + } + { + std::string value = "6:23"; + tt.expand(ctx, value); + EXPECT(value == "0623"); + } + { + std::string value = "06:23"; + tt.expand(ctx, value); + EXPECT(value == "0623"); + } { // We don't support seconds yet. std::string value = "00:00:12"; @@ -187,6 +217,29 @@ CASE("Test TypeType expansions") { std::string value = "12:34:56"; EXPECT_THROWS_AS(tt.expand(ctx, value), SeriousBug); } + + // times with units + + { + std::string value = "0h"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } + { + std::string value = "00H"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } + { + std::string value = "60m"; + tt.expand(ctx, value); + EXPECT(value == "0100"); + } + { + std::string value = "2h30m"; + tt.expand(ctx, value); + EXPECT(value == "0230"); + } }