whitestone 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
1
+ 2012-01-27 ruby-talk
2
+
3
+ Whitestone 1.0.1, a unit testing library, was released on 2012-01-02. This
4
+ update, 1.0.2, improves the implementation of float-equality testing,
5
+ especially regarding numbers near zero. As it stands, floats are considered
6
+ equal if their 14th significant figure is off by one. There is no provision
7
+ for specifying a tolerance: it is supposed to just work, and if it doesn't
8
+ then it's a bug.
9
+
10
+ Key features of Whitestone include terse testing code, colorful and
11
+ helpful output, custom assertions, a powerful and intuitive test
12
+ runner, simple debugger integration. The homepage explains and
13
+ demonstrates it well.
14
+
15
+ Here are the assertion methods:
16
+ T -- assert true
17
+ F -- assert false
18
+ N -- assert object is nil
19
+ Eq -- assert two objects are equal
20
+ Mt -- assert string matches regular expression
21
+ Id -- assert two objects are identical (same object)
22
+ E -- assert error is raised
23
+ Ko -- assert an object is kind_of a class/module
24
+ Ft -- assert two floats are essentially equal
25
+ C -- assert object is thrown
26
+
27
+ Homepage: http://gsinclair.github.com/whitestone.html
28
+ Code: http://github.com/gsinclair/whitestone
29
+ Licence: MIT
30
+
31
+ Regards,
32
+ Gavin
33
+
34
+ -------------------------------------------------------------------------------
35
+
36
+ 2012-01-02 ruby-talk
37
+
38
+ Hi all,
39
+
40
+ A long time ago, I imagined my ideal unit testing library. In the middle of
41
+ 2010, I created it (using Suraj N Karaputi's "dfect" v2.1.0 as a starting point)
42
+ and called it "attest", but never got around to releasing it. Well now I have.
43
+ Except the name "attest" is taken, so I renamed it "whitestone": it's the nicest
44
+ sounding word in /usr/share/dict/words containing the word "test".
45
+
46
+ It's not going to take over the testing world, but it's what keeps my Ruby
47
+ projects in line. If you're interested in testing libraries, you'll find it
48
+ worth a look. Note: "test" not "spec". And there's no mocks, stubs, etc.
49
+ either. I'm not knocking those things, but they haven't been necessary for my
50
+ projects.
51
+
52
+ Here are the assertion methods:
53
+ T -- assert true
54
+ F -- assert false
55
+ N -- assert object is nil
56
+ Eq -- assert two objects are equal
57
+ Mt -- assert string matches regular expression
58
+ Id -- assert two objects are identical (same object)
59
+ E -- assert error is raised
60
+ Ko -- assert an object is kind_of a class/module
61
+ Ft -- assert two floats are essentially equal
62
+ C -- assert object is thrown
63
+
64
+ Key features include terse code, colorful and helpful output, custom assertions,
65
+ a powerful and intuitive test runner, simple debugger integration.
66
+
67
+ Homepage: http://gsinclair.github.com/whitestone.html
68
+ Code: http://github.com/gsinclair/whitestone
69
+ Licence: MIT
70
+
71
+ Regards,
72
+ Gavin
@@ -1,3 +1,15 @@
1
+ === 1.0.2 / 2012-01-27
2
+
3
+ * Improved the implementation and testing of float equality (Ft).
4
+ There is a backwards-incompatible change in that Ft no longer
5
+ accepts an epsilon argument. If Ft doesn't work for you with
6
+ the built-in value (1e-13) then it's probably a bug in this
7
+ library. Theoretically, this should be version 2.0.0, but that
8
+ seems silly and I don't think anyone will be affected. Sorry
9
+ if you are.
10
+
11
+ * Correct Ruby dependency set in the gemspec (>= 1.8.7).
12
+
1
13
  === 1.0.1 / 2012-01-02
2
14
 
3
15
  * Correction in README.txt
@@ -795,7 +795,11 @@ They are hardcoded and it would be a major effort to customise them!
795
795
  ### History
796
796
 
797
797
  * July 2010: originally developed under the name 'attest' but not released
798
- * 1 January 2012: version 1.0.0
798
+ * 2 JAN 2012: version 1.0.0
799
+ * 2 JAN 2012: version 1.0.1 with corrected README.txt
800
+ * 27 JAN 2012: version 1.0.2 with improved implementation and testing of float
801
+ equality (Ft). Note slight backwards incompatibility: Ft no longer accepts
802
+ 'epsilon' argument.
799
803
 
800
804
  ### Future plans
801
805
 
@@ -263,25 +263,52 @@ module Whitestone
263
263
  end # class Assertion::KindOf
264
264
 
265
265
  class FloatEqual < Base
266
- EPSILON = 0.000001
266
+ # Experiments have shown this value to be a reliable threshold for
267
+ # ratio-based comparison, but that may be machine-dependant and may be
268
+ # overturned by more experiments. With this epsilon, floats appear to be
269
+ # considered equal if their first 13 significant figures are the same.
270
+ #
271
+ # Example: 1.1 - 1.0 gives 0.10000000000000009, which differs from 0.1 in
272
+ # the 17th digit. Therefore, I could, and perhaps should, be more
273
+ # aggressive and set an even smaller ratio like 1e-16. But I assume that
274
+ # complicated calculations involving floats would compound representation
275
+ # errors, so at the moment I choose to be conservative.
276
+ #
277
+ # It is by design that the programmer cannot specify a value for epsilon.
278
+ # This should "just work", and if someone finds a case where this epsilon
279
+ # is not sufficient for normal use, it is probably a bug in this library
280
+ # that needs to be addressed. If someone wants to experiment with
281
+ # different epsilon values, then they can do, for example
282
+ # WhiteStone::Assertion::FloatEqual.const_set :EPSILON, 1e-16
283
+ EPSILON = 1e-13
267
284
  def initialize(mode, *args, &block)
268
285
  super
269
286
  no_block_allowed
270
287
  type_check(args, Numeric)
271
- @actual, @expected, @epsilon = two_or_three_arguments(args).map { |x| x.to_f }
272
- @epsilon ||= EPSILON
288
+ @actual, @expected = two_arguments(args).map { |x| x.to_f }
289
+ @epsilon = EPSILON
273
290
  end
274
291
  def run
275
- if @actual.zero? or @expected.zero?
276
- # There's no scale, so we can only go on difference.
277
- (@actual - @expected) < @epsilon
292
+ if @actual.zero? and @expected.zero?
293
+ true
294
+ elsif @actual.zero? or @expected.zero?
295
+ # Precisely one of our values is zero. Ratios don't work in this case,
296
+ # so we work around by adding 0.01 to both to get them away from zero.
297
+ # We check first to be sure that this would actually work.
298
+ if (@actual - @expected).abs < 0.00001
299
+ floats_essentially_equal?(@actual + 0.01, @expected + 0.01)
300
+ else
301
+ # They differ by more than 0.00001 so they're clearly not equal enough.
302
+ false
303
+ end
278
304
  else
279
- # We go by ratio. The ratio of two equal numbers is one, so the ratio
280
- # of two practically-equal floats will be very nearly one.
281
- @ratio = (@actual/@expected - 1).abs
282
- @ratio < @epsilon
305
+ floats_essentially_equal?(@actual, @expected)
283
306
  end
284
307
  end
308
+ def floats_essentially_equal?(a, b)
309
+ @ratio = (a/b - 1).abs
310
+ @ratio < EPSILON
311
+ end
285
312
  def message
286
313
  String.new.tap { |str|
287
314
  case @mode
@@ -289,7 +316,7 @@ module Whitestone
289
316
  str << Col["Float equality test failed"].yb
290
317
  str << "\n" << Col[" Should be: #{@expected.inspect}"].gb
291
318
  str << "\n" << Col[" Was: #{@actual.inspect}"].rb
292
- str << "\n" << " Epsilon: #{@epsilon}"
319
+ str << "\n" << " Epsilon: #{EPSILON}"
293
320
  if @ratio
294
321
  str << "\n" << " Ratio: #{@ratio}"
295
322
  end
@@ -298,7 +325,7 @@ module Whitestone
298
325
  str << Col[line].yb
299
326
  str << "\n" << Col[" Value 1: ", @actual.inspect ].fmt(:yb, :rb)
300
327
  str << "\n" << Col[" Value 2: ", @expected.inspect].fmt(:yb, :rb)
301
- str << "\n" << " Epsilon: #{@epsilon}"
328
+ str << "\n" << " Epsilon: #{EPSILON}"
302
329
  if @ratio
303
330
  str << "\n" << " Ratio: #{@ratio}"
304
331
  end
@@ -1,3 +1,3 @@
1
1
  module Whitestone
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
@@ -122,28 +122,41 @@ D "Assertion classes" do
122
122
  end
123
123
 
124
124
  D 'Ft' do
125
- Ft Math::PI, 3.141592 # default tolerance 0.00001
126
- Ft! Math::PI, 3.14
127
- Ft Math::PI, 3.14, 0.1 # tolerance for this line is 0.1
128
- Ft Math::PI, 3.14, 0.01
129
- Ft Math::PI, 3.14, 0.001
130
- Ft! Math::PI, 3.14, 0.0001
125
+ D 'basic' do
126
+ Ft 45.44332211, 45.443322110000000000001
127
+ Ft! 109.123456, 109.123457 # These are too close to be considered
128
+ # essentially equal.
129
+ end
131
130
  D 'test values of massively differing magnitude' do
132
131
  a = 0.000000000837
133
132
  b = 0.0000000004315 # a and b are _not_ "essentially" equal
134
- c = 100.000000000837
135
- d = 100.0000000004315 # c and d _are_ "essentially" equal
136
133
  Ft! a, b
137
134
  Ft! b, a
135
+ c = 100.000000000000837
136
+ d = 100.0000000000004315 # c and d _are_ "essentially" equal
138
137
  Ft c, d
139
138
  Ft d, c
140
139
  end
140
+ D "anomolies like (1.1 - 1.0) does not equal 0.1" do
141
+ Ft 1.1 - 1.0, 0.1
142
+ Ft 1.1 - 1.0 - 0.1, 0.0
143
+ Ft 0.1 + 0.1, 0.2
144
+ Ft 0.2 + 0.1, 0.3 # This doesn't work when using ==
145
+ Ft 0.3 + 0.1, 0.4
146
+ Ft 0.4 + 0.1, 0.5
147
+ Ft 0.5 + 0.1, 0.6
148
+ Ft 0.6 + 0.1, 0.7
149
+ Ft 0.7 + 0.1, 0.8 # Nor does this one
150
+ Ft 0.8 + 0.1, 0.9
151
+ Ft 0.9 + 0.1, 1.0
152
+ end
141
153
  D 'integer values' do
142
154
  Ft 4, 4
143
155
  Ft 4.0, 4
144
156
  Ft 4, 4.0
145
157
  Ft -13, -13
146
158
  Ft -13.0, -13
159
+ Ft! 4, 5
147
160
  end
148
161
  D 'zero' do
149
162
  Ft 0, 0
@@ -154,26 +167,84 @@ D "Assertion classes" do
154
167
  Ft -1.1102230246251565e-16, 0.0
155
168
  end
156
169
  D 'numbers near zero' do
157
- Ft 0, 0.00000000000124, 0.0000000001
158
- Ft 0, 0.00000000000124, 0.00000000001
159
- Ft 0, 0.00000000000124, 0.000000000001
160
- Ft 0, 0.00000000000124, 0.0000000000001
161
- # The next test fails but I don't know what we really should expect.
162
- # Ft! 0, 0.00000000000124, 1e-25
170
+ Ft! 0, 0.001
171
+ Ft! 0, 0.0001
172
+ Ft! 0, 0.00001
173
+ Ft! 0, 0.000001
174
+ Ft! 0, 0.0000001
175
+ Ft! 0, 0.00000001
176
+ Ft! 0, 0.000000001
177
+ Ft! 0, 0.0000000001
178
+ Ft! 0, 0.00000000001
179
+ Ft! 0, 0.000000000001
180
+ Ft! 0, 0.0000000000001
181
+ Ft! 0, 0.00000000000001
182
+ Ft 0, 0.000000000000001 # This is the first float that is
183
+ Ft 0, 0.0000000000000001 # essentially equal to zero.
184
+ Ft 0, 0.00000000000000001
185
+ Ft 0, 0.000000000000000001
163
186
  end
164
187
  D '(near) equal and negative' do
165
- a = -2.0000051298352
166
- b = -2.0000051298336
167
- Ft a, b, 0.000000001
168
- Ft b, a, 0.000000001
169
- end
170
- D 'tiny numbers' do
171
- Ft 1.234567e-50, 1.234568e-50
172
- Ft! 1.234567e-50, 1.234567e-51
173
- end
174
- D 'huge numbers' do
175
- Ft 1.234567e50, 1.234568e50
176
- Ft! 1.234567e50, 1.234567e51
188
+ a = -2.000000000051298352
189
+ b = -2.000000000051298336
190
+ Ft a, b
191
+ Ft b, a
192
+ end
193
+ D "13th digit differs: not equal enough" do
194
+ Ft! 1.234567890123e50, 1.23456789122e50
195
+ Ft! 1.234567890123e40, 1.23456789122e40
196
+ Ft! 1.234567890123e30, 1.23456789122e30
197
+ Ft! 1.234567890123e20, 1.23456789122e20
198
+ Ft! 1.234567890123e10, 1.23456789122e10
199
+ Ft! 1.234567890123e0, 1.23456789122e0
200
+ Ft! 1.234567890123e-10, 1.23456789122e-10
201
+ Ft! 1.234567890123e-20, 1.23456789122e-20
202
+ Ft! 1.234567890123e-30, 1.23456789122e-30
203
+ Ft! 1.234567890123e-40, 1.23456789122e-40
204
+ end
205
+ D "14th digit differs: equal enough" do
206
+ Ft 1.2345678901234e90, 1.2345678901233e90
207
+ Ft 1.2345678901234e90, 1.2345678901234e90
208
+ Ft 1.2345678901234e90, 1.2345678901235e90
209
+ Ft 1.2345678901234e50, 1.2345678901233e50
210
+ Ft 1.2345678901234e50, 1.2345678901234e50
211
+ Ft 1.2345678901234e50, 1.2345678901235e50
212
+ Ft 1.2345678901234e10, 1.2345678901233e10
213
+ Ft 1.2345678901234e10, 1.2345678901234e10
214
+ Ft 1.2345678901234e10, 1.2345678901235e10
215
+ Ft 1.2345678901234e0, 1.2345678901233e0
216
+ Ft 1.2345678901234e0, 1.2345678901234e0
217
+ Ft 1.2345678901234e0, 1.2345678901235e0
218
+ Ft 1.2345678901234e-10, 1.2345678901233e-10
219
+ Ft 1.2345678901234e-10, 1.2345678901234e-10
220
+ Ft 1.2345678901234e-10, 1.2345678901235e-10
221
+ Ft 1.2345678901234e-50, 1.2345678901233e-50
222
+ Ft 1.2345678901234e-50, 1.2345678901234e-50
223
+ Ft 1.2345678901234e-50, 1.2345678901235e-50
224
+ Ft 1.2345678901234e-90, 1.2345678901233e-90
225
+ Ft 1.2345678901234e-90, 1.2345678901234e-90
226
+ Ft 1.2345678901234e-90, 1.2345678901235e-90
227
+ D "but it can only be off by 1" do
228
+ Ft! 1.2345678901234e90, 1.2345678901231e90
229
+ Ft! 1.2345678901234e90, 1.2345678901232e90
230
+ Ft! 1.2345678901234e90, 1.2345678901236e90
231
+ Ft! 1.2345678901234e90, 1.2345678901237e90
232
+ Ft! 1.2345678901234e10, 1.2345678901231e10
233
+ Ft! 1.2345678901234e10, 1.2345678901232e10
234
+ Ft! 1.2345678901234e10, 1.2345678901236e10
235
+ Ft! 1.2345678901234e10, 1.2345678901237e10
236
+ Ft! 1.2345678901234e-10, 1.2345678901231e-10
237
+ Ft! 1.2345678901234e-10, 1.2345678901232e-10
238
+ Ft! 1.2345678901234e-10, 1.2345678901236e-10
239
+ Ft! 1.2345678901234e-10, 1.2345678901237e-10
240
+ Ft! 1.2345678901234e-90, 1.2345678901231e-90
241
+ Ft! 1.2345678901234e-90, 1.2345678901232e-90
242
+ Ft! 1.2345678901234e-90, 1.2345678901236e-90
243
+ Ft! 1.2345678901234e-90, 1.2345678901237e-90
244
+ end
245
+ end
246
+ D "Ft does not allow epsilon argument" do
247
+ E(AssertionSpecificationError) { Ft? 3.14159265, 3.1415, 0.01 }
177
248
  end
178
249
  end
179
250
 
@@ -27,5 +27,5 @@ Gem::Specification.new do |s|
27
27
 
28
28
  s.add_development_dependency "bundler"
29
29
 
30
- s.required_ruby_version = '>= 1.8.6' # Not sure about this.
30
+ s.required_ruby_version = '>= 1.8.7' # Doesn't work on 1.8.6 (tested).
31
31
  end
metadata CHANGED
@@ -1,61 +1,61 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: whitestone
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
4
5
  prerelease:
5
- version: 1.0.1
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Gavin Sinclair
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2012-01-01 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
12
+ date: 2012-01-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
16
15
  name: col
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &2152166400 !ruby/object:Gem::Requirement
19
17
  none: false
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
23
21
  version: 1.0.1
24
22
  type: :runtime
25
- version_requirements: *id001
26
- - !ruby/object:Gem::Dependency
27
- name: differ
28
23
  prerelease: false
29
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *2152166400
25
+ - !ruby/object:Gem::Dependency
26
+ name: differ
27
+ requirement: &2152165520 !ruby/object:Gem::Requirement
30
28
  none: false
31
- requirements:
29
+ requirements:
32
30
  - - ~>
33
- - !ruby/object:Gem::Version
34
- version: "0.1"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.1'
35
33
  type: :runtime
36
- version_requirements: *id002
37
- - !ruby/object:Gem::Dependency
38
- name: bundler
39
34
  prerelease: false
40
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *2152165520
36
+ - !ruby/object:Gem::Dependency
37
+ name: bundler
38
+ requirement: &2152165060 !ruby/object:Gem::Requirement
41
39
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- version: "0"
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
46
44
  type: :development
47
- version_requirements: *id003
48
- description: " Unit testing library with colourful, helpful error messages,\n small testing code footprint, good debugger integration.\n (Derivative work of Dfect/Detest.)\n"
49
- email:
45
+ prerelease: false
46
+ version_requirements: *2152165060
47
+ description: ! " Unit testing library with colourful, helpful error messages,\n
48
+ \ small testing code footprint, good debugger integration.\n (Derivative work
49
+ of Dfect/Detest.)\n"
50
+ email:
50
51
  - gsinclair@gmail.com
51
- executables:
52
+ executables:
52
53
  - whitestone
53
54
  extensions: []
54
-
55
55
  extra_rdoc_files: []
56
-
57
- files:
56
+ files:
58
57
  - .gitignore
58
+ - Announcements.txt
59
59
  - Gemfile
60
60
  - History.txt
61
61
  - LICENSE
@@ -94,33 +94,31 @@ files:
94
94
  - whitestone.gemspec
95
95
  homepage: http://gsinclair.github.com/whitestone.html
96
96
  licenses: []
97
-
98
97
  post_install_message:
99
98
  rdoc_options: []
100
-
101
- require_paths:
99
+ require_paths:
102
100
  - lib
103
- required_ruby_version: !ruby/object:Gem::Requirement
101
+ required_ruby_version: !ruby/object:Gem::Requirement
104
102
  none: false
105
- requirements:
106
- - - ">="
107
- - !ruby/object:Gem::Version
108
- version: 1.8.6
109
- required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: 1.8.7
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
108
  none: false
111
- requirements:
112
- - - ">="
113
- - !ruby/object:Gem::Version
114
- version: "0"
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
115
113
  requirements: []
116
-
117
- rubyforge_project: ""
118
- rubygems_version: 1.8.11
114
+ rubyforge_project: ''
115
+ rubygems_version: 1.8.10
119
116
  signing_key:
120
117
  specification_version: 3
121
118
  summary: Succinct and simple unit testing
122
- test_files:
119
+ test_files:
123
120
  - test/_setup.rb
124
121
  - test/custom_assertions.rb
125
122
  - test/insulation.rb
126
123
  - test/whitestone_test.rb
124
+ has_rdoc: