assay 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/.ruby +46 -41
  2. data/COPYING.rdoc +38 -0
  3. data/HISTORY.rdoc +18 -1
  4. data/QED.rdoc +1100 -0
  5. data/README.rdoc +139 -16
  6. data/lib/assay.rb +82 -29
  7. data/lib/assay.yml +46 -41
  8. data/lib/assay/{adapters → adapter}/minitest.rb +0 -0
  9. data/lib/assay/{adapters → adapter}/testunit.rb +0 -0
  10. data/lib/assay/assertable.rb +174 -0
  11. data/lib/assay/assertion.rb +98 -124
  12. data/lib/assay/assertor.rb +187 -0
  13. data/lib/assay/boolean_assay.rb +15 -0
  14. data/lib/assay/case_assay.rb +17 -0
  15. data/lib/assay/compare_assay.rb +38 -0
  16. data/lib/assay/core_ext/kernel.rb +52 -0
  17. data/lib/assay/core_ext/na.rb +9 -0
  18. data/lib/assay/directory_assay.rb +20 -0
  19. data/lib/assay/empty_assay.rb +17 -0
  20. data/lib/assay/equal_assay.rb +35 -0
  21. data/lib/assay/equality_assay.rb +18 -0
  22. data/lib/assay/execution_assay.rb +59 -0
  23. data/lib/assay/false_assay.rb +17 -0
  24. data/lib/assay/file_assay.rb +17 -0
  25. data/lib/assay/identity_assay.rb +49 -0
  26. data/lib/assay/include_assay.rb +17 -0
  27. data/lib/assay/instance_assay.rb +17 -0
  28. data/lib/assay/kind_assay.rb +18 -0
  29. data/lib/assay/less_assay.rb +18 -0
  30. data/lib/assay/less_equal_assay.rb +25 -0
  31. data/lib/assay/like_assay.rb +17 -0
  32. data/lib/assay/match_assay.rb +17 -0
  33. data/lib/assay/more_assay.rb +18 -0
  34. data/lib/assay/more_equal_assay.rb +25 -0
  35. data/lib/assay/nil_assay.rb +15 -0
  36. data/lib/assay/nomatch_assay.rb +17 -0
  37. data/lib/assay/output_assay.rb +35 -0
  38. data/lib/assay/path_assay.rb +17 -0
  39. data/lib/assay/raise_assay.rb +109 -0
  40. data/lib/assay/rescue_assay.rb +55 -0
  41. data/lib/assay/respond_assay.rb +17 -0
  42. data/lib/assay/return_assay.rb +46 -0
  43. data/lib/assay/silent_assay.rb +59 -0
  44. data/lib/assay/stderr_assay.rb +30 -0
  45. data/lib/assay/stdout_assay.rb +30 -0
  46. data/lib/assay/throw_assay.rb +89 -0
  47. data/lib/assay/true_assay.rb +20 -0
  48. data/lib/assay/unequal_assay.rb +37 -0
  49. data/lib/assay/within_assay.rb +39 -0
  50. data/test/case_compare_assay.rb +59 -0
  51. data/test/case_empty_assay.rb +51 -0
  52. data/test/case_equal_assay.rb +53 -0
  53. data/test/case_equality_assay.rb +55 -0
  54. data/test/case_false_assay.rb +48 -0
  55. data/test/case_identity_assay.rb +51 -0
  56. data/test/case_include_assay.rb +51 -0
  57. data/test/case_instance_assay.rb +51 -0
  58. data/test/case_kind_assay.rb +51 -0
  59. data/test/case_less_assay.rb +53 -0
  60. data/test/case_less_equal_assay.rb +53 -0
  61. data/test/case_like_assay.rb +57 -0
  62. data/test/case_match_assay.rb +45 -0
  63. data/test/case_more_assay.rb +53 -0
  64. data/test/case_more_equal_assay.rb +53 -0
  65. data/test/case_nil_assay.rb +48 -0
  66. data/test/case_nomatch_assay.rb +47 -0
  67. data/test/case_raise_assay.rb +51 -0
  68. data/test/case_respond_assay.rb +51 -0
  69. data/test/case_throw_assay.rb +51 -0
  70. data/test/case_true_assay.rb +48 -0
  71. data/test/case_unequal_assay.rb +55 -0
  72. data/test/case_within_assay.rb +61 -0
  73. data/test/helper.rb +36 -0
  74. metadata +135 -108
  75. data/APACHE2.txt +0 -205
  76. data/NOTICE.rdoc +0 -18
  77. data/lib/assay/assertions/compare_failure.rb +0 -61
  78. data/lib/assay/assertions/delta_failure.rb +0 -80
  79. data/lib/assay/assertions/empty_failure.rb +0 -76
  80. data/lib/assay/assertions/equality_failure.rb +0 -100
  81. data/lib/assay/assertions/execution_failure.rb +0 -90
  82. data/lib/assay/assertions/false_failure.rb +0 -72
  83. data/lib/assay/assertions/identity_failure.rb +0 -85
  84. data/lib/assay/assertions/instance_failure.rb +0 -76
  85. data/lib/assay/assertions/kind_failure.rb +0 -80
  86. data/lib/assay/assertions/match_failure.rb +0 -85
  87. data/lib/assay/assertions/nil_failure.rb +0 -75
  88. data/lib/assay/assertions/raise_failure.rb +0 -134
  89. data/lib/assay/assertions/response_failure.rb +0 -86
  90. data/lib/assay/assertions/same_failure.rb +0 -82
  91. data/lib/assay/assertions/throw_failure.rb +0 -122
  92. data/lib/assay/assertions/true_failure.rb +0 -79
  93. data/lib/assay/matcher.rb +0 -48
  94. data/qed/01_failure_classes.rdoc +0 -75
  95. data/qed/02_assertives.rdoc +0 -118
  96. data/qed/03_matchers.rdoc +0 -118
  97. data/qed/04_lookup.rdoc +0 -10
