assert 0.1.0
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/.gitignore +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +17 -0
- data/README.rdoc +77 -0
- data/Rakefile +7 -0
- data/assert.gemspec +21 -0
- data/examples/empty_test.rb +5 -0
- data/examples/results_test.rb +25 -0
- data/examples/single_test.rb +9 -0
- data/lib/assert.rb +8 -0
- data/lib/assert/assertions.rb +253 -0
- data/lib/assert/context.rb +196 -0
- data/lib/assert/options.rb +43 -0
- data/lib/assert/rake_tasks.rb +95 -0
- data/lib/assert/result.rb +164 -0
- data/lib/assert/result_set.rb +14 -0
- data/lib/assert/runner.rb +60 -0
- data/lib/assert/setup/autorun.rb +34 -0
- data/lib/assert/setup/helpers.rb +62 -0
- data/lib/assert/setup/suite.rb +12 -0
- data/lib/assert/setup/view.rb +11 -0
- data/lib/assert/suite.rb +128 -0
- data/lib/assert/test.rb +90 -0
- data/lib/assert/version.rb +3 -0
- data/lib/assert/view/base.rb +54 -0
- data/lib/assert/view/terminal.rb +138 -0
- data/test/assertions/assert_block_test.rb +39 -0
- data/test/assertions/assert_instance_of_test.rb +43 -0
- data/test/assertions/assert_kind_of_test.rb +43 -0
- data/test/assertions/assert_not_block_test.rb +39 -0
- data/test/assertions/assert_not_instance_of_test.rb +43 -0
- data/test/assertions/assert_not_kind_of_test.rb +43 -0
- data/test/assertions/assert_not_respond_to_test.rb +43 -0
- data/test/assertions/assert_nothing_raised_test.rb +46 -0
- data/test/assertions/assert_raises_test.rb +49 -0
- data/test/assertions/assert_respond_to_test.rb +43 -0
- data/test/assertions_test.rb +334 -0
- data/test/context/class_methods_test.rb +314 -0
- data/test/context_test.rb +288 -0
- data/test/fixtures/inherited_stuff.rb +36 -0
- data/test/fixtures/sample_context.rb +13 -0
- data/test/helper.rb +52 -0
- data/test/irb.rb +10 -0
- data/test/options_test.rb +78 -0
- data/test/result_set_test.rb +89 -0
- data/test/result_test.rb +255 -0
- data/test/runner_test.rb +33 -0
- data/test/suite_test.rb +200 -0
- data/test/test/running_test.rb +327 -0
- data/test/test_test.rb +184 -0
- data/test/view_test.rb +35 -0
- metadata +155 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'assert/view/terminal'
|
2
|
+
|
3
|
+
module Assert
|
4
|
+
class Runner
|
5
|
+
|
6
|
+
# a Runner runs a suite of tests.
|
7
|
+
|
8
|
+
def initialize(suite, view)
|
9
|
+
raise ArgumentError if !suite.kind_of?(Suite)
|
10
|
+
@suite = suite
|
11
|
+
@view = view
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(*args)
|
15
|
+
@suite.setup_blocks.each do |setup| # TODO: tests!
|
16
|
+
setup.call
|
17
|
+
end
|
18
|
+
@view.render do
|
19
|
+
benchmark { run_suite }
|
20
|
+
end
|
21
|
+
@suite.teardown_blocks.each do |teardown| # TODO: tests!
|
22
|
+
teardown.call
|
23
|
+
end
|
24
|
+
count(:failed) + count(:errored)
|
25
|
+
end
|
26
|
+
|
27
|
+
def count(type)
|
28
|
+
@suite.count(type)
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def tests_to_run
|
34
|
+
tests = @suite.tests
|
35
|
+
|
36
|
+
# order tests randomly
|
37
|
+
max = tests.size
|
38
|
+
srand
|
39
|
+
seed = srand % 0xFFFF
|
40
|
+
srand seed
|
41
|
+
tests.sort.sort_by { rand max }
|
42
|
+
tests
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def benchmark
|
48
|
+
@suite.start_time = Time.now
|
49
|
+
yield if block_given?
|
50
|
+
@suite.end_time = Time.now
|
51
|
+
end
|
52
|
+
|
53
|
+
def run_suite
|
54
|
+
# TODO: parallel running
|
55
|
+
tests_to_run.each {|test| test.run(@view)}
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'assert/runner'
|
2
|
+
|
3
|
+
module Assert
|
4
|
+
|
5
|
+
# a flag to know if at_exit hook has been installed already
|
6
|
+
@@at_exit_installed ||= false
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# install at_exit hook (if needed) (runs at process exit)
|
11
|
+
# this ensures the test suite won't run unitl all test files are loaded
|
12
|
+
# (this is essentially a direct rip from Minitest)
|
13
|
+
def autorun
|
14
|
+
at_exit do
|
15
|
+
# don't run if there was an exception
|
16
|
+
next if $!
|
17
|
+
|
18
|
+
# the order here is important. The at_exit handler must be
|
19
|
+
# installed before anyone else gets a chance to install their
|
20
|
+
# own, that way we can be assured that our exit will be last
|
21
|
+
# to run (at_exit stacks).
|
22
|
+
|
23
|
+
exit_code = nil
|
24
|
+
at_exit { exit(false) if exit_code && exit_code != 0 }
|
25
|
+
# TODO: read options from a config for extentions??
|
26
|
+
Runner.new(self.suite, self.view).run
|
27
|
+
end unless @@at_exit_installed
|
28
|
+
@@at_exit_installed = true
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Assert
|
2
|
+
module Helpers
|
3
|
+
|
4
|
+
# when Assert is required it will automatically require in two helper files
|
5
|
+
# if they exist:
|
6
|
+
# * "./test/helper.rb - package-specific helpers
|
7
|
+
# * ~/.assert.rb - user-specific helpers (options, view, etc...)
|
8
|
+
# the user-specific helper file will always be required in after the
|
9
|
+
# package-specific one
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
# assume the test dir path is ./test and look for helpers in ./test/helper.rb
|
14
|
+
PACKAGE_TEST_DIR = "test"
|
15
|
+
PACKAGE_HELPER_FILE = "helper"
|
16
|
+
TEST_REGEX = /^#{PACKAGE_TEST_DIR}$|^#{PACKAGE_TEST_DIR}\/|\/#{PACKAGE_TEST_DIR}\/|\/#{PACKAGE_TEST_DIR}$/
|
17
|
+
|
18
|
+
USER_TEST_HELPER = "~/.assert"
|
19
|
+
|
20
|
+
def load(caller_info)
|
21
|
+
if (crp = caller_root_path(caller_info))
|
22
|
+
require_package_test_helper(crp)
|
23
|
+
end
|
24
|
+
require_user_test_helper
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def require_user_test_helper
|
30
|
+
begin
|
31
|
+
require File.expand_path(USER_TEST_HELPER)
|
32
|
+
rescue LoadError => err
|
33
|
+
# do nothing
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# require the package's test/helper file if it exists
|
38
|
+
def require_package_test_helper(root_path)
|
39
|
+
begin
|
40
|
+
require package_helper_file(root_path)
|
41
|
+
rescue LoadError => err
|
42
|
+
warn err.message
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def package_helper_file(root_path)
|
47
|
+
File.join(root_path, PACKAGE_TEST_DIR, PACKAGE_HELPER_FILE+'.rb')
|
48
|
+
end
|
49
|
+
|
50
|
+
# this method inspects the caller info and finds the caller's root path
|
51
|
+
# this expects the caller's root path to be the parent dir of the first
|
52
|
+
# parent dir of caller named TEST_DIR
|
53
|
+
def caller_root_path(caller_info)
|
54
|
+
caller_dirname = File.expand_path(File.dirname(caller_info[0]))
|
55
|
+
if (test_dir_pos = caller_dirname.index(TEST_REGEX)) > 0
|
56
|
+
root_dir = caller_dirname[0..(test_dir_pos-1)]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
data/lib/assert/suite.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'assert/test'
|
2
|
+
|
3
|
+
module Assert
|
4
|
+
class Suite < ::Hash
|
5
|
+
|
6
|
+
# A suite is a set of tests to run. When a test class subclasses
|
7
|
+
# the Context class, that test class is pushed to the suite.
|
8
|
+
|
9
|
+
attr_accessor :start_time, :end_time, :setup_blocks, :teardown_blocks
|
10
|
+
|
11
|
+
def run_time
|
12
|
+
(@end_time || 0) - (@start_time || 0)
|
13
|
+
end
|
14
|
+
|
15
|
+
def <<(context_klass)
|
16
|
+
# gsub off any trailing 'Test'
|
17
|
+
self[context_klass] ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
def contexts
|
21
|
+
self.keys.sort{|a,b| a.to_s <=> b.to_s}
|
22
|
+
end
|
23
|
+
|
24
|
+
def tests
|
25
|
+
prep
|
26
|
+
self.values.flatten
|
27
|
+
end
|
28
|
+
|
29
|
+
def ordered_tests(klass=nil)
|
30
|
+
prep
|
31
|
+
(klass.nil? ? self.contexts : [klass]).inject([]) do |tests, klass|
|
32
|
+
tests += (self[klass] || [])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def ordered_results(klass=nil)
|
37
|
+
ordered_tests(klass).inject([]) do |results, test|
|
38
|
+
results += test.results
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_count(klass=nil)
|
43
|
+
prep
|
44
|
+
count_tests(klass.nil? ? self.values : [self[klass]])
|
45
|
+
end
|
46
|
+
|
47
|
+
def result_count(type=nil)
|
48
|
+
prep
|
49
|
+
count_results(self.values, type)
|
50
|
+
end
|
51
|
+
|
52
|
+
def count(thing)
|
53
|
+
case thing
|
54
|
+
when :tests
|
55
|
+
test_count
|
56
|
+
when :results
|
57
|
+
result_count
|
58
|
+
when :passed, :pass
|
59
|
+
result_count(:pass)
|
60
|
+
when :failed, :fail
|
61
|
+
result_count(:fail)
|
62
|
+
when :ignored, :ignore
|
63
|
+
result_count(:ignore)
|
64
|
+
when :skipped, :skip
|
65
|
+
result_count(:skip)
|
66
|
+
when :errored, :error
|
67
|
+
result_count(:error)
|
68
|
+
else
|
69
|
+
0
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def setup_blocks
|
74
|
+
@setup_blocks ||= []
|
75
|
+
end
|
76
|
+
|
77
|
+
def teardown_blocks
|
78
|
+
@teardown_blocks ||= []
|
79
|
+
end
|
80
|
+
|
81
|
+
# TODO: tests!
|
82
|
+
def setup(&block)
|
83
|
+
raise ArgumentError, "please provide a setup block" unless block_given?
|
84
|
+
self.setup_blocks << block
|
85
|
+
end
|
86
|
+
|
87
|
+
# TODO: tests!
|
88
|
+
def teardown(&block)
|
89
|
+
raise ArgumentError, "please provide a teardown block" unless block_given?
|
90
|
+
self.teardown_blocks << block
|
91
|
+
end
|
92
|
+
|
93
|
+
protected
|
94
|
+
|
95
|
+
def local_public_test_methods(klass)
|
96
|
+
methods = klass.public_instance_methods
|
97
|
+
while (klass.superclass)
|
98
|
+
methods -= (klass = klass.superclass).public_instance_methods
|
99
|
+
end
|
100
|
+
methods.delete_if {|method_name| method_name !~ /^test./ }
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def count_tests(test_sets)
|
106
|
+
test_sets.inject(0) {|count, tests| count += tests.size}
|
107
|
+
end
|
108
|
+
|
109
|
+
def count_results(test_sets, type)
|
110
|
+
self.values.flatten.inject(0){|count, test| count += test.result_count(type) }
|
111
|
+
end
|
112
|
+
|
113
|
+
def prep
|
114
|
+
if @prepared != true
|
115
|
+
# look for local public methods starting with 'test_'and add
|
116
|
+
self.each do |context_class, tests|
|
117
|
+
local_public_test_methods(context_class).each do |meth|
|
118
|
+
tests << Test.new(meth.to_s, context_class, meth)
|
119
|
+
end
|
120
|
+
tests.uniq
|
121
|
+
end
|
122
|
+
end
|
123
|
+
@prepared = true
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
data/lib/assert/test.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'assert/result'
|
2
|
+
require 'assert/result_set'
|
3
|
+
|
4
|
+
module Assert
|
5
|
+
class Test
|
6
|
+
|
7
|
+
# a Test is some code/method to run in the scope of a Context. After a
|
8
|
+
# a test runs, it should have some assertions which are its results.
|
9
|
+
|
10
|
+
attr_reader :name, :code, :context_class
|
11
|
+
attr_accessor :results
|
12
|
+
|
13
|
+
def initialize(name, context_class, code = nil, &block)
|
14
|
+
@context_class = context_class
|
15
|
+
@name = name_from_context(name)
|
16
|
+
@code = (code || block)
|
17
|
+
@results = ResultSet.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def run(view=nil)
|
21
|
+
@results.view = view
|
22
|
+
begin
|
23
|
+
run_scope = @context_class.new(self)
|
24
|
+
run_setup(run_scope)
|
25
|
+
if @code.kind_of?(::Proc)
|
26
|
+
run_scope.instance_eval(&@code)
|
27
|
+
elsif run_scope.respond_to?(@code.to_s)
|
28
|
+
run_scope.send(@code.to_s)
|
29
|
+
end
|
30
|
+
rescue Result::TestSkipped => err
|
31
|
+
@results << Result::Skip.new(self.name, err)
|
32
|
+
rescue Exception => err
|
33
|
+
@results << Result::Error.new(self.name, err)
|
34
|
+
ensure
|
35
|
+
begin
|
36
|
+
run_teardown(run_scope) if run_scope
|
37
|
+
rescue Exception => teardown_err
|
38
|
+
@results << Result::Error.new(self.name, teardown_err)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
@results.view = nil
|
42
|
+
@results
|
43
|
+
end
|
44
|
+
|
45
|
+
def run_setup(scope)
|
46
|
+
@context_class.all_setup_blocks.each do |setup|
|
47
|
+
scope.instance_eval(&setup)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def run_teardown(scope)
|
52
|
+
@context_class.all_teardown_blocks.each do |teardown|
|
53
|
+
scope.instance_eval(&teardown)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Assert::Result.types.each do |name, klass|
|
58
|
+
define_method "#{name}_results" do
|
59
|
+
@results.select{|r| r.kind_of?(klass) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def result_count(type=nil)
|
64
|
+
if Assert::Result.types.include?(type)
|
65
|
+
self.send("#{type}_results").size
|
66
|
+
else
|
67
|
+
@results.size
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def <=>(other_test)
|
72
|
+
self.name <=> other_test.name
|
73
|
+
end
|
74
|
+
|
75
|
+
def inspect
|
76
|
+
attributes_string = ([ :name, :context_class, :results ].collect do |attr|
|
77
|
+
"@#{attr}=#{self.send(attr).inspect}"
|
78
|
+
end).join(" ")
|
79
|
+
"#<#{self.class} #{attributes_string}>"
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
|
84
|
+
def name_from_context(name)
|
85
|
+
name = name.gsub(/^test:\s+should/, "should")
|
86
|
+
[ @context_class.full_description, name ].compact.join(" ")
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'assert/options'
|
2
|
+
|
3
|
+
module Assert::View
|
4
|
+
|
5
|
+
class Base
|
6
|
+
include Assert::Options
|
7
|
+
|
8
|
+
attr_reader :suite
|
9
|
+
|
10
|
+
def initialize(suite, output_io)
|
11
|
+
@suite = suite
|
12
|
+
@out = output_io
|
13
|
+
end
|
14
|
+
|
15
|
+
# override this to define how a view calls the runner and renders its results
|
16
|
+
def render(*args, &runner)
|
17
|
+
end
|
18
|
+
|
19
|
+
def print_runtime_result(result)
|
20
|
+
sym = result.to_sym
|
21
|
+
if self.respond_to?(:options)
|
22
|
+
io_print(self.options.send("#{sym}_abbrev"))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def io_puts(msg, opts={})
|
29
|
+
@out.puts(io_msg(msg, opts={}))
|
30
|
+
end
|
31
|
+
|
32
|
+
def io_print(msg, opts={})
|
33
|
+
@out.print(io_msg(msg, opts={}))
|
34
|
+
end
|
35
|
+
|
36
|
+
def io_msg(msg, opts={})
|
37
|
+
if msg.kind_of?(::Symbol) && self.respond_to?(msg)
|
38
|
+
self.send(msg).to_s
|
39
|
+
else
|
40
|
+
msg.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def run_time(format='%.6f')
|
45
|
+
format % @suite.run_time
|
46
|
+
end
|
47
|
+
|
48
|
+
def count(type)
|
49
|
+
@suite.count(type)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|