aquarium 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,6 +9,17 @@ class Dummy
9
9
  def count; 0; end
10
10
  end
11
11
 
12
+ class ProtectionExample
13
+ def public_instance_m; end
14
+ protected
15
+ def protected_instance_m; end
16
+ private
17
+ def private_instance_m; end
18
+ def self.public_class_m; end
19
+ def self.private_class_m; end
20
+ private_class_method :private_class_m
21
+ end
22
+
12
23
  describe Aquarium::Aspects::JoinPoint, "#initialize with invalid parameters" do
13
24
 
14
25
  it "should require either a :type or an :object parameter when creating." do
@@ -29,48 +40,44 @@ describe Aquarium::Aspects::JoinPoint, "#initialize with parameters that specify
29
40
  it "should assume the :method_name refers to an instance method, by default." do
30
41
  jp = Aquarium::Aspects::JoinPoint.new :type => String, :method => :split
31
42
  jp.instance_method?.should be_true
43
+ jp.class_method?.should be_false
32
44
  end
33
45
 
34
46
  it "should treat the :method_name as refering to an instance method if :instance_method is specified as true." do
35
47
  jp = Aquarium::Aspects::JoinPoint.new :type => String, :method => :split, :instance_method => true
36
48
  jp.instance_method?.should be_true
49
+ jp.class_method?.should be_false
37
50
  end
38
51
 
39
52
  it "should treat the :method_name as refering to a class method if :instance_method is specified as false." do
40
53
  jp = Aquarium::Aspects::JoinPoint.new :type => String, :method => :split, :instance_method => false
41
54
  jp.instance_method?.should be_false
55
+ jp.class_method?.should be_true
42
56
  end
43
57
 
44
58
  it "should treat the :method_name as refering to an instance method if :class_method is specified as false." do
45
59
  jp = Aquarium::Aspects::JoinPoint.new :type => String, :method => :split, :class_method => false
46
60
  jp.instance_method?.should be_true
61
+ jp.class_method?.should be_false
47
62
  end
48
63
 
49
64
  it "should treat the :method_name as refering to a class method if :class_method is specified as true." do
50
65
  jp = Aquarium::Aspects::JoinPoint.new :type => String, :method => :split, :class_method => true
51
66
  jp.instance_method?.should be_false
67
+ jp.class_method?.should be_true
52
68
  end
53
69
 
54
70
  it "should treat give precedence to :instance_method if appears with :class_method." do
55
71
  jp = Aquarium::Aspects::JoinPoint.new :type => String, :method => :split, :instance_method => false, :class_method => true
56
72
  jp.instance_method?.should be_false
73
+ jp.class_method?.should be_true
57
74
  jp = Aquarium::Aspects::JoinPoint.new :type => String, :method => :split, :instance_method => true, :class_method => false
58
75
  jp.instance_method?.should be_true
76
+ jp.class_method?.should be_false
59
77
  end
60
78
  end
61
79
 
62
80
  describe Aquarium::Aspects::JoinPoint, "#visibility" do
63
- class ProtectionExample
64
- def public_instance_m; end
65
- protected
66
- def protected_instance_m; end
67
- private
68
- def private_instance_m; end
69
- def self.public_class_m; end
70
- def self.private_class_m; end
71
- private_class_method :private_class_m
72
- end
73
-
74
81
  it "should return :public for public instance methods." do
75
82
  jp = Aquarium::Aspects::JoinPoint.new :type => ProtectionExample, :method => :public_instance_m
76
83
  jp.visibility.should == :public
@@ -159,6 +166,21 @@ describe Aquarium::Aspects::JoinPoint, "#visibility" do
159
166
  jp.visibility.should == nil
160
167
  end
161
168
  end
169
+
170
+ describe Aquarium::Aspects::JoinPoint, "#target_type" do
171
+ it "should return the type at the JoinPoint" do
172
+ jp = Aquarium::Aspects::JoinPoint.new :type => ProtectionExample, :method => :foo
173
+ jp.target_type.should be_eql(ProtectionExample)
174
+ end
175
+ end
176
+
177
+ describe Aquarium::Aspects::JoinPoint, "#target_object" do
178
+ it "should return the object at the JoinPoint" do
179
+ example = ProtectionExample.new
180
+ jp = Aquarium::Aspects::JoinPoint.new :object => example, :method => :foo
181
+ jp.target_object.should be_eql(example)
182
+ end
183
+ end
162
184
 