@@ -1,149 +1,123 @@
1
- require 'ansi/diff'
2
- require 'assay/matcher'
1
+ require 'brass'
3
2
 
4
- module Assay
3
+ require_relative 'core_ext/na'
4
+ require_relative 'core_ext/kernel'
5
5
 
6
- #
7
- class Assertion < Exception
6
+ require_relative 'assertor'
7
+ require_relative 'assertable'
8
8
 
9
- # When displaying errors, use this as a rule of thumb
10
- # for determining when the inspected object will be too
11
- # big for a single line message.
12
- SIZE_LIMIT = 13
9
+ # TODO: Don't care for Proc === subject conditional code, but not
10
+ # sure how else to deal with lambda subjects.
13
11
 
14
- # Returns Matcher for the failure class.
15
- def self.to_matcher(*args, &blk)
16
- Matcher.new(self, *args, &blk)
17
- end
12
+ # Base class for all Assay classes. This class defines all the logic
13
+ # for assertions as exception classes as well as test assertion matchers.
14
+ #
15
+ class Assertion < Exception
18
16
 
19
- #
20
- def self.assertable_method
21
- "assert_#{assertion_name}"
22
- end
17
+ extend Assay::Assertable
23
18
 
24
- #
25
- def self.assert(*args, &blk)
26
- opts = Hash === args.last ? args.pop : {}
27
-
28
- backtrace = opts[:backtrace] || caller
29
- message = opts[:message]
30
-
31
- err = new(message, *args, &blk)
32
- err.set_backtrace(backtrace)
33
- err.assert
34
-
35
- #chk = check(*args, &blk)
36
- #msg = fail_message(*args, &blk)
37
- #if !chk
38
- # msg = opts[:message]
39
- # btr = opts[:backtrace] || caller
40
- # err = new(msg, *args)
41
- # err.set_backtrace(btr)
42
- # fail err
43
- #end
44
- end
19
+ #
20
+ # When displaying errors, use this as a rule of thumb
21
+ # for determining when the inspected object will be too
22
+ # big for a single line message.
23
+ #
24
+ SIZE_LIMIT = 13
45
25
 
46
- #
47
- def self.refute(*args, &blk)
48
- opts = Hash === args.last ? args.pop : {}
49
-
50
- backtrace = opts[:backtrace] || caller
51
- message = opts[:message]
52
-
53
- err = new(message, *args, &blk)
54
- err.set_backtrace(backtrace)
55
- err.refute
56
-
57
- #opts = Hash === args.last ? args.pop : {}
58
- #chk = check!(*args, &blk)
59
- ##msg = fail_message!(*args, &blk)
60
- #if !chk
61
- # msg = opts[:message]
62
- # btr = opts[:backtrace] || caller
63
- # err = new(msg, :backtrace=>btr, :arguments=>args)
64
- # fail err
65
- #end
66
- end
26
+ #
27
+ # Each new subclass must call the +register+ method. This is not an option!
28
+ # The method must be called in order to add the class to the Assertion
29
+ # name and operator indicies, so they might be looked-up efficiently by
30
+ # other libraries.
31
+ #
32
+ def self.register(op, name=nil)
33
+ case op.to_s
34
+ when /\W/
35
+ @operator = op.to_sym
36
+ @assertive_name = name.to_sym if name
37
+ else
38
+ @operator = (op.to_s + '?').to_sym
39
+ @assertive_name = op.to_sym
40
+ end
41
+
42
+ operator_index[operator] = self
43
+ name_index[assertive_name] = self
44
+ end
67
45
 
