• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/i18n/icu_util.h"
6 
7 #include "base/files/file_util.h"
8 #include "base/logging.h"
9 #include "base/strings/string_util.h"
10 #include "base/test/icu_test_util.h"
11 #include "build/build_config.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/icu/source/common/unicode/uclean.h"
14 #include "third_party/icu/source/i18n/unicode/timezone.h"
15 
16 namespace base {
17 namespace i18n {
18 
19 namespace {
20 
21 // Directory path to the tzdata configuration files.
22 const char kTzDataDirPath[] = "/pkg/base/test/data/tzdata/icu/44/le";
23 
24 // File path to the text file containing the expected ICU library revision, for
25 // example "2019c".
26 const char kRevisionFilePath[] = "/config/data/tzdata/revision.txt";
27 
28 }  // namespace
29 
30 class TimeZoneDataTest : public testing::Test {
31  protected:
TearDown()32   void TearDown() override {
33     ResetIcu();
34 
35     // ICU must be set back up in case e.g. a log statement that formats times
36     // uses it.
37     test::InitializeICUForTesting();
38   }
39 
40   // Needed to enable loading of ICU config files that are different from what
41   // is available in Chromium.  Both icu_util and ICU library keep internal
42   // state so clear both.
ResetIcu()43   void ResetIcu() {
44     // Clears the state in the reverse order of construction.
45     u_cleanup();
46     ResetGlobalsForTesting();
47   }
48 
GetActualRevision(std::string * icu_version)49   void GetActualRevision(std::string* icu_version) {
50     UErrorCode err = U_ZERO_ERROR;
51     *icu_version = icu::TimeZone::getTZDataVersion(err);
52     ASSERT_EQ(U_ZERO_ERROR, err) << u_errorName(err);
53   }
54 };
55 
56 // Loads a file revision.txt from the actual underlying filesystem, which
57 // contains the tzdata version we expect to be able to load.  It then attempts
58 // to load this configuration from the default path and compares the version it
59 // obtained from the load with the expected version, failing on version
60 // mismatch.
61 //
62 // In Fuchsia build bot setup, we ensure that the file revision.txt exists, so
63 // that this test is not skipped. In Chromium build bot setup, this file may
64 // not be present, in which case we skip running this test.
TEST_F(TimeZoneDataTest,CompareSystemRevisionWithExpected)65 TEST_F(TimeZoneDataTest, CompareSystemRevisionWithExpected) {
66   if (!base::PathExists(base::FilePath(kRevisionFilePath))) {
67     GTEST_SKIP() << "Skipped test because tzdata config is not present";
68   }
69 
70   // ResetIcu() ensures that time zone data is loaded from the default location.
71   // This is done after the GTEST_SKIP() call above, since that may output a
72   // timestamp that requires ICU to be set up.
73   ResetIcu();
74 
75   ASSERT_TRUE(InitializeICU());
76   std::string expected;
77   EXPECT_TRUE(
78       base::ReadFileToString(base::FilePath(kRevisionFilePath), &expected));
79   std::string actual;
80   GetActualRevision(&actual);
81   EXPECT_EQ(expected, actual);
82 }
83 
84 // Verifies that the current version of the ICU library in use can load ICU
85 // data in a specific version format (in this case 44).  Designed to fail if
86 // the ICU library version used in Chromium drifts from version 44 so much that
87 // the library is no longer able to load the old tzdata.  If the test fails,
88 // this could be a sign that all platforms Chromium runs on need to upgrade the
89 // ICU library versions.
TEST_F(TimeZoneDataTest,TestLoadingTimeZoneDataFromKnownConfigs)90 TEST_F(TimeZoneDataTest, TestLoadingTimeZoneDataFromKnownConfigs) {
91   ASSERT_TRUE(base::DirectoryExists(base::FilePath(kTzDataDirPath)));
92   ResetIcu();
93   SetIcuTimeZoneDataDirForTesting(kTzDataDirPath);
94 
95   ASSERT_TRUE(InitializeICU());
96   std::string actual;
97   GetActualRevision(&actual);
98   EXPECT_EQ("2019a", actual) << "If ICU no longer supports this tzdata "
99                                 "version, tzdata version needs to be upgraded";
100 }
101 
TEST_F(TimeZoneDataTest,DoesNotCrashWithInvalidPath)102 TEST_F(TimeZoneDataTest, DoesNotCrashWithInvalidPath) {
103   ResetIcu();
104   SetIcuTimeZoneDataDirForTesting("/some/nonexistent/path");
105 
106   ASSERT_TRUE(InitializeICU());
107   std::string actual;
108   GetActualRevision(&actual);
109   EXPECT_TRUE(
110       base::StartsWith(actual, "20", base::CompareCase::INSENSITIVE_ASCII))
111       << "Got version: " << actual;
112 }
113 
114 }  // namespace i18n
115 }  // namespace base
116