1require 'test/unit'
2require_relative 'envutil'
3
4# to supress warnings for future calls of Module#refine
5EnvUtil.suppress_warning do
6  Module.new {
7    refine(Object) {}
8  }
9end
10
11class TestRefinement < Test::Unit::TestCase
12  class Foo
13    def x
14      return "Foo#x"
15    end
16
17    def y
18      return "Foo#y"
19    end
20
21    def a
22      return "Foo#a"
23    end
24
25    def call_x
26      return x
27    end
28  end
29
30  module FooExt
31    refine Foo do
32      def x
33        return "FooExt#x"
34      end
35
36      def y
37        return "FooExt#y " + super
38      end
39
40      def z
41        return "FooExt#z"
42      end
43
44      def a
45        return "FooExt#a"
46      end
47    end
48  end
49
50  module FooExt2
51    refine Foo do
52      def x
53        return "FooExt2#x"
54      end
55
56      def y
57        return "FooExt2#y " + super
58      end
59
60      def z
61        return "FooExt2#z"
62      end
63    end
64  end
65
66  class FooSub < Foo
67    def x
68      return "FooSub#x"
69    end
70
71    def y
72      return "FooSub#y " + super
73    end
74  end
75
76  eval <<-EOF, TOPLEVEL_BINDING
77    using TestRefinement::FooExt
78
79    class TestRefinement::FooExtClient
80      def self.invoke_x_on(foo)
81        return foo.x
82      end
83
84      def self.invoke_y_on(foo)
85        return foo.y
86      end
87
88      def self.invoke_z_on(foo)
89        return foo.z
90      end
91
92      def self.send_z_on(foo)
93        return foo.send(:z)
94      end
95
96      def self.method_z(foo)
97        return foo.method(:z)
98      end
99
100      def self.invoke_call_x_on(foo)
101        return foo.call_x
102      end
103    end
104  EOF
105
106  eval <<-EOF, TOPLEVEL_BINDING
107    using TestRefinement::FooExt
108    using TestRefinement::FooExt2
109
110    class TestRefinement::FooExtClient2
111      def self.invoke_y_on(foo)
112        return foo.y
113      end
114
115      def self.invoke_a_on(foo)
116        return foo.a
117      end
118    end
119  EOF
120
121  def test_override
122    foo = Foo.new
123    assert_equal("Foo#x", foo.x)
124    assert_equal("FooExt#x", FooExtClient.invoke_x_on(foo))
125    assert_equal("Foo#x", foo.x)
126  end
127
128  def test_super
129    foo = Foo.new
130    assert_equal("Foo#y", foo.y)
131    assert_equal("FooExt#y Foo#y", FooExtClient.invoke_y_on(foo))
132    assert_equal("Foo#y", foo.y)
133  end
134
135  def test_super_not_chained
136    foo = Foo.new
137    assert_equal("Foo#y", foo.y)
138    assert_equal("FooExt2#y Foo#y", FooExtClient2.invoke_y_on(foo))
139    assert_equal("Foo#y", foo.y)
140  end
141
142  def test_using_same_class_refinements
143    foo = Foo.new
144    assert_equal("Foo#a", foo.a)
145    assert_equal("FooExt#a", FooExtClient2.invoke_a_on(foo))
146    assert_equal("Foo#a", foo.a)
147  end
148
149  def test_new_method
150    foo = Foo.new
151    assert_raise(NoMethodError) { foo.z }
152    assert_equal("FooExt#z", FooExtClient.invoke_z_on(foo))
153    assert_raise(NoMethodError) { foo.z }
154  end
155
156  module RespondTo
157    class Super
158      def foo
159      end
160    end
161
162    class Sub < Super
163    end
164
165    module M
166      refine Sub do
167        def foo
168        end
169      end
170    end
171  end
172
173  def test_send_should_not_use_refinements
174    foo = Foo.new
175    assert_raise(NoMethodError) { foo.send(:z) }
176    assert_raise(NoMethodError) { FooExtClient.send_z_on(foo) }
177    assert_raise(NoMethodError) { foo.send(:z) }
178
179    assert_equal(true, RespondTo::Sub.new.respond_to?(:foo))
180  end
181
182  def test_method_should_not_use_refinements
183    foo = Foo.new
184    assert_raise(NameError) { foo.method(:z) }
185    assert_raise(NameError) { FooExtClient.method_z(foo) }
186    assert_raise(NameError) { foo.method(:z) }
187  end
188
189  def test_no_local_rebinding
190    foo = Foo.new
191    assert_equal("Foo#x", foo.call_x)
192    assert_equal("Foo#x", FooExtClient.invoke_call_x_on(foo))
193    assert_equal("Foo#x", foo.call_x)
194  end
195
196  def test_subclass_is_prior
197    sub = FooSub.new
198    assert_equal("FooSub#x", sub.x)
199    assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub))
200    assert_equal("FooSub#x", sub.x)
201  end
202
203  def test_super_in_subclass
204    sub = FooSub.new
205    assert_equal("FooSub#y Foo#y", sub.y)
206    # not "FooSub#y FooExt#y Foo#y"
207    assert_equal("FooSub#y Foo#y", FooExtClient.invoke_y_on(sub))
208    assert_equal("FooSub#y Foo#y", sub.y)
209  end
210
211  def test_new_method_on_subclass
212    sub = FooSub.new
213    assert_raise(NoMethodError) { sub.z }
214    assert_equal("FooExt#z", FooExtClient.invoke_z_on(sub))
215    assert_raise(NoMethodError) { sub.z }
216  end
217
218  def test_module_eval
219    foo = Foo.new
220    assert_equal("Foo#x", foo.x)
221    assert_equal("Foo#x", FooExt.module_eval { foo.x })
222    assert_equal("Foo#x", FooExt.module_eval("foo.x"))
223    assert_equal("Foo#x", foo.x)
224  end
225
226  def test_instance_eval_without_refinement
227    foo = Foo.new
228    ext_client = FooExtClient.new
229    assert_equal("Foo#x", foo.x)
230    assert_equal("Foo#x", ext_client.instance_eval { foo.x })
231    assert_equal("Foo#x", foo.x)
232  end
233
234  module FixnumSlashExt
235    refine Fixnum do
236      def /(other) quo(other) end
237    end
238  end
239
240  def test_override_builtin_method
241    assert_equal(0, 1 / 2)
242    assert_equal(Rational(1, 2), eval_using(FixnumSlashExt, "1 / 2"))
243    assert_equal(0, 1 / 2)
244  end
245
246  module FixnumPlusExt
247    refine Fixnum do
248      def self.method_added(*args); end
249      def +(other) "overriden" end
250    end
251  end
252
253  def test_override_builtin_method_with_method_added
254    assert_equal(3, 1 + 2)
255    assert_equal("overriden", eval_using(FixnumPlusExt, "1 + 2"))
256    assert_equal(3, 1 + 2)
257  end
258
259  def test_return_value_of_refine
260    mod = nil
261    result = nil
262    m = Module.new {
263      result = refine(Object) {
264        mod = self
265      }
266    }
267    assert_equal mod, result
268  end
269
270  module RefineSameClass
271    REFINEMENT1 = refine(Fixnum) {
272      def foo; return "foo" end
273    }
274    REFINEMENT2 = refine(Fixnum) {
275      def bar; return "bar" end
276    }
277    REFINEMENT3 = refine(String) {
278      def baz; return "baz" end
279    }
280  end
281
282  def test_refine_same_class_twice
283    assert_equal("foo", eval_using(RefineSameClass, "1.foo"))
284    assert_equal("bar", eval_using(RefineSameClass, "1.bar"))
285    assert_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT2)
286    assert_not_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT3)
287  end
288
289  module FixnumFooExt
290    refine Fixnum do
291      def foo; "foo"; end
292    end
293  end
294
295  def test_respond_to_should_not_use_refinements
296    assert_equal(false, 1.respond_to?(:foo))
297    assert_equal(false, eval_using(FixnumFooExt, "1.respond_to?(:foo)"))
298  end
299
300  module StringCmpExt
301    refine String do
302      def <=>(other) return 0 end
303    end
304  end
305
306  module ArrayEachExt
307    refine Array do
308      def each
309        super do |i|
310          yield 2 * i
311        end
312      end
313    end
314  end
315
316  def test_builtin_method_no_local_rebinding
317    assert_equal(false, eval_using(StringCmpExt, '"1" >= "2"'))
318    assert_equal(1, eval_using(ArrayEachExt, "[1, 2, 3].min"))
319  end
320
321  module RefinePrependedClass
322    module M1
323      def foo
324        super << :m1
325      end
326    end
327
328    class C
329      prepend M1
330
331      def foo
332        [:c]
333      end
334    end
335
336    module M2
337      refine C do
338        def foo
339          super << :m2
340        end
341      end
342    end
343  end
344
345  def test_refine_prepended_class
346    x = eval_using(RefinePrependedClass::M2,
347                   "TestRefinement::RefinePrependedClass::C.new.foo")
348    assert_equal([:c, :m1, :m2], x)
349  end
350
351  def test_refine_module
352    m1 = Module.new
353    assert_raise(TypeError) do
354      Module.new {
355        refine m1 do
356        def foo
357          :m2
358        end
359        end
360      }
361    end
362  end
363
364  def test_refine_neither_class_nor_module
365    assert_raise(TypeError) do
366      Module.new {
367        refine Object.new do
368        end
369      }
370    end
371    assert_raise(TypeError) do
372      Module.new {
373        refine 123 do
374        end
375      }
376    end
377    assert_raise(TypeError) do
378      Module.new {
379        refine "foo" do
380        end
381      }
382    end
383  end
384
385  def test_refine_in_class
386    assert_raise(NoMethodError) do
387      Class.new {
388        refine Fixnum do
389          def foo
390            "c"
391          end
392        end
393      }
394    end
395  end
396
397  def test_main_using
398    assert_in_out_err([], <<-INPUT, %w(:C :M), /Refinements are experimental/)
399      class C
400        def foo
401          :C
402        end
403      end
404
405      module M
406        refine C do
407          def foo
408            :M
409          end
410        end
411      end
412
413      c = C.new
414      p c.foo
415      using M
416      p c.foo
417    INPUT
418  end
419
420  def test_main_using_is_private
421    assert_raise(NoMethodError) do
422      eval("self.using Module.new", TOPLEVEL_BINDING)
423    end
424  end
425
426  def test_no_kernel_using
427    assert_raise(NoMethodError) do
428      using Module.new
429    end
430  end
431
432  def test_no_module_using
433    assert_raise(NoMethodError) do
434      Module.new {
435        using Module.new
436      }
437    end
438  end
439
440  class UsingClass
441  end
442
443  def test_module_using_class
444    c = Class.new
445    assert_raise(TypeError) do
446      eval("using TestRefinement::UsingClass", TOPLEVEL_BINDING)
447    end
448  end
449
450  def test_refine_without_block
451    c1 = Class.new
452    e = assert_raise(ArgumentError) {
453      Module.new do
454        refine c1
455      end
456    }
457    assert_equal("no block given", e.message)
458  end
459
460  module Inspect
461    module M
462      Fixnum = refine(Fixnum) {}
463    end
464  end
465
466  def test_inspect
467    assert_equal("#<refinement:Fixnum@TestRefinement::Inspect::M>",
468                 Inspect::M::Fixnum.inspect)
469  end
470
471  def test_using_method_cache
472    assert_in_out_err([], <<-INPUT, %w(:M1 :M2), /Refinements are experimental/)
473      class C
474        def foo
475          "original"
476        end
477      end
478
479      module M1
480        refine C do
481          def foo
482            :M1
483          end
484        end
485      end
486
487      module M2
488        refine C do
489          def foo
490            :M2
491          end
492        end
493      end
494
495      c = C.new
496      using M1
497      p c.foo
498      using M2
499      p c.foo
500    INPUT
501  end
502
503  module RedefineRefinedMethod
504    class C
505      def foo
506        "original"
507      end
508    end
509
510    module M
511      refine C do
512        def foo
513          "refined"
514        end
515      end
516    end
517
518    class C
519      def foo
520        "redefined"
521      end
522    end
523  end
524
525  def test_redefine_refined_method
526    x = eval_using(RedefineRefinedMethod::M,
527                   "TestRefinement::RedefineRefinedMethod::C.new.foo")
528    assert_equal("refined", x)
529  end
530
531  module StringExt
532    refine String do
533      def foo
534        "foo"
535      end
536    end
537  end
538
539  module RefineScoping
540    refine String do
541      def foo
542        "foo"
543      end
544
545      def RefineScoping.call_in_refine_block
546        "".foo
547      end
548    end
549
550    def self.call_outside_refine_block
551      "".foo
552    end
553  end
554
555  def test_refine_scoping
556    assert_equal("foo", RefineScoping.call_in_refine_block)
557    assert_raise(NoMethodError) do
558      RefineScoping.call_outside_refine_block
559    end
560  end
561
562  module StringRecursiveLength
563    refine String do
564      def recursive_length
565        if empty?
566          0
567        else
568          self[1..-1].recursive_length + 1
569        end
570      end
571    end
572  end
573
574  def test_refine_recursion
575    x = eval_using(StringRecursiveLength, "'foo'.recursive_length")
576    assert_equal(3, x)
577  end
578
579  module ToJSON
580    refine Integer do
581      def to_json; to_s; end
582    end
583
584    refine Array do
585      def to_json; "[" + map { |i| i.to_json }.join(",") + "]" end
586    end
587
588    refine Hash do
589      def to_json; "{" + map { |k, v| k.to_s.dump + ":" + v.to_json }.join(",") + "}" end
590    end
591  end
592
593  def test_refine_mutual_recursion
594    x = eval_using(ToJSON, "[{1=>2}, {3=>4}].to_json")
595    assert_equal('[{"1":2},{"3":4}]', x)
596  end
597
598  def test_refine_with_proc
599    assert_raise(ArgumentError) do
600      Module.new {
601        refine(String, &Proc.new {})
602      }
603    end
604  end
605
606  def test_using_in_module
607    assert_raise(RuntimeError) do
608      eval(<<-EOF, TOPLEVEL_BINDING)
609        $main = self
610        module M
611        end
612        module M2
613          $main.send(:using, M)
614        end
615      EOF
616    end
617  end
618
619  def test_using_in_method
620    assert_raise(RuntimeError) do
621      eval(<<-EOF, TOPLEVEL_BINDING)
622        $main = self
623        module M
624        end
625        def call_using_in_method
626          $main.send(:using, M)
627        end
628        call_using_in_method
629      EOF
630    end
631  end
632
633  module IncludeIntoRefinement
634    class C
635      def bar
636        return "C#bar"
637      end
638
639      def baz
640        return "C#baz"
641      end
642    end
643
644    module Mixin
645      def foo
646        return "Mixin#foo"
647      end
648
649      def bar
650        return super << " Mixin#bar"
651      end
652
653      def baz
654        return super << " Mixin#baz"
655      end
656    end
657
658    module M
659      refine C do
660        include Mixin
661
662        def baz
663          return super << " M#baz"
664        end
665      end
666    end
667  end
668
669  eval <<-EOF, TOPLEVEL_BINDING
670    using TestRefinement::IncludeIntoRefinement::M
671
672    module TestRefinement::IncludeIntoRefinement::User
673      def self.invoke_foo_on(x)
674        x.foo
675      end
676
677      def self.invoke_bar_on(x)
678        x.bar
679      end
680
681      def self.invoke_baz_on(x)
682        x.baz
683      end
684    end
685  EOF
686
687  def test_include_into_refinement
688    x = IncludeIntoRefinement::C.new
689    assert_equal("Mixin#foo", IncludeIntoRefinement::User.invoke_foo_on(x))
690    assert_equal("C#bar Mixin#bar",
691                 IncludeIntoRefinement::User.invoke_bar_on(x))
692    assert_equal("C#baz Mixin#baz M#baz",
693                 IncludeIntoRefinement::User.invoke_baz_on(x))
694  end
695
696  module PrependIntoRefinement
697    class C
698      def bar
699        return "C#bar"
700      end
701
702      def baz
703        return "C#baz"
704      end
705    end
706
707    module Mixin
708      def foo
709        return "Mixin#foo"
710      end
711
712      def bar
713        return super << " Mixin#bar"
714      end
715
716      def baz
717        return super << " Mixin#baz"
718      end
719    end
720
721    module M
722      refine C do
723        prepend Mixin
724
725        def baz
726          return super << " M#baz"
727        end
728      end
729    end
730  end
731
732  eval <<-EOF, TOPLEVEL_BINDING
733    using TestRefinement::PrependIntoRefinement::M
734
735    module TestRefinement::PrependIntoRefinement::User
736      def self.invoke_foo_on(x)
737        x.foo
738      end
739
740      def self.invoke_bar_on(x)
741        x.bar
742      end
743
744      def self.invoke_baz_on(x)
745        x.baz
746      end
747    end
748  EOF
749
750  def test_prepend_into_refinement
751    x = PrependIntoRefinement::C.new
752    assert_equal("Mixin#foo", PrependIntoRefinement::User.invoke_foo_on(x))
753    assert_equal("C#bar Mixin#bar",
754                 PrependIntoRefinement::User.invoke_bar_on(x))
755    assert_equal("C#baz M#baz Mixin#baz",
756                 PrependIntoRefinement::User.invoke_baz_on(x))
757  end
758
759  module PrependAfterRefine
760    class C
761      def foo
762        "original"
763      end
764    end
765
766    module M
767      refine C do
768        def foo
769          "refined"
770        end
771
772        def bar
773          "refined"
774        end
775      end
776    end
777
778    module Mixin
779      def foo
780        "mixin"
781      end
782
783      def bar
784        "mixin"
785      end
786    end
787
788    class C
789      prepend Mixin
790    end
791  end
792
793  def test_prepend_after_refine
794    x = eval_using(PrependAfterRefine::M,
795                   "TestRefinement::PrependAfterRefine::C.new.foo")
796    assert_equal("refined", x)
797    assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.foo)
798    y = eval_using(PrependAfterRefine::M,
799                   "TestRefinement::PrependAfterRefine::C.new.bar")
800    assert_equal("refined", y)
801    assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.bar)
802  end
803
804  module SuperInBlock
805    class C
806      def foo(*args)
807        [:foo, *args]
808      end
809    end
810
811    module R
812      refine C do
813        def foo(*args)
814          tap do
815            return super(:ref, *args)
816          end
817        end
818      end
819    end
820  end
821
822  def test_super_in_block
823    bug7925 = '[ruby-core:52750] [Bug #7925]'
824    x = eval_using(SuperInBlock::R,
825                   "TestRefinement:: SuperInBlock::C.new.foo(#{bug7925.dump})")
826    assert_equal([:foo, :ref, bug7925], x, bug7925)
827  end
828
829  def test_case_dispatch_is_aware_of_refinements
830    assert_in_out_err([], <<-RUBY, ["refinement used"], [])
831      $VERBOSE = nil #to suppress warning "Refinements are experimental, ..."
832      module RefineSymbol
833        refine Symbol do
834          def ===(other)
835            true
836          end
837        end
838      end
839
840      using RefineSymbol
841
842      case :a
843      when :b
844        puts "refinement used"
845      else
846        puts "refinement not used"
847      end
848    RUBY
849  end
850
851  def test_instance_methods
852    bug8881 = '[ruby-core:57080] [Bug #8881]'
853    assert_not_include(Foo.instance_methods(false), :z, bug8881)
854    assert_not_include(FooSub.instance_methods(true), :z, bug8881)
855  end
856
857  def test_method_defined
858    assert_not_send([Foo, :method_defined?, :z])
859    assert_not_send([FooSub, :method_defined?, :z])
860  end
861
862  def test_undef_refined_method
863    bug8966 = '[ruby-core:57466] [Bug #8966]'
864
865    assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966)
866      $VERBOSE = nil #to suppress warning "Refinements are experimental, ..."
867      module Foo
868        refine Object do
869          def foo
870            puts "foo"
871          end
872        end
873      end
874
875      using Foo
876
877      class Object
878        begin
879          undef foo
880        rescue Exception => e
881          p e.class
882        end
883      end
884    INPUT
885
886    assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966)
887      $VERBOSE = nil #to suppress warning "Refinements are experimental, ..."
888      module Foo
889        refine Object do
890          def foo
891            puts "foo"
892          end
893        end
894      end
895
896      # without `using Foo'
897
898      class Object
899        begin
900          undef foo
901        rescue Exception => e
902          p e.class
903        end
904      end
905    INPUT
906  end
907
908  def test_refine_undefed_method_and_call
909    assert_in_out_err([], <<-INPUT, ["NoMethodError"], [])
910      $VERBOSE = nil #to suppress warning "Refinements are experimental, ..."
911      class Foo
912        def foo
913        end
914
915        undef foo
916      end
917
918      module FooExt
919        refine Foo do
920          def foo
921          end
922        end
923      end
924
925      begin
926        Foo.new.foo
927      rescue => e
928        p e.class
929      end
930    INPUT
931  end
932
933  def test_refine_undefed_method_and_send
934    assert_in_out_err([], <<-INPUT, ["NoMethodError"], [])
935      $VERBOSE = nil #to suppress warning "Refinements are experimental, ..."
936      class Foo
937        def foo
938        end
939
940        undef foo
941      end
942
943      module FooExt
944        refine Foo do
945          def foo
946          end
947        end
948      end
949
950      begin
951        Foo.new.send(:foo)
952      rescue => e
953        p e.class
954      end
955    INPUT
956  end
957
958  def test_adding_private_method
959    bug9452 = '[ruby-core:60111] [Bug #9452]'
960
961    assert_in_out_err([], <<-INPUT, ["Success!", "NoMethodError"], [], bug9452)
962      $VERBOSE = nil #to suppress warning "Refinements are experimental, ..."
963      module R
964        refine Object do
965          def m
966            puts "Success!"
967          end
968
969          private(:m)
970        end
971      end
972
973      using R
974
975      m
976      42.m rescue p($!.class)
977    INPUT
978  end
979
980  def test_making_private_method_public
981    bug9452 = '[ruby-core:60111] [Bug #9452]'
982
983    assert_in_out_err([], <<-INPUT, ["Success!", "Success!"], [], bug9452)
984        $VERBOSE = nil #to suppress warning "Refinements are experimental, ..."
985        class Object
986          private
987          def m
988          end
989        end
990
991        module R
992          refine Object do
993            def m
994              puts "Success!"
995            end
996          end
997        end
998
999        using R
1000        m
1001        42.m
1002    INPUT
1003  end
1004
1005  private
1006
1007  def eval_using(mod, s)
1008    eval("using #{mod}; #{s}", TOPLEVEL_BINDING)
1009  end
1010end
1011