File: C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/tzinfo-1.2.11/test/tc_transition_rule.rb
require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
include TZInfo
class TCTransitionRule < Minitest::Test
[-1, 0, 1].each do |transition_at|
define_method "test_transition_at_#{transition_at}" do
rule = TestTransitionRule.new(transition_at)
assert_equal(transition_at, rule.transition_at)
end
end
[
[-1, 19, 23, 59, 59],
[0, 20, 0, 0, 0],
[1, 20, 0, 0, 1],
[60, 20, 0, 1, 0],
[86399, 20, 23, 59, 59],
[86400, 21, 0, 0, 0]
].each do |(transition_at, expected_day, expected_hour, expected_minute, expected_second)|
define_method "test_at_with_transition_at_#{transition_at}" do
offset = TimezoneOffset.new(0, 0, 'TEST')
rule = TestTransitionRule.new(transition_at) do |y|
assert_equal(2020, y)
TimeOrDateTime.wrap(Time.utc(2020, 3, 20))
end
result = rule.at(offset, 2020)
assert_kind_of(TimeOrDateTime, result)
assert_equal(Time.utc(2020, 3, expected_day, expected_hour, expected_minute, expected_second), result.to_time)
end
end
[-7200, 0, 7200].each do |offset_seconds|
define_method "test_at_with_offset_#{offset_seconds}" do
offset = TimezoneOffset.new(offset_seconds, 0, 'TEST')
rule = TestTransitionRule.new(3600) do |y|
assert_equal(2020, y)
TimeOrDateTime.wrap(Time.utc(2020, 3, 20))
end
result = rule.at(offset, 2020)
assert_kind_of(TimeOrDateTime, result)
assert_equal(Time.utc(2020, 3, 20, 1, 0, 0) - offset_seconds, result.to_time)
end
end
[2020, 2021].each do |year|
define_method "test_at_with_year_#{year}" do
offset = TimezoneOffset.new(0, 0, 'TEST')
rule = TestTransitionRule.new(3600) do |y|
assert_equal(year, y)
TimeOrDateTime.wrap(Time.utc(year, 3, 20))
end
result = rule.at(offset, year)
assert_kind_of(TimeOrDateTime, result)
assert_equal(Time.utc(year, 3, 20, 1, 0, 0), result.to_time)
end
end
def test_at_crosses_64_bit_boundary
offset = TimezoneOffset.new(0, 0, 'TEST')
rule = TestTransitionRule.new(11648) do |y|
assert_equal(2038, y)
TimeOrDateTime.wrap(Time.utc(2038, 1, 19))
end
result = rule.at(offset, 2038)
assert_kind_of(TimeOrDateTime, result)
if RubyCoreSupport.time_supports_64bit
assert_kind_of(Time, result.to_orig)
else
assert_kind_of(DateTime, result.to_orig)
end
assert_equal(DateTime.new(2038, 1, 19, 3, 14, 8), result.to_datetime)
end
def test_at_crosses_negative_boundary
offset = TimezoneOffset.new(0, 0, 'TEST')
rule = TestTransitionRule.new(-1) do |y|
assert_equal(1970, y)
TimeOrDateTime.wrap(Time.utc(1970, 1, 1))
end
result = rule.at(offset, 1970)
assert_kind_of(TimeOrDateTime, result)
if RubyCoreSupport.time_supports_negative
assert_kind_of(Time, result.to_orig)
else
assert_kind_of(DateTime, result.to_orig)
end
assert_equal(DateTime.new(1969, 12, 31, 23, 59, 59), result.to_datetime)
end
NEGATIVE_DATES = [[1969, 12, 31]]
B32_DATES = [[1970, 1, 1], [2038, 1, 19]]
B64_DATES = [[2038, 1, 20], [2038, 2, 1], [2039, 1, 1]]
B32_DATES.concat(RubyCoreSupport.time_supports_negative ? NEGATIVE_DATES : []).concat(RubyCoreSupport.time_supports_64bit ? B64_DATES : []).each do |(year, month, day)|
define_method "test_new_time_or_datetime_returns_time_based_instance_for_#{year}_#{month}_#{day}" do
result = TestTransitionRule.new(0).new_time_or_datetime!(year, month, day)
assert_kind_of(TimeOrDateTime, result)
assert_kind_of(Time, result.to_orig)
assert_equal(Time.utc(year, month, day), result.to_orig)
end
end
(RubyCoreSupport.time_supports_negative ? [] : NEGATIVE_DATES).concat(RubyCoreSupport.time_supports_64bit ? [] : B64_DATES).each do |(year, month, day)|
define_method "test_new_time_or_datetime_returns_datetime_based_instance_for_#{year}_#{month}_#{day}" do
result = TestTransitionRule.new(0).new_time_or_datetime!(year, month, day)
assert_kind_of(TimeOrDateTime, result)
assert_kind_of(DateTime, result.to_orig)
assert_equal(DateTime.new(year, month, day), result.to_orig)
end
end
[1900, 2021, 2039].each do |year|
define_method "test_new_time_or_datetime_returns_march_1_for_feb_29_on_non_leap_year_#{year}" do
result = TestTransitionRule.new(0).new_time_or_datetime!(year, 2, 29)
assert_kind_of(TimeOrDateTime, result)
assert_equal(DateTime.new(year, 3, 1), result.to_datetime)
end
end
[1968, 2000, 2040].each do |year|
define_method "test_new_time_or_datetime_returns_feb_29_on_leap_year_#{year}" do
result = TestTransitionRule.new(0).new_time_or_datetime!(year, 2, 29)
assert_kind_of(TimeOrDateTime, result)
assert_equal(DateTime.new(year, 2, 29), result.to_datetime)
end
end
class TestTransitionRule < TransitionRule
def initialize(transition_at, &block)
super(transition_at)
@get_day = block
end
alias new_time_or_datetime! new_time_or_datetime
public :new_time_or_datetime!
protected
def get_day(year)
@get_day.call(year)
end
end
end
module BaseTransitionRuleTestHelper
def test_invalid_transition_at
error = assert_raises(ArgumentError) { create_with_transition_at('0') }
assert_match(/\btransition_at(\b.*)?/, error.message)
end
[:==, :eql?].each do |method|
define_method "test_not_equal_by_transition_at_with_#{method}" do
rule1 = create_with_transition_at(0)
rule2 = create_with_transition_at(1)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
define_method "test_not_equal_to_other_with_#{method}" do
rule = create_with_transition_at(0)
assert_equal(false, rule.send(method, Object.new))
end
end
end
class TCAbsoluteDayOfYearTransitionRule < Minitest::Test
include BaseTransitionRuleTestHelper
[-1, 366, '0'].each do |value|
define_method "test_invalid_day_#{value}" do
error = assert_raises(ArgumentError) { AbsoluteDayOfYearTransitionRule.new(value) }
assert_match(/\bday\b/, error.message)
end
end
[
[2020, 0, 1, 1],
[2020, 58, 2, 28],
[2020, 59, 2, 29],
[2020, 365, 12, 31],
[2021, 59, 3, 1],
[2021, 365, 13, 1],
[2100, 59, 3, 1],
[2100, 365, 13, 1],
[2000, 59, 2, 29],
[2000, 365, 12, 31]
].each do |(year, day, expected_month, expected_day)|
define_method "test_day_#{day}_of_year_#{year}" do
rule = AbsoluteDayOfYearTransitionRule.new(day, 3600)
offset = TimezoneOffset.new(0, 0, 'TEST')
result = rule.at(offset, year)
expected_year = year
if expected_month == 13
expected_year += 1
expected_month = 1
end
assert_kind_of(TimeOrDateTime, result)
assert_equal(DateTime.new(expected_year, expected_month, expected_day, 1, 0, 0), result.to_datetime)
end
end
def test_crosses_64_bit_boundary
# Internally the calculation starts with Jan 1 and adds days. Jan 20 2038
# will require a DateTime on 32-bit only systems.
rule = AbsoluteDayOfYearTransitionRule.new(19, 3600)
offset = TimezoneOffset.new(0, 0, 'TEST')
result = rule.at(offset, 2038)
assert_kind_of(TimeOrDateTime, result)
if RubyCoreSupport.time_supports_64bit
assert_kind_of(Time, result.to_orig)
else
assert_kind_of(DateTime, result.to_orig)
end
assert_equal(DateTime.new(2038, 1, 20, 1, 0, 0), result.to_datetime)
end
def test_day_0_is_always_first_day_of_year
rule = AbsoluteDayOfYearTransitionRule.new(0)
assert_equal(true, rule.is_always_first_day_of_year?)
end
[1, 365].each do |day|
define_method "test_day_#{day}_is_not_always_first_day_of_year" do
rule = AbsoluteDayOfYearTransitionRule.new(day)
assert_equal(false, rule.is_always_first_day_of_year?)
end
define_method "test_day_#{day}_is_not_always_last_day_of_year" do
rule = AbsoluteDayOfYearTransitionRule.new(day)
assert_equal(false, rule.is_always_last_day_of_year?)
end
end
[:==, :eql?].each do |method|
[
[0, 0],
[0, 3600],
[365, 0]
].each do |(day, transition_at)|
define_method "test_equal_for_day_#{day}_and_transition_at_#{transition_at}_with_#{method}" do
rule1 = AbsoluteDayOfYearTransitionRule.new(day, transition_at)
rule2 = AbsoluteDayOfYearTransitionRule.new(day, transition_at)
assert_equal(true, rule1.send(method, rule2))
assert_equal(true, rule2.send(method, rule1))
end
end
define_method "test_not_equal_by_day_with_#{method}" do
rule1 = AbsoluteDayOfYearTransitionRule.new(0, 3600)
rule2 = AbsoluteDayOfYearTransitionRule.new(1, 3600)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
define_method "test_not_equal_to_julian_with_#{method}" do
rule1 = AbsoluteDayOfYearTransitionRule.new(1, 0)
rule2 = JulianDayOfYearTransitionRule.new(1, 0)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
end
[
[0, 0],
[0, 3600],
[365, 0]
].each do |(day, transition_at)|
define_method "test_hash_for_day_#{day}_and_transition_at_#{transition_at}" do
rule = AbsoluteDayOfYearTransitionRule.new(day, transition_at)
expected = [AbsoluteDayOfYearTransitionRule, day * 86400, transition_at].hash
assert_equal(expected, rule.hash)
end
end
protected
def create_with_transition_at(transition_at)
AbsoluteDayOfYearTransitionRule.new(1, transition_at)
end
end
class TCJulianDayOfYearTransitionRule < Minitest::Test
include BaseTransitionRuleTestHelper
[0, 366, '1'].each do |value|
define_method "test_invalid_day_#{value}" do
error = assert_raises(ArgumentError) { JulianDayOfYearTransitionRule.new(value) }
assert_match(/\bday\b/, error.message)
end
end
[2020, 2021, 2100, 2000].each do |year|
[
[1, 1, 1],
[59, 2, 28],
[60, 3, 1],
[365, 12, 31]
].each do |(day, expected_month, expected_day)|
define_method "test_day_#{day}_of_year_#{year}" do
rule = JulianDayOfYearTransitionRule.new(day, 3600)
offset = TimezoneOffset.new(0, 0, 'TEST')
result = rule.at(offset, year)
assert_kind_of(TimeOrDateTime, result)
assert_equal(DateTime.new(year, expected_month, expected_day, 1, 0, 0), result.to_datetime)
end
end
end
def test_day_1_is_always_first_day_of_year
rule = JulianDayOfYearTransitionRule.new(1)
assert_equal(true, rule.is_always_first_day_of_year?)
end
[2, 365].each do |day|
define_method "test_day_#{day}_is_not_always_first_day_of_year" do
rule = JulianDayOfYearTransitionRule.new(day)
assert_equal(false, rule.is_always_first_day_of_year?)
end
end
def test_day_365_is_always_last_day_of_year
rule = JulianDayOfYearTransitionRule.new(365)
assert_equal(true, rule.is_always_last_day_of_year?)
end
[1, 364].each do |day|
define_method "test_day_#{day}_is_not_always_last_day_of_year" do
rule = JulianDayOfYearTransitionRule.new(day)
assert_equal(false, rule.is_always_last_day_of_year?)
end
end
[:==, :eql?].each do |method|
[
[1, 0],
[1, 3600],
[365, 0]
].each do |(day, transition_at)|
define_method "test_equal_for_day_#{day}_and_transition_at_#{transition_at}_with_#{method}" do
rule1 = JulianDayOfYearTransitionRule.new(day, transition_at)
rule2 = JulianDayOfYearTransitionRule.new(day, transition_at)
assert_equal(true, rule1.send(method, rule2))
assert_equal(true, rule2.send(method, rule1))
end
end
define_method "test_not_equal_by_day_with_#{method}" do
rule1 = JulianDayOfYearTransitionRule.new(1, 0)
rule2 = JulianDayOfYearTransitionRule.new(2, 0)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
define_method "test_not_equal_to_absolute_with_#{method}" do
rule1 = JulianDayOfYearTransitionRule.new(1, 0)
rule2 = AbsoluteDayOfYearTransitionRule.new(1, 0)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
end
[
[1, 0],
[1, 3600],
[365, 0]
].each do |(day, transition_at)|
define_method "test_hash_for_day_#{day}_and_transition_at_#{transition_at}" do
rule = JulianDayOfYearTransitionRule.new(day, transition_at)
expected = [JulianDayOfYearTransitionRule, day * 86400, transition_at].hash
assert_equal(expected, rule.hash)
end
end
protected
def create_with_transition_at(transition_at)
JulianDayOfYearTransitionRule.new(1, transition_at)
end
end
module DayOfWeekTransitionRuleTestHelper
[-1, 0, 13, '1'].each do |month|
define_method "test_invalid_month_#{month}" do
error = assert_raises(ArgumentError) { create_with_month_and_day_of_week(month, 0) }
assert_match(/\bmonth\b/, error.message)
end
end
[-1, 7, '0'].each do |day_of_week|
define_method "test_invalid_day_of_week_#{day_of_week}" do
error = assert_raises(ArgumentError) { create_with_month_and_day_of_week(1, day_of_week) }
assert_match(/\bday_of_week\b/, error.message)
end
end
def test_is_not_always_first_day_of_year
rule = create_with_month_and_day_of_week(1, 0)
assert_equal(false, rule.is_always_first_day_of_year?)
end
def test_is_not_always_last_day_of_year
rule = create_with_month_and_day_of_week(12, 6)
assert_equal(false, rule.is_always_last_day_of_year?)
end
[:==, :eql?].each do |method|
define_method "test_not_equal_by_month_with_#{method}" do
rule1 = create_with_month_and_day_of_week(1, 0)
rule2 = create_with_month_and_day_of_week(2, 0)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
define_method "test_not_equal_by_day_of_week_with_#{method}" do
rule1 = create_with_month_and_day_of_week(1, 0)
rule2 = create_with_month_and_day_of_week(1, 1)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
end
end
class TCDayOfMonthTransitionRule < Minitest::Test
include BaseTransitionRuleTestHelper
include DayOfWeekTransitionRuleTestHelper
[-1, 0, 5, '1'].each do |week|
define_method "test_invalid_week_#{week}" do
error = assert_raises(ArgumentError) { DayOfMonthTransitionRule.new(1, week, 0) }
assert_match(/\bweek\b/, error.message)
end
end
[
# All possible first week start days.
[2020, 3, [1, 2, 3, 4, 5, 6, 7]],
[2021, 3, [7, 1, 2, 3, 4, 5, 6]],
[2022, 3, [6, 7, 1, 2, 3, 4, 5]],
[2023, 3, [5, 6, 7, 1, 2, 3, 4]],
[2018, 3, [4, 5, 6, 7, 1, 2, 3]],
[2024, 3, [3, 4, 5, 6, 7, 1, 2]],
[2025, 3, [2, 3, 4, 5, 6, 7, 1]],
# All possible months.
[2019, 1, [6]],
[2019, 2, [3]],
[2019, 3, [3]],
[2019, 4, [7]],
[2019, 5, [5]],
[2019, 6, [2]],
[2019, 7, [7]],
[2019, 8, [4]],
[2019, 9, [1]],
[2019, 10, [6]],
[2019, 11, [3]],
[2019, 12, [1]]
].each do |(year, month, days)|
days.each_with_index do |expected_day, day_of_week|
(1..4).each do |week|
define_method "test_month_#{month}_week_#{week}_and_day_of_week_#{day_of_week}_year_#{year}" do
rule = DayOfMonthTransitionRule.new(month, week, day_of_week, 3600)
offset = TimezoneOffset.new(0, 0, 'TEST')
result = rule.at(offset, year)
assert_kind_of(TimeOrDateTime, result)
assert_equal(Time.utc(year, month, expected_day + (week - 1) * 7, 1, 0, 0), result.to_time)
end
end
end
end
[[3, 3, 20], [4, 6, 23]].each do |(week, day_of_week, expected_day)|
define_method "test_crosses_64_bit_boundary_for_day_of_week_#{day_of_week}" do
rule = DayOfMonthTransitionRule.new(1, week, day_of_week, 3600)
offset = TimezoneOffset.new(0, 0, 'TEST')
result = rule.at(offset, 2038)
assert_kind_of(TimeOrDateTime, result)
if RubyCoreSupport.time_supports_64bit
assert_kind_of(Time, result.to_orig)
else
assert_kind_of(DateTime, result.to_orig)
end
assert_equal(DateTime.new(2038, 1, expected_day, 1, 0, 0), result.to_datetime)
end
end
[:==, :eql?].each do |method|
[
[1, 1, 0, 0],
[1, 1, 0, 1],
[1, 1, 1, 0],
[1, 2, 0, 0],
[2, 1, 0, 0]
].each do |(month, week, day_of_week, transition_at)|
define_method "test_equal_for_month_#{month}_week_#{week}_day_of_week_#{day_of_week}_and_transition_at_#{transition_at}_with_#{method}" do
rule1 = DayOfMonthTransitionRule.new(month, week, day_of_week, transition_at)
rule2 = DayOfMonthTransitionRule.new(month, week, day_of_week, transition_at)
assert_equal(true, rule1.send(method, rule2))
assert_equal(true, rule2.send(method, rule1))
end
end
define_method "test_not_equal_by_week_with_#{method}" do
rule1 = DayOfMonthTransitionRule.new(1, 1, 0, 0)
rule2 = DayOfMonthTransitionRule.new(1, 2, 0, 0)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
define_method "test_not_equal_to_last_day_of_month_with_#{method}" do
rule1 = DayOfMonthTransitionRule.new(1, 1, 0, 0)
rule2 = LastDayOfMonthTransitionRule.new(1, 0, 0)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
end
[
[1, 1, 0, 0],
[1, 1, 0, 1],
[1, 1, 1, 0],
[1, 2, 0, 0],
[2, 1, 0, 0]
].each do |(month, week, day_of_week, transition_at)|
define_method "test_hash_for_month_#{month}_week_#{week}_day_of_week_#{day_of_week}_and_transition_at_#{transition_at}" do
rule = DayOfMonthTransitionRule.new(month, week, day_of_week, transition_at)
expected = [(week - 1) * 7 + 1, month, day_of_week, transition_at].hash
assert_equal(expected, rule.hash)
end
end
protected
def create_with_transition_at(transition_at)
DayOfMonthTransitionRule.new(1, 1, 0, transition_at)
end
def create_with_month_and_day_of_week(month, day_of_week)
DayOfMonthTransitionRule.new(month, 1, day_of_week)
end
end
class TCLastDayOfMonthTransitionRule < Minitest::Test
include BaseTransitionRuleTestHelper
include DayOfWeekTransitionRuleTestHelper
[
# All possible last days.
[2021, 10, [31, 25, 26, 27, 28, 29, 30]],
[2022, 10, [30, 31, 25, 26, 27, 28, 29]],
[2023, 10, [29, 30, 31, 25, 26, 27, 28]],
[2018, 10, [28, 29, 30, 31, 25, 26, 27]],
[2024, 10, [27, 28, 29, 30, 31, 25, 26]],
[2025, 10, [26, 27, 28, 29, 30, 31, 25]],
[2026, 10, [25, 26, 27, 28, 29, 30, 31]],
# All possible months.
[2020, 1, [26]],
[2020, 2, [23]],
[2020, 3, [29]],
[2020, 4, [26]],
[2020, 5, [31]],
[2020, 6, [28]],
[2020, 7, [26]],
[2020, 8, [30]],
[2020, 9, [27]],
[2020, 10, [25]],
[2020, 11, [29]],
[2020, 12, [27]]
].each do |(year, month, days)|
days.each_with_index do |expected_day, day_of_week|
define_method "test_month_#{month}_day_of_week_#{day_of_week}_year_#{year}" do
rule = LastDayOfMonthTransitionRule.new(month, day_of_week, 7200)
offset = TimezoneOffset.new(0, 0, 'TEST')
result = rule.at(offset, year)
assert_kind_of(TimeOrDateTime, result)
assert_equal(Time.utc(year, month, expected_day, 2, 0, 0), result.to_time)
end
end
end
[[2020, 6, 29], [2021, 0, 28], [2000, 2, 29], [2100, 0, 28]].each do |(year, day_of_week, expected_day)|
define_method "test_#{expected_day == 29 ? '' : 'non_'}leap_year_#{year}" do
rule = LastDayOfMonthTransitionRule.new(2, day_of_week, 7200)
offset = TimezoneOffset.new(0, 0, 'TEST')
result = rule.at(offset, year)
assert_kind_of(TimeOrDateTime, result)
assert_equal(DateTime.new(year, 2, expected_day, 2, 0, 0), result.to_datetime)
end
end
[:==, :eql?].each do |method|
[
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[2, 0, 0]
].each do |(month, day_of_week, transition_at)|
define_method "test_equal_for_month_#{month}_day_of_week_#{day_of_week}_and_transition_at_#{transition_at}_with_#{method}" do
rule1 = LastDayOfMonthTransitionRule.new(month, day_of_week, transition_at)
rule2 = LastDayOfMonthTransitionRule.new(month, day_of_week, transition_at)
assert_equal(true, rule1.send(method, rule2))
assert_equal(true, rule2.send(method, rule1))
end
end
define_method "test_not_equal_to_day_of_month_with_#{method}" do
rule1 = LastDayOfMonthTransitionRule.new(1, 0, 0)
rule2 = DayOfMonthTransitionRule.new(1, 1, 0, 0)
assert_equal(false, rule1.send(method, rule2))
assert_equal(false, rule2.send(method, rule1))
end
end
[
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[2, 0, 0]
].each do |(month, day_of_week, transition_at)|
define_method "test_hash_for_month_#{month}_day_of_week_#{day_of_week}_and_transition_at_#{transition_at}" do
rule = LastDayOfMonthTransitionRule.new(month, day_of_week, transition_at)
expected = [month, day_of_week, transition_at].hash
assert_equal(expected, rule.hash)
end
end
protected
def create_with_transition_at(transition_at)
LastDayOfMonthTransitionRule.new(1, 0, transition_at)
end
def create_with_month_and_day_of_week(month, day_of_week)
LastDayOfMonthTransitionRule.new(month, day_of_week)
end
end