test_rig 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jacob Rothstein
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,140 @@
1
+ h1. Test Rig
2
+
3
+ Test Rig provides two separate modules that work together.
4
+ *Dynamic assertions* are flexible xUnit style matchers called dynamically.
5
+ *Smarter message* supplements test failure messages with a several-line context
6
+ of the test failure.
7
+ This library works well with something like "Context":http://github.com/jeremymcanally/context or Shoulda.
8
+
9
+ h2. Installation
10
+
11
+ If necessary, install "Gemcutter":http://gemcutter.org.
12
+ <pre><code>sudo gem install gemcutter && sudo gem tumble</code></pre>
13
+
14
+ Install test-rig
15
+ <pre><code>sudo gem install test-rig</code></pre>
16
+
17
+ Add @require 'test_rig'@ to test_helper.rb, and @include TestRig@ into @Test::Unit:TestCase@.
18
+ If you only want dynamic assertions or smarter messages, @include TestRig::DynamicAssertions@
19
+ or @include TestRig::SmarterMessage@ instead of @TestRig@.
20
+
21
+ h2. Dynamic assertions
22
+
23
+ h3. Background & Philosophy
24
+
25
+ Rspec has never sat well for me. Object.method.should be_true style testing reads neat and is
26
+ really nicely like english. Here's the problem: What we are strictly saying in rspec is that
27
+ testing is the object's responsibility. It's like "hey, you! test yourself."
28
+
29
+ Testing is definitionally an external act. It is manipulating a system by its control points
30
+ (public api) and confirming that the behavior is as expected. Passing a "modal verb":http://en.wikipedia.org/wiki/Modal_verb
31
+ like "should" to the object in question does not describe this behavior.
32
+
33
+ From a more practical perspective, defining rspec behaviors is way too much of
34
+ a pain when we already have an easy way to define methods in ruby.
35
+
36
+ @Test::Unit@, particularly when combined with Context or Shoulda, is good
37
+ enough for most things. The only real issue is that you find yourself defining
38
+ a whole lot of helper methods, like @assert_new_record@, @assert_valid@, @assert_red@
39
+ *Dynamic assertions* fixes this. With the fantastic power of method missing,
40
+ assertions are generated on the fly.
41
+
42
+ One of the really nice things about Rspec is that every matcher automatically
43
+ gets an inverse (logical not) matcher. *Dynamic assertions* provides this as well.
44
+
45
+ h3. Example
46
+
47
+ Let's say we have class named @Entry@ that has a boolean @published?@ and a
48
+ boolean @saved?@ and a record @@foo@ that should be saved but not published.
49
+ Oh, and it should have a user, which we'll represent as the string @"joe"@
50
+
51
+ h4. Positive assertions
52
+
53
+ In Rspec: @@foo.should be_saved@
54
+
55
+ In Test::Unit: @assert @foo.saved?@
56
+
57
+ With Dynamic assertions: @assert_saved @foo@
58
+
59
+ h4. Negative assertions
60
+
61
+ In Rspec: @@foo.should_not be_published@
62
+
63
+ In Test::Unit: <code>assert !@foo.published?</code> or, if you've defined @assert_false@, <code>assert_false @foo.published</code>
64
+
65
+ With Dynamic assertions: <code>assert_not_published @foo</code>
66
+
67
+ h4. Nil assertions
68
+
69
+ In Rspec: @@foo.something.should be_nil@
70
+
71
+ In Test::Unit: @assert_nil @foo.something@
72
+
73
+ With Dynamic assertions: @assert_no_something @foo@
74
+
75
+ h4. Positive equality assertions
76
+
77
+ In Rspec: <code>@foo.user.should == "joe"</code>
78
+
79
+ In Test::Unit: <code>assert_equal "joe", @foo.user</code>
80
+
81
+ With Dynamic assertions: <code>assert_user "joe", @foo</code>
82
+
83
+ h4. Negative equality assertions
84
+
85
+ In Rspec: <code>@foo.user.should == "joe"</code>
86
+
87
+ In Test::Unit: <code>assert_not_equal "joe", @foo.user</code>
88
+
89
+ With Dynamic assertions: <code>assert_not_user "joe", @foo</code>
90
+
91
+ h4. Everything else
92
+
93
+ <code>assert @foo.user.include?('j')</code>
94
+ <code>assert_not @foo.user.include?('z')</code>
95
+
96
+ h2. Smarter Message
97
+
98
+ My bane: "false did not equal true" -- What you really want to know is what
99
+ the variable names were or the method calls.
100
+
101
+ If we have the stack trace, we should be able to show you the exact test that
102
+ failed immediately. Smarter Message does exactly that.
103
+
104
+ h3. Example
105
+
106
+ <pre><code>
107
+ #demo_test.rb
108
+ require File.join(File.dirname(__FILE__), "test_helper")
109
+ require 'smarter_message'
110
+
111
+ class DemoTest < Test::Unit::TestCase
112
+ include TestRig::SmarterMessage
113
+ test "demonstration" do
114
+ a = 'foo'
115
+ b = 'bar'
116
+ assert_equal a, b
117
+ end
118
+ end
119
+ </code></pre>
120
+
121
+ <pre><code>
122
+ 1) Failure:
123
+ test demonstration(DemoTest) [./test/demo_test.rb:11]:
124
+ <"foo"> expected but was
125
+ <"bar">.
126
+ ./test/smarter_message_test.rb:11:in `test demonstration'
127
+ 9: a = 'foo'
128
+ 10: b = 'bar'
129
+ --> 11: assert_equal a, b
130
+ 12: end
131
+ 13:end
132
+ </code></pre>
133
+
134
+ h3. Settings
135
+
136
+ @TestRig::SmarterMessage.context_lines = 2 #the default@
137
+
138
+ This defaults to two (yielding five lines; two context on each side + the actual line).
139
+ Set this in your test_helper.
140
+ If context_lines is zero, it will just print your failure line.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "test_rig"
8
+ gem.summary = %Q{TestRig makes Test::Unit fun again}
9
+ gem.description = %Q{TestRig supplies dynamic assertions and contextual failure messages}
10
+ gem.email = "github@jacobrothstein.com"
11
+ gem.homepage = "http://github.com/jbr/test-rig"
12
+ gem.authors = ["Jacob Rothstein"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/*_test.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+ task :test => :check_dependencies
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ if File.exist?('VERSION')
47
+ version = File.read('VERSION')
48
+ else
49
+ version = ""
50
+ end
51
+
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "test-rig #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.3
@@ -0,0 +1,38 @@
1
+ require 'active_support'
2
+
3
+ module TestRig
4
+ module DynamicAssertions
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ alias_method_chain :method_missing, :dynamic_assertions
8
+ end
9
+ end
10
+
11
+ def assert_not(*args)
12
+ assert !args.shift, *args
13
+ end
14
+
15
+ def method_missing_with_dynamic_assertions(method, *args)
16
+ case method.to_s
17
+ when /^assert_no_([a-z_]+)$/
18
+ method_name = $1.to_sym
19
+ if args.first.respond_to? method_name
20
+ assert_nil args.first.send(method_name)
21
+ return
22
+ end
23
+ when /^assert_(not_)?([a-z_]+)$/
24
+ method_name = $2.to_sym
25
+ if args.length == 1 && args.first.respond_to?(:"#{method_name}?")
26
+ actual = args.first.send :"#{method_name}?"
27
+ assert $1 ? !actual : actual
28
+ return
29
+ elsif args.length == 2 && args.last.respond_to?(method_name)
30
+ send :"assert_#{$1}equal", args.first, args.last.send(method_name)
31
+ return
32
+ end
33
+ end
34
+
35
+ method_missing_without_dynamic_assertions(method, *args)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,69 @@
1
+ require 'active_support'
2
+
3
+ module TestRig
4
+ module SmarterMessage
5
+ mattr_writer :backtrace_regex
6
+ mattr_accessor :context_lines
7
+ @@context_lines = 2
8
+
9
+ def self.backtrace_regex
10
+ @@backtrace_regex ||= /_test\.rb/
11
+ end
12
+
13
+ def self.included(klass)
14
+ klass.class_eval do
15
+ alias_method_chain :assert_block, :smarter_message
16
+ end
17
+ end
18
+
19
+ def assert_block_with_smarter_message(*args, &blk)
20
+ assert_block_without_smarter_message(*args, &blk)
21
+ rescue Test::Unit::AssertionFailedError => e
22
+ backtrace = e.backtrace
23
+ relevant_traces = relevant_traces(backtrace)
24
+ raise if relevant_traces.blank?
25
+ new_error = Test::Unit::AssertionFailedError.new e.message + "\n" + message_for_backtrace(backtrace)
26
+ new_error.set_backtrace(relevant_traces)
27
+ raise new_error
28
+ end
29
+
30
+ private
31
+
32
+ def message_for_backtrace(backtrace)
33
+ trace = first_relevant_trace(backtrace)
34
+ line = line_at_backtrace(trace, SmarterMessage.context_lines)
35
+ "#{trace}\n#{line}"
36
+ end
37
+
38
+ def relevant_traces(backtrace)
39
+ backtrace.select do |trace|
40
+ trace =~ TestRig::SmarterMessage.backtrace_regex &&
41
+ trace !~ /#{File.basename(__FILE__)}/
42
+ end
43
+ end
44
+
45
+ def first_relevant_trace(backtrace)
46
+ backtrace.detect { |trace| trace =~ /_test\.rb/}
47
+ end
48
+
49
+ def pad(number, width)
50
+ "#{" " * (width - number.to_s.size)}#{number}"
51
+ end
52
+
53
+ def line_at_backtrace(trace, context = 0)
54
+ file, line = trace.split(":")
55
+ line = line.to_i - 1
56
+ start, finish = line - context, line + context
57
+ width = [start, finish].map{|n| (n + 1).to_s.size }.max
58
+
59
+ lines = File.open(file).readlines
60
+ (start..finish).map do |line_number|
61
+ if lines[line_number]
62
+ "#{line_number == line.to_i ? "--> " : " "}"\
63
+ "#{pad line_number + 1, width}:" +
64
+ lines[line_number].rstrip
65
+ end
66
+ end.compact.join("\n")
67
+ end
68
+ end
69
+ end
data/lib/test_rig.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'test_rig/dynamic_assertions'
2
+ require 'test_rig/smarter_message'
3
+
4
+ module TestRig
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ include TestRig::DynamicAssertions
8
+ include TestRig::SmarterMessage
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,65 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class Entry
4
+ def published?() false end
5
+ def saved?() true end
6
+ def user() "joe" end
7
+ def something_nil() nil end
8
+ def something_not_nil() "not nil" end
9
+ end
10
+
11
+ class DynamicAssertionsTest < Test::Unit::TestCase
12
+ include TestRig::DynamicAssertions
13
+
14
+ def setup
15
+ @entry = Entry.new
16
+ end
17
+
18
+ test 'assert not' do
19
+ assert_not @entry.published?
20
+ end
21
+
22
+ test 'assert not failure' do
23
+ assert_test_failure { assert_not @entry.saved? }
24
+ end
25
+
26
+ test "positive assertion" do
27
+ assert_saved @entry
28
+ end
29
+
30
+ test "positive assertion failure" do
31
+ assert_test_failure { assert_not_saved @entry }
32
+ end
33
+
34
+ test "negative assertion" do
35
+ assert_not_published @entry
36
+ end
37
+
38
+ test "negative assertion failure" do
39
+ assert_test_failure { assert_published @entry }
40
+ end
41
+
42
+ test "positive equality assertion" do
43
+ assert_user "joe", @entry
44
+ end
45
+
46
+ test 'positive equality assertion failure' do
47
+ assert_test_failure { assert_user 'sue', @entry }
48
+ end
49
+
50
+ test "negative equality assertion" do
51
+ assert_not_user "sally", @entry
52
+ end
53
+
54
+ test 'negative equality assertion failure' do
55
+ assert_test_failure { assert_not_user 'joe', @entry }
56
+ end
57
+
58
+ test "assert no" do
59
+ assert_no_something_nil @entry
60
+ end
61
+
62
+ test "assert no failure" do
63
+ assert_test_failure { assert_no_something_not_nil @entry }
64
+ end
65
+ end
@@ -0,0 +1,51 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class SmarterMessageTest < Test::Unit::TestCase
4
+ include TestRig::SmarterMessage
5
+
6
+ test "smarter message includes the relevent snippet" do
7
+ a, b = 'foo', 'bar'
8
+ e = assert_test_failure { assert_equal a, b }
9
+ [
10
+ "<\"foo\"> expected but was\n<\"bar\">.",
11
+ "a, b = 'foo', 'bar'",
12
+ "--> 8",
13
+ "assert_equal a, b"
14
+ ].each {|snippet| assert_match snippet, e.message}
15
+ end
16
+
17
+ test "backtrace includes only relevant lines" do
18
+ e = assert_test_failure { assert false }
19
+ [
20
+ "backtrace includes only relevant lines",
21
+ "#{__FILE__}:18"
22
+ ].each {|snippet| assert_match snippet, e.backtrace.first}
23
+ end
24
+
25
+ test 'with four context lines' do
26
+ TestRig::SmarterMessage.context_lines = context = 4
27
+ e = assert_test_failure { assert false }
28
+ context_output = e.message.split("\n").select{|line| line =~ /^(-->)?\s+[0-9]+:/}
29
+
30
+ assert_equal context * 2 + 1, context_output.size
31
+ assert_match "test 'with four context lines", context_output[2]
32
+ assert_match /-->.+assert false/, context_output[context]
33
+ TestRig::SmarterMessage.context_lines = 2
34
+ end
35
+
36
+ test 'backtrace scrubbing' do
37
+ TestRig::SmarterMessage.backtrace_regex = /test_helper/
38
+ e = assert_test_failure { assert false }
39
+ assert_equal 1, e.backtrace.size
40
+
41
+ TestRig::SmarterMessage.backtrace_regex = /assert_test_failure/
42
+ e = assert_test_failure { assert false }
43
+ assert_equal 1, e.backtrace.size
44
+
45
+ TestRig::SmarterMessage.backtrace_regex = nil
46
+ assert_equal /_test\.rb/, TestRig::SmarterMessage.backtrace_regex
47
+ end
48
+ end
49
+
50
+
51
+
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ $:.unshift File.instance_eval { expand_path join(dirname(__FILE__), "..", "lib") }
3
+
4
+ require 'active_support'
5
+ require 'test/unit'
6
+ require 'test_rig'
7
+
8
+ class Test::Unit::TestCase
9
+ def self.test(name, &blk) define_method(:"test #{name}", &blk) end
10
+ def assert_test_failure(&blk)
11
+ assert_raise Test::Unit::AssertionFailedError, &blk
12
+ end
13
+ end
data/test-rig.gemspec ADDED
@@ -0,0 +1,55 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{test-rig}
8
+ s.version = "0.0.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jacob Rothstein"]
12
+ s.date = %q{2010-01-14}
13
+ s.description = %q{TestRig supplies dynamic assertions and contextual failure messages}
14
+ s.email = %q{github@jacobrothstein.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.textile"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.textile",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/test_rig.rb",
27
+ "lib/test_rig/dynamic_assertions.rb",
28
+ "lib/test_rig/smarter_message.rb",
29
+ "test-rig.gemspec",
30
+ "test/dynamic_assertions_test.rb",
31
+ "test/smarter_message_test.rb",
32
+ "test/test_helper.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/jbr/test-rig}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.5}
38
+ s.summary = %q{TestRig makes Test::Unit fun again}
39
+ s.test_files = [
40
+ "test/dynamic_assertions_test.rb",
41
+ "test/smarter_message_test.rb",
42
+ "test/test_helper.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
50
+ else
51
+ end
52
+ else
53
+ end
54
+ end
55
+
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: test_rig
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Jacob Rothstein
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-23 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: TestRig supplies dynamic assertions and contextual failure messages
17
+ email: github@jacobrothstein.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.textile
25
+ files:
26
+ - .document
27
+ - .gitignore
28
+ - LICENSE
29
+ - README.textile
30
+ - Rakefile
31
+ - VERSION
32
+ - lib/test_rig.rb
33
+ - lib/test_rig/dynamic_assertions.rb
34
+ - lib/test_rig/smarter_message.rb
35
+ - test-rig.gemspec
36
+ - test/dynamic_assertions_test.rb
37
+ - test/smarter_message_test.rb
38
+ - test/test_helper.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/jbr/test-rig
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --charset=UTF-8
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.3.5
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: TestRig makes Test::Unit fun again
67
+ test_files:
68
+ - test/dynamic_assertions_test.rb
69
+ - test/smarter_message_test.rb
70
+ - test/test_helper.rb