C0 code coverage information

Generated on Sun Oct 26 11:18:04 -0500 2008 with rcov 0.8.1.2


Code reported as executed by Ruby looks like this...
and this: this line is also marked as covered.
Lines considered as run by rcov, but not reported by Ruby, look like this,
and this: these lines were inferred by rcov (using simple heuristics).
Finally, here's a line marked as not executed.
Name Total lines Lines of code Total coverage Code coverage
spec/aquarium/aspects/aspect_invocation_spec.rb 2198 1883
100.0% 
100.0% 
   1 require File.dirname(__FILE__) + '/../spec_helper'
   2 require 'aquarium/spec_example_types'
   3 require 'aquarium/utils/type_utils_sample_nested_types'
   4 require 'aquarium/aspects/aspect'
   5 require 'aquarium/dsl'
   6 require 'aquarium/utils/array_utils'
   7 require 'aquarium/finders/pointcut_finder_spec_test_classes'
   8 
   9 require 'profiler'
  10 
  11 include Aquarium::Aspects
  12 include Aquarium::Utils::ArrayUtils
  13 include Aquarium::PointcutFinderTestClasses 
  14 
  15 
  16 def aspects_should_be_equal num_jps, aspect1, aspect2
  17   # We don't use @aspect1.should eql(@aspect2) because the "specifications" are different.
  18   aspect1.pointcuts.size.should == 1
  19   aspect2.pointcuts.size.should == 1
  20   aspect1.pointcuts.should eql(aspect2.pointcuts)
  21   aspect1.advice.should eql(@advice)
  22   aspect2.advice.should eql(@advice)
  23   join_points_should_be_equal num_jps, aspect1, aspect2
  24 end
  25 
  26 def join_points_should_be_equal num_jps, aspect1, aspect2
  27   aspect1.join_points_matched.size.should == num_jps
  28   aspect2.join_points_matched.size.should == num_jps
  29   aspect1.join_points_matched.each {|jp| @expected_methods.should include(jp.method_name)}
  30   aspect2.join_points_matched.each {|jp| @expected_methods.should include(jp.method_name)}
  31   aspect1.join_points_matched.should eql(aspect2.join_points_matched)
  32   aspect1.join_points_not_matched.should eql(aspect2.join_points_not_matched)
  33 end
  34 
  35 module Aquarium
  36   class AspectInvocationTestClass
  37     include Aquarium::DSL
  38     attr_accessor :public_test_method_args
  39     def public_test_method *args; @args=args; end
  40     protected
  41     def protected_test_method *args; @args=args; end
  42     private
  43     def private_test_method *args; @args=args; end
  44     def self.public_class_test_method *args; end
  45     def self.private_class_test_method *args; end
  46     private_class_method :private_class_test_method
  47   end
  48   class AspectInvocationTestClass2
  49     include Aquarium::DSL
  50     attr_accessor :public_test_method_args
  51     def public_test_method *args; @args=args; end
  52   end
  53   class AspectInvocationTestClass3
  54     attr_accessor :public_test_method_args
  55     attr_accessor :public_test_method_args2
  56     def public_test_method *args; @args=args; end
  57   end
  58 end
  59 
  60 describe Aspect, "methods" do
  61   include Aquarium::TypeUtilsStub
  62   
  63   before :all do
  64     stub_type_utils_descendents
  65   end
  66   after :all do
  67     unstub_type_utils_descendents
  68   end
  69     
  70   describe Aspect, ".new (the :ignore_no_matching_join_points parameter that specifies whether or not to warn about no join point matches)" do
  71     before :each do
  72       @log_stream = StringIO.new
  73     end
  74   
  75     it "should warn about no join point matches if the :ignore_no_matching_join_points is not specified." do
  76       lambda {Aspect.new(:after, :logger_stream => @log_stream) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
  77       @log_stream.string.should_not be_empty
  78     end
  79     it "should warn about no join point matches if :ignore_no_matching_join_points => false is specified." do
  80       lambda {Aspect.new(:after, :logger_stream => @log_stream, :ignore_no_matching_join_points => false) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
  81       @log_stream.string.should_not be_empty
  82     end
  83     it "should not warn about no join point matches if :ignore_no_matching_join_points => true is specified." do
  84       lambda {Aspect.new(:after, :logger_stream => @log_stream, :ignore_no_matching_join_points => true) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
  85       @log_stream.string.should be_empty
  86     end
  87   end
  88 
  89   describe Aspect, ".new (parameters that specify the kind of advice)" do
  90     before :all do
  91       @pointcut_opts = {:type => Aquarium::AspectInvocationTestClass}
  92     end
  93     
  94     it "should require the kind of advice as the first parameter." do
  95       lambda { Aspect.new :pointcut => @pointcut_opts }.should raise_error(Aquarium::Utils::InvalidOptions)
  96     end
  97 
  98     it "should contain no other advice types if :around advice specified." do
  99       lambda { Aspect.new :around, :before,          :pointcut => @pointcut_opts }.should raise_error(Aquarium::Utils::InvalidOptions)
 100       lambda { Aspect.new :around, :after,           :pointcut => @pointcut_opts }.should raise_error(Aquarium::Utils::InvalidOptions)
 101       lambda { Aspect.new :around, :after_returning, :pointcut => @pointcut_opts }.should raise_error(Aquarium::Utils::InvalidOptions)
 102       lambda { Aspect.new :around, :after_raising,   :pointcut => @pointcut_opts }.should raise_error(Aquarium::Utils::InvalidOptions)
 103     end
 104 
 105     it "should allow only one of :after, :after_returning, or :after_raising advice to be specified." do
 106       lambda { Aspect.new :after, :after_returning, :pointcut => @pointcut_opts }.should raise_error(Aquarium::Utils::InvalidOptions)
 107       lambda { Aspect.new :after, :after_raising,   :pointcut => @pointcut_opts }.should raise_error(Aquarium::Utils::InvalidOptions)
 108       lambda { Aspect.new :after_returning, :after_raising, :pointcut => @pointcut_opts }.should raise_error(Aquarium::Utils::InvalidOptions)
 109     end
 110 
 111     it "should allow :before to be specified with :after." do
 112       lambda { Aspect.new :before, :after, :pointcut => @pointcut_opts, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
 113     end
 114 
 115     it "should allow :before to be specified with :after_returning." do
 116       lambda { Aspect.new :before, :after_returning, :pointcut => @pointcut_opts, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
 117     end
 118 
 119     it "should allow :before to be specified with :after_raising." do
 120       lambda { Aspect.new :before, :after_raising,   :pointcut => @pointcut_opts, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
 121     end
 122 
 123     it "should accept a single exception specified with :after_raising." do
 124       lambda { Aspect.new :before, :after_raising => Exception, :pointcut => @pointcut_opts, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
 125     end
 126   
 127     it "should accept a list of exceptions specified with :after_raising." do
 128       lambda { Aspect.new :before, :after_raising => [Exception, String], :pointcut => @pointcut_opts, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
 129     end
 130 
 131     it "should accept a separate :exceptions => list of exceptions specified with :after_raising." do
 132       lambda { Aspect.new :before, :after_raising, :exceptions => [Exception, String], :pointcut => @pointcut_opts, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
 133     end
 134 
 135     it "should reject the :exceptions argument unless specified with :after_raising." do
 136       lambda { Aspect.new :before, :after, :exceptions => [Exception, String], :pointcut => @pointcut_opts, :noop => true }.should raise_error(Aquarium::Utils::InvalidOptions)
 137     end
 138   end
 139 
 140   describe Aspect, ".new (parameters that specify pointcuts)" do
 141     before :all do
 142       @pointcut_opts = {:type => Aquarium::AspectInvocationTestClass}
 143     end
 144     
 145     it "should contain at least one of :method(s), :pointcut(s), :named_pointcut(s), :type(s), or :object(s)." do
 146       lambda {Aspect.new(:after, :ignore_no_matching_join_points => true) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
 147     end
 148 
 149     it "should contain at least one of :pointcut(s), :named_pointcut(s), :type(s), or :object(s) unless :default_objects => object is given." do
 150       aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass.new, :method => :public_test_method, :noop => true) {true}
 151     end
 152 
 153     it "should ignore the :default_objects if at least one other :object is given and the :default_objects are objects." do
 154       object1 = Aquarium::AspectInvocationTestClass.new
 155       object2 = Aquarium::AspectInvocationTestClass2.new
 156       aspect = Aspect.new(:after, :default_objects => object1, :object => object2, :method => :public_test_method) {true}
 157       aspect.join_points_matched.size.should == 1
 158       aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object1}
 159     end
 160 
 161     it "should ignore the :default_objects if at least one other :object is given and the :default_objects are types." do
 162       object = Aquarium::AspectInvocationTestClass2.new
 163       aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, 
 164         :object => object, :method => :public_test_method) {true}
 165       aspect.join_points_matched.size.should == 1
 166       aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass}
 167     end
 168 
 169     it "should ignore the :default_objects if at least one :pointcut is given even if the :default_objects => object are given." do
 170       object = Aquarium::AspectInvocationTestClass.new
 171       aspect = Aspect.new(:after, :default_objects => object, 
 172         :pointcut => {:type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method}, :method => :public_test_method) {true}
 173       aspect.join_points_matched.size.should == 1
 174       aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object}
 175     end
 176 
 177     it "should ignore the :default_objects if at least one :pointcut is given even if the :default_objects => type are given." do
 178       aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, 
 179         :pointcut => {:type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method}, :method => :public_test_method) {true}
 180       aspect.join_points_matched.size.should == 1
 181       aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass}
 182     end
 183 
 184     it "should ignore the :default_objects if at least one :join_point is given and the :default_objects are objects." do
 185       join_point = JoinPoint.new :type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method
 186       object = Aquarium::AspectInvocationTestClass.new
 187       aspect = Aspect.new(:after, :default_objects => object, :join_point => join_point, :method => :public_test_method) {true}
 188       aspect.join_points_matched.size.should == 1
 189       aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object}
 190     end
 191 
 192     it "should ignore the :default_objects if at least one :join_point is given and the :default_objects are types." do
 193       join_point = JoinPoint.new :type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method
 194       aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, :join_point => join_point, :method => :public_test_method) {true}
 195       aspect.join_points_matched.size.should == 1
 196       aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass}
 197     end
 198 
 199     [:type, :type_and_descendents, :type_and_ancestors, :type_and_nested_types].each do |type_key|
 200       it "should ignore the :default_objects if at least one :#{type_key} is given and the :default_objects are objects." do
 201         object = Aquarium::AspectInvocationTestClass.new
 202         aspect = Aspect.new(:after, :default_objects => object, type_key => Aquarium::AspectInvocationTestClass2, :method => :public_test_method, :method => :public_test_method) {true}
 203         aspect.join_points_matched.size.should == 1
 204         aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object}
 205       end
 206 
 207       it "should ignore the :default_objects if at least one :#{type_key} is given and the :default_objects are types." do
 208         aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, type_key => Aquarium::AspectInvocationTestClass2, :method => :public_test_method, :method => :public_test_method) {true}
 209         aspect.join_points_matched.size.should == 1
 210         aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass}
 211       end
 212     end
 213 
 214     Aspect::CANONICAL_OPTIONS["default_objects"].each do |key|
 215       it "should accept :#{key} as a synonym for :default_objects." do
 216         aspect = Aspect.new(:after, key.intern => Aquarium::AspectInvocationTestClass.new, :method => :public_test_method, :noop => true) {true}
 217       end
 218     end
 219   
 220     it "should not contain :pointcut(s) and either :type(s) or :object(s)." do
 221       lambda {Aspect.new(:after, :pointcuts => @pointcut_opts, :type => Aquarium::AspectInvocationTestClass, :method => :public_test_method) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
 222       lambda {Aspect.new(:after, :pointcuts => @pointcut_opts, :object => Aquarium::AspectInvocationTestClass.new, :method => :public_test_method) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
 223     end
 224   end
 225 
 226   describe Aspect, ".new (parameters that specify named constant and/or class variable pointcuts)" do
 227     it "should contain at least one :types or TypeFinder synonym for :types." do
 228       lambda {Aspect.new(:after, :named_pointcuts => {}, :noop => true) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
 229       lambda {Aspect.new(:after, :named_pointcuts => {:types => all_pointcut_classes}, :noop => true) {true}}.should_not raise_error(Aquarium::Utils::InvalidOptions)
 230     end
 231 
 232     it "should ignore the :default_objects if at least one :named_pointcut is given even if the :default_objects => object are given." do
 233       object = Aquarium::AspectInvocationTestClass.new
 234       aspect = Aspect.new(:after, :default_objects => object, :named_pointcut => {:types => Aquarium::PointcutFinderTestClasses::PointcutClassVariableHolder1}) {true}
 235       aspect.join_points_matched.size.should == 1
 236       aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object}
 237     end
 238 
 239     it "should ignore the :default_objects if at least one :named_pointcut is given even if the :default_objects => type are given." do
 240       aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, :named_pointcut => {:types => Aquarium::PointcutFinderTestClasses::PointcutClassVariableHolder1}) {true}
 241       aspect.join_points_matched.size.should == 1
 242       aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass}
 243     end
 244 
 245     Aspect::CANONICAL_OPTIONS["named_pointcuts"].each do |key|
 246       it "should accept :#{key} as a synonym for :named_pointcuts." do
 247         lambda { Aspect.new :before, key.intern => {:types => Aquarium::PointcutFinderTestClasses.all_pointcut_classes}, :noop => true do; end }.should_not raise_error
 248       end
 249     end
 250 
 251     it "should not contain :named_pointcut(s) and either :type(s) or :object(s)." do
 252       lambda {Aspect.new(:after, :named_pointcuts => {:types => Aquarium::PointcutFinderTestClasses::PointcutClassVariableHolder1}, :type => Aquarium::AspectInvocationTestClass, :method => :public_test_method) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
 253       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)
 254     end
 255   end
 256   
 257   describe Aspect, ".new with :types parameter" do
 258     it "should advise the specified types." do
 259       @advice_called = false
 260       aspect = Aspect.new :before, :types => Aquarium::AspectInvocationTestClass, :method => :public_test_method do; @advice_called = true; end
 261       Aquarium::AspectInvocationTestClass.new.public_test_method
 262       aspect.unadvise
 263       @advice_called.should be_true
 264     end
 265 
 266     Aspect::CANONICAL_OPTIONS["types"].each do |key|
 267       it "should accept :#{key} as a synonym for :types." do
 268         lambda { Aspect.new :before, key.intern => Aquarium::AspectInvocationTestClass, :method => :public_test_method, :noop => true do; end }.should_not raise_error
 269       end
 270     end
 271   end
 272 
 273   describe Aspect, ".new with :pointcuts parameter" do
 274     it "should advise the specified pointcuts." do
 275       @advice_called = false
 276       aspect = Aspect.new :before, :pointcuts => {:types => Aquarium::AspectInvocationTestClass, :method => :public_test_method} do; @advice_called = true; end
 277       Aquarium::AspectInvocationTestClass.new.public_test_method
 278       aspect.unadvise
 279       @advice_called.should be_true
 280     end
 281 
 282     Aspect::CANONICAL_OPTIONS["pointcuts"].each do |key|
 283       it "should accept :#{key} as a synonym for :pointcuts." do
 284         lambda { Aspect.new :before, key.intern => {:type => Aquarium::AspectInvocationTestClass, :method => :public_test_method}, :noop => true do; end }.should_not raise_error
 285       end
 286     end
 287   end
 288 
 289   describe Aspect, ".new with :objects parameter" do
 290     it "should advise the specified objects." do
 291       @advice_called = false
 292       object = Aquarium::AspectInvocationTestClass.new
 293       aspect = Aspect.new :before, :objects => object, :method => :public_test_method do; @advice_called = true; end
 294       object.public_test_method
 295       aspect.unadvise
 296       @advice_called.should be_true
 297     end
 298 
 299     Aspect::CANONICAL_OPTIONS["objects"].each do |key|
 300       it "should accept :#{key} as a synonym for :objects." do
 301         object = Aquarium::AspectInvocationTestClass.new
 302         lambda { Aspect.new :before, key.intern => object, :method => :public_test_method, :noop => true do; end }.should_not raise_error
 303       end
 304     end
 305   end
 306 
 307   describe Aspect, ".new with :methods parameter" do
 308     it "should advise the specified methods." do
 309       @advice_called = false
 310       aspect = Aspect.new :before, :types => Aquarium::AspectInvocationTestClass, :methods => :public_test_method do; @advice_called = true; end
 311       Aquarium::AspectInvocationTestClass.new.public_test_method
 312       aspect.unadvise
 313       @advice_called.should be_true
 314     end
 315 
 316     Aspect::CANONICAL_OPTIONS["methods"].each do |key|
 317       it "should accept :#{key} as a synonym for :methods." do
 318         lambda { Aspect.new :before, :type => Aquarium::AspectInvocationTestClass, key.intern => :public_test_method, :noop => true do; end }.should_not raise_error
 319       end
 320     end
 321   end
 322 
 323   describe Aspect, ".new (:attributes parameter)" do
 324     Aspect::CANONICAL_OPTIONS["attributes"].each do |key|
 325       it "should accept :#{key} as a synonym for :attributes." do
 326         @advice_called = false
 327         aspect = Aspect.new :before, :types => Aquarium::AspectInvocationTestClass, :attributes => :public_test_method_args do; @advice_called = true; end
 328         Aquarium::AspectInvocationTestClass.new.public_test_method_args
 329         aspect.unadvise
 330       end
 331     end
 332 
 333     it "should require the values for :reading => ... and :writing => ... to be equal if both are specified." do
 334       @advice = Proc.new {}
 335       lambda {Aspect.new :before, :type => Aquarium::AspectInvocationTestClass3, 
 336         :reading => :public_test_method_args, :writing => :public_test_method_args2, :advice => @advice}.should raise_error(Aquarium::Utils::InvalidOptions)
 337     end
 338 
 339     it "should require the values for :reading => ... and :changing => ... to be equal if both are specified." do
 340       @advice = Proc.new {}
 341       lambda {Aspect.new :before, :type => Aquarium::AspectInvocationTestClass3, 
 342         :reading => :public_test_method_args, :changing => :public_test_method_args2, :advice => @advice}.should raise_error(Aquarium::Utils::InvalidOptions)
 343     end
 344 
 345     it "should accept :reading => ... as a synonym for :attributes => ..., :attribute_options => [:readers]." do
 346       @advice = Proc.new {}
 347       @expected_methods = [:public_test_method_args]
 348       aspect1 = Aspect.new :before, :type => Aquarium::AspectInvocationTestClass, :reading    => :public_test_method_args, :advice => @advice
 349       aspect2 = Aspect.new :before, :type => Aquarium::AspectInvocationTestClass, :attributes => :public_test_method_args, :attribute_options => [:readers], :advice => @advice
 350       aspects_should_be_equal 1, aspect1, aspect2
 351       aspect1.unadvise
 352       aspect2.unadvise
 353     end
 354 
 355     it "should accept :writing => ... as a synonym for :attributes => ..., :attribute_options => [:writer]." do
 356       @advice = Proc.new {}
 357       @expected_methods = [:public_test_method_args=]
 358       aspect1 = Aspect.new :before, :type => Aquarium::AspectInvocationTestClass, :writing    => :public_test_method_args, :advice => @advice
 359       aspect2 = Aspect.new :before, :type => Aquarium::AspectInvocationTestClass, :attributes => :public_test_method_args, :attribute_options => [:writers], :advice => @advice
 360       aspects_should_be_equal 1, aspect1, aspect2
 361       aspect1.unadvise
 362       aspect2.unadvise
 363     end
 364 
 365     it "should accept :changing => ... as a synonym for :attributes => ..., :attribute_options => [:writer]." do
 366       @advice = Proc.new {}
 367       @expected_methods = [:public_test_method_args=]
 368       aspect1 = Aspect.new :before, :type => Aquarium::AspectInvocationTestClass, :changing   => :public_test_method_args, :advice => @advice
 369       aspect2 = Aspect.new :before, :type => Aquarium::AspectInvocationTestClass, :attributes => :public_test_method_args, :attribute_options => [:writers], :advice => @advice
 370       aspects_should_be_equal 1, aspect1, aspect2
 371       aspect1.unadvise
 372       aspect2.unadvise
 373     end
 374   end
 375 
 376   describe Aspect, ".new (with a :type(s) parameter and a :method(s) parameter)" do  
 377     before :each do
 378       @protection = 'public'
 379       @are_class_methods = false
 380       @types_option = :types
 381       @method_options = []
 382     end
 383   
 384     def do_type_spec
 385       aspect = nil
 386       advice_called = false
 387       aspect = Aspect.new :before, @types_option => @type_spec, :methods => @method_spec, :method_options => @method_options do |jp, obj, *args|
 388         advice_called = true
 389         jp.should_not be_nil
 390         args.size.should == 4
 391         args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 392       end 
 393       if @are_class_methods
 394         Aquarium::AspectInvocationTestClass.method("#{@protection}_class_test_method").call :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
 395       else
 396         Aquarium::AspectInvocationTestClass.new.method("#{@protection}_test_method").call :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
 397       end
 398       advice_called.should be_true
 399       aspect.unadvise
 400     end
 401 
 402     it "should accept :type(s) => T1, :methods => m" do  
 403       @type_spec = Aquarium::AspectInvocationTestClass
 404       @method_spec = :public_test_method
 405       do_type_spec
 406     end
 407 
 408     it "should accept :type(s) => T1, :methods => [m, ...]" do  
 409       @type_spec = Aquarium::AspectInvocationTestClass
 410       @method_spec = [:public_test_method]
 411       do_type_spec
 412     end
 413 
 414     it "should accept :type(s) => T1, :methods => /m/" do  
 415       @type_spec = Aquarium::AspectInvocationTestClass
 416       @method_spec = /test_method/
 417       do_type_spec
 418     end
 419 
 420     it "should accept :type(s) => [T1, ...], :methods => m" do  
 421       @type_spec = [Aquarium::AspectInvocationTestClass]
 422       @method_spec = :public_test_method
 423       do_type_spec
 424     end
 425 
 426     it "should accept :type(s) => [T1, ...], :methods => [m, ...]" do  
 427       @type_spec = [Aquarium::AspectInvocationTestClass]
 428       @method_spec = [:public_test_method]
 429       do_type_spec
 430     end
 431 
 432     it "should accept :type(s) => [T1, ...], :methods => /m/" do  
 433       @type_spec = [Aquarium::AspectInvocationTestClass]
 434       @method_spec = /test_method/
 435       do_type_spec
 436     end
 437 
 438     it "should accept :type(s) => /T1/, :methods => m" do  
 439       @type_spec = /Aquarium::AspectInvocationTestClass/
 440       @method_spec = :public_test_method
 441       do_type_spec
 442     end
 443 
 444     it "should accept :type(s) => /T1/, :methods => [m, ...]" do  
 445       @type_spec = /Aquarium::AspectInvocationTestClass/
 446       @method_spec = [:public_test_method]
 447       do_type_spec
 448     end
 449 
 450     it "should accept :type(s) => /T1/, :methods => /m/" do  
 451       @type_spec = /Aquarium::AspectInvocationTestClass/
 452       @method_spec = /test_method/
 453       do_type_spec
 454     end
 455 
 456     it "should accept :type(s)_and_ancestors => T1, :methods => [m, ...]" do  
 457       @types_option = :types_and_ancestors
 458       @type_spec = Aquarium::AspectInvocationTestClass
 459       @method_spec = [:public_test_method]
 460       do_type_spec
 461     end
 462 
 463     it "should accept :type(s)_and_ancestors => [T1, ...], :methods => [m, ...]" do  
 464       @types_option = :types_and_ancestors
 465       @type_spec = [Aquarium::AspectInvocationTestClass]
 466       @method_spec = [:public_test_method]
 467       do_type_spec
 468     end
 469 
 470     it "should accept :type(s)_and_ancestors => /T1/, :methods => [m, ...]" do  
 471       @types_option = :types_and_ancestors
 472       @type_spec = /Aquarium::AspectInvocationTestClass/
 473       @method_spec = [:public_test_method]
 474       do_type_spec
 475     end
 476 
 477     it "should accept :type(s)_and_descendents => T1, :methods => [m, ...]" do  
 478       @types_option = :types_and_descendents
 479       @type_spec = Aquarium::AspectInvocationTestClass
 480       @method_spec = [:public_test_method]
 481       do_type_spec
 482     end
 483 
 484     it "should accept :type(s)_and_descendents => [T1, ...], :methods => [m, ...]" do  
 485       @types_option = :types_and_descendents
 486       @type_spec = [Aquarium::AspectInvocationTestClass]
 487       @method_spec = [:public_test_method]
 488       do_type_spec
 489     end
 490 
 491     it "should accept :type(s)_and_descendents => /T1/, :methods => [m, ...]" do  
 492       @types_option = :types_and_descendents
 493       @type_spec = /Aquarium::AspectInvocationTestClass/
 494       @method_spec = [:public_test_method]
 495       do_type_spec
 496     end
 497 
 498     it "should accept :type(s)_and_nested_types => T1, :methods => [m, ...]" do  
 499       @types_option = :types_and_nested_types
 500       @type_spec = Aquarium::AspectInvocationTestClass
 501       @method_spec = [:public_test_method]
 502       do_type_spec
 503     end
 504 
 505     it "should accept :type(s)_and_nested_types => [T1, ...], :methods => [m, ...]" do  
 506       @types_option = :types_and_nested_types
 507       @type_spec = [Aquarium::AspectInvocationTestClass]
 508       @method_spec = [:public_test_method]
 509       do_type_spec
 510     end
 511 
 512     it "should accept :type(s)_and_nested_types => /T1/, :methods => [m, ...]" do  
 513       @types_option = :types_and_nested_types
 514       @type_spec = /Aquarium::AspectInvocationTestClass/
 515       @method_spec = [:public_test_method]
 516       do_type_spec
 517     end
 518 
 519     it "should accept :type(s) => ..., :methods => ..., :method_options => [:exclude_ancestor_methods] to exclude methods defined in ancestors" do  
 520       @type_spec = /Aquarium::AspectInvocationTestClass/
 521       @method_spec = /test_method/
 522       @method_options = [:exclude_ancestor_methods]
 523       do_type_spec
 524     end
 525 
 526     it "should accept :type(s) => ..., :methods => ..., :method_options => [:instance, :public] to match only instance and public (both are the defaults) methods" do  
 527       @type_spec = /Aquarium::AspectInvocationTestClass/
 528       @method_spec = /test_method/
 529       @method_options = [:instance, :public]
 530       do_type_spec
 531     end
 532 
 533     %w[public protected private].each do |protection|
 534       it "should accept :type(s) => ..., :methods => ..., :method_options => [#{protection.intern}] to match only instance (default) #{protection} methods" do  
 535         @type_spec = /Aquarium::AspectInvocationTestClass/
 536         @method_spec = /test_method/
 537         @method_options = [protection.intern]
 538         @protection = protection
 539         do_type_spec
 540       end
 541     end
 542 
 543     it "should accept :type(s) => ..., :methods => ..., :method_options => [:class] to match only public (default) class methods" do  
 544       @type_spec = /Aquarium::AspectInvocationTestClass/
 545       @method_spec = /test_method/
 546       @method_options = [:class]
 547       @are_class_methods = true
 548       do_type_spec
 549     end
 550 
 551     %w[public private].each do |protection|
 552       it "should accept :type(s) => ..., :methods => ..., :method_options => [:class, :#{protection.intern}] to match only class #{protection} methods" do  
 553         @type_spec = /Aquarium::AspectInvocationTestClass/
 554         @method_spec = /test_method/
 555         @method_options = [:class, protection.intern]
 556         @protection = protection
 557         @are_class_methods = true
 558         do_type_spec
 559       end
 560     end
 561   end
 562 
 563 
 564   describe Aspect, ".new (with a :type(s) parameter and a :attribute(s) parameter)" do  
 565     before :each do
 566       @protection = 'public'
 567       @attribute_options = []
 568       @are_class_methods = false
 569     end
 570   
 571     def do_type_attribute_spec
 572       aspect = nil
 573       advice_called = false
 574       aspect = Aspect.new :before, :types => @type_spec, :attributes => @attribute_spec, :attribute_options => @attribute_options do |jp, obj, *args|
 575         advice_called = true
 576         jp.should_not be_nil
 577         expected_args = make_array(@expected_args)
 578         args.should == expected_args
 579         args.size.should == expected_args.size
 580       end 
 581       object = Aquarium::AspectInvocationTestClass.new
 582       @expected_args = nil
 583       object.method("#{@protection}_test_method_args".intern).call 
 584       @expected_args = :a1
 585       object.method("#{@protection}_test_method_args=".intern).call @expected_args
 586       advice_called.should be_true
 587       aspect.unadvise
 588     end
 589 
 590     it "should accept :type(s) => [T1, ...], :attribute(s) => [a, ...]" do  
 591       @type_spec = [Aquarium::AspectInvocationTestClass]
 592       @attribute_spec = [:public_test_method_args]
 593       do_type_attribute_spec
 594     end
 595 
 596     it "should accept :type(s) => [T1, ...], :attribute(s) => a" do  
 597       @type_spec = [Aquarium::AspectInvocationTestClass]
 598       @attribute_spec = :public_test_method_args
 599       do_type_attribute_spec
 600     end
 601 
 602     it "should accept :type(s) => [T1, ...], :attribute(s) => /a/" do  
 603       @type_spec = [Aquarium::AspectInvocationTestClass]
 604       @attribute_spec = /test_method_args/
 605       do_type_attribute_spec
 606     end
 607 
 608     it "should accept :type(s) => T1, :attribute(s) => [a]" do  
 609       @type_spec = Aquarium::AspectInvocationTestClass
 610       @attribute_spec = [:public_test_method_args]
 611       do_type_attribute_spec
 612     end
 613 
 614     it "should accept :type(s) => T1, :attribute(s) => a" do  
 615       @type_spec = Aquarium::AspectInvocationTestClass
 616       @attribute_spec = :public_test_method_args
 617       do_type_attribute_spec
 618     end
 619 
 620     it "should accept :type(s) => T1, :attribute(s) => /a/" do  
 621       @type_spec = Aquarium::AspectInvocationTestClass
 622       @attribute_spec = /test_method_args/
 623       do_type_attribute_spec
 624     end
 625 
 626     it "should accept :type(s) => /T1/, :attribute(s) => [a, ...]" do  
 627       @type_spec = /Aquarium::AspectInvocationTestClass/
 628       @attribute_spec = [:public_test_method_args]
 629       do_type_attribute_spec
 630     end
 631 
 632     it "should accept :type(s) => /T1/, :attribute(s) => a" do  
 633       @type_spec = /Aquarium::AspectInvocationTestClass/
 634       @attribute_spec = :public_test_method_args
 635       do_type_attribute_spec
 636     end
 637 
 638     it "should accept :type(s) => /T1/, :attribute(s) => a" do  
 639       @type_spec = /Aquarium::AspectInvocationTestClass/
 640       @attribute_spec = /test_method_args/
 641       do_type_attribute_spec
 642     end
 643 
 644     it "should accept :type(s) => ..., :attributes => ..., :attribute_options => [:readers, :writers] to include both attribute reader and writer methods (default)" do  
 645       @type_spec = /Aquarium::AspectInvocationTestClass/
 646       @attribute_spec = /test_method_args/
 647       @attribute_options = [:readers, :writers]
 648       do_type_attribute_spec
 649     end
 650 
 651     it "should accept :type(s) => ..., :attributes => ..., :attribute_options => [:readers] to include only attribute reader methods" do  
 652       @type_spec = /Aquarium::AspectInvocationTestClass/
 653       @attribute_spec = /test_method_args/
 654       @attribute_options = [:readers]
 655       do_type_attribute_spec
 656     end
 657 
 658     it "should accept attribute option :reader as a synonym for :readers" do
 659       @type_spec = /Aquarium::AspectInvocationTestClass/
 660       @attribute_spec = /test_method_args/
 661       @attribute_options = [:reader]
 662       do_type_attribute_spec
 663     end
 664 
 665     it "should accept :type(s) => ..., :attributes => ..., :attribute_options => [:writers] to include only attribute writer methods" do  
 666       @type_spec = /Aquarium::AspectInvocationTestClass/
 667       @attribute_spec = /test_method_args/
 668       @attribute_options = [:writers]
 669       do_type_attribute_spec
 670     end
 671 
 672     it "should accept attribute option :writer as a synonym for :writers" do
 673       @type_spec = /Aquarium::AspectInvocationTestClass/
 674       @attribute_spec = /test_method_args/
 675       @attribute_options = [:writer]
 676       do_type_attribute_spec
 677     end
 678 
 679     it "should accept :type(s) => ..., :attributes => ..., :attribute_options => [:class, :readers, :writers] to include both attribute reader and writer methods (default) for class methods" do  
 680       @type_spec = /Aquarium::AspectInvocationTestClass/
 681       @attribute_spec = /test_method_args/
 682       @attribute_options = [:class, :readers, :writers]
 683       do_type_attribute_spec
 684     end
 685 
 686     it "should accept :type(s) => ..., :attributes => ..., :attribute_options => [:class, :readers] to include only attribute reader class methods" do  
 687       @type_spec = /Aquarium::AspectInvocationTestClass/
 688       @attribute_spec = /test_method_args/
 689       @attribute_options = [:class, :readers]
 690       do_type_attribute_spec
 691     end
 692 
 693     it "should accept :type(s) => ..., :attributes => ..., :attribute_options => [:class, :writers] to include only attribute writer class methods" do  
 694       @type_spec = /Aquarium::AspectInvocationTestClass/
 695       @attribute_spec = /test_method_args/
 696       @attribute_options = [:class, :writers]
 697       do_type_attribute_spec
 698     end
 699   end
 700 
 701   describe Aspect, ".new (with a :object(s) parameter and a :method(s) parameter)" do  
 702     before :each do
 703       @object1 = Aquarium::AspectInvocationTestClass.new
 704       @object2 = Aquarium::AspectInvocationTestClass.new
 705       @protection = 'public'
 706       @method_options = []
 707     end
 708   
 709     def do_object_spec
 710       aspect = nil
 711       advice_called = false
 712       aspect = Aspect.new :before, :objects => @object_spec, :methods => @method_spec, :method_options => @method_options do |jp, obj, *args|
 713         advice_called = true
 714         jp.should_not be_nil
 715         args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 716       end 
 717       make_array(@object_spec).each do |object|
 718         object.method("#{@protection}_test_method".intern).call :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
 719       end
 720       advice_called.should be_true
 721       aspect.unadvise
 722     end
 723 
 724     it "should accept :object(s) => [o1, ...], :methods => [m, ...]" do  
 725       @object_spec = [@object1, @object2]
 726       @method_spec = [:public_test_method]
 727       do_object_spec
 728     end
 729 
 730     it "should accept :object(s) => [o1, ...], :methods => m" do  
 731       @object_spec = [@object1, @object2]
 732       @method_spec = :public_test_method
 733       do_object_spec
 734     end
 735 
 736     it "should accept :object(s) => [o1, ...], :methods => /m/" do  
 737       @object_spec = [@object1, @object2]
 738       @method_spec = /test_method/
 739       do_object_spec
 740     end
 741 
 742     it "should accept :object(s) => o1, :methods => [m, ...]" do  
 743       @object_spec = @object1
 744       @method_spec = [:public_test_method]
 745       do_object_spec
 746     end
 747 
 748     it "should accept :object(s) => o1, :methods => m" do  
 749       @object_spec = @object1
 750       @method_spec = :public_test_method
 751       do_object_spec
 752     end
 753 
 754     it "should accept :object(s) => o1, :methods => /m/" do  
 755       @object_spec = @object1
 756       @method_spec = /test_method/
 757       do_object_spec
 758     end
 759 
 760     it "should accept :object(s) => ..., :methods => ..., :method_options => [:exclude_ancestor_methods] to exclude methods defined in ancestors" do  
 761       @object_spec = @object1
 762       @method_spec = /test_method/
 763       @method_options = [:exclude_ancestor_methods]
 764       do_object_spec
 765     end
 766 
 767     it "should accept :object(s) => ..., :methods => ..., :method_options => [:instance, :public] to match only instance and public (both are the defaults) methods" do  
 768       @object_spec = @object1
 769       @method_spec = /test_method/
 770       @method_options = [:instance, :public]
 771       do_object_spec
 772     end
 773 
 774     %w[public protected private].each do |protection|
 775       it "should accept :object(s) => ..., :methods => ..., :method_options => [#{protection.intern}] to match only instance (default) #{protection} methods" do  
 776         @object_spec = @object1
 777         @method_spec = /test_method/
 778         @method_options = [protection.intern]
 779         @protection = protection
 780         do_object_spec
 781       end
 782 
 783       it "should accept :object(s) => ..., :methods => ..., :method_options => [:instance, #{protection.intern}] to match only instance #{protection} methods" do  
 784         @object_spec = @object1
 785         @method_spec = /test_method/
 786         @method_options = [:instance, protection.intern]
 787         @protection = protection
 788         do_object_spec
 789       end
 790     end
 791   end
 792 
 793   describe Aspect, ".new (with a :object(s) parameter and a :attribute(s) parameter)" do  
 794     before :each do
 795       @object1 = Aquarium::AspectInvocationTestClass.new
 796       @object2 = Aquarium::AspectInvocationTestClass.new
 797       @protection = 'public'
 798       @attribute_options = []
 799     end
 800   
 801     def do_object_attribute_spec
 802       aspect = nil
 803       advice_called = false
 804       aspect = Aspect.new :before, :objects => @object_spec, :attributes => @attribute_spec, :attribute_options => @attribute_options do |jp, obj, *args|
 805         advice_called = true
 806         jp.should_not be_nil
 807         expected_args = make_array(@expected_args)
 808         args.should == expected_args
 809         args.size.should == expected_args.size
 810       end 
 811       make_array(@object_spec).each do |object|
 812         @expected_args = nil
 813         object.method("#{@protection}_test_method_args".intern).call 
 814         @expected_args = :a1
 815         object.method("#{@protection}_test_method_args=".intern).call @expected_args
 816         advice_called.should be_true
 817       end
 818       aspect.unadvise
 819     end
 820 
 821     it "should accept :object(s) => [T1, ...], :attribute(s) => [a, ...]" do  
 822       @object_spec = [@object1, @object2]
 823       @attribute_spec = [:public_test_method_args]
 824       do_object_attribute_spec
 825     end
 826 
 827     it "should accept :object(s) => [T1, ...], :attribute(s) => a" do  
 828       @object_spec = [@object1, @object2]
 829       @attribute_spec = :public_test_method_args
 830       do_object_attribute_spec
 831     end
 832 
 833     it "should accept :object(s) => [T1, ...], :attribute(s) => /a/" do  
 834       @object_spec = [@object1, @object2]
 835       @attribute_spec = /test_method_args/
 836       do_object_attribute_spec
 837     end
 838 
 839     it "should accept :object(s) => T1, :attribute(s) => [a]" do  
 840       @object_spec = @object1
 841       @attribute_spec = [:public_test_method_args]
 842       do_object_attribute_spec
 843     end
 844 
 845     it "should accept :object(s) => T1, :attribute(s) => a" do  
 846       @object_spec = @object1
 847       @attribute_spec = :public_test_method_args
 848       do_object_attribute_spec
 849     end
 850 
 851     it "should accept :object(s) => T1, :attribute(s) => /a/" do  
 852       @object_spec = @object1
 853       @attribute_spec = /test_method_args/
 854       do_object_attribute_spec
 855     end
 856 
 857     it "should accept :object(s) => ..., :attributes => ..., :attribute_options => [:readers, :writers] to include both attribute reader and writer methods (default)" do  
 858       @object_spec = @object1
 859       @attribute_spec = /test_method_args/
 860       @attribute_options = [:readers, :writers]
 861       do_object_attribute_spec
 862     end
 863 
 864     it "should accept :object(s) => ..., :attributes => ..., :attribute_options => [:readers] to include only attribute reader methods" do  
 865       @object_spec = @object1
 866       @attribute_spec = /test_method_args/
 867       @attribute_options = [:readers]
 868       do_object_attribute_spec
 869     end
 870 
 871     it "should accept attribute option :reader as a synonym for :readers" do
 872       @object_spec = @object1
 873       @attribute_spec = /test_method_args/
 874       @attribute_options = [:reader]
 875       do_object_attribute_spec
 876     end
 877 
 878     it "should accept :object(s) => ..., :attributes => ..., :attribute_options => [:writers] to include only attribute writer methods" do  
 879       @object_spec = @object1
 880       @attribute_spec = /test_method_args/
 881       @attribute_options = [:writers]
 882       do_object_attribute_spec
 883     end
 884 
 885     it "should accept attribute option :writer as a synonym for :writers" do
 886       @object_spec = @object1
 887       @attribute_spec = /test_method_args/
 888       @attribute_options = [:writer]
 889       do_object_attribute_spec
 890     end
 891   end
 892 
 893   describe Aspect, ".new (with a :pointcut parameter taking a hash with type specifications)" do  
 894     before :each do
 895       @protection = 'public'
 896       @are_class_methods = false
 897     end
 898   
 899     def do_type_pointcut_spec
 900       aspect = nil
 901       advice_called = false
 902       aspect = Aspect.new :before, :pointcut => @pointcut_hash do |jp, obj, *args|
 903         advice_called = true
 904         jp.should_not be_nil
 905         args.size.should == 4
 906         args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 907       end 
 908       if @are_class_methods
 909         Aquarium::AspectInvocationTestClass.method("#{@protection}_class_test_method".intern).call :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
 910       else
 911         Aquarium::AspectInvocationTestClass.new.method("#{@protection}_test_method".intern).call :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
 912       end
 913       advice_called.should be_true
 914       aspect.unadvise
 915     end
 916 
 917     it "should accept {:type(s) => [T1, ...], :methods => [m, ...]} " do  
 918       @pointcut_hash = {:type => [Aquarium::AspectInvocationTestClass], :methods => [:public_test_method]}
 919       do_type_pointcut_spec
 920     end
 921 
 922     it "should accept {:type(s) => [T1, ...], :methods => m} " do  
 923       @pointcut_hash = {:type => [Aquarium::AspectInvocationTestClass], :methods => :public_test_method}
 924       do_type_pointcut_spec
 925     end
 926 
 927     it "should accept {:type(s) => [T1, ...], :methods => /m/} " do  
 928       @pointcut_hash = {:type => [Aquarium::AspectInvocationTestClass], :methods => /test_method/}
 929       do_type_pointcut_spec
 930     end
 931 
 932     it "should accept {:type(s)_and_ancestors => [T1, ...], :methods => /m/} " do  
 933       @pointcut_hash = {:type_and_ancestors => [Aquarium::AspectInvocationTestClass], :methods => /test_method/}
 934       do_type_pointcut_spec
 935     end
 936 
 937     it "should accept {:type(s)_and_descendents => [T1, ...], :methods => /m/} " do  
 938       @pointcut_hash = {:type_and_descendents => [Aquarium::AspectInvocationTestClass], :methods => /test_method/}
 939       do_type_pointcut_spec
 940     end
 941 
 942     it "should accept {:type(s)_and_nested_types => [T1, ...], :methods => /m/} " do  
 943       @pointcut_hash = {:type_and_nested_types => [Aquarium::AspectInvocationTestClass], :methods => /test_method/}
 944       do_type_pointcut_spec
 945     end
 946 
 947     it "should accept {:type(s) => T1, :methods => [m, ...]} " do  
 948       @pointcut_hash = {:type => Aquarium::AspectInvocationTestClass, :methods => [:public_test_method]}
 949       do_type_pointcut_spec
 950     end
 951 
 952     it "should accept {:type(s) => T1, :methods => m} " do  
 953       @pointcut_hash = {:type => Aquarium::AspectInvocationTestClass, :methods => :public_test_method}
 954       do_type_pointcut_spec
 955     end
 956 
 957     it "should accept {:type(s) => T1, :methods => /m/} " do  
 958       @pointcut_hash = {:type => Aquarium::AspectInvocationTestClass, :methods => /test_method/}
 959       do_type_pointcut_spec
 960     end
 961 
 962     it "should accept {:type(s)_and_ancestors => T1, :methods => /m/} " do  
 963       @pointcut_hash = {:type_and_ancestors => Aquarium::AspectInvocationTestClass, :methods => /test_method/}
 964       do_type_pointcut_spec
 965     end
 966 
 967     it "should accept {:type(s)_and_descendents => T1, :methods => /m/} " do  
 968       @pointcut_hash = {:type_and_descendents => Aquarium::AspectInvocationTestClass, :methods => /test_method/}
 969       do_type_pointcut_spec
 970     end
 971 
 972     it "should accept {:type(s)_and_nested_types => T1, :methods => /m/} " do  
 973       @pointcut_hash = {:type_and_nested_types => Aquarium::AspectInvocationTestClass, :methods => /test_method/}
 974       do_type_pointcut_spec
 975     end
 976 
 977     it "should accept {:type(s) => /T1/, :methods => [m, ...]} " do  
 978       @pointcut_hash = {:type => /Aquarium::AspectInvocationTestClass/, :methods => [:public_test_method]}
 979       do_type_pointcut_spec
 980     end
 981 
 982     it "should accept {:type(s) => /T1/, :methods => m} " do  
 983       @pointcut_hash = {:type => /Aquarium::AspectInvocationTestClass/, :methods => :public_test_method}
 984       do_type_pointcut_spec
 985     end
 986 
 987     it "should accept {:type(s) => /T1/, :methods => /m/} " do  
 988       @pointcut_hash = {:type => /Aquarium::AspectInvocationTestClass/, :methods => /test_method/}
 989       do_type_pointcut_spec
 990     end
 991 
 992     it "should accept {:type(s)_and_ancestors => /T1/, :methods => /m/} " do  
 993       @pointcut_hash = {:type_and_ancestors => /Aquarium::AspectInvocationTestClass/, :methods => /test_method/}
 994       do_type_pointcut_spec
 995     end
 996 
 997     it "should accept {:type(s)_and_descendents => /T1/, :methods => /m/} " do  
 998       @pointcut_hash = {:type_and_descendents => /Aquarium::AspectInvocationTestClass/, :methods => /test_method/}
 999       do_type_pointcut_spec
1000     end
1001 
1002     it "should accept {:type(s)_and_nested_types => /T1/, :methods => /m/} " do  
1003       @pointcut_hash = {:type_and_nested_types => /Aquarium::AspectInvocationTestClass/, :methods => /test_method/}
1004       do_type_pointcut_spec
1005     end
1006 
1007     %w[public protected private].each do |protection|
1008       it "should accept {:type(s) => T1, :methods => /m/, :method_options =>[:instance, #{protection}]} " do  
1009         @protection = protection
1010         @pointcut_hash = {:type => Aquarium::AspectInvocationTestClass, :methods => /test_method/, :method_options =>[:instance, protection.intern]}
1011         do_type_pointcut_spec
1012       end
1013     end
1014 
1015     %w[public private].each do |protection|
1016       it "should accept {:type(s) => T1, :methods => /m/, :method_options =>[:class, #{protection}]} " do  
1017         @pointcut_hash = {:type => Aquarium::AspectInvocationTestClass, :methods => /class_test_method/, :method_options =>[:class, protection.intern]}
1018         @protection = protection
1019         @are_class_methods = true
1020         do_type_pointcut_spec
1021       end
1022     end
1023 
1024     it "should accept {:type(s) => T1, :methods => /m/, :method_options =>[:instance]} defaults to public methods" do  
1025       @pointcut_hash = {:type => Aquarium::AspectInvocationTestClass, :methods => /test_method/, :method_options =>[:instance]}
1026       do_type_pointcut_spec
1027     end
1028 
1029     it "should accept {:type(s) => T1, :methods => /m/, :method_options =>[:class]} defaults to public class methods" do  
1030       @pointcut_hash = {:type => Aquarium::AspectInvocationTestClass, :methods => /test_method/, :method_options =>[:class]}
1031       @are_class_methods = true
1032       do_type_pointcut_spec
1033     end
1034   end
1035 
1036   describe Aspect, ".new (with a :pointcut parameter taking a hash with object specifications)" do  
1037     before :each do
1038       @protection = 'public'
1039       @expected_advice_count = 2
1040       @object1 = Aquarium::AspectInvocationTestClass.new
1041       @object2 = Aquarium::AspectInvocationTestClass.new
1042     end
1043   
1044     def do_object_pointcut_spec
1045       aspect = nil
1046       advice_count = 0
1047       aspect = Aspect.new :before, :pointcut => @pointcut_hash do |jp, obj, *args|
1048         advice_count += 1
1049         jp.should_not be_nil
1050         args.size.should == 4
1051         args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
1052       end 
1053       @object1.method("#{@protection}_test_method".intern).call :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
1054       @object2.method("#{@protection}_test_method".intern).call :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
1055       advice_count.should == @expected_advice_count
1056       aspect.unadvise
1057     end
1058 
1059     it "should accept {:objects => [o1, ...], :methods => [m, ...]} " do  
1060       @pointcut_hash = {:objects => [@object1, @object2], :methods => [:public_test_method]}
1061       do_object_pointcut_spec
1062     end
1063 
1064     it "should accept {:objects => [o1, ...], :methods => m} " do  
1065       @pointcut_hash = {:objects => [@object1, @object2], :methods => :public_test_method}
1066       do_object_pointcut_spec
1067     end
1068 
1069     it "should accept {:objects => [o1, ...], :methods => /m/} " do  
1070       @pointcut_hash = {:objects => [@object1, @object2], :methods => /test_method/}
1071       do_object_pointcut_spec
1072     end
1073 
1074     it "should accept {:object => o1, :methods => [m, ...]} " do  
1075       @expected_advice_count = 1
1076       @pointcut_hash = {:object => @object1, :methods => [:public_test_method]}
1077       do_object_pointcut_spec
1078     end
1079 
1080     it "should accept {:objects => o1, :methods => m} " do  
1081       @expected_advice_count = 1
1082       @pointcut_hash = {:objects => @object1, :methods => :public_test_method}
1083       do_object_pointcut_spec
1084     end
1085 
1086     it "should accept {:objects => o1, :methods => /m/} " do  
1087       @expected_advice_count = 1
1088       @pointcut_hash = {:objects => @object1, :methods => /test_method/}
1089       do_object_pointcut_spec
1090     end
1091   end
1092 
1093   describe Aspect, ".new (with a :pointcut parameter and a Pointcut object or an array of Pointcuts)" do  
1094     def do_pointcut_pointcut_spec
1095       aspect = nil
1096       advice_called = false
1097       aspect = Aspect.new :before, :pointcut => @pointcuts do |jp, obj, *args|
1098         advice_called = true
1099         jp.should_not be_nil
1100         args.size.should == 4
1101         args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
1102       end 
1103       Aquarium::AspectInvocationTestClass.new.public_test_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
1104       advice_called.should be_true
1105       aspect.unadvise
1106     end
1107 
1108     it "should accept a single Pointcut object." do
1109       @pointcuts = Pointcut.new :type => [Aquarium::AspectInvocationTestClass], :methods => :public_test_method
1110       do_pointcut_pointcut_spec
1111     end
1112   
1113     it "should accept an array of Pointcut objects." do
1114       pointcut1 = Pointcut.new :type => [Aquarium::AspectInvocationTestClass], :methods => :public_test_method
1115       pointcut2 = Pointcut.new :type => [Aquarium::AspectInvocationTestClass], :methods => :public_class_test_method, :method_options => [:class]
1116       @pointcuts = [pointcut1, pointcut2]
1117       do_pointcut_pointcut_spec
1118     end
1119   end
1120 
1121   describe Aspect, ".new (with a :pointcut parameter and an array of Pointcuts)" do  
1122     it "should treat the array as if it is one Pointcut \"or'ed\" together." do
1123       advice_called = 0
1124       advice = Proc.new {|jp, obj, *args|
1125         advice_called += 1
1126         jp.should_not be_nil
1127         args.size.should == 4
1128         args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
1129       }
1130       pointcut1 = Pointcut.new :type => [Aquarium::AspectInvocationTestClass], :methods => :public_test_method
1131       pointcut2 = Pointcut.new :type => [Aquarium::AspectInvocationTestClass], :methods => :public_class_test_method, :method_options => [:class]
1132       pointcut12 = pointcut1.or pointcut2