spec/aquarium/aspects/aspect_invocation_spec.rb in aquarium-0.4.1 vs spec/aquarium/aspects/aspect_invocation_spec.rb in aquarium-0.4.2

- old
+ new

@@ -1,15 +1,18 @@ require File.dirname(__FILE__) + '/../spec_helper' require File.dirname(__FILE__) + '/../spec_example_types' +require File.dirname(__FILE__) + '/../utils/type_utils_sample_nested_types' require 'aquarium/aspects/aspect' -require 'aquarium/aspects/dsl' +require 'aquarium/dsl' require 'aquarium/utils/array_utils' +require File.dirname(__FILE__) + '/../finders/pointcut_finder_spec_test_classes' require 'profiler' include Aquarium::Aspects include Aquarium::Utils::ArrayUtils +include Aquarium::PointcutFinderTestClasses def aspects_should_be_equal num_jps, aspect1, aspect2 # We don't use @aspect1.should eql(@aspect2) because the "specifications" are different. aspect1.pointcuts.size.should == 1 @@ -130,22 +133,22 @@ end it "should reject the :exceptions argument unless specified with :after_raising." do lambda { Aspect.new :before, :after, :exceptions => [Exception, String], :pointcut => @pointcut_opts, :noop => true }.should raise_error(Aquarium::Utils::InvalidOptions) end -end + end describe Aspect, ".new (parameters that specify pointcuts)" do before :all do @pointcut_opts = {:type => Aquarium::AspectInvocationTestClass} end - it "should contain at least one of :method(s), :pointcut(s), :type(s), or :object(s)." do + it "should contain at least one of :method(s), :pointcut(s), :named_pointcut(s), :type(s), or :object(s)." do lambda {Aspect.new(:after, :ignore_no_matching_join_points => true) {true}}.should raise_error(Aquarium::Utils::InvalidOptions) end - it "should contain at least one of :pointcut(s), :type(s), or :object(s) unless :default_objects => object is given." do + it "should contain at least one of :pointcut(s), :named_pointcut(s), :type(s), or :object(s) unless :default_objects => object is given." do aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass.new, :method => :public_test_method, :noop => true) {true} end it "should ignore the :default_objects if at least one other :object is given and the :default_objects are objects." do object1 = Aquarium::AspectInvocationTestClass.new @@ -161,19 +164,19 @@ :object => object, :method => :public_test_method) {true} aspect.join_points_matched.size.should == 1 aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass} end - it "should ignore the :default_objects if at least one :pointcut is given and the :default_objects are objects." do + it "should ignore the :default_objects if at least one :pointcut is given even if the :default_objects => object are given." do object = Aquarium::AspectInvocationTestClass.new aspect = Aspect.new(:after, :default_objects => object, :pointcut => {:type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method}, :method => :public_test_method) {true} aspect.join_points_matched.size.should == 1 aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object} end - it "should ignore the :default_objects if at least one :pointcut is given and the :default_objects are types." do + it "should ignore the :default_objects if at least one :pointcut is given even if the :default_objects => type are given." do aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, :pointcut => {:type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method}, :method => :public_test_method) {true} aspect.join_points_matched.size.should == 1 aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass} end @@ -191,11 +194,11 @@ aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, :join_point => join_point, :method => :public_test_method) {true} aspect.join_points_matched.size.should == 1 aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass} end - [:type, :type_and_descendents, :type_and_ancestors].each do |type_key| + [:type, :type_and_descendents, :type_and_ancestors, :type_and_nested_types].each do |type_key| it "should ignore the :default_objects if at least one :#{type_key} is given and the :default_objects are objects." do object = Aquarium::AspectInvocationTestClass.new aspect = Aspect.new(:after, :default_objects => object, type_key => Aquarium::AspectInvocationTestClass2, :method => :public_test_method, :method => :public_test_method) {true} aspect.join_points_matched.size.should == 1 aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object} @@ -218,11 +221,41 @@ lambda {Aspect.new(:after, :pointcuts => @pointcut_opts, :type => Aquarium::AspectInvocationTestClass, :method => :public_test_method) {true}}.should raise_error(Aquarium::Utils::InvalidOptions) lambda {Aspect.new(:after, :pointcuts => @pointcut_opts, :object => Aquarium::AspectInvocationTestClass.new, :method => :public_test_method) {true}}.should raise_error(Aquarium::Utils::InvalidOptions) end end + describe Aspect, ".new (parameters that specify named constant and/or class variable pointcuts)" do + it "should contain at least one :types or TypeFinder synonym for :types." do + lambda {Aspect.new(:after, :named_pointcuts => {}, :noop => true) {true}}.should raise_error(Aquarium::Utils::InvalidOptions) + lambda {Aspect.new(:after, :named_pointcuts => {:types => all_pointcut_classes}, :noop => true) {true}}.should_not raise_error(Aquarium::Utils::InvalidOptions) + end + it "should ignore the :default_objects if at least one :named_pointcut is given even if the :default_objects => object are given." do + object = Aquarium::AspectInvocationTestClass.new + aspect = Aspect.new(:after, :default_objects => object, :named_pointcut => {:types => Aquarium::PointcutFinderTestClasses::PointcutClassVariableHolder1}) {true} + aspect.join_points_matched.size.should == 1 + aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object} + end + + it "should ignore the :default_objects if at least one :named_pointcut is given even if the :default_objects => type are given." do + aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, :named_pointcut => {:types => Aquarium::PointcutFinderTestClasses::PointcutClassVariableHolder1}) {true} + aspect.join_points_matched.size.should == 1 + aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass} + end + + Aspect::CANONICAL_OPTIONS["named_pointcuts"].each do |key| + it "should accept :#{key} as a synonym for :named_pointcuts." do + lambda { Aspect.new :before, key.intern => {:types => Aquarium::PointcutFinderTestClasses.all_pointcut_classes}, :noop => true do; end }.should_not raise_error + end + end + + it "should not contain :named_pointcut(s) and either :type(s) or :object(s)." do + lambda {Aspect.new(:after, :named_pointcuts => {:types => Aquarium::PointcutFinderTestClasses::PointcutClassVariableHolder1}, :type => Aquarium::AspectInvocationTestClass, :method => :public_test_method) {true}}.should raise_error(Aquarium::Utils::InvalidOptions) + lambda {Aspect.new(:after, :named_pointcuts => {:types => Aquarium::PointcutFinderTestClasses::PointcutClassVariableHolder1}, :object => Aquarium::AspectInvocationTestClass.new, :method => :public_test_method) {true}}.should raise_error(Aquarium::Utils::InvalidOptions) + end + end + describe Aspect, ".new with :types parameter" do it "should advise the specified types." do @advice_called = false aspect = Aspect.new :before, :types => Aquarium::AspectInvocationTestClass, :method => :public_test_method do; @advice_called = true; end Aquarium::AspectInvocationTestClass.new.public_test_method @@ -460,10 +493,31 @@ @type_spec = /Aquarium::AspectInvocationTestClass/ @method_spec = [:public_test_method] do_type_spec end + it "should accept :type(s)_and_nested_types => T1, :methods => [m, ...]" do + @types_option = :types_and_nested_types + @type_spec = Aquarium::AspectInvocationTestClass + @method_spec = [:public_test_method] + do_type_spec + end + + it "should accept :type(s)_and_nested_types => [T1, ...], :methods => [m, ...]" do + @types_option = :types_and_nested_types + @type_spec = [Aquarium::AspectInvocationTestClass] + @method_spec = [:public_test_method] + do_type_spec + end + + it "should accept :type(s)_and_nested_types => /T1/, :methods => [m, ...]" do + @types_option = :types_and_nested_types + @type_spec = /Aquarium::AspectInvocationTestClass/ + @method_spec = [:public_test_method] + do_type_spec + end + it "should accept :type(s) => ..., :methods => ..., :method_options => [:exclude_ancestor_methods] to exclude methods defined in ancestors" do @type_spec = /Aquarium::AspectInvocationTestClass/ @method_spec = /test_method/ @method_options = [:exclude_ancestor_methods] do_type_spec @@ -883,10 +937,15 @@ it "should accept {:type(s)_and_descendents => [T1, ...], :methods => /m/} " do @pointcut_hash = {:type_and_descendents => [Aquarium::AspectInvocationTestClass], :methods => /test_method/} do_type_pointcut_spec end + it "should accept {:type(s)_and_nested_types => [T1, ...], :methods => /m/} " do + @pointcut_hash = {:type_and_nested_types => [Aquarium::AspectInvocationTestClass], :methods => /test_method/} + do_type_pointcut_spec + end + it "should accept {:type(s) => T1, :methods => [m, ...]} " do @pointcut_hash = {:type => Aquarium::AspectInvocationTestClass, :methods => [:public_test_method]} do_type_pointcut_spec end @@ -908,10 +967,15 @@ it "should accept {:type(s)_and_descendents => T1, :methods => /m/} " do @pointcut_hash = {:type_and_descendents => Aquarium::AspectInvocationTestClass, :methods => /test_method/} do_type_pointcut_spec end + it "should accept {:type(s)_and_nested_types => T1, :methods => /m/} " do + @pointcut_hash = {:type_and_nested_types => Aquarium::AspectInvocationTestClass, :methods => /test_method/} + do_type_pointcut_spec + end + it "should accept {:type(s) => /T1/, :methods => [m, ...]} " do @pointcut_hash = {:type => /Aquarium::AspectInvocationTestClass/, :methods => [:public_test_method]} do_type_pointcut_spec end @@ -933,10 +997,15 @@ it "should accept {:type(s)_and_descendents => /T1/, :methods => /m/} " do @pointcut_hash = {:type_and_descendents => /Aquarium::AspectInvocationTestClass/, :methods => /test_method/} do_type_pointcut_spec end + it "should accept {:type(s)_and_nested_types => /T1/, :methods => /m/} " do + @pointcut_hash = {:type_and_nested_types => /Aquarium::AspectInvocationTestClass/, :methods => /test_method/} + do_type_pointcut_spec + end + %w[public protected private].each do |protection| it "should accept {:type(s) => T1, :methods => /m/, :method_options =>[:instance, #{protection}]} " do @protection = protection @pointcut_hash = {:type => Aquarium::AspectInvocationTestClass, :methods => /test_method/, :method_options =>[:instance, protection.intern]} do_type_pointcut_spec @@ -1151,10 +1220,30 @@ pointcut = Aquarium::Aspects::Pointcut.new :type_and_descendents => Aquarium::AspectInvocationTestClass, :method => :public_test_method @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice aspects_should_be_equal 1, @aspect1, @aspect2 end + it "should advise equivalent join points when :type_and_nested_types => T and :method => m is used or :pointcut =>{:type_and_nested_types => T, :method => m} is used." do + @aspect1 = Aspect.new :after, :type_and_nested_types => Aquarium::AspectInvocationTestClass, :method => :public_test_method, &@advice + @aspect2 = Aspect.new :after, :pointcut => {:type_and_nested_types => Aquarium::AspectInvocationTestClass, :method => :public_test_method}, &@advice + aspects_should_be_equal 1, @aspect1, @aspect2 + end + + it "should advise equivalent join points when :type_and_nested_types => T and :method => m is used or :pointcut => pointcut is used, where pointcut matches :type_and_nested_types => T and :method => m." do + @aspect1 = Aspect.new :after, :type_and_nested_types => Aquarium::AspectInvocationTestClass, :method => :public_test_method, &@advice + pointcut = Aquarium::Aspects::Pointcut.new :type_and_nested_types => Aquarium::AspectInvocationTestClass, :method => :public_test_method + @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice + aspects_should_be_equal 1, @aspect1, @aspect2 + end + + it "should advise equivalent join points when :pointcut =>{:type_and_nested_types => T, :method => m} is used or :pointcut => pointcut is used, where pointcut matches :type_and_nested_types => T and :method => m." do + @aspect1 = Aspect.new :after, :pointcut => {:type_and_nested_types => Aquarium::AspectInvocationTestClass, :method => :public_test_method}, &@advice + pointcut = Aquarium::Aspects::Pointcut.new :type_and_nested_types => Aquarium::AspectInvocationTestClass, :method => :public_test_method + @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice + aspects_should_be_equal 1, @aspect1, @aspect2 + end + end describe Aspect, ".new (with a :type(s) parameter and an :attributes(s) parameter or one of several equivalent :pointcut parameters)" do class ClassWithAttrib1 def dummy; end @@ -1405,11 +1494,11 @@ lambda { Aspect.new :before, :type => Aquarium::AspectInvocationTestClass, :methods => :public_test_method, :noop => true do; end }.should_not raise_error(Exception) end end describe Aspect, ".new (advice block to around advice with just the join_point parameter - Bug #19262)" do - it "should work not raise an error" do + it "should not raise an error" do aspect = Aspect.new :around, :type => Aquarium::AspectInvocationTestClass, :methods => :public_test_method do |jp|; jp.proceed; end Aquarium::AspectInvocationTestClass.new.public_test_method aspect.unadvise end end @@ -1437,11 +1526,11 @@ class Exclude1c < Exclude1 def initialize arg; super(arg); end def doit3; end end - describe Aspect, ".new (with a :type(s) parameter and an :exclude_type(s), and :exclude_type(s)_and_ancestors, or an :exclude_type(s)_and_descendents parameter)" do + describe Aspect, ".new (with a :type(s) parameter and an :exclude_type(s), and :exclude_type(s)_and_ancestors, an :exclude_type(s)_and_descendents, or an :exclude_type(s)_and_nested_types parameter)" do before :all do @included_types = [DontExclude1, DontExclude2] @excluded_types = [Exclude1, Exclude2] @all_types = @included_types + @excluded_types end @@ -1494,10 +1583,20 @@ it "should accept :#{key} as a synonym for :exclude_types_and_descendents." do lambda { Aspect.new :before, :types => @all_types, key.intern => @excluded_types, :methods => :doit, :noop => true do; end }.should_not raise_error end end + it "should accept :type(s) => [T1, ...], :exclude_types_and_nested_types => [T2, ...] and exclude join points in the excluded types" do + do_exclude_types :exclude_types_and_nested_types + end + + Aspect::CANONICAL_OPTIONS["exclude_types_and_nested_types"].each do |key| + it "should accept :#{key} as a synonym for :exclude_types_and_nested_types." do + lambda { Aspect.new :before, :types => @all_types, key.intern => @excluded_types, :methods => :doit, :noop => true do; end }.should_not raise_error + end + end + end describe Aspect, ".new (with a :object(s) parameter and an :exclude_object(s) parameter)" do before :all do @@ -1648,10 +1747,31 @@ advice_called.should be_false aspect.unadvise end end + describe Aspect, ".new (with a :type(s)_and_nested_types parameter and an :exclude_join_point(s) parameter)" do + it "should accept :type(s)_and_nested_types => [T1, ...], :exclude_join_point(s) => [jps], where [jps] are the list of join points for the types and methods to exclude" do + included_types = [ClassWithPublicInstanceMethod, ModuleWithPublicInstanceMethod] + excluded_join_point1 = JoinPoint.new :type => ClassWithPublicInstanceMethod, :method => :public_instance_test_method + excluded_join_point2 = JoinPoint.new :type => ModuleWithPublicInstanceMethod, :method => :public_instance_module_test_method + excluded_join_points = [excluded_join_point1, excluded_join_point2] + aspect = nil + advice_called = false + aspect = Aspect.new :before, :types_and_nested_types => included_types, :methods => :doit, + :exclude_join_points => excluded_join_points, :ignore_no_matching_join_points => true do |jp, obj, *args|; advice_called = true; end + + advice_called = false + ClassWithPublicInstanceMethod.new.public_instance_test_method + advice_called.should be_false + advice_called = false + ClassIncludingModuleWithPublicInstanceMethod.new.public_instance_module_test_method + advice_called.should be_false + aspect.unadvise + end + end + describe Aspect, ".new (with a :pointcut(s) parameter and an :exclude_join_point(s) parameter)" do it "should accept :pointcut(s) => [P1, ...], :exclude_join_point(s) => [jps], where [jps] are the list of join points for the types and methods to exclude" do included_types = [DontExclude1, DontExclude2] excluded_types = [Exclude1, Exclude2] excluded_join_point1 = JoinPoint.new :type => Exclude1, :method => :doit @@ -1714,11 +1834,11 @@ aspect.unadvise end Aspect::CANONICAL_OPTIONS["exclude_pointcuts"].each do |key| it "should accept :#{key} as a synonym for :exclude_pointcuts." do - lambda {aspect = Aspect.new :before, :objects => @all_objects, :exclude_pointcuts => @excluded_pointcuts, :methods => :doit, :noop => true do; end}.should_not raise_error + lambda {aspect = Aspect.new :before, :objects => @all_objects, key.intern => @excluded_pointcuts, :methods => :doit, :noop => true do; end}.should_not raise_error end end end describe Aspect, ".new (with a :type(s) and an :exclude_pointcut(s) parameter)" do @@ -1785,91 +1905,180 @@ end aspect.unadvise end end - describe Aspect, ".new (with type-based :pointcut(s) and :exclude_type(s) parameter)" do - it "should accept :pointcut(s) => [P1, ...], :exclude_type(s) => [types], where join points with [types] are excluded" do - included_types = [DontExclude1, DontExclude2] - excluded_types = [Exclude1, Exclude2] - pointcut1 = Pointcut.new :types => included_types, :method => :doit - pointcut2 = Pointcut.new :types => excluded_types, :method => :doit + describe Aspect, ".new (with a :pointcut(s) and an :exclude_named_pointcut(s) parameter)" do + it "should accept :pointcut(s) => [P1, ...], :exclude_named_pointcut(s) => {...}, where any pointcuts matching the latter are excluded" do aspect = nil advice_called = false - aspect = Aspect.new :before, :pointcuts => [pointcut1, pointcut2], :exclude_types => excluded_types do |jp, obj, *args| + aspect = Aspect.new :before, :pointcuts => Aquarium::PointcutFinderTestClasses.all_pointcuts, + :exclude_named_pointcuts => {:matching => /POINTCUT/, :in_types => Aquarium::PointcutFinderTestClasses.all_pointcut_classes} do |jp, obj, *args| advice_called = true - excluded_types.should_not include(jp.target_type) + Aquarium::PointcutFinderTestClasses.all_constants_pointcut_classes.should_not include(jp.target_type) end + Aquarium::PointcutFinderTestClasses.all_class_variables_pointcut_classes.each do |type| + advice_called = false + type.new.doit + advice_called.should be_true + end + Aquarium::PointcutFinderTestClasses.all_constants_pointcut_classes.each do |type| + advice_called = false + type.new.doit + advice_called.should_not be_true + end + aspect.unadvise + end - included_types.each do |type| + Aspect::CANONICAL_OPTIONS["exclude_named_pointcuts"].each do |key| + it "should accept :#{key} as a synonym for :exclude_named_pointcuts." do + lambda {aspect = Aspect.new :before, :pointcuts => Aquarium::PointcutFinderTestClasses.all_pointcuts, + key.intern => {:matching => /POINTCUT/, :in_types => Aquarium::PointcutFinderTestClasses.all_pointcut_classes}, + :noop => true do; end}.should_not raise_error + end + end + end + + describe Aspect, ".new (with type-based :pointcut(s) and :exclude_type(s) parameter)" do + before :all do + @included_types = [DontExclude1, DontExclude2] + @excluded_types = [Exclude1, Exclude2] + @pointcut1 = Pointcut.new :types => @included_types, :method => :doit + @pointcut2 = Pointcut.new :types => @excluded_types, :method => :doit + end + + it "should accept :pointcut(s) => [P1, ...], :exclude_type(s) => [types], where join points with [types] are excluded" do + advice_called = false + aspect = Aspect.new :before, :pointcuts => [@pointcut1, @pointcut2], :exclude_types => @excluded_types do |jp, obj, *args| + advice_called = true + @excluded_types.should_not include(jp.target_type) + end + + @included_types.each do |type| advice_called = false type.new(1).doit advice_called.should be_true end - excluded_types.each do |type| + @excluded_types.each do |type| advice_called = false type.new(1).doit advice_called.should_not be_true end aspect.unadvise end + + Aspect::CANONICAL_OPTIONS["exclude_types"].each do |key| + it "should accept :#{key} as a synonym for :exclude_types." do + lambda {aspect = Aspect.new :before, :pointcuts => [@pointcut1, @pointcut2], key.intern => @excluded_types, + :noop => true do; end}.should_not raise_error + end + end end describe Aspect, ".new (with type-based :pointcut(s) and :exclude_type(s)_and_ancestors parameter)" do + before :all do + @excluded_types = [ClassWithPublicInstanceMethod, ModuleWithPublicInstanceMethod] + @types = @excluded_types + [ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod] + @pointcut1 = Pointcut.new :types => @types, :method => :all, :method_options => [:exclude_ancestor_methods] + end + it "should accept :pointcut(s) => [P1, ...], :exclude_type(s)_and_ancestors => [types], where join points with [types] are excluded" do - excluded_types = [ClassWithPublicInstanceMethod, ModuleWithPublicInstanceMethod] - types = excluded_types + [ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod] - pointcut1 = Pointcut.new :types => types, :method => :all, :method_options => [:exclude_ancestor_methods] - advice_called = false - aspect = Aspect.new :before, :pointcuts => pointcut1, :exclude_types_and_ancestors => excluded_types do |jp, obj, *args|; end + aspect = Aspect.new :before, :pointcuts => @pointcut1, :exclude_types_and_ancestors => @excluded_types do |jp, obj, *args|; end aspect.pointcuts.each do |pc| pc.join_points_matched.each do |jp| jp.target_type.should == ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod end end aspect.unadvise end + + Aspect::CANONICAL_OPTIONS["exclude_types_and_ancestors"].each do |key| + it "should accept :#{key} as a synonym for :exclude_types_and_ancestors." do + lambda {aspect = Aspect.new :before, :pointcuts => @pointcut1, key.intern => @excluded_types, + :noop => true do; end}.should_not raise_error + end + end end describe Aspect, ".new (with type-based :pointcut(s) and :exclude_type(s)_and_descendents parameter)" do + before :all do + @excluded_types = [ClassWithPublicInstanceMethod, ModuleWithPublicInstanceMethod] + @types = @excluded_types + [ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod] + @pointcut1 = Pointcut.new :types => @types, :method => :all, :method_options => [:exclude_ancestor_methods] + end it "should accept :pointcut(s) => [P1, ...], :exclude_type(s)_and_descendents => [types], where join points with [types] are excluded" do - excluded_types = [ClassWithPublicInstanceMethod, ModuleWithPublicInstanceMethod] - types = excluded_types + [ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod] - pointcut1 = Pointcut.new :types => types, :method => :all, :method_options => [:exclude_ancestor_methods] - advice_called = false - aspect = Aspect.new :before, :pointcuts => pointcut1, :exclude_types_and_descendents => excluded_types, :ignore_no_matching_join_points => true do |jp, obj, *args|; end + aspect = Aspect.new :before, :pointcuts => @pointcut1, :exclude_types_and_descendents => @excluded_types, + :ignore_no_matching_join_points => true do |jp, obj, *args|; end aspect.pointcuts.size.should == 0 aspect.unadvise end + + Aspect::CANONICAL_OPTIONS["exclude_types_and_descendents"].each do |key| + it "should accept :#{key} as a synonym for :exclude_types_and_descendents." do + lambda {aspect = Aspect.new :before, :pointcuts => @pointcut1, key.intern => @excluded_types, + :ignore_no_matching_join_points => true, :noop => true do; end}.should_not raise_error + end + end end - describe Aspect, ".new (with object-based :pointcut(s) and :exclude_object(s) or :exclude_method(s) parameter)" do + describe Aspect, ".new (with type-based :pointcut(s) and :exclude_type(s)_and_nested_types parameter)" do + before :all do + @excluded_types = [ClassWithPublicInstanceMethod, ModuleWithPublicInstanceMethod] + @types = @excluded_types + [ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod] + @pointcut1 = Pointcut.new :types => @types, :method => :all, :method_options => [:exclude_ancestor_methods] + end + it "should accept :pointcut(s) => [P1, ...], :exclude_type(s)_and_nested_types => [types], where join points with [types] are excluded" do + aspect = Aspect.new :before, :pointcuts => @pointcut1, :exclude_types_and_nested_types => @excluded_types, + :ignore_no_matching_join_points => true do |jp, obj, *args|; end + aspect.pointcuts.size.should == 1 + aspect.unadvise + end + + Aspect::CANONICAL_OPTIONS["exclude_types_and_nested_types"].each do |key| + it "should accept :#{key} as a synonym for :exclude_types_and_nested_types." do + lambda {aspect = Aspect.new :before, :pointcuts => @pointcut1, key.intern => @excluded_types, + :ignore_no_matching_join_points => true, :noop => true do; end}.should_not raise_error + end + end + end + + describe Aspect, ".new (with object-based :pointcut(s) and :exclude_object(s) parameter)" do + before :all do + @dontExclude1 = DontExclude1.new(1) + @dontExclude2 = DontExclude1.new(2) + @exclude1 = DontExclude1.new(3) + @exclude2 = DontExclude1.new(4) + @included_objects = [@dontExclude1, @dontExclude2] + @excluded_objects = [@exclude1, @exclude2] + @pointcut1 = Pointcut.new :objects => @included_objects, :method => :doit + @pointcut2 = Pointcut.new :objects => @excluded_objects, :method => :doit + end + it "should accept :pointcut(s) => [P1, ...], :exclude_object(s) => [objects], where join points with [objects] are excluded" do - dontExclude1 = DontExclude1.new(1) - dontExclude2 = DontExclude1.new(2) - exclude1 = DontExclude1.new(3) - exclude2 = DontExclude1.new(4) - included_objects = [dontExclude1, dontExclude2] - excluded_objects = [exclude1, exclude2] - pointcut1 = Pointcut.new :objects => included_objects, :method => :doit - pointcut2 = Pointcut.new :objects => excluded_objects, :method => :doit aspect = nil advice_called = false - aspect = Aspect.new :before, :pointcuts => [pointcut1, pointcut2], :exclude_objects => excluded_objects do |jp, obj, *args| + aspect = Aspect.new :before, :pointcuts => [@pointcut1, @pointcut2], :exclude_objects => @excluded_objects do |jp, obj, *args| advice_called = true - excluded_objects.should_not include(obj) + @excluded_objects.should_not include(obj) end - included_objects.each do |object| + @included_objects.each do |object| advice_called = false object.doit advice_called.should be_true end - excluded_objects.each do |object| + @excluded_objects.each do |object| advice_called = false object.doit advice_called.should_not be_true end aspect.unadvise + end + + Aspect::CANONICAL_OPTIONS["exclude_objects"].each do |key| + it "should accept :#{key} as a synonym for :exclude_objects." do + lambda {aspect = Aspect.new :before, :pointcuts => [@pointcut1, @pointcut2], key.intern => @excluded_objects, + :noop => true do; end}.should_not raise_error + end end end describe Aspect, ".new (with :method(s) and :exclude_method(s) parameter)" do before :each do \ No newline at end of file