LCOV - code coverage report
Current view: top level - tests - dosdatetime.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 225 230 97.8 %
Date: 2019-04-24 14:10:30 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   Zipios -- a small C++ library that provides easy access to .zip files.
       3             : 
       4             :   Copyright (C) 2019  Made to Order Software Corporation
       5             : 
       6             :   This library is free software; you can redistribute it and/or
       7             :   modify it under the terms of the GNU Lesser General Public
       8             :   License as published by the Free Software Foundation; either
       9             :   version 2.1 of the License, or (at your option) any later version.
      10             : 
      11             :   This library is distributed in the hope that it will be useful,
      12             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :   Lesser General Public License for more details.
      15             : 
      16             :   You should have received a copy of the GNU Lesser General Public
      17             :   License along with this library; if not, write to the Free Software
      18             :   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      19             : */
      20             : 
      21             : /** \file
      22             :  *
      23             :  * Zipios unit tests verify the dosdatetime.cpp/hpp implementation.
      24             :  *
      25             :  * Keep in mind that the date is saved as a local time date in a zip file.
      26             :  * It's crap. But that comes from the old days of DOS which chose that format
      27             :  * at the time. Sharing between people in the whole world was not viewed in
      28             :  * a way similar to today's world...
      29             :  *
      30             :  * \warning
      31             :  * This test will fail if run around a standard time to a saving time
      32             :  * or a saving time to a standard time changing period (i.e. during the
      33             :  * 1h or so when time changes in spring and autumn.)
      34             :  */
      35             : 
      36             : #include "tests.hpp"
      37             : 
      38             : #include "zipios/dosdatetime.hpp"
      39             : #include "zipios/zipiosexceptions.hpp"
      40             : 
      41             : #include <fstream>
      42             : 
      43             : #include <sys/stat.h>
      44             : #include <unistd.h>
      45             : 
      46             : #include <cstring>
      47             : #include <iostream>
      48             : 
      49             : 
      50             : 
      51             : 
      52             : // min = Jan  1, 1980 at 00:00:00
      53             : std::time_t g_minimum_unix = -1;
      54             : 
      55             : // max = Dec 31, 2107 at 23:59:59
      56             : std::time_t g_maximum_unix = -1;
      57             : 
      58             : 
      59           5 : void init_min_max()
      60             : {
      61           5 :     if(g_minimum_unix == -1)
      62             :     {
      63             :         struct tm t;
      64             : 
      65           1 :         memset(&t, 0, sizeof(t));
      66           1 :         t.tm_sec = 0;
      67           1 :         t.tm_min = 0;
      68           1 :         t.tm_hour = 0;
      69           1 :         t.tm_mday = 1;
      70           1 :         t.tm_mon = 0;
      71           1 :         t.tm_year = 1980 - 1900;
      72           1 :         t.tm_isdst = -1;
      73           1 :         g_minimum_unix = mktime(&t);
      74             : 
      75             :         struct tm c;
      76           1 :         localtime_r(&g_minimum_unix, &c);
      77             :     }
      78             : 
      79           5 :     if(g_maximum_unix == -1)
      80             :     {
      81             :         struct tm t;
      82             : 
      83           1 :         memset(&t, 0, sizeof(t));
      84           1 :         t.tm_sec = 58;
      85           1 :         t.tm_min = 59;
      86           1 :         t.tm_hour = 23;
      87           1 :         t.tm_mday = 31;
      88           1 :         t.tm_mon = 11;
      89           1 :         t.tm_year = 2107 - 1900;
      90           1 :         t.tm_isdst = -1;
      91           1 :         g_maximum_unix = mktime(&t);
      92             :     }
      93           5 : }
      94             : 
      95             : 
      96             : 
      97           3 : TEST_CASE("DOS Date & Time Min/Max", "[dosdatetime]")
      98             : {
      99           4 :     SECTION("DOS time minimum")
     100             :     {
     101           1 :         zipios::DOSDateTime t;
     102           1 :         t.setYear(1980);
     103           1 :         t.setMonth(1);
     104           1 :         t.setMDay(1);
     105           1 :         t.setHour(0);
     106           1 :         t.setMinute(0);
     107           1 :         t.setSecond(0);
     108           1 :         REQUIRE(zipios::DOSDateTime::g_min_dosdatetime == t.getDOSDateTime());
     109             :     }
     110             : 
     111           4 :     SECTION("DOS time maximum")
     112             :     {
     113           1 :         zipios::DOSDateTime t;
     114           1 :         t.setYear(2107);
     115           1 :         t.setMonth(12);
     116           1 :         t.setMDay(31);
     117           1 :         t.setHour(23);
     118           1 :         t.setMinute(59);
     119           1 :         t.setSecond(59);
     120           1 :         REQUIRE(zipios::DOSDateTime::g_max_dosdatetime == t.getDOSDateTime());
     121             :     }
     122           2 : }
     123             : 
     124             : 
     125           8 : TEST_CASE("Invalid DOS Date & Time", "[dosdatetime]")
     126             : {
     127          14 :     SECTION("daysInMonth() when month is invalid")
     128             :     {
     129             :         // by default the date is 0 which means the month is 0 and
     130             :         // trying to call daysInMonth() fails with -1
     131             :         //
     132           1 :         zipios::DOSDateTime d;
     133           1 :         REQUIRE(d.daysInMonth() == -1);
     134             :     }
     135             : 
     136          14 :     SECTION("get/set seconds")
     137             :     {
     138          61 :         for(int i = 0; i < 60; ++i)
     139             :         {
     140          60 :             zipios::DOSDateTime t;
     141          60 :             t.setSecond(i);
     142          60 :             REQUIRE(t.getSecond() == (i & -2));
     143             :         }
     144          21 :         for(int i = -20; i < 0; ++i)
     145             :         {
     146          20 :             zipios::DOSDateTime t;
     147          20 :             int const r(rand() % 60);
     148          20 :             t.setSecond(r);
     149          20 :             REQUIRE(t.getSecond() == (r & -2));
     150          20 :             REQUIRE_THROWS_AS(t.setSecond(i), zipios::InvalidException);
     151          20 :             REQUIRE(t.getSecond() == (r & -2));
     152             :         }
     153          22 :         for(int i = 60; i <= 80; ++i)
     154             :         {
     155          21 :             zipios::DOSDateTime t;
     156          21 :             int const r(rand() % 60);
     157          21 :             t.setSecond(r);
     158          21 :             REQUIRE(t.getSecond() == (r & -2));
     159          21 :             REQUIRE_THROWS_AS(t.setSecond(i), zipios::InvalidException);
     160          21 :             REQUIRE(t.getSecond() == (r & -2));
     161             :         }
     162             :     }
     163             : 
     164          14 :     SECTION("get/set minutes")
     165             :     {
     166          61 :         for(int i = 0; i < 60; ++i)
     167             :         {
     168          60 :             zipios::DOSDateTime t;
     169          60 :             t.setMinute(i);
     170          60 :             REQUIRE(t.getMinute() == i);
     171             :         }
     172          21 :         for(int i = -20; i < 0; ++i)
     173             :         {
     174          20 :             zipios::DOSDateTime t;
     175          20 :             int const r(rand() % 60);
     176          20 :             t.setMinute(r);
     177          20 :             REQUIRE(t.getMinute() == r);
     178          20 :             REQUIRE_THROWS_AS(t.setMinute(i), zipios::InvalidException);
     179          20 :             REQUIRE(t.getMinute() == r);
     180             :         }
     181          22 :         for(int i = 60; i <= 80; ++i)
     182             :         {
     183          21 :             zipios::DOSDateTime t;
     184          21 :             int const r(rand() % 60);
     185          21 :             t.setMinute(r);
     186          21 :             REQUIRE(t.getMinute() == r);
     187          21 :             REQUIRE_THROWS_AS(t.setMinute(i), zipios::InvalidException);
     188          21 :             REQUIRE(t.getMinute() == r);
     189             :         }
     190             :     }
     191             : 
     192          14 :     SECTION("get/set hours")
     193             :     {
     194          25 :         for(int i = 0; i < 24; ++i)
     195             :         {
     196          24 :             zipios::DOSDateTime t;
     197          24 :             t.setHour(i);
     198          24 :             REQUIRE(t.getHour() == i);
     199             :         }
     200          21 :         for(int i = -20; i < 0; ++i)
     201             :         {
     202          20 :             zipios::DOSDateTime t;
     203          20 :             int const r(rand() % 24);
     204          20 :             t.setHour(r);
     205          20 :             REQUIRE(t.getHour() == r);
     206          20 :             REQUIRE_THROWS_AS(t.setHour(i), zipios::InvalidException);
     207          20 :             REQUIRE(t.getHour() == r);
     208             :         }
     209          22 :         for(int i = 24; i <= 44; ++i)
     210             :         {
     211          21 :             zipios::DOSDateTime t;
     212          21 :             int const r(rand() % 24);
     213          21 :             t.setHour(r);
     214          21 :             REQUIRE(t.getHour() == r);
     215          21 :             REQUIRE_THROWS_AS(t.setHour(i), zipios::InvalidException);
     216          21 :             REQUIRE(t.getHour() == r);
     217             :         }
     218             :     }
     219             : 
     220             :     // day is limited between 1 and 31 on a setMDay()
     221             :     // use the isValid() to know whether it is valid for the current month
     222             :     // and year
     223             :     //
     224          14 :     SECTION("get/set day of the month")
     225             :     {
     226          32 :         for(int i = 1; i < 32; ++i)
     227             :         {
     228          31 :             zipios::DOSDateTime t;
     229          31 :             t.setMDay(i);
     230          31 :             REQUIRE(t.getMDay() == i);
     231             :         }
     232          22 :         for(int i = -20; i <= 0; ++i)
     233             :         {
     234          21 :             zipios::DOSDateTime t;
     235          21 :             int const r(rand() % 31 + 1);
     236          21 :             t.setMDay(r);
     237          21 :             REQUIRE(t.getMDay() == r);
     238          21 :             REQUIRE_THROWS_AS(t.setMDay(i), zipios::InvalidException);
     239          21 :             REQUIRE(t.getMDay() == r);
     240             :         }
     241          22 :         for(int i = 32; i <= 52; ++i)
     242             :         {
     243          21 :             zipios::DOSDateTime t;
     244          21 :             int const r(rand() % 31 + 1);
     245          21 :             t.setMDay(r);
     246          21 :             REQUIRE(t.getMDay() == r);
     247          21 :             REQUIRE_THROWS_AS(t.setMDay(i), zipios::InvalidException);
     248          21 :             REQUIRE(t.getMDay() == r);
     249             :         }
     250             :     }
     251             : 
     252          14 :     SECTION("get/set month")
     253             :     {
     254          12 :         for(int i = 1; i < 12; ++i)
     255             :         {
     256          11 :             zipios::DOSDateTime t;
     257          11 :             t.setMonth(i);
     258          11 :             REQUIRE(t.getMonth() == i);
     259             :         }
     260          22 :         for(int i = -20; i <= 0; ++i)
     261             :         {
     262          21 :             zipios::DOSDateTime t;
     263          21 :             int const r(rand() % 12 + 1);
     264          21 :             t.setMonth(r);
     265          21 :             REQUIRE(t.getMonth() == r);
     266          21 :             REQUIRE_THROWS_AS(t.setMonth(i), zipios::InvalidException);
     267          21 :             REQUIRE(t.getMonth() == r);
     268             :         }
     269          22 :         for(int i = 13; i <= 33; ++i)
     270             :         {
     271          21 :             zipios::DOSDateTime t;
     272          21 :             int const r(rand() % 12 + 1);
     273          21 :             t.setMonth(r);
     274          21 :             REQUIRE(t.getMonth() == r);
     275          21 :             REQUIRE_THROWS_AS(t.setMonth(i), zipios::InvalidException);
     276          21 :             REQUIRE(t.getMonth() == r);
     277             :         }
     278             :     }
     279             : 
     280          14 :     SECTION("get/set year")
     281             :     {
     282         129 :         for(int i = 1980; i <= 2107; ++i)
     283             :         {
     284         128 :             zipios::DOSDateTime t;
     285         128 :             t.setYear(i);
     286         128 :             REQUIRE(t.getYear() == i);
     287             :         }
     288         981 :         for(int i = 1000; i < 1980; ++i)
     289             :         {
     290         980 :             zipios::DOSDateTime t;
     291         980 :             int const r(rand() % (2107 - 1980 + 1) + 1980);
     292         980 :             t.setYear(r);
     293         980 :             REQUIRE(t.getYear() == r);
     294         980 :             REQUIRE_THROWS_AS(t.setYear(i), zipios::InvalidException);
     295         980 :             REQUIRE(t.getYear() == r);
     296             :         }
     297          94 :         for(int i = 2108; i <= 2200; ++i)
     298             :         {
     299          93 :             zipios::DOSDateTime t;
     300          93 :             int const r(rand() % (2107 - 1980 + 1) + 1980);
     301          93 :             t.setYear(r);
     302          93 :             REQUIRE(t.getYear() == r);
     303          93 :             REQUIRE_THROWS_AS(t.setYear(i), zipios::InvalidException);
     304          93 :             REQUIRE(t.getYear() == r);
     305             :         }
     306             :     }
     307           7 : }
     308             : 
     309             : 
     310             : #if 0
     311             : // this test is too long, which is why it is commented out by default
     312             : // still, it is great if you want to verify that all possible DOS Time & Date
     313             : //
     314             : TEST_CASE("All Valid DOS Date & Time", "[dosdatetime]")
     315             : {
     316             :     if(sizeof(std::time_t) < sizeof(uint64_t))
     317             :     {
     318             :         std::cerr << "warning: Unix to DOS time conversion is ignored on platform with a 32 bit time_t definition." << std::endl;
     319             :         return;
     320             :     }
     321             : 
     322             :     init_min_max();
     323             : 
     324             :     SECTION("all valid DOS Date Time values")
     325             :     {
     326             :         // make sure the maximum limit is checked properly
     327             :         //
     328             :         for(std::time_t t(g_minimum_unix); t <= g_maximum_unix; ++t)
     329             :         {
     330             :             std::time_t et((t + 1) & ~1);
     331             : 
     332             :             zipios::DOSDateTime td;
     333             :             REQUIRE_FALSE(td.isValid());
     334             :             td.setUnixTimestamp(t);
     335             :             REQUIRE(td.isValid());
     336             : 
     337             :             zipios::DOSDateTime::dosdatetime_t const d(td.getDOSDateTime());
     338             : 
     339             :             zipios::DOSDateTime tu;
     340             :             REQUIRE_FALSE(tu.isValid());
     341             :             tu.setDOSDateTime(d);
     342             :             REQUIRE(tu.isValid());
     343             : 
     344             :             std::time_t const u(tu.getUnixTimestamp());
     345             :             REQUIRE(u == et);
     346             :         }
     347             :     }
     348             : }
     349             : #endif
     350             : 
     351             : 
     352           3 : TEST_CASE("Small DOS Date & Time", "[dosdatetime]")
     353             : {
     354             :     if(sizeof(std::time_t) < sizeof(uint64_t))
     355             :     {
     356             :         std::cerr << "warning: Unix to DOS time conversion is ignored on platform with a 32 bit time_t definition." << std::endl;
     357             :         return;
     358             :     }
     359             : 
     360           2 :     init_min_max();
     361             : 
     362           4 :     SECTION("just under the minimum")
     363             :     {
     364             :         // make sure the minimum limit is checked properly
     365             :         //
     366           1 :         for(std::time_t t(g_minimum_unix - 20); t < 0; ++t)
     367             :         {
     368           0 :             zipios::DOSDateTime td;
     369           0 :             REQUIRE_FALSE(td.isValid());
     370           0 :             REQUIRE_THROWS_AS(td.setUnixTimestamp(t), zipios::InvalidException);
     371           0 :             REQUIRE_FALSE(td.isValid());
     372             :         }
     373             :     }
     374             : 
     375           4 :     SECTION("just around minimum, but valid")
     376             :     {
     377             :         // the "g_minimum_unix - 1" case is peculiar, the Unix date is not
     378             :         // usable as is because it is odd and we're going to use the next
     379             :         // second which means we're getting `minimum_unix` as the date,
     380             :         // which is valid!
     381             :         //
     382          22 :         for(std::time_t t(g_minimum_unix); t <= g_minimum_unix + 20; ++t)
     383             :         {
     384          21 :             std::time_t et((t + 1) & ~1);
     385             : 
     386          21 :             zipios::DOSDateTime td;
     387          21 :             REQUIRE_FALSE(td.isValid());
     388          21 :             td.setUnixTimestamp(t);
     389          21 :             REQUIRE(td.isValid());
     390             : 
     391          21 :             zipios::DOSDateTime::dosdatetime_t const d(td.getDOSDateTime());
     392             : 
     393          21 :             zipios::DOSDateTime tu;
     394          21 :             REQUIRE_FALSE(tu.isValid());
     395          21 :             tu.setDOSDateTime(d);
     396          21 :             REQUIRE(tu.isValid());
     397             : 
     398          21 :             std::time_t const u(tu.getUnixTimestamp());
     399          21 :             REQUIRE(u == et);
     400             :         }
     401             :     }
     402             : }
     403             : 
     404             : 
     405           3 : TEST_CASE("Large DOS Date & Time", "[dosdatetime]")
     406             : {
     407             :     if(sizeof(std::time_t) < sizeof(uint64_t))
     408             :     {
     409             :         std::cerr << "warning: Unix to DOS time conversion is ignored on platform with a 32 bit time_t definition." << std::endl;
     410             :         return;
     411             :     }
     412             : 
     413           2 :     init_min_max();
     414             : 
     415           4 :     SECTION("just around maximum, but valid")
     416             :     {
     417             :         // make sure the maximum limit is checked properly
     418             :         //
     419          22 :         for(std::time_t t(g_maximum_unix - 20); t <= g_maximum_unix; ++t)
     420             :         {
     421          21 :             std::time_t et((t + 1) & ~1);
     422             : 
     423          21 :             zipios::DOSDateTime td;
     424          21 :             REQUIRE_FALSE(td.isValid());
     425          21 :             td.setUnixTimestamp(t);
     426          21 :             REQUIRE(td.isValid());
     427             : 
     428          21 :             zipios::DOSDateTime::dosdatetime_t const d(td.getDOSDateTime());
     429             : 
     430          21 :             zipios::DOSDateTime tu;
     431          21 :             REQUIRE_FALSE(tu.isValid());
     432          21 :             tu.setDOSDateTime(d);
     433          21 :             REQUIRE(tu.isValid());
     434             : 
     435          21 :             std::time_t const u(tu.getUnixTimestamp());
     436          21 :             REQUIRE(u == et);
     437             :         }
     438             :     }
     439             : 
     440           4 :     SECTION("just a bit too large")
     441             :     {
     442             :         // make sure the maximum limit is checked properly
     443             :         //
     444          21 :         for(std::time_t t(g_maximum_unix + 1); t <= g_maximum_unix + 20; ++t)
     445             :         {
     446          20 :             std::time_t et((t + 1) & ~1);
     447             : 
     448          20 :             zipios::DOSDateTime td;
     449          20 :             REQUIRE(td.getDOSDateTime() == 0);
     450          20 :             REQUIRE_FALSE(td.isValid());
     451          20 :             REQUIRE_THROWS_AS(td.setUnixTimestamp(t), zipios::InvalidException);
     452          20 :             REQUIRE_FALSE(td.isValid());
     453          20 :             REQUIRE(td.getDOSDateTime() == 0);
     454          20 :             REQUIRE(td.getUnixTimestamp() == 0);
     455             :         }
     456             :     }
     457             : }
     458             : 
     459             : 
     460           2 : TEST_CASE("Random DOS Date & Time", "[dosdatetime]")
     461             : {
     462           1 :     init_min_max();
     463             : 
     464           2 :     SECTION("more random tests")
     465             :     {
     466             :         std::time_t const max(sizeof(std::time_t) < sizeof(uint64_t)
     467             :                                 ? 0x7FFFFFFF        // max. in 32 bits is less in Unix time_t than what the DOS Date Time supports
     468           1 :                                 : 0x104000000LL);   // Dec 31, 2107 23:59:59 is 0x10391447F, so use something a little higher
     469             : 
     470      266643 :         for(std::time_t t(0); t <= max; t += rand() & 0x7FFF)
     471             :         {
     472      266642 :             if(t < g_minimum_unix
     473      247332 :             || t > g_maximum_unix)
     474             :             {
     475       19747 :                 zipios::DOSDateTime td;
     476       19747 :                 REQUIRE_THROWS_AS(td.setUnixTimestamp(t), zipios::InvalidException);
     477             :             }
     478             :             else
     479             :             {
     480      246895 :                 std::time_t et(t);
     481      246895 :                 if(t == g_maximum_unix)
     482             :                 {
     483           0 :                     et += 1;
     484             :                 }
     485      246895 :                 et &= ~1;
     486             : 
     487      246895 :                 zipios::DOSDateTime td;
     488      246895 :                 td.setUnixTimestamp(t);
     489             : 
     490      246895 :                 zipios::DOSDateTime::dosdatetime_t const d(td.getDOSDateTime());
     491             : 
     492      246895 :                 zipios::DOSDateTime tu;
     493      246895 :                 tu.setDOSDateTime(d);
     494             : 
     495      246895 :                 std::time_t const u(tu.getUnixTimestamp());
     496             :             }
     497             :         }
     498             :     }
     499           4 : }
     500             : 
     501             : 
     502             : 
     503             : // Local Variables:
     504             : // mode: cpp
     505             : // indent-tabs-mode: nil
     506             : // c-basic-offset: 4
     507             : // tab-width: 4
     508             : // End:
     509             : 
     510             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12