Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Redistribution and use in source and binary forms, with or without
3 : // modification, are permitted provided that the following conditions are
4 : // met:
5 : //
6 : // * Redistributions of source code must retain the above copyright
7 : // notice, this list of conditions and the following disclaimer.
8 : // * Redistributions in binary form must reproduce the above
9 : // copyright notice, this list of conditions and the following
10 : // disclaimer in the documentation and/or other materials provided
11 : // with the distribution.
12 : // * Neither the name of Google Inc. nor the names of its
13 : // contributors may be used to endorse or promote products derived
14 : // from this software without specific prior written permission.
15 : //
16 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 :
28 : #include "src/date.h"
29 : #include "src/global-handles.h"
30 : #include "src/isolate.h"
31 : #include "src/v8.h"
32 : #include "test/cctest/cctest.h"
33 :
34 : namespace v8 {
35 : namespace internal {
36 :
37 12 : class DateCacheMock: public DateCache {
38 : public:
39 : struct Rule {
40 : int year, start_month, start_day, end_month, end_day, offset_sec;
41 : };
42 :
43 : DateCacheMock(int local_offset, Rule* rules, int rules_count)
44 6 : : local_offset_(local_offset), rules_(rules), rules_count_(rules_count) {}
45 :
46 : protected:
47 11442 : virtual int GetDaylightSavingsOffsetFromOS(int64_t time_sec) {
48 11442 : int days = DaysFromTime(time_sec * 1000);
49 11442 : int time_in_day_sec = TimeInDay(time_sec * 1000, days) / 1000;
50 : int year, month, day;
51 11442 : YearMonthDayFromDays(days, &year, &month, &day);
52 11442 : Rule* rule = FindRuleFor(year, month, day, time_in_day_sec);
53 11442 : return rule == nullptr ? 0 : rule->offset_sec * 1000;
54 : }
55 :
56 :
57 7224 : virtual int GetLocalOffsetFromOS() {
58 7224 : return local_offset_;
59 : }
60 :
61 : private:
62 11442 : Rule* FindRuleFor(int year, int month, int day, int time_in_day_sec) {
63 : Rule* result = nullptr;
64 57210 : for (int i = 0; i < rules_count_; i++)
65 45768 : if (Match(&rules_[i], year, month, day, time_in_day_sec)) {
66 14856 : result = &rules_[i];
67 : }
68 11442 : return result;
69 : }
70 :
71 :
72 45768 : bool Match(Rule* rule, int year, int month, int day, int time_in_day_sec) {
73 45768 : if (rule->year != 0 && rule->year != year) return false;
74 43536 : if (rule->start_month > month) return false;
75 26244 : if (rule->end_month < month) return false;
76 18300 : int start_day = ComputeRuleDay(year, rule->start_month, rule->start_day);
77 18300 : if (rule->start_month == month && start_day > day) return false;
78 19716 : if (rule->start_month == month && start_day == day &&
79 2460 : 2 * 3600 > time_in_day_sec)
80 : return false;
81 17010 : int end_day = ComputeRuleDay(year, rule->end_month, rule->end_day);
82 17010 : if (rule->end_month == month && end_day < day) return false;
83 16302 : if (rule->end_month == month && end_day == day &&
84 1368 : 2 * 3600 <= time_in_day_sec)
85 : return false;
86 14856 : return true;
87 : }
88 :
89 :
90 35310 : int ComputeRuleDay(int year, int month, int day) {
91 35310 : if (day != 0) return day;
92 24972 : int days = DaysFromYearMonth(year, month);
93 : // Find the first Sunday of the month.
94 171912 : while (Weekday(days + day) != 6) day++;
95 24972 : return day + 1;
96 : }
97 :
98 : int local_offset_;
99 : Rule* rules_;
100 : int rules_count_;
101 : };
102 :
103 : static int64_t TimeFromYearMonthDay(DateCache* date_cache,
104 : int year,
105 : int month,
106 : int day) {
107 570 : int64_t result = date_cache->DaysFromYearMonth(year, month);
108 570 : return (result + day - 1) * DateCache::kMsPerDay;
109 : }
110 :
111 :
112 7218 : static void CheckDST(int64_t time) {
113 7218 : Isolate* isolate = CcTest::i_isolate();
114 : DateCache* date_cache = isolate->date_cache();
115 7218 : int64_t actual = date_cache->ToLocal(time);
116 14436 : int64_t expected = time + date_cache->GetLocalOffsetFromOS() +
117 14436 : date_cache->GetDaylightSavingsOffsetFromOS(time / 1000);
118 7218 : CHECK_EQ(actual, expected);
119 7218 : }
120 :
121 :
122 23724 : TEST(DaylightSavingsTime) {
123 6 : LocalContext context;
124 6 : v8::Isolate* isolate = context->GetIsolate();
125 12 : v8::HandleScope scope(isolate);
126 : DateCacheMock::Rule rules[] = {
127 : {0, 2, 0, 10, 0, 3600}, // DST from March to November in any year.
128 : {2010, 2, 0, 7, 20, 3600}, // DST from March to August 20 in 2010.
129 : {2010, 7, 20, 8, 10, 0}, // No DST from August 20 to September 10 in 2010.
130 : {2010, 8, 10, 10, 0, 3600}, // DST from September 10 to November in 2010.
131 6 : };
132 :
133 : int local_offset_ms = -36000000; // -10 hours.
134 :
135 : DateCacheMock* date_cache =
136 6 : new DateCacheMock(local_offset_ms, rules, arraysize(rules));
137 :
138 : reinterpret_cast<Isolate*>(isolate)->set_date_cache(date_cache);
139 :
140 : int64_t start_of_2010 = TimeFromYearMonthDay(date_cache, 2010, 0, 1);
141 : int64_t start_of_2011 = TimeFromYearMonthDay(date_cache, 2011, 0, 1);
142 : int64_t august_20 = TimeFromYearMonthDay(date_cache, 2010, 7, 20);
143 : int64_t september_10 = TimeFromYearMonthDay(date_cache, 2010, 8, 10);
144 6 : CheckDST((august_20 + september_10) / 2);
145 6 : CheckDST(september_10);
146 6 : CheckDST(september_10 + 2 * 3600);
147 6 : CheckDST(september_10 + 2 * 3600 - 1000);
148 6 : CheckDST(august_20 + 2 * 3600);
149 6 : CheckDST(august_20 + 2 * 3600 - 1000);
150 6 : CheckDST(august_20);
151 : // Check each day of 2010.
152 2202 : for (int64_t time = start_of_2011 + 2 * 3600;
153 : time >= start_of_2010;
154 : time -= DateCache::kMsPerDay) {
155 2196 : CheckDST(time);
156 2196 : CheckDST(time - 1000);
157 2196 : CheckDST(time + 1000);
158 : }
159 : // Check one day from 2010 to 2100.
160 546 : for (int year = 2100; year >= 2010; year--) {
161 546 : CheckDST(TimeFromYearMonthDay(date_cache, year, 5, 5));
162 : }
163 6 : CheckDST((august_20 + september_10) / 2);
164 6 : CheckDST(september_10);
165 6 : CheckDST(september_10 + 2 * 3600);
166 6 : CheckDST(september_10 + 2 * 3600 - 1000);
167 6 : CheckDST(august_20 + 2 * 3600);
168 6 : CheckDST(august_20 + 2 * 3600 - 1000);
169 12 : CheckDST(august_20);
170 6 : }
171 :
172 : namespace {
173 : int legacy_parse_count = 0;
174 36 : void DateParseLegacyCounterCallback(v8::Isolate* isolate,
175 : v8::Isolate::UseCounterFeature feature) {
176 36 : if (feature == v8::Isolate::kLegacyDateParser) legacy_parse_count++;
177 36 : }
178 : } // anonymous namespace
179 :
180 23724 : TEST(DateParseLegacyUseCounter) {
181 6 : CcTest::InitializeVM();
182 6 : v8::HandleScope scope(CcTest::isolate());
183 12 : LocalContext context;
184 6 : CcTest::isolate()->SetUseCounterCallback(DateParseLegacyCounterCallback);
185 6 : CHECK_EQ(0, legacy_parse_count);
186 : CompileRun("Date.parse('2015-02-31')");
187 6 : CHECK_EQ(0, legacy_parse_count);
188 : CompileRun("Date.parse('2015-02-31T11:22:33.444Z01:23')");
189 6 : CHECK_EQ(0, legacy_parse_count);
190 : CompileRun("Date.parse('2015-02-31T11:22:33.444')");
191 6 : CHECK_EQ(0, legacy_parse_count);
192 : CompileRun("Date.parse('2000 01 01')");
193 6 : CHECK_EQ(1, legacy_parse_count);
194 : CompileRun("Date.parse('2015-02-31T11:22:33.444 ')");
195 12 : CHECK_EQ(1, legacy_parse_count);
196 6 : }
197 :
198 : #ifdef V8_INTL_SUPPORT
199 23724 : TEST(DateCacheVersion) {
200 6 : FLAG_allow_natives_syntax = true;
201 6 : v8::Isolate* isolate = CcTest::isolate();
202 : v8::Isolate::Scope isolate_scope(isolate);
203 12 : v8::HandleScope scope(isolate);
204 6 : v8::Local<v8::Context> context = v8::Context::New(isolate);
205 : v8::Context::Scope context_scope(context);
206 : v8::Local<v8::Number> date_cache_version =
207 : v8::Local<v8::Number>::Cast(CompileRun("%DateCacheVersion()"));
208 :
209 6 : CHECK(date_cache_version->IsNumber());
210 12 : CHECK_EQ(0.0, date_cache_version->NumberValue(context).FromMaybe(-1.0));
211 :
212 6 : v8::Date::DateTimeConfigurationChangeNotification(isolate);
213 :
214 : date_cache_version =
215 : v8::Local<v8::Number>::Cast(CompileRun("%DateCacheVersion()"));
216 6 : CHECK(date_cache_version->IsNumber());
217 12 : CHECK_EQ(1.0, date_cache_version->NumberValue(context).FromMaybe(-1.0));
218 6 : }
219 : #endif // V8_INTL_SUPPORT
220 :
221 : } // namespace internal
222 71154 : } // namespace v8
|