lax 0.0.3 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +25 -26
- data/lax.gemspec +5 -4
- data/lib/lax/rake_task.rb +20 -0
- data/lib/lax/source.rb +288 -0
- data/lib/lax.rb +3 -35
- data/spec/acceptance/acceptance_spec.rb +26 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/unit/fixture/hashable_spec.rb +27 -0
- data/spec/unit/hook_spec.rb +40 -0
- data/spec/unit/lax_spec.rb +20 -0
- data/spec/unit/target_spec.rb +25 -0
- data/test/control.rb +28 -0
- metadata +36 -21
- data/lib/lax/case.rb +0 -17
- data/lib/lax/hook.rb +0 -24
- data/lib/lax/task.rb +0 -36
- data/lib/lax/tree.rb +0 -60
- data/lib/lax/version.rb +0 -3
- data/rakefile +0 -6
- data/test/case/cases.rb +0 -5
- data/test/case/control.rb +0 -32
- data/test/unit/callbacks.rb +0 -11
- data/test/unit/implicit_receiver.rb +0 -5
- data/test/unit/test.rb +0 -8
data/README.md
CHANGED
@@ -1,43 +1,42 @@
|
|
1
1
|
lax
|
2
2
|
===
|
3
|
-
|
3
|
+
Lax is an insouciant smidgen of a testing framework that tries to be an invisible wrapper around your ideas about how your code should work.
|
4
4
|
```ruby
|
5
|
-
|
6
|
-
|
5
|
+
Lax.assert do
|
6
|
+
let number: 1,
|
7
|
+
string: 'Hi There',
|
8
|
+
regexp: defer{ /the/ } # lazy evaluation
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
+
number + 1 == 2
|
11
|
+
string.downcase =~ regexp
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
assert do
|
14
|
+
let number: 2
|
15
|
+
number - 1 == 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Lax::Run[ Lax ] #=> pass, pass, pass
|
14
20
|
|
15
|
-
0.upto(10) { |n|
|
16
|
-
calling(:**).with n
|
17
|
-
}
|
18
|
-
}
|
19
|
-
}
|
20
|
-
}
|
21
|
-
Lax.test!
|
22
21
|
```
|
23
|
-
|
24
|
-
|
25
|
-
*
|
26
|
-
*
|
27
|
-
*
|
22
|
+
how come lax is neat
|
23
|
+
--------------------
|
24
|
+
* Minimal bullshit legalese.
|
25
|
+
* Easy-to-define custom matchers and hooks.
|
26
|
+
* Hackable with a tiny code footprint (< 300 SLOC).
|
28
27
|
* Does not pollute your toplevel namespace or infect the entire Ruby object hierarchy with its code.
|
29
28
|
|
30
|
-
make it do it
|
31
|
-
|
29
|
+
how to make it do it
|
30
|
+
--------------------
|
32
31
|
```shell
|
32
|
+
gem install lax
|
33
33
|
cd my/project/root
|
34
|
-
|
35
|
-
|
36
|
-
echo "require 'lax'; Lax::RakeTask.new(:dir=>'lax')" >> rakefile
|
34
|
+
echo "require 'lax/rake_task'; Lax::RakeTask.new" >> Rakefile
|
35
|
+
# write yr tests in the test directory (default test)
|
37
36
|
rake lax
|
38
37
|
```
|
39
38
|
|
40
39
|
license
|
41
40
|
-------
|
42
|
-
X11. See LICENSE for details.
|
41
|
+
MIT/X11. See LICENSE for details.
|
43
42
|
|
data/lax.gemspec
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
$LOAD_PATH << File.expand_path('../lib', __FILE__)
|
2
2
|
require 'rake'
|
3
|
-
require 'lax
|
3
|
+
require 'lax'
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'lax'
|
7
7
|
spec.version = Lax::VERSION
|
8
8
|
spec.author = 'feivel jellyfish'
|
9
9
|
spec.email = 'feivel@sdf.org'
|
10
|
-
spec.files = FileList['lax.gemspec','lib
|
11
|
-
spec.test_files = FileList['
|
10
|
+
spec.files = FileList['lax.gemspec','lib/**/*','README.md','LICENSE']
|
11
|
+
spec.test_files = FileList['test/**/*.rb','spec/**/*.rb']
|
12
12
|
spec.license = 'MIT/X11'
|
13
13
|
spec.homepage = 'http://github.com/gwentacle/lax'
|
14
14
|
spec.summary = 'An insouciant smidgen of a testing framework.'
|
15
|
-
spec.description = 'A lightweight testing framework
|
15
|
+
spec.description = 'A lightweight testing framework.'
|
16
|
+
spec.add_development_dependency 'rspec'
|
16
17
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'lax'
|
3
|
+
class Lax
|
4
|
+
module RakeTask
|
5
|
+
class << self
|
6
|
+
include Rake::DSL
|
7
|
+
def new(opts = {})
|
8
|
+
o = Lax.config.task.merge opts
|
9
|
+
namespace o[:name] do
|
10
|
+
task(:load) { Dir["./#{o[:dir]}/**/*.rb"].each {|f| load f} }
|
11
|
+
task(:run) do
|
12
|
+
Lax::Run[ Lax ]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
task o[:name] => ["#{o[:name]}:load", "#{o[:name]}:run"]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
data/lib/lax/source.rb
ADDED
@@ -0,0 +1,288 @@
|
|
1
|
+
VERSION = '0.2.1'
|
2
|
+
|
3
|
+
class Assertion < Struct.new :name, :subject, :condition, :src, :matcher, :args, :hooks
|
4
|
+
def pass?
|
5
|
+
memoize(:pass) { condition.call value }
|
6
|
+
end
|
7
|
+
|
8
|
+
def value
|
9
|
+
memoize(:value) { subject.call }
|
10
|
+
end
|
11
|
+
|
12
|
+
def validate
|
13
|
+
memoize(:validate) do
|
14
|
+
hooks.before.call self
|
15
|
+
pass?
|
16
|
+
self.tap { hooks.after.call self }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def memoize(key)
|
22
|
+
@memo ||= {}
|
23
|
+
@memo.has_key?(key) ? @memo[key] : @memo[key] = yield
|
24
|
+
end
|
25
|
+
|
26
|
+
class Xptn < Struct.new :assertion, :exception
|
27
|
+
attr_accessor :name, :src, :matcher, :args
|
28
|
+
|
29
|
+
def pass?
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
def value
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(a, x)
|
38
|
+
super
|
39
|
+
%w{name src matcher args}.each {|m| send "#{m}=", a.send(m)}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Fixture
|
45
|
+
def self.new(hash)
|
46
|
+
klass = Struct.new(*hash.keys)
|
47
|
+
klass.send :include, self
|
48
|
+
klass.new *hash.values
|
49
|
+
end
|
50
|
+
|
51
|
+
module Hashable
|
52
|
+
def self.new(hashable)
|
53
|
+
hash = hashable.to_hash
|
54
|
+
klass = Struct.new(*hash.keys)
|
55
|
+
klass.send :include, self, Fixture
|
56
|
+
klass.new(*hash.values.map do |val|
|
57
|
+
(Hash===val) ? new(val) : val
|
58
|
+
end)
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_hash
|
62
|
+
Hash[
|
63
|
+
members.zip entries.map {|e| e.kind_of?(Hashable) ? e.to_hash : e }
|
64
|
+
]
|
65
|
+
end
|
66
|
+
|
67
|
+
def merge(hashable)
|
68
|
+
Hashable.new to_hash.merge hashable
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Target < BasicObject
|
74
|
+
def self.define_matcher(sym, &p)
|
75
|
+
define_method(sym) do |*a,&b|
|
76
|
+
p ?
|
77
|
+
satisfies(sym) do |o|
|
78
|
+
p[*a.map {|v| resolve v},&b][o]
|
79
|
+
end :
|
80
|
+
satisfies(sym,*a) do |o|
|
81
|
+
o.__send__ sym,*a.map {|v| resolve v},&b
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.define_predicate(sym)
|
87
|
+
if sym =~ /(.*)(\?|_?p)$/
|
88
|
+
define_method($1) { satisfies($1) {|o| o.__send__ sym} }
|
89
|
+
else
|
90
|
+
raise ArgumentError, "#{sym} does not appear to be a predicate"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
%w{== === != =~ !~ < > <= >=}.each {|m| define_matcher m}
|
95
|
+
%w{odd? even? is_a? kind_of? include?}.each {|m| define_predicate m}
|
96
|
+
|
97
|
+
def initialize(node, subj, name, src)
|
98
|
+
@node, @subj, @name, @src = node, subj, name, src
|
99
|
+
end
|
100
|
+
|
101
|
+
def satisfies(matcher=nil, *args, &cond)
|
102
|
+
assert!(cond, *[ matcher, args ])
|
103
|
+
end
|
104
|
+
|
105
|
+
def method_missing(sym, *args, &blk)
|
106
|
+
Target.new @node, ->{@subj.call.__send__(sym, *args, &blk)}, @name, @src
|
107
|
+
end
|
108
|
+
|
109
|
+
def __val__
|
110
|
+
@subj.call
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
def assert!(cond, matcher=nil, args=nil)
|
115
|
+
name, subj, src, hooks = @name, @subj, @src, @node.hooks
|
116
|
+
ord = @node.instance_methods.size.to_s
|
117
|
+
@node.send(:include, ::Module.new do
|
118
|
+
define_method(ord) do
|
119
|
+
::Lax::Assertion.new name, subj, cond, src, matcher, args, hooks
|
120
|
+
end
|
121
|
+
end)
|
122
|
+
end
|
123
|
+
|
124
|
+
def resolve(v)
|
125
|
+
::Lax::Target === v ? v.__val__ : v
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
module Run
|
131
|
+
def self.[](lax)
|
132
|
+
hook = lax.config.run.hooks
|
133
|
+
hook.start[ as = lax.map(&:new).flatten ]
|
134
|
+
as.map do |assertion|
|
135
|
+
hook.before[ assertion ]
|
136
|
+
validate_protect(assertion).tap {|v| hook.after[v]}
|
137
|
+
end.tap {|vs| hook.finish[vs]}
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
def self.validate_protect(a)
|
142
|
+
begin
|
143
|
+
a.validate
|
144
|
+
rescue => e
|
145
|
+
Assertion::Xptn.new(a, e)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class Hook < Proc
|
151
|
+
class << self
|
152
|
+
def _resolve(hook)
|
153
|
+
if hook.is_a? Hook
|
154
|
+
hook
|
155
|
+
elsif hook.is_a? Proc
|
156
|
+
new &hook
|
157
|
+
elsif hook.is_a?(Symbol) and self.respond_to?(hook)
|
158
|
+
send hook
|
159
|
+
else
|
160
|
+
raise NameError, "Unable to resolve hook `#{hook}'"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def noop
|
165
|
+
new {|*a|}
|
166
|
+
end
|
167
|
+
|
168
|
+
def output
|
169
|
+
new {|tc| print tc.pass? ? "\x1b[32m.\x1b[0m" : "\x1b[31mX\x1b[0m"}
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns a hook for generating terminal output from test cases.
|
173
|
+
def summary
|
174
|
+
new {|cs| puts "\nFinished #{cs.size} tests with #{cs.reject(&:pass?).size} failures"}
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns a hook for generating terminal output from test cases.
|
178
|
+
def failures
|
179
|
+
new do |cs|
|
180
|
+
cs.reject(&:pass?).each do |f|
|
181
|
+
puts " #{f.src}\n " <<
|
182
|
+
"#{f.exception ?
|
183
|
+
"(raised an unhandled #{f.exception.class})" :
|
184
|
+
"(got #{f.subject})"}"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def define(sym, &p)
|
190
|
+
define_singleton_method(sym) {new &p}
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def <<(hook)
|
195
|
+
Hook.new {|*a,&b| call(Hook._resolve(hook)[*a,&b])}
|
196
|
+
end
|
197
|
+
|
198
|
+
def +(hook)
|
199
|
+
Hook.new {|*a,&b| call(*a,&b); Hook._resolve(hook)[*a,&b]}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
CONFIG = Fixture::Hashable.new(
|
204
|
+
task: { dir: :test, name: :lax },
|
205
|
+
node: {
|
206
|
+
hooks: {
|
207
|
+
before: Hook.noop,
|
208
|
+
after: Hook.noop
|
209
|
+
}
|
210
|
+
},
|
211
|
+
run: {
|
212
|
+
hooks: {
|
213
|
+
start: Hook.noop,
|
214
|
+
before: Hook.noop,
|
215
|
+
after: Hook.output,
|
216
|
+
finish: Hook.summary
|
217
|
+
}
|
218
|
+
}
|
219
|
+
)
|
220
|
+
|
221
|
+
@hooks = CONFIG.node.hooks
|
222
|
+
@children = []
|
223
|
+
|
224
|
+
def self.inherited(child)
|
225
|
+
@children << child
|
226
|
+
child.hooks = @hooks.dup
|
227
|
+
child.children = []
|
228
|
+
end
|
229
|
+
|
230
|
+
extend Enumerable
|
231
|
+
|
232
|
+
class << self
|
233
|
+
attr_accessor :hooks, :children
|
234
|
+
|
235
|
+
def reboot(suppress_warning = true)
|
236
|
+
(stderr, $stderr = $stderr, StringIO.new) if suppress_warning
|
237
|
+
Object.const_set :Lax, Class.new(Array)
|
238
|
+
Lax.const_set :SOURCE, SOURCE
|
239
|
+
Lax.class_eval SOURCE
|
240
|
+
($stderr = stderr) if suppress_warning
|
241
|
+
Lax
|
242
|
+
end
|
243
|
+
|
244
|
+
def config
|
245
|
+
block_given? ? yield(CONFIG) : CONFIG
|
246
|
+
end
|
247
|
+
|
248
|
+
def matcher(sym, &b)
|
249
|
+
Target.define_matcher(sym, &b)
|
250
|
+
end
|
251
|
+
|
252
|
+
def hook(sym, &b)
|
253
|
+
Hook.define(sym, &b)
|
254
|
+
end
|
255
|
+
|
256
|
+
def each(&b)
|
257
|
+
yield self
|
258
|
+
children.each {|c| c.each(&b)}
|
259
|
+
end
|
260
|
+
|
261
|
+
def let(h)
|
262
|
+
h.each do |key, value|
|
263
|
+
val = value.is_a?(Hook) ? value : ->{value}
|
264
|
+
define_singleton_method(key) do
|
265
|
+
Target.new(self, val, key, caller[0])
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def defer(&v)
|
271
|
+
Hook.new(&v)
|
272
|
+
end
|
273
|
+
alias _ defer
|
274
|
+
|
275
|
+
def fix(hash)
|
276
|
+
Fixture.new(hash)
|
277
|
+
end
|
278
|
+
|
279
|
+
def assert(*vals, &b)
|
280
|
+
Class.new(self).tap {|node| node.class_eval(&b)}
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def initialize
|
285
|
+
ks = methods - self.class.superclass.instance_methods
|
286
|
+
ks.map {|k| send k}.each {|k| self << k}
|
287
|
+
end
|
288
|
+
|
data/lib/lax.rb
CHANGED
@@ -1,36 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
autoload :Tree, 'lax/tree'
|
5
|
-
autoload :Hook, 'lax/hook'
|
6
|
-
autoload :Task, 'lax/task'
|
7
|
-
|
8
|
-
class << self
|
9
|
-
@@cases = []
|
10
|
-
def test(c={},&b)
|
11
|
-
preproc(b)[t=Tree.new(c)]
|
12
|
-
t.leaves.tap {|cs|@@cases+=cs}
|
13
|
-
end
|
14
|
-
|
15
|
-
def test!(opts={})
|
16
|
-
cases = opts[:cases] || @@cases
|
17
|
-
call opts[:start], cases
|
18
|
-
cases.each do |c|
|
19
|
-
call opts[:before], c
|
20
|
-
c.test
|
21
|
-
call opts[:after], c
|
22
|
-
end
|
23
|
-
call opts[:finish], cases
|
24
|
-
cases
|
25
|
-
end
|
26
|
-
|
27
|
-
def call(p, *as)
|
28
|
-
p[*as] if p
|
29
|
-
end
|
30
|
-
|
31
|
-
def preproc(p)
|
32
|
-
p.parameters.any?? p : ->(o) { o.instance_exec &p }
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
1
|
+
Object::Lax = Class.new(Array)
|
2
|
+
Lax::SOURCE = File.new(File.expand_path('../lax/source.rb', __FILE__)).read
|
3
|
+
Lax.class_eval Lax::SOURCE
|
36
4
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Lax do
|
4
|
+
|
5
|
+
let :simple_case do
|
6
|
+
Lax.assert do
|
7
|
+
let number: 19,
|
8
|
+
string: 'asdf',
|
9
|
+
symbol: :symbol
|
10
|
+
|
11
|
+
number.odd? == true
|
12
|
+
number == 19
|
13
|
+
string == 'asdf'
|
14
|
+
number == 20
|
15
|
+
string.upcase == 'ASDF'
|
16
|
+
symbol.to_s == 'symbol'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { simple_case.new }
|
21
|
+
it { should have(6).things }
|
22
|
+
specify { subject.select(&:pass?).should have(5).things }
|
23
|
+
specify { subject.reject(&:pass?).should have(1).things }
|
24
|
+
|
25
|
+
end
|
26
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Lax::Fixture::Hashable do
|
4
|
+
let(:hash) { { name: 'phyllis', fears: { mild: ['spiders'], severe: ['manatees'] } } }
|
5
|
+
let(:config) { Lax::Fixture::Hashable.new hash }
|
6
|
+
|
7
|
+
describe '::new' do
|
8
|
+
specify { ->{Lax::Fixture::Hashable.new}.should raise_error ArgumentError }
|
9
|
+
specify { [:name, :fears].each {|msg| config.should respond_to msg } }
|
10
|
+
specify { config.name.should == 'phyllis' }
|
11
|
+
specify { config.fears.should be_a_kind_of Lax::Fixture::Hashable }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#merge' do
|
15
|
+
subject { config.merge manners: 'impeccable' }
|
16
|
+
it { should be_a_kind_of Lax::Fixture::Hashable }
|
17
|
+
specify { subject.name.should == 'phyllis' }
|
18
|
+
specify { subject.manners.should == 'impeccable' }
|
19
|
+
specify { subject.fears.should be_a_kind_of Lax::Fixture::Hashable }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#to_hash' do
|
23
|
+
subject { config.to_hash }
|
24
|
+
it { should == hash }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Lax::Hook do
|
4
|
+
let(:one) { Lax::Hook.new {1} }
|
5
|
+
specify { one.should be_a_kind_of Proc }
|
6
|
+
|
7
|
+
describe '#<<' do
|
8
|
+
let(:doubler) { Lax::Hook.new {|n| 2*n} }
|
9
|
+
subject { doubler << one }
|
10
|
+
its(:call) { should == 2 }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#+' do
|
14
|
+
let(:thing) { Object.new }
|
15
|
+
let(:hash) { Lax::Hook.new { thing.hash } }
|
16
|
+
subject { hash + one }
|
17
|
+
its(:call) { should == 1 }
|
18
|
+
specify do
|
19
|
+
thing.should_receive :hash
|
20
|
+
subject.call
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '::_resolve' do
|
25
|
+
let(:resolve) { Lax::Hook.method :_resolve }
|
26
|
+
context 'given a hook' do
|
27
|
+
let(:hook) { Lax::Hook.new {:surprise!} }
|
28
|
+
subject { resolve[hook] }
|
29
|
+
it { should == hook }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'given a symbol' do
|
33
|
+
let(:a_hook) { :noop }
|
34
|
+
let(:random_sym) { :asdfqwer }
|
35
|
+
specify { resolve[a_hook].call.should == nil }
|
36
|
+
specify { -> {resolve[random_sym]}.should raise_error NameError }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Lax do
|
4
|
+
subject { Lax }
|
5
|
+
|
6
|
+
describe '::let' do
|
7
|
+
before do
|
8
|
+
Lax.let number: 1
|
9
|
+
Lax.number == 1
|
10
|
+
end
|
11
|
+
subject { Lax.instance_methods - Lax.superclass.instance_methods }
|
12
|
+
it { should have(1).thing }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#initialize' do
|
16
|
+
subject { Lax.reboot.new }
|
17
|
+
it { should be_empty }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Lax::Target do
|
4
|
+
let(:node) { Lax.assert { let num: 1 } }
|
5
|
+
|
6
|
+
describe 'establishing a target' do
|
7
|
+
subject { node.num }
|
8
|
+
specify { (Lax::Target === subject).should == true }
|
9
|
+
specify { subject.__val__.should == 1 }
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when specifying a condition' do
|
13
|
+
before { node.num == 1234 }
|
14
|
+
specify { node.new.should have(1).thing }
|
15
|
+
describe 'the entailed assertion' do
|
16
|
+
subject { node.new.first }
|
17
|
+
it { should be_an_instance_of Lax::Assertion }
|
18
|
+
its(:subject) { should be_an_instance_of Proc }
|
19
|
+
its(:name) { should == :num }
|
20
|
+
its(:matcher) { should == '==' }
|
21
|
+
its(:pass?) { should == false }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/test/control.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Lax.assert do
|
2
|
+
let number: 1,
|
3
|
+
string: 'asdf',
|
4
|
+
symbol: :a_sym,
|
5
|
+
regexp: _{/asd/}
|
6
|
+
|
7
|
+
assert do
|
8
|
+
number == 1
|
9
|
+
assert do
|
10
|
+
let number: 2
|
11
|
+
number == 2
|
12
|
+
|
13
|
+
string.upcase.downcase == 'asdf'
|
14
|
+
string =~ regexp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
Lax.assert do
|
19
|
+
let number: 1,
|
20
|
+
string: 'Hi There',
|
21
|
+
regexp: defer{ /the/ }
|
22
|
+
number + 1 == 2
|
23
|
+
string.downcase =~ regexp
|
24
|
+
assert do
|
25
|
+
let number: 2
|
26
|
+
number - 1 == 1
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lax
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,9 +9,25 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
13
|
-
dependencies:
|
14
|
-
|
12
|
+
date: 2012-12-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: A lightweight testing framework.
|
15
31
|
email: feivel@sdf.org
|
16
32
|
executables: []
|
17
33
|
extensions: []
|
@@ -19,19 +35,17 @@ extra_rdoc_files: []
|
|
19
35
|
files:
|
20
36
|
- lax.gemspec
|
21
37
|
- lib/lax.rb
|
22
|
-
- lib/lax/
|
23
|
-
- lib/lax/
|
24
|
-
- lib/lax/case.rb
|
25
|
-
- lib/lax/tree.rb
|
26
|
-
- lib/lax/hook.rb
|
38
|
+
- lib/lax/rake_task.rb
|
39
|
+
- lib/lax/source.rb
|
27
40
|
- README.md
|
28
41
|
- LICENSE
|
29
|
-
-
|
30
|
-
-
|
31
|
-
-
|
32
|
-
-
|
33
|
-
-
|
34
|
-
-
|
42
|
+
- test/control.rb
|
43
|
+
- spec/spec_helper.rb
|
44
|
+
- spec/acceptance/acceptance_spec.rb
|
45
|
+
- spec/unit/hook_spec.rb
|
46
|
+
- spec/unit/target_spec.rb
|
47
|
+
- spec/unit/lax_spec.rb
|
48
|
+
- spec/unit/fixture/hashable_spec.rb
|
35
49
|
homepage: http://github.com/gwentacle/lax
|
36
50
|
licenses:
|
37
51
|
- MIT/X11
|
@@ -58,9 +72,10 @@ signing_key:
|
|
58
72
|
specification_version: 3
|
59
73
|
summary: An insouciant smidgen of a testing framework.
|
60
74
|
test_files:
|
61
|
-
-
|
62
|
-
-
|
63
|
-
-
|
64
|
-
-
|
65
|
-
-
|
66
|
-
-
|
75
|
+
- test/control.rb
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
- spec/acceptance/acceptance_spec.rb
|
78
|
+
- spec/unit/hook_spec.rb
|
79
|
+
- spec/unit/target_spec.rb
|
80
|
+
- spec/unit/lax_spec.rb
|
81
|
+
- spec/unit/fixture/hashable_spec.rb
|
data/lib/lax/case.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
module Lax
|
2
|
-
class Case < Hash
|
3
|
-
def test
|
4
|
-
Lax.call self[:before], self
|
5
|
-
self[:pass] = begin
|
6
|
-
self[:cond][self[:value]=self[:obj].__send__(self[:msg],*self[:args],&self[:blk])]
|
7
|
-
rescue self[:xptn] => e
|
8
|
-
true
|
9
|
-
rescue => e
|
10
|
-
self[:xptn] = e
|
11
|
-
false
|
12
|
-
end
|
13
|
-
Lax.call self[:after], self
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
data/lib/lax/hook.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
module Lax
|
2
|
-
class Hook < Proc
|
3
|
-
def <<(cb); Hook.new {|e| self[cb[e]]} end
|
4
|
-
def +(cb); Hook.new {|e| self[e]; cb[e]} end
|
5
|
-
|
6
|
-
StartTime = Hook.new { @start = Time.now }
|
7
|
-
StopTime = Hook.new { @stop = Time.now }
|
8
|
-
PassFail = Hook.new {|tc| $stdout.write(tc[:pass] ? "\x1b[32m=\x1b[0m" : "\x1b[31m#\x1b[0m")}
|
9
|
-
|
10
|
-
Summary = Hook.new do |cases|
|
11
|
-
puts "\nFinished #{cases.size} tests" <<
|
12
|
-
" in #{(@stop - @start).round 10} seconds" <<
|
13
|
-
" with #{(cases.reject{|c|c[:pass]}).size} failures"
|
14
|
-
end
|
15
|
-
|
16
|
-
Failures = Hook.new do |cases|
|
17
|
-
cases.reject {|c|c[:pass]}.each do |f|
|
18
|
-
puts " #{Module===f[:obj] ? "#{f[:obj]}::" : "#{f[:obj].class}#"}#{f[:msg]}" <<
|
19
|
-
"#{?(+[*f[:args]]*', '+?) if f[:args]} " << (f.has_key?(:value) ? "#=> #{f[:value]}" : "raised unhandled #{f[:xptn].class}")
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
data/lib/lax/task.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'rake'
|
2
|
-
module Lax
|
3
|
-
class Task
|
4
|
-
include Rake::DSL
|
5
|
-
def initialize(opts = {})
|
6
|
-
dir = opts.delete(:dir) || :test
|
7
|
-
make_tasks dir, {
|
8
|
-
start: Hook::StartTime,
|
9
|
-
after: Hook::PassFail,
|
10
|
-
finish: Hook::StopTime + Hook::Summary + Hook::Failures
|
11
|
-
}.merge(opts)
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
def make_tasks(dir, opts)
|
16
|
-
namespace dir do
|
17
|
-
desc "[Lax] load all test files"
|
18
|
-
task load: make_groups(dir)
|
19
|
-
desc "[Lax] run all loaded tests"
|
20
|
-
task(:run) { Lax.test! opts }
|
21
|
-
end
|
22
|
-
desc "[Lax] load and run all tests"
|
23
|
-
task dir => ["#{dir}:load","#{dir}:run"]
|
24
|
-
end
|
25
|
-
|
26
|
-
def make_groups(dir)
|
27
|
-
FileList["#{dir}/**/*"].select {|f| File.directory? f}.map do |group|
|
28
|
-
name = group.sub(/^#{dir}\//,'').gsub(/\//,?:)
|
29
|
-
desc "[Lax] load files in #{group}"
|
30
|
-
task(name) { Dir["#{group}/*.rb"].each {|file| load file} }
|
31
|
-
[dir,name]*?:
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
data/lib/lax/tree.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
module Lax
|
2
|
-
class Tree < Array
|
3
|
-
attr_reader :tc
|
4
|
-
def initialize(tc={})
|
5
|
-
@tc = Case.new.merge tc
|
6
|
-
end
|
7
|
-
|
8
|
-
def on(obj,&b)
|
9
|
-
where({obj: obj},&b)
|
10
|
-
end
|
11
|
-
|
12
|
-
def calling(msg,&b)
|
13
|
-
where({msg: msg},&b)
|
14
|
-
end
|
15
|
-
|
16
|
-
def with(*args,&b)
|
17
|
-
where({args: args},&b)
|
18
|
-
end
|
19
|
-
|
20
|
-
def with_block(blk=nil,&b)
|
21
|
-
blk ? where({blk: blk},&b) : where(blk: b)
|
22
|
-
end
|
23
|
-
|
24
|
-
def satisfies(cond=nil,&b)
|
25
|
-
cond ? where({cond: cond},&b) : where(cond: Lax.preproc(b))
|
26
|
-
end
|
27
|
-
|
28
|
-
def before(bef=nil,&b)
|
29
|
-
bef ? where({before: bef},&b) : where(before: b)
|
30
|
-
end
|
31
|
-
|
32
|
-
def after(aft=nil,&b)
|
33
|
-
aft ? where({after: aft},&b) : where(after: b)
|
34
|
-
end
|
35
|
-
|
36
|
-
def raises(xptn=StandardError,&b)
|
37
|
-
where({xptn: xptn},&b)
|
38
|
-
end
|
39
|
-
|
40
|
-
def it
|
41
|
-
calling(:tap).with_block {}
|
42
|
-
end
|
43
|
-
|
44
|
-
def returns(v,&b)
|
45
|
-
satisfies ->(e){e==v}, &b
|
46
|
-
end
|
47
|
-
|
48
|
-
def where(h,&b)
|
49
|
-
t=Tree.new tc.merge h
|
50
|
-
Lax.preproc(b)[t] if b
|
51
|
-
push(t).last
|
52
|
-
end
|
53
|
-
|
54
|
-
def leaves
|
55
|
-
any?? map(&:leaves).flatten : [tc]
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
data/lib/lax/version.rb
DELETED
data/rakefile
DELETED
data/test/case/cases.rb
DELETED
data/test/case/control.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
Lax.test(obj: 1) {|that|
|
2
|
-
that.calling(:/).with(0).raises ZeroDivisionError
|
3
|
-
that.calling(:**) {|exponentiation|
|
4
|
-
exponentiation.with(1).satisfies {|n|n==1}
|
5
|
-
exponentiation.with(2).satisfies ->(n){n==1}
|
6
|
-
}
|
7
|
-
}
|
8
|
-
|
9
|
-
Lax.test {
|
10
|
-
calling(:/).on(1).with(0).raises ZeroDivisionError
|
11
|
-
returns(1) {
|
12
|
-
on(0).calling(:+).with 1
|
13
|
-
on(1) {
|
14
|
-
calling(:* ).with 1
|
15
|
-
calling(:**).with 2
|
16
|
-
calling(:+ ).with 0
|
17
|
-
}
|
18
|
-
}
|
19
|
-
}
|
20
|
-
|
21
|
-
Lax.test(msg: :object_id, cond: ->(v){Fixnum===v}) {
|
22
|
-
on 1
|
23
|
-
on 'asdf'
|
24
|
-
on String
|
25
|
-
on Lax
|
26
|
-
calling(:size).on([1,2,3])
|
27
|
-
}
|
28
|
-
|
29
|
-
Lax.test(obj: 222) {|that|
|
30
|
-
that.it.returns 222
|
31
|
-
}
|
32
|
-
|
data/test/unit/callbacks.rb
DELETED