163
185
  describe Aquarium::Aspects::JoinPoint, "#dup" do
164
186
  it "should duplicate the fields in the join point." do
@@ -274,6 +296,67 @@ describe Aquarium::Aspects::JoinPoint, "#make_current_context_join_point when th
274
296
  end
275
297
  end
276
298
 
299
+ describe Aquarium::Aspects::JoinPoint, "#type_or_object" do
300
+ it "should return the type if the object is nil" do
301
+ jp = Aquarium::Aspects::JoinPoint.new :type => String, :method_name => :split
302
+ jp.type_or_object.should eql(String)
303
+ end
304
+
305
+ it "should return the object if the type is nil" do
306
+ jp = Aquarium::Aspects::JoinPoint.new :object => String.new, :method_name => :split
307
+ jp.type_or_object.should eql("")
308
+ end
309
+ end
310
+
311
+ describe Aquarium::Aspects::JoinPoint, "#exists?" do
312
+ it "should return false if the join point represents a non-existent join point for an instance method in the runtime environment" do
313
+ jp = Aquarium::Aspects::JoinPoint.new :type => ProtectionExample, :method_name => :foo
314
+ jp.exists?.should be_false
315
+ end
316
+
317
+ it "should return false if the join point represents a non-existent join point for a class method in the runtime environment" do
318
+ jp = Aquarium::Aspects::JoinPoint.new :type => ProtectionExample, :method_name => :foo, :class_method => true
319
+ jp.exists?.should be_false
320
+ end
321
+
322
+ it "should return true if the join point represents a real join point for a public instance method in the runtime environment" do
323
+ jp = Aquarium::Aspects::JoinPoint.new :type => ProtectionExample, :method_name => :public_instance_m
324
+ jp.exists?.should be_true
325
+ end
326
+
327
+ it "should return true if the join point represents a real join point for a protected instance method in the runtime environment" do
328
+ jp = Aquarium::Aspects::JoinPoint.new :type => ProtectionExample, :method_name => :protected_instance_m
329
+ jp.exists?.should be_true
330
+ end
331
+
332
+ it "should return true if the join point represents a real join point for a private instance method in the runtime environment" do
333
+ jp = Aquarium::Aspects::JoinPoint.new :type => ProtectionExample, :method_name => :private_instance_m
334
+ jp.exists?.should be_true
335
+ end
336
+
337
+ it "should return true if the join point represents a real join point for a public class method in the runtime environment" do
338
+ jp = Aquarium::Aspects::JoinPoint.new :type => ProtectionExample, :method_name => :public_class_m, :class_method => true
339
+ jp.exists?.should be_true
340
+ end
341
+
342
+ it "should return true if the join point represents a real join point for a private class method in the runtime environment" do
343
+ jp = Aquarium::Aspects::JoinPoint.new :type => ProtectionExample, :method_name => :private_class_m, :class_method => true
344
+ jp.exists?.should be_true
345
+ end
346
+
347
+ class ProtectionExample2
348
+ def public_instance_m; end
349
+ protected
350
+ def protected_instance_m; end
351
+ private
352
+ def private_instance_m; end
353
+ def self.public_class_m; end
354
+ def self.private_class_m; end
355
+ private_class_method :private_class_m
356
+ end
357
+
358
+ end
359
+
277
360
  describe Aquarium::Aspects::JoinPoint, "#make_current_context_join_point when the Aquarium::Aspects::JoinPoint::Context object is not nil" do
278
361
  it "should return a new join_point that contains the non-context information of the advised_object plus an updated Aquarium::Aspects::JoinPoint::Context with the specified context information." do
279
362
  jp = Aquarium::Aspects::JoinPoint.new :type => String, :method_name => :split
@@ -296,18 +379,6 @@ describe Aquarium::Aspects::JoinPoint, "#make_current_context_join_point when th
296
379
  end
297
380
  end
298
381
 
299
- describe Aquarium::Aspects::JoinPoint, "#type_or_object" do
300
- it "should return the type if the object is nil" do
301
- jp = Aquarium::Aspects::JoinPoint.new :type => String, :method_name => :split
302
- jp.type_or_object.should eql(String)
303
- end
304
-
305
- it "should return the object if the type is nil" do
306
- jp = Aquarium::Aspects::JoinPoint.new :object => String.new, :method_name => :split
307
- jp.type_or_object.should eql("")
308
- end
309
- end
310
-
311
382
  describe Aquarium::Aspects::JoinPoint::Context, "#initialize" do
