test-belt 0.2.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +2 -1
  2. data/Gemfile.lock +23 -0
  3. data/lib/test_belt/callbacks.rb +22 -0
  4. data/lib/test_belt/callbacks/case.rb +86 -0
  5. data/lib/test_belt/callbacks/suite.rb +106 -0
  6. data/lib/test_belt/callbacks/test.rb +58 -0
  7. data/lib/test_belt/context.rb +40 -0
  8. data/lib/test_belt/default_test.rb +18 -0
  9. data/lib/test_belt/helper.rb +24 -3
  10. data/lib/test_belt/matchers.rb +29 -0
  11. data/lib/test_belt/matchers/base.rb +21 -0
  12. data/lib/test_belt/matchers/have_accessors.rb +23 -0
  13. data/lib/test_belt/matchers/have_class_methods.rb +40 -0
  14. data/lib/test_belt/matchers/have_files.rb +38 -0
  15. data/lib/test_belt/matchers/have_instance_methods.rb +44 -0
  16. data/lib/test_belt/matchers/have_readers.rb +26 -0
  17. data/lib/test_belt/matchers/have_writers.rb +30 -0
  18. data/lib/test_belt/should.rb +76 -0
  19. data/lib/test_belt/skip.rb +41 -0
  20. data/lib/test_belt/subject.rb +47 -0
  21. data/lib/test_belt/version.rb +1 -1
  22. data/test/callbacks_test.rb +172 -0
  23. data/test/fixtures/{shoulda_macros/thing.rb → thing.rb} +0 -0
  24. data/test/helpers_test.rb +175 -0
  25. data/test/matchers_test.rb +135 -0
  26. data/test/rake_tasks_test.rb +8 -17
  27. metadata +33 -31
  28. data/lib/test_belt/shoulda_macros.rb +0 -9
  29. data/lib/test_belt/shoulda_macros/classes.rb +0 -105
  30. data/lib/test_belt/shoulda_macros/context.rb +0 -25
  31. data/lib/test_belt/shoulda_macros/files.rb +0 -49
  32. data/lib/test_belt/test_unit.rb +0 -8
  33. data/lib/test_belt/test_unit/context.rb +0 -71
  34. data/lib/test_belt/test_unit/runner.rb +0 -48
  35. data/lib/test_belt/test_unit/test_case.rb +0 -26
  36. data/test/shoulda_macros/classes_test.rb +0 -58
  37. data/test/shoulda_macros/context_test.rb +0 -28
  38. data/test/shoulda_macros/files_test.rb +0 -36
  39. data/test/test_unit/context_test.rb +0 -65
  40. data/test/test_unit/runner_test.rb +0 -31
  41. data/test/test_unit/test_case_test.rb +0 -30
