diff --git a/include/exiv2/value.hpp b/include/exiv2/value.hpp index f9383817..dc50bfa8 100644 --- a/include/exiv2/value.hpp +++ b/include/exiv2/value.hpp @@ -979,7 +979,6 @@ namespace Exiv2 { //! Simple Date helper structure struct EXIV2API Date { - Date() = default; int year{0}; //!< Year int month{0}; //!< Month int day{0}; //!< Day @@ -1031,6 +1030,7 @@ namespace Exiv2 { @return Number of characters written. */ long copy(byte* buf, ByteOrder byteOrder = invalidByteOrder) const override; + //! Return date struct containing date information virtual const Date& getDate() const; long count() const override; @@ -1150,31 +1150,6 @@ namespace Exiv2 { //@} private: - //! @name Manipulators - //@{ - /*! - @brief Set time from \em buf if it conforms to \em format - (3 input items). - - This function only sets the hour, minute and second parts of time_. - - @param buf A 0 terminated C-string containing the time to parse. - @param format Format string for sscanf(). - @return 0 if successful, else 1. - */ - int scanTime3(const char* buf, const char* format); - /*! - @brief Set time from \em buf if it conforms to \em format - (6 input items). - - This function sets all parts of time_. - - @param buf A 0 terminated C-string containing the time to parse. - @param format Format string for sscanf(). - @return 0 if successful, else 1. - */ - int scanTime6(const char* buf, const char* format); - //@} //! @name Accessors //@{ diff --git a/src/value.cpp b/src/value.cpp index 3092423d..37cd817b 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -27,16 +27,17 @@ #include "unused.h" // + standard includes -#include -#include -#include +#include + #include -#include -#include #include #include #include -#include +#include +#include +#include +#include +#include // ***************************************************************************** // class member definitions @@ -776,13 +777,13 @@ namespace Exiv2 { } int LangAltValue::read(const std::string& buf) - { + { std::string b = buf; std::string lang = "x-default"; if (buf.length() > 5 && buf.substr(0, 5) == "lang=") { static const char* ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static const char* ALPHA_NUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - + const std::string::size_type pos = buf.find_first_of(' '); if (pos == std::string::npos) { lang = buf.substr(5); @@ -796,7 +797,7 @@ namespace Exiv2 { if (lang.empty() || lang.find('"') != lang.length() - 1) throw Error(kerInvalidLangAltValue, buf); - + lang = lang.substr(0, lang.length()-1); } @@ -809,7 +810,7 @@ namespace Exiv2 { if (lang.at(charPos) != '-' || lang.find_first_not_of(ALPHA_NUM, charPos+1) != std::string::npos) throw Error(kerInvalidLangAltValue, buf); } - + b.clear(); if (pos != std::string::npos) b = buf.substr(pos+1); } @@ -906,51 +907,30 @@ namespace Exiv2 { int DateValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/) { - // Hard coded to read Iptc style dates - if (len != 8) { -#ifndef SUPPRESS_WARNINGS - EXV_WARNING << Error(kerUnsupportedDateFormat) << "\n"; -#endif - return 1; - } - // Make the buffer a 0 terminated C-string for sscanf - char b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - std::memcpy(b, reinterpret_cast(buf), 8); - int scanned = sscanf(b, "%4d%2d%2d", - &date_.year, &date_.month, &date_.day); - if ( scanned != 3 - || date_.year < 0 - || date_.month < 1 || date_.month > 12 - || date_.day < 1 || date_.day > 31) { -#ifndef SUPPRESS_WARNINGS - EXV_WARNING << Error(kerUnsupportedDateFormat) << "\n"; -#endif - return 1; - } - return 0; + const std::string str(reinterpret_cast(buf), len); + return read(str); } int DateValue::read(const std::string& buf) { - // Hard coded to read Iptc style dates - if (buf.length() < 8) { -#ifndef SUPPRESS_WARNINGS - EXV_WARNING << Error(kerUnsupportedDateFormat) << "\n"; -#endif - return 1; + // ISO 8601 date formats: + // https://web.archive.org/web/20171020084445/https://www.loc.gov/standards/datetime/ISO_DIS%208601-1.pdf + static const std::regex reExtended(R"(^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]))"); + static const std::regex reBasic(R"(^(\d{4})(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01]))"); + std::smatch sm; + + // Note: We use here regex_search instead of regex_match, because the string can be longer than expected and + // also contain the time + if (std::regex_search(buf, sm, reExtended) || std::regex_search(buf, sm, reBasic)) { + date_.year = std::stoi(sm[1].str()); + date_.month = std::stoi(sm[2].str()); + date_.day = std::stoi(sm[3].str()); + return 0; } - int scanned = sscanf(buf.c_str(), "%4d-%2d-%2d", - &date_.year, &date_.month, &date_.day); - if ( scanned != 3 - || date_.year < 0 - || date_.month < 1 || date_.month > 12 - || date_.day < 1 || date_.day > 31) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(kerUnsupportedDateFormat) << "\n"; #endif - return 1; - } - return 0; + return 1; } void DateValue::setDate(const Date& src) @@ -962,9 +942,11 @@ namespace Exiv2 { long DateValue::copy(byte* buf, ByteOrder /*byteOrder*/) const { + // \note Here the date is copied in the Basic format YYYYMMDD, as the IPTC key Iptc.Application2.DateCreated + // wants it. Check https://exiv2.org/iptc.html + // sprintf wants to add the null terminator, so use oversized buffer char temp[9]; - int wrote = snprintf(temp, sizeof(temp), "%04d%02d%02d", date_.year, date_.month, date_.day); assert(wrote == 8); std::memcpy(buf, temp, wrote); @@ -993,8 +975,9 @@ namespace Exiv2 { std::ostream& DateValue::write(std::ostream& os) const { + // Write DateValue in ISO 8601 Extended format: YYYY-MM-DD std::ios::fmtflags f( os.flags() ); - os << date_.year << '-' << std::right + os << std::setw(4) << std::setfill('0') << date_.year << '-' << std::right << std::setw(2) << std::setfill('0') << date_.month << '-' << std::setw(2) << std::setfill('0') << date_.day; os.flags(f); @@ -1044,83 +1027,50 @@ namespace Exiv2 { int TimeValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/) { - // Make the buffer a 0 terminated C-string for scanTime[36] - char b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - std::memcpy(b, reinterpret_cast(buf), (len < 12 ? len : 11)); - // Hard coded to read HHMMSS or Iptc style times - int rc = 1; - if (len == 6) { - // Try to read (non-standard) HHMMSS format - rc = scanTime3(b, "%2d%2d%2d"); - } - if (len == 11) { - rc = scanTime6(b, "%2d%2d%2d%1c%2d%2d"); - } - if (rc) { - rc = 1; -#ifndef SUPPRESS_WARNINGS - EXV_WARNING << Error(kerUnsupportedTimeFormat) << "\n"; -#endif - } - return rc; + const std::string str(reinterpret_cast(buf), len); + return read(str); } int TimeValue::read(const std::string& buf) { - // Hard coded to read H:M:S or Iptc style times - int rc = 1; - if (buf.length() < 9) { - // Try to read (non-standard) H:M:S format - rc = scanTime3(buf.c_str(), "%d:%d:%d"); - } - else { - rc = scanTime6(buf.c_str(), "%d:%d:%d%1c%d:%d"); + // ISO 8601 time formats: + // https://web.archive.org/web/20171020084445/https://www.loc.gov/standards/datetime/ISO_DIS%208601-1.pdf + // Not supported formats: + // 4.2.2.4 Representations with decimal fraction: 232050,5 + static const std::regex re(R"(^(2[0-3]|[01][0-9]):?([0-5][0-9])?:?([0-5][0-9])?$)"); + static const std::regex reExt(R"(^(2[0-3]|[01][0-9]):?([0-5][0-9]):?([0-5][0-9])(Z|[+-](?:2[0-3]|[01][0-9])(?::?(?:[0-5][0-9]))?)$)"); + + std::smatch sm; + if (std::regex_match(buf, sm, re) || std::regex_match(buf, sm, reExt)) { + time_.hour = sm.length(1) ? std::stoi(sm[1].str()) : 0; + time_.minute = sm.length(2) ? std::stoi(sm[2].str()) : 0; + time_.second = sm.length(3) ? std::stoi(sm[3].str()) : 0; + if (sm.size() > 4) + { + std::string str = sm[4].str(); + const auto strSize = str.size(); + auto posColon = str.find(':'); + + if (posColon == std::string::npos) { + // Extended format + time_.tzHour = std::stoi(str.substr(0,3)); + if (strSize > 3) { + int minute = std::stoi(str.substr(3)); + time_.tzMinute = time_.tzHour < 0 ? -minute : minute; + } + } else { + // Basic format + time_.tzHour = std::stoi(str.substr(0, posColon)); + int minute = std::stoi(str.substr(posColon+1)); + time_.tzMinute = time_.tzHour < 0 ? -minute : minute; + } + } + return 0; } - if (rc) { - rc = 1; #ifndef SUPPRESS_WARNINGS - EXV_WARNING << Error(kerUnsupportedTimeFormat) << "\n"; + EXV_WARNING << Error(kerUnsupportedTimeFormat) << "\n"; #endif - } - return rc; - } - - int TimeValue::scanTime3(const char* buf, const char* format) - { - int rc = 1; - Time t; - int scanned = sscanf(buf, format, &t.hour, &t.minute, &t.second); - if ( scanned == 3 - && t.hour >= 0 && t.hour < 24 - && t.minute >= 0 && t.minute < 60 - && t.second >= 0 && t.second < 60) { - time_ = t; - rc = 0; - } - return rc; - } - - int TimeValue::scanTime6(const char* buf, const char* format) - { - int rc = 1; - Time t; - char plusMinus = 0; - int scanned = sscanf(buf, format, &t.hour, &t.minute, &t.second, - &plusMinus, &t.tzHour, &t.tzMinute); - if ( scanned == 6 - && t.hour >= 0 && t.hour < 24 - && t.minute >= 0 && t.minute < 60 - && t.second >= 0 && t.second < 60 - && t.tzHour >= 0 && t.tzHour < 24 - && t.tzMinute >= 0 && t.tzMinute < 60) { - time_ = t; - if (plusMinus == '-') { - time_.tzHour *= -1; - time_.tzMinute *= -1; - } - rc = 0; - } - return rc; + return 1; } void TimeValue::setTime( const Time& src ) @@ -1130,6 +1080,8 @@ namespace Exiv2 { long TimeValue::copy(byte* buf, ByteOrder /*byteOrder*/) const { + // NOTE: Here the time is copied in the Basic format HHMMSS:HHMM, as the IPTC key Iptc.Application2.TimeCreated + // wants it. Check https://exiv2.org/iptc.html char temp[12]; char plusMinus = '+'; if (time_.tzHour < 0 || time_.tzMinute < 0) @@ -1167,8 +1119,10 @@ namespace Exiv2 { std::ostream& TimeValue::write(std::ostream& os) const { + // Write TimeValue in ISO 8601 Extended format: hh:mm:ss±hh:mm char plusMinus = '+'; - if (time_.tzHour < 0 || time_.tzMinute < 0) plusMinus = '-'; + if (time_.tzHour < 0 || time_.tzMinute < 0) + plusMinus = '-'; std::ios::fmtflags f( os.flags() ); os << std::right diff --git a/tests/bash_tests/utils.py b/tests/bash_tests/utils.py index 98053907..f64345e9 100644 --- a/tests/bash_tests/utils.py +++ b/tests/bash_tests/utils.py @@ -642,11 +642,11 @@ def addModTest(filename): stdin = """ a Iptc.Application2.Headline The headline I am a Iptc.Application2.Keywords Yet another keyword -m Iptc.Application2.DateCreated 2004-8-3 +m Iptc.Application2.DateCreated 2004-08-03 a Iptc.Application2.Urgency 3 m Iptc.Application2.SuppCategory "bla bla ba" a Iptc.Envelope.ModelVersion 2 -a Iptc.Envelope.TimeSent 14:41:0-05:00 +a Iptc.Envelope.TimeSent 14:41:00-05:00 a Iptc.Application2.RasterizedCaption 230 42 34 2 90 84 23 146 """.lstrip('\n').encode() Executer('iptctest {tmp}', vars(), stdin=stdin) diff --git a/unitTests/test_DateValue.cpp b/unitTests/test_DateValue.cpp index db02eec5..ed968d3a 100644 --- a/unitTests/test_DateValue.cpp +++ b/unitTests/test_DateValue.cpp @@ -19,8 +19,13 @@ */ #include "value.hpp" + #include +#include +#include +#include + using namespace Exiv2; TEST(ADateValue, isDefaultConstructed) @@ -31,7 +36,7 @@ TEST(ADateValue, isDefaultConstructed) ASSERT_EQ(0, dateValue.getDate().day); } -TEST(ADateValue, isConstructedWithArgs) +TEST(ADateValue, canBeConstructedWithValidDate) { const DateValue dateValue (2018, 4, 2); ASSERT_EQ(2018, dateValue.getDate().year); @@ -39,6 +44,45 @@ TEST(ADateValue, isConstructedWithArgs) ASSERT_EQ(2, dateValue.getDate().day); } +/// \todo Probably we should avoid this ... +TEST(ADateValue, canBeConstructedWithInvalidDate) +{ + const DateValue dateValue (2018, 13, 69); + ASSERT_EQ(2018, dateValue.getDate().year); + ASSERT_EQ(13, dateValue.getDate().month); + ASSERT_EQ(69, dateValue.getDate().day); +} + +TEST(ADateValue, setsValidDateCorrectly) +{ + DateValue dateValue; + DateValue::Date date; + date.year = 2018; + date.month = 4; + date.day = 2; + + dateValue.setDate(date); + ASSERT_EQ(2018, dateValue.getDate().year); + ASSERT_EQ(4, dateValue.getDate().month); + ASSERT_EQ(2, dateValue.getDate().day); +} + +/// \todo Probably we should avoid this ... +TEST(ADateValue, setsInvalidDateCorrectly) +{ + DateValue dateValue; + DateValue::Date date; + date.year = 2018; + date.month = 13; + date.day = 69; + + dateValue.setDate(date); + ASSERT_EQ(2018, dateValue.getDate().year); + ASSERT_EQ(13, dateValue.getDate().month); + ASSERT_EQ(69, dateValue.getDate().day); +} + + TEST(ADateValue, readFromByteBufferWithExpectedSize) { @@ -54,7 +98,7 @@ TEST(ADateValue, doNotReadFromByteBufferWithoutExpectedSize) { DateValue dateValue; const byte date[8] = {0x32, 0x30, 0x31, 0x38, 0x30, 0x34, 0x30, 0x32 }; // 20180402 - ASSERT_EQ(1, dateValue.read(date, 9)); + ASSERT_EQ(1, dateValue.read(date, 6)); } TEST(ADateValue, doNotReadFromByteBufferWithExpectedSizeButNotCorrectContent) @@ -65,7 +109,7 @@ TEST(ADateValue, doNotReadFromByteBufferWithExpectedSizeButNotCorrectContent) } -TEST(ADateValue, readFromStringWithExpectedSize) +TEST(ADateValue, readFromStringWithExpectedSizeAndDashes) { DateValue dateValue; const std::string date ("2018-04-02"); @@ -75,29 +119,90 @@ TEST(ADateValue, readFromStringWithExpectedSize) ASSERT_EQ(2, dateValue.getDate().day); } -TEST(ADateValue, doNotReadFromStringWithoutExpectedSize) +TEST(ADateValue, readFromStringWithExpectedSizeWithoutDashes) { DateValue dateValue; const std::string date ("20180402"); - ASSERT_EQ(1, dateValue.read(date)); + ASSERT_EQ(0, dateValue.read(date)); + ASSERT_EQ(2018, dateValue.getDate().year); + ASSERT_EQ(4, dateValue.getDate().month); + ASSERT_EQ(2, dateValue.getDate().day); +} + +TEST(ADateValue, readFromStringWithTime) +{ + DateValue dateValue; + const std::string date ("2018-04-02T12:01:44.999999999"); + ASSERT_EQ(0, dateValue.read(date)); + ASSERT_EQ(2018, dateValue.getDate().year); + ASSERT_EQ(4, dateValue.getDate().month); + ASSERT_EQ(2, dateValue.getDate().day); +} + +TEST(ADateValue, doNotReadFromStringWithoutExpectedSize) +{ + DateValue dateValue; + ASSERT_EQ(1, dateValue.read("2018-04-0")); + ASSERT_EQ(1, dateValue.read("2018040")); } TEST(ADateValue, doNotReadFromStringWithExpectedSizeButNotCorrectContent) { DateValue dateValue; - const std::string date ("2018-aa-bb"); - ASSERT_EQ(1, dateValue.read(date)); + ASSERT_EQ(1, dateValue.read("2018-24-02")); + ASSERT_EQ(1, dateValue.read("2018-aa-bb")); + ASSERT_EQ(1, dateValue.read("2018aabb")); } +TEST(ADateValue, writesRecentDateToExtendedFormat) +{ + const DateValue dateValue (2021, 12, 1); + std::ostringstream stream; + dateValue.write(stream); + ASSERT_EQ("2021-12-01", stream.str()); +} +TEST(ADateValue, writesVeryOldDateToExtendedFormat) +{ + const DateValue dateValue (1, 1, 1); + std::ostringstream stream; + dateValue.write(stream); + ASSERT_EQ("0001-01-01", stream.str()); +} -TEST(ADateValue, copyToByteBuffer) +TEST(ADateValue, copiesToByteBufferWithBasicFormat) { - const DateValue dateValue (2018, 4, 2); - const byte expectedDate[8] = {0x32, 0x30, 0x31, 0x38, 0x30, 0x34, 0x30, 0x32 }; // 20180402 - byte buffer[8]; - ASSERT_EQ(8, dateValue.copy(buffer)); - for (int i = 0; i < 8; ++i) { - ASSERT_EQ(expectedDate[i], buffer[i]); - } + const DateValue dateValue (2021, 12, 1); + std::array buf; + buf.fill(0); + + const byte expectedDate[10] = {'2', '0', '2', '1', '1', '2', '0', '1'}; + ASSERT_EQ(8, dateValue.copy(buf.data())); + ASSERT_TRUE(std::equal(buf.begin(), buf.end(), expectedDate)); +} + +// I used https://www.epochconverter.com/ for knowing the expectations +/* These functions convert the time to the local calendar time. Find a way to do the conversions with UTC + +TEST(ADateValue, toLong) +{ + const DateValue dateValue (2021, 12, 1); + long val = dateValue.toLong(); + ASSERT_EQ(1638313200, val); +} + +TEST(ADateValue, toFloat) +{ + const DateValue dateValue (2021, 12, 1); + long val = dateValue.toFloat(); + ASSERT_FLOAT_EQ(1638313200.f, val); +} + +TEST(ADateValue, toRational) +{ + const DateValue dateValue (2021, 12, 1); + auto val = dateValue.toRational(); + ASSERT_EQ(1638313200, val.first); + ASSERT_EQ(1, val.second); } +*/ diff --git a/unitTests/test_TimeValue.cpp b/unitTests/test_TimeValue.cpp index 46141762..8249d035 100644 --- a/unitTests/test_TimeValue.cpp +++ b/unitTests/test_TimeValue.cpp @@ -44,7 +44,37 @@ TEST(ATimeValue, isConstructedWithArgs) /// \todo add tests to check what happen with values out of valid ranges -TEST(ATimeValue, canBeReadFromStringHMS) +TEST(ATimeValue, canBeReadFromCompleteBasicFormatString) +{ + TimeValue value; + const std::string hms("235502"); + ASSERT_EQ(0, value.read(hms)); + ASSERT_EQ(23, value.getTime().hour); + ASSERT_EQ(55, value.getTime().minute); + ASSERT_EQ(2, value.getTime().second); +} + +TEST(ATimeValue, canBeReadFromReducedBasicFormatString_HHMM) +{ + TimeValue value; + const std::string hms("2355"); + ASSERT_EQ(0, value.read(hms)); + ASSERT_EQ(23, value.getTime().hour); + ASSERT_EQ(55, value.getTime().minute); + ASSERT_EQ(0, value.getTime().second); +} + +TEST(ATimeValue, canBeReadFromReducedBasicFormatString_HH) +{ + TimeValue value; + const std::string hms("23"); + ASSERT_EQ(0, value.read(hms)); + ASSERT_EQ(23, value.getTime().hour); + ASSERT_EQ(0, value.getTime().minute); + ASSERT_EQ(0, value.getTime().second); +} + +TEST(ATimeValue, canBeReadFromCompleteExtendedFormatString) { TimeValue value; const std::string hms("23:55:02"); @@ -52,45 +82,86 @@ TEST(ATimeValue, canBeReadFromStringHMS) ASSERT_EQ(23, value.getTime().hour); ASSERT_EQ(55, value.getTime().minute); ASSERT_EQ(2, value.getTime().second); - ASSERT_EQ(0, value.getTime().tzHour); +} + +TEST(ATimeValue, canBeReadFromReducedExtendedFormatString_HHMM) +{ + TimeValue value; + const std::string hms("23:55"); + ASSERT_EQ(0, value.read(hms)); + ASSERT_EQ(23, value.getTime().hour); + ASSERT_EQ(55, value.getTime().minute); + ASSERT_EQ(0, value.getTime().second); +} + +TEST(ATimeValue, canBeReadFromBasicStringWithTimeZoneDesignatorPositive) +{ + TimeValue value; + std::string hms("152746+0100"); + ASSERT_EQ(0, value.read(hms)); + ASSERT_EQ(15, value.getTime().hour); + ASSERT_EQ(27, value.getTime().minute); + ASSERT_EQ(46, value.getTime().second); + ASSERT_EQ(1, value.getTime().tzHour); + ASSERT_EQ(0, value.getTime().tzMinute); + + value = TimeValue(); + hms = "152746+02"; + ASSERT_EQ(0, value.read(hms)); + ASSERT_EQ(15, value.getTime().hour); + ASSERT_EQ(27, value.getTime().minute); + ASSERT_EQ(46, value.getTime().second); + ASSERT_EQ(2, value.getTime().tzHour); ASSERT_EQ(0, value.getTime().tzMinute); } -TEST(ATimeValue, canBeReadFromWideString) +TEST(ATimeValue, canBeReadFromExtendedStringWithTimeZoneDesignatorPositive) { TimeValue value; - const std::string hms("23:55:02+04:04"); + std::string hms("23:55:02+04:04"); ASSERT_EQ(0, value.read(hms)); ASSERT_EQ(23, value.getTime().hour); ASSERT_EQ(55, value.getTime().minute); ASSERT_EQ(2, value.getTime().second); ASSERT_EQ(4, value.getTime().tzHour); ASSERT_EQ(4, value.getTime().tzMinute); + + value = TimeValue(); + hms = "23:44:03+04"; + ASSERT_EQ(0, value.read(hms)); + ASSERT_EQ(23, value.getTime().hour); + ASSERT_EQ(44, value.getTime().minute); + ASSERT_EQ(3, value.getTime().second); + ASSERT_EQ(4, value.getTime().tzHour); + ASSERT_EQ(0, value.getTime().tzMinute); } -TEST(ATimeValue, canBeReadFromWideStringNegative) +TEST(ATimeValue, canBeReadFromExtendedStringWithTimeZoneDesignatorNegative) { TimeValue value; - const std::string hms("23:55:02-04:04"); + std::string hms("23:55:02-04:04"); ASSERT_EQ(0, value.read(hms)); ASSERT_EQ(23, value.getTime().hour); ASSERT_EQ(55, value.getTime().minute); ASSERT_EQ(2, value.getTime().second); ASSERT_EQ(-4, value.getTime().tzHour); ASSERT_EQ(-4, value.getTime().tzMinute); + + value = TimeValue(); + hms = "23:44:03-04"; + ASSERT_EQ(0, value.read(hms)); + ASSERT_EQ(23, value.getTime().hour); + ASSERT_EQ(44, value.getTime().minute); + ASSERT_EQ(3, value.getTime().second); + ASSERT_EQ(-4, value.getTime().tzHour); + ASSERT_EQ(0, value.getTime().tzMinute); } -/// \todo check what we should do here. -TEST(ATimeValue, canBeReadFromWideStringOther) +TEST(ATimeValue, cannotBeReadFromStringWithTimeZoneDesignatorWithoutSymbol) { TimeValue value; const std::string hms("23:55:02?04:04"); - ASSERT_EQ(0, value.read(hms)); - ASSERT_EQ(23, value.getTime().hour); - ASSERT_EQ(55, value.getTime().minute); - ASSERT_EQ(2, value.getTime().second); - ASSERT_EQ(4, value.getTime().tzHour); - ASSERT_EQ(4, value.getTime().tzMinute); + ASSERT_EQ(1, value.read(hms)); } TEST(ATimeValue, cannotReadFromStringWithBadFormat)