312
383
  it "should require :advice_kind, :advised_object and :parameters arguments." do
313
384
  lambda { Aquarium::Aspects::JoinPoint::Context.new :advised_object => "object", :parameters => [","]}.should raise_error(Aquarium::Utils::InvalidOptions)
@@ -32,12 +32,14 @@ describe "Aquarium::Aspects::Pointcut#and" do
32
32
 
33
33
  it "should return a new Aquarium::Aspects::Pointcut whose join points are the union of the left- and right-hand side Aquarium::Aspects::Pointcuts for type-based Aquarium::Aspects::Pointcuts." do
34
34
  pc1 = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers, :suppress_ancestor_methods]
35
- pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :method_options => :suppress_ancestor_methods
35
+ # "[^F]" excludes the ClassWithFunkyMethodNames...
36
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class[^F]+Method/, :method_options => :suppress_ancestor_methods
36
37
  pc = pc1.or pc2
37
38
  jp1 = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method => :attrRW_ClassWithAttribs=
38
39
  jp2 = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method => :attrW_ClassWithAttribs=
39
- jp3 = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicInstanceMethod, :method => :public_instance_test_method
40
- pc.join_points_matched.should == Set.new([jp1, jp2, jp3])
40
+ jp3 = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicInstanceMethod, :method => :public_instance_test_method
41
+ jp4 = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicInstanceMethod2, :method => :public_instance_test_method2
42
+ pc.join_points_matched.should == Set.new([jp1, jp2, jp3, jp4])
41
43
  pc.join_points_not_matched.should == @not_matched_jps
42
44
  end
43
45
 
@@ -1,6 +1,8 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
2
  require File.dirname(__FILE__) + '/../spec_example_classes'
3
+ require 'aquarium/utils/invalid_options'
3
4
  require 'aquarium/extensions/hash'
5
+ require 'aquarium/aspects/join_point'
4
6
  require 'aquarium/aspects/pointcut'
5
7
  require 'aquarium/utils'
6
8
 
@@ -21,7 +23,13 @@ def common_setup
21
23
  @expected_not_matched_jps = Set.new [@apro_jp, @apri_jp, @acpub_jp, @acpri_jp]
22
24
  end
23
25
 
24
- describe Aquarium::Aspects::Pointcut, " (empty)" do
26
+ describe Aquarium::Aspects::Pointcut, "#new (invalid arguments)" do
27
+ it "should raise if an unknown argument is specified" do
28
+ lambda { Aquarium::Aspects::Pointcut.new :foo => :bar }.should raise_error(Aquarium::Utils::InvalidOptions)
29
+ end
30
+ end
31
+
32
+ describe Aquarium::Aspects::Pointcut, "#new (empty)" do
25
33
  it "should match no join points by default." do
26
34
  pc = Aquarium::Aspects::Pointcut.new
27
35
  pc.should be_empty
@@ -51,6 +59,16 @@ describe Aquarium::Aspects::Pointcut, " (empty)" do
51
59
  pc = Aquarium::Aspects::Pointcut.new :objects => nil
52
60
  pc.should be_empty
53
61
  end
62
+
63
+ it "should match no join points if join_points = nil specified." do
64
+ pc = Aquarium::Aspects::Pointcut.new :join_points => nil
65
+ pc.should be_empty
66
+ end
67
+
68
+ it "should match no join points if join_points = [] specified." do
69
+ pc = Aquarium::Aspects::Pointcut.new :join_points => []
70
+ pc.should be_empty
71
+ end
54
72
  end
55
73
 
56
74
  describe Aquarium::Aspects::Pointcut, "#empty?" do
@@ -81,11 +99,17 @@ describe Aquarium::Aspects::Pointcut, " (types specified using regular expressio
81
99
  common_setup
82
100
  end
83
101
 
84
- it "should match multiple classes using regular expressions." do
85
- pc = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :method_options => :suppress_ancestor_methods
102
+ it "should match multiple classes using regular expressions that cover the full class names." do
103
+ pc = Aquarium::Aspects::Pointcut.new :types => /Class.*Method\Z/, :method_options => :suppress_ancestor_methods
86
104
  pc.join_points_matched.should == @expected_matched_jps
87
105
  pc.join_points_not_matched.should == @expected_not_matched_jps
88
106
  end
