// Copyright 2019 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/i18n/icu_util.h" #include "base/files/file_util.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/icu/source/common/unicode/uclean.h" #include "third_party/icu/source/i18n/unicode/timezone.h" namespace base { namespace i18n { namespace { // Directory path to the tzdata configuration files. const char kTzDataDirPath[] = "/pkg/base/test/data/tzdata/icu/44/le"; // File path to the text file containing the expected ICU library revision, for // example "2019c". const char kRevisionFilePath[] = "/config/data/tzdata/revision.txt"; } // namespace class TimeZoneDataTest : public testing::Test { protected: void SetUp() override { ResetIcu(); } void TearDown() override { ResetIcu(); } // Needed to enable loading of ICU config files that are different from what // is available in Chromium. Both icu_util and ICU library keep internal // state so clear both. void ResetIcu() { // Clears the state in the reverse order of construction. u_cleanup(); ResetGlobalsForTesting(); } void GetActualRevision(std::string* icu_version) { UErrorCode err = U_ZERO_ERROR; *icu_version = icu::TimeZone::getTZDataVersion(err); ASSERT_EQ(U_ZERO_ERROR, err) << u_errorName(err); } }; // Loads a file revision.txt from the actual underlying filesystem, which // contains the tzdata version we expect to be able to load. It then attempts // to load this configuration from the default path and compares the version it // obtained from the load with the expected version, failing on version // mismatch. // // In Fuchsia build bot setup, we ensure that the file revision.txt exists, so // that this test is not skipped. In Chromium build bot setup, this file may // not be present, in which case we skip running this test. TEST_F(TimeZoneDataTest, CompareSystemRevisionWithExpected) { if (!base::PathExists(base::FilePath(kRevisionFilePath))) { LOG(INFO) << "Skipped test because tzdata config is not present"; return; } // ResetIcu() ensures that time zone data is loaded from the default location. ASSERT_TRUE(InitializeICU()); std::string expected; ASSERT_TRUE( base::ReadFileToString(base::FilePath(kRevisionFilePath), &expected)); std::string actual; GetActualRevision(&actual); EXPECT_EQ(expected, actual); } // Verifies that the current version of the ICU library in use can load ICU // data in a specific version format (in this case 44). Designed to fail if // the ICU library version used in Chromium drifts from version 44 so much that // the library is no longer able to load the old tzdata. If the test fails, // this could be a sign that all platforms Chromium runs on need to upgrade the // ICU library versions. TEST_F(TimeZoneDataTest, TestLoadingTimeZoneDataFromKnownConfigs) { ASSERT_TRUE(base::DirectoryExists(base::FilePath(kTzDataDirPath))); SetIcuTimeZoneDataDirForTesting(kTzDataDirPath); EXPECT_TRUE(InitializeICU()); std::string actual; GetActualRevision(&actual); EXPECT_EQ("2019a", actual) << "If ICU no longer supports this tzdata " "version, tzdata version needs to be upgraded"; } TEST_F(TimeZoneDataTest, DoesNotCrashWithInvalidPath) { SetIcuTimeZoneDataDirForTesting("/some/nonexistent/path"); EXPECT_TRUE(InitializeICU()); std::string actual; GetActualRevision(&actual); EXPECT_TRUE( base::StartsWith(actual, "20", base::CompareCase::INSENSITIVE_ASCII)) << "Got version: " << actual; } } // namespace i18n } // namespace base