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.
Files changed (52) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +6 -0
  3. data/Gemfile.lock +17 -0
  4. data/README.rdoc +77 -0
  5. data/Rakefile +7 -0
  6. data/assert.gemspec +21 -0
  7. data/examples/empty_test.rb +5 -0
  8. data/examples/results_test.rb +25 -0
  9. data/examples/single_test.rb +9 -0
  10. data/lib/assert.rb +8 -0
  11. data/lib/assert/assertions.rb +253 -0
  12. data/lib/assert/context.rb +196 -0
  13. data/lib/assert/options.rb +43 -0
  14. data/lib/assert/rake_tasks.rb +95 -0
  15. data/lib/assert/result.rb +164 -0
  16. data/lib/assert/result_set.rb +14 -0
  17. data/lib/assert/runner.rb +60 -0
  18. data/lib/assert/setup/autorun.rb +34 -0
  19. data/lib/assert/setup/helpers.rb +62 -0
  20. data/lib/assert/setup/suite.rb +12 -0
  21. data/lib/assert/setup/view.rb +11 -0
  22. data/lib/assert/suite.rb +128 -0
  23. data/lib/assert/test.rb +90 -0
  24. data/lib/assert/version.rb +3 -0
  25. data/lib/assert/view/base.rb +54 -0
  26. data/lib/assert/view/terminal.rb +138 -0
  27. data/test/assertions/assert_block_test.rb +39 -0
  28. data/test/assertions/assert_instance_of_test.rb +43 -0
  29. data/test/assertions/assert_kind_of_test.rb +43 -0
  30. data/test/assertions/assert_not_block_test.rb +39 -0
  31. data/test/assertions/assert_not_instance_of_test.rb +43 -0
  32. data/test/assertions/assert_not_kind_of_test.rb +43 -0
  33. data/test/assertions/assert_not_respond_to_test.rb +43 -0
  34. data/test/assertions/assert_nothing_raised_test.rb +46 -0
  35. data/test/assertions/assert_raises_test.rb +49 -0
  36. data/test/assertions/assert_respond_to_test.rb +43 -0
  37. data/test/assertions_test.rb +334 -0
  38. data/test/context/class_methods_test.rb +314 -0
  39. data/test/context_test.rb +288 -0
  40. data/test/fixtures/inherited_stuff.rb +36 -0
  41. data/test/fixtures/sample_context.rb +13 -0
  42. data/test/helper.rb +52 -0
  43. data/test/irb.rb +10 -0
  44. data/test/options_test.rb +78 -0
  45. data/test/result_set_test.rb +89 -0
  46. data/test/result_test.rb +255 -0
  47. data/test/runner_test.rb +33 -0
  48. data/test/suite_test.rb +200 -0
  49. data/test/test/running_test.rb +327 -0
  50. data/test/test_test.rb +184 -0
  51. data/test/view_test.rb +35 -0
  52. metadata +155 -0
@@ -0,0 +1,14 @@
1
+ module Assert
2
+ class ResultSet < ::Array
3
+
4
+ attr_accessor :view
5
+
6
+ def <<(result)
7
+ super
8
+ if @view && @view.respond_to?(:print_runtime_result)
9
+ @view.print_runtime_result(result)
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -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
@@ -0,0 +1,12 @@
1
+ require 'assert/context'
2
+ require 'assert/suite'
3
+
4
+ module Assert
5
+
6
+ # Setup the default global suite for collecting tests as contexts are defined
7
+ @@suite = Suite.new
8
+ class << self
9
+ def suite; @@suite; end
10
+ end
11
+
12
+ end
@@ -0,0 +1,11 @@
1
+ require 'assert/view/terminal'
2
+
3
+ module Assert
4
+
5
+ # Setup the default view to render test results (override in user or package helpers)
6
+ @@view = View::Terminal.new(self.suite, $stdout)
7
+ class << self
8
+ def view; @@view; end
9
+ end
10
+
11
+ end
@@ -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
@@ -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,3 @@
1
+ module Assert
2
+ VERSION = "0.1.0"
3
+ 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