107
+
108
+ it "should match classes using regular expressions that only cover partial class names." do
109
+ pc = Aquarium::Aspects::Pointcut.new :types => /lass.*Pro.*Inst.*Met/, :method_options => [:public, :protected, :suppress_ancestor_methods]
110
+ pc.join_points_matched.should == Set.new([@pro_jp])
111
+ pc.join_points_not_matched.size.should == 0
112
+ end
89
113
  end
90
114
 
91
115
  describe Aquarium::Aspects::Pointcut, " (types specified using names)" do
@@ -438,6 +462,35 @@ describe Aquarium::Aspects::Pointcut, " (types or objects specified with attribu
438
462
  end
439
463
  end
440
464
 
465
+ describe Aquarium::Aspects::Pointcut, " (join points specified)" do
466
+ setup do
467
+ common_setup
468
+ @anClassWithPublicInstanceMethod = ClassWithPublicInstanceMethod.new
469
+ @expected_matched = [@pub_jp, @pro_jp, @pri_jp, @cpub_jp, @cpri_jp,
470
+ Aquarium::Aspects::JoinPoint.new(:object => @anClassWithPublicInstanceMethod, :method => :public_instance_test_method)]
471
+ @expected_not_matched = [
472
+ Aquarium::Aspects::JoinPoint.new(:type => ClassWithPublicInstanceMethod, :method => :foo),
473
+ Aquarium::Aspects::JoinPoint.new(:object => @anClassWithPublicInstanceMethod, :method => :foo)]
474
+ end
475
+
476
+ it "should return matches only for existing join points." do
477
+ pc = Aquarium::Aspects::Pointcut.new :join_points => (@expected_matched + @expected_not_matched)
478
+ pc.join_points_matched.should == Set.new(@expected_matched)
479
+ end
480
+
481
+ it "should return non-matches for non-existing join points." do
482
+ pc = Aquarium::Aspects::Pointcut.new :join_points => (@expected_matched + @expected_not_matched)
483
+ pc.join_points_not_matched.should == Set.new(@expected_not_matched)
484
+ end
485
+
486
+ it "should ignore :methods, :attributes, :method_options, and :attribute_options for the join points specified." do
487
+ pc = Aquarium::Aspects::Pointcut.new :join_points => (@expected_matched + @expected_not_matched),
488
+ :methods => :kind_of?, :attributes => :name, :method_options => [:class], :attribute_options => [:readers]
489
+ pc.join_points_matched.should == Set.new(@expected_matched)
490
+ pc.join_points_not_matched.should == Set.new(@expected_not_matched)
491
+ end
492
+ end
493
+
441
494
  describe Aquarium::Aspects::Pointcut, " (methods that end in non-alphanumeric characters)" do
442
495
  class ClassWithFunkyMethodNames
443
496
  def huh?; true; end
@@ -611,8 +664,8 @@ describe Aquarium::Aspects::Pointcut, "#eql?" do
611
664
  end
612
665
 
613
666
  it "should return false if the not_matched types are different." do
614
- pc1 = Aquarium::Aspects::Pointcut.new :types => /Foo/
615
- pc2 = Aquarium::Aspects::Pointcut.new :types => /Bar/
667
+ pc1 = Aquarium::Aspects::Pointcut.new :types => :UnknownFoo
668
+ pc2 = Aquarium::Aspects::Pointcut.new :types => :UnknownBar
616
669
  pc1.should_not eql(pc2)
617
670
  end
618
671
 
@@ -685,7 +738,7 @@ describe "Aquarium::Aspects::Pointcut#eql?" do
685
738
  end
686
739
  end
687
740
 
688
- describe "Aquarium::Aspects::Pointcut#candidate_types" do
741
+ describe Aquarium::Aspects::Pointcut, "#candidate_types" do
689
742
  setup do
690
743
  common_setup
691
744
  end
@@ -715,7 +768,7 @@ describe "Aquarium::Aspects::Pointcut#candidate_types" do
715
768
  end
716
769
  end
717
770
 
718
- describe "Aquarium::Aspects::Pointcut#candidate_objects" do
771
+ describe Aquarium::Aspects::Pointcut, "#candidate_objects" do
719
772
  setup do
720
773
  common_setup
721
774
  end
@@ -730,7 +783,36 @@ describe "Aquarium::Aspects::Pointcut#candidate_objects" do
730
783
  end
731
784
  end
732
785
 
