ae-1.8.2/0000755000000000000000000000000012406706117010611 5ustar rootrootae-1.8.2/NOTICE.md0000644000000000000000000000402112406706117012111 0ustar rootroot# COPYRIGHT NOTICES ## AE Copyright:: (c) 2008 Thomas Sawyer License: BSD-2-Clause Copyright 2008 Thomas Sawyer. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY Thomas Sawyer ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Thomas Sawyer OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Thoams Sawyer. ## BlankSlate Copyright:: (c) 2004,2006 Jim Weirich License:: Custom AE::BasicObject is based on Jim Weirich's BlankSlate class. Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org). All rights reserved. Permission is granted for use, copying, modification, distribution, and distribution of modified versions of this work as long as the above copyright notice is included. ae-1.8.2/metadata.yml0000644000000000000000000000534612406706117013124 0ustar rootroot--- !ruby/object:Gem::Specification name: ae version: !ruby/object:Gem::Version version: 1.8.2 prerelease: platform: ruby authors: - Trans autorequire: bindir: bin cert_chain: [] date: 2013-02-18 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: ansi requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: detroit requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: qed requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' description: ! "Assertive Expressive is an assertions library specifically designed \nfor reuse by other test frameworks." email: - transfire@gmail.com executables: [] extensions: [] extra_rdoc_files: - DEMO.rdoc - HISTORY.md - README.md - NOTICE.md files: - .ruby - .yardopts - lib/ae/adapter.rb - lib/ae/adapters/minitest.rb - lib/ae/adapters/rspec.rb - lib/ae/adapters/testunit.rb - lib/ae/ansi.rb - lib/ae/assert.rb - lib/ae/assertion.rb - lib/ae/assertor.rb - lib/ae/basic_object.rb - lib/ae/check.rb - lib/ae/core_ext/exception.rb - lib/ae/core_ext/helpers.rb - lib/ae/core_ext.rb - lib/ae/expect.rb - lib/ae/legacy.rb - lib/ae/must.rb - lib/ae/pry.rb - lib/ae/should.rb - lib/ae/subjunctive.rb - lib/ae/version.rb - lib/ae.rb - lib/ae.yml - DEMO.rdoc - HISTORY.md - README.md - NOTICE.md homepage: http://rubyworks.github.com/ae licenses: - BSD-2-Clause post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 1.8.24 signing_key: specification_version: 3 summary: Assertive Expressive test_files: [] has_rdoc: ae-1.8.2/HISTORY.md0000644000000000000000000001514112406706117012276 0ustar rootroot# RELEASE HISTORY ## 1.8.2 / 2013-02-18 This release primarily fixes one bug --the assertions count global variable wasn't all caps, which prevented assertions from being counted correctly. Changes: * Fix $ASSERTION_COUNTS letter case. ## 1.8.1 / 2011-12-04 Fixed missing ae/ansi.rb file from distribution. Changes: * Update manifest, missing ae/ansi.rb ## 1.8.0 / 2011-12-03 / Checkered Flag This new release improves support for Proc-based assertions and RSpec-style matchers. In addition, this release sees the optional Check Ok/No library in a usable state. And, lastly, note the license has been changed to BSD-2-Clause. Changes: * Finalize the Check mixin API. * Improve Proc and RSpec-style matchers. * Modernize the build configuration. * Change licenses to BSD-2-Clause. ## 1.7.4 / 2011-06-08 Quick release fixes an issue due to Ruby 1.9+'s constant look-up system. Yes, BasicObject has no clue. This is fixed using the `const_missing` hook. Changes: * Add const_missing hook to Assertor class to redirect to toplevel methods. ## 1.7.3 / 2011-06-06 / D-Day This release simply adds a new optional help library, `ok.rb`. The API is still in it's infancy, so it probably will change but this early release can help refine it's development. Changes: * Add option `ok` helper library. ## 1.7.2 / 2011-06-02 Minor release adds color diffs for failed equality comparisons to the error message, and it fixes an issue in which class references needed the toplevel prefix (`::`) to ensure they can be found in all cases. Note that ANSI color diffs can be deactivated via AE.ansi = false or using the master switch an upcoming release of the ANSI gem. Changes: * Add toplevel prefix (`::`) to class references in assertor.rb. * Provide ANSI colored diffs for failed equality comparisons. ## 1.7.1 / 2011-05-06 This release adds a specialized message for certain comparison operators to allow them have a more forensic output. This is done via ANSI::Diff library. This release also deprecates the optional dot.rb and detest.rb emulation scripts. Changes: * Add special message for comparison assertions. * Remove optional dot.rb and detest.rb emulation scripts. ## 1.7.0 / 2011-04-28 AE now uses proper namespace for all classes. In particular, the `Assertor` class has become `AE::Assertor`. Only the `Assertion` class remains outside the `AE` namespace, as it is now used to map to the current exception class for raising assertions as defined by current test framework. In addition, AE's Kernel extensions, which are used to adapt AE for use with any given test framework have been moved to the AE and AE::Assertor classes as class methods along with AE's assertion count methods. Changes: * All AE classes use proper namespace. * Framework methods moved to AE::Assertor class. * Assertion count tracking methods moved to AE::Assertor class. * AE::Assertion class simplified to a simple subclass of Exception. ## 1.6.1 / 2010-11-05 This release has test passing for Ruby 1.9.2. Ruby 1.9.2 doesn't appear to like &block and block_given? to be used in same method scope. It may be a Ruby bug, nonetheless AE has been adjusted to circumvent the problem. Changes: * Use `&block` and not `block_given?`. ## 1.6.0 / 2010-11-04 Support libraries defining toplevel methods, such as `legacy.rb`, now place their methods in AE::World module instead of Object. AE::World needs to to be included in the context desired for the testing framework used. This is important to prevent pollution of the Object namespace. Changes: * Toplevel extras are defined in AE::World instead of Object. * In dot.rb #true/#false methods renamed to `#true!`/`#false!`. * In dot.rb `#true!`/`#false!` methods can take an error or error message. ## 1.5.0 / 2010-09-06 This release adds adapters for TestUnit, MiniTest and RSpec. AE worked with them previously but AE assertions were seen as errors rather than nice assertions. Likewise assertion counts were off in the final tally. These adapters insert AE's counts so the tally are correct. In addition to this the Assertion class itself now acts as the final end point for all assertions, which makes for a very clean interface. Changes: * Add adapters for TestUnit, MiniTest and RSpec. * Move final assertion call to Assertion#test. ## 1.4.0 / 2010-09-02 Version 1.4 brings Ruby 1.9 compatibility. The Assertor class is now a subclass of BasicObject. This fixes an issues Assertor would had applying to methods defined both in a class and Kernel. Changes: * Assertor is a subclass of BasicObject. * Use custom BasicObject when using Ruby 1.8. * Add #assert= which works like `assert ==`. * Add #refute= which works like `refute ==`. ## 1.3.0 / 2010-06-17 New release of AE adds support for RSpec-style matchers. This means it should be usable with Shoulda 3.0 and any other matchers library. This release also cleans up the underlying code, which is now extremely clean. Lastly a small API change allows #assert to compare it's argument to the return of it's block using #==, just as #expect does using #===. Changes: * Add RSpec-style matchers support. * Move #expect code to Assertor. * #assert method can do equality comparison. ## 1.2.3 / 2010-06-07 This release is a quick fix, which adds a missing `require 'yaml'`. Changes: * Add missing require 'yaml'. ## 1.2.2 / 2010-06-06 Version 1.2.2 simply add one new feature --the ability to use 'object.assert = other' instead of 'object.assert == other'. This was added simply because I found I often made the mistake of a missing '=', and since #assert= has no definition, there was no reason not to have behave accordingly. Also note that I switched the license from LGPL to MIT. With regards to reusable libraries and I moving all my work, such that I am able, to MIT to maximize free usage. Changes: * Add `#assert=` method as a shortcut for `#assert ==`. * Now distributed under MIT license. ## 1.2.0 / 2010-01-27 This release fixes '=~' assertions and now requires the ae/expect library by default. Changes: * Expect method is now loaded by default when requiring 'ae'. * Fixed bug where #=~ did not work correctly against Assertor. ## 1.1.0 / 2009-09-06 This release provided two major improvements. The first is the #expect method which is similar to #assert, but uses case equality (#===) for comparison. And second, an optional library `ae/legacy.rb`, is has been added that provides backward compatibility with Test::Unit assertions, should it be needed. Changes: * New #expect method. * Proved legacy assertion in optional ae/legacy.rb library. * Added backtrace parameter to flunk calls. ## 1.0.0 / 2009-09-03 This is the initial release of AE. Changes: * Happy Birthday! ae-1.8.2/DEMO.rdoc0000644000000000000000000004111412406706117012207 0ustar rootroot= Introduction AE is an assertions framework for Ruby. It's designed around the concept of an Assertor. The Assertor is an Assertion Functor, or Higher-Order Function, which reroutes method calls while monitoring them for failing conditions. == What AE Provides Requiring the AE library. require 'ae' Loads two classes, +Assertion+ and +Assertor+, the Kernel method +assert+ and it's antonyms +assert!+ and +refute+ and a set of core extensions that make writing certain types of assertions easier. == Assertion and Assertor Classes The +Assertion+ class is at the heart of AE. All other AE methods depend on it. The +Assertion+ class is a subclass of Exception. When an assertion is made and fails, it is an instance of Assertion that is raised. expect Assertion do msg = "my failure message" assert false, msg end Like any raised exception, the last Assertion message is available via $!. (FYI, in Test::Unit the equivalent class was called +AssertionFailedError+.) Assertions themselves are not generally used in creating tests or behavior specifications. Rather they are used to create additional types of assertion methods. As mentioned above the +Assertor+ class is a type of Higher-Order function, or Functor, which intercedes with a normal message invocation to monitor for failed conditions, upon which is raises Assertion exceptions. == Assertion Methods The three methods, +assert+, assert! and +refute+ all return an Assertor instance when used fluidly, i.e. magic-dot notation, higher-order notation, functor notation, whatever you prefer to call it. assert(AE::Assertor === assert) Through the use of +method_missing+, the Assertor allows us to write statements like: 1.assert == 1 If the operation evaluates to false or nil, then an Assertion error is raised. expect Assertion do 1.assert == 2 end The methods assert! and +refute+ are just like +assert+ expect they purport the negative condition. Patterned after Ruby's own use of "!" as meaning +not+, assert! should be read "assert not". While +refute+ exists for the sake of those who find the use of a bang method for this purpose unsuited to them. == How It Works An Assertor essentially sits in wait for a method call (via method_missing). When that happens it applies the method to the original receiver, but wrapped in a clause that raises an Assertion should the statement fail. If we wanted to be pedantic, we could write our assertions like: raise Assertion.new("1 != 1") unless 1 == 1 Instead of 1.assert == 1 Obviously using Assertor methods are whole lot more concise. = Assertion Class The Assertion class is a subclass of Exception and is the error raised when and assertion fails. = Assert Method == Compatible with Test::Unit The +assert+ method is designed to be backward compatible with the same method in Test::Unit. Using an argument, +assert+ will check that an argument evaluates to true. Optionally one can send along a meaningful message should the assertion fail. assert(true, "Not true!") expect Assertion do assert(false, "Not true!") end == Assert with a Block In addition +assert+ has been extended to accept a block. Like the case of the argument, the block is expected to return something that evaluates as true. assert do true end Assertion.assert.raised? do assert do false end end We should also mention that, while probably not very useful, since the arity of a block can be checked, one can also pass the receiver into the block as a block argument. "hi".assert do |s| /h/ =~ s end == Antonyms for Assert We can state the opposite assertion using assert!. 10.assert! == 9 Or, because some people do not like the use of a bang method, +refute+. 10.refute == 9 These terms can be used just as +assert+ is used in all examples, but with the opposite inference. Another way to get the opposite inference, is to use +not+. 10.assert.not == 9 == Lambda Assertions Passing +assert+ a `Proc` object, or any object that responds to `#call`, will be used as if it were a block. This allows for a simple way to quickly create reusable assertions. palindrome = lambda{ |word| word == word.reverse } "abracarba".assert palindrome The message for a failed assertion will come from calling `#to_s` on the object. == RSpec-style Assertion Matchers If an object passed to assert responds to `#matches?` then AE will handle the object as an RSpec-style mather, the receiver will be passed to the `#matches?` method to determine if the assertion passes and RSpec matcher message methods will be used if they are defined. palindrome = Object.new def palindrome.matches?(word) word == word.reverse end "abracarba".assert palindrome == Identity Assertions Rather then the general form. x = 10 x.assert.object_id == x.object_id We can use Ruby's own equal? method. x.assert.equal?(x) AE provides identical? method as an alternative to make it a bit more clear. x.assert.identical?(x) == Equality Assertions The most common assertion is that of value equality (==), as we have seen throughout this document. But other forms of equality can be verified as easily. We have already mentioned identity. In addition there is type equality. 17.assert.eql? 17 Assertion.assert.raised? do 17.assert.eql? 17.0 end And there is case equality. Numeric.assert === 3 == Checking Equality with a Block Because operators can not take blocks, and at times blocks can be convenient means of supplying a value to an assertion, AE has defined alternate renditions of the equality methods. For equal? and eql?, the method names are the same, they simply can take a block in place of an argument if need be. For value equality (==), the method is called eq?. 10.assert.eq? do 10.0 end And should it fail... Assertion.assert.raised? do 10.assert.eq? do 20 end end == Case Equality For case equality (===), it is case?. Numeric.assert.case? do "3".to_i end Assertion.assert.raised? do Numeric.assert.case? do "3" end end == Regular Expressions Regular Expressions can be used to make assertions in much the same way as equality. /i/.assert =~ "i" Assertion.assert.raised? do /i/.assert =~ "g" end Conversely the String class recognizes the #=~ method as well. "i".assert =~ /i/ Assertion.assert.raised? do "i".assert =~ /g/ end == Exception Assertions Validating errors is easy too, as has already been shown in the document to verify assertion failures. StandardError.assert.raised? do unknown_method end == Assertions on Object State While testing or specifying the internal state of an object is generally considered poor form, there are times when it is necessary. Assert combined with +instance_eval+ makes it easy too. class X attr :a def initialize(a); @a = a; end end x = X.new(1) x.assert.instance_eval do @a == 1 end == Catch/Try Assertions Catch/Try throws can be tested via Symbol#thrown?. :hookme.assert.thrown? do throw :hookme end Alternatively, a lambda containing the potential throw can be the receiver using throws?. hook = lambda{ throw :hookme } hook.assert.throws?(:hookme) == Assertions on Proc Changes I have to admit I'm not sure how this is useful, but I found it in the Bacon API and ported it over just for sake of thoroughness. a = 0 l = lambda{ a } l.assert.change?{ a +=1 } == Assertion on literal True, False and Nil Ruby already provides the #nil? method. nil.assert.nil? AE adds true? and false? which acts accordingly. true.assert.true? false.assert.false? == Send Assertions Assert that a method can be successfully called. "STRING".assert.send?(:upcase) == Numeric Delta and Epsilon You may wish to assert that a numeric value is with some range. 3.in_delta?(1,5) Or minimum range. 3.in_epsilon?(3,5) == Verifying Object State Not surprisingly if underlying object state needs to be verified, +instance_eval+ can be used in conjunction with +assert+. class X attr :a def initialize(a); @a = a; end end x = X.new(4) x.instance_eval do @a.assert == 4 end However #instance_eval is a reserved method for the underlying Assertor class, so it cannot be used on #assert, e.g. x.assert.instance_eval do @a == "obvisouly wrong" end AE offers an optional helper method for times when testing underlying private or protected methods is important, called #pry. See the QED on pry for more information. For some testing underlying implementation might be considered poor form. You will get no argument here. It should be used thoughtfully, but I would not bet against there being occasions when such validations might be needed. = Subjunctives Okay. I can hear the BDDers rumbling, "where's the *should?*" AE has nothing against "should", but there are different approaches for utilizing should nomenclature in specifications, and AE wants to be open to these techniques. One of which is how Shoulda (http://shoulda.rubyforge.org) utilizes +should+ in a way analogous to RSpec's use of +it+. Even so, AE provides an optional mixin called +Subjunctive+ which can be used to create assertor methods with English subjunctive terms, such as +should+, or +must+, +shall+ and +will+. To load this library use: require 'ae/subjunctive' Then all that is required it to define a subjunctive method for all objects. For example: def will(*args, &block) Assertor.new(self, :backtrace=>caller).be(*args,&block) end It's that easy. Because of their commonality AE provides two such terms, +should+ and +must+ as optional add-ons out-of-the-box. require 'ae/should' require 'ae/must' We will use these two methods interchangeable for the rest of this demonstration, but to be clear they both work exactly the same way, and almost exactly like +assert+. Keep in mind, AE "conical" functionality does not entail the subjunctive forms. These are simply options you can load via your test_helper.rb, or similar script, if you prefer these nomenclatures. == Fluent Notation and Antonyms Like +assert+, +should+ and +must+ can be used as higher order functions. 4.should == 4 4.must == 4 Antonyms provided for +should+ as should! (read "should not") and +shouldnt+. For +must+ +must+, they are must! and +wont+. 4.should! == 5 4.shouldnt == 5 4.must! == 5 4.wont == 5 == To Be On occasions where the English readability of a specification is hindered, +be+ can be used. StandardError.must.be.raised? do unknown_method end The +be+ method is the same as +assert+ with the single exception that it will compare a lone argument to the receiver using +equate?+, unlike +assert+ which simply checks to see that the argument evaluates as true. 10.should.be 10 10.should.be 10.0 10.should.be Numeric Assertion.assert.raised? do 10.should.be "40" end == Indefinite Articles Additional English forms are +a+ and +an+, equivalent to +be+ except that they use case? (same as #===) instead of equate? when acting on a single argument. "hi".must.be.a String Assertion.assert.raised? do /x/.must.be.a /x/ end Otherwise they are interchangeable. "hi".must.be.an.instance_of?(String) The indefinite articles work well when a noun follows as an arguments. palindrome = lambda{ |x| x == x.reverse } "abracarba".must.be.a palindrome = Expect Method Expect is another assertion nomenclature available for use in your tests or specifications. Inspired by Jay Fields' Expectations library, it provides convenient syntax for creating exception and case equality assertions. require 'ae/expect' == Underlying Comparison Expect uses #=== for comparison. So providing an argument and a block to #expect we can test for a somewhat broader range of compassion than #assert. For example we can test for a subclass. expect Numeric do 3 end Assertion.assert.raised? do expect Numeric do "3" end end == Exception Expectation If the comparator is an Exception class or a instance of an Exception class, then #expect will check to see if the block raises that kind of exception. expect StandardError do some_undefined_method end expect Assertion do expect(nil) end This is an important distinction to note because it means #expect can not be used if verify instances of Exception classes. Assertion.assert.raised? do expect Exception do Exception.new end end == Regex Expectations That #expect entails #=== also means we can check for Regexp matches. expect /x/ do "oooxooo" end == Expected Method We can use #expected to make the receiver the object of expectation. x = "dummy" /x/.expected do "x" end == Without Block Without a block, the receiver is compared to the argument. x.expect String == Negative Forms Like #assert, #expect has a negated form called #expect! expect! /x/ do "o" end The pure word form for those who do not like the clever use of the explimation mark is #forbid. forbid /x/ do "o" end == Functor, or Higher Order Function Like #assert, #expect can be used used as a *fluid* notation. 10.expect == 10 In which case it works just like #assert, including negative forms. 10.expect! == 11 10.forbid == 11 = Assertion Counts AE tracks the number of assertions made and the number that failed to pass. We can reset the count using the +recount+ class method. old_counts = AE::Assertor.recount For example if we have one assertion pass and another fail. assert(true) expect Assertion do assert(false) end We will see that AE counted three assertions and one failure. counts = AE::Assertor.counts.dup counts[:total].assert == 3 counts[:pass].assert == 2 counts[:fail].assert == 1 The #expect call is an assertion too, which is why the total count is 3 rather than 2. Now that we are done checking counts we will restore them so that any other demos being run with this will tally correctly. AE::Assertor.recount(old_counts) AE::Assertor.counts[:total] += 3 AE::Assertor.counts[:pass] += 3 = Matchers Matchers are simply Procs or objects with the proper interface that can be passed to #assert or #refute (or other Assertor) as an ecapsulated test. == Proc or #to_proc Passing a Proc object or an object that responds to :to_proc, will use it as if it were a block of the method. This allows for a simple way to quickly create reusable assertions. palindrome = lambda{ |word| word == word.reverse } "abracarba".assert palindrome == #matches? Additionally if an object responds to #matches? then the receiver will be passed to this method to determine if the assertion passes. palindrome = Object.new def palindrome.matches?(word) word == word.reverse end "abracarba".assert palindrome == RSpec, Shoulda and other 3rd-Party Matchers With tha addition of #matches?, AE supports the same interface for matchers as RSpec. Any matcher library designed for use with RSpec should therefore be usable with AE as well. This includes RSpecs own matchers and Shoulda's excellent Rails matchers. == Check Ok/No The Check library is an optional library that can be used to conveniently speed-up construction of reptitive assertions. To use it, first require the library, then include the mixin into the namespace in which you will utilize it. require 'ae/check' include AE::Check Now we can define ok/no check procedures. A one-off procedure is defined with a block only. check do |x, y| x == y end ok 1,1 no 1,2 To define reusable check procedures, give the procedure a name. check :palindrome do |x| x.reverse == x end This will also cause the current check method to be set. Later in the code, the check procedure can be reset to this by just passing the name. check :palindrome ok 'abracarba' no 'foolishness' The Check mixin comes preloaded with a few standard checks. By default the `:equality` procedure is used. check :equality ok 1=>1.0 Notice the use of the hash argument here. This is a useful construct for many check procedures becuase it it akin to the `#=>` pattern we often see in code examples and it also allows for multiple assertions in one call. For instance, in the case of `:equality`, multiple entries convey a meaning of logical-or. ok 1=>2, 1=>1 This would pass becuase the second assertion of equality is true. Another built in check is `:case_equality` which uses `#===` instead of `#==` to make the comparison. check :case_equality ok 1=>Integer ae-1.8.2/.yardopts0000644000000000000000000000007012406706117012454 0ustar rootroot--title "AE API" --protected --private lib/ - [A-Z]*.* ae-1.8.2/.ruby0000664000000000000000000000000012406706117011563 0ustar rootrootae-1.8.2/README.md0000644000000000000000000001143512406706117012074 0ustar rootroot# Assertive Expressive [Homepage](http://rubyworks.github.com/ae) / [Source Code](http://github.com/rubyworks/ae) / [Documentation](http://rubydoc.info/gems/ae) / [User Manual](http://wiki.github.com/rubyworks/ae) / [Report Issue](http://github.com/rubyworks/ae/issues) / [Mailing List](http://googlegroups.com/group/rubyworks-mailinglist) / [IRC Channel](irc://irc.freenode.net/rubyworks)     [![Build Status](https://secure.travis-ci.org/rubyworks/qed.png)](http://travis-ci.org/rubyworks/ae) [![Gem Version](https://badge.fury.io/rb/qed.png)](http://badge.fury.io/rb/ae) ## About Assertive Expressive (AE) is an assertions framework intended for reuse by any TDD, BDD or similar system. ## Features * Clear, simple and concise syntax. * Uses higher-order functions and fluid notation. * Reusable core extensions ease assertion construction. * Core extensions are standardized around Ruby Facets. * But Facets is not a dependency; the extensions are built-in. * Easily extensible allowing for alternate notations. * Eats it's own dog food. ## Synopsis AE defines the method `assert`. It's is compatible with the method as defined by Test::Unit and MiniTest, which verifies truth of a single argument (and can accept an optional failure message). assert(true) In addition AE's `assert` method has been extended to accept a block, the result of which is likewise verified. assert{true} But the real power the AE's +assert+ method lies in it's use without argument or block. In that case it returns an instance of `Assertor`. An `Assertor` is an *Assertions Functor*, or *Higher-Order Function*. It is a function that operates on another function. With it, we can make assertions like so: x.assert == y a.assert.include? e StandardError.assert.raised? do ... end And so forth. Any method can be used in conjunction with +assert+ to make an assertion. Eg. class String def daffy? /daffy/i =~ self end end "Daffy Duck".assert.daffy? When an assertion fails an Assertion exception is raised. Any test framework can catch this exception and process it accordingly. Technically the framework should check to see that the exception object responds affirmatively to the #assertion? method. This way any type of exception can be used as a means of assertion, not just AE's Assertion class. Please have a look at the QED and API documentation to learn more. ## Integration Generally speaking, AE can be used with any test framework simply by putting `require 'ae'` in a test helper script. However to fully integrate with a test framework and ensure the test framework recognizes AE assertions (as more than just exceptions) and to ensure assertion counts are correct, a little extra interfacing code may be necessary. Lucky for you AE has already done the leg work for the most common test frameworks: require 'ae/adapters/testunit' require 'ae/adapters/minitest' require 'ae/adapters/rspec' (Note that Cucumber does not need an adapter.) AE also includes a script that will automatically detect the current test framework by checking for the existence of their respective namespace modules. require 'ae/adapter' ## Nomenclature With AE, defining assertions centers around the #assert method. So *assert* can be thought of as AE's primary _nomenclature_. However, variant nomenclatures have been popularized by other test frameworks, in particular *should* and *must*. If you prefer one of them terms, AE provides optional libraries that can loaded for utilizing them. require 'ae/should' require 'ae/must' By loading one of these scripts (or both) into your test system (e.g. via a test helper script) you gain access to subjunctive terminology. See the API documentation for the Subjunctive module for details. ## Legacy To ease transition from TestUnit style assertion methods, AE provides a TestUnit legacy module. require 'ae/legacy' This provides a module `AE::Legacy::Assertions` which is included in AE::World and can be mixed into your test environment to provide old-school assertion methods, e.g. assert_equal(foo, bar, "it failed") ## Installation ### Gem Installs Install AE in the usual fashion: $ gem install ae ### Site Installs Local installation requires Setup.rb. $ gem install setup Then download the tarball package from GitHub and do: $ tar -xvzf ae-1.0.0.tgz $ cd ae-1.0.0.tgz $ sudo setup.rb all Windows users use 'ruby setup.rb all'. ## Copyrights & License Copyright (c) 2008 Rubyworks. All rights reserved. Unless otherwise provided for by the originating author, this program is distributed under the terms of the *BSD-2-Clause* license. Portions of this program may be copyrighted by others. See the NOTICE.rdoc file for details. AE is a [Rubyworks](http://rubyworks.github.com) project. ae-1.8.2/lib/0000755000000000000000000000000012406706117011357 5ustar rootrootae-1.8.2/lib/ae.rb0000644000000000000000000000124612406706117012274 0ustar rootrootmodule AE # TODO: Should we really be reseting a constant for ::Assertion? # How about using a variable instead? # Set Assertion class. This is a convenience method # for framework adapters, used to set the exception class # that a framework uses to raise an assertion error. # # @param [Class] exception_class # The Exception subclass used to raise assertions. # def self.assertion_error=(exception_class) verbose, $VERBOSE = $VERBOSE, nil Object.const_set(:Assertion, exception_class) $VERBOSE = verbose end end require 'ae/version' require 'ae/assert' require 'ae/expect' class ::Object include AE::Assert include AE::Expect end ae-1.8.2/lib/ae.yml0000644000000000000000000000224412406706117012471 0ustar rootroot--- revision: 2013 type: ruby sources: - var authors: - name: Trans email: transfire@gmail.com organizations: [] requirements: - name: ansi - groups: - build development: true name: detroit - groups: - test development: true name: qed conflicts: [] alternatives: [] resources: - type: home uri: http://rubyworks.github.com/ae label: Homepage - type: code uri: http://github.com/rubyworks/ae label: Source Code - type: docs uri: http://rubydoc.info/gems/ae label: Documentation - type: wiki uri: http://wiki.github.com/rubyworks/ae label: User Guide - type: bugs uri: http://github.com/rubyworks/ae/issues label: Issue Tracker - type: mail uri: http://groups.google.com/group/rubyworks-mailinglist label: Mailing List repositories: - name: upstream scm: git uri: git://github.com/rubyworks/ae.git categories: [] copyrights: - holder: Rubyworks year: '2008' license: BSD-2-Clause customs: [] paths: lib: - lib created: '2008-08-17' summary: Assertive Expressive title: AE version: 1.8.2 name: ae description: ! "Assertive Expressive is an assertions library specifically designed \nfor reuse by other test frameworks." date: '2013-02-18' ae-1.8.2/lib/ae/0000755000000000000000000000000012406706117011744 5ustar rootrootae-1.8.2/lib/ae/must.rb0000644000000000000000000000302612406706117013262 0ustar rootrootmodule AE require 'ae/subjunctive' # Must # # "It is not enough to succeed. Others must fail." # --Gore Vidal (1925 - ) # # @note THIS IS AN OPTIONAL LIBRARY. module Must # The #must method is functionaly the same as #should. # # @example # 4.must == 3 #=> Assertion Error # # @example # 4.must do # self == 4 # end # # @return [Assertor] Assertion functor. def must(*args, &block) Assertor.new(self, :backtrace=>caller).be(*args, &block) end # Same as 'object.must == other'. # # @return [Assertor] Assertion functor. def must=(cmp) Assertor.new(self, :backtrace=>caller) == cmp end # Designate a negated expectation via a *functor*. # Read this as "must not". # # @example # 4.must! == 4 #=> Assertion Error # # @return [Assertor] Assertion functor. def must!(*args, &block) Assertor.new(self, :backtrace=>caller).not.be(*args, &block) end # TODO: Are these negation methods needed now, since Ruby 1.9 allows for # redefining `!` as a method? # Perhaps not literally the counter-term to *must* (rather *will*), # but close enough for our purposes, and conveys the appropriate # semantics. alias_method :wont, :must! # Alias for #must! method. alias_method :must_not, :must! # Alias for #must! method. alias_method :mustnt, :must! end end class ::Object #:nodoc: include AE::Must end # Copyright (c) 2008 Thomas Sawyer ae-1.8.2/lib/ae/check.rb0000644000000000000000000000611612406706117013352 0ustar rootrootmodule AE # The Ok mixin is a reusable assertion helper that # makes it easy to construct parameterized assertions # with an elegant syntax. # module Check # The Check::Proc class encapsulates a labeled procedure # for making assertions using the `ok`/`no` methods. # class Proc # Setup new check procedure. def initialize(options={}, &check) @name = options[:name] @message = options[:message] || @name @check = check end # def message(&block) if block @message = message end @message end # def message=(msg) @message = msg end # Call check procedure. def call(*args) @check.call(*args) end # def to_s(*args) case @message when nil @name.to_s when ::Proc @message.call(*args) else # TODO: count %\S and apply `% args.map{|a|a.inspect}[0,count]` @message.to_s end end # def ok!(*args) assert(call(*args), to_s(*args)) end # def no!(*args) refute(call(*args), to_s(*args)) end end # TODO: Better way to customize error message so it can have # arguments in the messages ? # Built-in check procedures. TABLE = { :equality => Check::Proc.new(:message=>"should be equal"){|h| h.any?{|a,b| b==a}}, :case_equality => Check::Proc.new(:message=>"should be equal"){|h| h.any?{|a,b| b===a}} } # def self.table @table ||= TABLE.dup end # Define a univerally available ok/no check. # # AE::Check.define(:palindrome) do |x| # x.reverse == x # end # def self.define(name, &block) table[name] = Check::Proc.new(name, &block) end # def check_table Check.table end # Define an ok/no check procedure. A one-off procedure is defined # with a block. # # check do |x, y| # x == y # end # # ok 1,1 # no 1,2 # # The check method can also be used to define reusable checks. # # check(:palindrome) do |x| # x.reverse == x # end # # This will also cause the current check to be set. # Later in the code, the check procedure can be restored # by just passing the symbolic name. # # check :palindrome # # ok 'abracarba' # no 'foolishness' # def check(name=nil, &block) if name if block check_table[name] = Check::Proc.new(:name=>name, &block) end @__check__ = check_table[name] else #raise ArgumentError if block.arity == 0 @__check__ = Check::Proc.new(&block) end end # def ok(*args) __check__.ok!(*args) end # def no(*args) __check__.no!(*args) end # Returns the current check. def __check__ @__check__ || check_table[:equality] end end end module AE::World # It's upto the test framework to include where needed. include AE::Check end ae-1.8.2/lib/ae/adapter.rb0000644000000000000000000000026212406706117013711 0ustar rootrootif defined?(::MiniTest) require 'ae/adapters/minitest' elsif defined?(::Test::Unit) require 'ae/adapters/testunit' elsif defined?(::RSpec) require 'ae/adapters/rspec' end ae-1.8.2/lib/ae/version.rb0000644000000000000000000000057712406706117013767 0ustar rootrootmodule AE # Access project metadata. # # @return [Hash] def self.metadata @metadata ||= ( require 'yaml' YAML.load(File.new(File.dirname(__FILE__) + '/../ae.yml')) ) end # def self.const_missing(name) key = name.to_s.downcase metadata[key] || super(name) end # Becuase Ruby 1.8~ gets in the way :( VERSION = metadata['version'] end ae-1.8.2/lib/ae/legacy.rb0000644000000000000000000002412412406706117013540 0ustar rootrootmodule AE module Legacy #:nodoc: # Test::Unit Legacy Assertions # # This module provides a compatibility layer for Test::Unit. # This is an optional module and is intended for providing # an easier transition from Test::Unit to AE assertions. # # Note that two methods are not provided, +#assert_nothing_raised+, # and +#assert_nothing_thrown+. # module Assertions # Private method upon which all of the legacy assertions are based # (except for #assert itself). # # @raise [Assertion] If test fails. # # @return nothing def __assert__(test, msg=nil) msg = "failed assertion (no message given)" unless msg raise Assertion.new(msg, :backtrace=>caller[1..-1]) unless test end private :__assert__ # The assertion upon which all other assertions are based. # # @example # assert [1, 2].include?(5) # # @return [Assertor] if `test` not given def assert(test=nil, msg=nil) if test msg = "failed assertion (no message given)" unless msg raise Assertion.new(msg, :backtrace=>caller) unless test else Assertor.new(self, :backtrace=>caller) # TODO: Probably remove this! end end # Passes if the block yields true. # # @example # assert_block "Couldn't do the thing" do # do_the_thing # end # # @raise [Assertion] if test fails # # @return nothing def assert_block(msg=nil) # :yields: test = ! yield msg = "assertion failed" unless msg __assert__(test, msg) end # Passes if expected == +actual. # # Note that the ordering of arguments is important, # since a helpful error message is generated when this # one fails that tells you the values of expected and actual. # # @example # assert_equal 'MY STRING', 'my string'.upcase # # @raise [Assertion] if test fails # # @return nothing def assert_equal(exp, act, msg=nil) test = (exp == act) msg = "Expected #{act.inspect} to be equal to #{exp.inspect}" unless msg __assert__(test, msg) end # Passes if expected_float and actual_float are equal within delta tolerance. # # @example # assert_in_delta 0.05, (50000.0 / 10**6), 0.00001 # # @raise [Assertion] if test fails # # @return nothing def assert_in_delta(exp, act, delta, msg=nil) test = (exp.to_f - act.to_f).abs <= delta.to_f msg = "Expected #{exp} to be within #{delta} of #{act}" unless msg __assert__(test, msg) end # Passes if object .instance_of? klass # # @example # assert_instance_of String, 'foo' # # @raise [Assertion] if test fails # # @return nothing def assert_instance_of(cls, obj, msg=nil) test = (cls === obj) msg = "Expected #{obj} to be a #{cls}" unless msg __assert__(test, msg) end # Passes if object .kind_of? klass # # @example # assert_kind_of Object, 'foo' # # @raise [Assertion] if test fails # # @return nothing def assert_kind_of(cls, obj, msg=nil) test = obj.kind_of?(cls) msg = "Expected #{obj.inspect} to be a kind of #{cls}" unless msg __assert__(test, msg) end # Passes if string =~ pattern. # # @example # assert_match(/\d+/, 'five, 6, seven') # # @raise [Assertion] if test fails # # @return nothing def assert_match(exp, act, msg=nil) test = (act =~ exp) msg = "Expected #{act.inspect} to match #{exp.inspect}" unless msg __assert__(test, msg) end # Passes if object is nil. # # @example # assert_nil [1, 2].uniq! # # @raise [Assertion] if test fails # # @return nothing def assert_nil(obj, msg=nil) test = obj.nil? msg = "Expected #{obj.inspect} to be nil" unless msg __assert__(test, msg) end # Passes if regexp !~ string # # @example # assert_no_match(/two/, 'one 2 three') # # @raise [Assertion] if test fails # # @return nothing def assert_no_match(exp, act, msg=nil) test = (act !~ exp) msg = "Expected #{act.inspect} to match #{exp.inspect}" unless msg __assert__(test, msg) end # Passes if expected != actual # # @example # assert_not_equal 'some string', 5 # # @raise [Assertion] if test fails # # @return nothing def assert_not_equal(exp, act, msg=nil) test = (exp != act) msg = "Expected #{act.inspect} to not be equal to #{exp.inspect}" unless msg __assert__(test, msg) end # Passes if ! object .nil? # # @example # assert_not_nil '1 two 3'.sub!(/two/, '2') # # @raise [Assertion] if test fails # # @return nothing def assert_not_nil(obj, msg=nil) test = ! obj.nil? msg = "Expected #{obj.inspect} to not be nil" unless msg __assert__(test, msg) end # Passes if ! actual .equal? expected # # @example # assert_not_same Object.new, Object.new # # @raise [Assertion] if test fails # # @return nothing def assert_not_same(exp, act, msg=nil) test = ! exp.equal?(act) msg = "Expected #{act.inspect} to not be the same as #{exp.inspect}" unless msg __assert__(test, msg) end # Compares the +object1+ with +object2+ using operator. # # Passes if object1.send(operator, object2) is true. # # @example # assert_operator 5, :>=, 4 # # @raise [Assertion] if test fails # # @return nothing def assert_operator(o1, op, o2, msg="") test = o1.__send__(op, o2) msg = "Expected #{o1}.#{op}(#{o2}) to be true" unless msg __assert__(test, msg) end # Passes if the block raises one of the given exceptions. # # @example # assert_raise RuntimeError, LoadError do # raise 'Boom!!!' # end # # @raise [Assertion] if test fails # # @return nothing def assert_raises(*args) msg = (Module === args.last ? nil : args.pop) begin yield msg = "Expected #{exp} to be raised" unless msg __assert__(false, msg) rescue Exception => e test = (exp === e) msg = "Expected #{exp} to be raised, but got #{e.class}" unless msg __assert__(test, msg) return e end end alias_method :assert_raise, :assert_raises # Provides a way to assert that a procedure # does not raise an exception. # # @example # refute_raises(StandardError){ raise } # #def assert_raises!(exception, &block) # begin # block.call(*a) # rescue exception # raise Assertion # end #end #alias_method :refute_raises, :assert_raises! # Passes if +object+ respond_to? +method+. # # @example # assert_respond_to 'bugbear', :slice # # @raise [Assertion] if test fails # # @return nothing def assert_respond_to(obj, meth, msg=nil) msg = "Expected #{obj} (#{obj.class}) to respond to ##{meth}" unless msg #flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs #obj, meth = meth, obj if flip test = obj.respond_to?(meth) __assert__(test, msg) end # Passes if +actual+ .equal? +expected+ (i.e. they are the same instance). # # @example # o = Object.new # assert_same(o, o) # # @raise [Assertion] if test fails # # @return nothing def assert_same(exp, act, msg=nil) msg = "Expected #{act.inspect} to be the same as #{exp.inspect}" unless msg test = exp.equal?(act) __assert__(test, msg) end # Passes if the method send returns a true value. # The parameter +send_array+ is composed of: # # * A receiver # * A method # * Arguments to the method # # @example # assert_send [[1, 2], :include?, 4] # # @raise [Assertion] if test fails # # @return nothing def assert_send(send_array, msg=nil) r, m, *args = *send_array test = r.__send__(m, *args) msg = "Expected #{r}.#{m}(*#{args.inspect}) to return true" unless msg __assert__(test, msg) end # Passes if the block throws expected_symbol # # @example # assert_throws :done do # throw :done # end # # @raise [Assertion] if test fails # # @return nothing def assert_throws(sym, msg=nil) msg = "Expected #{sym} to have been thrown" unless msg test = true catch(sym) do begin yield rescue ArgumentError => e # 1.9 exception default += ", not #{e.message.split(/ /).last}" rescue NameError => e # 1.8 exception default += ", not #{e.name.inspect}" end test = false end __assert__(test, msg) end # Assert that an Array, or any other object the responds to #include? # thus contains the given element. # # @raise [Assertion] if test fails # # @return nothing def assert_includes(elem, array, msg=nil) test = array.include?(elem) msg = "Expected #{elem.inspect} is not found in #{array.inspect}" unless msg __assert__(test, msg) end # Flunk always fails. # # @example # flunk 'Not done testing yet.' # # @raise [Assertion] always # # @return nothing def flunk(msg=nil) __assert__(false, msg) end end #module Assertions end #module Legacy module World include AE::Legacy::Assertions end end ae-1.8.2/lib/ae/core_ext/0000755000000000000000000000000012406706117013554 5ustar rootrootae-1.8.2/lib/ae/core_ext/helpers.rb0000644000000000000000000000662712406706117015556 0ustar rootroot# Nearly all, if not all, of these core extension are available from Ruby Facets. # hack NoArgument = Object.new module Kernel # Is literally true. def true? TrueClass === self end # Is literally false. def false? FalseClass === self end # Are identical, eg. object_id's are equal. def identical?(exp) exp.object_id == object_id end # Alias for #identical? alias_method :identical_to?, :identical? # Word form of #==. Also can take a block. def eq?(value=NoArgument) #:yield: if block_given? self == yield else self == value end end # Word form of #===. Also can take a block. def case?(value=NoArgument) #:yield: if block_given? self === yield else self === value end end # Word form for #=~. Also can take a block. def match?(value=NoArgument) if block_given? self =~ yield else self =~ value end end # Broad equality. def equate?(x) equal?(x) || eql?(x) || self == x || self === x end # Can a message be sent to the receiver successfully? def send?(method, *args, &block) begin __send__(method, *args, &block) true rescue NoMethodError false end end # #def returns?(value) #:yield: # value == yield #end unless method_defined?(:public_send) # def public_send(m,*a,&b) raise NoMethodError unless respond_to?(m) __send__(m,*a,&b) end end end class Object # Allows equal? to take a block. def equal?(value=NoArgument) #:yield: if block_given? super(yield) else super end end # Allows eql? to take a block. def eql?(value=NoArgument) #:yield: if block_given? super(yield) else super end end end class Numeric # Is self and given number within delta tolerance. # # 0.05.in_delta?(50000.0 / 10**6, 0.00001) # def in_delta?(orig, delta=0.001) #(num.to_f - to_f).abs <= delta.to_f delta >= (orig - self).abs end # Alias for #in_delta. alias_method :close?, :in_delta? # Verify epsilon tolerance. def in_epsilon?(orig, epsilon=0.001) in_delta?(orig, [orig, self].min * epsilon) end end class Module # Is a given class or module an ancestor of this # class or module? # # class X ; end # class Y < X ; end # # Y.is?(X) #=> true # def is?(base) Module===base && ancestors.slice(1..-1).include?(base) end end class Proc # def raises?(exception=Exception, *args) begin call(*args) false rescue exception => error exception === error end end # def throws?(sym, *args) catch(sym) do begin call(*args) rescue ArgumentError # 1.9 exception rescue NameError # 1.8 exception end return false end return true end # TODO: Put in facets? # TODO: wrong place, change yield? def change? pre_result = yield called = call post_result = yield pre_result != post_result end end class Symbol # Does the block throw this symbol? # def thrown?(*args) catch(self) do begin yield(*args) rescue ArgumentError # 1.9 exception rescue NameError # 1.8 exception end return false end return true end end class Exception # def self.raised? #:yeild: begin yield false rescue self true end end end # Copyright (c) 2008,2009 Thomas Sawyer ae-1.8.2/lib/ae/core_ext/exception.rb0000644000000000000000000000055312406706117016102 0ustar rootrootclass Exception # Is this exception the result of an assertion? def assertion? @assertion || false end # Set +true+/+false+ if the this exception is # an assertion. def set_assertion(boolean) @assertion = !!boolean end # def negative? @negative || false end # def set_negative(boolean) @negative = !!boolean end end ae-1.8.2/lib/ae/ansi.rb0000644000000000000000000000055212406706117013225 0ustar rootrootrequire 'ansi/diff' module AE # Default ANSI mode is "on". @ansi = true # ANSI mode. # # @return [Boolean] ANSI mode. def self.ansi? @ansi end # To turn of ANSI colorized error messages off, set # ansi to +false+ in your test helper. # # @example # AE.ansi = false # def self.ansi=(boolean) @ansi = boolean end end ae-1.8.2/lib/ae/pry.rb0000644000000000000000000000172412406706117013107 0ustar rootrootrequire 'ae/basic_object' module Kernel # TODO: Is th cache really neccessry? # $PRY_TABLE = {} # Pry allows you to test private and protected methods # thru a public-only interface. # # Generally one should avoid testing private and protected # methods directly, instead relying on tests of public methods to # indirectly test them, because private and protected methods are # considered implementation details. But sometimes it is necessary # to test them directly, or if you wish to achieve *absolute # coverage*, say in a mission critical system. # # @return [Pry] pry functor def pry $PRY_TABLE[self] ||= Pry.new do |op, *a, &b| __send__(op, *a, &b) end end # Pry Functor class Pry < AE::BasicObject #instance_methods.each{ |m| private m unless m.to_s =~ /^__/ } def initialize(&function) @function = function end def method_missing(op, *a, &b) @function.call(op, *a, &b) end end end ae-1.8.2/lib/ae/should.rb0000644000000000000000000000260212406706117013567 0ustar rootrootrequire 'ae/subjunctive' module AE # Should # # "Always and never are two words you should always # remember never to use." # --Wendell Johnson # # @note THIS IS AN OPTIONAL LIBRARY. module Should # Make an assertion in subjunctive tense. # # 4.should == 3 #=> Assertion Error # # 4.should do # self == 4 # end # # @return [Assertor] Assertion functor. def should(*args, &block) Assertor.new(self, :backtrace=>caller).be(*args, &block) end # Same as 'object.should == other'. # # @return [Assertor] Assertion functor. def should=(cmp) Assertor.new(self, :backtrace=>caller).assert == cmp end # Designate a negated expectation via a *functor*. # Read this as "should not". # # 4.should! = 4 #=> Assertion Error # # @return [Assertor] Assertion functor. def should!(*args, &block) Assertor.new(self, :backtrace=>caller).not.be(*args, &block) end # NOTE: It would be nice if their were a single term that # meant the opposite of should, rather than a two word compound. # Alias for #should! method. alias_method :should_not, :should! # Alias for #should! method. alias_method :shouldnt, :should! end end class ::Object #:nodoc: include AE::Should end # Copyright (c) 2008 Thomas Sawyer, Rubyworks ae-1.8.2/lib/ae/core_ext.rb0000644000000000000000000000024112406706117014076 0ustar rootrootrequire 'ae/core_ext/exception' require 'ae/core_ext/helpers' # We need BasicObject for Assertor. unless defined?(BasicObject) require 'ae/basic_object' end ae-1.8.2/lib/ae/basic_object.rb0000644000000000000000000000643612406706117014711 0ustar rootrootif RUBY_VERSION >= '1.9' module AE BasicObject = ::BasicObject end else module AE # BasicObject provides an abstract base class with no predefined # methods (except for \_\_send__ and \_\_id__). # BasicObject is useful as a base class when writing classes that # depend upon method_missing (e.g. dynamic proxies). # # BasicObject is based on BlankSlate by Jim Weirich. # # Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org). # All rights reserved. class BasicObject #:nodoc: # Hide the method named +name+ in the BlankSlate class. Don't # hide +instance_eval+ or any method beginning with "__". def self.hide(name) name = name.to_s if instance_methods.include?(name) and name !~ /^(__|instance_eval|instance_exec)/ @hidden_methods ||= {} @hidden_methods[name.to_sym] = instance_method(name) undef_method name end end def self.find_hidden_method(name) @hidden_methods ||= {} @hidden_methods[name.to_sym] || superclass.find_hidden_method(name) end # Redefine a previously hidden method so that it may be called on a blank # slate object. def self.reveal(name) hidden_method = find_hidden_method(name) fail "Don't know how to reveal method '#{name}'" unless hidden_method define_method(name, hidden_method) end # instance_methods.each { |m| hide(m) } end end # Since Ruby is very dynamic, methods added to the ancestors of # BlankSlate after BlankSlate is defined will show up in the # list of available BlankSlate methods. We handle this by defining a # hook in the Object and Kernel classes that will hide any method # defined after BlankSlate has been loaded. # module Kernel class << self alias_method :basic_object_method_added, :method_added # Detect method additions to Kernel and remove them in the # BasicObject class. def method_added(name) result = basic_object_method_added(name) return result if self != Kernel AE::BasicObject.hide(name) result end end end # Same as above, except in Object. # class Object class << self alias_method :basic_object_method_added, :method_added # Detect method additions to Object and remove them in the # BlankSlate class. def method_added(name) result = basic_object_method_added(name) return result if self != Object AE::BasicObject.hide(name) result end def find_hidden_method(name) nil end end end # Also, modules included into Object need to be scanned and have their # instance methods removed from blank slate. In theory, modules # included into Kernel would have to be removed as well, but a # "feature" of Ruby prevents late includes into modules from being # exposed in the first place. # class Module #:nodoc: alias basic_object_original_append_features append_features def append_features(mod) result = basic_object_original_append_features(mod) return result if mod != Object instance_methods.each do |name| AE::BasicObject.hide(name) end result end end end ae-1.8.2/lib/ae/assert.rb0000644000000000000000000000444012406706117013574 0ustar rootrootrequire 'ae/assertor' module AE # The Assert module is simple a conatiner module for the core # extension methods: #assert, #expect, etc. # # This module is included directory into the Object class. module Assert # Assert a operational relationship. # # 4.assert == 3 # # If only a single test argument is given then #assert # simply validates that it evalutate to true. An optional # message argument can be given in this case which will # be used instead of the deafult message. # # assert(4==3, "not the same thing") # # In block form, #assert ensures the block evalutes # truthfully, i.e. not as nil or false. # # assert{ 4==3 } # # @return [Assertor] Assertion functor. def assert(*args, &block) Assertor.new(self, :backtrace=>caller).assert(*args, &block) end # Same as 'object.assert == other'. # # @return [Assertor] Assertion functor. def assert=(cmp) Assertor.new(self, :backtrace=>caller).assert == cmp end # Opposite of assert. # # 4.refute == 4 #=> Assertion Error # # @return [Assertor] Assertion functor. def refute(*args, &block) Assertor.new(self, :backtrace=>caller).not.assert(*args, &block) end # Same as 'object.refute == other'. # # @return [Assertor] Assertion functor. def refute=(cmp) Assertor.new(self, :backtrace=>caller).not.assert == cmp end # Alias for #refute. Read it as "assert not". # # 4.assert! == 4 # # NOTE: This method would not be necessary if Ruby would allow # +!=+ to be define as a method, or at least +!+ as a unary method. # Looks like this is possible in Ruby 1.9, but we will wait until # Ruby 1.9 is the norm. alias_method :assert!, :refute # Directly raise an Assertion failure. # # @param message [String] # Error message. # # @param backtrace [String] # Backtrace, used to pass up an error from lower in the stack. # # @raise [Assertion] # Assertion error with given `message`. def flunk(message=nil, backtrace=nil) #Assertor.new(self, :backtrace=>caller).assert(false, message) Assertor.assert(false, message, backtrace || caller) end end end # Copyright (c) 2008 Thomas Sawyer ae-1.8.2/lib/ae/assertor.rb0000644000000000000000000002750512406706117014144 0ustar rootrootrequire 'ae/assertion' require 'ae/basic_object' require 'ae/ansi' module AE # Assertor is the underlying class of the whole system. It implements # the flutent assertion notation. # # An Assertor is an Assertion Functor. A Functor is a succinct name for what # is also known as Higher Order Function. In other words, it is a function # that acts on a function. It is very similiar to a delegator in most # respects, but is conditioned on the operation applied, rather then simply # passing-off to an alternate reciever. # class Assertor < AE::BasicObject # Initial settings of assertion counts. ZERO_COUNTS = {:total=>0,:pass=>0,:fail=>0} # Initialize assertion counts global variable. $ASSERTION_COUNTS = ZERO_COUNTS.dup # Returns Hash used to track assertion counts. def self.counts $ASSERTION_COUNTS end # Reset assertion counts. # # reset - Hash which can be used to set counts manually (optional). # # Returns the Hash of previous counts. def self.recount(reset=nil) old_counts = counts.dup if reset reset.each do |type, value| counts[type.to_sym] = value end else counts.replace(ZERO_COUNTS.dup) end return old_counts end # Increment assertion counts. If +pass+ is +true+ then +:total+ # and +:pass+ are increased. If +pass+ if +false+ then +:total+ # and +:fail+ are incremented. def self.increment_counts(pass) counts[:total] += 1 if pass counts[:pass] += 1 else counts[:fail] += 1 end return counts end # Basic assertion. This method by-passes all the Assertor fluent # constructs and performs the underlying assertion procedure. It # is used by Assertor as the end call of an assertion. def self.assert(pass, error=nil, negated=nil, backtrace=nil) pass = negated ^ !!pass increment_counts(pass) if !pass backtrace = backtrace || caller raise_assertion(error, negated, backtrace) end return pass end # The intent of the method is to raise an assertion failure # class that the test framework supports. def self.raise_assertion(error, negated, backtrace=nil) if not ::Exception === error error = assertion_error.new(error) end error.set_negative(negated) error.set_backtrace(backtrace || caller) error.set_assertion(true) fail error end # Returns the Exception class to be raised when an assertion fails. def self.assertion_error ::Assertion end # NOT HAPPENING ## Is ::Assay defined. This is used for integration of the Assay library. #def self.assay? # @_assay ||= defined?(::Assay) #end # #def self.message(sym, neg, *args, &blk) # if method = Message.lookup(sym) # method = "non_#{method}" if neg # Message.send(method, *args, &blk) # else # nil # end #end # if ::RUBY_VERSION >= '1.9' eval "private :==, :!, :!=" # using eval here b/c it's a syntax error in 1.8- end # New Assertor. # def initialize(delegate, opts={}) #, backtrace) @delegate = delegate @message = opts[:message] @backtrace = opts[:backtrace] || caller #[1..-1] @negated = !!opts[:negated] end # TODO: Should #not return a new Assertor instead of in place negation? # Negate the meaning of the assertion. # def not(msg=nil) @negated = !@negated @message = msg if msg self end # Internal assert, provides all functionality associated # with external #assert method. (See Assert#assert) # # NOTE: I'm calling YAGNI on using extra arguments to pass # to the block. The interface is much nicer if a macro is # created to handle any neccessry arguments. Eg. # # assert something(parameter) # # instead of # # assert something, parameter # # Returns +true+ or +false+ based on assertions success. # def assert(*args, &block) return self if !block && args.empty? target = args.shift unless block error = nil # Block if block match = args.shift result = block.arity > 0 ? block.call(@delegate) : block.call if match pass = (match == result) error = @message || "#{match.inspect} == #{result.inspect}" else pass = result error = @message || block.inspect # "#{result.inspect}" end # Proc-style elsif proc_assertion?(target) pass, error = proc_apply(target) # Assay-style assertions #elsif assay_assertion?(target) # pass, error = assay_assertion_apply(target) # RSpec-style matchers elsif rspec_matcher?(target) pass, error = rspec_matcher_apply(target) # Truthiness else pass = target # truthiness error = args.shift # optional message for TestUnit compatiability end __assert__(pass, error) end # TODO: Should we deprecate the receiver matches in favor of #expected ? # In other words, should || @delegate be dropped? # Internal expect, provides all functionality associated # with external #expect method. (See Expect#expect) # def expect(*args, &block) return self if !block && args.empty? # same as #assert pass = false error = nil if block match = args.shift || @delegate # TODO: see above if exception?(match) $DEBUG, debug = false, $DEBUG # b/c it always spits-out a NameError begin block.arity > 0 ? block.call(@delegate) : block.call pass = false error = "#{match} not raised" rescue match => error pass = true error = "#{match} raised" rescue ::Exception => error pass = false error = "#{match} expected but #{error.class} was raised" ensure $DEBUG = debug end else result = block.arity > 0 ? block.call(@delegte) : block.call pass = (match === result) error = @message || "#{match.inspect} === #{result.inspect}" end ## Matcher #elsif target.respond_to?(:matches?) # pass = target.matches?(@delegate) # error = @message || matcher_message(target) #|| target.inspect # if target.respond_to?(:exception) # #error_class = target.failure_class # error = target.exception #failure(:backtrace=>@backtrace, :negated=>@negated) # end # Case Equality else target = args.shift pass = (target === @delegate) error = @message || "#{target.inspect} === #{@delegate.inspect}" end __assert__(pass, error) end # def flunk(message=nil, backtrace=nil) __assert__(false, message || @message) end # Ruby seems to have a quark in it's implementation whereby # this must be defined explicitly, otherwise it somehow # skips #method_missing. def =~(match) method_missing(:"=~", match) end # def send(op, *a, &b) method_missing(op, *a, &b) end # def inspect @delegate.inspect end private # AE-STYLE ASSERTIONS # def proc_assertion?(target) ::Proc === target || target.respond_to?(:call) || target.respond_to?(:to_proc) end # def proc_apply(target) call = target.method(:call) rescue target.to_proc pass = call.arity != 0 ? call.call(@delegate) : call.call error = @message || ( to_s = target.method(:to_s) to_s.arity == 0 ? to_s.call : to_s.call(@negated) ) return pass, error end # ASSAY-STYLE ASSERTIONS # (not yet supported b/c api is not 100%) # Is the `assertion` object an assay-style assertion? def assay_assertion?(assertion) assertion.respond_to?(:exception) && assertion.respond_to?(:pass?) end # def assay_assertion_apply(assay) if @negated pass = assay.fail?(@delegate) error = assay #.exception(@message || ) else pass = assay.pass?(@delegate) error = assay #.exception(@message || ) end return pass, error end # RSPEC-STYLE MATCHERS # Is `target` an Rspec-style Matcher? def rspec_matcher?(target) target.respond_to?(:matches?) end # def rspec_matcher_apply(matcher) pass = matcher.matches?(@delegate) error = @message || rspec_matcher_message(matcher) return pass, error end # TODO: Is there anything to be done with matcher.description? # def rspec_matcher_message(matcher) if @negated if matcher.respond_to?(:failure_message_for_should_not) return matcher.failure_message_for_should_not end if matcher.respond_to?(:negative_failure_message) return matcher.negative_failure_message end end if matcher.respond_to?(:failure_message_for_should) return matcher.failure_message_for_should end if matcher.respond_to?(:failure_message) return matcher.failure_message end return matcher.to_s # TODO: or just `nil` ? end # TODO: Should we use a more libreral determination of exception. # e.g. respond_to?(:exception). # Is the +object+ an Exception or an instance of one? def exception?(object) ::Exception === object or ::Class === object and object.ancestors.include?(::Exception) end # TODO: In future should probably be `@delegate.public_send(sym, *a, &b)`. # Converts a missing method into an Assertion. def method_missing(sym, *args, &block) error = @message || compare_message(sym, *args, &block) || generic_message(sym, *args, &block) pass = @delegate.__send__(sym, *args, &block) __assert__(pass, error) end # TODO: Can the handling of the message be simplified/improved? # Simple assert. def __assert__(pass, error=nil) Assertor.assert(pass, error, @negated, @backtrace) end # COMPARISON_OPERATORS = { :"==" => :"!=" } # Message to use when making a comparion assertion. # # NOTE: This message utilizes the ANSI gem to produce colorized # comparisons. If you need to remove color output (for non-ANSI # terminals) you can either set `AE.ansi = false` or use the # ANSI library's master switch to deactive all ANSI codes, # which can be set in your test helper. # # @param operator [Symbol] operator/method # # @see http://rubyworks.github.com/ansi def compare_message(operator, *args, &blk) return nil unless COMPARISON_OPERATORS.key?(operator) prefix = "" a, b = @delegate.inspect, args.first.inspect if @negated op = COMPARISON_OPERATORS[operator] if op operator = op else prefix = "NOT " end end if AE.ansi? diff = ::ANSI::Diff.new(a,b) a = diff.diff1 b = diff.diff2 end if a.size > 13 or b.size > 13 prefix + "a #{operator} b\na) " + a + "\nb) " + b else prefix + "#{a} #{operator} #{b}" end end # Puts together a suitable error message. # # @param op [Symbol] operator/method # # @return [String] message def generic_message(op, *a, &b) inspection = @delegate.send(:inspect) if @negated "! #{inspection} #{op} #{a.collect{|x| x.inspect}.join(',')}" else "#{inspection} #{op} #{a.collect{|x| x.inspect}.join(',')}" end #self.class.message(m)[@delegate, *a] ) end # @see http://redmine.ruby-lang.org/issues/3768 def self.const_missing(const) ::Object.const_get(const) end end end # DO WE MAKE THESE EXCEPTIONS? #class BasicObject # def assert # end #end # Copyright (c) 2008 Thomas Sawyer ae-1.8.2/lib/ae/adapters/0000755000000000000000000000000012406706117013547 5ustar rootrootae-1.8.2/lib/ae/adapters/minitest.rb0000644000000000000000000000254312406706117015734 0ustar rootrootrequire 'ae' AE.assertion_error = ::MiniTest::Assertion module MiniTest #:nodoc: class Unit #:nodoc: # MiniTest tracks assertion counts internally in it's Unit class via the # +assertion_count+ attribute. To work with AE we need add in AE's assertion # total by overriding the +assertion_count+ method. # # @return [Integer] Number of assertions made. def assertion_count @assertion_count + AE::Assertor.counts[:total] end # To teach MiniTest to recognize AE's expanded concept of assertions # we add in an extra capture clause to it's #puke method. # # @return [String] Status code is `S`, `F`, or `E`. def puke k, m, e case e when MiniTest::Skip @skips += 1 return "S" unless @verbose e = "Skipped:\n#{m}(#{k}) [#{location e}]:\n#{e.message}\n" when MiniTest::Assertion @failures += 1 e = "Failure:\n#{m}(#{k}) [#{location e}]:\n#{e.message}\n" else if e.respond_to?(:assertion?) && e.assertion? @failures += 1 e = "Failure:\n#{m}(#{c}) [#{location e}]:\n#{e.message}\n" else @errors += 1 b = MiniTest::filter_backtrace(e.backtrace).join "\n " e = "Error:\n#{m}(#{k}):\n#{e.class}: #{e.message}\n #{b}\n" end end @report << e e[0, 1] end end end ae-1.8.2/lib/ae/adapters/rspec.rb0000644000000000000000000000032412406706117015207 0ustar rootrootrequire 'ae' AE.assertion_error = ::RSpec::Expectations::ExpectationNotMetError # TODO: Teach RSpec the expanded concept of assertions, as Exception # classes that respond to `#assertion?` in the affirmative. ae-1.8.2/lib/ae/adapters/testunit.rb0000644000000000000000000000406712406706117015762 0ustar rootrootrequire 'ae' AE.assertion_error = ::Test::Unit::AssertionFailedError # TestUnit uses #add_assertion on it's +result+ object to track counts. # We capture the result object by overriding the TestCase#run method, # store it in a global variable and then use it when AE increments # assertion counts. # # In addition we teach #run to recognize any Exception class that # responds to #assertion? in the affirmative as an assertion # rather than an error. # module Test #:nodoc: module Unit #:nodoc: class TestCase #:nodoc: # These exceptions are not caught by #run. PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt, SystemExit] # Runs the individual test method represented by this # instance of the fixture, collecting statistics, failures # and errors in result. def run(result) $_test_unit_result = result yield(STARTED, name) @_result = result begin setup __send__(@method_name) rescue AssertionFailedError => e add_failure(e.message, e.backtrace) rescue Exception => e if e.respond_to?(:assertion?) && e.assertion? add_failure(e.message, e.backtrace) else raise if PASSTHROUGH_EXCEPTIONS.include? $!.class add_error($!) end ensure begin teardown rescue AssertionFailedError => e add_failure(e.message, e.backtrace) rescue Exception => e if e.respond_to?(:assertion?) && e.assertion? add_failure(e.message, e.backtrace) else raise if PASSTHROUGH_EXCEPTIONS.include? $!.class add_error($!) end end end result.add_run yield(FINISHED, name) end end end end class AE::Assertor #:nodoc: def self.increment_counts(pass) $_test_unit_result.add_assertion if $_test_unit_result counts[:total] += 1 if pass counts[:pass] += 1 else counts[:fail] += 1 end return counts end end ae-1.8.2/lib/ae/assertion.rb0000644000000000000000000000275012406706117014304 0ustar rootrootrequire 'ae/core_ext' module AE # The Assertion class is simply a subclass of Exception that is used # by AE as the default error raised when an assertion fails. # # "The reserve of modern assertions is sometimes pushed to extremes, # in which the fear of being contradicted leads the writer to strip # himself of almost all sense and meaning." # -- Sir Winston Churchill (1874 - 1965) # # class Assertion < Exception # @deprecated # This will be removed in favor of `AE::Assertor.counts`. def self.counts AE::Assertor.counts end # New assertion (failure). # # @param message [String] the failure message # @param options [Hash] options such as :backtrace # def initialize(message=nil, options={}) super(message) backtrace = options[:backtrace] set_backtrace(backtrace) if backtrace set_assertion(true) end # Technically any object that affirmatively responds to #assertion? # can be taken to be an Assertion. This makes it easier for various # libraries to work together without having to depend upon a common # Assertion base class. def assertion? true end # Parents error message prefixed with "(assertion)". # # @return [String] error message def to_s '(assertion) ' + super end end end # Set top-level Assertion to AE::Assertion if not already present. Assertion = AE::Assertion unless defined?(Assertion) ae-1.8.2/lib/ae/expect.rb0000644000000000000000000000331012406706117013556 0ustar rootrootmodule AE require 'ae/assertor' # = Expect # # "When love and skill work together, expect a masterpiece." # --John Ruskin (1819 - 1900) # module Expect # The #expect method is a convenient tool for defining # certain sets of expectations in your specifications. # # Expect is used to expect a result from a block of code. # If the argument to expect is a subclass of Exception # or instance thereof, then the block is monitored for # the raising of such an exception. # # expect StandardError do # raise ArgumentError # end # # All other expectations are compared using case equality (#===). # This allows one to verify matching Regexp. # # expect /x/ do # "x" # end # # As well as checking that an object is an instance of a given Class. # # expect String do # "x" # end # # Like #assert it can be used to designate an expectation # via a *functor*. # # 4.expect == 3 # def expect(*args, &block) Assertor.new(self, :backtrace=>caller).expect(*args, &block) end # Designate a negated expectation. Read this as "expect not". # # See #expect. # def expect!(*args, &block) Assertor.new(self, :backtrace=>caller).not.expect(*args, &block) end # Alias for #expect! method. alias_method :forbid, :expect! # Like #expect but uses the reciever as the object # of expectation. # # @example # /x/.expected do # "oooxooo" # end # def expected(*args, &block) expect(self, *args, &block) end end end # Copyright (c) 2008 Thomas Sawyer ae-1.8.2/lib/ae/subjunctive.rb0000644000000000000000000000334712406706117014641 0ustar rootrootrequire 'ae/assertor' module AE # Subjunctive # # Mixin for Assertor that provides additional English-eque verbage # such as 'be' and 'an'. This makes it easier to create assertor # methods of subjunctive terms like 'should'. # # @note THIS IS AN OPTIONAL LIBRARY. module Subjunctive # Like #assert, except if an argument is provided and no block, # uses #equate? to compare the argument to the receiver. This # allows for statements of the form: # # 5.should.be Numeric # def be(*args, &block) return self if args.empty? && !block block = args.shift if !block && ::Proc === args.first if block pass = block.arity > 0 ? block.call(@delegate) : block.call #@delegate.instance_eval(&block) msg = args.shift || @message || block.inspect else pass = args.shift.equate?(@delegate) msg = args.shift end __assert__(pass, msg) end # Alias of #be. # # 5.assert.is Numeric # alias_method :is , :be alias_method :does, :be # The indefinite article is like #be, except that it compares a lone argument # with #case?, rather than #equate? # def a(*args, &block) return self if args.empty? && !block block = args.shift if !block && ::Proc === args.first if block pass = block.arity > 0 ? block.call(@delegate) : block.call #@delegate.instance_eval(&block) msg = args.shift || @message || block.inspect else pass = (args.shift === @delegate) # case equality msg = args.shift end __assert__(pass, msg) end alias_method :an, :a end end#module AE class AE::Assertor include ::AE::Subjunctive end # Copyright (c) 2008 Thomas Sawyer