diff options
32 files changed, 427 insertions, 125 deletions
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 4675239528..03c0f7a4f5 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -25,13 +25,6 @@ jobs: strategy: matrix: include: - - os: 2019 - vc: 2015 - vcvars: '10.0.14393.0 -vcvars_ver=14.0' # The oldest Windows 10 SDK w/ VC++ 2015 toolset (v140) - test_task: check - - os: 2019 - vc: 2019 - test_task: check - os: 2022 vc: 2019 vcvars: '10.0.22621.0 -vcvars_ver=14.2' # The defautl Windows 11 SDK and toolset are broken at windows-2022 @@ -65,7 +58,6 @@ jobs: env: GITPULLOPTIONS: --no-tags origin ${{ github.ref }} - OS_VER: windows-${{ matrix.os < 2022 && '2019' || matrix.os }} VCPKG_DEFAULT_TRIPLET: ${{ matrix.target || 'x64' }}-windows RUBY_OPT_DIR: ${{ matrix.os == '11-arm' && 'C' || 'D' }}:/a/ruby/ruby/src/vcpkg_installed/%VCPKG_DEFAULT_TRIPLET% @@ -66,9 +66,9 @@ The following default gems are updated. * json 2.11.3 * optparse 0.7.0.dev.2 * prism 1.4.0 -* psych 5.2.3 +* psych 5.2.4 * stringio 3.1.8.dev -* strscan 3.1.4.dev +* strscan 3.1.5.dev * uri 1.0.3 The following bundled gems are added. diff --git a/addr2line.c b/addr2line.c index dc0892e308..745364cc0f 100644 --- a/addr2line.c +++ b/addr2line.c @@ -2175,9 +2175,8 @@ fill_lines(int num_traces, void **traces, int check_debuglink, } } - if (offset == -1) { + if (offset == 0) { /* main executable */ - offset = 0; if (dynsym_shdr && dynstr_shdr) { char *strtab = file + dynstr_shdr->sh_offset; ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset); diff --git a/doc/string/new.rdoc b/doc/string/new.rdoc index 1d44291f76..e2752d6e1f 100644 --- a/doc/string/new.rdoc +++ b/doc/string/new.rdoc @@ -1,34 +1,38 @@ -Returns a new \String that is a copy of +string+. +Returns a new \String object containing the given +string+. -With no arguments, returns the empty string with the Encoding <tt>ASCII-8BIT</tt>: +The +options+ are optional keyword options (see below). - s = String.new - s # => "" - s.encoding # => #<Encoding:ASCII-8BIT> +With no argument given and keyword +encoding+ also not given, +returns an empty string with the Encoding <tt>ASCII-8BIT</tt>: -With optional argument +string+ and no keyword arguments, -returns a copy of +string+ with the same encoding: + s = String.new # => "" + s.encoding # => #<Encoding:ASCII-8BIT> - String.new('foo') # => "foo" - String.new('тест') # => "тест" - String.new('こんにちは') # => "こんにちは" +With argument +string+ given and keyword option +encoding+ not given, +returns a new string with the same encoding as +string+: + + s0 = 'foo'.encode(Encoding::UTF_16) + s1 = String.new(s0) + s1.encoding # => #<Encoding:UTF-16 (dummy)> (Unlike \String.new, a {string literal}[rdoc-ref:syntax/literals.rdoc@String+Literals] like <tt>''</tt> or a {here document literal}[rdoc-ref:syntax/literals.rdoc@Here+Document+Literals] always has {script encoding}[rdoc-ref:encodings.rdoc@Script+Encoding].) -With optional keyword argument +encoding+, returns a copy of +string+ -with the specified encoding; +With keyword option +encoding+ given, +returns a string with the specified encoding; the +encoding+ may be an Encoding object, an encoding name, or an encoding name alias: + String.new(encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII> + String.new('', encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII> String.new('foo', encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII> String.new('foo', encoding: 'US-ASCII').encoding # => #<Encoding:US-ASCII> String.new('foo', encoding: 'ASCII').encoding # => #<Encoding:US-ASCII> The given encoding need not be valid for the string's content, -and that validity is not checked: +and its validity is not checked: s = String.new('こんにちは', encoding: 'ascii') s.valid_encoding? # => false @@ -37,19 +41,11 @@ But the given +encoding+ itself is checked: String.new('foo', encoding: 'bar') # Raises ArgumentError. -With optional keyword argument +capacity+, returns a copy of +string+ -(or an empty string, if +string+ is not given); -the given +capacity+ is advisory only, +With keyword option +capacity+ given, +the given value is advisory only, and may or may not set the size of the internal buffer, which may in turn affect performance: - String.new(capacity: 1) - String.new('foo', capacity: 4096) - -Note that Ruby strings are null-terminated internally, so the internal -buffer size will be one or more bytes larger than the requested capacity -depending on the encoding. - -The +string+, +encoding+, and +capacity+ arguments may all be used together: - - String.new('hello', encoding: 'UTF-8', capacity: 25) + String.new('foo', capacity: 1) # Buffer size is at least 4 (includes terminal null byte). + String.new('foo', capacity: 4096) # Buffer size is at least 4; + # may be equal to, greater than, or less than 4096. diff --git a/ext/json/generator/extconf.rb b/ext/json/generator/extconf.rb index e44890e2ed..60372ee558 100644 --- a/ext/json/generator/extconf.rb +++ b/ext/json/generator/extconf.rb @@ -18,7 +18,7 @@ else return 0; } SRC - $defs.push("-DENABLE_SIMD") + $defs.push("-DJSON_ENABLE_SIMD") end end @@ -29,7 +29,7 @@ else return 0; } SRC - $defs.push("-DENABLE_SIMD") + $defs.push("-DJSON_ENABLE_SIMD") end have_header('cpuid.h') diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index 536c2aa1b7..06ab8010d9 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -112,7 +112,7 @@ typedef struct _search_state { const char *cursor; FBuffer *buffer; -#ifdef ENABLE_SIMD +#ifdef HAVE_SIMD const char *chunk_base; const char *chunk_end; bool has_matches; @@ -124,7 +124,7 @@ typedef struct _search_state { #else #error "Unknown SIMD Implementation." #endif /* HAVE_SIMD_NEON */ -#endif /* ENABLE_SIMD */ +#endif /* HAVE_SIMD */ } search_state; #if (defined(__GNUC__ ) || defined(__clang__)) @@ -189,15 +189,11 @@ static inline FORCE_INLINE void escape_UTF8_char_basic(search_state *search) case '\r': fbuffer_append(search->buffer, "\\r", 2); break; case '\t': fbuffer_append(search->buffer, "\\t", 2); break; default: { - if (ch < ' ') { - const char *hexdig = "0123456789abcdef"; - char scratch[6] = { '\\', 'u', '0', '0', 0, 0 }; - scratch[4] = hexdig[(ch >> 4) & 0xf]; - scratch[5] = hexdig[ch & 0xf]; - fbuffer_append(search->buffer, scratch, 6); - } else { - fbuffer_append_char(search->buffer, ch); - } + const char *hexdig = "0123456789abcdef"; + char scratch[6] = { '\\', 'u', '0', '0', 0, 0 }; + scratch[4] = hexdig[(ch >> 4) & 0xf]; + scratch[5] = hexdig[ch & 0xf]; + fbuffer_append(search->buffer, scratch, 6); break; } } @@ -265,7 +261,7 @@ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len) search->cursor = (search->ptr += ch_len); } -#ifdef ENABLE_SIMD +#ifdef HAVE_SIMD static inline FORCE_INLINE char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len) { @@ -537,7 +533,7 @@ static inline TARGET_SSE2 FORCE_INLINE unsigned char search_escape_basic_sse2(se #endif /* HAVE_SIMD_SSE2 */ -#endif /* ENABLE_SIMD */ +#endif /* HAVE_SIMD */ static const unsigned char script_safe_escape_table[256] = { // ASCII Control Characters @@ -1302,11 +1298,11 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat search.cursor = search.ptr; search.end = search.ptr + len; -#ifdef ENABLE_SIMD +#ifdef HAVE_SIMD search.matches_mask = 0; search.has_matches = false; search.chunk_base = NULL; -#endif /* ENABLE_SIMD */ +#endif /* HAVE_SIMD */ switch(rb_enc_str_coderange(obj)) { case ENC_CODERANGE_7BIT: @@ -2174,7 +2170,7 @@ void Init_generator(void) switch(find_simd_implementation()) { -#ifdef ENABLE_SIMD +#ifdef HAVE_SIMD #ifdef HAVE_SIMD_NEON case SIMD_NEON: search_escape_basic_impl = search_escape_basic_neon; @@ -2185,7 +2181,7 @@ void Init_generator(void) search_escape_basic_impl = search_escape_basic_sse2; break; #endif /* HAVE_SIMD_SSE2 */ -#endif /* ENABLE_SIMD */ +#endif /* HAVE_SIMD */ default: search_escape_basic_impl = search_escape_basic; break; diff --git a/ext/json/generator/simd.h b/ext/json/generator/simd.h index 2fbc93169d..b12890cb09 100644 --- a/ext/json/generator/simd.h +++ b/ext/json/generator/simd.h @@ -4,7 +4,7 @@ typedef enum { SIMD_SSE2 } SIMD_Implementation; -#ifdef ENABLE_SIMD +#ifdef JSON_ENABLE_SIMD #ifdef __clang__ #if __has_builtin(__builtin_ctzll) @@ -56,6 +56,7 @@ static SIMD_Implementation find_simd_implementation(void) { return SIMD_NEON; } +#define HAVE_SIMD 1 #define HAVE_SIMD_NEON 1 uint8x16x4_t load_uint8x16_4(const unsigned char *table) { @@ -74,6 +75,7 @@ uint8x16x4_t load_uint8x16_4(const unsigned char *table) { #ifdef HAVE_X86INTRIN_H #include <x86intrin.h> +#define HAVE_SIMD 1 #define HAVE_SIMD_SSE2 1 #ifdef HAVE_CPUID_H @@ -101,7 +103,7 @@ static SIMD_Implementation find_simd_implementation(void) { #endif /* HAVE_X86INTRIN_H */ #endif /* X86_64 Support */ -#endif /* ENABLE_SIMD */ +#endif /* JSON_ENABLE_SIMD */ #ifndef FIND_SIMD_IMPLEMENTATION_DEFINED static SIMD_Implementation find_simd_implementation(void) { diff --git a/ext/psych/lib/psych/class_loader.rb b/ext/psych/lib/psych/class_loader.rb index 50efc35ee2..c8f509720a 100644 --- a/ext/psych/lib/psych/class_loader.rb +++ b/ext/psych/lib/psych/class_loader.rb @@ -6,6 +6,7 @@ module Psych class ClassLoader # :nodoc: BIG_DECIMAL = 'BigDecimal' COMPLEX = 'Complex' + DATA = 'Data' unless RUBY_VERSION < "3.2" DATE = 'Date' DATE_TIME = 'DateTime' EXCEPTION = 'Exception' diff --git a/ext/psych/lib/psych/versions.rb b/ext/psych/lib/psych/versions.rb index d91563c861..0adcdae5f4 100644 --- a/ext/psych/lib/psych/versions.rb +++ b/ext/psych/lib/psych/versions.rb @@ -2,7 +2,7 @@ module Psych # The version of Psych you are using - VERSION = '5.2.3' + VERSION = '5.2.4' if RUBY_ENGINE == 'jruby' DEFAULT_SNAKEYAML_VERSION = '2.9'.freeze diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb index f0b4a94e45..580a74e9fb 100644 --- a/ext/psych/lib/psych/visitors/to_ruby.rb +++ b/ext/psych/lib/psych/visitors/to_ruby.rb @@ -96,11 +96,11 @@ module Psych Float(@ss.tokenize(o.value)) when "!ruby/regexp" klass = class_loader.regexp - o.value =~ /^\/(.*)\/([mixn]*)$/m - source = $1 + matches = /^\/(?<string>.*)\/(?<options>[mixn]*)$/m.match(o.value) + source = matches[:string].gsub('\/', '/') options = 0 lang = nil - $2&.each_char do |option| + matches[:options].each_char do |option| case option when 'x' then options |= Regexp::EXTENDED when 'i' then options |= Regexp::IGNORECASE @@ -197,6 +197,32 @@ module Psych s end + when /^!ruby\/data(-with-ivars)?(?::(.*))?$/ + data = register(o, resolve_class($2).allocate) if $2 + members = {} + + if $1 # data-with-ivars + ivars = {} + o.children.each_slice(2) do |type, vars| + case accept(type) + when 'members' + revive_data_members(members, vars) + data ||= allocate_anon_data(o, members) + when 'ivars' + revive_hash(ivars, vars) + end + end + ivars.each do |ivar, v| + data.instance_variable_set ivar, v + end + else + revive_data_members(members, o) + end + data ||= allocate_anon_data(o, members) + init_struct(data, **members) + data.freeze + data + when /^!ruby\/object:?(.*)?$/ name = $1 || 'Object' @@ -340,6 +366,20 @@ module Psych list end + def allocate_anon_data node, members + klass = class_loader.data.define(*members.keys) + register(node, klass.allocate) + end + + def revive_data_members hash, o + o.children.each_slice(2) do |k,v| + name = accept(k) + value = accept(v) + hash[class_loader.symbolize(name)] = value + end + hash + end + def revive_hash hash, o, tagged= false o.children.each_slice(2) { |k,v| key = accept(k) diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb index a9476df96e..d7958a8431 100644 --- a/ext/psych/lib/psych/visitors/yaml_tree.rb +++ b/ext/psych/lib/psych/visitors/yaml_tree.rb @@ -73,7 +73,7 @@ module Psych method = respond_to?(method) ? method : h[klass.superclass] - raise(TypeError, "Can't dump #{target.class}") unless method + raise(TypeError, "can't dump #{klass.name}") unless method h[klass] = method end.compare_by_identity @@ -162,6 +162,44 @@ module Psych alias :visit_Delegator :visit_Object + def visit_Data o + ivars = o.instance_variables + if ivars.empty? + tag = ['!ruby/data', o.class.name].compact.join(':') + register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) + o.members.each do |member| + @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY + accept o.send member + end + @emitter.end_mapping + + else + tag = ['!ruby/data-with-ivars', o.class.name].compact.join(':') + node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) + register(o, node) + + # Dump the members + accept 'members' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + o.members.each do |member| + @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY + accept o.send member + end + @emitter.end_mapping + + # Dump the ivars + accept 'ivars' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + ivars.each do |ivar| + accept ivar.to_s + accept o.instance_variable_get ivar + end + @emitter.end_mapping + + @emitter.end_mapping + end + end + def visit_Struct o tag = ['!ruby/struct', o.class.name].compact.join(':') diff --git a/ext/psych/psych_to_ruby.c b/ext/psych/psych_to_ruby.c index ffe0c69c7f..d473a5f840 100644 --- a/ext/psych/psych_to_ruby.c +++ b/ext/psych/psych_to_ruby.c @@ -24,6 +24,15 @@ static VALUE path2class(VALUE self, VALUE path) return rb_path_to_class(path); } +static VALUE init_struct(VALUE self, VALUE data, VALUE attrs) +{ + VALUE args = rb_ary_new2(1); + rb_ary_push(args, attrs); + rb_struct_initialize(data, args); + + return data; +} + void Init_psych_to_ruby(void) { VALUE psych = rb_define_module("Psych"); @@ -33,6 +42,7 @@ void Init_psych_to_ruby(void) VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject); cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor); + rb_define_private_method(cPsychVisitorsToRuby, "init_struct", init_struct, 2); rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2); rb_define_private_method(class_loader, "path2class", path2class, 1); } diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c index 5a6446adb3..e094e2f55a 100644 --- a/ext/strscan/strscan.c +++ b/ext/strscan/strscan.c @@ -22,7 +22,7 @@ extern size_t onig_region_memsize(const struct re_registers *regs); #include <stdbool.h> -#define STRSCAN_VERSION "3.1.4.dev" +#define STRSCAN_VERSION "3.1.5.dev" /* ======================================================================= Data Type Definitions @@ -2211,7 +2211,10 @@ named_captures_iter(const OnigUChar *name, VALUE value = RUBY_Qnil; int i; for (i = 0; i < back_num; i++) { - value = strscan_aref(data->self, INT2NUM(back_refs[i])); + VALUE v = strscan_aref(data->self, INT2NUM(back_refs[i])); + if (!RB_NIL_P(v)) { + value = v; + } } rb_hash_aset(data->captures, key, value); return 0; diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb index d3176d4564..8d9a9b2d35 100644 --- a/lib/rubygems/gemcutter_utilities.rb +++ b/lib/rubygems/gemcutter_utilities.rb @@ -263,7 +263,10 @@ module Gem::GemcutterUtilities port = server.addr[1].to_s url_with_port = "#{webauthn_url}?port=#{port}" - say "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option." + say "You have enabled multi-factor authentication. Please visit the following URL to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option." + say "" + say url_with_port + say "" threads = [WebauthnListener.listener_thread(host, server), WebauthnPoller.poll_thread(options, host, webauthn_url, credentials)] otp_thread = wait_for_otp_thread(*threads) @@ -2347,9 +2347,14 @@ rb_str_with_debug_created_info(VALUE str, VALUE path, int line) } /* + * The documentation block below uses an include (instead of inline text) + * because the included text has non-ASCII characters (which are not allowed in a C file). + */ + +/* * * call-seq: - * String.new(string = '', **opts) -> new_string + * String.new(string = ''.encode(Encoding::ASCII_8BIT) , **options) -> new_string * * :include: doc/string/new.rdoc * @@ -172,7 +172,7 @@ rb_id_attrset(ID id) /* make new symbol and ID */ if (!(str = lookup_id_str(id))) { - RBIMPL_ATTR_NONSTRING() static const char id_types[][8] = { + static const char id_types[][8] = { "local", "instance", "invalid", diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb index 39fa72e7dd..326cf22e1f 100644 --- a/test/objspace/test_objspace.rb +++ b/test/objspace/test_objspace.rb @@ -203,8 +203,9 @@ class TestObjSpace < Test::Unit::TestCase assert_equal(line1, ObjectSpace.allocation_sourceline(o1)) assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o1)) assert_equal(c1, ObjectSpace.allocation_generation(o1)) - assert_equal(self.class.name, ObjectSpace.allocation_class_path(o1)) - assert_equal(__method__, ObjectSpace.allocation_method_id(o1)) + # These assertions fail under coverage measurement: https://bugs.ruby-lang.org/issues/21298 + #assert_equal(self.class.name, ObjectSpace.allocation_class_path(o1)) + #assert_equal(__method__, ObjectSpace.allocation_method_id(o1)) assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o2)) assert_equal(line2, ObjectSpace.allocation_sourceline(o2)) diff --git a/test/psych/test_data.rb b/test/psych/test_data.rb new file mode 100644 index 0000000000..a67a037b9e --- /dev/null +++ b/test/psych/test_data.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true +require_relative 'helper' + +class PsychDataWithIvar < Data.define(:foo) + attr_reader :bar + def initialize(**) + @bar = 'hello' + super + end +end unless RUBY_VERSION < "3.2" + +module Psych + class TestData < TestCase + class SelfReferentialData < Data.define(:foo) + attr_accessor :ref + def initialize(foo:) + @ref = self + super + end + end unless RUBY_VERSION < "3.2" + + def setup + omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2" + end + + # TODO: move to another test? + def test_dump_data + assert_equal <<~eoyml, Psych.dump(PsychDataWithIvar["bar"]) + --- !ruby/data-with-ivars:PsychDataWithIvar + members: + foo: bar + ivars: + "@bar": hello + eoyml + end + + def test_self_referential_data + circular = SelfReferentialData.new("foo") + + loaded = Psych.unsafe_load(Psych.dump(circular)) + assert_instance_of(SelfReferentialData, loaded.ref) + + assert_equal(circular, loaded) + assert_same(loaded, loaded.ref) + end + + def test_roundtrip + thing = PsychDataWithIvar.new("bar") + data = Psych.unsafe_load(Psych.dump(thing)) + + assert_equal "hello", data.bar + assert_equal "bar", data.foo + end + + def test_load + obj = Psych.unsafe_load(<<~eoyml) + --- !ruby/data-with-ivars:PsychDataWithIvar + members: + foo: bar + ivars: + "@bar": hello + eoyml + + assert_equal "hello", obj.bar + assert_equal "bar", obj.foo + end + end +end + diff --git a/test/psych/test_object_references.rb b/test/psych/test_object_references.rb index 86bb9034b9..0498d54eec 100644 --- a/test/psych/test_object_references.rb +++ b/test/psych/test_object_references.rb @@ -31,6 +31,11 @@ module Psych assert_reference_trip Struct.new(:foo).new(1) end + def test_data_has_references + omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2" + assert_reference_trip Data.define(:foo).new(1) + end + def assert_reference_trip obj yml = Psych.dump([obj, obj]) assert_match(/\*-?\d+/, yml) diff --git a/test/psych/test_safe_load.rb b/test/psych/test_safe_load.rb index a9ed737528..e6ca1e142b 100644 --- a/test/psych/test_safe_load.rb +++ b/test/psych/test_safe_load.rb @@ -114,6 +114,38 @@ module Psych end end + D = Data.define(:d) unless RUBY_VERSION < "3.2" + + def test_data_depends_on_sym + omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2" + assert_safe_cycle(D.new(nil), permitted_classes: [D, Symbol]) + assert_raise(Psych::DisallowedClass) do + cycle D.new(nil), permitted_classes: [D] + end + end + + def test_anon_data + omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2" + assert Psych.safe_load(<<-eoyml, permitted_classes: [Data, Symbol]) +--- !ruby/data + foo: bar + eoyml + + assert_raise(Psych::DisallowedClass) do + Psych.safe_load(<<-eoyml, permitted_classes: [Data]) +--- !ruby/data + foo: bar + eoyml + end + + assert_raise(Psych::DisallowedClass) do + Psych.safe_load(<<-eoyml, permitted_classes: [Symbol]) +--- !ruby/data + foo: bar + eoyml + end + end + def test_safe_load_default_fallback assert_nil Psych.safe_load("") end diff --git a/test/psych/test_serialize_subclasses.rb b/test/psych/test_serialize_subclasses.rb index 344c79b3ef..640c331337 100644 --- a/test/psych/test_serialize_subclasses.rb +++ b/test/psych/test_serialize_subclasses.rb @@ -35,5 +35,23 @@ module Psych so = StructSubclass.new('foo', [1,2,3]) assert_equal so, Psych.unsafe_load(Psych.dump(so)) end + + class DataSubclass < Data.define(:foo) + def initialize(foo:) + @bar = "hello #{foo}" + super(foo: foo) + end + + def == other + super(other) && @bar == other.instance_eval{ @bar } + end + end unless RUBY_VERSION < "3.2" + + def test_data_subclass + omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2" + so = DataSubclass.new('foo') + assert_equal so, Psych.unsafe_load(Psych.dump(so)) + end + end end diff --git a/test/psych/test_yaml.rb b/test/psych/test_yaml.rb index 897a7c8935..134c346c90 100644 --- a/test/psych/test_yaml.rb +++ b/test/psych/test_yaml.rb @@ -6,6 +6,7 @@ require_relative 'helper' # [ruby-core:01946] module Psych_Tests StructTest = Struct::new( :c ) + DataTest = Data.define( :c ) unless RUBY_VERSION < "3.2" end class Psych_Unit_Tests < Psych::TestCase @@ -35,6 +36,10 @@ class Psych_Unit_Tests < Psych::TestCase assert_cycle(Regexp.new("foo\nbar")) end + def test_regexp_with_slash + assert_cycle(Regexp.new('/')) + end + # [ruby-core:34969] def test_regexp_with_n assert_cycle(Regexp.new('',Regexp::NOENCODING)) @@ -1037,7 +1042,6 @@ EOY end def test_ruby_struct - Struct.send(:remove_const, :MyBookStruct) if Struct.const_defined?(:MyBookStruct) # Ruby structures book_struct = Struct::new( "MyBookStruct", :author, :title, :year, :isbn ) assert_to_yaml( @@ -1069,6 +1073,47 @@ EOY c: 123 EOY + ensure + Struct.__send__(:remove_const, :MyBookStruct) if book_struct + end + + def test_ruby_data + omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2" + # Ruby Data value objects + book_class = Data.define(:author, :title, :year, :isbn) + Object.const_set(:MyBookData, book_class) + assert_to_yaml( + [ book_class.new( "Yukihiro Matsumoto", "Ruby in a Nutshell", 2002, "0-596-00214-9" ), + book_class.new( [ 'Dave Thomas', 'Andy Hunt' ], "The Pickaxe", 2002, + book_class.new( "This should be the ISBN", "but I have more data here", 2002, "None" ) + ) + ], <<EOY +- !ruby/data:MyBookData + author: Yukihiro Matsumoto + title: Ruby in a Nutshell + year: 2002 + isbn: 0-596-00214-9 +- !ruby/data:MyBookData + author: + - Dave Thomas + - Andy Hunt + title: The Pickaxe + year: 2002 + isbn: !ruby/data:MyBookData + author: This should be the ISBN + title: but I have more data here + year: 2002 + isbn: None +EOY + ) + + assert_to_yaml( Psych_Tests::DataTest.new( 123 ), <<EOY ) +--- !ruby/data:Psych_Tests::DataTest +c: 123 +EOY + + ensure + Object.__send__(:remove_const, :MyBookData) if book_class end def test_ruby_rational diff --git a/test/psych/visitors/test_yaml_tree.rb b/test/psych/visitors/test_yaml_tree.rb index 01e685134a..bd3919f83d 100644 --- a/test/psych/visitors/test_yaml_tree.rb +++ b/test/psych/visitors/test_yaml_tree.rb @@ -73,6 +73,27 @@ module Psych assert_equal s.method, obj.method end + D = Data.define(:foo) unless RUBY_VERSION < "3.2" + + def test_data + omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2" + assert_cycle D.new('bar') + end + + def test_data_anon + omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2" + d = Data.define(:foo).new('bar') + obj = Psych.unsafe_load(Psych.dump(d)) + assert_equal d.foo, obj.foo + end + + def test_data_override_method + omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2" + d = Data.define(:method).new('override') + obj = Psych.unsafe_load(Psych.dump(d)) + assert_equal d.method, obj.method + end + def test_exception ex = Exception.new 'foo' loaded = Psych.unsafe_load(Psych.dump(ex)) diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index 032f78f6a8..86c1f51dde 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -92,7 +92,7 @@ class TestISeq < Test::Unit::TestCase 42 end EOF - assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval) + assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval) end def test_forwardable @@ -102,7 +102,7 @@ class TestISeq < Test::Unit::TestCase def foo(...); bar(...); end } EOF - assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval.new.foo(40, 2)) + assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval.new.foo(40, 2)) end def test_super_with_block @@ -112,7 +112,7 @@ class TestISeq < Test::Unit::TestCase end 42 EOF - assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval) + assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval) end def test_super_with_block_hash_0 @@ -123,7 +123,7 @@ class TestISeq < Test::Unit::TestCase end 42 EOF - assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval) + assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval) end def test_super_with_block_and_kwrest @@ -133,7 +133,7 @@ class TestISeq < Test::Unit::TestCase end 42 EOF - assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval) + assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval) end def test_lambda_with_ractor_roundtrip @@ -143,7 +143,7 @@ class TestISeq < Test::Unit::TestCase Ractor.make_shareable(y) y.call EOF - assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval) + assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval) end def test_super_with_anonymous_block @@ -153,7 +153,7 @@ class TestISeq < Test::Unit::TestCase end 42 EOF - assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval) + assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval) end def test_ractor_unshareable_outer_variable @@ -182,7 +182,7 @@ class TestISeq < Test::Unit::TestCase # shareable_constant_value: literal REGEX = /#{}/ # [Bug #20569] RUBY - assert_includes iseq.to_binary, "REGEX".b + assert_includes iseq_to_binary(iseq), "REGEX".b end def test_disasm_encoding @@ -566,16 +566,20 @@ class TestISeq < Test::Unit::TestCase } end + def iseq_to_binary(iseq) + iseq.to_binary + rescue RuntimeError => e + omit e.message if /compile with coverage/ =~ e.message + raise + end + def assert_iseq_to_binary(code, mesg = nil) iseq = RubyVM::InstructionSequence.compile(code) bin = assert_nothing_raised(mesg) do - iseq.to_binary - rescue RuntimeError => e - omit e.message if /compile with coverage/ =~ e.message - raise + iseq_to_binary(iseq) end 10.times do - bin2 = iseq.to_binary + bin2 = iseq_to_binary(iseq) assert_equal(bin, bin2, message(mesg) {diff hexdump(bin), hexdump(bin2)}) end iseq2 = RubyVM::InstructionSequence.load_from_binary(bin) @@ -593,7 +597,7 @@ class TestISeq < Test::Unit::TestCase def test_to_binary_with_hidden_local_variables assert_iseq_to_binary("for _foo in bar; end") - bin = RubyVM::InstructionSequence.compile(<<-RUBY).to_binary + bin = iseq_to_binary(RubyVM::InstructionSequence.compile(<<-RUBY)) Object.new.instance_eval do a = [] def self.bar; [1] end @@ -668,7 +672,7 @@ class TestISeq < Test::Unit::TestCase end RUBY - iseq_bin = iseq.to_binary + iseq_bin = iseq_to_binary(iseq) iseq = ISeq.load_from_binary(iseq_bin) lines = [] TracePoint.new(tracepoint_type){|tp| @@ -764,7 +768,7 @@ class TestISeq < Test::Unit::TestCase def test_iseq_builtin_load Tempfile.create(["builtin", ".iseq"]) do |f| f.binmode - f.write(RubyVM::InstructionSequence.of(1.method(:abs)).to_binary) + f.write(iseq_to_binary(RubyVM::InstructionSequence.of(1.method(:abs)))) f.close assert_separately(["-", f.path], "#{<<~"begin;"}\n#{<<~'end;'}") begin; @@ -857,7 +861,7 @@ class TestISeq < Test::Unit::TestCase def test_loading_kwargs_memory_leak assert_no_memory_leak([], "#{<<~"begin;"}", "#{<<~'end;'}", rss: true) - a = RubyVM::InstructionSequence.compile("foo(bar: :baz)").to_binary + a = iseq_to_binary(RubyVM::InstructionSequence.compile("foo(bar: :baz)")) begin; 1_000_000.times do RubyVM::InstructionSequence.load_from_binary(a) @@ -868,7 +872,7 @@ class TestISeq < Test::Unit::TestCase def test_ibf_bignum iseq = RubyVM::InstructionSequence.compile("0x0"+"_0123_4567_89ab_cdef"*5) expected = iseq.eval - result = RubyVM::InstructionSequence.load_from_binary(iseq.to_binary).eval + result = RubyVM::InstructionSequence.load_from_binary(iseq_to_binary(iseq)).eval assert_equal expected, result, proc {sprintf("expected: %x, result: %x", expected, result)} end diff --git a/test/rubygems/test_gem_commands_owner_command.rb b/test/rubygems/test_gem_commands_owner_command.rb index bc4f13ff2a..ac18699736 100644 --- a/test/rubygems/test_gem_commands_owner_command.rb +++ b/test/rubygems/test_gem_commands_owner_command.rb @@ -386,9 +386,10 @@ EOF end end - assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output + assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"] assert_match response_success, @stub_ui.output @@ -413,9 +414,10 @@ EOF end assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key - assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output + assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output assert_match "ERROR: Security device verification failed: Something went wrong", @stub_ui.error refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output refute_match response_success, @stub_ui.output @@ -435,9 +437,10 @@ EOF end end - assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \ "command with the `--otp [your_code]` option.", @stub_ui.output + assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"] assert_match response_success, @stub_ui.output @@ -463,9 +466,10 @@ EOF end assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key - assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \ "command with the `--otp [your_code]` option.", @stub_ui.output + assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \ "or been used already.", @stub_ui.error refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb index 2d0190b49f..bedc8e0d58 100644 --- a/test/rubygems/test_gem_commands_push_command.rb +++ b/test/rubygems/test_gem_commands_push_command.rb @@ -477,9 +477,10 @@ class TestGemCommandsPushCommand < Gem::TestCase end end - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output assert_match "You are verified with a security device. You may close the browser window.", @ui.output assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"] assert_match response_success, @ui.output @@ -505,9 +506,10 @@ class TestGemCommandsPushCommand < Gem::TestCase assert_equal 1, error.exit_code assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error refute_match "You are verified with a security device. You may close the browser window.", @ui.output refute_match response_success, @ui.output @@ -527,9 +529,10 @@ class TestGemCommandsPushCommand < Gem::TestCase end end - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output assert_match "You are verified with a security device. You may close the browser window.", @ui.output assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"] assert_match response_success, @ui.output @@ -553,9 +556,10 @@ class TestGemCommandsPushCommand < Gem::TestCase assert_equal 1, error.exit_code assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ - "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \ - "command with the `--otp [your_code]` option.", @ui.output + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ + "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ + "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \ "or been used already.", @ui.error refute_match "You are verified with a security device. You may close the browser window.", @ui.output diff --git a/test/rubygems/test_gem_commands_yank_command.rb b/test/rubygems/test_gem_commands_yank_command.rb index eb78e3a542..213f098374 100644 --- a/test/rubygems/test_gem_commands_yank_command.rb +++ b/test/rubygems/test_gem_commands_yank_command.rb @@ -131,9 +131,10 @@ class TestGemCommandsYankCommand < Gem::TestCase end assert_match %r{Yanking gem from http://example}, @ui.output - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output assert_match "You are verified with a security device. You may close the browser window.", @ui.output assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"] assert_match "Successfully yanked", @ui.output @@ -163,9 +164,10 @@ class TestGemCommandsYankCommand < Gem::TestCase assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key assert_match %r{Yanking gem from http://example}, @ui.output - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error refute_match "You are verified with a security device. You may close the browser window.", @ui.output refute_match "Successfully yanked", @ui.output @@ -189,9 +191,10 @@ class TestGemCommandsYankCommand < Gem::TestCase end assert_match %r{Yanking gem from http://example}, @ui.output - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output assert_match "You are verified with a security device. You may close the browser window.", @ui.output assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"] assert_match "Successfully yanked", @ui.output @@ -219,9 +222,10 @@ class TestGemCommandsYankCommand < Gem::TestCase assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key assert_match %r{Yanking gem from http://example}, @ui.output - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \ "or been used already.", @ui.error refute_match "You are verified with a security device. You may close the browser window.", @ui.output diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb index a3236e6276..9204dc5f20 100644 --- a/test/rubygems/test_gem_gemcutter_utilities.rb +++ b/test/rubygems/test_gem_gemcutter_utilities.rb @@ -233,9 +233,10 @@ class TestGemGemcutterUtilities < Gem::TestCase end end - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"] end @@ -255,9 +256,10 @@ class TestGemGemcutterUtilities < Gem::TestCase end assert_equal 1, error.exit_code - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output assert_match "ERROR: Security device verification failed: Something went wrong", @sign_in_ui.error refute_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output refute_match "Signed in with API key:", @sign_in_ui.output @@ -273,9 +275,10 @@ class TestGemGemcutterUtilities < Gem::TestCase util_sign_in end - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"] end @@ -292,9 +295,10 @@ class TestGemGemcutterUtilities < Gem::TestCase end end - assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \ + assert_match "You have enabled multi-factor authentication. Please visit the following URL " \ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \ "you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output + assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output assert_match "ERROR: Security device verification failed: " \ "The token in the link you used has either expired or been used already.", @sign_in_ui.error end diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb index 0a28d92368..e895a8382b 100644 --- a/test/strscan/test_stringscanner.rb +++ b/test/strscan/test_stringscanner.rb @@ -967,6 +967,12 @@ module StringScannerTests assert_equal({}, scan.named_captures) end + def test_named_captures_same_name_union + scan = StringScanner.new("123") + assert_equal(1, scan.match?(/(?<number>0)|(?<number>1)|(?<number>2)/)) + assert_equal({"number" => "1"}, scan.named_captures) + end + def test_scan_integer s = create_string_scanner('abc') assert_equal(3, s.match?(/(?<a>abc)/)) # set named_captures diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb index 903baf49dd..5b0bca72b7 100755 --- a/tool/sync_default_gems.rb +++ b/tool/sync_default_gems.rb @@ -46,7 +46,6 @@ module SyncDefaultGems resolv: "ruby/resolv", rubygems: 'rubygems/rubygems', securerandom: "ruby/securerandom", - set: "ruby/set", shellwords: "ruby/shellwords", singleton: "ruby/singleton", stringio: 'ruby/stringio', @@ -295,9 +294,6 @@ module SyncDefaultGems cp_r("#{upstream}/test/digest", "test") cp_r("#{upstream}/digest.gemspec", "ext/digest") `git checkout ext/digest/depend ext/digest/*/depend` - when "set" - sync_lib gem, upstream - cp_r(Dir.glob("#{upstream}/test/*"), "test/set") when "optparse" sync_lib gem, upstream rm_rf(%w[doc/optparse]) diff --git a/tool/test-coverage.rb b/tool/test-coverage.rb index 055577feea..28ef0bf7f8 100644 --- a/tool/test-coverage.rb +++ b/tool/test-coverage.rb @@ -114,6 +114,10 @@ pid = $$ pwd = Dir.pwd at_exit do + # Some tests leave GC.stress enabled, causing slow coverage processing. + # Reset it here to avoid performance issues. + GC.stress = false + exit_exc = $! Dir.chdir(pwd) do diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index f4ecb46383..d54617efe4 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -619,7 +619,7 @@ impl<T: Copy + Into<usize> + PartialEq> UnionFind<T> { } /// Find the set representative for `insn` without doing path compression. - pub fn find_const(&self, insn: T) -> T { + fn find_const(&self, insn: T) -> T { let mut result = insn; loop { match self.at(result) { @@ -645,7 +645,7 @@ pub struct Function { // TODO: get method name and source location from the ISEQ insns: Vec<Insn>, - union_find: UnionFind<InsnId>, + union_find: std::cell::RefCell<UnionFind<InsnId>>, insn_types: Vec<Type>, blocks: Vec<Block>, entry_block: BlockId, @@ -657,7 +657,7 @@ impl Function { iseq, insns: vec![], insn_types: vec![], - union_find: UnionFind::new(), + union_find: UnionFind::new().into(), blocks: vec![Block::default()], entry_block: BlockId(0), } @@ -740,7 +740,7 @@ impl Function { macro_rules! find { ( $x:expr ) => { { - self.union_find.find_const($x) + self.union_find.borrow_mut().find($x) } }; } @@ -749,12 +749,12 @@ impl Function { { BranchEdge { target: $edge.target, - args: $edge.args.iter().map(|x| self.union_find.find_const(*x)).collect(), + args: $edge.args.iter().map(|x| find!(*x)).collect(), } } }; } - let insn_id = self.union_find.find_const(insn_id); + let insn_id = self.union_find.borrow_mut().find(insn_id); use Insn::*; match &self.insns[insn_id.0] { result@(PutSelf | Const {..} | Param {..} | NewArray {..} | GetConstantPath {..} @@ -822,12 +822,12 @@ impl Function { /// Replace `insn` with the new instruction `replacement`, which will get appended to `insns`. fn make_equal_to(&mut self, insn: InsnId, replacement: InsnId) { // Don't push it to the block - self.union_find.make_equal_to(insn, replacement); + self.union_find.borrow_mut().make_equal_to(insn, replacement); } fn type_of(&self, insn: InsnId) -> Type { assert!(self.insns[insn.0].has_output()); - self.insn_types[self.union_find.find_const(insn).0] + self.insn_types[self.union_find.borrow_mut().find(insn).0] } /// Check if the type of `insn` is a subtype of `ty`. @@ -1978,19 +1978,19 @@ mod union_find_tests { } #[test] - fn test_find_const_returns_target() { + fn test_find_returns_target() { let mut uf = UnionFind::new(); uf.make_equal_to(3, 4); - assert_eq!(uf.find_const(3usize), 4); + assert_eq!(uf.find(3usize), 4); } #[test] - fn test_find_const_returns_transitive_target() { + fn test_find_returns_transitive_target() { let mut uf = UnionFind::new(); uf.make_equal_to(3, 4); uf.make_equal_to(4, 5); - assert_eq!(uf.find_const(3usize), 5); - assert_eq!(uf.find_const(4usize), 5); + assert_eq!(uf.find(3usize), 5); + assert_eq!(uf.find(4usize), 5); } #[test] |