733
- describe "Aquarium::Aspects::Pointcut#specification" do
786
+ describe Aquarium::Aspects::Pointcut, "#candidate_join_points" do
787
+ setup do
788
+ common_setup
789
+ end
790
+
791
+ it "should return only candidate non-matching join points for the input join points that do not exist." do
792
+ anClassWithPublicInstanceMethod = ClassWithPublicInstanceMethod.new
793
+ example_jps = [
794
+ Aquarium::Aspects::JoinPoint.new(:type => ClassWithPublicInstanceMethod, :method => :foo),
795
+ Aquarium::Aspects::JoinPoint.new(:object => anClassWithPublicInstanceMethod, :method => :foo)]
796
+ pc = Aquarium::Aspects::Pointcut.new :join_points => example_jps
797
+ pc.candidate_join_points.matched.size.should == 0
798
+ pc.candidate_join_points.not_matched[example_jps[0]].should_not be_nil
799
+ pc.candidate_join_points.not_matched[example_jps[1]].should_not be_nil
800
+ end
801
+
802
+ it "should return only candidate matching join points for the input join points that do exist." do
803
+ anClassWithPublicInstanceMethod = ClassWithPublicInstanceMethod.new
804
+ example_jps = [
805
+ Aquarium::Aspects::JoinPoint.new(:type => ClassWithPublicInstanceMethod, :method => :public_instance_test_method),
806
+ Aquarium::Aspects::JoinPoint.new(:object => anClassWithPublicInstanceMethod, :method => :public_instance_test_method)]
807
+ pc = Aquarium::Aspects::Pointcut.new :join_points => example_jps
808
+ pc.candidate_join_points.matched.size.should == 2
809
+ pc.candidate_join_points.matched[example_jps[0]].should_not be_nil
810
+ pc.candidate_join_points.matched[example_jps[1]].should_not be_nil
811
+ pc.candidate_join_points.not_matched.size.should == 0
812
+ end
813
+ end
814
+
815
+ describe Aquarium::Aspects::Pointcut, "#specification" do
734
816
  setup do
735
817
  common_setup
736
818
  @expected_specification_subset = {
@@ -741,15 +823,15 @@ describe "Aquarium::Aspects::Pointcut#specification" do
741
823
 
742
824
  it "should return ':attribute_options => []', by default, if no arguments are given." do
743
825
  pc = Aquarium::Aspects::Pointcut.new
744
- pc.specification.should == { :types => @empty_set, :objects => @empty_set, :default_object => @empty_set,
745
- :methods => Set.new([:all]), :method_options => Set.new([]),
826
+ pc.specification.should == { :types => @empty_set, :objects => @empty_set, :join_points => @empty_set,
827
+ :methods => Set.new([:all]), :method_options => Set.new([]), :default_object => @empty_set,
746
828
  :attributes => @empty_set, :attribute_options => @empty_set }
747
829
  end
748
830
 
749
831
  it "should return the input :types and :type arguments combined into an array keyed by :types." do
750
832
  pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :type => String
751
- pc.specification.should == { :types => Set.new(@example_types + [String]), :objects => @empty_set, :default_object => @empty_set,
752
- :methods => Set.new([:all]), :method_options => Set.new([]),
833
+ pc.specification.should == { :types => Set.new(@example_types + [String]), :objects => @empty_set, :join_points => @empty_set,
834
+ :methods => Set.new([:all]), :method_options => Set.new([]), :default_object => @empty_set,
753
835
  :attributes => @empty_set, :attribute_options => @empty_set }
754
836
  end
755
837
 
@@ -757,36 +839,36 @@ describe "Aquarium::Aspects::Pointcut#specification" do
757
839
  example_objs = @example_types.map {|t| t.new}
758
840
  s1234 = "1234"
759
841
  pc = Aquarium::Aspects::Pointcut.new :objects => example_objs, :object => s1234
760
- pc.specification.should == { :types => @empty_set, :objects => Set.new(example_objs + [s1234]), :default_object => @empty_set,
761
- :methods => Set.new([:all]), :method_options => Set.new([]),
842
+ pc.specification.should == { :types => @empty_set, :objects => Set.new(example_objs + [s1234]), :join_points => @empty_set,
843
+ :methods => Set.new([:all]), :method_options => Set.new([]), :default_object => @empty_set,
762
844
  :attributes => @empty_set, :attribute_options => @empty_set }
763
845
  end
764
846
 
765
847
  it "should return the input :methods and :method arguments combined into an array keyed by :methods." do
766
848
  pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :methods => /^get/, :method => "dup"
767
- pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :default_object => @empty_set,
768
- :methods => Set.new([/^get/, "dup"]), :method_options => Set.new([]),
849
+ pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :join_points => @empty_set,
850
+ :methods => Set.new([/^get/, "dup"]), :method_options => Set.new([]), :default_object => @empty_set,
769
851
  :attributes => @empty_set, :attribute_options => @empty_set }
770
852
  end
771
853
 
772
854
  it "should return the input :method_options verbatim." do
773
855
  pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :methods => /^get/, :method => "dup", :method_options => [:instance, :public]
774
- pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :default_object => @empty_set,
775
- :methods => Set.new([/^get/, "dup"]), :method_options => Set.new([:instance, :public]),
856
+ pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :join_points => @empty_set,
857
+ :methods => Set.new([/^get/, "dup"]), :method_options => Set.new([:instance, :public]), :default_object => @empty_set,
776
858
  :attributes => @empty_set, :attribute_options => @empty_set }
777
859
  end
778
860
 
779
861
  it "should return the input :methods and :method arguments combined into an array keyed by :methods." do
780
862
  pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :attributes => /^state/, :attribute => "name"
781
- pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :default_object => @empty_set,
782
- :methods => @empty_set, :method_options => Set.new([]),
863
+ pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :join_points => @empty_set,
864
+ :methods => @empty_set, :method_options => Set.new([]), :default_object => @empty_set,
783
865
  :attributes => Set.new([/^state/, "name"]), :attribute_options => @empty_set }
784
866
  end
785
867
 
786
868
  it "should return the input :attributes, :attribute and :attribute_options arguments, verbatim." do
787
869
  pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :attributes => /^state/, :attribute => "name", :attribute_options => :reader
788
- pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :default_object => @empty_set,
789
- :methods => @empty_set, :method_options => Set.new([]),
870
+ pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :join_points => @empty_set,
871
+ :methods => @empty_set, :method_options => Set.new([]), :default_object => @empty_set,
790
872
  :attributes => Set.new([/^state/, "name"]), :attribute_options => Set.new([:reader]) }