@@ -0,0 +1,23 @@
1
+ require 'test_belt/matchers/have_readers'
2
+ require 'test_belt/matchers/have_writers'
3
+
4
+ module TestBelt::Matchers
5
+ module HaveAccessors
6
+
7
+ def self.included(receiver)
8
+ receiver.send(:extend, ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ def have_accessors(*meths)
13
+ meths.collect do |meth|
14
+ [ ::TestBelt::Matchers::HaveReaders::Matcher.new(meth),
15
+ ::TestBelt::Matchers::HaveWriters::Matcher.new(meth)
16
+ ]
17
+ end.flatten
18
+ end
19
+ alias_method :have_accessor, :have_accessors
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ module TestBelt::Matchers
2
+ module HaveClassMethods
3
+
4
+ def self.included(receiver)
5
+ receiver.send(:extend, ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def have_class_methods(*meths)
10
+ meths.collect do |meth|
11
+ Matcher.new(meth)
12
+ end
13
+ end
14
+ alias_method :have_class_method, :have_class_methods
15
+ end
16
+
17
+ class Matcher < ::TestBelt::Matchers::Base
18
+ def initialize(method)
19
+ unless method.kind_of?(::String) || method.kind_of?(::Symbol)
20
+ raise ArgumentError, "please specify the method name using a string or symbol"
21
+ end
22
+ @method = method
23
+ end
24
+
25
+ def desc
26
+ "respond to class method ##{@method}"
27
+ end
28
+
29
+ def matches?(subject)
30
+ @subject = subject
31
+ subject.class.respond_to?(@method)
32
+ end
33
+
34
+ def fail_message
35
+ "#{@subject.class.name} does not have the class method ##{@method}"
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ module TestBelt::Matchers
2
+ module HaveFiles
3
+
4
+ def self.included(receiver)
5
+ receiver.send(:extend, ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def have_files(*files)
10
+ files.collect do |file|
11
+ Matcher.new(file)
12
+ end
13
+ end
14
+ alias_method :have_file, :have_files
15
+ alias_method :have_directories, :have_files
16
+ alias_method :have_directory, :have_files
17
+ end
18
+
19
+ class Matcher < ::TestBelt::Matchers::Base
20
+ def initialize(file_path)
21
+ @file_path = file_path
22
+ end
23
+
24
+ def desc
25
+ "have the file path '#{@file_path}'"
26
+ end
27
+
28
+ def matches?(subject)
29
+ File.exists?(@file_path)
30
+ end
31
+
32
+ def fail_message
33
+ "'#{@file}' does not exist"
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,44 @@
1
+ module TestBelt::Matchers
2
+ module HaveInstanceMethods
3
+
4
+ def self.included(receiver)
5
+ receiver.send(:extend, ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def have_instance_methods(*meths)
10
+ meths.collect do |meth|
11
+ Matcher.new(meth)
12
+ end
13
+ end
14
+ alias_method :have_instance_method, :have_instance_methods
15
+ end
16
+
17
+ class Matcher < ::TestBelt::Matchers::Base
18
+ def initialize(method)
19
+ unless method.kind_of?(::String) || method.kind_of?(::Symbol)
20
+ raise ArgumentError, "please specify the method name using a string or symbol"
21
+ end
22
+ @method = method
23
+ end
24
+
25
+ def method_type
26
+ "instance method"
27
+ end
28
+
29
+ def desc
30
+ "respond to #{method_type} ##{@method}"
31
+ end
32
+
33
+ def matches?(subject)
34
+ @subject = subject
35
+ subject.respond_to?(@method)
36
+ end
37
+
38
+ def fail_message
39
+ "#{@subject.class.name} does not have instance method ##{@method}"
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_belt/matchers/have_instance_methods'
2
+
3
+ module TestBelt::Matchers
4
+ module HaveReaders
5
+
6
+ def self.included(receiver)
7
+ receiver.send(:extend, ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def have_readers(*meths)
12
+ meths.collect do |meth|
13
+ Matcher.new(meth)
14
+ end
15
+ end
16
+ alias_method :have_reader, :have_readers
17
+ end
18
+
19
+ class Matcher < ::TestBelt::Matchers::HaveInstanceMethods::Matcher
20
+ def method_type
21
+ "reader"
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_belt/matchers/have_instance_methods'
2
+
3
+ module TestBelt::Matchers
4
+ module HaveWriters
5
+
6
+ def self.included(receiver)
7
+ receiver.send(:extend, ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def have_writers(*meths)
12
+ meths.collect do |meth|
13
+ Matcher.new(meth)
14
+ end
15
+ end
16
+ alias_method :have_writer, :have_writers
17
+ end
18
+
19
+ class Matcher < ::TestBelt::Matchers::HaveInstanceMethods::Matcher
20
+ def initialize(method)
21
+ super("#{method}=")
22
+ end
23
+
24
+ def method_type
25
+ "writer"
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,76 @@
1
+ module TestBelt
2
+ module Should
3
+
4
+ # This defines a class method 'should' that takes a string
5
+ # describing the test and a block that executes the test. The
6
+ # test will be named:
7
+ # "test: #{context} should #{description}."
8
+
9
+ # Usage:
10
+ # class SomeTest < Test::Unit::TestCase
11
+ # extend TestBelt::Should
12
+ # end
13
+
14
+ def should(matchers_or_desc, &block)
15
+ tests = should_tests(matchers_or_desc, &block)
16
+ context = should_context
17
+
18
+ each_should(context, tests) do |name, code|
19
+ define_method(name) do
20
+ begin
21
+ self.class._testbelt_setups.each {|sb| instance_eval(&sb)}
22
+ instance_eval(&code)
23
+ ensure
24
+ self.class._testbelt_teardowns.reverse.each {|tb| instance_eval(&tb)}
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ # This method is identical to the should version, however this one does
31
+ # nothing but skip any tests described or matched on
32
+ def should_eventually(matchers_or_desc, &block)
33
+ tests = should_tests(matchers_or_desc, &block)
34
+ context = should_context
35
+
36
+ each_should(context, tests) do |name, code|
37
+ define_method(name) { skip }
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def each_should(context, tests)
44
+ tests.each do |t|
45
+ yield should_test_name(context, t[0]), t[1]
46
+ end
47
+ end
48
+
49
+ def should_tests(matchers_or_desc, &block)
50
+ unless matchers_or_desc.kind_of?(::Array) || block_given?
51
+ raise ArgumentError, "either specify a test block and description or a set of matchers"
52
+ end
53
+
54
+ if matchers_or_desc.kind_of?(::Array)
55
+ matchers_or_desc.collect do |matcher|
56
+ [matcher.desc, Proc.new {assert_matcher(matcher)}]
57
+ end
58
+ else
59
+ [[matchers_or_desc.to_s, block]]
60
+ end
61
+ end
62
+
63
+ def should_context
64
+ '' # TODO: context stuff needs to be added to test name
65
+ end
66
+
67
+ def should_test_name(context, name)
68
+ test_name = ["test:", "should", "#{name}. "].flatten.join(' ').to_sym
69
+ if instance_methods.include?(test_name.to_s)
70
+ warn " * WARNING: '#{test_name}' is already defined"
71
+ end
72
+ test_name
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,41 @@
1
+ module Test::Unit
2
+ class TestCase
3
+
4
+ alias_method(:orig_add_error, :add_error)
5
+ def add_error(*args, &block)
6
+ unless args.first.kind_of?(::TestBelt::TestSkipped)
7
+ orig_add_error *args, &block
8
+ end
9
+ end
10
+
11
+ end
12
+ end
13
+
14
+ module TestBelt
15
+ class TestSkipped < Exception; end
16
+
17
+ module Skip
18
+
19
+ # Sometimes while testing, you may wish to define some tests but not run
20
+ # them just yet. LeftRight provides some nice UI for dealing with skipped
21
+ # tests. Test Belt provides a handy 'skip' method for test cases. Use
22
+ # this method to skip individual tests. If you wish to skip a whole
23
+ # context of tests, add the skip method to a before [[Callback]] and all
24
+ # the tests will be skipped for the class. Since callbacks inherit, any
25
+ # subclassed tests will be skipped as well.
26
+
27
+ # Usage:
28
+ # class SomeTest < Test::Unit::TestCase
29
+ # include TestBelt::Skip
30
+ # end
31
+
32
+ def skip(halt_test=true)
33
+ if defined? ::LeftRight
34
+ ::LeftRight.state.skip = true
35
+ ::LeftRight.state.skipped_count += 1
36
+ end
37
+ raise ::TestBelt::TestSkipped if halt_test
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,47 @@
1
+ module TestBelt
2
+ module Subject
3
+
4
+ # This provides a class method 'subject' on a TestCase. Use this method
5
+ # to initialize the subject of the TestCase. This may be a model, class,
6
+ # or whatever. The subject method takes a block and the result of the
7
+ # block is used as the subject value. Note, the block is for every test
8
+ # withing the scope of the TestCase instance, and after any setup/before
9
+ # callbacks. The subject value is available using the 'subject instance
10
+ # method on the TestCase. Any sub-classed TestCase that does not define
11
+ # it's own subject will inherite the subject of it's super class.
12
+
13
+ # Usage:
14
+ # class SomeTest < Test::Unit::TestCase
15
+ # include TestBelt::Subject
16
+ # end
17
+
18
+ def self.included(receiver)
19
+ receiver.send(:extend, ClassMethods)
20
+ receiver.send(:include, InstanceMethods)
21
+ end
22
+
23
+ module ClassMethods
24
+ def subject(&block)
25
+ raise ArgumentError, "please provide a subject block" unless block_given?
26
+ @_testbelt_subject = block
27
+ end
28
+
29
+ def _testbelt_subject
30
+ @_testbelt_subject || begin
31
+ superclass._testbelt_subject
32
+ rescue NoMethodError
33
+ nil
34
+ end
35
+ end
36
+ end
37
+
38
+ module InstanceMethods
39
+ def subject
40
+ @_testbelt_subject ||= if (sb = self.class._testbelt_subject)
41
+ instance_eval(&sb)
42
+ end
43
+ end
44
+ end
45
+
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module TestBelt
2
- VERSION = "0.2.1"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -0,0 +1,172 @@
1
+ require "test/helper"
2
+
3
+ module TestBelt
4
+
5
+ class TestCallbacksTest < Test::Unit::TestCase
6
+ include TestBelt
7
+
8
+ context "A test with callbacks"
9
+ subject { 'subject' }
10
+ before {
11
+ @before = 'before'
12
+ @before_subject = subject
13
+ @expected_after = 'after'
14
+ }
15
+ setup {
16
+ @setup = 'setup'
17
+ @setup_subject = subject
18
+ @expected_teardown = 'teardown'
19
+ }
20
+
21
+ should "run the it's callbacks appropriately" do
22
+ assert_equal 'before', @before
23
+ assert_equal 'setup', @setup
24
+ assert_equal 'subject', @before_subject
25
+ assert_equal 'subject', @setup_subject
26
+ end
27
+
28
+ after {
29
+ assert_equal 'after', @expected_after
30
+ }
31
+ teardown {
32
+ assert_equal 'teardown', @expected_teardown
33
+ }
34
+ end
35
+ class RootCallbacksTest < Test::Unit::TestCase
36
+ include TestBelt
37
+
38
+ before {
39
+ @before = ['root']
40
+ }
41
+ after {
42
+ assert_equal ['nested nested', 'nested'], @after
43
+ }
44
+ end
45
+ class NestedCallbacksTest < RootCallbacksTest
46
+ before {
47
+ @before << 'nested'
48
+ }
49
+ after {
50
+ @after << 'nested'
51
+ }
52
+ end
53
+ class NestedNestedCallbacksTest < NestedCallbacksTest
54
+ should "call it's nested callbacks in order" do
55
+ assert_equal ['root', 'nested'], @before
56
+ end
57
+
58
+ after {
59
+ @after = ['nested nested']
60
+ }
61
+ end
62
+
63
+
64
+
65
+
66
+ class CaseCallbacksTest < Test::Unit::TestCase
67
+ include TestBelt
68
+
69
+ context "A test with case callbacks"
70
+
71
+ before_once {
72
+ @expected_after = 'after'
73
+ if (@@before_once rescue nil)
74
+ @before_once_fail = true
75
+ end
76
+ @@before_once = true
77
+ }
78
+ setup_once {
79
+ @expected_teardown = 'teardown'
80
+ if (@@setup_once rescue nil)
81
+ @setup_once_fail = true
82
+ end
83
+ @@setup_once = true
84
+ }
85
+
86
+ should "run the case callbacks just once" do
87
+ assert true
88
+ end
89
+ should "not run the case callbacks more than once" do
90
+ assert true
91
+ end
92
+
93
+ after_once {
94
+ if (@@after_once rescue nil)
95
+ @after_once_fail = true
96
+ end
97
+ @@after_once = true
98
+ raise 'looks like before_once did not run' unless @expected_after == 'after'
99
+ raise "before_once did not run once" unless (@@before_once rescue nil)
100
+ raise "before_once ran more than once" unless @before_once_fail.nil?
101
+ raise "after_once did not run once" unless (@@after_once rescue nil)
102
+ raise "after_once ran more than once" unless @after_once_fail.nil?
103
+ }
104
+ teardown_once {
105
+ if (@@teardown_once rescue nil)
106
+ @teardown_once_fail = true
107
+ end
108
+ @@teardown_once = true
109
+ raise 'looks like setup_once did not run' unless @expected_teardown == 'teardown'
110
+ raise "setup_once did not run once" unless (@@setup_once rescue nil)
111
+ raise "setup_once ran more than once" unless @setup_once_fail.nil?
112
+ raise "teardown_once did not run once" unless (@@teardown_once rescue nil)
113
+ raise "teardown_once ran more than once" unless @teardown_once_fail.nil?
114
+ }
115
+ end
116
+
117
+
118
+
119
+
120
+ class SuiteCallbacksTest < Test::Unit::TestCase
121
+ include TestBelt
122
+
123
+ context "A test with suite callbacks"
124
+
125
+ suite_started {
126
+ @started_assert = true
127
+ @expected_finished = 'finished'
128
+ if (@@started rescue nil)
129
+ @started_fail = true
130
+ end
131
+ @@started = true
132
+ }
133
+ on_suite_started {
134
+ @on_started_assert = true
135
+ @expected_on_finished = 'on finished'
136
+ if (@@on_started rescue nil)
137
+ @on_started_fail = true
138
+ end
139
+ @@on_started = true
140
+ }
141
+
142
+ should "run the suite callbacks just once" do
143
+ assert true
144
+ end
145
+ should "not run the suite callbacks more than once" do
146
+ assert true
147
+ end
148
+
149
+ suite_finished {
150
+ if (@@finished rescue nil)
151
+ @finished_fail = true
152
+ end
153
+ @@finished = true
154
+ raise 'looks like suite_started did not run' unless @expected_finished == 'finished'
155
+ raise "suite_started did not run once" unless (@@started rescue nil)
156
+ raise "suite_started ran more than once" unless @started_fail.nil?
157
+ raise "suite_finished did not run once" unless (@@finished rescue nil)
158
+ raise "suite_finished ran more than once" unless @finished_fail.nil?
159
+ }
160
+ on_suite_finished {
161
+ if (@@on_finished rescue nil)
162
+ @on_finished_fail = true
163
+ end
164
+ @@on_finished = true
165
+ raise 'looks like on_suite_started did not run' unless @expected_on_finished == 'on finished'
166
+ raise "on_suite_started did not run once" unless (@@on_started rescue nil)
167
+ raise "on_suite_started ran more than once" unless @on_started_fail.nil?
168
+ raise "on_suite_finished did not run once" unless (@@on_finished rescue nil)
169
+ raise "on_suite_finished ran more than once" unless @on_finished_fail.nil?
170
+ }
171
+ end
172
+ end