blob: 59166a7c82dd26a9ebe7abcdd2171266b5986e38 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "absl/time/internal/test_util.h"
16
17#include <algorithm>
18#include <cstddef>
19#include <cstring>
20
21#include "absl/base/internal/raw_logging.h"
22#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
23
24namespace cctz = absl::time_internal::cctz;
25
26namespace absl {
27namespace time_internal {
28
29TimeZone LoadTimeZone(const std::string& name) {
30 TimeZone tz;
31 ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str());
32 return tz;
33}
34
35} // namespace time_internal
36} // namespace absl
37
38namespace absl {
39namespace time_internal {
40namespace cctz_extension {
41namespace {
42
43// Embed the zoneinfo data for time zones used during tests and benchmarks.
44// The data was generated using "xxd -i zoneinfo-file". There is no need
45// to update the data as long as the tests do not depend on recent changes
46// (and the past rules remain the same).
47#include "absl/time/internal/zoneinfo.inc"
48
49const struct ZoneInfo {
50 const char* name;
51 const char* data;
52 std::size_t length;
53} kZoneInfo[] = {
54 // The three real time zones used by :time_test and :time_benchmark.
55 {"America/Los_Angeles", //
56 reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
57 {"America/New_York", //
58 reinterpret_cast<char*>(America_New_York), America_New_York_len},
59 {"Australia/Sydney", //
60 reinterpret_cast<char*>(Australia_Sydney), Australia_Sydney_len},
61
62 // Other zones named in tests but which should fail to load.
63 {"Invalid/TimeZone", nullptr, 0},
64 {"", nullptr, 0},
65
66 // Also allow for loading the local time zone under TZ=US/Pacific.
67 {"US/Pacific", //
68 reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
69
70 // Allows use of the local time zone from a system-specific location.
71#ifdef _MSC_VER
72 {"localtime", //
73 reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
74#else
75 {"/etc/localtime", //
76 reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
77#endif
78};
79
80class TestZoneInfoSource : public cctz::ZoneInfoSource {
81 public:
82 TestZoneInfoSource(const char* data, std::size_t size)
83 : data_(data), end_(data + size) {}
84
85 std::size_t Read(void* ptr, std::size_t size) override {
86 const std::size_t len = std::min<std::size_t>(size, end_ - data_);
87 memcpy(ptr, data_, len);
88 data_ += len;
89 return len;
90 }
91
92 int Skip(std::size_t offset) override {
93 data_ += std::min<std::size_t>(offset, end_ - data_);
94 return 0;
95 }
96
97 private:
98 const char* data_;
99 const char* const end_;
100};
101
102std::unique_ptr<cctz::ZoneInfoSource> TestFactory(
103 const std::string& name,
104 const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
105 const std::string& name)>& /*fallback_factory*/) {
106 for (const ZoneInfo& zoneinfo : kZoneInfo) {
107 if (name == zoneinfo.name) {
108 if (zoneinfo.data == nullptr) return nullptr;
109 return std::unique_ptr<cctz::ZoneInfoSource>(
110 new TestZoneInfoSource(zoneinfo.data, zoneinfo.length));
111 }
112 }
113 ABSL_RAW_LOG(FATAL, "Unexpected time zone \"%s\" in test", name.c_str());
114 return nullptr;
115}
116
117} // namespace
118
119ZoneInfoSourceFactory zone_info_source_factory = TestFactory;
120
121} // namespace cctz_extension
122} // namespace time_internal
123} // namespace absl