791
873
  end
792
874
  end
@@ -51,9 +51,11 @@ describe Aquarium::Extras::DesignByContract, "invariant" do
51
51
  end
52
52
  attr_reader :invar
53
53
  def good_action
54
+ "good"
54
55
  end
55
56
  def bad_action
56
57
  @invar = 1
58
+ "bad"
57
59
  end
58
60
 
59
61
  invariant :methods => /action$/, :message => "Must not change the @invar value." do |jp, *args|
@@ -68,4 +70,8 @@ describe Aquarium::Extras::DesignByContract, "invariant" do
68
70
  it "should add advice that does not raise if the invariant is satisfied" do
69
71
  InvarCond.new.good_action
70
72
  end
73
+
74
+ it "should return the value returned by the checked method when the invariant is satisfied" do
75
+ InvarCond.new.good_action.should == "good"
76
+ end
71
77
  end
@@ -11,13 +11,13 @@ describe Aquarium::Finders::TypeFinder, "#find" do
11
11
  lambda { Aquarium::Finders::TypeFinder.new.find "foo" }.should raise_error(Aquarium::Utils::InvalidOptions)
12
12
  end
13
13
 
14
- it "should return no matched and no unmatched expressions by default (i.e., the input is empty)." do
14
+ it "should return no matched types and no unmatched type expressions by default (i.e., the input is empty)." do
15
15
  actual = Aquarium::Finders::TypeFinder.new.find
16
16
  actual.matched.should == {}
17
17
  actual.not_matched.should == {}
18
18
  end
19
19
 
20
- it "should return no matched and no unmatched expressions if the input hash is empty." do
20
+ it "should return no matched types and no unmatched type expressions if the input hash is empty." do
21
21
  actual = Aquarium::Finders::TypeFinder.new.find {}
22
22
  actual.matched.should == {}
23
23
  actual.not_matched.should == {}
@@ -61,17 +61,25 @@ end
61
61
 
62
62
  class Outside
63
63
  class Inside1; end
64
- class Inside2; end
64
+ class Inside2
65
+ class ReallyInside; end
66
+ end
65
67
  end
66
68
 
67
69
  describe Aquarium::Finders::TypeFinder, "#find with :type or :name used to specify a single type" do
68
- it "should find a type matching a simple name (without :: namespace delimiters) using its name." do
70
+ it "should find a type matching a simple name (without :: namespace delimiters) using its name and the :type option." do
69
71
  actual = Aquarium::Finders::TypeFinder.new.find :type => :Object
