baretest 0.1.0 → 0.2.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/LICENSE.txt +52 -0
- data/MANIFEST.txt +50 -31
- data/README.rdoc +260 -0
- data/bin/baretest +82 -24
- data/doc/baretest.rdoc +98 -0
- data/doc/mocking_stubbing_test_doubles.rdoc +5 -0
- data/doc/quickref.rdoc +261 -0
- data/doc/writing_tests.rdoc +148 -0
- data/examples/test.rake +58 -30
- data/examples/tests/irb_mode/failures.rb +26 -0
- data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
- data/examples/tests/mock_developer/test/setup.rb +57 -0
- data/examples/tests/mock_developer/test/suite/mock_demo.rb +19 -0
- data/examples/tests/overview/test.rb +89 -0
- data/examples/tests/variations/variations_01.rb +14 -0
- data/examples/tests/variations/variations_02.rb +19 -0
- data/examples/tests/variations/variations_03.rb +19 -0
- data/lib/baretest/assertion/context.rb +20 -0
- data/lib/baretest/assertion/failure.rb +22 -0
- data/lib/baretest/assertion/skip.rb +21 -0
- data/lib/{test → baretest}/assertion/support.rb +174 -39
- data/lib/baretest/assertion.rb +182 -0
- data/lib/baretest/irb_mode.rb +263 -0
- data/lib/{test/assertion/failure.rb → baretest/layout.rb} +6 -5
- data/lib/baretest/mocha.rb +18 -0
- data/lib/baretest/run/cli.rb +104 -0
- data/lib/{test → baretest}/run/errors.rb +12 -7
- data/lib/{test → baretest}/run/minimal.rb +8 -3
- data/lib/baretest/run/profile.rb +151 -0
- data/lib/{test → baretest}/run/spec.rb +10 -4
- data/lib/baretest/run/tap.rb +44 -0
- data/lib/baretest/run/xml.rb +80 -0
- data/lib/{test → baretest}/run.rb +31 -18
- data/lib/baretest/setup.rb +15 -0
- data/lib/baretest/skipped/assertion.rb +20 -0
- data/lib/baretest/skipped/suite.rb +49 -0
- data/lib/baretest/skipped.rb +15 -0
- data/lib/baretest/suite.rb +234 -0
- data/lib/baretest/utilities.rb +43 -0
- data/lib/{test → baretest}/version.rb +12 -3
- data/lib/baretest.rb +112 -0
- data/test/external/bootstraptest.rb +1 -1
- data/test/setup.rb +1 -1
- data/test/{lib/test → suite/lib/baretest}/assertion/support.rb +78 -24
- data/test/suite/lib/baretest/assertion.rb +192 -0
- data/test/{lib/test → suite/lib/baretest}/irb_mode.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/cli.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/errors.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/interactive.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/spec.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/tap.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/xml.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run.rb +63 -61
- data/test/{lib/test → suite/lib/baretest}/suite.rb +77 -54
- data/test/{lib/test.rb → suite/lib/baretest.rb} +37 -37
- metadata +61 -40
- data/README.markdown +0 -229
- data/examples/test.rb +0 -93
- data/lib/test/assertion.rb +0 -117
- data/lib/test/debug.rb +0 -34
- data/lib/test/irb_mode.rb +0 -104
- data/lib/test/run/cli.rb +0 -79
- data/lib/test/run/interactive.rb +0 -60
- data/lib/test/run/tap.rb +0 -32
- data/lib/test/run/xml.rb +0 -56
- data/lib/test/suite.rb +0 -95
- data/lib/test.rb +0 -118
- data/test/lib/test/assertion.rb +0 -142
- data/test/lib/test/debug.rb +0 -63
@@ -0,0 +1,80 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
class Run
|
11
|
+
|
12
|
+
# XML runner is invoked with `-f xml` or `--format xml`.
|
13
|
+
# This runner provides xml output as a simple machine readable format.
|
14
|
+
# The schema is relatively simple:
|
15
|
+
# <tests>
|
16
|
+
# <suite description="the suites description">
|
17
|
+
# <test>
|
18
|
+
# <file>the file the test was defined in</file>
|
19
|
+
# <line>the line the assertion starts on</line>
|
20
|
+
# <status>one of: success, pending, skipped, failure, error</status>
|
21
|
+
# <description>the description of the test</test>
|
22
|
+
# </test>
|
23
|
+
# ...many tests and/or suites
|
24
|
+
# </suite>
|
25
|
+
# </tests>
|
26
|
+
# <report>
|
27
|
+
# <duration>the duration in seconds as a float</duration>
|
28
|
+
# <count type="the counters name, see BareTest::Run#count">integer</count>
|
29
|
+
# ...many counts
|
30
|
+
# </report>
|
31
|
+
# <status>The final status, one of: success, incomplete, failure, error</status>
|
32
|
+
#
|
33
|
+
module XML # :nodoc:
|
34
|
+
def run_all
|
35
|
+
@depth = 1
|
36
|
+
|
37
|
+
puts '<?xml version="1.0" encoding="utf-8"?>',
|
38
|
+
'<tests>'
|
39
|
+
start = Time.now
|
40
|
+
super
|
41
|
+
stop = Time.now
|
42
|
+
status = case
|
43
|
+
when @count[:error] > 0 then 'error'
|
44
|
+
when @count[:failure] > 0 then 'failure'
|
45
|
+
when @count[:pending] > 0 then 'incomplete'
|
46
|
+
when @count[:skipped] > 0 then 'incomplete'
|
47
|
+
else 'success'
|
48
|
+
end
|
49
|
+
puts %{</tests>},
|
50
|
+
%{<report>},
|
51
|
+
%{\t<duration>#{stop-start}</duration>}
|
52
|
+
@count.each { |key, value|
|
53
|
+
puts %{\t<count type="#{key}">#{value}</count>}
|
54
|
+
}
|
55
|
+
puts %{</report>},
|
56
|
+
%{<status>#{status}</status>}
|
57
|
+
end
|
58
|
+
|
59
|
+
def run_suite(suite)
|
60
|
+
puts %{#{"\t"*@depth}<suite description="#{suite.description}">}
|
61
|
+
@depth += 1
|
62
|
+
super
|
63
|
+
@depth -= 1
|
64
|
+
puts %{#{"\t"*@depth}</suite>}
|
65
|
+
end
|
66
|
+
|
67
|
+
def run_test(assertion, setup)
|
68
|
+
rv = super
|
69
|
+
puts %{#{"\t"*@depth}<test>},
|
70
|
+
%{#{"\t"*@depth}\t<file>#{rv.file}</file>},
|
71
|
+
%{#{"\t"*@depth}\t<line>#{rv.line}</line>},
|
72
|
+
%{#{"\t"*@depth}\t<status>#{rv.status}</status>},
|
73
|
+
%{#{"\t"*@depth}\t<description>#{rv.description}</description>},
|
74
|
+
%{#{"\t"*@depth}</test>}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
@format["baretest/run/xml"] = Run::XML
|
80
|
+
end
|
@@ -6,15 +6,18 @@
|
|
6
6
|
|
7
7
|
|
8
8
|
|
9
|
-
module
|
9
|
+
module BareTest
|
10
10
|
|
11
|
-
# Run is the
|
11
|
+
# Run is the environment in which the suites and asserts are executed.
|
12
12
|
# Prior to the execution, the Run instance extends itself with the
|
13
13
|
# formatter given.
|
14
14
|
# Your formatter can override:
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
15
|
+
# :run_all:: Invoked once, before the first run_suite is ran. No arguments.
|
16
|
+
# :run_suite:: Invoked per suite. Takes the suite to run as argument.
|
17
|
+
# :run_test:: Invoked per assertion. Takes the assertion to execute as argument.
|
18
|
+
#
|
19
|
+
# Don't forget to call super within your overrides, or the tests won't be
|
20
|
+
# executed.
|
18
21
|
class Run
|
19
22
|
# The toplevel suite.
|
20
23
|
attr_reader :suite
|
@@ -38,12 +41,12 @@ module Test
|
|
38
41
|
# suite).
|
39
42
|
# Options accepted:
|
40
43
|
# * :extenders: An Array of Modules, will be used as argument to self.extend, useful e.g. for
|
41
|
-
#
|
44
|
+
# mock integration
|
42
45
|
# * :format: A string with the basename (without suffix) of the formatter to use - or a
|
43
|
-
#
|
46
|
+
# Module
|
44
47
|
# * :interactive: true/false, will switch this Test::Run instance into IRB mode, where an error
|
45
|
-
#
|
46
|
-
#
|
48
|
+
# will cause an irb session to be started in the context of a clean copy of
|
49
|
+
# the assertion with all setup callbacks invoked
|
47
50
|
#
|
48
51
|
# The order of extensions is:
|
49
52
|
# * :extender
|
@@ -55,18 +58,18 @@ module Test
|
|
55
58
|
@options = opts || {}
|
56
59
|
@count = @options[:count] || Hash.new(0)
|
57
60
|
|
58
|
-
(
|
61
|
+
(BareTest.extender+Array(@options[:extender])).each do |extender|
|
59
62
|
extend(extender)
|
60
63
|
end
|
61
64
|
|
62
65
|
# Extend with the output formatter
|
63
66
|
if format = @options[:format] then
|
64
|
-
require "
|
65
|
-
extend(String === format ?
|
67
|
+
require "baretest/run/#{format}" if String === format
|
68
|
+
extend(String === format ? BareTest.format["baretest/run/#{format}"] : format)
|
66
69
|
end
|
67
70
|
|
68
71
|
# Extend with irb dropout code
|
69
|
-
extend(
|
72
|
+
extend(BareTest::IRBMode) if @options[:interactive]
|
70
73
|
|
71
74
|
# Initialize extenders
|
72
75
|
@inits.each { |init| instance_eval(&init) }
|
@@ -98,19 +101,29 @@ module Test
|
|
98
101
|
# Gets the suite to run as single argument.
|
99
102
|
# Runs all assertions and nested suites.
|
100
103
|
def run_suite(suite)
|
101
|
-
suite.
|
102
|
-
|
104
|
+
suite.assertions.each do |test|
|
105
|
+
run_test_variants(test)
|
103
106
|
end
|
104
|
-
suite.suites.each do |suite|
|
107
|
+
suite.suites.each do |(description, suite)|
|
105
108
|
run_suite(suite)
|
106
109
|
end
|
107
110
|
@count[:suite] += 1
|
108
111
|
end
|
109
112
|
|
110
|
-
# Formatter callback.
|
111
113
|
# Invoked once for every assertion.
|
114
|
+
# Iterates over all variants of an assertion and invokes run_test
|
115
|
+
# for each.
|
116
|
+
def run_test_variants(test)
|
117
|
+
test.suite.each_component_variant do |setups|
|
118
|
+
run_test(test, setups)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Formatter callback.
|
123
|
+
# Invoked once for every variation of an assertion.
|
112
124
|
# Gets the assertion to run as single argument.
|
113
|
-
def run_test(assertion)
|
125
|
+
def run_test(assertion, setup)
|
126
|
+
assertion.setups = setup
|
114
127
|
rv = assertion.execute
|
115
128
|
@count[:test] += 1
|
116
129
|
@count[assertion.status] += 1
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
Setup = Struct.new(:component, :substitute, :value, :block) do
|
11
|
+
def inspect
|
12
|
+
sprintf "#<Setup component=%s substitute=%p value=%p>", component, substitute, value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
module Skipped
|
11
|
+
|
12
|
+
# Like Test::Assertion, but fakes execution and sets status always to
|
13
|
+
# skipped.
|
14
|
+
class Assertion < ::BareTest::Assertion
|
15
|
+
def execute(setup=nil) # :nodoc:
|
16
|
+
@status = :skipped and self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'baretest/skipped/assertion'
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
module BareTest
|
14
|
+
|
15
|
+
module Skipped
|
16
|
+
|
17
|
+
# Like Test::Suite, but all Assertions are defined as Skipped::Assertion
|
18
|
+
class Suite < ::BareTest::Suite
|
19
|
+
def self.create(description=nil, parent=nil, opts={}, &block) # :nodoc:
|
20
|
+
new(description, parent, &block) # Skipped::Suite always
|
21
|
+
end
|
22
|
+
|
23
|
+
# All Assertions use Skipped::Assertion instead of Test::Assertion.
|
24
|
+
def assert(description=nil, &block) # :nodoc:
|
25
|
+
@skipped << Skipped::Assertion.new(self, description, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
# All setup blocks are disabled
|
29
|
+
def ancestry_setup # :nodoc:
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
# All teardown blocks are disabled
|
34
|
+
def ancestry_teardown # :nodoc:
|
35
|
+
[]
|
36
|
+
end
|
37
|
+
|
38
|
+
# All setup blocks are disabled
|
39
|
+
def setup(&block) # :nodoc:
|
40
|
+
[]
|
41
|
+
end
|
42
|
+
|
43
|
+
# All teardown blocks are disabled
|
44
|
+
def teardown(&block) # :nodoc:
|
45
|
+
[]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
|
11
|
+
# Skipped contains variants of Suite and Assertion.
|
12
|
+
# See Skipped::Suite and Skipped::Assertion
|
13
|
+
module Skipped
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'baretest/setup'
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
module BareTest
|
14
|
+
|
15
|
+
# A Suite is a container for multiple assertions.
|
16
|
+
# You can give a suite a description, also a suite can contain
|
17
|
+
# setup and teardown blocks that are executed before (setup) and after
|
18
|
+
# (teardown) every assertion.
|
19
|
+
#
|
20
|
+
# Suites can also be nested. Nested suites will inherit setup and teardown.
|
21
|
+
class Suite
|
22
|
+
|
23
|
+
# Nested suites, in the order of definition
|
24
|
+
attr_reader :suites
|
25
|
+
|
26
|
+
# All assertions in this suite
|
27
|
+
attr_reader :assertions
|
28
|
+
|
29
|
+
# All skipped assertions in this suite
|
30
|
+
attr_reader :skipped
|
31
|
+
|
32
|
+
# This suites description. Toplevel suites usually don't have a description.
|
33
|
+
attr_reader :description
|
34
|
+
|
35
|
+
# This suites direct parent. Nil if toplevel suite.
|
36
|
+
attr_reader :parent
|
37
|
+
|
38
|
+
# An Array containing the suite itself (first element), then its direct
|
39
|
+
# parent suite, then that suite's parent and so on
|
40
|
+
attr_reader :ancestors
|
41
|
+
|
42
|
+
# Create a new suite.
|
43
|
+
#
|
44
|
+
# The arguments 'description', 'parent' and '&block' are the same as on Suite::new,
|
45
|
+
# 'opts' is an additional options hash.
|
46
|
+
#
|
47
|
+
# Keys the options hash accepts:
|
48
|
+
# :requires:: A string or array of strings with requires that have to be done in order to run
|
49
|
+
# this suite. If a require fails, the suite is created as a Skipped::Suite instead.
|
50
|
+
#
|
51
|
+
def self.create(description=nil, parent=nil, opts={}, &block)
|
52
|
+
Array(opts[:requires]).each { |file| require file } if opts[:requires]
|
53
|
+
rescue LoadError
|
54
|
+
# A suite is skipped if requirements are not met
|
55
|
+
Skipped::Suite.new(description, parent, &block)
|
56
|
+
else
|
57
|
+
# All suites within Skipped::Suite are Skipped::Suite
|
58
|
+
(block ? self : Skipped::Suite).new(description, parent, &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Create a new suite.
|
62
|
+
#
|
63
|
+
# Arguments:
|
64
|
+
# description:: A string with a human readable description of this suite, preferably
|
65
|
+
# less than 60 characters and without newlines
|
66
|
+
# parent:: The suite that nests this suite. Ancestry plays a role in execution of setup
|
67
|
+
# and teardown blocks (all ancestors setups and teardowns are executed too).
|
68
|
+
# &block:: The given block is instance evaled.
|
69
|
+
def initialize(description=nil, parent=nil, &block)
|
70
|
+
@description = description
|
71
|
+
@parent = parent
|
72
|
+
@suites = [] # [["description", subsuite, skipped], ["description2", ...], ...] - see Array#assoc
|
73
|
+
@assertions = []
|
74
|
+
@skipped = []
|
75
|
+
@setup = {nil => []}
|
76
|
+
@components = []
|
77
|
+
@teardown = []
|
78
|
+
@ancestors = [self] + (@parent ? @parent.ancestors : [])
|
79
|
+
instance_eval(&block) if block
|
80
|
+
end
|
81
|
+
|
82
|
+
# Define a nested suite.
|
83
|
+
#
|
84
|
+
# Nested suites inherit setup & teardown methods.
|
85
|
+
# Also if an outer suite is skipped, all inner suites are skipped too.
|
86
|
+
#
|
87
|
+
# Valid values for opts:
|
88
|
+
# :requires:: A list of files to require, if one of the requires fails,
|
89
|
+
# the suite will be skipped. Accepts a String or an Array
|
90
|
+
def suite(description=nil, opts={}, &block)
|
91
|
+
suite = self.class.create(description, self, opts, &block)
|
92
|
+
if append_to = @suites.assoc(description) then
|
93
|
+
append_to.last.update(suite)
|
94
|
+
else
|
95
|
+
@suites << [description, suite]
|
96
|
+
end
|
97
|
+
suite
|
98
|
+
end
|
99
|
+
|
100
|
+
# Performs a recursive merge with the given suite.
|
101
|
+
#
|
102
|
+
# Used to merge suites with the same description.
|
103
|
+
def update(with_suite)
|
104
|
+
if ::BareTest::Skipped::Suite === with_suite then
|
105
|
+
@skipped.concat(with_suite.skipped)
|
106
|
+
else
|
107
|
+
@assertions.concat(with_suite.assertions)
|
108
|
+
@setup.update(with_suite.setup) do |k,v1,v2| v1+v2 end
|
109
|
+
@teardown.concat(with_suite.teardown)
|
110
|
+
with_suite.suites.each { |description, suite|
|
111
|
+
if append_to = @suites.assoc(description) then
|
112
|
+
append_to.last.update(suite)
|
113
|
+
else
|
114
|
+
@suites << [description, suite]
|
115
|
+
end
|
116
|
+
}
|
117
|
+
end
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
# All setups in the order of their definition and nesting (outermost first,
|
122
|
+
# innermost last)
|
123
|
+
def ancestry_setup
|
124
|
+
@parent ? @parent.ancestry_setup.merge(@setup) { |k,v1,v2|
|
125
|
+
v1+v2
|
126
|
+
} : @setup
|
127
|
+
end
|
128
|
+
|
129
|
+
# All setup-components in the order of their definition and nesting
|
130
|
+
# (outermost first, innermost last)
|
131
|
+
def ancestry_components
|
132
|
+
@parent ? @parent.ancestry_components|@components : @components
|
133
|
+
end
|
134
|
+
|
135
|
+
# All teardowns in the order of their nesting (innermost first, outermost last)
|
136
|
+
def ancestry_teardown
|
137
|
+
ancestors.map { |suite| suite.teardown }.flatten
|
138
|
+
end
|
139
|
+
|
140
|
+
# Define a setup block for this suite. The block will be ran before every
|
141
|
+
# assertion once, even for nested suites.
|
142
|
+
def setup(component=nil, multiplexed=nil, &block)
|
143
|
+
if component.nil? && block then
|
144
|
+
@setup[nil] << ::BareTest::Setup.new(nil, nil, nil, block)
|
145
|
+
elsif block then
|
146
|
+
@components << component unless @setup.has_key?(component)
|
147
|
+
@setup[component] ||= []
|
148
|
+
|
149
|
+
case multiplexed
|
150
|
+
when String
|
151
|
+
@setup[component] << ::BareTest::Setup.new(component, multiplexed, nil, block)
|
152
|
+
when Array
|
153
|
+
multiplexed.each do |substitute|
|
154
|
+
@setup[component] << BareTest::Setup.new(component, substitute.to_s, substitute, block)
|
155
|
+
end
|
156
|
+
when Hash
|
157
|
+
multiplexed.each do |substitute, value|
|
158
|
+
@setup[component] << BareTest::Setup.new(component, substitute, value, block)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
elsif component || multiplexed
|
162
|
+
raise ArgumentError, "With component or multiplexed given, a block must be provided too."
|
163
|
+
end
|
164
|
+
|
165
|
+
@setup
|
166
|
+
end
|
167
|
+
|
168
|
+
# Define a teardown block for this suite. The block will be ran after every
|
169
|
+
# assertion once, even for nested suites.
|
170
|
+
def teardown(&block)
|
171
|
+
block ? @teardown << block : @teardown
|
172
|
+
end
|
173
|
+
|
174
|
+
def each_component_variant
|
175
|
+
setups = ancestry_setup
|
176
|
+
components = ancestry_components
|
177
|
+
base = setups[nil]
|
178
|
+
|
179
|
+
if components.empty?
|
180
|
+
yield(base)
|
181
|
+
else
|
182
|
+
setup_in_order = setups.values_at(*components)
|
183
|
+
maximums = setup_in_order.map { |i| i.size }
|
184
|
+
iterations = maximums.inject { |r,f| r*f } || 0
|
185
|
+
|
186
|
+
iterations.times do |i|
|
187
|
+
process = maximums.map { |e| i,e=i.divmod(e); e }
|
188
|
+
yield base+setup_in_order.zip(process).map { |variants, current|
|
189
|
+
variants[current]
|
190
|
+
}
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
self
|
195
|
+
end
|
196
|
+
|
197
|
+
def first_component_variant
|
198
|
+
setups, *comps = ancestry_setup.values_at(nil, *ancestry_components)
|
199
|
+
setups = setups+comps.map { |comp| comp.first }
|
200
|
+
yield(setups) if block_given?
|
201
|
+
|
202
|
+
setups
|
203
|
+
end
|
204
|
+
|
205
|
+
# Define an assertion. The block is supposed to return a trueish value
|
206
|
+
# (anything but nil or false).
|
207
|
+
#
|
208
|
+
# See Assertion for more info.
|
209
|
+
def assert(description=nil, &block)
|
210
|
+
assertion = Assertion.new(self, description, &block)
|
211
|
+
if match = caller.first.match(/^(.*):(\d+)(?::.+)?$/) then
|
212
|
+
file, line = match.captures
|
213
|
+
file = File.expand_path(file)
|
214
|
+
if File.exist?(file) then
|
215
|
+
assertion.file = file
|
216
|
+
assertion.line = line.to_i
|
217
|
+
end
|
218
|
+
end
|
219
|
+
@assertions << assertion
|
220
|
+
end
|
221
|
+
|
222
|
+
def to_s #:nodoc:
|
223
|
+
sprintf "%s %s", self.class, @description
|
224
|
+
end
|
225
|
+
|
226
|
+
def inspect #:nodoc:
|
227
|
+
sprintf "#<%s:%08x %p>", self.class, object_id>>1, @description
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
|
234
|
+
require 'baretest/skipped/suite' # TODO: determine why this require is on the bottom and document it.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module Kernel
|
10
|
+
# All extensions Kernel#require_path and Kernel#expanded_require_path will try
|
11
|
+
# for a given filename
|
12
|
+
RequireExtensions = %w[.rb .so .dll .bundle .dylib]
|
13
|
+
|
14
|
+
# Returns the path to the file require would load, also see Kernel#expanded_require_path
|
15
|
+
def require_path(name, extensions=nil)
|
16
|
+
extensions = (extensions || ::Kernel::RequireExtensions).join(',')
|
17
|
+
Dir.glob("{#{$LOAD_PATH.join(',')}}/#{name}{#{extensions}}") { |path|
|
18
|
+
return path
|
19
|
+
}
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the absolute path to the file require would load, also see Kernel#require_path
|
24
|
+
def expanded_require_path(name, extensions=nil)
|
25
|
+
path = require_path(name, extensions)
|
26
|
+
path && File.expand_path(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Will load the given file like load (but accepts files without .rb in the end, like require),
|
30
|
+
# but evaluate it into the module given with the second arg (defaulting to Module.new).
|
31
|
+
# It uses Kernel#expanded_require_path with '' and '.rb' as extensions to determine the file to
|
32
|
+
# load uses the returned path for error messages (second argument to Module#modul_eval).
|
33
|
+
def load_into(name, mod=nil)
|
34
|
+
mod ||= Module.new
|
35
|
+
path = expanded_require_path(name, ['', '.rb'])
|
36
|
+
raise LoadError, "No such file to load -- #{name}" unless path
|
37
|
+
mod.module_eval(File.read(path), path)
|
38
|
+
|
39
|
+
mod
|
40
|
+
end
|
41
|
+
|
42
|
+
module_function :require_path, :expanded_require_path, :load_into
|
43
|
+
end
|
@@ -6,12 +6,21 @@
|
|
6
6
|
|
7
7
|
|
8
8
|
|
9
|
-
module
|
9
|
+
module BareTest
|
10
|
+
|
11
|
+
# The version of the baretest library
|
10
12
|
module VERSION
|
13
|
+
|
14
|
+
# The major version number
|
11
15
|
MAJOR = 0
|
12
|
-
MINOR = 1
|
13
|
-
TINY = 0
|
14
16
|
|
17
|
+
# The minor version number
|
18
|
+
MINOR = 2
|
19
|
+
|
20
|
+
# The tiny version number
|
21
|
+
TINY = 3
|
22
|
+
|
23
|
+
# The version as a string
|
15
24
|
def self.to_s
|
16
25
|
"#{MAJOR}.#{MINOR||0}.#{TINY||0}"
|
17
26
|
end
|
data/lib/baretest.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'baretest/assertion'
|
10
|
+
require 'baretest/irb_mode'
|
11
|
+
require 'baretest/run'
|
12
|
+
require 'baretest/suite'
|
13
|
+
require 'baretest/utilities'
|
14
|
+
require 'baretest/version'
|
15
|
+
# See bottom for more requires
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
module BareTest
|
20
|
+
class << self
|
21
|
+
# A hash of formatters (require-string => module) to be used with Test::Run.
|
22
|
+
attr_reader :format
|
23
|
+
|
24
|
+
# For mock integration and others, append modules that should extend the Test::Run instance.
|
25
|
+
attr_reader :extender
|
26
|
+
|
27
|
+
# The toplevel suite. That's the one run_if_mainfile and define add suites
|
28
|
+
# and assertions to.
|
29
|
+
attr_reader :toplevel_suite
|
30
|
+
|
31
|
+
# The full path to this file
|
32
|
+
# Needed to test baretest itself using baretest
|
33
|
+
attr_reader :required_file # :nodoc:
|
34
|
+
end
|
35
|
+
|
36
|
+
# Loads all files in a test directory in order to load the suites and
|
37
|
+
# assertions. Used by the 'baretest' executable and the standard rake task.
|
38
|
+
#
|
39
|
+
# Options:
|
40
|
+
# :verbose:: Will print information about the load process (default: false)
|
41
|
+
# :setup_path:: The path to the setup file, the first loaded file (default: 'test/setup.rb')
|
42
|
+
# :chdir:: The directory this routine chdirs before loading, will jump back to the original
|
43
|
+
# directory after loading (default: '.')
|
44
|
+
def self.load_standard_test_files(opts={})
|
45
|
+
verbose = opts.delete(:verbose)
|
46
|
+
setup_path = opts.delete(:setup_path) || 'test/setup.rb'
|
47
|
+
chdir = opts.delete(:chdir) || '.'
|
48
|
+
Dir.chdir(chdir) do
|
49
|
+
load(setup_path) if File.exist?(setup_path)
|
50
|
+
Dir.glob('test/{suite,unit,integration,system}/**/*.rb') { |path|
|
51
|
+
helper_path = path.sub(%r{^test/(suite|unit|integration|system)/}, 'test/helper/\1/')
|
52
|
+
puts(File.exist?(helper_path) ? "Loading helper file #{helper_path}" : "No helper file #{helper_path} to load") if verbose
|
53
|
+
load(helper_path) if File.exist?(helper_path)
|
54
|
+
puts "Loading test file #{path}" if verbose
|
55
|
+
load(path)
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Initializes BareTest, is automatically called
|
61
|
+
#
|
62
|
+
# Needed for bootstrapped selftest
|
63
|
+
def self.init # :nodoc:
|
64
|
+
@format = {}
|
65
|
+
@extender = []
|
66
|
+
@toplevel_suite = BareTest::Suite.new
|
67
|
+
@required_file = ["", *$LOAD_PATH].map { |path|
|
68
|
+
File.expand_path(File.join(path, __FILE__))
|
69
|
+
}.find { |full| File.exist?(full) }
|
70
|
+
end
|
71
|
+
init
|
72
|
+
|
73
|
+
# If no description was given, it adds the contained assertions and suites to the toplevel suite,
|
74
|
+
# if a description was given, a suite with the given description is created, added to the toplevel
|
75
|
+
# suite, and all the contained assertions and suites are added to the created suite.
|
76
|
+
def self.suite(description=nil, opts={}, &block)
|
77
|
+
if description then
|
78
|
+
@toplevel_suite.suite(description, opts, &block)
|
79
|
+
elsif opts && !opts.empty?
|
80
|
+
raise ArgumentError, "Suites with options must have names"
|
81
|
+
else
|
82
|
+
@toplevel_suite.instance_eval(&block)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Creates a Test::Run instance, adds the assertions and suites defined in its
|
87
|
+
# own block to that Test::Run instance's toplevel suite and if $PROGRAM_NAME
|
88
|
+
# (aka $0) is equal to \_\_FILE__ (means the current file is the file directly
|
89
|
+
# executed by ruby, and not just required/loaded/evaled by another file),
|
90
|
+
# subsequently also runs that suite.
|
91
|
+
def self.run_if_mainfile(description=nil, opts={}, &block)
|
92
|
+
suite(description, opts, &block)
|
93
|
+
if caller.first[/^[^:]*/] == $0 then # if is mainfile
|
94
|
+
run(:format => ENV['FORMAT'], :interactive => ENV['INTERACTIVE'])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Runs the toplevel suite (which usually contains all suites and assertions
|
99
|
+
# defined in all loaded test files).
|
100
|
+
#
|
101
|
+
# Returns the Run instance.
|
102
|
+
def self.run(opts=nil)
|
103
|
+
runner = BareTest::Run.new(@toplevel_suite, opts)
|
104
|
+
runner.run_all
|
105
|
+
runner
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
# At bottom due to dependencies
|
112
|
+
require 'baretest/assertion/support' # Needs Test.extender to be defined
|