104
104
UserMarshal . should_not_receive ( :name )
105
105
Marshal . dump ( UserMarshal . new )
106
106
end
107
+
108
+ it "raises TypeError if an Object is an instance of an anonymous class" do
109
+ -> { Marshal . dump ( Class . new ( UserMarshal ) . new ) } . should raise_error ( TypeError , /can't dump anonymous class/ )
110
+ end
107
111
end
108
112
109
113
describe "with an object responding to #_dump" do
110
- it "dumps the object returned by #_dump" do
114
+ it "dumps the String returned by #_dump" do
111
115
Marshal . dump ( UserDefined . new ) . should == "\004 \b u:\020 UserDefined\022 \004 \b [\a :\n stuff;\000 "
112
116
end
113
117
118
+ it "dumps the String in non US-ASCII and non UTF-8 encoding" do
119
+ object = UserDefinedString . new ( "a" . encode ( "windows-1251" ) )
120
+ Marshal . dump ( object ) . should == "\x04 \b Iu:\x16 UserDefinedString\x06 a\x06 :\r encoding\" \x11 Windows-1251"
121
+ end
122
+
123
+ it "dumps the String in multibyte encoding" do
124
+ object = UserDefinedString . new ( "a" . encode ( "utf-32le" ) )
125
+ Marshal . dump ( object ) . should == "\x04 \b Iu:\x16 UserDefinedString\t a\x00 \x00 \x00 \x06 :\r encoding\" \r UTF-32LE"
126
+ end
127
+
128
+ it "ignores overridden name method" do
129
+ obj = MarshalSpec ::UserDefinedWithOverriddenName . new
130
+ Marshal . dump ( obj ) . should == "\x04 \b u:/MarshalSpec::UserDefinedWithOverriddenName\x12 \x04 \b [\a :\n stuff;\x00 "
131
+ end
132
+
114
133
it "raises a TypeError if _dump returns a non-string" do
115
134
m = mock ( "marshaled" )
116
135
m . should_receive ( :_dump ) . and_return ( 0 )
117
136
-> { Marshal . dump ( m ) } . should raise_error ( TypeError )
118
137
end
119
138
139
+ it "raises TypeError if an Object is an instance of an anonymous class" do
140
+ -> { Marshal . dump ( Class . new ( UserDefined ) . new ) } . should raise_error ( TypeError , /can't dump anonymous class/ )
141
+ end
142
+
120
143
it "favors marshal_dump over _dump" do
121
144
m = mock ( "marshaled" )
122
145
m . should_receive ( :marshal_dump ) . and_return ( 0 )
@@ -166,8 +189,17 @@ def _dump(level)
166
189
Marshal . dump ( UserDefined ::Nested ) . should == "\004 \b c\030 UserDefined::Nested"
167
190
end
168
191
192
+ it "ignores overridden name method" do
193
+ Marshal . dump ( MarshalSpec ::ClassWithOverriddenName ) . should == "\x04 \b c)MarshalSpec::ClassWithOverriddenName"
194
+ end
195
+
196
+ it "dumps a class with multibyte characters in name" do
197
+ source_object = eval ( "MarshalSpec::MultibyteぁあぃいClass" . force_encoding ( Encoding ::UTF_8 ) )
198
+ Marshal . dump ( source_object ) . should == "\x04 \b c,MarshalSpec::Multibyte\xE3 \x81 \x81 \xE3 \x81 \x82 \xE3 \x81 \x83 \xE3 \x81 \x84 Class"
199
+ end
200
+
169
201
it "raises TypeError with an anonymous Class" do
170
- -> { Marshal . dump ( Class . new ) } . should raise_error ( TypeError )
202
+ -> { Marshal . dump ( Class . new ) } . should raise_error ( TypeError , /can't dump anonymous class/ )
171
203
end
172
204
173
205
it "raises TypeError with a singleton Class" do
@@ -180,6 +212,15 @@ def _dump(level)
180
212
Marshal . dump ( Marshal ) . should == "\004 \b m\f Marshal"
181
213
end
182
214
215
+ it "ignores overridden name method" do
216
+ Marshal . dump ( MarshalSpec ::ModuleWithOverriddenName ) . should == "\x04 \b c*MarshalSpec::ModuleWithOverriddenName"
217
+ end
218
+
219
+ it "dumps a module with multibyte characters in name" do
220
+ source_object = eval ( "MarshalSpec::MultibyteけげこごModule" . force_encoding ( Encoding ::UTF_8 ) )
221
+ Marshal . dump ( source_object ) . should == "\x04 \b m-MarshalSpec::Multibyte\xE3 \x81 \x91 \xE3 \x81 \x92 \xE3 \x81 \x93 \xE3 \x81 \x94 Module"
222
+ end
223
+
183
224
it "raises TypeError with an anonymous Module" do
184
225
-> { Marshal . dump ( Module . new ) } . should raise_error ( TypeError )
185
226
end
@@ -255,6 +296,11 @@ def _dump(level)
255
296
Marshal . dump ( UserString . new . extend ( Meths ) . force_encoding ( "binary" ) ) . should == "\004 \b e:\n MethsC:\017 UserString\" \000 "
256
297
end
257
298
299
+ it "ignores overridden name method when dumps a String subclass" do
300
+ obj = MarshalSpec ::StringWithOverriddenName . new
301
+ Marshal . dump ( obj ) . should == "\x04 \b C:*MarshalSpec::StringWithOverriddenName\" \x00 "
302
+ end
303
+
258
304
it "dumps a String with instance variables" do
259
305
str = ""
260
306
str . instance_variable_set ( "@foo" , "bar" )
@@ -310,14 +356,42 @@ def _dump(level)
310
356
Marshal . dump ( o ) . should == "\x04 \b /\x00 \x10 "
311
357
end
312
358
359
+ it "dumps an ascii-compatible Regexp" do
360
+ o = Regexp . new ( "a" . encode ( "us-ascii" ) , Regexp ::FIXEDENCODING )
361
+ Marshal . dump ( o ) . should == "\x04 \b I/\x06 a\x10 \x06 :\x06 EF"
362
+
363
+ o = Regexp . new ( "a" . encode ( "us-ascii" ) )
364
+ Marshal . dump ( o ) . should == "\x04 \b I/\x06 a\x00 \x06 :\x06 EF"
365
+
366
+ o = Regexp . new ( "a" . encode ( "windows-1251" ) , Regexp ::FIXEDENCODING )
367
+ Marshal . dump ( o ) . should == "\x04 \b I/\x06 a\x10 \x06 :\r encoding\" \x11 Windows-1251"
368
+
369
+ o = Regexp . new ( "a" . encode ( "windows-1251" ) )
370
+ Marshal . dump ( o ) . should == "\x04 \b I/\x06 a\x00 \x06 :\x06 EF"
371
+ end
372
+
313
373
it "dumps a UTF-8 Regexp" do
314
374
o = Regexp . new ( "" . force_encoding ( "utf-8" ) , Regexp ::FIXEDENCODING )
315
375
Marshal . dump ( o ) . should == "\x04 \b I/\x00 \x10 \x06 :\x06 ET"
376
+
377
+ o = Regexp . new ( "a" . force_encoding ( "utf-8" ) , Regexp ::FIXEDENCODING )
378
+ Marshal . dump ( o ) . should == "\x04 \b I/\x06 a\x10 \x06 :\x06 ET"
379
+
380
+ o = Regexp . new ( "\u3042 " . force_encoding ( "utf-8" ) , Regexp ::FIXEDENCODING )
381
+ Marshal . dump ( o ) . should == "\x04 \b I/\b \xE3 \x81 \x82 \x10 \x06 :\x06 ET"
316
382
end
317
383
318
384
it "dumps a Regexp in another encoding" do
319
385
o = Regexp . new ( "" . force_encoding ( "utf-16le" ) , Regexp ::FIXEDENCODING )
320
386
Marshal . dump ( o ) . should == "\x04 \b I/\x00 \x10 \x06 :\r encoding\" \r UTF-16LE"
387
+
388
+ o = Regexp . new ( "a" . encode ( "utf-16le" ) , Regexp ::FIXEDENCODING )
389
+ Marshal . dump ( o ) . should == "\x04 \b I/\a a\x00 \x10 \x06 :\r encoding\" \r UTF-16LE"
390
+ end
391
+
392
+ it "ignores overridden name method when dumps a Regexp subclass" do
393
+ obj = MarshalSpec ::RegexpWithOverriddenName . new ( "" )
394
+ Marshal . dump ( obj ) . should == "\x04 \b IC:*MarshalSpec::RegexpWithOverriddenName/\x00 \x00 \x06 :\x06 EF"
321
395
end
322
396
end
323
397
@@ -349,13 +423,22 @@ def _dump(level)
349
423
it "dumps an extended Array" do
350
424
Marshal . dump ( [ ] . extend ( Meths ) ) . should == "\004 \b e:\n Meths[\000 "
351
425
end
426
+
427
+ it "ignores overridden name method when dumps an Array subclass" do
428
+ obj = MarshalSpec ::ArrayWithOverriddenName . new
429
+ Marshal . dump ( obj ) . should == "\x04 \b C:)MarshalSpec::ArrayWithOverriddenName[\x00 "
430
+ end
352
431
end
353
432
354
433
describe "with a Hash" do
355
434
it "dumps a Hash" do
356
435
Marshal . dump ( { } ) . should == "\004 \b {\000 "
357
436
end
358
437
438
+ it "dumps a non-empty Hash" do
439
+ Marshal . dump ( { a : 1 } ) . should == "\x04 \b {\x06 :\x06 ai\x06 "
440
+ end
441
+
359
442
it "dumps a Hash subclass" do
360
443
Marshal . dump ( UserHash . new ) . should == "\004 \b C:\r UserHash{\000 "
361
444
end
@@ -364,8 +447,24 @@ def _dump(level)
364
447
Marshal . dump ( Hash . new ( 1 ) ) . should == "\004 \b }\000 i\006 "
365
448
end
366
449
450
+ ruby_version_is "3.1" do
451
+ it "dumps a Hash with compare_by_identity" do
452
+ h = { }
453
+ h . compare_by_identity
454
+
455
+ Marshal . dump ( h ) . should == "\004 \b C:\t Hash{\x00 "
456
+ end
457
+
458
+ it "dumps a Hash subclass with compare_by_identity" do
459
+ h = UserHash . new
460
+ h . compare_by_identity
461
+
462
+ Marshal . dump ( h ) . should == "\x04 \b C:\r UserHashC:\t Hash{\x00 "
463
+ end
464
+ end
465
+
367
466
it "raises a TypeError with hash having default proc" do
368
- -> { Marshal . dump ( Hash . new { } ) } . should raise_error ( TypeError )
467
+ -> { Marshal . dump ( Hash . new { } ) } . should raise_error ( TypeError , "can't dump hash with default proc" )
369
468
end
370
469
371
470
it "dumps a Hash with instance variables" do
@@ -381,6 +480,11 @@ def _dump(level)
381
480
it "dumps an Hash subclass with a parameter to initialize" do
382
481
Marshal . dump ( UserHashInitParams . new ( 1 ) ) . should == "\004 \b IC:\027 UserHashInitParams{\000 \006 :\a @ai\006 "
383
482
end
483
+
484
+ it "ignores overridden name method when dumps a Hash subclass" do
485
+ obj = MarshalSpec ::HashWithOverriddenName . new
486
+ Marshal . dump ( obj ) . should == "\x04 \b C:(MarshalSpec::HashWithOverriddenName{\x00 "
487
+ end
384
488
end
385
489
386
490
describe "with a Struct" do
@@ -409,6 +513,15 @@ def _dump(level)
409
513
Marshal . dump ( obj ) . should == "\004 \b e:\n MethsS:\025 Struct::Extended\a :\006 a[\a ;\a \" \a hi:\006 b[\a ;\000 @\a "
410
514
Struct . send ( :remove_const , :Extended )
411
515
end
516
+
517
+ it "ignores overridden name method" do
518
+ obj = MarshalSpec ::StructWithOverriddenName . new ( "member" )
519
+ Marshal . dump ( obj ) . should == "\x04 \b S:*MarshalSpec::StructWithOverriddenName\x06 :\x06 a\" \v member"
520
+ end
521
+
522
+ it "raises TypeError with an anonymous Struct" do
523
+ -> { Marshal . dump ( Struct . new ( :a ) . new ( 1 ) ) } . should raise_error ( TypeError , /can't dump anonymous class/ )
524
+ end
412
525
end
413
526
414
527
describe "with an Object" do
@@ -440,20 +553,51 @@ def _dump(level)
440
553
Marshal . dump ( obj ) . should == "\004 \b o:\x0B Object\x00 "
441
554
end
442
555
443
- it "dumps an Object if it has a singleton class but no singleton methods" do
556
+ it "dumps an Object if it has a singleton class but no singleton methods and no singleton instance variables " do
444
557
obj = Object . new
445
558
obj . singleton_class
446
559
Marshal . dump ( obj ) . should == "\004 \b o:\x0B Object\x00 "
447
560
end
448
561
449
- it "raises if an Object has a singleton class and singleton methods" do
562
+ it "ignores overridden name method" do
563
+ obj = MarshalSpec ::ClassWithOverriddenName . new
564
+ Marshal . dump ( obj ) . should == "\x04 \b o:)MarshalSpec::ClassWithOverriddenName\x00 "
565
+ end
566
+
567
+ it "raises TypeError if an Object has a singleton class and singleton methods" do
450
568
obj = Object . new
451
569
def obj . foo ; end
452
570
-> {
453
571
Marshal . dump ( obj )
454
572
} . should raise_error ( TypeError , "singleton can't be dumped" )
455
573
end
456
574
575
+ it "raises TypeError if an Object has a singleton class and singleton instance variables" do
576
+ obj = Object . new
577
+ class << obj
578
+ @v = 1
579
+ end
580
+
581
+ -> {
582
+ Marshal . dump ( obj )
583
+ } . should raise_error ( TypeError , "singleton can't be dumped" )
584
+ end
585
+
586
+ it "raises TypeError if an Object is an instance of an anonymous class" do
587
+ anonymous_class = Class . new
588
+ obj = anonymous_class . new
589
+
590
+ -> { Marshal . dump ( obj ) } . should raise_error ( TypeError , /can't dump anonymous class/ )
591
+ end
592
+
593
+ it "raises TypeError if an Object extends an anonymous module" do
594
+ anonymous_module = Module . new
595
+ obj = Object . new
596
+ obj . extend ( anonymous_module )
597
+
598
+ -> { Marshal . dump ( obj ) } . should raise_error ( TypeError , /can't dump anonymous class/ )
599
+ end
600
+
457
601
it "dumps a BasicObject subclass if it defines respond_to?" do
458
602
obj = MarshalSpec ::BasicObjectSubWithRespondToFalse . new
459
603
Marshal . dump ( obj ) . should == "\x04 \b o:2MarshalSpec::BasicObjectSubWithRespondToFalse\x00 "
@@ -483,6 +627,10 @@ def obj.foo; end
483
627
load . instance_variable_get ( :@foo ) . should == 42
484
628
end
485
629
end
630
+
631
+ it "raises TypeError with an anonymous Range subclass" do
632
+ -> { Marshal . dump ( Class . new ( Range ) . new ( 1 , 2 ) ) } . should raise_error ( TypeError , /can't dump anonymous class/ )
633
+ end
486
634
end
487
635
488
636
describe "with a Time" do
@@ -520,6 +668,20 @@ def obj.foo; end
520
668
zone = ":\t zoneI\" \b UTC\x06 :\x06 EF" # Last is 'F' (US-ASCII)
521
669
dump . should == "\x04 \b Iu:\t Time\r #{ @utc_dump } \x06 #{ zone } "
522
670
end
671
+
672
+ it "ignores overridden name method" do
673
+ obj = MarshalSpec ::TimeWithOverriddenName . new
674
+ Marshal . dump ( obj ) . should include ( "MarshalSpec::TimeWithOverriddenName" )
675
+ end
676
+
677
+ it "dumps a Time subclass with multibyte characters in name" do
678
+ source_object = eval ( "MarshalSpec::MultibyteぁあぃいTime" . force_encoding ( Encoding ::UTF_8 ) )
679
+ Marshal . dump ( source_object ) . should == "\x04 \b c+MarshalSpec::Multibyte\xE3 \x81 \x81 \xE3 \x81 \x82 \xE3 \x81 \x83 \xE3 \x81 \x84 Time"
680
+ end
681
+
682
+ it "raises TypeError with an anonymous Time subclass" do
683
+ -> { Marshal . dump ( Class . new ( Time ) . now ) } . should raise_error ( TypeError )
684
+ end
523
685
end
524
686
525
687
describe "with an Exception" do
@@ -560,6 +722,23 @@ def obj.foo; end
560
722
reloaded . cause . should be_an_instance_of ( StandardError )
561
723
reloaded . cause . message . should == "the cause"
562
724
end
725
+
726
+ # NoMethodError uses an exception formatter on TruffleRuby and computes a message lazily
727
+ it "dumps the message for the raised NoMethodError exception" do
728
+ begin
729
+ "" . foo
730
+ rescue => e
731
+ end
732
+
733
+ Marshal . dump ( e ) . should . include? "undefined method `foo' for \" \" :String"
734
+ end
735
+
736
+ it "raises TypeError if an Object is an instance of an anonymous class" do
737
+ anonymous_class = Class . new ( Exception )
738
+ obj = anonymous_class . new
739
+
740
+ -> { Marshal . dump ( obj ) } . should raise_error ( TypeError , /can't dump anonymous class/ )
741
+ end
563
742
end
564
743
565
744
it "dumps subsequent appearances of a symbol as a link" do
0 commit comments