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,196 @@
1
+ require 'assert/suite'
2
+ require 'assert/assertions'
3
+ require 'assert/result'
4
+
5
+ module Assert
6
+ class Context
7
+ include Assert::Assertions
8
+
9
+ # a Context is a scope for tests to run in. Contexts have setup and
10
+ # teardown blocks, subjects, and descriptions. Tests are run in the
11
+ # scope of a Context instance. Therefore, a Context should have
12
+ # minimal base logic/methods/instance_vars. The instance should remain
13
+ # pure to not pollute test scopes.
14
+
15
+ # if a class subclasses Context, add it to the suite
16
+ def self.inherited(klass)
17
+ Assert.suite << klass
18
+ end
19
+
20
+ # put all logic here to keep context instances pure for running tests
21
+ class << self
22
+ attr_accessor :subject_block
23
+
24
+ def setup_once(&block)
25
+ Assert.suite.setup(&block)
26
+ end
27
+ alias_method :before_once, :setup_once
28
+
29
+ def teardown_once(&block)
30
+ Assert.suite.teardown(&block)
31
+ end
32
+ alias_method :after_once, :teardown_once
33
+
34
+ def setup(&block)
35
+ raise ArgumentError, "please provide a setup block" unless block_given?
36
+ self.setup_blocks << block
37
+ end
38
+ alias_method :before, :setup
39
+
40
+ def teardown(&block)
41
+ raise ArgumentError, "please provide a teardown block" unless block_given?
42
+ self.teardown_blocks << block
43
+ end
44
+ alias_method :after, :teardown
45
+
46
+ def setup_blocks
47
+ @setup_blocks ||= []
48
+ end
49
+
50
+ def teardown_blocks
51
+ @teardown_blocks ||= []
52
+ end
53
+
54
+ def all_setup_blocks
55
+ inherited_blocks = if superclass.respond_to?(:all_setup_blocks)
56
+ superclass.all_setup_blocks
57
+ end
58
+ (inherited_blocks || []) + self.setup_blocks
59
+ end
60
+
61
+ def all_teardown_blocks
62
+ inherited_blocks = if superclass.respond_to?(:all_teardown_blocks)
63
+ superclass.all_teardown_blocks
64
+ end
65
+ (inherited_blocks || []) + self.teardown_blocks
66
+ end
67
+
68
+ def desc(text)
69
+ raise ArgumentError, "no context description provided" if text.nil?
70
+ self.descriptions << text
71
+ end
72
+ alias_method :description, :desc
73
+
74
+ def descriptions
75
+ @descriptions ||= []
76
+ end
77
+
78
+ def full_description
79
+ inherited_description = if superclass.respond_to?(:full_description)
80
+ superclass.full_description
81
+ end
82
+ parts = [ inherited_description ].push(self.descriptions).flatten.reject do |part|
83
+ !part || part.to_s.empty?
84
+ end
85
+ parts.join(" ") if !parts.empty?
86
+ end
87
+
88
+ def subject(&block)
89
+ raise ArgumentError, "please provide a subject block" unless block_given?
90
+ self.subject_block = block
91
+ end
92
+
93
+ def subject_block
94
+ @subject_block ||= if superclass.respond_to?(:subject_block)
95
+ superclass.subject_block
96
+ end
97
+ end
98
+
99
+ def should(desc, &block)
100
+ raise ArgumentError, "please provide a test block" unless block_given?
101
+ method_name = "test: should #{desc}"
102
+ if method_defined?(method_name)
103
+ from = caller.first
104
+ puts "WARNING: should #{desc.inspect} is redefining #{method_name}!"
105
+ puts " from: #{from}"
106
+ end
107
+ define_method(method_name, &block)
108
+ end
109
+
110
+ def should_eventually(desc, &block)
111
+ should(desc){ skip }
112
+ end
113
+
114
+ end
115
+
116
+ def initialize(running_test = nil)
117
+ @__running_test__ = running_test
118
+ end
119
+
120
+ # check if the assertion is a truthy value, if so create a new pass result, otherwise
121
+ # create a new fail result with the desc and what failed msg.
122
+ # all other assertion helpers use this one in the end
123
+ def assert(assertion, fail_desc=nil, what_failed_msg=nil)
124
+ what_failed_msg ||= "Failed assert: assertion was <#{assertion.inspect}>."
125
+ msg = fail_message(fail_desc) { what_failed_msg }
126
+ assertion ? pass : fail(msg)
127
+ end
128
+
129
+ # the opposite of assert, check if the assertion is a false value, if so create a new pass
130
+ # result, otherwise create a new fail result with the desc and it's what failed msg
131
+ def assert_not(assertion, fail_desc=nil)
132
+ what_failed_msg = "Failed assert_not: assertion was <#{assertion.inspect}>."
133
+ assert(!assertion, fail_desc, what_failed_msg)
134
+ end
135
+ alias_method :refute, :assert_not
136
+
137
+ # adds a Skip result to the end of the test's results and breaks test execution
138
+ def skip(skip_msg=nil)
139
+ raise(Result::TestSkipped, skip_msg || "")
140
+ end
141
+
142
+ # adds a Pass result to the end of the test's results
143
+ # does not break test execution
144
+ def pass(pass_msg=nil)
145
+ capture_result do |test_name, backtrace|
146
+ Assert::Result::Pass.new(test_name, pass_msg, backtrace)
147
+ end
148
+ end
149
+
150
+ # adds a Fail result to the end of the test's results
151
+ # does not break test execution
152
+ def fail(fail_msg=nil)
153
+ capture_result do |test_name, backtrace|
154
+ message = (fail_message(fail_msg) { }).call
155
+ Assert::Result::Fail.new(test_name, message, backtrace)
156
+ end
157
+ end
158
+ alias_method :flunk, :fail
159
+
160
+ # adds an Ignore result to the end of the test's results
161
+ # does not break test execution
162
+ def ignore(ignore_msg=nil)
163
+ capture_result do |test_name, backtrace|
164
+ Assert::Result::Ignore.new(test_name, ignore_msg, backtrace)
165
+ end
166
+ end
167
+
168
+ def subject
169
+ if subject_block = self.class.subject_block
170
+ instance_eval(&subject_block)
171
+ end
172
+ end
173
+
174
+ def inspect
175
+ "#<#{self.class}>"
176
+ end
177
+
178
+ protected
179
+
180
+ def capture_result
181
+ if block_given?
182
+ result = yield @__running_test__.name, caller
183
+ @__running_test__.results << result
184
+ result
185
+ end
186
+ end
187
+
188
+ # Returns a Proc that will output a custom message along with the default fail message.
189
+ def fail_message(fail_desc=nil, &what_failed)
190
+ fail_desc.kind_of?(::Proc) ? fail_desc : Proc.new do
191
+ [ what_failed.call, fail_desc ].compact.join("\n")
192
+ end
193
+ end
194
+
195
+ end
196
+ end
@@ -0,0 +1,43 @@
1
+ module Assert
2
+ module Options
3
+
4
+ class Base
5
+ def method_missing(method, *args, &block)
6
+ if args.empty?
7
+ self.instance_variable_get("@#{method}")
8
+ else
9
+ value = args.size == 1 ? args.first : args
10
+ self.instance_variable_set("@#{method}", value)
11
+ if method.to_s =~ /^default_/
12
+ self.instance_variable_set("@#{$'}", value)
13
+ end
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ def self.included(receiver)
20
+ receiver.send(:class_variable_set, "@@options", Base.new)
21
+ receiver.send(:extend, ClassMethods)
22
+ receiver.send(:include, InstanceMethods)
23
+ end
24
+
25
+ module ClassMethods
26
+ def options(&block)
27
+ options = self.send(:class_variable_get, "@@options")
28
+ if block_given?
29
+ options.instance_eval(&block)
30
+ else
31
+ options
32
+ end
33
+ end
34
+ end
35
+
36
+ module InstanceMethods
37
+ def options
38
+ self.class.options
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,95 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ module Assert; end
5
+ module Assert::RakeTasks
6
+
7
+ FILE_SUFFIX = "_test.rb"
8
+
9
+ class TestTask < Rake::TaskLib
10
+ attr_accessor :name, :description, :test_files
11
+
12
+ # Create a testing task.
13
+ def initialize(name=:test)
14
+ @name = name
15
+ @description = "Run tests" + (@name==:test ? "" : " for #{@name}")
16
+ @test_files = []
17
+ yield self if block_given?
18
+ end
19
+
20
+ # Define the rake task to run this test suite
21
+ def to_task
22
+ desc @description
23
+ task @name do
24
+ RakeFileUtils.verbose(true) { ruby "\"#{rake_loader}\" " + file_list }
25
+ end
26
+ end
27
+
28
+ def file_list # :nodoc:
29
+ @test_files.collect{|f| "\"#{f}\""}.join(' ')
30
+ end
31
+
32
+ protected
33
+
34
+ def rake_loader # :nodoc:
35
+ find_file('rake/rake_test_loader') or
36
+ fail "unable to find rake test loader"
37
+ end
38
+
39
+ def find_file(fn) # :nodoc:
40
+ $LOAD_PATH.each do |path|
41
+ file_path = File.join(path, "#{fn}.rb")
42
+ return file_path if File.exist? file_path
43
+ end
44
+ nil
45
+ end
46
+ end
47
+
48
+ class << self
49
+ def for(test_namespace = :test)
50
+ self.irb_task(test_namespace.to_s)
51
+ self.to_tasks(test_namespace.to_s)
52
+ end
53
+
54
+ def irb_task(path)
55
+ irb_file = File.join(path, "irb.rb")
56
+ if File.exist?(irb_file)
57
+ desc "Open irb preloaded with #{irb_file}"
58
+ task :irb do
59
+ sh "irb -rubygems -r ./#{irb_file}"
60
+ end
61
+ end
62
+ end
63
+
64
+ def to_tasks(path)
65
+ suite_name = File.basename(path)
66
+
67
+ # define a rake test task for all top-level test files at this path
68
+ if !Dir.glob(File.join(path, "**/*#{FILE_SUFFIX}")).empty?
69
+ TestTask.new(suite_name.to_sym) do |t|
70
+ file_location = suite_name == path ? '' : " for #{File.join(path.split(File::SEPARATOR)[1..-1])}"
71
+ t.description = "Run all tests#{file_location}"
72
+ t.test_files = FileList["#{path}/**/*#{FILE_SUFFIX}"]
73
+ end.to_task
74
+ end
75
+
76
+ namespace suite_name.to_s do
77
+ # define rake test tasks for each top-level test file individually
78
+ Dir.glob(File.join(path, "*#{FILE_SUFFIX}")).each do |test_file|
79
+ test_name = File.basename(test_file, FILE_SUFFIX)
80
+ TestTask.new(test_name.to_sym) do |t|
81
+ t.description = "Run tests for #{[path.split(File::SEPARATOR), test_name].flatten[1..-1].join(':')}"
82
+ t.test_files = FileList[test_file]
83
+ end.to_task
84
+ end
85
+
86
+ # recursively define rake test tasks for each file
87
+ # in each top-level directory
88
+ Dir.glob(File.join(path, "*/")).each do |test_dir|
89
+ self.to_tasks(test_dir)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ end
@@ -0,0 +1,164 @@
1
+ module Assert; end
2
+ module Assert::Result
3
+
4
+ class Base; end
5
+ class Pass < Base; end
6
+ class Fail < Base; end
7
+ class Ignore < Base; end
8
+ class FromException < Base; end
9
+ class Error < FromException; end
10
+ class Skip < FromException; end
11
+
12
+ class << self
13
+ def types
14
+ { :pass => Pass,
15
+ :fail => Fail,
16
+ :ignore => Ignore,
17
+ :skip => Skip,
18
+ :error => Error
19
+ }
20
+ end
21
+ end
22
+
23
+ class Backtrace < ::Array
24
+ # ripped from minitest...
25
+
26
+ file = File.expand_path __FILE__
27
+ # if RUBY_VERSION =~ /^1\.9/ then # bt's expanded, but __FILE__ isn't :(
28
+ # File.expand_path __FILE__
29
+ # elsif __FILE__ =~ /^[^\.]/ then # assume both relative
30
+ # require 'pathname'
31
+ # pwd = Pathname.new Dir.pwd
32
+ # pn = Pathname.new File.expand_path(__FILE__)
33
+ # relpath = pn.relative_path_from(pwd) rescue pn
34
+ # pn = File.join ".", relpath unless pn.relative?
35
+ # pn.to_s
36
+ # else # assume both are expanded
37
+ # __FILE__
38
+ # end
39
+
40
+ # './lib' in project dir, or '/usr/local/blahblah' if installed
41
+ ASSERT_DIR = File.dirname(File.dirname(file))
42
+
43
+ def initialize(value=nil)
44
+ super(value || ["No backtrace"])
45
+ end
46
+
47
+ def to_s
48
+ self.join("\n")
49
+ end
50
+
51
+ def filtered
52
+ new_bt = []
53
+
54
+ self.each do |line|
55
+ break if line.rindex ASSERT_DIR, 0
56
+ new_bt << line
57
+ end
58
+
59
+ new_bt = self.reject { |line| line.rindex ASSERT_DIR, 0 } if new_bt.empty?
60
+ new_bt = self.dup if new_bt.empty?
61
+
62
+ self.class.new(new_bt)
63
+ end
64
+ end
65
+
66
+
67
+ # Result classes...
68
+
69
+ class Base
70
+
71
+ attr_reader :test_name, :message, :backtrace
72
+
73
+ def initialize(test_name, message, backtrace=nil)
74
+ @backtrace = Backtrace.new(backtrace)
75
+ @test_name = test_name
76
+ @message = message && !message.empty? ? message : nil
77
+ end
78
+
79
+ Assert::Result.types.keys.each do |meth|
80
+ define_method("#{meth}?") { false }
81
+ end
82
+
83
+ def to_sym; nil; end
84
+
85
+ def to_s
86
+ [self.test_name, self.message, self.trace].compact.join("\n")
87
+ end
88
+
89
+ def trace
90
+ self.backtrace.filtered.first.to_s
91
+ end
92
+
93
+ def ==(other)
94
+ self.class == other.class && self.message == other.message
95
+ end
96
+
97
+ def inspect
98
+ "#<#{self.class} @message=#{self.message.inspect}>"
99
+ end
100
+
101
+ end
102
+
103
+ class Pass < Base
104
+ def pass?; true; end
105
+ def to_sym; :passed; end
106
+
107
+ def to_s
108
+ "PASS: #{super}"
109
+ end
110
+ end
111
+
112
+ class Fail < Base
113
+ def fail?; true; end
114
+ def to_sym; :failed; end
115
+
116
+ def to_s
117
+ "FAIL: #{super}"
118
+ end
119
+ end
120
+
121
+ class Ignore < Base
122
+ def ignore?; true; end
123
+ def to_sym; :ignored; end
124
+
125
+ def to_s
126
+ "IGNORE: #{super}"
127
+ end
128
+ end
129
+
130
+ # Error and Skip results are built from exceptions being raised
131
+ class FromException < Base
132
+ def initialize(test_name, exception)
133
+ super(test_name, exception.message, exception.backtrace || [])
134
+ end
135
+ end
136
+
137
+ # raised by the 'skip' context helper to break test execution
138
+ class TestSkipped < RuntimeError; end
139
+
140
+ class Skip < FromException
141
+ def skip?; true; end
142
+ def to_sym; :skipped; end
143
+
144
+ def to_s
145
+ "SKIP: #{super}"
146
+ end
147
+ end
148
+
149
+ class Error < FromException
150
+
151
+ def error?; true; end
152
+ def to_sym; :errored; end
153
+
154
+ def to_s
155
+ "ERROR: #{super}"
156
+ end
157
+
158
+ # override of the base, always show the full unfiltered backtrace for errors
159
+ def trace
160
+ self.backtrace.to_s
161
+ end
162
+ end
163
+
164
+ end