68
- #
69
- def self.pass?(*args, &blk)
70
- raise NotImplementedError
71
- end
46
+ #
47
+ # When Assertion is inherited, a list of all Assertion subclasses is kept.
48
+ # This can be used to assertions frameworks with dynamic implementations.
49
+ #
50
+ def self.inherited(base)
51
+ @@by_operator = nil
52
+ @@by_name = nil
53
+ subclasses << base
54
+ end
72
55
 
73
- #
74
- def self.fail?(*args, &blk)
75
- ! pass?(*args, &blk)
76
- end
56
+ #
57
+ # List of all subclasses of Assertion.
58
+ #
59
+ def self.subclasses
60
+ @@subclasses ||= []
61
+ end
62
+
63
+ #
64
+ # If operator is not given, returns a hash table of assertion classes
65
+ # indexed by operator.
66
+ #
67
+ def self.by_operator(operator=nil)
68
+ return operator_index.dup unless operator
69
+ operator_index[operator.to_sym]
70
+ end
77
71
 
78
- #
79
- def initialize(message=nil, *arguments, &block)
80
- message ? super(message % arguments) : super()
72
+ #
73
+ # If operator is not given, returns a hash table of assertion classes
74
+ # indexed by assertive name.
75
+ #
76
+ def self.by_name(name=nil)
77
+ return name_index.dup unless name
78
+ name_index[name.to_sym]
79
+ end
81
80
 
82
- @mesg = message # why isn't this in @mesg from super()?
83
- @arguments = arguments
84
- @block = block
81
+ private
85
82
 
86
- #set_arguments options[:arguments] if options[:arguments]
87
- #set_negative options[:negated] if options[:negated]
88
- #set_backtrace options[:backtrace] if options[:backtrace]
83
+ def self.operator_index
84
+ @@operator_index ||= {}
89
85
  end
90
86
 
91
- # Failure is always a type of assertion.
92
- #
93
- # This method allows Assay's classes to work in any test framework
94
- # that supports this interface.
95
- def assertion?
96
- true # @assertion = true if @assertion.nil?
87
+ def self.name_index
88
+ @@name_index ||= {}
97
89
  end
98
90
 
99
- #
100
- def pass?
101
- self.class.pass?(*@arguments, &@block) #^ @negative
102
- end
91
+ #
92
+ # Setup new Assertion object.
93
+ #
94
+ def initialize(msg=nil) #, *criteria, &block)
95
+ super(msg)
103
96
 
104
- #
105
- def fail?
106
- not pass?
107
- end
97
+ #@criteria = criteria
98
+ #@block = block
99
+ #@not = false
108
100
 
109
- #
110
- def assert
111
- #@negative = false
112
- raise self unless pass?
113
- end
101
+ @assertion = true
114
102
 
115
- #
116
- def refute
117
- #@negative = true
118
- raise self unless fail?
119
- end
103
+ #options = (Hash === criteria.last ? criteria.pop : {})
104
+ #set_backtrace(options[:backtrace]) if options[:backtrace]
105
+ #set_negative(options[:negated]) if options[:negated]
106
+ end
120
107
 
121
- #
122
- def negative?
123
- @negative
124
- end
108
+ end
125
109
 
126
- # Set whether this failure was the inverse of it's normal meaning.
127
- # For example, `!=` rather than `==`.
128
- def set_negative(negative)
129
- @negative = !!negative
130
- end
131
110
 
132
- # Set arguments used to make assertion.
133
- def set_arguments(arguments)
134
- @arguments = arguments
135
- #@block = block
136
- end
111
+ =begin
137
112
 
138
- #
139
- def to_s
140
- if @negative
141
- "NOT " + super()
142
- else
143
- super()
144
- end
145
- end
113
+ #
114
+ #def to_s
115
+ # #if @negative
116
+ # # "NOT " + super()
117
+ # #else
118
+ # super()
119
+ # #end
120
+ #end
146
121
 
147
- end
122
+ =end
148
123
 
