michael@0: michael@0: var BUGNUMBER; michael@0: var summary; michael@0: michael@0: function runDSTOffsetCachingTestsFraction(part, parts) michael@0: { michael@0: BUGNUMBER = 563938; michael@0: summary = 'Cache DST offsets to improve SunSpider score'; michael@0: michael@0: print(BUGNUMBER + ": " + summary); michael@0: michael@0: var MAX_UNIX_TIMET = 2145859200; michael@0: var RANGE_EXPANSION_AMOUNT = 30 * 24 * 60 * 60; michael@0: michael@0: /** michael@0: * Computes the time zone offset in minutes at the given timestamp. michael@0: */ michael@0: function tzOffsetFromUnixTimestamp(timestamp) michael@0: { michael@0: var d = new Date(NaN); michael@0: d.setTime(timestamp); // local slot = NaN, UTC slot = timestamp michael@0: return d.getTimezoneOffset(); // get UTC, calculate local => diff in minutes michael@0: } michael@0: michael@0: /** michael@0: * Clear the DST offset cache, leaving it initialized to include a timestamp michael@0: * completely unlike the provided one (i.e. one very, very far away in time michael@0: * from it). Thus an immediately following lookup for the provided timestamp michael@0: * will cache-miss and compute a clean value. michael@0: */ michael@0: function clearDSTOffsetCache(undesiredTimestamp) michael@0: { michael@0: var opposite = (undesiredTimestamp + MAX_UNIX_TIMET / 2) % MAX_UNIX_TIMET; michael@0: michael@0: // Generic purge to known, but not necessarily desired, state michael@0: tzOffsetFromUnixTimestamp(0); michael@0: tzOffsetFromUnixTimestamp(MAX_UNIX_TIMET); michael@0: michael@0: // Purge to desired state. Cycle 2x in case opposite or undesiredTimestamp michael@0: // is close to 0 or MAX_UNIX_TIMET. michael@0: tzOffsetFromUnixTimestamp(opposite); michael@0: tzOffsetFromUnixTimestamp(undesiredTimestamp); michael@0: tzOffsetFromUnixTimestamp(opposite); michael@0: tzOffsetFromUnixTimestamp(undesiredTimestamp); michael@0: } michael@0: michael@0: function computeCanonicalTZOffset(timestamp) michael@0: { michael@0: clearDSTOffsetCache(timestamp); michael@0: return tzOffsetFromUnixTimestamp(timestamp); michael@0: } michael@0: michael@0: var TEST_TIMESTAMPS_SECONDS = michael@0: [ michael@0: // Special-ish timestamps michael@0: 0, michael@0: RANGE_EXPANSION_AMOUNT, michael@0: MAX_UNIX_TIMET, michael@0: ]; michael@0: michael@0: var ONE_DAY = 24 * 60 * 60; michael@0: var EIGHTY_THREE_HOURS = 83 * 60 * 60; michael@0: var NINETY_EIGHT_HOURS = 98 * 60 * 60; michael@0: function nextIncrement(i) michael@0: { michael@0: return i === EIGHTY_THREE_HOURS ? NINETY_EIGHT_HOURS : EIGHTY_THREE_HOURS; michael@0: } michael@0: michael@0: // Now add a long sequence of non-special timestamps, from a fixed range, that michael@0: // overlaps a DST change by "a bit" on each side. 67 days should be enough michael@0: // displacement that we can occasionally exercise the implementation's michael@0: // thirty-day expansion and the DST-offset-change logic. Use two different michael@0: // increments just to be safe and catch something a single increment might not. michael@0: var DST_CHANGE_DATE = 1268553600; // March 14, 2010 michael@0: for (var t = DST_CHANGE_DATE - 67 * ONE_DAY, michael@0: i = nextIncrement(NINETY_EIGHT_HOURS), michael@0: end = DST_CHANGE_DATE + 67 * ONE_DAY; michael@0: t < end; michael@0: i = nextIncrement(i), t += i) michael@0: { michael@0: TEST_TIMESTAMPS_SECONDS.push(t); michael@0: } michael@0: michael@0: var TEST_TIMESTAMPS = michael@0: TEST_TIMESTAMPS_SECONDS.map(function(v) { return v * 1000; }); michael@0: michael@0: /************** michael@0: * BEGIN TEST * michael@0: **************/ michael@0: michael@0: // Compute the correct time zone offsets for all timestamps to be tested. michael@0: var CORRECT_TZOFFSETS = TEST_TIMESTAMPS.map(computeCanonicalTZOffset); michael@0: michael@0: // Intentionally and knowingly invoking every single logic path in the cache michael@0: // isn't easy for a human to get right (and know he's gotten it right), so michael@0: // let's do it the easy way: exhaustively try all possible four-date sequences michael@0: // selecting from our array of possible timestamps. michael@0: michael@0: var sz = TEST_TIMESTAMPS.length; michael@0: var start = Math.floor((part - 1) / parts * sz); michael@0: var end = Math.floor(part / parts * sz); michael@0: michael@0: print("Exhaustively testing timestamps " + michael@0: "[" + start + ", " + end + ") of " + sz + "..."); michael@0: michael@0: try michael@0: { michael@0: for (var i = start; i < end; i++) michael@0: { michael@0: print("Testing timestamp " + i + "..."); michael@0: michael@0: var t1 = TEST_TIMESTAMPS[i]; michael@0: for (var j = 0; j < sz; j++) michael@0: { michael@0: var t2 = TEST_TIMESTAMPS[j]; michael@0: for (var k = 0; k < sz; k++) michael@0: { michael@0: var t3 = TEST_TIMESTAMPS[k]; michael@0: for (var w = 0; w < sz; w++) michael@0: { michael@0: var t4 = TEST_TIMESTAMPS[w]; michael@0: michael@0: clearDSTOffsetCache(t1); michael@0: michael@0: var tzo1 = tzOffsetFromUnixTimestamp(t1); michael@0: var tzo2 = tzOffsetFromUnixTimestamp(t2); michael@0: var tzo3 = tzOffsetFromUnixTimestamp(t3); michael@0: var tzo4 = tzOffsetFromUnixTimestamp(t4); michael@0: michael@0: assertEq(tzo1, CORRECT_TZOFFSETS[i]); michael@0: assertEq(tzo2, CORRECT_TZOFFSETS[j]); michael@0: assertEq(tzo3, CORRECT_TZOFFSETS[k]); michael@0: assertEq(tzo4, CORRECT_TZOFFSETS[w]); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: catch (e) michael@0: { michael@0: assertEq(true, false, michael@0: "Error when testing with timestamps " + michael@0: i + ", " + j + ", " + k + ", " + w + michael@0: " (" + t1 + ", " + t2 + ", " + t3 + ", " + t4 + ")!"); michael@0: } michael@0: michael@0: reportCompare(true, true); michael@0: print("All tests passed!"); michael@0: }