C0 code coverage information

Generated on Sun Oct 26 11:18:05 -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_spec.rb 1093 980
100.0% 
100.0% 
   1 require File.dirname(__FILE__) + '/../spec_helper'
   2 require 'aquarium/spec_example_types'
   3 require 'aquarium/aspects'
   4 require 'logger'
   5 
   6 include Aquarium::Aspects
   7 
   8 class MyError1 < StandardError; end
   9 class MyError2 < StandardError; end
  10 class MyError3 < StandardError; end
  11 class ClassThatRaises
  12   class CTRException < StandardError; end
  13   def raises
  14     raise CTRException
  15   end
  16 end
  17 class ClassThatRaisesString
  18   class CTRException < StandardError; end
  19   def raises
  20     raise "A string exception."
  21   end
  22 end
  23 
  24 
  25 describe Aspect, " cannot advise the private implementation methods inserted by other aspects" do  
  26   it "should have no affect." do
  27     class WithAspectLikeMethod
  28       def _aspect_foo; end
  29     end
  30     aspect = Aspect.new(:after, :pointcut => {:type => WithAspectLikeMethod, :methods => :_aspect_foo}) {|jp, obj, *args| fail}
  31     WithAspectLikeMethod.new._aspect_foo
  32     aspect.unadvise
  33   end
  34 end
  35 
  36 describe Aspect, " when advising a type" do  
  37   before(:all) do
  38     @advice = Proc.new {}
  39   end
  40   after(:each) do
  41     @aspect.unadvise
  42   end
  43   
  44   it "should not add new public instance or class methods that the advised type responds to." do
  45     all_public_methods_before = all_public_methods_of_type Watchful
  46     @aspect = Aspect.new :after, :pointcut => {:type => Watchful, :method_options => :exclude_ancestor_methods}, :advice => @advice 
  47     (all_public_methods_of_type(Watchful) - all_public_methods_before).should == []
  48   end
  49 
  50   it "should not add new protected instance methods that the advised type responds to." do
  51     all_protected_methods_before = all_protected_methods_of_type Watchful
  52     @aspect = Aspect.new :after, :pointcut => {:type => Watchful, :method_options => :exclude_ancestor_methods}, :advice => @advice  
  53     (all_protected_methods_of_type(Watchful) - all_protected_methods_before).should == []
  54   end
  55 end
  56 
  57 describe Aspect, " when advising an object" do  
  58   before(:all) do
  59     @advice = Proc.new {}
  60   end
  61   after(:each) do
  62     @aspect.unadvise
  63   end
  64 
  65   it "should not add new public instance or class methods that the advised object responds to." do
  66     watchful = Watchful.new
  67     all_public_methods_before = all_public_methods_of_object Watchful
  68     @aspect = Aspect.new :after, :pointcut => {:object => watchful, :method_options => :exclude_ancestor_methods}, :advice => @advice  
  69     (all_public_methods_of_object(Watchful) - all_public_methods_before).should == []
  70   end
  71 
  72   it "should not add new protected instance or class methods that the advised object responds to." do
  73     watchful = Watchful.new
  74     all_protected_methods_before = all_protected_methods_of_object Watchful
  75     @aspect = Aspect.new :after, :pointcut => {:object => watchful, :method_options => :exclude_ancestor_methods}, :advice => @advice  
  76     (all_protected_methods_of_object(Watchful) - all_protected_methods_before).should == []
  77   end
  78 end
  79 
  80 describe Aspect, " with :before advice" do  
  81   after(:each) do
  82     @aspect.unadvise if @aspect
  83   end
  84 
  85   it "should pass the context information to the advice, including self and the method parameters." do
  86     watchful = Watchful.new
  87     advice_called = false
  88     @aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
  89       advice_called = true
  90       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
  91       jp.context.advice_kind.should == :before
  92       jp.context.advised_object.should == watchful
  93       jp.context.returned_value.should == nil
  94       jp.context.raised_exception.should == nil
  95     end 
  96     block_called = 0
  97     watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
  98     block_called.should == 1
  99     advice_called.should be_true
 100   end
 101 
 102   it "should evaluate the advice before the method body and its block (if any)." do
 103     @aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 104       @advice_called += 1
 105     end 
 106     do_watchful_public_protected_private 
 107   end
 108 end
 109 
 110 describe Aspect, " with :after advice" do  
 111   after(:each) do
 112     @aspect.unadvise if @aspect
 113   end
 114 
 115   it "should pass the context information to the advice, including self, the method parameters, and the return value when the method returns normally." do
 116     watchful = Watchful.new
 117     advice_called = false
 118     @aspect = Aspect.new :after, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 119       advice_called = true
 120       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 121       jp.context.advice_kind.should == :after
 122       jp.context.advised_object.should == watchful
 123       jp.context.returned_value.should == 1
 124       jp.context.raised_exception.should == nil
 125     end 
 126     block_called = 0
 127     watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
 128     block_called.should == 1
 129     advice_called.should be_true
 130   end
 131 
 132   it "should pass the context information to the advice, including self, the method parameters, and the rescued exception when an exception is raised." do
 133     watchful = Watchful.new
 134     context = nil
 135     @aspect = Aspect.new :after, :pointcut => {:type => Watchful, :methods => /public_watchful_method/} do |jp, obj, *args|
 136       context = jp.context
 137     end 
 138     block_called = 0
 139     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') do |*args| 
 140       block_called += 1 
 141       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 142     end }.should raise_error(Watchful::WatchfulError)
 143     block_called.should == 1
 144     context.advised_object.should == watchful
 145     context.returned_value.should == nil
 146     context.raised_exception.kind_of?(Watchful::WatchfulError).should be_true
 147   end
 148 
 149   it "should evaluate the advice after the method body and its block (if any)." do
 150     @aspect = Aspect.new :after, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 151       @advice_called += 1
 152     end 
 153     do_watchful_public_protected_private 
 154   end
 155   
 156   it "should ignore the value returned by the advice" do
 157     class ReturningValue
 158       def doit args
 159         args + ["d"]
 160       end
 161     end
 162     ary = %w[a b c]
 163     ReturningValue.new.doit(ary).should == %w[a b c d]
 164     @aspect = Aspect.new :after, :type => ReturningValue, :method => :doit do |jp, obj, *args|
 165       %w[aa] + jp.context.returned_value + %w[e]
 166     end 
 167     ReturningValue.new.doit(ary).should == %w[a b c d]
 168   end
 169 
 170   it "should all the advice to assign a new return value" do
 171     class ReturningValue
 172       def doit args
 173         args + ["d"]
 174       end
 175     end
 176     ary = %w[a b c]
 177     ReturningValue.new.doit(ary).should == %w[a b c d]
 178     @aspect = Aspect.new :after, :type => ReturningValue, :method => :doit do |jp, obj, *args|
 179       jp.context.returned_value = %w[aa] + jp.context.returned_value + %w[e]
 180     end 
 181     ReturningValue.new.doit(ary).should == %w[aa a b c d e]
 182   end
 183 
 184   it "should allow advice to change the exception raised" do
 185     aspect_advice_invoked = false
 186     @aspect = Aspect.new :after, :pointcut => {:type => ClassThatRaises, :methods => :raises} do |jp, obj, *args|
 187       aspect_advice_invoked = true
 188       jp.context.raised_exception = MyError1
 189     end 
 190     aspect_advice_invoked.should be_false
 191     ctr = ClassThatRaises.new
 192     lambda {ctr.raises}.should raise_error(MyError1)
 193     aspect_advice_invoked.should be_true
 194   end
 195 end
 196 
 197 describe Aspect, " with :after_returning advice" do  
 198   after(:each) do
 199     @aspect.unadvise if @aspect
 200   end
 201 
 202   it "should pass the context information to the advice, including self, the method parameters, and the return value." do
 203     watchful = Watchful.new
 204     advice_called = false
 205     @aspect = Aspect.new :after_returning, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 206       advice_called = true
 207       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 208       jp.context.advice_kind.should == :after_returning
 209       jp.context.advised_object.should == watchful
 210       jp.context.returned_value.should == 1
 211       jp.context.raised_exception.should == nil
 212     end 
 213     block_called = 0
 214     watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
 215     block_called.should == 1
 216     advice_called.should be_true
 217   end
 218 
 219   it "should evaluate the advice after the method body and its block (if any)." do
 220     @aspect = Aspect.new :after_returning, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 221       @advice_called += 1
 222     end 
 223     do_watchful_public_protected_private 
 224   end
 225   
 226   it "should ignore the value returned by the advice" do
 227     class ReturningValue
 228       def doit args
 229         args + ["d"]
 230       end
 231     end
 232     ary = %w[a b c]
 233     ReturningValue.new.doit(ary).should == %w[a b c d]
 234     @aspect = Aspect.new :after_returning, :type => ReturningValue, :method => :doit do |jp, obj, *args|
 235       %w[aa] + jp.context.returned_value + %w[e]
 236     end 
 237     ReturningValue.new.doit(ary).should == %w[a b c d]
 238   end
 239 
 240   it "should allow the advice to change the returned value" do
 241     class ReturningValue
 242       def doit args
 243         args + ["d"]
 244       end
 245     end
 246     ary = %w[a b c]
 247     ReturningValue.new.doit(ary).should == %w[a b c d]
 248     @aspect = Aspect.new :after_returning, :type => ReturningValue, :method => :doit do |jp, obj, *args|
 249       jp.context.returned_value = %w[aa] + jp.context.returned_value + %w[e]
 250     end 
 251     ReturningValue.new.doit(ary).should == %w[aa a b c d e]
 252   end
 253 end
 254 
 255 describe Aspect, " with :after_raising advice" do  
 256   after(:each) do
 257     @aspect.unadvise if @aspect
 258   end
 259 
 260   it "should pass the context information to the advice, including self, the method parameters, and the rescued exception." do
 261     watchful = Watchful.new
 262     advice_called = false
 263     @aspect = Aspect.new :after_raising, :pointcut => {:type => Watchful, :methods => /public_watchful_method/} do |jp, obj, *args|
 264       advice_called = true
 265       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 266       jp.context.advised_object.should == watchful
 267       jp.context.advice_kind.should == :after_raising
 268       jp.context.returned_value.should == nil
 269       jp.context.raised_exception.kind_of?(Watchful::WatchfulError).should be_true
 270     end 
 271     block_called = 0
 272     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }}.should raise_error(Watchful::WatchfulError)
 273     block_called.should == 1
 274     advice_called.should be_true
 275   end
 276 
 277   it "should evaluate the advice after the method body and its block (if any)." do
 278     @aspect = Aspect.new :after_raising, :pointcut => {:type => Watchful, :methods => /public_watchful_method/} do |jp, obj, *args|
 279       @advice_called += 1
 280     end 
 281     do_watchful_public_protected_private true
 282   end
 283   
 284   it "should invoke advice when exceptions of the specified type are raised" do
 285     aspect_advice_invoked = false
 286     @aspect = Aspect.new(:after_raising => Watchful::WatchfulError, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
 287     block_invoked = false
 288     watchful = Watchful.new
 289     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
 290     aspect_advice_invoked.should be_true
 291     block_invoked.should be_true
 292   end
 293   
 294   it "should invoke advice when exceptions of the specified type are raised, which were specified with :exceptions => ..." do
 295     aspect_advice_invoked = false
 296     @aspect = Aspect.new(:after_raising, :exceptions => Watchful::WatchfulError, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
 297     block_invoked = false
 298     watchful = Watchful.new
 299     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
 300     aspect_advice_invoked.should be_true
 301     block_invoked.should be_true
 302   end
 303   
 304   it "should not invoke advice when exceptions of types that don't match the specified exception type are raised" do
 305     aspect_advice_invoked = false
 306     @aspect = Aspect.new(:after_raising => MyError1, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
 307     block_invoked = false
 308     watchful = Watchful.new
 309     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
 310     aspect_advice_invoked.should be_false
 311     block_invoked.should be_true
 312   end
 313   
 314   it "should not invoke advice when exceptions of types that don't match the specified exception type are raised, which were specified with :exceptions => ..." do
 315     aspect_advice_invoked = false
 316     @aspect = Aspect.new(:after_raising, :exceptions => MyError1, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
 317     block_invoked = false
 318     watchful = Watchful.new
 319     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
 320     aspect_advice_invoked.should be_false
 321     block_invoked.should be_true
 322   end
 323   
 324   it "should invoke advice when one exception in the list of the specified types is raised" do
 325     aspect_advice_invoked = false
 326     @aspect = Aspect.new(:after_raising => [Watchful::WatchfulError, MyError1], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
 327     block_invoked = false
 328     watchful = Watchful.new
 329     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
 330     aspect_advice_invoked.should be_true
 331     block_invoked.should be_true
 332   end
 333   
 334   it "should invoke advice when an exception that subclasses a specified exception type is raised" do
 335     aspect_advice_invoked = false
 336     @aspect = Aspect.new(:after_raising => StandardError, :pointcut => {:type => ClassThatRaises, :methods => :raises}) {|jp, obj, *args| aspect_advice_invoked = true}
 337     ctr = ClassThatRaises.new
 338     lambda {ctr.raises}.should raise_error(ClassThatRaises::CTRException)
 339     aspect_advice_invoked.should be_true
 340   end
 341   
 342   it "should not invoke advice when exceptions of types that don't match the specified list of exception types are raised" do
 343     aspect_advice_invoked = false
 344     @aspect = Aspect.new(:after_raising => [MyError1, MyError2], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
 345     block_invoked = false
 346     watchful = Watchful.new
 347     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
 348     aspect_advice_invoked.should be_false
 349     block_invoked.should be_true
 350   end
 351   
 352   it "should not invoke advice when exceptions of types that don't match the specified list of exception types are raised, which were specified with :exceptions => ..." do
 353     aspect_advice_invoked = false
 354     @aspect = Aspect.new(:after_raising, :exceptions => [MyError1, MyError2], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
 355     block_invoked = false
 356     watchful = Watchful.new
 357     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
 358     aspect_advice_invoked.should be_false
 359     block_invoked.should be_true
 360   end
 361   
 362   it "should treat :exception as a synonym for :exceptions" do
 363     aspect_advice_invoked = false
 364     @aspect = Aspect.new(:after_raising, :exception => [MyError1, MyError2], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
 365     block_invoked = false
 366     watchful = Watchful.new
 367     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
 368     aspect_advice_invoked.should be_false
 369     block_invoked.should be_true
 370   end
 371   
 372   it "should merge exceptions specified with :exception(s) and :after_raising" do
 373     aspect_advice_invoked = false
 374     @aspect = Aspect.new(:after_raising => MyError1, :exception => [MyError2, MyError3], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
 375     @aspect.specification[:after_raising].should eql(Set.new([MyError1, MyError2, MyError3]))
 376   end
 377   
 378   it "should advise all methods that raise exceptions when no specific exceptions are specified" do
 379     aspect_advice_invoked = false
 380     @aspect = Aspect.new :after_raising, :pointcut => {:type => ClassThatRaises, :methods => :raises} do |jp, obj, *args|
 381       aspect_advice_invoked = true
 382     end 
 383     aspect_advice_invoked.should be_false
 384     ctr = ClassThatRaises.new
 385     lambda {ctr.raises}.should raise_error(ClassThatRaises::CTRException)
 386     aspect_advice_invoked.should be_true
 387   end
 388 
 389   it "should advise all methods that raise strings (which are converted to RuntimeError) when no specific exceptions are specified" do
 390     aspect_advice_invoked = false
 391     @aspect = Aspect.new :after_raising, :pointcut => {:type => ClassThatRaisesString, :methods => :raises} do |jp, obj, *args|
 392       aspect_advice_invoked = true
 393     end 
 394     aspect_advice_invoked.should be_false
 395     ctr = ClassThatRaisesString.new
 396     lambda {ctr.raises}.should raise_error(RuntimeError)
 397     aspect_advice_invoked.should be_true
 398   end
 399 
 400   it "should allow advice to change the exception raised" do
 401     aspect_advice_invoked = false
 402     @aspect = Aspect.new :after_raising, :pointcut => {:type => ClassThatRaises, :methods => :raises} do |jp, obj, *args|
 403       aspect_advice_invoked = true
 404       jp.context.raised_exception = MyError1
 405     end 
 406     aspect_advice_invoked.should be_false
 407     ctr = ClassThatRaises.new
 408     lambda {ctr.raises}.should raise_error(MyError1)
 409     aspect_advice_invoked.should be_true
 410   end
 411 end
 412 
 413 describe Aspect, " with :before and :after advice" do  
 414   after(:each) do
 415     @aspect.unadvise if @aspect
 416   end
 417 
 418   it "should pass the context information to the advice, including self and the method parameters, plus the return value for the after-advice case." do
 419     # We record the contexts seen and the volatile advice kinds and returned values separately, as those values will have been
 420     # reset in the contexts by the time we return from the advised method. 
 421     contexts = []
 422     advice_kinds = []
 423     returned_values = []
 424     @aspect = Aspect.new :before, :after, :pointcut => {:type => Watchful, :methods => [:public_watchful_method]} do |jp, obj, *args|
 425       contexts << jp.context
 426       advice_kinds << jp.context.advice_kind
 427       returned_values << jp.context.returned_value
 428       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 429     end 
 430     watchful = Watchful.new
 431     public_block_called = 0
 432     watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') do |*args| 
 433       public_block_called += 1 
 434     end
 435     public_block_called.should == 1
 436     contexts.size.should == 2
 437     advice_kinds[0].should == :before
 438     advice_kinds[1].should == :after
 439     returned_values[0].should == nil
 440     returned_values[1].should == 1
 441     contexts.each do |context|
 442       context.advised_object.should == watchful
 443       context.raised_exception.should == nil
 444     end
 445 
 446     %w[protected private].each do |protection|  
 447       block_called = 0
 448       watchful.send("#{protection}_watchful_method", :b1, :b2, :b3) {|*args| block_called += 1}
 449       block_called.should == 1
 450       contexts.size.should == 2
 451     end
 452   end
 453 
 454   it "should evaluate the advice before and after the method body and its block (if any)." do
 455     @aspect = Aspect.new :before, :after, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 456       @advice_called += 1
 457     end 
 458     do_watchful_public_protected_private false, 2 
 459   end
 460 end
 461 
 462 describe Aspect, " with :before and :after_returning advice" do  
 463   after(:each) do
 464     @aspect.unadvise if @aspect
 465   end
 466 
 467   it "should pass the context information to the advice, including self and the method parameters, plus the return value for the after-advice case." do
 468     watchful = Watchful.new
 469     # We record the contexts seen and the volatile advice kinds and returned values separately, as those values will have been
 470     # reset in the contexts by the time we return from the advised method. 
 471     contexts = []
 472     advice_kinds = []
 473     returned_values = []
 474     @aspect = Aspect.new :before, :after_returning, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 475       contexts << jp.context
 476       advice_kinds << jp.context.advice_kind
 477       returned_values << jp.context.returned_value
 478       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 479     end 
 480     block_called = 0
 481     watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
 482     block_called.should == 1
 483     contexts.size.should == 2
 484     advice_kinds[0].should == :before
 485     advice_kinds[1].should == :after_returning
 486     returned_values[0].should == nil
 487     returned_values[1].should == 1
 488     contexts.each do |context|
 489       context.advised_object.should == watchful
 490       context.raised_exception.should == nil
 491     end
 492   end
 493 
 494   it "should evaluate the advice before and after the method body and its block (if any)." do
 495     @aspect = Aspect.new :before, :after_returning, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 496       @advice_called += 1
 497     end 
 498     do_watchful_public_protected_private false, 2 
 499   end
 500 end
 501 
 502 describe Aspect, " with :before and :after_raising advice" do  
 503   after(:each) do
 504     @aspect.unadvise if @aspect
 505   end
 506 
 507   it "should pass the context information to the advice, including self and the method parameters, plus the raised exception for the after-advice case." do
 508     watchful = Watchful.new
 509     # We record the contexts seen and the volatile advice kinds and raised exceptions separately, as those values will have been
 510     # reset in the contexts by the time we return from the advised method. 
 511     contexts = []
 512     advice_kinds = []
 513     raised_exceptions = []
 514     @aspect = Aspect.new :before, :after_raising, :pointcut => {:type => Watchful, :methods => :public_watchful_method_that_raises} do |jp, obj, *args|
 515       contexts << jp.context
 516       advice_kinds << jp.context.advice_kind
 517       raised_exceptions << jp.context.raised_exception
 518       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 519     end 
 520     block_called = 0
 521     lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }}.should raise_error(Watchful::WatchfulError)
 522     block_called.should == 1
 523     contexts.size.should == 2
 524     advice_kinds[0].should == :before
 525     advice_kinds[1].should == :after_raising
 526     raised_exceptions[0].should == nil
 527     raised_exceptions[1].kind_of?(Watchful::WatchfulError).should be_true
 528     contexts.each do |context|
 529       context.advised_object.should == watchful
 530       context.returned_value.should == nil
 531     end
 532   end
 533 
 534   it "should evaluate the advice before and after the method body and its block (if any)." do
 535     @aspect = Aspect.new :before, :after_raising, :pointcut => {:type => Watchful, :methods => :public_watchful_method_that_raises} do |jp, obj, *args|
 536       @advice_called += 1
 537     end 
 538     do_watchful_public_protected_private true, 2 
 539   end
 540 end
 541 
 542 describe Aspect, " with :around advice" do  
 543   after(:each) do
 544     @aspect.unadvise if @aspect
 545   end
 546 
 547   it "should pass the context information to the advice, including the object, advice kind, the method invocation parameters, etc." do
 548     watchful = Watchful.new
 549     advice_called = false
 550     @aspect = Aspect.new :around, :pointcut => {:type => Watchful, :methods => [:public_watchful_method]} do |jp, obj, *args|
 551       advice_called = true
 552       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 553       jp.context.advised_object.should == watchful
 554       jp.context.advice_kind.should == :around
 555       jp.context.returned_value.should == nil
 556       jp.context.raised_exception.should == nil
 557     end 
 558     public_block_called = false
 559     protected_block_called = false
 560     private_block_called = false
 561     watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| public_block_called = true }
 562     watchful.send(:protected_watchful_method, :b1, :b2, :b3) {|*args| protected_block_called = true}
 563     watchful.send(:private_watchful_method, :c1, :c2, :c3) {|*args| private_block_called = true}
 564     public_block_called.should be_false  # proceed is never called!
 565     protected_block_called.should be_true
 566     private_block_called.should be_true
 567     advice_called.should be_true
 568   end
 569 
 570   it "should advise subclass invocations of methods advised in the superclass." do
 571     module AdvisingSuperClass
 572       class SuperClass
 573         def public_method *args
 574           # yield *args if block_given?
 575         end
 576         protected
 577         def protected_method *args
 578           yield *args if block_given?
 579         end
 580         private
 581         def private_method *args
 582           yield *args if block_given?
 583         end
 584       end
 585       class SubClass < SuperClass
 586       end
 587     end
 588     
 589     child = AdvisingSuperClass::SubClass.new
 590     advice_called = false
 591     @aspect = Aspect.new :around, :pointcut => {:type => AdvisingSuperClass::SuperClass, :methods => [:public_method]} do |jp, obj, *args|
 592       advice_called = true
 593       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 594       jp.context.advised_object.should == child
 595       jp.context.advice_kind.should == :around
 596       jp.context.returned_value.should == nil
 597       jp.context.raised_exception.should == nil
 598     end 
 599     public_block_called = false
 600     protected_block_called = false
 601     private_block_called = false
 602     child.public_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| fail }
 603     child.send(:protected_method, :b1, :b2, :b3) {|*args| protected_block_called = true}
 604     child.send(:private_method, :c1, :c2, :c3) {|*args| private_block_called = true}
 605     public_block_called.should be_false  # proceed is never called!
 606     protected_block_called.should be_true
 607     private_block_called.should be_true
 608     advice_called.should be_true
 609   end
 610 
 611   it "should advise subclass invocations of methods advised in the subclass that are defined in the superclass." do
 612     module AdvisingSubClass
 613       class SuperClass
 614         def public_method *args
 615           # yield *args if block_given?
 616         end
 617         protected
 618         def protected_method *args
 619           yield *args if block_given?
 620         end
 621         private
 622         def private_method *args
 623           yield *args if block_given?
 624         end
 625       end
 626       class SubClass < SuperClass
 627       end
 628     end
 629     
 630     child = AdvisingSubClass::SubClass.new
 631     advice_called = false
 632     @aspect = Aspect.new :around, :pointcut => {:type => AdvisingSubClass::SuperClass, :methods => [:public_method]} do |jp, obj, *args|
 633       advice_called = true
 634       args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
 635       jp.context.advised_object.should == child
 636       jp.context.advice_kind.should == :around
 637       jp.context.returned_value.should == nil
 638       jp.context.raised_exception.should == nil
 639     end 
 640     public_block_called = false
 641     protected_block_called = false
 642     private_block_called = false
 643     child.public_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| fail }
 644     child.send(:protected_method, :b1, :b2, :b3) {|*args| protected_block_called = true}
 645     child.send(:private_method, :c1, :c2, :c3) {|*args| private_block_called = true}
 646     public_block_called.should be_false  # proceed is never called!
 647     protected_block_called.should be_true
 648     private_block_called.should be_true
 649     advice_called.should be_true
 650   end
 651 
 652   it "should not advise subclass overrides of superclass methods, when advising superclasses (but calls to superclass methods are advised)." do
 653     class WatchfulChild2 < Watchful
 654       def public_watchful_method *args
 655         @override_called = true
 656         yield(*args) if block_given?
 657       end
 658       attr_reader :override_called
 659       def initialize
 660         super
 661         @override_called = false
 662       end
 663     end
 664     @aspect = Aspect.new(:around, :pointcut => {:type => Watchful, :methods => [:public_watchful_method]}) {|jp, obj, *args| fail}
 665     child = WatchfulChild2.new
 666     public_block_called = false
 667     child.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| public_block_called = true }
 668     public_block_called.should be_true  # advice never called
 669   end
 670 
 671   it "should evaluate the advice and only evaluate the method body and its block (if any) when JoinPoint#proceed is called." do
 672     do_around_spec
 673   end
 674   
 675   it "should pass the block that was passed to the method by default if the block is not specified explicitly in the around advice in the call to JoinPoint#proceed." do
 676     do_around_spec
 677   end
 678   
 679   it "should pass the parameters and block that were passed to the method by default if JoinPoint#proceed is invoked without parameters and a block." do
 680     do_around_spec
 681   end
 682   
 683   it "should pass parameters passed explicitly to JoinPoint#proceed, rather than the original method parameters, but also pass the original block if a new block is not specified." do
 684     do_around_spec :a4, :a5, :a6
 685   end
 686   
 687   it "should pass parameters and a block passed explicitly to JoinPoint#proceed, rather than the original method parameters and block." do
 688     override_block_called = false
 689     @aspect = Aspect.new :around, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 690       jp.proceed(:a4, :a5, :a6) {|*args| override_block_called = true}
 691     end 
 692     watchful = Watchful.new
 693     orig_block_called = false
 694     watchful.public_watchful_method(:a1, :a2, :a3) {|*args| orig_block_called = true}
 695     override_block_called.should be_true
 696     orig_block_called.should be_false
 697     watchful.public_watchful_method_args.should == [:a4, :a5, :a6]
 698   end
 699   
 700   it "should return the value returned by the advice, NOT the value returned by the advised join point!" do
 701     class ReturningValue
 702       def doit args
 703         args + ["d"]
 704       end
 705     end
 706     ary = %w[a b c]
 707     ReturningValue.new.doit(ary).should == %w[a b c d]
 708     @aspect = Aspect.new :around, :type => ReturningValue, :method => :doit do |jp, obj, *args|
 709       jp.proceed
 710       %w[aa bb cc]
 711     end 
 712     ReturningValue.new.doit(ary).should == %w[aa bb cc]
 713   end
 714 
 715   it "should return the value returned by the advised join point only if the advice returns the value" do
 716     class ReturningValue
 717       def doit args
 718         args + ["d"]
 719       end
 720     end
 721     ary = %w[a b c]
 722     ReturningValue.new.doit(ary).should == %w[a b c d]
 723     @aspect = Aspect.new :around, :type => ReturningValue, :method => :doit do |jp, obj, *args|
 724       begin
 725         jp.proceed
 726       ensure
 727         %w[aa bb cc]
 728       end
 729     end 
 730     ReturningValue.new.doit(ary).should == %w[a b c d]
 731   end
 732 
 733   def do_around_spec *args_passed_to_proceed
 734     @aspect = Aspect.new :around, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, obj, *args|
 735       @advice_called += 1
 736       returned_value = args_passed_to_proceed.empty? ? jp.proceed : jp.proceed(*args_passed_to_proceed) 
 737       @advice_called += 1
 738       returned_value
 739     end 
 740     do_watchful_public_protected_private false, 2, (args_passed_to_proceed.empty? ? nil : args_passed_to_proceed)
 741   end
 742 end
 743 
 744 describe Aspect, " with advice that calls JoinPoint#invoke_original_join_point" do
 745   class AdvicesInvocationCounter
 746     def initialize; @counter = 0; end
 747     def increment; @counter += 1; end
 748     def counter; @counter; end
 749   end
 750   
 751   it "should not call the intermediate advices" do
 752     aspect1 = Aspect.new :around, :type => AdvicesInvocationCounter, :method => :increment do |jp, obj, *args|; fail; end
 753     aspect2 = Aspect.new :around, :type => AdvicesInvocationCounter, :method => :increment do |jp, obj, *args|
 754       jp.invoke_original_join_point
 755     end
 756     aic = AdvicesInvocationCounter.new
 757     aic.increment
 758     aic.counter.should == 1
 759     aspect1.unadvise
 760     aspect2.unadvise
 761   end
 762 end
 763 
 764 describe Aspect, "#unadvise called more than once on the same aspect" do
 765   before(:all) do
 766     @advice = Proc.new {}
 767   end
 768   
 769   it "should do nothing on the second invocation." do
 770     aspect = Aspect.new :around, :type => Watchful, :method => /does_not_exist/, :advice => @advice, :severity => Logger::Severity::ERROR
 771     aspect.unadvise
 772     lambda {aspect.unadvise}.should_not raise_error
 773     lambda {aspect.unadvise}.should_not raise_error
 774   end
 775 end
 776 
 777 describe Aspect, "#unadvise for 'empty' aspects" do
 778   before(:all) do
 779     @advice = Proc.new {}
 780   end
 781   
 782   it "should do nothing for unadvised types." do
 783     expected_methods = (Watchful.private_methods + Watchful.private_instance_methods).sort
 784     aspect = Aspect.new :around, :type => Watchful, :method => /does_not_exist/, :advice => @advice, :severity => Logger::Severity::ERROR
 785     ((Watchful.private_methods + Watchful.private_instance_methods).sort - expected_methods).should == []
 786     aspect.unadvise
 787     ((Watchful.private_methods + Watchful.private_instance_methods).sort - expected_methods).should == []
 788     aspect.unadvise
 789     ((Watchful.private_methods + Watchful.private_instance_methods).sort - expected_methods).should == []
 790   end
 791     
 792   it "should do nothing for unadvised objects." do
 793     @watchful = Watchful.new
 794     expected_methods = @watchful.private_methods.sort
 795     aspect = Aspect.new :around, :object => @watchful, :method => /does_not_exist/, :advice => @advice, :severity => Logger::Severity::ERROR
 796     (@watchful.private_methods.sort - expected_methods).should == []
 797     aspect.unadvise
 798     (@watchful.private_methods.sort - expected_methods).should == []
 799     aspect.unadvise
 800     (@watchful.private_methods.sort - expected_methods).should == []
 801   end
 802 end
 803 
 804 describe Aspect, "#unadvise clean up" do
 805   before(:all) do
 806     @advice = Proc.new {}
 807     @watchful = Watchful.new
 808   end
 809 
 810   def get_type_methods
 811     public_methods    = (Watchful.public_methods    + Watchful.public_instance_methods).sort
 812     protected_methods = (Watchful.protected_methods + Watchful.protected_instance_methods).sort
 813     private_methods   = (Watchful.private_methods   + Watchful.private_instance_methods).sort
 814     [public_methods, protected_methods, private_methods]
 815   end
 816   
 817   def get_object_methods
 818     public_methods    = @watchful.public_methods.sort
 819     protected_methods = @watchful.protected_methods.sort
 820     private_methods   = @watchful.private_methods.sort
 821     [public_methods, protected_methods, private_methods]
 822   end
 823   
 824   def diff_methods actual, expected, private_should_not_be_equal = false
 825     3.times do |i|
 826       if i==2 && private_should_not_be_equal
 827         actual[i].should_not == expected[i] 
 828       else
 829         actual[i].should == expected[i] 
 830       end
 831     end
 832   end
 833   
 834   def do_unadvise_spec parameters, which_get_methods
 835     parameters[:after] = ''
 836     expected_methods = send(which_get_methods)
 837     advice_called = false
 838     aspect = Aspect.new(:after, parameters) {|jp, obj, *args| advice_called = true}
 839     diff_methods send(which_get_methods), expected_methods, true
 840     aspect.unadvise
 841     diff_methods send(which_get_methods), expected_methods
 842 
 843     %w[public protected private].each do |protection|
 844       advice_called = false
 845       block_called = false
 846       @watchful.send("#{protection}_watchful_method".intern, :a1, :a2, :a3) {|*args| block_called = true}
 847       advice_called.should be_false
 848       block_called.should be_true
 849     end
 850   end
 851   
 852   it "should remove all advice added by a pointcut-based aspect." do
 853     do_unadvise_spec({:pointcut => {:type => Watchful, :method_options => :exclude_ancestor_methods}}, :get_type_methods)
 854   end
 855   
 856   it "should remove all advice added by a type-based aspect." do
 857     do_unadvise_spec({:type => Watchful, :method_options => :exclude_ancestor_methods}, :get_type_methods)
 858   end
 859   
 860   it "should remove all advice added by an object-based aspect." do
 861     do_unadvise_spec({:object => @watchful, :method_options => :exclude_ancestor_methods}, :get_object_methods)
 862   end
 863 end  
 864 
 865 module Aquarium
 866   class FooForPrivateCheck
 867     def bar; end
 868   end
 869 end
 870 
 871 describe Aspect, "#unadvise clean up when all advices have been removed" do
 872   before(:all) do
 873     @advice = Proc.new {}
 874     @aspect1 = @aspect2 = nil
 875   end
 876 
 877   def check_cleanup before_methods, before_class_variables
 878     after  = yield
 879     (after[0] - before_methods).should_not == []
 880     (after[1] - before_class_variables).should_not == []
 881     @aspect1.unadvise
 882     after  = yield
 883     (after[0] - before_methods).should_not == []
 884     (after[1] - before_class_variables).should_not == []
 885     @aspect2.unadvise
 886     after  = yield
 887     (after[0] - before_methods).should == []
 888     (after[1] - before_class_variables).should == []
 889   end
 890   
 891   it "should remove all advice overhead for pointcut-based aspects." do
 892     before_methods = Aquarium::FooForPrivateCheck.private_instance_methods.sort
 893     before_class_variables = Aquarium::FooForPrivateCheck.class_variables.sort
 894     @aspect1 = Aspect.new(:before, :pointcut => {:type => Aquarium::FooForPrivateCheck, :method_options => :exclude_ancestor_methods}) {|jp, obj, *args| true}
 895     @aspect2 = Aspect.new(:after,  :pointcut => {:type => Aquarium::FooForPrivateCheck, :method_options => :exclude_ancestor_methods}) {|jp, obj, *args| true}
 896     check_cleanup(before_methods, before_class_variables) do
 897       [Aquarium::FooForPrivateCheck.private_instance_methods.sort, Aquarium::FooForPrivateCheck.class_variables.sort]
 898     end
 899   end
 900   
 901   it "should remove all advice overhead for type-based aspects." do
 902     before_methods = Aquarium::FooForPrivateCheck.private_instance_methods.sort
 903     before_class_variables = Aquarium::FooForPrivateCheck.class_variables.sort
 904     @aspect1 = Aspect.new(:before, :type => Aquarium::FooForPrivateCheck, :method_options => :exclude_ancestor_methods) {|jp, obj, *args| true}
 905     @aspect2 = Aspect.new(:after,  :type => Aquarium::FooForPrivateCheck, :method_options => :exclude_ancestor_methods) {|jp, obj, *args| true}
 906     check_cleanup(before_methods, before_class_variables) do
 907       [Aquarium::FooForPrivateCheck.private_instance_methods.sort, Aquarium::FooForPrivateCheck.class_variables.sort]
 908     end
 909   end
 910 
 911   it "should remove all advice overhead for object-based aspects." do
 912     object = Aquarium::FooForPrivateCheck.new
 913     before_methods = object.private_methods.sort
 914     before_class_variables = (class << object; self.class_variables.sort; end)
 915     @aspect1 = Aspect.new(:before, :object => object, :method_options => :exclude_ancestor_methods) {|jp, obj, *args| true}
 916     @aspect2 = Aspect.new(:after,  :object => object, :method_options => :exclude_ancestor_methods) {|jp, obj, *args| true}
 917     check_cleanup(before_methods, before_class_variables) do
 918       [object.private_methods.sort, (class << object; self.class_variables.sort; end)]
 919     end
 920   end
 921 end
 922 
 923 %w[public protected private].each do |protection|
 924   describe Aspect, " when advising and unadvising #{protection} methods" do
 925     it "should keep the protection level of the advised methods unchanged." do
 926       meta   = "#{protection}_instance_methods"
 927       method = "#{protection}_watchful_method"
 928       Watchful.send(meta).should include(method)
 929       aspect = Aspect.new(:after, :type => Watchful, :method => method.intern, :method_options => [protection.intern]) {|jp, obj, *args| true }
 930       Watchful.send(meta).should include(method)
 931       aspect.unadvise
 932       Watchful.send(meta).should include(method)
 933     end
 934   end  
 935 end
 936 
 937 
 938 describe Aspect, " when unadvising methods for instance-type pointcuts for type-defined methods" do
 939   class TypeDefinedMethodClass
 940     def inititalize; @called = false; end
 941     def m; @called = true; end
 942     attr_reader :called
 943   end
 944   
 945   it "should cause the object to respond to the type's original method." do
 946     object = TypeDefinedMethodClass.new
 947     aspect = Aspect.new(:before, :object => object, :method => :m) {true}
 948     aspect.unadvise
 949     object.m
 950     object.called.should be_true
 951   end
 952 end
 953 
 954 describe Aspect, " when unadvising methods for instance-type pointcuts for instance-defined methods" do
 955   class InstanceDefinedMethodClass
 956     def inititalize; @called = false; end
 957     attr_reader :called
 958   end
 959   
 960   it "should cause the object to respond to the object's original method." do
 961     object = TypeDefinedMethodClass.new
 962     def object.m; @called = true; end
 963     aspect = Aspect.new(:before, :object => object, :method => :m) {true}
 964     aspect.unadvise
 965     object.m
 966     object.called.should be_true
 967   end
 968 end
 969 
 970 describe Aspect, " when advising methods with non-alphanumeric characters" do
 971   module Aquarium::Aspects
 972     class ClassWithMethodNamesContainingOddChars
 973       @@method_names = []
 974       %w[= ! ?].each do |s|
 975         @@method_names << "_a#{s}" << "a#{s}"
 976       end
 977       %w[+ - * / < << > >> =~ == === <=> % ^ ~ [] & | `].each do |s|
 978         @@method_names << s 
 979       end
 980       @@method_names.each do |s|
 981         class_eval(<<-EOF, __FILE__, __LINE__)
 982           def #{s}; "#{s}"; end
 983         EOF
 984       end
 985       def self.method_names; @@method_names; end
 986     end
 987   end
 988   it "should work with any valid ruby character" do
 989     actual = ""
 990     Aspect.new :before, :type => Aquarium::Aspects::ClassWithMethodNamesContainingOddChars, 
 991       :methods => Aquarium::Aspects::ClassWithMethodNamesContainingOddChars.method_names do |jp, obj, *args|
 992       actual += ", #{jp.method_name}"
 993     end
 994     object = Aquarium::Aspects::ClassWithMethodNamesContainingOddChars.new
 995     expected = ""
 996     Aquarium::Aspects::ClassWithMethodNamesContainingOddChars.method_names.each do |s|
 997       object.send s
 998       expected += ", #{s}"
 999     end
1000     actual.should == expected
1001   end
1002 end
1003 
1004 describe Aspect, "#eql?" do
1005   before(:all) do
1006     @advice = Proc.new {}
1007   end
1008   after(:each) do
1009     @aspect1.unadvise
1010     @aspect2.unadvise
1011   end
1012   
1013   it "should return true if both aspects have the same specification and pointcuts." do
1014     @aspect1 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, :advice => @advice 
1015     @aspect2 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, :advice => @advice 
1016     @aspect1.should eql(@aspect2)
1017   end
1018 
1019   it "should return true if both aspects have the same specification and pointcuts, even if the advice procs are not equal." do
1020     @aspect1 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do true end
1021     @aspect2 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do false end
1022     @aspect1.should eql(@aspect2)
1023   end
1024 
1025   it "should return false if each aspect advises pointcuts in different objects, even if the the objects are equivalent." do
1026     @aspect1 = Aspect.new :before, :pointcut => {:object => Watchful.new, :methods => :public_watchful_method} do true end
1027     @aspect2 = Aspect.new :before, :pointcut => {:object => Watchful.new, :methods => :public_watchful_method} do false end
1028     @aspect1.should_not eql(@aspect2)
1029   end
1030 end
1031 
1032 describe Aspect, "#==" do
1033   before(:all) do
1034     @advice = Proc.new {}
1035   end
1036   after(:each) do
1037     @aspect1.unadvise
1038     @aspect2.unadvise
1039   end
1040   
1041   it "should be equivalent to #eql?." do
1042     @aspect1 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, :advice => @advice
1043     @aspect2 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, :advice => @advice
1044     @aspect1.specification.should == @aspect2.specification
1045     @aspect1.pointcuts.should == @aspect2.pointcuts
1046     @aspect1.should eql(@aspect2)
1047     @aspect1.should == @aspect2
1048   end
1049 end
1050 
1051 describe Aspect, "#advice_chain_inspect" do
1052   it "should return the string '[nil]' if passed a nil advice chain" do
1053     Aspect.advice_chain_inspect(nil).should == "[nil]"
1054     chain = NoAdviceChainNode.new({:aspect => nil}) 
1055     Aspect.advice_chain_inspect(chain).should include("NoAdviceChainNode")
1056   end
1057 end
1058 
1059 def all_public_methods_of_type type
1060   (type.public_methods + type.public_instance_methods).sort
1061 end
1062 def all_protected_methods_of_type type
1063   (type.protected_methods + type.protected_instance_methods).sort
1064 end
1065 def all_public_methods_of_object object
1066   object.public_methods.sort
1067 end
1068 def all_protected_methods_of_object object
1069   object.protected_methods.sort
1070 end
1071 
1072 def do_watchful_public_protected_private raises = false, expected_advice_called_value = 1, args_passed_to_proceed = nil
1073   %w[public protected private].each do |protection|
1074     do_watchful_spec protection, raises, expected_advice_called_value, args_passed_to_proceed
1075   end
1076 end
1077 
1078 def do_watchful_spec protection, raises, expected_advice_called_value, args_passed_to_proceed
1079   suffix = raises ? "_that_raises" : ""
1080   expected_advice_called = protection == "public" ? expected_advice_called_value : 0
1081   watchful = Watchful.new
1082   @advice_called = 0
1083   block_called = 0
1084   if raises
1085     lambda {watchful.send("#{protection}_watchful_method#{suffix}".intern, :a1, :a2, :a3) {|*args| block_called += 1}}.should raise_error(Watchful::WatchfulError)
1086   else
1087     watchful.send("#{protection}_watchful_method#{suffix}".intern, :a1, :a2, :a3) {|*args| block_called += 1}
1088   end
1089   @advice_called.should == expected_advice_called
1090   block_called.should == 1
1091   expected_args = (protection == "public" && !args_passed_to_proceed.nil?) ? args_passed_to_proceed : [:a1, :a2, :a3]
1092   watchful.instance_variable_get("@#{protection}_watchful_method#{suffix}_args".intern).should == expected_args
1093 end

Generated using the rcov code coverage analysis tool for Ruby version 0.8.1.2.

Valid XHTML 1.0! Valid CSS!