whitestone 1.0.1 → 1.0.2

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.
@@ -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: