minitest 1.7.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +27 -0
- data/Manifest.txt +6 -3
- data/README.txt +133 -67
- data/lib/minitest/benchmark.rb +324 -0
- data/lib/minitest/mock.rb +14 -7
- data/lib/minitest/pride.rb +35 -0
- data/lib/minitest/spec.rb +8 -5
- data/lib/minitest/unit.rb +179 -86
- data/test/test_minitest_benchmark.rb +98 -0
- data/test/test_minitest_mock.rb +106 -0
- data/test/{test_mini_spec.rb → test_minitest_spec.rb} +12 -2
- data/test/{test_mini_test.rb → test_minitest_unit.rb} +51 -73
- metadata +38 -18
- data/test/test_mini_mock.rb +0 -77
data/History.txt
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
=== 2.0.0 / 2010-11-11
|
2
|
+
|
3
|
+
* 3 major enhancements:
|
4
|
+
|
5
|
+
* Added minitest/benchmark! Assert your performance! YAY!
|
6
|
+
* Refactored runner to allow for more extensibility. See minitest/benchmark.
|
7
|
+
* This makes the runner backwards incompatible in some ways!
|
8
|
+
|
9
|
+
* 9 minor enhancements:
|
10
|
+
|
11
|
+
* Added MiniTest::Unit.after_tests { ... }
|
12
|
+
* Improved output by adding test rates and a more sortable verbose format
|
13
|
+
* Improved readme based on feedback from others
|
14
|
+
* Added io method to TestCase. If used, it'll supplant '.EF' output.
|
15
|
+
* Refactored IO in MiniTest::Unit.
|
16
|
+
* Refactored _run_anything to _run_suite to make it easier to wrap (ngauthier)
|
17
|
+
* Spec class names are now the unmunged descriptions (btakita)
|
18
|
+
* YAY for not having redundant rdoc/readmes!
|
19
|
+
* Help output is now generated from the flags you passed straight up.
|
20
|
+
|
21
|
+
* 4 bug fixes:
|
22
|
+
|
23
|
+
* Fixed scoping issue on minitest/mock (srbaker/prosperity)
|
24
|
+
* Fixed some of the assertion default messages
|
25
|
+
* Fixes autorun when on windows with ruby install on different drive (larsch)
|
26
|
+
* Fixed rdoc output bug in spec.rb
|
27
|
+
|
1
28
|
=== 1.7.2 / 2010-09-23
|
2
29
|
|
3
30
|
* 3 bug fixes:
|
data/Manifest.txt
CHANGED
@@ -5,9 +5,12 @@ README.txt
|
|
5
5
|
Rakefile
|
6
6
|
design_rationale.rb
|
7
7
|
lib/minitest/autorun.rb
|
8
|
+
lib/minitest/benchmark.rb
|
8
9
|
lib/minitest/mock.rb
|
10
|
+
lib/minitest/pride.rb
|
9
11
|
lib/minitest/spec.rb
|
10
12
|
lib/minitest/unit.rb
|
11
|
-
test/
|
12
|
-
test/
|
13
|
-
test/
|
13
|
+
test/test_minitest_benchmark.rb
|
14
|
+
test/test_minitest_mock.rb
|
15
|
+
test/test_minitest_spec.rb
|
16
|
+
test/test_minitest_unit.rb
|
data/README.txt
CHANGED
@@ -1,25 +1,44 @@
|
|
1
|
-
= minitest
|
1
|
+
= minitest/*
|
2
2
|
|
3
3
|
* http://rubyforge.org/projects/bfts
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
minitest
|
8
|
-
|
9
|
-
test writer and for language implementors that need a minimal set of
|
10
|
-
methods to bootstrap a working unit test suite.
|
7
|
+
minitest provides a complete suite of testing facilities supporting
|
8
|
+
TDD, BDD, mocking, and benchmarking.
|
11
9
|
|
12
|
-
|
10
|
+
minitest/unit is a small and incredibly fast unit testing framework.
|
11
|
+
It provides a rich set of assertions to make your tests clean and
|
12
|
+
readable.
|
13
13
|
|
14
|
-
|
14
|
+
minitest/spec is a functionally complete spec engine. It hooks onto
|
15
|
+
minitest/unit and seamlessly bridges test assertions over to spec
|
16
|
+
expectations.
|
15
17
|
|
16
|
-
|
18
|
+
minitest/benchmark is an awesome way to assert the performance of your
|
19
|
+
algorithms in a repeatable manner. Now you can assert that your newb
|
20
|
+
co-worker doesn't replace your linear algorithm with an exponential
|
21
|
+
one!
|
22
|
+
|
23
|
+
minitest/mock by Steven Baker, is a beautifully tiny mock object
|
24
|
+
framework.
|
25
|
+
|
26
|
+
minitest/pride shows pride in testing and adds coloring to your test
|
27
|
+
output.
|
28
|
+
|
29
|
+
minitest/unit is meant to have a clean implementation for language
|
30
|
+
implementors that need a minimal set of methods to bootstrap a working
|
31
|
+
test suite. For example, there is no magic involved for test-case
|
32
|
+
discovery.
|
17
33
|
|
18
34
|
== FEATURES/PROBLEMS:
|
19
35
|
|
20
|
-
*
|
21
|
-
*
|
22
|
-
*
|
36
|
+
* minitest/autorun - the easy and explicit way to run all your tests.
|
37
|
+
* minitest/unit - a very fast, simple, and clean test system.
|
38
|
+
* minitest/spec - a very fast, simple, and clean spec system.
|
39
|
+
* minitest/mock - a simple and clean mock system.
|
40
|
+
* minitest/benchmark - an awesome way to assert your algorithm's performance.
|
41
|
+
* minitest/pride - show your pride in testing!
|
23
42
|
* Incredibly small and fast runner, but no bells and whistles.
|
24
43
|
|
25
44
|
== RATIONALE:
|
@@ -30,100 +49,147 @@ See design_rationale.rb to see how specs and tests work in minitest.
|
|
30
49
|
|
31
50
|
Given that you'd like to test the following class:
|
32
51
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
def does_it_blend?
|
39
|
-
"YES!"
|
40
|
-
end
|
52
|
+
class Meme
|
53
|
+
def i_can_has_cheezburger?
|
54
|
+
"OHAI!"
|
41
55
|
end
|
42
56
|
|
57
|
+
def does_it_blend?
|
58
|
+
"YES!"
|
59
|
+
end
|
60
|
+
end
|
43
61
|
|
44
62
|
=== Unit tests
|
45
63
|
|
46
|
-
|
47
|
-
MiniTest::Unit.autorun
|
64
|
+
require 'minitest/autorun'
|
48
65
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
66
|
+
class TestMeme < MiniTest::Unit::TestCase
|
67
|
+
def setup
|
68
|
+
@meme = Meme.new
|
69
|
+
end
|
53
70
|
|
54
|
-
|
55
|
-
|
56
|
-
|
71
|
+
def test_that_kitty_can_eat
|
72
|
+
assert_equal "OHAI!", @meme.i_can_has_cheezburger?
|
73
|
+
end
|
57
74
|
|
58
|
-
|
59
|
-
|
60
|
-
end
|
75
|
+
def test_that_it_doesnt_not_blend
|
76
|
+
refute_match /^no/i, @meme.does_it_blend?
|
61
77
|
end
|
78
|
+
end
|
62
79
|
|
63
80
|
=== Specs
|
64
81
|
|
65
|
-
|
66
|
-
|
82
|
+
require 'minitest/autorun'
|
83
|
+
|
84
|
+
describe Meme do
|
85
|
+
before do
|
86
|
+
@meme = Meme.new
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "when asked about cheeseburgers" do
|
90
|
+
it "must respond positively" do
|
91
|
+
@meme.i_can_has_cheezburger?.must_equal "OHAI!"
|
92
|
+
end
|
93
|
+
end
|
67
94
|
|
68
|
-
describe
|
69
|
-
|
70
|
-
@meme
|
95
|
+
describe "when asked about blending possibilities" do
|
96
|
+
it "won't say no" do
|
97
|
+
@meme.does_it_blend?.wont_match /^no/i
|
71
98
|
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
=== Benchmarks
|
103
|
+
|
104
|
+
Add benchmarks to your regular unit tests. If the unit tests fail, the
|
105
|
+
benchmarks won't run.
|
72
106
|
|
73
|
-
|
74
|
-
|
75
|
-
|
107
|
+
# optionally run benchmarks, good for CI-only work!
|
108
|
+
require 'minitest/benchmark' if ENV["BENCH"]
|
109
|
+
|
110
|
+
class TestMeme < MiniTest::Unit::TestCase
|
111
|
+
# Override self.bench_range or default range is [1, 10, 100, 1_000, 10_000]
|
112
|
+
def bench_my_algorithm
|
113
|
+
assert_performance_linear 0.9999 do |n| # n is a range value
|
114
|
+
n.times do
|
115
|
+
@obj.my_algorithm
|
76
116
|
end
|
77
117
|
end
|
118
|
+
end
|
119
|
+
end
|
78
120
|
|
79
|
-
|
80
|
-
|
81
|
-
|
121
|
+
Or add them to your specs. If you make benchmarks optional, you'll
|
122
|
+
need to wrap your benchmarks in a conditional since the methods won't
|
123
|
+
be defined.
|
124
|
+
|
125
|
+
describe Meme do
|
126
|
+
if ENV["BENCH"] then
|
127
|
+
bench_performance_linear "my_algorithm", 0.9999 do |n|
|
128
|
+
100.times do
|
129
|
+
@obj.my_algorithm(n)
|
82
130
|
end
|
83
131
|
end
|
84
132
|
end
|
133
|
+
end
|
134
|
+
|
135
|
+
outputs something like:
|
136
|
+
|
137
|
+
# Running benchmarks:
|
138
|
+
|
139
|
+
TestBlah 100 1000 10000
|
140
|
+
bench_my_algorithm 0.006167 0.079279 0.786993
|
141
|
+
bench_other_algorithm 0.061679 0.792797 7.869932
|
142
|
+
|
143
|
+
Output is tab-delimited to make it easy to paste into a spreadsheet.
|
85
144
|
|
86
145
|
=== Mocks
|
87
146
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
147
|
+
class MemeAsker
|
148
|
+
def initialize(meme)
|
149
|
+
@meme = meme
|
150
|
+
end
|
92
151
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
152
|
+
def ask(question)
|
153
|
+
method = question.tr(" ","_") + "?"
|
154
|
+
@meme.send(method)
|
97
155
|
end
|
156
|
+
end
|
98
157
|
|
99
|
-
|
100
|
-
require 'minitest/mock'
|
101
|
-
MiniTest::Unit.autorun
|
158
|
+
require 'minitest/autorun'
|
102
159
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
160
|
+
describe MemeAsker do
|
161
|
+
before do
|
162
|
+
@meme = MiniTest::Mock.new
|
163
|
+
@meme_asker = MemeAsker.new @meme
|
164
|
+
end
|
108
165
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
166
|
+
describe "#ask" do
|
167
|
+
describe "when passed an unpunctuated question" do
|
168
|
+
it "should invoke the appropriate predicate method on the meme" do
|
169
|
+
@meme.expect :does_it_blend?, :return_value
|
170
|
+
@meme_asker.ask "does it blend"
|
171
|
+
@meme.verify
|
116
172
|
end
|
117
173
|
end
|
118
174
|
end
|
175
|
+
end
|
119
176
|
|
120
177
|
== REQUIREMENTS:
|
121
178
|
|
122
|
-
|
179
|
+
* Ruby 1.8, maybe even 1.6 or lower. No magic is involved.
|
123
180
|
|
124
181
|
== INSTALL:
|
125
182
|
|
126
|
-
|
183
|
+
sudo gem install minitest
|
184
|
+
|
185
|
+
On 1.9, you already have it. To get newer candy you can still install
|
186
|
+
the gem, but you'll need to activate the gem explicitly to use it:
|
187
|
+
|
188
|
+
require 'rubygems'
|
189
|
+
gem 'minitest' # ensures you're using the gem, and not the built in MT
|
190
|
+
require 'minitest/autorun'
|
191
|
+
|
192
|
+
# ... usual testing stuffs ...
|
127
193
|
|
128
194
|
== LICENSE:
|
129
195
|
|
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'minitest/unit'
|
2
|
+
require 'minitest/spec'
|
3
|
+
|
4
|
+
class MiniTest::Unit
|
5
|
+
attr_accessor :runner
|
6
|
+
|
7
|
+
def run_benchmarks
|
8
|
+
_run_anything :benchmark
|
9
|
+
end
|
10
|
+
|
11
|
+
def benchmark_suite_header suite
|
12
|
+
"\n#{suite}\t#{suite.bench_range.join("\t")}"
|
13
|
+
end
|
14
|
+
|
15
|
+
class TestCase
|
16
|
+
##
|
17
|
+
# Returns a set of ranges stepped exponentially from +min+ to
|
18
|
+
# +max+ by powers of +base+. Eg:
|
19
|
+
#
|
20
|
+
# bench_exp(2, 16, 2) # => [2, 4, 8, 16]
|
21
|
+
|
22
|
+
def self.bench_exp min, max, base = 10
|
23
|
+
min = (Math.log10(min) / Math.log10(base)).to_i
|
24
|
+
max = (Math.log10(max) / Math.log10(base)).to_i
|
25
|
+
|
26
|
+
(min..max).map { |m| base ** m }.to_a
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Returns a set of ranges stepped linearly from +min+ to +max+ by
|
31
|
+
# +step+. Eg:
|
32
|
+
#
|
33
|
+
# bench_linear(20, 40, 10) # => [20, 30, 40]
|
34
|
+
|
35
|
+
def self.bench_linear min, max, step = 10
|
36
|
+
(min..max).step(step).to_a
|
37
|
+
rescue LocalJumpError # 1.8.6
|
38
|
+
r = []; (min..max).step(step) { |n| r << n }; r
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Returns the benchmark methods (methods that start with bench_)
|
43
|
+
# for that class.
|
44
|
+
|
45
|
+
def self.benchmark_methods # :nodoc:
|
46
|
+
public_instance_methods(true).grep(/^bench_/).map { |m| m.to_s }.sort
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Returns all test suites that have benchmark methods.
|
51
|
+
|
52
|
+
def self.benchmark_suites
|
53
|
+
TestCase.test_suites.reject { |s| s.benchmark_methods.empty? }
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Specifies the ranges used for benchmarking for that class.
|
58
|
+
# Defaults to exponential growth from 1 to 10k by powers of 10.
|
59
|
+
# Override if you need different ranges for your benchmarks.
|
60
|
+
#
|
61
|
+
# See also: ::bench_exp and ::bench_linear.
|
62
|
+
|
63
|
+
def self.bench_range
|
64
|
+
bench_exp 1, 10_000
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Runs the given +work+, gathering the times of each run. Range
|
69
|
+
# and times are then passed to a given +validation+ proc. Outputs
|
70
|
+
# the benchmark name and times in tab-separated format, making it
|
71
|
+
# easy to paste into a spreadsheet for graphing or further
|
72
|
+
# analysis.
|
73
|
+
#
|
74
|
+
# Ranges are specified by ::bench_range.
|
75
|
+
#
|
76
|
+
# Eg:
|
77
|
+
#
|
78
|
+
# def bench_algorithm
|
79
|
+
# validation = proc { |x, y| ... }
|
80
|
+
# assert_performance validation do |x|
|
81
|
+
# @obj.algorithm
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
|
85
|
+
def assert_performance validation, &work
|
86
|
+
range = self.class.bench_range
|
87
|
+
|
88
|
+
io.print "#{__name__}"
|
89
|
+
|
90
|
+
times = []
|
91
|
+
|
92
|
+
range.each do |x|
|
93
|
+
GC.start
|
94
|
+
t0 = Time.now
|
95
|
+
instance_exec(x, &work)
|
96
|
+
t = Time.now - t0
|
97
|
+
|
98
|
+
io.print "\t%9.6f" % t
|
99
|
+
times << t
|
100
|
+
end
|
101
|
+
io.puts
|
102
|
+
|
103
|
+
validation[range, times]
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Runs the given +work+ and asserts that the times gathered fit to
|
108
|
+
# match a constant rate (eg, linear slope == 0) within a given error
|
109
|
+
# +threshold+.
|
110
|
+
#
|
111
|
+
# Fit is calculated by #fit_constant.
|
112
|
+
#
|
113
|
+
# Ranges are specified by ::bench_range.
|
114
|
+
#
|
115
|
+
# Eg:
|
116
|
+
#
|
117
|
+
# def bench_algorithm
|
118
|
+
# assert_performance_constant 0.9999 do |x|
|
119
|
+
# @obj.algorithm
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
|
123
|
+
def assert_performance_constant threshold = 0.99, &work
|
124
|
+
validation = proc do |range, times|
|
125
|
+
a, b, rr = fit_linear range, times
|
126
|
+
assert_in_delta 0, b, 1 - threshold
|
127
|
+
[a, b, rr]
|
128
|
+
end
|
129
|
+
|
130
|
+
assert_performance validation, &work
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Runs the given +work+ and asserts that the times gathered fit to
|
135
|
+
# match a exponential curve within a given error +threshold+.
|
136
|
+
#
|
137
|
+
# Fit is calculated by #fit_exponential.
|
138
|
+
#
|
139
|
+
# Ranges are specified by ::bench_range.
|
140
|
+
#
|
141
|
+
# Eg:
|
142
|
+
#
|
143
|
+
# def bench_algorithm
|
144
|
+
# assert_performance_exponential 0.9999 do |x|
|
145
|
+
# @obj.algorithm
|
146
|
+
# end
|
147
|
+
# end
|
148
|
+
|
149
|
+
def assert_performance_exponential threshold = 0.99, &work
|
150
|
+
assert_performance validation_for_fit(:exponential, threshold), &work
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Runs the given +work+ and asserts that the times gathered fit to
|
155
|
+
# match a straight line within a given error +threshold+.
|
156
|
+
#
|
157
|
+
# Fit is calculated by #fit_linear.
|
158
|
+
#
|
159
|
+
# Ranges are specified by ::bench_range.
|
160
|
+
#
|
161
|
+
# Eg:
|
162
|
+
#
|
163
|
+
# def bench_algorithm
|
164
|
+
# assert_performance_linear 0.9999 do |x|
|
165
|
+
# @obj.algorithm
|
166
|
+
# end
|
167
|
+
# end
|
168
|
+
|
169
|
+
def assert_performance_linear threshold = 0.99, &work
|
170
|
+
assert_performance validation_for_fit(:linear, threshold), &work
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Runs the given +work+ and asserts that the times gathered curve
|
175
|
+
# fit to match a power curve within a given error +threshold+.
|
176
|
+
#
|
177
|
+
# Fit is calculated by #fit_power.
|
178
|
+
#
|
179
|
+
# Ranges are specified by ::bench_range.
|
180
|
+
#
|
181
|
+
# Eg:
|
182
|
+
#
|
183
|
+
# def bench_algorithm
|
184
|
+
# assert_performance_power 0.9999 do |x|
|
185
|
+
# @obj.algorithm
|
186
|
+
# end
|
187
|
+
# end
|
188
|
+
|
189
|
+
def assert_performance_power threshold = 0.99, &work
|
190
|
+
assert_performance validation_for_fit(:power, threshold), &work
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# Takes an array of x/y pairs and calculates the general R^2 value.
|
195
|
+
#
|
196
|
+
# See: http://en.wikipedia.org/wiki/Coefficient_of_determination
|
197
|
+
|
198
|
+
def fit_error xys
|
199
|
+
y_bar = sigma(xys) { |x, y| y } / xys.size.to_f
|
200
|
+
ss_tot = sigma(xys) { |x, y| (y - y_bar) ** 2 }
|
201
|
+
ss_err = sigma(xys) { |x, y| (yield(x) - y) ** 2 }
|
202
|
+
|
203
|
+
1 - (ss_err / ss_tot)
|
204
|
+
end
|
205
|
+
|
206
|
+
##
|
207
|
+
# To fit a functional form: y = ae^(bx).
|
208
|
+
#
|
209
|
+
# Takes x and y values and returns [a, b, r^2].
|
210
|
+
#
|
211
|
+
# See: http://mathworld.wolfram.com/LeastSquaresFittingExponential.html
|
212
|
+
|
213
|
+
def fit_exponential xs, ys
|
214
|
+
n = xs.size
|
215
|
+
xys = xs.zip(ys)
|
216
|
+
sxlny = sigma(xys) { |x,y| x * Math.log(y) }
|
217
|
+
slny = sigma(xys) { |x,y| Math.log(y) }
|
218
|
+
sx2 = sigma(xys) { |x,y| x * x }
|
219
|
+
sx = sigma xs
|
220
|
+
|
221
|
+
c = n * sx2 - sx ** 2
|
222
|
+
a = (slny * sx2 - sx * sxlny) / c
|
223
|
+
b = ( n * sxlny - sx * slny ) / c
|
224
|
+
|
225
|
+
return Math.exp(a), b, fit_error(xys) { |x| Math.exp(a + b * x) }
|
226
|
+
end
|
227
|
+
|
228
|
+
##
|
229
|
+
# Fits the functional form: a + bx.
|
230
|
+
#
|
231
|
+
# Takes x and y values and returns [a, b, r^2].
|
232
|
+
#
|
233
|
+
# See: http://mathworld.wolfram.com/LeastSquaresFitting.html
|
234
|
+
|
235
|
+
def fit_linear xs, ys
|
236
|
+
n = xs.size
|
237
|
+
xys = xs.zip(ys)
|
238
|
+
sx = sigma xs
|
239
|
+
sy = sigma ys
|
240
|
+
sx2 = sigma(xs) { |x| x ** 2 }
|
241
|
+
sxy = sigma(xys) { |x,y| x * y }
|
242
|
+
|
243
|
+
c = n * sx2 - sx**2
|
244
|
+
a = (sy * sx2 - sx * sxy) / c
|
245
|
+
b = ( n * sxy - sx * sy ) / c
|
246
|
+
|
247
|
+
return a, b, fit_error(xys) { |x| a + b * x }
|
248
|
+
end
|
249
|
+
|
250
|
+
##
|
251
|
+
# To fit a functional form: y = ax^b.
|
252
|
+
#
|
253
|
+
# Takes x and y values and returns [a, b, r^2].
|
254
|
+
#
|
255
|
+
# See: http://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html
|
256
|
+
|
257
|
+
def fit_power xs, ys
|
258
|
+
n = xs.size
|
259
|
+
xys = xs.zip(ys)
|
260
|
+
slnxlny = sigma(xys) { |x, y| Math.log(x) * Math.log(y) }
|
261
|
+
slnx = sigma(xs) { |x | Math.log(x) }
|
262
|
+
slny = sigma(ys) { | y| Math.log(y) }
|
263
|
+
slnx2 = sigma(xs) { |x | Math.log(x) ** 2 }
|
264
|
+
|
265
|
+
b = (n * slnxlny - slnx * slny) / (n * slnx2 - slnx ** 2);
|
266
|
+
a = (slny - b * slnx) / n
|
267
|
+
|
268
|
+
return Math.exp(a), b, fit_error(xys) { |x| (Math.exp(a) * (x ** b)) }
|
269
|
+
end
|
270
|
+
|
271
|
+
##
|
272
|
+
# Enumerates over +enum+ mapping +block+ if given, returning the
|
273
|
+
# sum of the result. Eg:
|
274
|
+
#
|
275
|
+
# sigma([1, 2, 3]) # => 1 + 2 + 3 => 7
|
276
|
+
# sigma([1, 2, 3]) { |n| n ** 2 } # => 1 + 4 + 9 => 14
|
277
|
+
|
278
|
+
def sigma enum, &block
|
279
|
+
enum = enum.map(&block) if block
|
280
|
+
enum.inject { |sum, n| sum + n }
|
281
|
+
end
|
282
|
+
|
283
|
+
##
|
284
|
+
# Returns a proc that calls the specified fit method and asserts
|
285
|
+
# that the error is within a tolerable threshold.
|
286
|
+
|
287
|
+
def validation_for_fit msg, threshold
|
288
|
+
proc do |range, times|
|
289
|
+
a, b, rr = send "fit_#{msg}", range, times
|
290
|
+
assert_operator rr, :>=, threshold
|
291
|
+
[a, b, rr]
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
class MiniTest::Spec
|
298
|
+
def self.bench name, &block
|
299
|
+
define_method "bench_#{name.gsub(/\W+/, '_')}", &block
|
300
|
+
end
|
301
|
+
|
302
|
+
def self.bench_range &block
|
303
|
+
meta = (class << self; self; end)
|
304
|
+
meta.send :define_method, "bench_range", &block
|
305
|
+
end
|
306
|
+
|
307
|
+
def self.bench_performance_linear name, threshold = 0.9, &work
|
308
|
+
bench name do
|
309
|
+
assert_performance_linear threshold, &work
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def self.bench_performance_constant name, threshold = 0.99, &work
|
314
|
+
bench name do
|
315
|
+
assert_performance_constant threshold, &work
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def self.bench_performance_exponential name, threshold = 0.99, &work
|
320
|
+
bench name do
|
321
|
+
assert_performance_exponential threshold, &work
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|