assert 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|