test robustness against DST transition
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Fri, 26 Apr 2019 13:42:35 +0000 (15:42 +0200)
committerPhilipp Gesang <philipp.gesang@intra2net.com>
Fri, 26 Apr 2019 14:29:44 +0000 (16:29 +0200)
test/test_timefunc.cpp

index 6192b78..74174c7 100644 (file)
@@ -35,6 +35,7 @@ on this file might be covered by the GNU General Public License.
 #endif
 
 #define BOOST_TEST_DYN_LINK
+#include <time.h>
 #include <boost/test/unit_test.hpp>
 
 #include <timefunc.hxx>
@@ -53,7 +54,13 @@ class TestTimeFuncFixture
 protected:
    typedef std::list< std::string > StringList;
    std::set<std::string>  used_check_files;
-   std::string tz; /* save and restore TZ from envp */
+
+   struct {
+       std::string env; /* save and restore TZ from envp */
+       char *name[2];
+       long zone;
+       int dst;
+   } timezone;
 
    std::string get_check_file_path(std::string tag)
    {
@@ -63,6 +70,12 @@ protected:
       return result;
    } // eo get_check_file_path
 
+   void dump_tz_info (void)
+   {
+       fprintf (stderr, "timezone: %s(%s) %ld, dst: %d\n",
+                tzname[0], tzname[1], ::timezone, daylight);
+   }
+
    void remove_check_files()
    {
       for (std::set<std::string>::iterator it= used_check_files.begin();
@@ -99,28 +112,43 @@ protected:
        this->set_tz ("UTC");
    }
 
+   void set_dst (const bool dst=true)
+   {
+       daylight = dst ? 1 : 0;
+       tzset ();
+   }
+
 public:
     TestTimeFuncFixture()
-        : tz (secure_getenv ("TZ") ?: "")
     {
+        this->timezone.env = std::string (secure_getenv ("TZ") ?: "");
+        this->timezone.name[0] = tzname [0];
+        this->timezone.name[1] = tzname [1];
+        this->timezone.zone = ::timezone;
+        this->timezone.dst = daylight;
     }
 
     ~TestTimeFuncFixture()
     {
         remove_check_files();
 
+        /* time zone related cleanup */
+        daylight = this->timezone.dst;
+        ::timezone = this->timezone.zone;
+
+        tzname [0] = this->timezone.name[0];
+        tzname [1] = this->timezone.name[1];
+
         errno = 0;
-        if (setenv ("TZ", this->tz.c_str (), 1) == -1)
+        if (setenv ("TZ", this->timezone.env.c_str (), 1) == -1)
         {
             std::cerr
-                << "error cleaning up environment 'TZ': [" << this->tz << "]"
+                << "error cleaning up environment 'TZ': [" << this->timezone.env << "]"
                 << std::endl
                 ;
         }
-        else
-        {
-            tzset();
-        }
+
+        tzset();
     }
 };
 
@@ -1272,6 +1300,27 @@ BOOST_AUTO_TEST_SUITE(Clock)
         BOOST_CHECK_EQUAL(*t3->format_iso8601 (), "2019-04-25T15:41:47+0000");
     }
 
+    BOOST_AUTO_TEST_CASE(FromString_iso8601_dst)
+    {
+        const std::string in1 ("2019-03-30T12:42:42"); /* “winter time” */
+        const std::string in2 ("2019-03-31T12:42:42"); /* “summer time” */
+
+        this->set_utc ();
+        boost::optional<I2n::clock::Time> t1 = I2n::clock::time_of_iso8601 (in1, true, true, false);
+        boost::optional<I2n::clock::Time> t2 = I2n::clock::time_of_iso8601 (in2, true, true, false);
+
+        BOOST_CHECK(t1);
+        BOOST_CHECK(t2);
+        BOOST_CHECK_EQUAL(t1->get_sec (), 1553949762);
+        BOOST_CHECK_EQUAL(t2->get_sec (), 1554036162);
+        BOOST_CHECK_EQUAL(*t1->format_iso8601 (), in1 + "+0000");
+        BOOST_CHECK_EQUAL(*t2->format_iso8601 (), in2 + "+0000");
+
+        this->set_tz ("CET");
+        BOOST_CHECK_EQUAL(*t1->format_iso8601 (false, true, true, true), "2019-03-30T13:42:42+0100");
+        BOOST_CHECK_EQUAL(*t2->format_iso8601 (false, true, true, true), "2019-03-31T14:42:42+0200");
+    }
+
     BOOST_AUTO_TEST_CASE(FromString_iso8601_tzdiff)
     {
         const std::string in ("2019-04-26T13:45:02+0000");