diff -Nur a/lib/tzinfo/ruby_core_support.rb b/lib/tzinfo/ruby_core_support.rb --- a/lib/tzinfo/ruby_core_support.rb 2022-02-18 13:30:12.167937090 +0800 +++ b/lib/tzinfo/ruby_core_support.rb 2022-02-18 13:27:08.880845143 +0800 @@ -137,10 +137,40 @@ def self.open_file(file_name, mode, opts, &block) File.open(file_name, mode, &block) end - else + elsif RUBY_VERSION =~ /\A1\.9\./ def self.open_file(file_name, mode, opts, &block) File.open(file_name, mode, opts, &block) end + else + # Evaluate method as a string because **opts isn't valid syntax prior to + # Ruby 2.0. + eval(<<-EOF + def self.open_file(file_name, mode, opts, &block) + File.open(file_name, mode, **opts, &block) + end + EOF + ) + end + + + # Object#untaint is a deprecated no-op in Ruby >= 2.7 and will be removed in + # 3.0. Add a refinement to either silence the warning, or supply the method + # if needed. + old_verbose = $VERBOSE + $VERBOSE = false + begin + o = Object.new + if [:taint, :untaint, :tainted?].none? {|m| o.respond_to?(m) } || !o.taint.tainted? + module UntaintExt + refine Object do + def untaint + self + end + end + end + end + ensure + $VERBOSE = old_verbose end end end diff -Nur a/lib/tzinfo/ruby_data_source.rb b/lib/tzinfo/ruby_data_source.rb --- a/lib/tzinfo/ruby_data_source.rb 2022-02-18 13:30:12.167937090 +0800 +++ b/lib/tzinfo/ruby_data_source.rb 2022-02-18 13:26:53.348583123 +0800 @@ -1,4 +1,6 @@ module TZInfo + using RubyCoreSupport::UntaintExt if RubyCoreSupport.const_defined?(:UntaintExt) + # A DataSource that loads data from the set of Ruby modules included in the # TZInfo::Data library (tzinfo-data gem). # diff -Nur a/lib/tzinfo/zoneinfo_data_source.rb b/lib/tzinfo/zoneinfo_data_source.rb --- a/lib/tzinfo/zoneinfo_data_source.rb 2022-02-18 13:30:12.171937158 +0800 +++ b/lib/tzinfo/zoneinfo_data_source.rb 2022-02-18 13:26:53.348583123 +0800 @@ -1,4 +1,6 @@ module TZInfo + using RubyCoreSupport::UntaintExt if RubyCoreSupport.const_defined?(:UntaintExt) + # An InvalidZoneinfoDirectory exception is raised if the DataSource is # set to a specific zoneinfo path, which is not a valid zoneinfo directory # (i.e. a directory containing index files named iso3166.tab and zone.tab diff -Nur a/lib/tzinfo/zoneinfo_timezone_info.rb b/lib/tzinfo/zoneinfo_timezone_info.rb --- a/lib/tzinfo/zoneinfo_timezone_info.rb 2022-02-18 13:30:12.171937158 +0800 +++ b/lib/tzinfo/zoneinfo_timezone_info.rb 2022-02-18 13:26:53.348583123 +0800 @@ -1,4 +1,6 @@ module TZInfo + using RubyCoreSupport::UntaintExt if RubyCoreSupport.const_defined?(:UntaintExt) + # An InvalidZoneinfoFile exception is raised if an attempt is made to load an # invalid zoneinfo file. class InvalidZoneinfoFile < StandardError diff -Nur a/test/tc_country.rb b/test/tc_country.rb --- a/test/tc_country.rb 2022-02-18 13:30:12.171937158 +0800 +++ b/test/tc_country.rb 2022-02-18 13:26:53.348583123 +0800 @@ -2,6 +2,8 @@ include TZInfo +using TaintExt if Module.const_defined?(:TaintExt) + class TCCountry < Minitest::Test def setup @orig_data_source = DataSource.get @@ -46,7 +48,7 @@ def test_get_tainted_loaded Country.get('GB') - safe_test do + safe_test(:unavailable => :skip) do code = 'GB'.dup.taint assert(code.tainted?) country = Country.get(code) @@ -65,7 +67,7 @@ end def test_get_tainted_not_previously_loaded - safe_test do + safe_test(:unavailable => :skip) do code = 'GB'.dup.taint assert(code.tainted?) country = Country.get(code) diff -Nur a/test/tc_ruby_data_source.rb b/test/tc_ruby_data_source.rb --- a/test/tc_ruby_data_source.rb 2022-02-18 13:30:12.179937293 +0800 +++ b/test/tc_ruby_data_source.rb 2022-02-18 13:28:17.321999706 +0800 @@ -2,6 +2,8 @@ include TZInfo +using TaintExt if Module.const_defined?(:TaintExt) + class TCRubyDataSource < Minitest::Test def setup @data_source = RubyDataSource.new @@ -55,7 +57,8 @@ end def test_load_timezone_info_tainted - safe_test do + + safe_test(:unavailable => :skip) do identifier = 'Europe/Amsterdam'.dup.taint assert(identifier.tainted?) info = @data_source.load_timezone_info(identifier) @@ -119,7 +123,7 @@ end def test_load_country_info_tainted - safe_test do + safe_test(:unavailable => :skip) do code = 'NL'.dup.taint assert(code.tainted?) info = @data_source.load_country_info(code) diff -Nur a/test/tc_timezone.rb b/test/tc_timezone.rb --- a/test/tc_timezone.rb 2022-02-18 13:30:12.179937293 +0800 +++ b/test/tc_timezone.rb 2022-02-18 13:28:41.098400800 +0800 @@ -2,6 +2,8 @@ include TZInfo +using TaintExt if Module.const_defined?(:TaintExt) + class TCTimezone < Minitest::Test class BlockCalled < StandardError @@ -242,7 +244,7 @@ def test_get_tainted_loaded Timezone.get('Europe/Andorra') - safe_test do + safe_test(:unavailable => :skip) do identifier = 'Europe/Andorra'.dup.taint assert(identifier.tainted?) tz = Timezone.get(identifier) @@ -261,7 +263,8 @@ end def test_get_tainted_not_previously_loaded - safe_test do + + safe_test(:unavailable => :skip) do identifier = 'Europe/Andorra'.dup.taint assert(identifier.tainted?) tz = Timezone.get(identifier) diff -Nur a/test/tc_zoneinfo_data_source.rb b/test/tc_zoneinfo_data_source.rb --- a/test/tc_zoneinfo_data_source.rb 2022-02-18 13:30:12.183937360 +0800 +++ b/test/tc_zoneinfo_data_source.rb 2022-02-18 13:26:53.348583123 +0800 @@ -7,6 +7,9 @@ include TZInfo +using RubyCoreSupport::UntaintExt if RubyCoreSupport.const_defined?(:UntaintExt) +using TaintExt if Module.const_defined?(:TaintExt) + class TCZoneinfoDataSource < Minitest::Test ZONEINFO_DIR = File.join(File.expand_path(File.dirname(__FILE__)), 'zoneinfo').untaint @@ -653,7 +656,7 @@ end def test_load_timezone_info_tainted - safe_test do + safe_test(:unavailable => :skip) do identifier = 'Europe/Amsterdam'.dup.taint assert(identifier.tainted?) info = @data_source.load_timezone_info(identifier) @@ -840,7 +843,7 @@ end def test_load_country_info_tainted - safe_test do + safe_test(:unavailable => :skip) do code = 'NL'.dup.taint assert(code.tainted?) info = @data_source.load_country_info(code) diff -Nur a/test/tc_zoneinfo_timezone_info.rb b/test/tc_zoneinfo_timezone_info.rb --- a/test/tc_zoneinfo_timezone_info.rb 2022-02-18 13:30:12.183937360 +0800 +++ b/test/tc_zoneinfo_timezone_info.rb 2022-02-18 13:26:53.348583123 +0800 @@ -5,6 +5,8 @@ include TZInfo +using RubyCoreSupport::UntaintExt if RubyCoreSupport.const_defined?(:UntaintExt) + class TCZoneinfoTimezoneInfo < Minitest::Test begin diff -Nur a/test/test_utils.rb b/test/test_utils.rb --- a/test/test_utils.rb 2022-02-18 13:30:12.187937428 +0800 +++ b/test/test_utils.rb 2022-02-18 13:29:32.443266958 +0800 @@ -1,4 +1,6 @@ -TESTS_DIR = File.expand_path(File.dirname(__FILE__)).untaint +tests_dir = File.expand_path(File.dirname(__FILE__)) +tests_dir.untaint if RUBY_VERSION < '2.7' +TESTS_DIR = tests_dir TZINFO_LIB_DIR = File.expand_path(File.join(TESTS_DIR, '..', 'lib')) TZINFO_TEST_DATA_DIR = File.join(TESTS_DIR, 'tzinfo-data') TZINFO_TEST_ZONEINFO_DIR = File.join(TESTS_DIR, 'zoneinfo') @@ -55,8 +57,8 @@ end def safe_test(options = {}) - # JRuby and Rubinus don't support SAFE levels. - available = !(defined?(RUBY_ENGINE) && %w(jruby rbx).include?(RUBY_ENGINE)) + # Ruby >= 2.7, JRuby and Rubinus don't support SAFE levels. + available = RUBY_VERSION < '2.7' && !(defined?(RUBY_ENGINE) && %w(jruby rbx).include?(RUBY_ENGINE)) if available || options[:unavailable] != :skip thread = Thread.new do @@ -150,6 +152,19 @@ end end end + + +# Object#taint is a deprecated no-op in Ruby 2.7 and outputs a warning. It will +# be removed in 3.0. Silence the warning or supply a replacement. +if TZInfo::RubyCoreSupport.const_defined?(:UntaintExt) + module TaintExt + refine Object do + def taint + self + end + end + end +end # JRuby 1.7.5 to 1.7.9 consider DateTime instances that differ by less than diff -Nur a/test/ts_all_zoneinfo.rb b/test/ts_all_zoneinfo.rb --- a/test/ts_all_zoneinfo.rb 2022-02-18 13:30:12.187937428 +0800 +++ b/test/ts_all_zoneinfo.rb 2022-02-18 13:26:53.348583123 +0800 @@ -2,6 +2,8 @@ # Use a zoneinfo directory containing files needed by the tests. # The symlinks in this directory are set up in test_utils.rb. -TZInfo::DataSource.set(:zoneinfo, File.join(File.expand_path(File.dirname(__FILE__)), 'zoneinfo').untaint) +zoneinfo_path = File.join(File.expand_path(File.dirname(__FILE__)), 'zoneinfo') +zoneinfo_path.untaint if RUBY_VERSION < '2.7' +TZInfo::DataSource.set(:zoneinfo, zoneinfo_path) require File.join(File.expand_path(File.dirname(__FILE__)), 'ts_all.rb')