149
- end
@@ -0,0 +1,187 @@
1
+ module Assay
2
+
3
+ # Assertor delegates to Assay class. It provides an object-oriented
4
+ # interface to makeing assertions, as opposed to the functional
5
+ # interface of the Assay classes themselves.
6
+ #
7
+ class Assertor
8
+
9
+ #
10
+ #
11
+ def initialize(assay_class, *criteria, &block)
12
+ @assay = assay_class
13
+ @criteria = criteria
14
+ @block = block
15
+ @not = false
16
+ end
17
+
18
+ #
19
+ # The assay class to which this assertor delegates.
20
+ #
21
+ attr :assay
22
+
23
+ #
24
+ # The criteria for applying the assertor.
25
+ #
26
+ attr :criteria
27
+
28
+ #
29
+ # Block criterion.
30
+ #
31
+ attr :block
32
+
33
+ #
34
+ # Is the assertor negated?
35
+ #
36
+ def not?
37
+ @not
38
+ end
39
+
40
+ #
41
+ #
42
+ def pass?(subject, &block)
43
+ arguments, block = complete_criteria(subject, &block)
44
+ @not ^ @assay.pass?(*arguments, &block)
45
+ end
46
+
47
+ #
48
+ #
49
+ def fail?(subject, &block)
50
+ arguments, block = complete_criteria(subject, &block)
51
+ @not ^ @assay.fail?(*arguments, &block)
52
+ end
53
+
54
+ #
55
+ #
56
+ def assert!(subject, &block)
57
+ # technically this needs to be controlled by the assay class
58
+ if block.nil? && Proc === subject
59
+ block = subject
60
+ subject = NA
61
+ end
62
+
63
+ arguments, block = complete_criteria(subject, &block)
64
+
65
+ if @not
66
+ @assay.refute!(*arguments, &block)
67
+ else
68
+ @assay.assert!(*arguments, &block)
69
+ end
70
+ end
71
+
72
+ #
73
+ #
74
+ def refute!(subject, &block)
75
+ # technically this needs to be controlled by the assay class
76
+ if block.nil? && Proc === subject
77
+ block = subject
78
+ subject = NA
79
+ end
80
+
81
+ arguments, block = complete_criteria(subject, &block)
82
+
83
+ if @not
84
+ @assay.assert!(*arguments, &block)
85
+ else
86
+ @assay.refute!(*arguments, &block)
87
+ end
88
+ end
89
+
90
+ alias_method :==, :pass?
91
+ alias_method :!=, :fail?
92
+
93
+ alias_method :=~, :assert!
94
+ alias_method :!~, :refute!
95
+
96
+ alias_method :===, :assert!
97
+
98
+ #
99
+ # Create a negated form of the matcher.
100
+ #
101
+ # @todo Should this be @! method instead?
102
+ #
103
+ def !@
104
+ dup.negate!
105
+ end
106
+
107
+ #
108
+ # Create a negated form of the matcher.
109
+ #
110
+ # @todo Best name for this method?
111
+ #
112
+ def not
113
+ dup.negate!
114
+ end
115
+
116
+ #
117
+ # Assertion message. This is only used by RSpec compatibility methods.
118
+ #
119
+ def assert_message(subject, &block)
120
+ arguments, block = complete_criteria(subject, &block)
121
+ @assay.assert_message(*arguments, &block)
122
+ end
123
+
124
+ #
125
+ # Refutation message. This is only used by RSpec compatibility methods.
126
+ #
127
+ def refute_message(subject, &block)
128
+ arguments, block = complete_criteria(subject, &block)
129
+ @assay.refute_message(*arguments, &block)
130
+ end
131
+
132
+ # The following methods allow Assay objects to work as RSpec matchers.
133
+
134
+ # For RSpec matcher compatability.
135
+ alias matches? pass?
136
+
137
+ # For RSpec matcher compatability.
138
+ alias does_not_match? fail?
139
+
140
+ # For RSpec matcher compatability.
141
+ alias failure_message_for_should assert_message
142
+
143
+ # For RSpec matcher compatability.
144
+ alias failure_message_for_should_not refute_message
145
+
146
+ ##
147
+ ## Returns Assay instance.
148
+ ##
149
+ #def exception(subject, msg=nil)
150
+ # @assay.new(msg || message, subject, *criteria, &block)
151
+ # # :negated => options[:negated],
152
+ # # :backtrace => options[:backtrace] || caller,
153
+ #end
154
+
155
+ protected
156
+
157
+ #
158
+ # Toggle the `@not` flag.
159
+ #
160
+ def negate!
161
+ @not = !@not
162
+ self
163
+ end
164
+
165
+ private
166
+
167
+ #
168
+ #
169
+ #
170
+ def complete_criteria(subject, &block)
171
+ block = block || @block
172
+
173
+ return @criteria, block if subject == NA
174
+
175
+ if i = @criteria.index(NA)
176
+ args = @criteria[0...i] + [subject] + @criteria[i+1..-1]
177
+ else
178
+ args = [subject] + @criteria
179
+ end
180
+
181
+ return args, block
182
+ end
183
+
184
+ end
185
+
186
+ end
187
+
@@ -0,0 +1,15 @@
1
+ require_relative 'assertion'
2
+
3
+ class BooleanAssay < Assertion
4
+
5
+ register :boolean
6
+
7
+ #
8
+ # Check assertion.
9
+ #
10
+ def self.pass?(subject)
11
+ subject.true? || subject.false? # TODO: Kernel#boolean? method
12
+ end
13
+
14
+ end
15
+