sexp_processor 4.9.0 → 4.10.0b1
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/History.txt +45 -0
- data/Manifest.txt +1 -0
- data/README.txt +36 -7
- data/Rakefile +4 -0
- data/lib/composite_sexp_processor.rb +4 -4
- data/lib/pt_testcase.rb +21 -25
- data/lib/sexp.rb +1150 -107
- data/lib/sexp_processor.rb +127 -65
- data/lib/strict_sexp.rb +126 -0
- data/lib/unique.rb +7 -1
- data/test/test_composite_sexp_processor.rb +9 -12
- data/test/test_environment.rb +2 -2
- data/test/test_sexp.rb +1311 -113
- data/test/test_sexp_processor.rb +65 -52
- metadata +5 -4
- metadata.gz.sig +0 -0
data/lib/unique.rb
CHANGED
@@ -2,10 +2,16 @@
|
|
2
2
|
# Unique creates unique variable names.
|
3
3
|
|
4
4
|
class Unique
|
5
|
-
|
5
|
+
##
|
6
|
+
# Reset current count back to zero. Mainly used for testing.
|
7
|
+
|
8
|
+
def self.reset
|
6
9
|
@@curr = 0
|
7
10
|
end
|
8
11
|
|
12
|
+
##
|
13
|
+
# Get the next unique variable name.
|
14
|
+
|
9
15
|
def self.next
|
10
16
|
@@curr += 1
|
11
17
|
"temp_#{@@curr}".intern
|
@@ -1,7 +1,7 @@
|
|
1
1
|
$TESTING = true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "composite_sexp_processor"
|
4
|
+
require "minitest/autorun"
|
5
5
|
|
6
6
|
class FakeProcessor1 < SexpProcessor # ZenTest SKIP
|
7
7
|
|
@@ -9,16 +9,13 @@ class FakeProcessor1 < SexpProcessor # ZenTest SKIP
|
|
9
9
|
super
|
10
10
|
self.warn_on_default = false
|
11
11
|
self.default_method = :default_processor
|
12
|
+
self.require_empty = false
|
12
13
|
self.expected = Array
|
13
14
|
end
|
14
15
|
|
15
|
-
def default_processor
|
16
|
-
|
17
|
-
|
18
|
-
until exp.empty? do
|
19
|
-
result << exp.shift.to_s + " woot"
|
20
|
-
end
|
21
|
-
result
|
16
|
+
def default_processor exp
|
17
|
+
t, *rest = exp
|
18
|
+
s(t, *rest.map { |s| "#{s} woot" })
|
22
19
|
end
|
23
20
|
end
|
24
21
|
|
@@ -29,20 +26,20 @@ class TestCompositeSexpProcessor < Minitest::Test
|
|
29
26
|
end
|
30
27
|
|
31
28
|
def test_process_default
|
32
|
-
data =
|
29
|
+
data = s(1, 2, 3)
|
33
30
|
result = @p.process(data.dup)
|
34
31
|
assert_equal(data.dup, result)
|
35
32
|
end
|
36
33
|
|
37
34
|
def test_process_fake1
|
38
|
-
data =
|
35
|
+
data = s(:x, 1, 2, 3)
|
39
36
|
@p << FakeProcessor1.new
|
40
37
|
result = @p.process(data.dup)
|
41
38
|
assert_equal [:x, "1 woot", "2 woot", "3 woot"], result
|
42
39
|
end
|
43
40
|
|
44
41
|
def test_process_fake1_twice
|
45
|
-
data =
|
42
|
+
data = s(:x, 1, 2, 3)
|
46
43
|
@p << FakeProcessor1.new
|
47
44
|
@p << FakeProcessor1.new
|
48
45
|
result = @p.process(data.dup)
|
data/test/test_environment.rb
CHANGED
data/test/test_sexp.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
$TESTING = true
|
2
2
|
|
3
|
-
|
3
|
+
if ENV["COV"]
|
4
|
+
require "simplecov"
|
5
|
+
SimpleCov.start do
|
6
|
+
add_filter "lib/sexp_processor"
|
7
|
+
add_filter "test"
|
8
|
+
end
|
9
|
+
warn "Running simplecov"
|
10
|
+
end
|
11
|
+
|
12
|
+
require "minitest/autorun"
|
13
|
+
require "minitest/hell" # beat these up
|
4
14
|
require "minitest/benchmark" if ENV["BENCH"]
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require 'pp'
|
15
|
+
require "sexp_processor" # for deep_clone (TODO: why is that on SP and not S?)
|
16
|
+
require "sexp"
|
8
17
|
|
9
18
|
def pyramid_sexp max
|
10
19
|
# s(:array,
|
@@ -20,49 +29,119 @@ def pyramid_sexp max
|
|
20
29
|
end
|
21
30
|
|
22
31
|
class SexpTestCase < Minitest::Test
|
32
|
+
M = Sexp::Matcher
|
33
|
+
MC = Sexp::MatchCollection
|
34
|
+
MR = Sexp # ::MatchResult
|
35
|
+
|
36
|
+
CLASS_SEXP = s(:class, :cake, nil,
|
37
|
+
s(:defn, :foo, s(:args), s(:add, :a, :b)),
|
38
|
+
s(:defn, :bar, s(:args), s(:sub, :a, :b)))
|
39
|
+
|
40
|
+
def skip_if_strict n = 1
|
41
|
+
strict = ENV["STRICT_SEXP"].to_i
|
42
|
+
|
43
|
+
skip "Can't pass on STRICT_SEXP mode" if strict >= n
|
44
|
+
end
|
45
|
+
|
23
46
|
# KEY for regex tests
|
24
47
|
# :a == no change
|
25
48
|
# :b == will change (but sometimes ONLY once)
|
26
49
|
# :c == change to
|
27
50
|
|
28
|
-
|
51
|
+
def assert_equal3 x, y
|
52
|
+
skip_if_strict
|
29
53
|
|
30
|
-
|
31
|
-
result = x == y
|
32
|
-
refute_nil result, "#{x.inspect} does not === #{y.inspect}"
|
54
|
+
assert_operator x, :===, y
|
33
55
|
end
|
34
56
|
|
35
|
-
def
|
36
|
-
|
37
|
-
refute_nil result, "#{x.inspect} does not === #{y.inspect}"
|
57
|
+
def refute_equal3 x, y
|
58
|
+
refute_operator x, :===, y
|
38
59
|
end
|
39
60
|
|
40
|
-
def
|
41
|
-
|
61
|
+
def assert_pretty_print expect, input
|
62
|
+
assert_equal expect, input.pretty_inspect.chomp
|
42
63
|
end
|
43
|
-
end
|
44
64
|
|
45
|
-
|
65
|
+
def assert_inspect expect, input
|
66
|
+
assert_equal expect, input.inspect
|
67
|
+
end
|
46
68
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
69
|
+
def assert_search count, sexp, pattern
|
70
|
+
assert_equal count, sexp.search_each(pattern).count
|
71
|
+
end
|
72
|
+
|
73
|
+
def assert_satisfy pattern, sexp
|
74
|
+
assert_operator pattern, :satisfy?, sexp
|
75
|
+
end
|
76
|
+
|
77
|
+
def refute_satisfy pattern, sexp
|
78
|
+
refute_operator pattern, :satisfy?, sexp
|
79
|
+
end
|
80
|
+
end # class SexpTestCase
|
81
|
+
|
82
|
+
class MatcherTestCase < SexpTestCase
|
83
|
+
def self.abstract_test_case! klass = self # REFACTOR: push this up to minitest
|
84
|
+
extend Module.new {
|
85
|
+
define_method :run do |*args|
|
86
|
+
super(*args) unless self == klass
|
87
|
+
end
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
abstract_test_case!
|
92
|
+
|
93
|
+
def matcher
|
94
|
+
raise "Subclass responsibility"
|
95
|
+
end
|
96
|
+
|
97
|
+
def inspect_str
|
98
|
+
raise "Subclass responsibility"
|
99
|
+
end
|
100
|
+
|
101
|
+
def pretty_str
|
102
|
+
inspect_str
|
103
|
+
end
|
104
|
+
|
105
|
+
def sexp
|
106
|
+
s(:a)
|
107
|
+
end
|
108
|
+
|
109
|
+
def bad_sexp
|
110
|
+
s(:b)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_satisfy_eh
|
114
|
+
assert_equal3 matcher, sexp
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_satisfy_eh_fail
|
118
|
+
skip "not applicable" unless bad_sexp
|
119
|
+
refute_equal3 matcher, bad_sexp
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_greedy
|
123
|
+
refute_operator matcher, :greedy?
|
51
124
|
end
|
52
125
|
|
53
|
-
def
|
54
|
-
|
55
|
-
PP.pp(input, io)
|
56
|
-
io.rewind
|
57
|
-
assert_equal(expect, io.read.chomp)
|
126
|
+
def test_inspect
|
127
|
+
assert_inspect inspect_str, matcher
|
58
128
|
end
|
59
129
|
|
130
|
+
def test_pretty_print
|
131
|
+
assert_pretty_print pretty_str, matcher
|
132
|
+
end
|
133
|
+
end # class MatcherTestCase
|
134
|
+
|
135
|
+
class TestSexp < SexpTestCase # ZenTest FULL
|
60
136
|
def setup
|
61
137
|
super
|
62
138
|
@sexp_class = Object.const_get(self.class.name[4..-1])
|
63
|
-
@processor = SexpProcessor.new
|
64
139
|
@sexp = @sexp_class.new(1, 2, 3)
|
65
140
|
@basic_sexp = s(:lasgn, :var, s(:lit, 42).line(1)).line(1)
|
141
|
+
@basic_sexp.each_sexp do |s|
|
142
|
+
s.file = "file.rb"
|
143
|
+
end
|
144
|
+
|
66
145
|
@complex_sexp = s(:block,
|
67
146
|
s(:lasgn, :foo, s(:str, "foo").line(1)).line(1),
|
68
147
|
s(:if, s(:and, s(:true).line(2), s(:lit, 1).line(2)).line(2),
|
@@ -76,38 +155,50 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
76
155
|
@bad1 = s(:blah, 42)
|
77
156
|
end
|
78
157
|
|
158
|
+
def assert_from_array exp, input
|
159
|
+
assert_equal exp, Sexp.from_array(input)
|
160
|
+
end
|
161
|
+
|
79
162
|
def test_class_from_array
|
80
|
-
|
163
|
+
assert_from_array s(), []
|
164
|
+
assert_from_array s(:s), [:s]
|
165
|
+
assert_from_array s(:s, s(:m)), [:s, [:m]]
|
166
|
+
assert_from_array s(:s, s(:m)), [:s, s(:m)]
|
167
|
+
assert_from_array s(:s, s(:m, [:not_converted])), [:s, s(:m, [:not_converted])]
|
81
168
|
end
|
82
169
|
|
83
|
-
def
|
84
|
-
|
170
|
+
def test_compact
|
171
|
+
input = s(:a, nil, :b)
|
172
|
+
|
173
|
+
actual = input.compact
|
174
|
+
|
175
|
+
assert_equal s(:a, :b), actual
|
176
|
+
assert_same input, actual # returns mutated result
|
85
177
|
end
|
86
178
|
|
87
179
|
def test_array_type_eh
|
88
|
-
|
89
|
-
|
90
|
-
|
180
|
+
capture_io do # HACK
|
181
|
+
assert_equal false, s(:lit, 42).array_type?
|
182
|
+
assert_equal true, s(:array, 42).array_type?
|
183
|
+
end
|
91
184
|
end
|
92
185
|
|
93
186
|
def test_each_of_type
|
94
187
|
# TODO: huh... this tests fails if top level sexp :b is removed
|
95
188
|
@sexp = s(:b, s(:a, s(:b, s(:a), :a, s(:b, :a), s(:b, s(:a)))))
|
96
189
|
count = 0
|
97
|
-
@sexp.each_of_type
|
190
|
+
@sexp.each_of_type :a do
|
98
191
|
count += 1
|
99
192
|
end
|
100
193
|
assert_equal(3, count, "must find 3 a's in #{@sexp.inspect}")
|
101
194
|
end
|
102
195
|
|
103
196
|
def test_equals2_array
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
#
|
109
|
-
# assert_not_equal([1, 2, 3], @sexp,
|
110
|
-
# "Sexp must not be equal to equivalent array")
|
197
|
+
refute_equal @sexp, [1, 2, 3] # Sexp == Array
|
198
|
+
assert_raises Minitest::Assertion do # Array == Sexp.
|
199
|
+
refute_equal [1, 2, 3], @sexp # This is a bug in ruby:
|
200
|
+
end
|
201
|
+
# TODO: test if it is calling to_ary first? seems not to
|
111
202
|
end
|
112
203
|
|
113
204
|
def test_equals2_not_body
|
@@ -124,81 +215,107 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
124
215
|
end
|
125
216
|
end
|
126
217
|
|
127
|
-
def
|
128
|
-
|
129
|
-
|
130
|
-
|
218
|
+
def test_equal3_full_match
|
219
|
+
assert_equal3 s(), s() # 0
|
220
|
+
assert_equal3 s(:blah), s(:blah) # 1
|
221
|
+
assert_equal3 s(:a, :b), s(:a, :b) # 2
|
222
|
+
assert_equal3 @basic_sexp, @basic_sexp.dup # deeper structure
|
131
223
|
end
|
132
224
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
225
|
+
def test_equal3_mismatch
|
226
|
+
refute_equal3 s(), s(:a)
|
227
|
+
refute_equal3 s(:a), s()
|
228
|
+
refute_equal3 s(:blah1), s(:blah2)
|
229
|
+
refute_equal3 s(:a), s(:a, :b)
|
230
|
+
refute_equal3 s(:a, :b), s(:a)
|
231
|
+
refute_equal3 s(:a1, :b), s(:a2, :b)
|
232
|
+
refute_equal3 s(:a, :b1), s(:a, :b2)
|
138
233
|
end
|
139
234
|
|
140
|
-
def
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
assert_nil s(:a1, :b) === s(:a2, :b)
|
147
|
-
assert_nil s(:a, :b1) === s(:a, :b2)
|
148
|
-
assert_nil @basic_sexp === @basic_sexp.dup.push(42)
|
149
|
-
assert_nil @basic_sexp.dup.push(42) === @basic_sexp
|
235
|
+
def test_equal3_subset_match
|
236
|
+
assert_match s{s(:a)}, s(s(:a), s(:b)) # left - =~
|
237
|
+
assert_equal3 s{s(:a)}, s(s(:a), s(:b)) # left - ===
|
238
|
+
assert_equal3 s{s(:a)}, s(:blah, s(:a ), s(:b)) # mid 1
|
239
|
+
assert_equal3 s{s(:a, 1)}, s(:blah, s(:a, 1), s(:b)) # mid 2
|
240
|
+
assert_equal3 s{s(:a)}, s(:blah, s(:blah, s(:a))) # left deeper
|
150
241
|
end
|
151
242
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
util_equals3 s(:a, 1), s(:blah, s(:a, 1), s(:b)) # mid 2
|
156
|
-
util_equals3 @basic_sexp, s(:blah, @basic_sexp.dup, s(:b)) # mid deeper
|
157
|
-
util_equals3 @basic_sexp, s(@basic_sexp.dup, s(:a), s(:b)) # left deeper
|
158
|
-
|
159
|
-
util_equals3 s(:a), s(:blah, s(:blah, s(:a))) # left deeper
|
160
|
-
end
|
243
|
+
def test_equalstilde_fancy
|
244
|
+
assert_match s{ s(:b) }, s(:a, s(:b), :c)
|
245
|
+
assert_match s(:a, s(:b), :c), s{ s(:b) }
|
161
246
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
# end
|
247
|
+
e = assert_raises ArgumentError do
|
248
|
+
s(:b) =~ s(:a, s(:b), :c)
|
249
|
+
end
|
250
|
+
assert_equal "Not a pattern: s(:a, s(:b), :c)", e.message
|
167
251
|
|
168
|
-
|
169
|
-
|
170
|
-
|
252
|
+
e = assert_raises ArgumentError do
|
253
|
+
s(:a, s(:b), :c) =~ s(:b)
|
254
|
+
end
|
255
|
+
assert_equal "Not a pattern: s(:b)", e.message
|
171
256
|
end
|
172
257
|
|
173
258
|
def test_equalstilde_plain
|
174
|
-
|
175
|
-
|
259
|
+
s{ s(:re) } =~ s(:data) # pattern on LHS
|
260
|
+
s(:data) =~ s{ s(:re) } # pattern on RHS
|
261
|
+
|
262
|
+
e = assert_raises ArgumentError do
|
263
|
+
s(:re) =~ s(:data) # no pattern
|
264
|
+
end
|
265
|
+
|
266
|
+
assert_equal "Not a pattern: s(:data)", e.message
|
176
267
|
end
|
177
268
|
|
178
269
|
def test_find_and_replace_all
|
179
|
-
|
180
|
-
|
270
|
+
skip_if_strict 2
|
271
|
+
|
272
|
+
@sexp = s(:a, s(:a, :b, s(:a, :b), s(:a), :b, s(:a, s(:a))))
|
273
|
+
expected = s(:a, s(:a, :a, s(:a, :a), s(:a), :a, s(:a, s(:a))))
|
181
274
|
|
182
275
|
@sexp.find_and_replace_all(:b, :a)
|
183
276
|
|
184
277
|
assert_equal(expected, @sexp)
|
185
278
|
end
|
186
279
|
|
280
|
+
def assert_gsub exp, sexp, from, to
|
281
|
+
assert_equal exp, sexp.gsub(from, to)
|
282
|
+
end
|
283
|
+
|
187
284
|
def test_gsub
|
188
|
-
|
189
|
-
|
190
|
-
|
285
|
+
assert_gsub s(:c), s(:b), s(:b), s(:c)
|
286
|
+
assert_gsub s(:a), s(:a), s(:b), s(:c)
|
287
|
+
assert_gsub s(:a, s(:c)), s(:a, s(:b)), s(:b), s(:c)
|
191
288
|
end
|
192
289
|
|
193
290
|
def test_gsub_empty
|
194
|
-
|
291
|
+
assert_gsub s(:c), s(), s(), s(:c)
|
195
292
|
end
|
196
293
|
|
197
294
|
def test_gsub_multiple
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
295
|
+
assert_gsub s(:a, s(:c), s(:c)), s(:a, s(:b), s(:b)), s(:b), s(:c)
|
296
|
+
assert_gsub s(:a, s(:c), s(:a, s(:c))), s(:a, s(:b), s(:a, s(:b))), s(:b), s(:c)
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_gsub_matcher
|
300
|
+
assert_gsub s(:a, :b, :c), s(:a, s(:b, 42), :c), s{ s(:b, _) }, :b
|
301
|
+
assert_gsub s(:a, s(:b), :c), s(:a, s(:b), :c), s{ s(:b, _) }, :b
|
302
|
+
assert_gsub s(:a, s(:c, :b), :d), s(:a, s(:c, s(:b, 42)), :d), s{ s(:b, _) }, :b
|
303
|
+
assert_gsub s(:a, s(:q), :c), s(:a, s(:q), :c), s{ s(:b, _) }, :b
|
304
|
+
end
|
305
|
+
|
306
|
+
def with_env key
|
307
|
+
old_val, ENV[key] = ENV[key], "1"
|
308
|
+
yield
|
309
|
+
ensure
|
310
|
+
ENV[key] = old_val
|
311
|
+
end
|
312
|
+
|
313
|
+
def with_verbose &block
|
314
|
+
with_env "VERBOSE", &block
|
315
|
+
end
|
316
|
+
|
317
|
+
def with_debug &block
|
318
|
+
with_env "DEBUG", &block
|
202
319
|
end
|
203
320
|
|
204
321
|
def test_inspect
|
@@ -212,6 +329,17 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
212
329
|
k.new(:a, :b).inspect)
|
213
330
|
assert_equal("#{n}(:a, #{n}(:b))",
|
214
331
|
k.new(:a, k.new(:b)).inspect)
|
332
|
+
|
333
|
+
with_verbose do
|
334
|
+
assert_equal("#{n}().line(42)",
|
335
|
+
k.new().line(42).inspect)
|
336
|
+
assert_equal("#{n}(:a).line(42)",
|
337
|
+
k.new(:a).line(42).inspect)
|
338
|
+
assert_equal("#{n}(:a, :b).line(42)",
|
339
|
+
k.new(:a, :b).line(42).inspect)
|
340
|
+
assert_equal("#{n}(:a, #{n}(:b).line(43)).line(42)",
|
341
|
+
k.new(:a, k.new(:b).line(43)).line(42).inspect)
|
342
|
+
end
|
215
343
|
end
|
216
344
|
|
217
345
|
def test_line
|
@@ -226,6 +354,54 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
226
354
|
assert_equal 5, @complex_sexp.line_max
|
227
355
|
end
|
228
356
|
|
357
|
+
def test_new
|
358
|
+
file = "file.rb"
|
359
|
+
|
360
|
+
old = s(:lasgn, :var, s(:lit, 42).line(2)).line(1)
|
361
|
+
old.file = file
|
362
|
+
old.each_sexp do |x|
|
363
|
+
x.file = file
|
364
|
+
end
|
365
|
+
old.comments = "do the thing"
|
366
|
+
|
367
|
+
assert_same file, old.file
|
368
|
+
assert_equal 1, old.line
|
369
|
+
assert_same file, old.last.file
|
370
|
+
assert_equal 2, old.last.line
|
371
|
+
|
372
|
+
new = old.new(1, 2, 3)
|
373
|
+
|
374
|
+
assert_equal s(1, 2, 3), new
|
375
|
+
|
376
|
+
assert_same file, new.file
|
377
|
+
assert_equal 1, new.line
|
378
|
+
assert_same old.comments, new.comments
|
379
|
+
end
|
380
|
+
|
381
|
+
def test_map
|
382
|
+
file = "file.rb"
|
383
|
+
|
384
|
+
old = s(:lasgn, :var, s(:lit, 42).line(2)).line(1)
|
385
|
+
old.file = file
|
386
|
+
old.each_sexp do |x|
|
387
|
+
x.file = file
|
388
|
+
end
|
389
|
+
old.comments = "do the thing"
|
390
|
+
|
391
|
+
assert_same file, old.file
|
392
|
+
assert_equal 1, old.line
|
393
|
+
assert_same file, old.last.file
|
394
|
+
assert_equal 2, old.last.line
|
395
|
+
|
396
|
+
new = old.map { |x| x }
|
397
|
+
|
398
|
+
assert_same file, new.file
|
399
|
+
assert_equal 1, new.line
|
400
|
+
assert_same file, new.last.file
|
401
|
+
assert_equal 2, new.last.line
|
402
|
+
assert_same old.comments, new.comments
|
403
|
+
end
|
404
|
+
|
229
405
|
def test_mass
|
230
406
|
assert_equal 1, s(:a).mass
|
231
407
|
assert_equal 3, s(:a, s(:b), s(:c)).mass
|
@@ -259,11 +435,52 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
259
435
|
end
|
260
436
|
|
261
437
|
def test_method_missing
|
262
|
-
|
263
|
-
|
438
|
+
skip_if_strict 3
|
439
|
+
|
440
|
+
capture_io do
|
441
|
+
assert_nil @sexp.not_there
|
442
|
+
assert_equal s(:lit, 42), @basic_sexp.lit
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def test_method_missing_missing
|
447
|
+
skip_if_strict 3
|
448
|
+
skip "debugging for now" if ENV["DEBUG"]
|
449
|
+
|
450
|
+
assert_silent do
|
451
|
+
assert_nil @basic_sexp.missing
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
def test_method_missing_missing_debug
|
456
|
+
skip_if_strict 3
|
457
|
+
|
458
|
+
exp = /#{Regexp.escape @basic_sexp.to_s}.method_missing\(:missing\) => nil from/
|
459
|
+
|
460
|
+
with_debug do
|
461
|
+
assert_output "", exp do
|
462
|
+
assert_nil @basic_sexp.missing
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
def test_method_missing_hit_debug_verbose
|
468
|
+
skip_if_strict 3
|
469
|
+
|
470
|
+
with_debug do
|
471
|
+
with_verbose do
|
472
|
+
exp = /#{Regexp.escape @basic_sexp.to_s}.method_missing\(:lit\) from/
|
473
|
+
|
474
|
+
assert_output "", exp do
|
475
|
+
assert_equal s(:lit, 42), @basic_sexp.lit
|
476
|
+
end
|
477
|
+
end
|
478
|
+
end
|
264
479
|
end
|
265
480
|
|
266
481
|
def test_method_missing_ambigious
|
482
|
+
skip_if_strict 3
|
483
|
+
|
267
484
|
assert_raises NoMethodError do
|
268
485
|
pirate = s(:says, s(:arrr!), s(:arrr!), s(:arrr!))
|
269
486
|
pirate.arrr!
|
@@ -271,26 +488,34 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
271
488
|
end
|
272
489
|
|
273
490
|
def test_method_missing_deep
|
274
|
-
|
275
|
-
|
491
|
+
skip_if_strict 3
|
492
|
+
|
493
|
+
capture_io do
|
494
|
+
sexp = s(:blah, s(:a, s(:b, s(:c, :yay!))))
|
495
|
+
assert_equal(s(:c, :yay!), sexp.a.b.c)
|
496
|
+
end
|
276
497
|
end
|
277
498
|
|
278
499
|
def test_method_missing_delete
|
500
|
+
skip_if_strict 3
|
501
|
+
|
279
502
|
sexp = s(:blah, s(:a, s(:b, s(:c, :yay!))))
|
280
503
|
|
281
|
-
|
282
|
-
|
504
|
+
capture_io do
|
505
|
+
assert_equal(s(:c, :yay!), sexp.a.b.c(true))
|
506
|
+
assert_equal(s(:blah, s(:a, s(:b))), sexp)
|
507
|
+
end
|
283
508
|
end
|
284
509
|
|
285
510
|
def test_pretty_print
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
511
|
+
assert_pretty_print("s()",
|
512
|
+
s())
|
513
|
+
assert_pretty_print("s(:a)",
|
514
|
+
s(:a))
|
515
|
+
assert_pretty_print("s(:a, :b)",
|
516
|
+
s(:a, :b))
|
517
|
+
assert_pretty_print("s(:a, s(:b))",
|
518
|
+
s(:a, s(:b)))
|
294
519
|
end
|
295
520
|
|
296
521
|
def test_sexp_body
|
@@ -298,6 +523,8 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
298
523
|
end
|
299
524
|
|
300
525
|
def test_shift
|
526
|
+
skip_if_strict 5
|
527
|
+
|
301
528
|
skip "https://github.com/MagLev/maglev/issues/250" if maglev?
|
302
529
|
|
303
530
|
assert_equal(1, @sexp.shift)
|
@@ -327,6 +554,17 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
327
554
|
assert_equal(backup, @sexp)
|
328
555
|
end
|
329
556
|
|
557
|
+
def test_structure_deprecated
|
558
|
+
exp_err = "NOTE: form s(s(:subsexp)).structure is deprecated. Removing in 5.0\n"
|
559
|
+
|
560
|
+
assert_output "", exp_err do
|
561
|
+
sexp = s(s(:subsexp))
|
562
|
+
act = sexp.structure
|
563
|
+
|
564
|
+
assert_equal s(:bogus, s(:subsexp)), act
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
330
568
|
def test_sub
|
331
569
|
assert_equal s(:c), s(:b). sub(s(:b), s(:c))
|
332
570
|
assert_equal s(:a, s(:c), s(:b)), s(:a, s(:b), s(:b)). sub(s(:b), s(:c))
|
@@ -342,8 +580,39 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
342
580
|
assert_equal s(:c), s(). sub(s(), s(:c))
|
343
581
|
end
|
344
582
|
|
583
|
+
def assert_sub exp, sexp, from, to
|
584
|
+
assert_equal exp, sexp.sub(from, to)
|
585
|
+
end
|
586
|
+
|
587
|
+
def test_sub_matcher
|
588
|
+
assert_sub s(:c), s(:b), s{ s(:b) }, s(:c)
|
589
|
+
assert_sub s(:a, s(:c), s(:b)), s(:a, s(:b), s(:b)), s{ s(:b) }, s(:c)
|
590
|
+
assert_sub s(:a, s(:c), s(:a)), s(:a, s(:b), s(:a)), s{ s(:b) }, s(:c)
|
591
|
+
|
592
|
+
assert_sub s(:a, :b, :c), s(:a, s(:b, 42), :c), s{ s(:b, _) }, :b
|
593
|
+
assert_sub s(:a, s(:b), :c), s(:a, s(:b), :c), s{ s(:b, _) }, :b
|
594
|
+
assert_sub s(:a, s(:c, :b), :d), s(:a, s(:c, s(:b, 42)), :d), s{ s(:b, _) }, :b
|
595
|
+
assert_sub s(:a, s(:q), :c), s(:a, s(:q), :c), s{ s(:b, _) }, :b
|
596
|
+
end
|
597
|
+
|
345
598
|
def test_sub_structure
|
346
|
-
|
599
|
+
assert_sub s(:a, s(:c, s(:b))), s(:a, s(:b)), s(:b), s(:c, s(:b))
|
600
|
+
end
|
601
|
+
|
602
|
+
def test_sexp_type_eq
|
603
|
+
sexp = s(:bad_type, 42)
|
604
|
+
|
605
|
+
sexp.sexp_type = :good_type
|
606
|
+
|
607
|
+
assert_equal s(:good_type, 42), sexp
|
608
|
+
end
|
609
|
+
|
610
|
+
def test_sexp_body_eq
|
611
|
+
sexp = s(:type, 42)
|
612
|
+
|
613
|
+
sexp.sexp_body = [1, 2, 3]
|
614
|
+
|
615
|
+
assert_equal s(:type, 1, 2, 3), sexp
|
347
616
|
end
|
348
617
|
|
349
618
|
def test_to_a
|
@@ -374,7 +643,7 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
374
643
|
|
375
644
|
def test_deep_each
|
376
645
|
result = []
|
377
|
-
@complex_sexp.deep_each { |s| result << s if s.
|
646
|
+
@complex_sexp.deep_each { |s| result << s if s.sexp_type == :if }
|
378
647
|
assert_equal [:if, :if], result.map { |k, _| k }
|
379
648
|
end
|
380
649
|
|
@@ -382,28 +651,896 @@ class TestSexp < SexpTestCase # ZenTest FULL
|
|
382
651
|
assert_kind_of Enumerator, @complex_sexp.deep_each
|
383
652
|
assert_equal [:if, :if], @complex_sexp.deep_each.select { |s, _| s == :if }.map { |k, _| k }
|
384
653
|
end
|
654
|
+
|
655
|
+
def test_unary_not
|
656
|
+
skip "TODO?"
|
657
|
+
assert_equal M::Not.new(M.q(:a)), s{ !s(:a) }
|
658
|
+
end
|
659
|
+
|
660
|
+
def test_unary_not_outside
|
661
|
+
skip "TODO?"
|
662
|
+
assert_equal M::Not.new(s(:a)), !s(:a)
|
663
|
+
end
|
664
|
+
end # TestSexp
|
665
|
+
|
666
|
+
class TestSexpMatcher < SexpTestCase
|
667
|
+
def test_cls_s
|
668
|
+
assert_equal M.s(:x), s{ s(:x) }
|
669
|
+
end
|
670
|
+
|
671
|
+
def test_cls_underscore
|
672
|
+
assert_equal M::Wild.new, s{ _ }
|
673
|
+
end
|
674
|
+
|
675
|
+
def test_cls_underscore3
|
676
|
+
assert_equal M::Remaining.new, s{ ___ }
|
677
|
+
end
|
678
|
+
|
679
|
+
def test_cls_include
|
680
|
+
assert_equal M::Include.new(:a), s{ include(:a) }
|
681
|
+
end
|
682
|
+
|
683
|
+
def test_cls_atom
|
684
|
+
assert_equal M::Atom.new, s{ atom }
|
685
|
+
end
|
686
|
+
|
687
|
+
def test_cls_any
|
688
|
+
assert_equal M::Any.new(M.s(:a), M.s(:b)), s{ any(s(:a), s(:b)) }
|
689
|
+
end
|
690
|
+
|
691
|
+
def test_cls_all
|
692
|
+
assert_equal M::All.new(M.s(:a), M.s(:b)), s{ all(s(:a), s(:b)) }
|
693
|
+
end
|
694
|
+
|
695
|
+
def test_cls_not_eh
|
696
|
+
assert_equal M::Not.new(M.s(:a)), s{ not?(s(:a)) }
|
697
|
+
end
|
698
|
+
|
699
|
+
def test_cls_child
|
700
|
+
assert_equal M::Child.new(M.s(:a)), s{ child(s(:a)) }
|
701
|
+
end
|
702
|
+
|
703
|
+
def test_cls_t
|
704
|
+
assert_equal M::Type.new(:a), s{ t(:a) }
|
705
|
+
end
|
706
|
+
|
707
|
+
def test_cls_m
|
708
|
+
assert_equal M::Pattern.new(/a/), s{ m(/a/) }
|
709
|
+
assert_equal M::Pattern.new(/\Aa\Z/), s{ m(:a) }
|
710
|
+
assert_equal M::Pattern.new(/test_\w/), s{ m(/test_\w/) }
|
711
|
+
re = Regexp.union [/\w/, /\d/]
|
712
|
+
assert_equal M::Pattern.new(re), s{ m(/\w/,/\d/) }
|
713
|
+
end
|
714
|
+
|
715
|
+
def test_amp
|
716
|
+
m = s{ s(:a) & s(:b) }
|
717
|
+
e = M::All.new(M.s(:a), M.s(:b))
|
718
|
+
|
719
|
+
assert_equal e, m
|
720
|
+
end
|
721
|
+
|
722
|
+
def test_pipe
|
723
|
+
m = s{ s(:a) | s(:b) }
|
724
|
+
e = M::Any.new(M.s(:a), M.s(:b))
|
725
|
+
|
726
|
+
assert_equal e, m
|
727
|
+
end
|
728
|
+
|
729
|
+
def test_unary_minus
|
730
|
+
assert_equal M::Not.new(M.s(:a)), s{ -s(:a) }
|
731
|
+
end
|
732
|
+
|
733
|
+
def test_rchevron
|
734
|
+
assert_equal M::Sibling.new(M.s(:a), M.s(:b)), s{ s(:a) >> s(:b) }
|
735
|
+
end
|
736
|
+
|
737
|
+
def test_greedy_eh
|
738
|
+
refute_operator s{ s(:a) }, :greedy?
|
739
|
+
end
|
740
|
+
|
741
|
+
def test_inspect
|
742
|
+
assert_inspect "q(:a)", s{ s(:a) }
|
743
|
+
end
|
744
|
+
|
745
|
+
def test_pretty_print
|
746
|
+
assert_pretty_print "q(:a)", s{ s(:a) }
|
747
|
+
end
|
748
|
+
end # class TestSexpMatcher
|
749
|
+
|
750
|
+
class TestWild < MatcherTestCase
|
751
|
+
def matcher
|
752
|
+
s{ _ }
|
753
|
+
end
|
754
|
+
|
755
|
+
def bad_sexp
|
756
|
+
nil
|
757
|
+
end
|
758
|
+
|
759
|
+
def inspect_str
|
760
|
+
"_"
|
761
|
+
end
|
762
|
+
|
763
|
+
def test_wild_satisfy_eh # TODO: possibly remove
|
764
|
+
w = Sexp::Wild.new
|
765
|
+
|
766
|
+
assert_satisfy w, :a
|
767
|
+
assert_satisfy w, 1
|
768
|
+
assert_satisfy w, nil
|
769
|
+
assert_satisfy w, []
|
770
|
+
assert_satisfy w, s()
|
771
|
+
end
|
772
|
+
|
773
|
+
def test_wild_search # TODO: possibly remove
|
774
|
+
sexp = CLASS_SEXP.dup
|
775
|
+
|
776
|
+
assert_search 1, s(:add, :a, :b), s{ s(:add, _, :b) }
|
777
|
+
assert_search 1, sexp, s{ s(:defn, :bar, _, _) }
|
778
|
+
assert_search 2, sexp, s{ s(:defn, _, _, s(_, :a, :b) ) }
|
779
|
+
assert_search 1, s(:a, s()), s{ s(:a, _) }
|
780
|
+
assert_search 1, s(:a, :b, :c), s{ s(_, _, _) }
|
781
|
+
assert_search 7, sexp, s{ _ }
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
class TestRemaining < MatcherTestCase
|
786
|
+
def matcher
|
787
|
+
s{ ___ }
|
788
|
+
end
|
789
|
+
|
790
|
+
def bad_sexp
|
791
|
+
nil
|
792
|
+
end
|
793
|
+
|
794
|
+
def inspect_str
|
795
|
+
"___"
|
796
|
+
end
|
797
|
+
|
798
|
+
def test_remaining_satisfy_eh # TODO: possibly remove
|
799
|
+
assert_satisfy s{ ___ }, s(:a)
|
800
|
+
assert_satisfy s{ ___ }, s(:a, :b, :c)
|
801
|
+
assert_satisfy s{ s(:x, ___ ) }, s(:x, :y)
|
802
|
+
refute_satisfy s{ s(:y, ___ ) }, s(:x, :y)
|
803
|
+
end
|
804
|
+
|
805
|
+
def test_greedy
|
806
|
+
assert_operator matcher, :greedy?
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
class TestAny < MatcherTestCase
|
811
|
+
def matcher
|
812
|
+
s{ s(:a) | s(:c) }
|
813
|
+
end
|
814
|
+
|
815
|
+
def inspect_str
|
816
|
+
"q(:a) | q(:c)"
|
817
|
+
end
|
818
|
+
|
819
|
+
def pretty_str
|
820
|
+
"any(q(:a), q(:c))"
|
821
|
+
end
|
822
|
+
|
823
|
+
def test_any_search # TODO: possibly remove
|
824
|
+
assert_search 2, s(:foo, s(:a), s(:b)), s{ s(any(:a, :b)) }
|
825
|
+
assert_search 1, s(:foo, s(:a), s(:b)), s{ any( s(:a), s(:c)) }
|
826
|
+
end
|
827
|
+
|
828
|
+
def test_or_satisfy_eh # TODO: possibly remove
|
829
|
+
assert_satisfy s{ s(:a) | s(:b) }, s(:a)
|
830
|
+
refute_satisfy s{ s(:a) | s(:b) }, s(:c)
|
831
|
+
end
|
832
|
+
|
833
|
+
def test_or_search # TODO: possibly remove
|
834
|
+
sexp = CLASS_SEXP.dup
|
835
|
+
|
836
|
+
assert_search 2, s(:a, s(:b, :c), s(:b, :d)), s{ s(:b, :c) | s(:b, :d) }
|
837
|
+
assert_search 2, sexp, s{ s(:add, :a, :b) | s(:defn, :bar, _, _) }
|
838
|
+
end
|
839
|
+
end
|
840
|
+
|
841
|
+
class TestAll < MatcherTestCase
|
842
|
+
def matcher
|
843
|
+
s{ s(:a) & s(:a) }
|
844
|
+
end
|
845
|
+
|
846
|
+
def inspect_str
|
847
|
+
"q(:a) & q(:a)"
|
848
|
+
end
|
849
|
+
|
850
|
+
def pretty_str
|
851
|
+
"all(q(:a), q(:a))"
|
852
|
+
end
|
853
|
+
|
854
|
+
def test_and_satisfy_eh # TODO: possibly remove
|
855
|
+
refute_satisfy s{ s(:a) & s(:b) }, s(:a)
|
856
|
+
assert_satisfy s{ s(:a) & s(atom) }, s(:a)
|
857
|
+
end
|
858
|
+
end
|
859
|
+
|
860
|
+
class TestNot < MatcherTestCase
|
861
|
+
def matcher
|
862
|
+
s{ not? s(:b) } # TODO: test unary minus
|
863
|
+
end
|
864
|
+
|
865
|
+
def inspect_str
|
866
|
+
"not?(q(:b))" # TODO: change?
|
867
|
+
end
|
868
|
+
|
869
|
+
def pretty_str
|
870
|
+
"not?(q(:b))" # TODO: change?
|
871
|
+
end
|
872
|
+
|
873
|
+
def test_not_satisfy_eh # TODO: possibly remove
|
874
|
+
refute_satisfy s{ -_ }, s(:a)
|
875
|
+
assert_satisfy s{ -s(:b) }, s(:a)
|
876
|
+
assert_satisfy s{ not?(s(:b)) }, s(:a)
|
877
|
+
refute_satisfy s{ -s(atom) }, s(:a)
|
878
|
+
assert_satisfy s{ s(not?(:b)) }, s(:a)
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
882
|
+
class TestChild < MatcherTestCase
|
883
|
+
def matcher
|
884
|
+
s{ child(s(:a)) }
|
885
|
+
end
|
886
|
+
|
887
|
+
def sexp
|
888
|
+
s(:x, s(:a))
|
889
|
+
end
|
890
|
+
|
891
|
+
def bad_sexp
|
892
|
+
s(:x, s(:b))
|
893
|
+
end
|
894
|
+
|
895
|
+
def inspect_str
|
896
|
+
"child(q(:a))"
|
897
|
+
end
|
898
|
+
|
899
|
+
def test_child_search # TODO: possibly remove
|
900
|
+
sexp = CLASS_SEXP.dup
|
901
|
+
|
902
|
+
assert_search 1, sexp, s{ s(:class, :cake, _, _, child( s(:sub, :a, :b) ) ) }
|
903
|
+
assert_search 1, sexp, s{ s(:class, :cake, _, _, child(include(:a))) }
|
904
|
+
end
|
905
|
+
|
906
|
+
def test_satisfy_eh_by_child
|
907
|
+
assert_satisfy matcher, s(:a)
|
908
|
+
end
|
909
|
+
end
|
910
|
+
|
911
|
+
class TestAtom < MatcherTestCase
|
912
|
+
def matcher
|
913
|
+
s{ atom }
|
914
|
+
end
|
915
|
+
|
916
|
+
def sexp
|
917
|
+
42
|
918
|
+
end
|
919
|
+
|
920
|
+
def bad_sexp
|
921
|
+
s(:a)
|
922
|
+
end
|
923
|
+
|
924
|
+
def inspect_str
|
925
|
+
"atom"
|
926
|
+
end
|
927
|
+
|
928
|
+
def test_atom_satisfy_eh # TODO: possibly remove
|
929
|
+
a = s{ atom }
|
930
|
+
|
931
|
+
assert_satisfy a, :a
|
932
|
+
assert_satisfy a, 1
|
933
|
+
assert_satisfy a, nil
|
934
|
+
refute_satisfy a, s()
|
935
|
+
end
|
936
|
+
|
937
|
+
def test_atom_search # TODO: possibly remove
|
938
|
+
sexp = CLASS_SEXP.dup
|
939
|
+
|
940
|
+
assert_search 1, s(:add, :a, :b), s{ s(:add, atom, :b) }
|
941
|
+
assert_search 2, sexp, s{ s(:defn, atom, _, s(atom, :a, :b) ) }
|
942
|
+
assert_search 0, s(:a, s()), s{ s(:a, atom) }
|
943
|
+
end
|
944
|
+
end
|
945
|
+
|
946
|
+
class TestPattern < MatcherTestCase
|
947
|
+
def matcher
|
948
|
+
s{ s(:a, m(/a/)) }
|
949
|
+
end
|
950
|
+
|
951
|
+
def sexp
|
952
|
+
s(:a, :blah)
|
953
|
+
end
|
954
|
+
|
955
|
+
def inspect_str
|
956
|
+
"q(:a, m(/a/))"
|
957
|
+
end
|
958
|
+
|
959
|
+
def test_pattern_satisfy_eh # TODO: possibly remove
|
960
|
+
assert_satisfy s{ m(/a/) }, :a
|
961
|
+
assert_satisfy s{ m(/^test/) }, :test_case
|
962
|
+
assert_satisfy s{ m("test") }, :test
|
963
|
+
refute_satisfy s{ m("test") }, :test_case
|
964
|
+
refute_satisfy s{ m(/a/) }, s(:a)
|
965
|
+
end
|
966
|
+
|
967
|
+
def test_pattern_search # TODO: possibly remove
|
968
|
+
sexp = CLASS_SEXP.dup
|
969
|
+
|
970
|
+
assert_search 2, sexp, s{ s(m(/\w{3}/), :a, :b) }
|
971
|
+
|
972
|
+
assert_search 0, s(:a), s{ m(/\w/) }
|
973
|
+
assert_search 1, s(:a), s{ s(m(/\w/)) }
|
974
|
+
assert_search 0, s(:a), s{ m(/\w/,/\d/) }
|
975
|
+
assert_search 1, s(:a), s{ s(m(/\w/,/\d/)) }
|
976
|
+
|
977
|
+
assert_search 0, s(:tests, s(s(:test_a), s(:test_b))), s{ m(/test_\w/) }
|
978
|
+
assert_search 2, s(:tests, s(s(:test_a), s(:test_b))), s{ s(m(/test_\w/)) }
|
979
|
+
end
|
980
|
+
end
|
981
|
+
|
982
|
+
class TestType < MatcherTestCase
|
983
|
+
def matcher
|
984
|
+
s{ t(:a) }
|
985
|
+
end
|
986
|
+
|
987
|
+
def test_type_satisfy_eh # TODO: possibly remove
|
988
|
+
assert_satisfy s{ t(:a) }, s(:a)
|
989
|
+
assert_satisfy s{ t(:a) }, s(:a, :b, s(:oh_hai), :d)
|
990
|
+
end
|
991
|
+
|
992
|
+
def test_type_search
|
993
|
+
assert_search 2, CLASS_SEXP.dup, s{ t(:defn) }
|
994
|
+
end
|
995
|
+
|
996
|
+
def inspect_str
|
997
|
+
"t(:a)"
|
998
|
+
end
|
999
|
+
end
|
1000
|
+
|
1001
|
+
class TestInclude < MatcherTestCase
|
1002
|
+
def sexp
|
1003
|
+
s(:x, s(:a))
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
def matcher
|
1007
|
+
s{ include(s(:a)) }
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
def inspect_str
|
1011
|
+
"include(q(:a))"
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
def test_include_search # TODO: possibly remove
|
1015
|
+
sexp = CLASS_SEXP.dup
|
1016
|
+
|
1017
|
+
assert_search 1, s(:add, :a, :b), s{ include(:a) }
|
1018
|
+
assert_search 1, sexp, s{ include(:bar) }
|
1019
|
+
assert_search 2, sexp, s{ s(:defn, atom, _, include(:a)) }
|
1020
|
+
assert_search 2, sexp, s{ include(:a) }
|
1021
|
+
assert_search 0, s(:a, s(:b, s(:c))), s{ s(:a, include(:c)) }
|
1022
|
+
end
|
385
1023
|
end
|
386
1024
|
|
387
|
-
class
|
1025
|
+
class TestSibling < MatcherTestCase
|
1026
|
+
def sexp
|
1027
|
+
s(:x, s(:a), s(:x), s(:b))
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
def matcher
|
1031
|
+
s{ s(:a) >> s(:b) }
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
def inspect_str
|
1035
|
+
"q(:a) >> q(:b)"
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
def test_pretty_print_distance
|
1039
|
+
m = s{ M::Sibling.new(s(:a), s(:b), 3) } # maybe s(:a) << s(:b) << 3 ?
|
1040
|
+
assert_pretty_print "sibling(q(:a), q(:b), 3)", m
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
def test_sibling_satisfy_eh # TODO: possibly remove
|
1044
|
+
a_a = s{ s(:a) >> s(:a) }
|
1045
|
+
a_b = s{ s(:a) >> s(:b) }
|
1046
|
+
a_c = s{ s(:a) >> s(:c) }
|
1047
|
+
c_a = s{ s(:c) >> s(:a) }
|
1048
|
+
|
1049
|
+
assert_satisfy a_b, s(s(:a), s(:b))
|
1050
|
+
assert_satisfy a_b, s(s(:a), s(:b), s(:c))
|
1051
|
+
assert_satisfy a_c, s(s(:a), s(:b), s(:c))
|
1052
|
+
refute_satisfy c_a, s(s(:a), s(:b), s(:c))
|
1053
|
+
refute_satisfy a_a, s(s(:a))
|
1054
|
+
assert_satisfy a_a, s(s(:a), s(:b), s(:a))
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def test_sibling_search # TODO: possibly remove
|
1058
|
+
sexp = CLASS_SEXP.dup
|
1059
|
+
|
1060
|
+
assert_search 1, sexp, s{ t(:defn) >> t(:defn) }
|
1061
|
+
end
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
class TestMatchCollection < SexpTestCase
|
1065
|
+
attr_accessor :sexp, :pat, :act
|
388
1066
|
|
389
1067
|
def setup
|
390
|
-
|
1068
|
+
self.sexp = s(:a, :b, :c)
|
1069
|
+
self.pat = s{ _ }
|
1070
|
+
self.act = sexp / pat
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
def test_slash
|
1074
|
+
self.sexp =
|
1075
|
+
s(:class, :cake, nil,
|
1076
|
+
s(:defn, :foo, s(:args), s(:add, :a, :b)),
|
1077
|
+
s(:defn, :bar, s(:args), s(:sub, :a, :b)))
|
1078
|
+
|
1079
|
+
res = sexp / s{ s(:class, atom, _, ___) } # sexp / pat => MC
|
1080
|
+
act = res / s{ s(:defn, atom, ___) } # MC / pat => MC
|
1081
|
+
|
1082
|
+
_, _, _, defn1, defn2 = sexp
|
1083
|
+
|
1084
|
+
exp = MC.new
|
1085
|
+
exp << defn1.deep_clone
|
1086
|
+
exp << defn2.deep_clone
|
1087
|
+
|
1088
|
+
assert_equal exp, act
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
def test_sanity
|
1092
|
+
act = sexp / pat
|
1093
|
+
exp = MC.new << sexp
|
1094
|
+
|
1095
|
+
assert_equal exp, act
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
STR = "MatchCollection.new(s(:a, :b, :c))"
|
1099
|
+
|
1100
|
+
def test_to_s
|
1101
|
+
assert_equal STR, act.to_s
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
def test_inspect
|
1105
|
+
assert_inspect STR, act
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
def test_pretty_print
|
1109
|
+
assert_pretty_print STR, act
|
1110
|
+
end
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
class TestSexpSearch < SexpTestCase
|
1114
|
+
attr_accessor :sexp
|
1115
|
+
|
1116
|
+
make_my_diffs_pretty!
|
1117
|
+
|
1118
|
+
def setup
|
1119
|
+
self.sexp = CLASS_SEXP.dup
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
def coll *args
|
1123
|
+
exp = MC.new
|
1124
|
+
|
1125
|
+
args.each_slice 2 do |sexp, hash|
|
1126
|
+
exp << res(sexp, hash)
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
exp
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
def res sexp, hash
|
1133
|
+
MR.new sexp.deep_clone, hash
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
def test_slash_simple
|
1137
|
+
act = sexp / s{ s(:class, atom, _, ___) }
|
1138
|
+
|
1139
|
+
exp = MC.new
|
1140
|
+
exp << sexp.deep_clone
|
1141
|
+
|
1142
|
+
assert_equal exp, act
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
def test_slash_subsexp
|
1146
|
+
act = sexp / s{ s(:defn, atom, ___) }
|
1147
|
+
|
1148
|
+
exp = MC.new
|
1149
|
+
exp << s(:defn, :foo, s(:args), s(:add, :a, :b))
|
1150
|
+
exp << s(:defn, :bar, s(:args), s(:sub, :a, :b))
|
1151
|
+
|
1152
|
+
assert_equal exp, act
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
def test_slash_data
|
1156
|
+
pat = s{ s(:defn, m(/^test_.+/), ___ ) }
|
1157
|
+
|
1158
|
+
_, _, (_klass, _, _, _setup, t1, t2, t3) = TestUseCase.sexp.deep_clone
|
1159
|
+
exp = [t1, t2, t3]
|
1160
|
+
|
1161
|
+
assert_equal exp, TestUseCase.sexp.deep_clone / pat
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
def test_search_each_no_block
|
1165
|
+
assert_kind_of Enumerator, sexp.search_each(s{_})
|
1166
|
+
assert_equal 7, sexp.search_each(s{_}).count
|
1167
|
+
assert_equal 2, sexp.search_each(s{t(:defn)}).count
|
1168
|
+
assert_search 7, sexp, s{_}
|
1169
|
+
assert_search 2, sexp, s{t(:defn)}
|
1170
|
+
|
1171
|
+
_, _, _, defn1, defn2 = sexp
|
1172
|
+
|
1173
|
+
mc = []
|
1174
|
+
mc << defn1.deep_clone
|
1175
|
+
mc << defn2.deep_clone
|
1176
|
+
|
1177
|
+
assert_equal mc, sexp.search_each(s{t(:defn)}).map { |x| x }
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
def test_searching_simple_examples # TODO: possibly remove
|
1181
|
+
assert_raises ArgumentError do
|
1182
|
+
assert_search 0, sexp, :class # non-pattern should raise
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
assert_search 0, sexp, s{ s(:class) }
|
1186
|
+
assert_search 1, sexp, s{ s(:add, :a, :b) }
|
1187
|
+
assert_search 1, s(:a, s(:b, s(:c))), s{ s(:b, s(:c)) }
|
1188
|
+
assert_search 0, s(:a, s(:b, s(:c))), s{ s(:a, s(:c)) }
|
1189
|
+
assert_search 1, sexp, s{ s(:defn, :bar, _, s(:sub, :a, :b)) }
|
391
1190
|
end
|
392
1191
|
|
393
|
-
def
|
394
|
-
|
395
|
-
|
396
|
-
|
1192
|
+
def test_satisfy_eh_any_capture # TODO: remove
|
1193
|
+
sexp = s(:add, :a, :b)
|
1194
|
+
assert_satisfy s{ any(s(:add, :a, :b), s(:sub, :a, :b)) }, sexp
|
1195
|
+
|
1196
|
+
assert_satisfy s{ any(s(atom, :a, :b), s(:sub, :a, :b)) }, sexp
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
def test_satisfy_eh_all_capture # TODO: remove
|
1200
|
+
sexp = s(:add, :a, :b)
|
1201
|
+
assert_satisfy s{ all(s(_, :a, :b), s(atom, :a, :b)) }, sexp
|
1202
|
+
|
1203
|
+
assert_satisfy s{ all(s(_, :a, :b), s(atom, :a, :b)) }, sexp
|
1204
|
+
|
1205
|
+
assert_search 1, sexp, s{ all(s(_, :a, :b), s(atom, :a, :b)) }
|
1206
|
+
end
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
class TestSexpPath < Minitest::Test
|
1210
|
+
def test_global_s_block
|
1211
|
+
sexp = s(:a, :b, :c) # s called outside block
|
1212
|
+
|
1213
|
+
assert_instance_of Sexp, s{ sexp.deep_clone }
|
1214
|
+
assert_instance_of Sexp::Matcher, s{ s(:a, :b, :c) }
|
1215
|
+
assert_instance_of Sexp::Matcher, s{ s(:a, atom, :c) }
|
1216
|
+
end
|
1217
|
+
end
|
1218
|
+
|
1219
|
+
class TestSexpReplaceSexp < SexpTestCase
|
1220
|
+
def test_replace_sexp
|
1221
|
+
sexp = s(:a, s(:b), :c)
|
1222
|
+
actual = sexp.replace_sexp(s{ s(:b) }) { :b }
|
1223
|
+
|
1224
|
+
assert_equal s(:a, :b, :c), actual
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
def test_replace_sexp_root
|
1228
|
+
sexp = s(:a, s(:b), :c)
|
1229
|
+
actual = sexp.replace_sexp(s{ t(:a) }) { s(:new) }
|
1230
|
+
|
1231
|
+
assert_equal s(:new), actual
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
def test_replace_sexp_yields_match_result
|
1235
|
+
sexp = s(:a, s(:b), :c)
|
1236
|
+
|
1237
|
+
exp = sexp.deep_clone
|
1238
|
+
|
1239
|
+
sexp.replace_sexp(s{ t(:a) }) { |x|
|
1240
|
+
assert_equal exp, x
|
1241
|
+
}
|
397
1242
|
end
|
398
1243
|
|
399
|
-
def
|
400
|
-
|
401
|
-
|
402
|
-
|
1244
|
+
def test_replace_sexp_non_matcher
|
1245
|
+
e = assert_raises ArgumentError do
|
1246
|
+
s(:a, s(:b), :c).replace_sexp(42) { :b }
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
assert_equal "Needs a pattern", e.message
|
403
1250
|
end
|
404
1251
|
|
1252
|
+
def test_search_each_yields_match_result
|
1253
|
+
sexp = s(:a, s(:b), :c)
|
1254
|
+
|
1255
|
+
exp = sexp.deep_clone
|
1256
|
+
|
1257
|
+
sexp.search_each(s{ t(:a) }) { |x|
|
1258
|
+
assert_equal exp, x
|
1259
|
+
}
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
def test_search_each_no_pattern
|
1263
|
+
e = assert_raises ArgumentError do
|
1264
|
+
s(:a, s(:b), :c).search_each(42) { :b }
|
1265
|
+
end
|
1266
|
+
|
1267
|
+
assert_equal "Needs a pattern", e.message
|
1268
|
+
end
|
405
1269
|
end
|
406
1270
|
|
1271
|
+
# Here's a crazy idea, these tests actually use sexp_path on some "real"
|
1272
|
+
# code to see if it can satisfy my requirements.
|
1273
|
+
#
|
1274
|
+
# These tests are two fold:
|
1275
|
+
# 1. Make sure it works
|
1276
|
+
# 2. Make sure it's not painful to use
|
1277
|
+
|
1278
|
+
class TestUseCase < SexpTestCase
|
1279
|
+
@@sexp = eval File.read(__FILE__).split(/^__END__/).last
|
1280
|
+
|
1281
|
+
def self.sexp
|
1282
|
+
@@sexp
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
def setup
|
1286
|
+
@sexp = @@sexp.deep_clone
|
1287
|
+
end
|
1288
|
+
|
1289
|
+
def test_finding_methods
|
1290
|
+
methods = @sexp / s{ t(:defn) }
|
1291
|
+
assert_equal 5, methods.length
|
1292
|
+
end
|
1293
|
+
|
1294
|
+
def test_finding_classes_and_methods
|
1295
|
+
res = @sexp / s{ s(:class, atom, ___ ) }
|
1296
|
+
|
1297
|
+
_klass, name, * = res.first
|
1298
|
+
|
1299
|
+
assert_equal 1, res.length
|
1300
|
+
assert_equal :ExampleTest, name
|
1301
|
+
|
1302
|
+
methods = res / s{ t(:defn) }
|
1303
|
+
assert_equal 5, methods.length
|
1304
|
+
end
|
1305
|
+
|
1306
|
+
def test_finding_empty_test_methods
|
1307
|
+
empty_test = s{ s(:defn, m(/^test_.+/), s(:args), s(:nil)) }
|
1308
|
+
res = @sexp / empty_test
|
1309
|
+
|
1310
|
+
_, _, (_klass, _, _, _setup, _t1, t2, _t3) = TestUseCase.sexp.deep_clone
|
1311
|
+
|
1312
|
+
assert_equal [t2], res
|
1313
|
+
end
|
1314
|
+
|
1315
|
+
def test_search_each_finding_duplicate_test_names
|
1316
|
+
pat = s{ s(:defn, m(/^test_.+/), ___ ) }
|
1317
|
+
counts = Hash.new { |h, k| h[k] = 0 }
|
1318
|
+
|
1319
|
+
@sexp.search_each pat do |x|
|
1320
|
+
_, name, * = x
|
1321
|
+
counts[name] += 1
|
1322
|
+
end
|
1323
|
+
|
1324
|
+
assert_equal 1, counts[:test_b], "Should have seen test_b once"
|
1325
|
+
assert_equal 2, counts[:test_a], "Should have caught test_a being repeated"
|
1326
|
+
end
|
1327
|
+
|
1328
|
+
def test_finding_duplicate_test_names_via_res
|
1329
|
+
pat = s{ s(:defn, m(/^test_.+/), ___ ) }
|
1330
|
+
res = @sexp / pat
|
1331
|
+
counts = Hash.new { |h, k| h[k] = 0 }
|
1332
|
+
|
1333
|
+
_, _, (_klass, _, _, _setup, t1, t2, t3) = TestUseCase.sexp.deep_clone
|
1334
|
+
exp = [t1, t2, t3]
|
1335
|
+
|
1336
|
+
assert_equal exp, res
|
1337
|
+
|
1338
|
+
res.each do |m|
|
1339
|
+
_, name, * = m
|
1340
|
+
counts[name] += 1
|
1341
|
+
end
|
1342
|
+
|
1343
|
+
assert_equal 1, counts[:test_b], "Should have seen test_b once"
|
1344
|
+
assert_equal 2, counts[:test_a], "Should have caught test_a being repeated"
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
def test_rewriting_colon2s
|
1348
|
+
colon2 = s{ s(:colon2, s(:const, atom), atom) }
|
1349
|
+
expected = s{ s(:const, "Minitest::Test") }
|
1350
|
+
|
1351
|
+
new_sexp = @sexp.replace_sexp(colon2) { |r|
|
1352
|
+
(_, (_, a), b) = r
|
1353
|
+
s(:const, "%s::%s" % [a, b])
|
1354
|
+
}
|
1355
|
+
|
1356
|
+
assert_search 1, new_sexp, expected
|
1357
|
+
assert_search 0, @sexp, expected
|
1358
|
+
end
|
1359
|
+
end
|
1360
|
+
|
1361
|
+
##
|
1362
|
+
# NOTE: this entire class is now redundant, but it illustrates usage
|
1363
|
+
# and edge cases well.
|
1364
|
+
|
1365
|
+
class TestSexpMatchers < SexpTestCase
|
1366
|
+
CLASS_LIT = s(:class, :X, nil,
|
1367
|
+
s(:lasgn, :x, s(:lit, 42)),
|
1368
|
+
s(:cdecl, :Y,
|
1369
|
+
s(:hash, s(:lit, :a), s(:lit, 1), s(:lit, :b), s(:lit, 2))))
|
1370
|
+
|
1371
|
+
SEXP = s(:class, :X, nil, s(:defn, :x, s(:args)))
|
1372
|
+
|
1373
|
+
def test_match_subset
|
1374
|
+
assert_match s{ child(s(:a)) }, s(:blah, s(:blah, s(:a)))
|
1375
|
+
assert_match s{ child(s(:a)) }, s(:a)
|
1376
|
+
end
|
1377
|
+
|
1378
|
+
def test_match_simple
|
1379
|
+
assert_match s{ s(:lit, _) }, s(:lit, 42)
|
1380
|
+
end
|
1381
|
+
|
1382
|
+
def test_match_mismatch_type
|
1383
|
+
refute_match s{ s(:xxx, 42) }, s(:lit, 42)
|
1384
|
+
end
|
1385
|
+
|
1386
|
+
def test_match_mismatch_data
|
1387
|
+
refute_match s{ s(:lit, 24) }, s(:lit, 42)
|
1388
|
+
end
|
1389
|
+
|
1390
|
+
def test_match_mismatch_length_shorter
|
1391
|
+
refute_match s{ s(:a, :b) }, s(:a, :b, :c)
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
def test_match_mismatch_length_longer
|
1395
|
+
refute_match s{ s(:a, :b, :c) }, s(:a, :b)
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
def test_match_wild
|
1399
|
+
assert_match s{ s(:class, _, _, _) }, SEXP
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
def test_match_rest_same_length
|
1403
|
+
assert_match s{ s(:class, _, _, ___) }, SEXP
|
1404
|
+
end
|
1405
|
+
|
1406
|
+
def test_match_rest_diff_length
|
1407
|
+
skip_if_strict
|
1408
|
+
|
1409
|
+
assert_match s{ s(:class, ___) }, SEXP
|
1410
|
+
end
|
1411
|
+
|
1412
|
+
def test_match_reversed
|
1413
|
+
assert_match SEXP, s{ s(:class, _, _, ___) }
|
1414
|
+
end
|
1415
|
+
|
1416
|
+
def assert_match_case pat, data
|
1417
|
+
case data
|
1418
|
+
when pat then
|
1419
|
+
assert true
|
1420
|
+
else
|
1421
|
+
flunk "Expected %p to match %p" % [pat, data]
|
1422
|
+
end
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
def test_match_case
|
1426
|
+
assert_match_case s{ s(:class, _, _, ___) }, SEXP
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
# NOTE: eqt is =~ (equal-tilde)
|
1430
|
+
|
1431
|
+
# cmt = create_match_test
|
1432
|
+
def self.cmt e1, e2, e3, e4, lit, pat
|
1433
|
+
Class.new SexpTestCase do
|
1434
|
+
attr_accessor :lit, :pat
|
1435
|
+
|
1436
|
+
define_method :setup do
|
1437
|
+
self.lit = lit
|
1438
|
+
self.pat = pat
|
1439
|
+
end
|
1440
|
+
|
1441
|
+
define_method :test_match_lit_eqt_pat do
|
1442
|
+
skip_if_strict
|
1443
|
+
|
1444
|
+
if e1 then
|
1445
|
+
assert_match lit, pat
|
1446
|
+
else
|
1447
|
+
refute_match lit, pat
|
1448
|
+
end
|
1449
|
+
end
|
1450
|
+
|
1451
|
+
define_method :test_match_pat_eqt_lit do
|
1452
|
+
skip_if_strict
|
1453
|
+
|
1454
|
+
if e2 then
|
1455
|
+
assert_match pat, lit
|
1456
|
+
else
|
1457
|
+
refute_match pat, lit
|
1458
|
+
end
|
1459
|
+
end
|
1460
|
+
|
1461
|
+
define_method :test_match_lit_eq3_pat do
|
1462
|
+
if e3 then
|
1463
|
+
assert_equal3 lit, pat
|
1464
|
+
else
|
1465
|
+
refute_equal3 lit, pat
|
1466
|
+
end
|
1467
|
+
end
|
1468
|
+
|
1469
|
+
define_method :test_match_pat_eq3_lit do
|
1470
|
+
if e4 then
|
1471
|
+
assert_equal3 pat, lit
|
1472
|
+
else
|
1473
|
+
refute_equal3 pat, lit
|
1474
|
+
end
|
1475
|
+
end
|
1476
|
+
end
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
l_a = s(:a)
|
1480
|
+
l_abc = s(:a, s(:b, s(:c)))
|
1481
|
+
l_cls = s(:class, :X, nil,
|
1482
|
+
s(:something_in_between),
|
1483
|
+
s(:cdecl, :Y, s(:hash, s(:lit, :a), s(:lit, 1))))
|
1484
|
+
p_cls1 = s{ s(:class, ___) & include(s(:cdecl, _, s(:hash, ___))) }
|
1485
|
+
p_cls2 = s{ s(:class, _, _, s(:cdecl, _, s(:hash, ___))) }
|
1486
|
+
|
1487
|
+
x, o = true, false
|
1488
|
+
TestMatcherDirectMatch = cmt x, x, o, x, l_a, s{ s(:a) }
|
1489
|
+
TestMatcherSubtree = cmt x, x, o, x, l_abc, s{ s(:c) }
|
1490
|
+
TestMatcherSubtreeType = cmt x, x, o, x, l_abc, s{ t(:c) }
|
1491
|
+
TestMatcherDisparateSubtree = cmt x, x, o, x, l_cls, p_cls1
|
1492
|
+
TestMatcherDisparateSubtree2 = cmt o, o, o, o, l_cls, p_cls2 # TODO: make pass
|
1493
|
+
end
|
1494
|
+
|
1495
|
+
class TestSexpMatcherParser < Minitest::Test
|
1496
|
+
def assert_parse exp, str
|
1497
|
+
act = Sexp::Matcher.parse str
|
1498
|
+
|
1499
|
+
if exp.nil? then
|
1500
|
+
assert_nil act
|
1501
|
+
else
|
1502
|
+
assert_equal exp, act
|
1503
|
+
end
|
1504
|
+
end
|
1505
|
+
|
1506
|
+
def self.test_parse name, exp_lambda, str
|
1507
|
+
define_method "test_parse_#{name}" do
|
1508
|
+
exp = exp_lambda && exp_lambda.call
|
1509
|
+
assert_parse exp, str
|
1510
|
+
end
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
def self.test_bad_parse name, str
|
1514
|
+
define_method "test_parse_bad_#{name}" do
|
1515
|
+
assert_raises SyntaxError do
|
1516
|
+
assert_parse :whatever, str
|
1517
|
+
end
|
1518
|
+
end
|
1519
|
+
end
|
1520
|
+
|
1521
|
+
def self.delay &b
|
1522
|
+
lambda { s(&b) }
|
1523
|
+
end
|
1524
|
+
|
1525
|
+
test_parse "nothing", nil, ""
|
1526
|
+
test_parse "nil", delay{ nil }, "nil"
|
1527
|
+
test_parse "empty", delay{ s() }, "()"
|
1528
|
+
test_parse "simple", delay{ s(:a) }, "(a)"
|
1529
|
+
test_parse "number", delay{ s(:a, 42) }, "(a 42)"
|
1530
|
+
test_parse "string", delay{ s(:a, "s") }, "(a \"s\")"
|
1531
|
+
test_parse "compound", delay{ s(:b) }, "(a) (b)"
|
1532
|
+
test_parse "complex", delay{ s(:a, _, s(:b, :cde), ___) }, "(a _ (b cde) ___)"
|
1533
|
+
test_parse "type", delay{ s(:a, t(:b)) }, "(a [t b])"
|
1534
|
+
test_parse "match", delay{ s(:a, m(/b/)) }, "(a [m /b/])"
|
1535
|
+
test_parse "not_atom", delay{ s(:atom) }, "(atom)"
|
1536
|
+
test_parse "atom", delay{ atom }, "[atom]"
|
1537
|
+
|
1538
|
+
test_bad_parse "open_sexp", "(a"
|
1539
|
+
test_bad_parse "closed_sexp", "a)"
|
1540
|
+
test_bad_parse "open_cmd", "[a"
|
1541
|
+
test_bad_parse "closed_cmd", "a]"
|
1542
|
+
end # class TestSexpMatcherParser
|
1543
|
+
|
407
1544
|
class BenchSexp < Minitest::Benchmark
|
408
1545
|
def run
|
409
1546
|
GC.disable
|
@@ -430,3 +1567,64 @@ class BenchSexp < Minitest::Benchmark
|
|
430
1567
|
end
|
431
1568
|
end
|
432
1569
|
end if ENV["BENCH"]
|
1570
|
+
|
1571
|
+
# class ExampleTest < Minitest::Test
|
1572
|
+
# def setup
|
1573
|
+
# 1 + 2
|
1574
|
+
# end
|
1575
|
+
#
|
1576
|
+
# def test_a
|
1577
|
+
# assert_equal 1+2, 4
|
1578
|
+
# end
|
1579
|
+
#
|
1580
|
+
# def test_b
|
1581
|
+
# # assert 1+1
|
1582
|
+
# end
|
1583
|
+
#
|
1584
|
+
# def test_a
|
1585
|
+
# assert_equal 1+2, 3
|
1586
|
+
# end
|
1587
|
+
#
|
1588
|
+
# private
|
1589
|
+
#
|
1590
|
+
# def helper_method apples, oranges, cakes = nil
|
1591
|
+
# [apples, oranges, cakes].compact.map { |food| food.to_s.upcase }
|
1592
|
+
# end
|
1593
|
+
# end
|
1594
|
+
|
1595
|
+
__END__
|
1596
|
+
s(:block,
|
1597
|
+
s(:call, nil, :require, s(:str, "minitest/autorun")),
|
1598
|
+
s(:class,
|
1599
|
+
:ExampleTest,
|
1600
|
+
s(:colon2, s(:const, :Minitest), :Test),
|
1601
|
+
s(:defn, :setup, s(:args), s(:call, s(:lit, 1), :+, s(:lit, 2))),
|
1602
|
+
s(:defn,
|
1603
|
+
:test_a,
|
1604
|
+
s(:args),
|
1605
|
+
s(:call,
|
1606
|
+
nil,
|
1607
|
+
:assert_equal,
|
1608
|
+
s(:call, s(:lit, 1), :+, s(:lit, 2)),
|
1609
|
+
s(:lit, 4))),
|
1610
|
+
s(:defn, :test_b, s(:args), s(:nil)),
|
1611
|
+
s(:defn,
|
1612
|
+
:test_a,
|
1613
|
+
s(:args),
|
1614
|
+
s(:call,
|
1615
|
+
nil,
|
1616
|
+
:assert_equal,
|
1617
|
+
s(:call, s(:lit, 1), :+, s(:lit, 2)),
|
1618
|
+
s(:lit, 3))),
|
1619
|
+
s(:call, nil, :private),
|
1620
|
+
s(:defn,
|
1621
|
+
:helper_method,
|
1622
|
+
s(:args, :apples, :oranges, s(:lasgn, :cakes, s(:nil))),
|
1623
|
+
s(:iter,
|
1624
|
+
s(:call,
|
1625
|
+
s(:call,
|
1626
|
+
s(:array, s(:lvar, :apples), s(:lvar, :oranges), s(:lvar, :cakes)),
|
1627
|
+
:compact),
|
1628
|
+
:map),
|
1629
|
+
s(:args, :food),
|
1630
|
+
s(:call, s(:call, s(:lvar, :food), :to_s), :upcase)))))
|