70
72
  actual.matched_keys.should == [Object]
71
73
  actual.not_matched.should == {}
72
74
  end
73
75
 
74
- it "should return an empty match for a simple name (without :: namespace delimiters) that doesn't match an existing class." do
76
+ it "should find a type matching a simple name (without :: namespace delimiters) using its name and the :name option." do
77
+ actual = Aquarium::Finders::TypeFinder.new.find :name => :Object
78
+ actual.matched_keys.should == [Object]
79
+ actual.not_matched.should == {}
80
+ end
81
+
82
+ it "should return an empty match for a simple name (without :: namespace delimiters) that doesn't match an existing type." do
75
83
  actual = Aquarium::Finders::TypeFinder.new.find :name => :Unknown
76
84
  actual.matched.should == {}
77
85
  actual.not_matched_keys.should == [:Unknown]
@@ -84,7 +92,7 @@ describe Aquarium::Finders::TypeFinder, "#find with :type or :name used to speci
84
92
  end
85
93
  end
86
94
 
87
- describe Aquarium::Finders::TypeFinder, "#find with :types, :names, :type, and :name used to specify one or more names and/or regular expressions" do
95
+ describe Aquarium::Finders::TypeFinder, "#find with :types, :names, :type, and :name used to specify one or more names" do
88
96
  it "should find types matching simple names (without :: namespace delimiters) using their names." do
89
97
  expected_found_types = [Class, Kernel, Module, Object]
90
98
  expected_unfound_exps = %w[TestCase Unknown1 Unknown2]
@@ -92,30 +100,61 @@ describe Aquarium::Finders::TypeFinder, "#find with :types, :names, :type, and :
92
100
  actual.matched_keys.sort.should == expected_found_types.sort
93
101
  actual.not_matched_keys.should == expected_unfound_exps
94
102
  end
103
+
104
+ it "should find types with :: namespace delimiters using their names." do
105
+ expected_found_types = [Outside::Inside1, Outside::Inside2]
106
+ expected_unfound_exps = %w[Foo::Bar::Baz]
107
+ actual = Aquarium::Finders::TypeFinder.new.find :names => (expected_found_types.map {|t| t.to_s} + expected_unfound_exps)
108
+ actual.matched_keys.sort_by {|x| x.to_s}.should == expected_found_types.sort_by {|x| x.to_s}
109
+ actual.not_matched_keys.sort.should == expected_unfound_exps.sort
110
+ end
111
+ end
95
112
 
113
+ describe Aquarium::Finders::TypeFinder, "#find with :types, :names, :type, and :name used to specify one or more regular expressions" do
96
114
  it "should find types matching simple names (without :: namespace delimiters) using lists of regular expressions." do
97
115
  expected_found_types = [Class, Kernel, Module, Object]
98
116
  expected_unfound_exps = [/Unknown2/, /^.*TestCase.*$/, /^Unknown1/]
99
- actual = Aquarium::Finders::TypeFinder.new.find :types => [/K.+l/, /^Mod.+e$/, /^Object$/, /Clas{2}/, /^.*TestCase.*$/, /^Unknown1/, /Unknown2/]
117
+ actual = Aquarium::Finders::TypeFinder.new.find :types => [/K.+l/, /^Mod.+e$/, /^Object$/, /^Clas{2}$/, /^.*TestCase.*$/, /^Unknown1/, /Unknown2/]
100
118
  actual.matched_keys.sort_by {|x| x.to_s}.should == expected_found_types.sort_by {|x| x.to_s}
101
119
  actual.not_matched_keys.sort.should == expected_unfound_exps.sort
102
120
  end
103
121
 
104
- it "should find types with :: namespace delimiters using their names." do
105
- expected_found_types = [Outside::Inside1, Outside::Inside2]
106
- expected_unfound_exps = %w[Foo::Bar::Baz]
107
- actual = Aquarium::Finders::TypeFinder.new.find :names => (expected_found_types.map {|t| t.to_s} + expected_unfound_exps)
122
+ it "should find types matching simple names (without :: namespace delimiters) using regular expressions that match parts of the names." do
123
+ expected_found_types = [FalseClass, Module, TrueClass]
124
+ expected_unfound_exps = []
125
+ actual = Aquarium::Finders::TypeFinder.new.find :types => [/eClass$/, /^Modu/]
108
126
  actual.matched_keys.sort_by {|x| x.to_s}.should == expected_found_types.sort_by {|x| x.to_s}
109
127
  actual.not_matched_keys.sort.should == expected_unfound_exps.sort
110
128
  end
111
129
 
112
130
  it "should find types with :: namespace delimiters using lists of regular expressions." do
113
- expected_found_types = [Outside::Inside1, Outside::Inside2]
131
+ expected_found_types = [Outside::Inside1, Outside::Inside2, Outside::Inside2::ReallyInside]
114
132
  expected_unfound_exps = [/^.*Fo+::.*Bar+::Baz.$/]
115
- actual = Aquarium::Finders::TypeFinder.new.find :types => [/^.*Fo+::.*Bar+::Baz.$/, /Outside::.*1$/, "Out.*::In.*2"]
133
+ actual = Aquarium::Finders::TypeFinder.new.find :types => [/^.*Fo+::.*Bar+::Baz.$/, /Outside::.*1$/, /Out.*::In.*2/, /Out.*::In.*2::R.*/]
116
134
  actual.matched_keys.sort_by {|x| x.to_s}.should == expected_found_types.sort_by {|x| x.to_s}
117
135
  actual.not_matched_keys.should == expected_unfound_exps
118
136
  end
137
+
138
+ it "should allow a partial trailing name before the first :: namespace delimiter in a regular expression." do
139
+ expected_found_types = [Outside::Inside1, Outside::Inside2]
140
+ actual = Aquarium::Finders::TypeFinder.new.find :types => [/side::In.*/]
141
+ actual.matched_keys.sort_by {|x| x.to_s}.should == expected_found_types.sort_by {|x| x.to_s}
142
+ actual.not_matched_keys.size.should == 0
143
+ end
144
+
145
+ it "should allow a partial leading name after the last :: namespace delimiter in a regular expression." do
146
+ expected_found_types = [Outside::Inside1, Outside::Inside2, Outside::Inside2::ReallyInside]
147
+ actual = Aquarium::Finders::TypeFinder.new.find :types => [/side::In/, /side::Inside2::Real/]
148
+ actual.matched_keys.sort_by {|x| x.to_s}.should == expected_found_types.sort_by {|x| x.to_s}
149
+ actual.not_matched_keys.size.should == 0
150
+ end
151
+
152
+ it "should require a full name-matching regular expression between :: namespace delimiters." do
153
+ expected_found_types = [Outside::Inside2::ReallyInside]
154
+ actual = Aquarium::Finders::TypeFinder.new.find :types => [/side::In::Real/]
155
+ actual.matched_keys.size.should == 0
156
+ actual.not_matched_keys.should == [/side::In::Real/]
157
+ end
119
158
  end
120
159
 
121
160
  describe Aquarium::Finders::TypeFinder, "#find" do
@@ -131,7 +170,7 @@ describe Aquarium::Finders::TypeFinder, "#find_all_by" do
131
170
  it "should find types with :: namespace delimiters using lists of regular expressions." do
132
171
  expected_found_types = [Outside::Inside1, Outside::Inside2]
133
172
  expected_unfound_exps = [/^.*Fo+::.*Bar+::Baz.$/]
134
- actual = Aquarium::Finders::TypeFinder.new.find_all_by [/^.*Fo+::.*Bar+::Baz.$/, /Outside::.*1$/, "Out.*::In.*2"]
173
+ actual = Aquarium::Finders::TypeFinder.new.find_all_by [/^.*Fo+::.*Bar+::Baz.$/, /Outside::.*1$/, /Out.*::In.*2/]
135
174
  actual.matched_keys.sort_by {|x| x.to_s}.should == expected_found_types.sort_by {|x| x.to_s}
136
175
  actual.not_matched_keys.should == expected_unfound_exps
137
176
  end
@@ -206,5 +245,12 @@ describe Aquarium::Finders::TypeFinder, "#find_by_type" do
206
245
  actual.not_matched_keys.should == []
207
246
  end
208
247
  end
248
+
249
+ # TODO refactor this protected method into a new class.
250
+ describe Aquarium::Finders::TypeFinder, "#get_type_from_parent should" do
251
+ it "should raise if a type doesn't exist that matches the constant" do
252
+ lambda {Aquarium::Finders::TypeFinder.new.send(:get_type_from_parent, Aquarium::Finders, "Nonexistent", /Non/)}.should raise_error(NameError)
253
+ end
254
+ end
209
255
 
210
256