sexp_processor 4.9.0 → 4.10.0b1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/unique.rb CHANGED
@@ -2,10 +2,16 @@
2
2
  # Unique creates unique variable names.
3
3
 
4
4
  class Unique
5
- def self.reset # mostly for testing
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 'composite_sexp_processor'
4
- require 'minitest/autorun'
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(exp)
16
- result = []
17
- result << exp.shift
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 = [1, 2, 3]
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 = [:x, 1, 2, 3]
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 = [:x, 1, 2, 3]
42
+ data = s(:x, 1, 2, 3)
46
43
  @p << FakeProcessor1.new
47
44
  @p << FakeProcessor1.new
48
45
  result = @p.process(data.dup)
@@ -1,7 +1,7 @@
1
1
  $TESTING = true
2
2
 
3
- require 'minitest/autorun'
4
- require 'sexp_processor'
3
+ require "minitest/autorun"
4
+ require "sexp_processor"
5
5
 
6
6
  class TestEnvironment < Minitest::Test
7
7
 
data/test/test_sexp.rb CHANGED
@@ -1,10 +1,19 @@
1
1
  $TESTING = true
2
2
 
3
- require 'minitest/autorun'
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 'sexp_processor'
6
- require 'stringio'
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
- include SexpMatchSpecials
51
+ def assert_equal3 x, y
52
+ skip_if_strict
29
53
 
30
- def util_equals(x, y)
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 util_equals3(x, y)
36
- result = x === y
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 setup
41
- @any = ANY()
61
+ def assert_pretty_print expect, input
62
+ assert_equal expect, input.pretty_inspect.chomp
42
63
  end
43
- end
44
64
 
45
- class TestSexp < SexpTestCase # ZenTest FULL
65
+ def assert_inspect expect, input
66
+ assert_equal expect, input.inspect
67
+ end
46
68
 
47
- class SexpFor
48
- def method
49
- 1
50
- end
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 util_pretty_print(expect, input)
54
- io = StringIO.new
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
- skip 'Need to write test_class_from_array'
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 test_class_index
84
- skip 'Need to write test_class_index'
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
- assert_equal false, @sexp.array_type?
89
- @sexp.unshift :array
90
- assert_equal true, @sexp.array_type?
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(:a) do |exp|
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
- # can't use assert_equals because it uses array as receiver
105
- refute_equal(@sexp, [1, 2, 3],
106
- "Sexp must not be equal to equivalent array")
107
- # both directions just in case
108
- # HACK - this seems to be a bug in ruby as far as I'm concerned
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 test_equals3_any
128
- util_equals3 @any, s()
129
- util_equals3 @any, s(:a)
130
- util_equals3 @any, s(:a, :b, s(:c))
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 test_equals3_full_match
134
- util_equals3 s(), s() # 0
135
- util_equals3 s(:blah), s(:blah) # 1
136
- util_equals3 s(:a, :b), s(:a, :b) # 2
137
- util_equals3 @basic_sexp, @basic_sexp.dup # deeper structure
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 test_equals3_mismatch
141
- assert_nil s() === s(:a)
142
- assert_nil s(:a) === s()
143
- assert_nil s(:blah1) === s(:blah2)
144
- assert_nil s(:a) === s(:a, :b)
145
- assert_nil s(:a, :b) === s(:a)
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 test_equals3_subset_match
153
- util_equals3 s(:a), s(s(:a), s(:b)) # left
154
- util_equals3 s(:a), s(:blah, s(:a ), s(:b)) # mid 1
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
- # def test_equalstilde_any
163
- # result = @basic_sexp =~ s(:lit, ANY())
164
- # p result
165
- # assert result
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
- def test_equalstilde_fancy
169
- assert_nil s(:b) =~ s(:a, s(:b), :c)
170
- refute_nil s(:a, s(:b), :c) =~ s(:b)
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
- result = @basic_sexp =~ @re
175
- assert result
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
- @sexp = s(:a, s(:b, s(:a), s(:b), s(:b, s(:a))))
180
- expected = s(:a, s(:a, s(:a), s(:a), s(:a, s(:a))))
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
- assert_equal s(:c), s(:b). gsub(s(:b), s(:c))
189
- assert_equal s(:a), s(:a). gsub(s(:b), s(:c))
190
- assert_equal s(:a, s(:c)), s(:a, s(:b)).gsub(s(:b), s(:c))
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
- assert_equal s(:c), s().gsub(s(), s(:c))
291
+ assert_gsub s(:c), s(), s(), s(:c)
195
292
  end
196
293
 
197
294
  def test_gsub_multiple
198
- assert_equal(s(:a, s(:c), s(:c)),
199
- s(:a, s(:b), s(:b)). gsub(s(:b), s(:c)))
200
- assert_equal(s(:a, s(:c), s(:a, s(:c))),
201
- s(:a, s(:b), s(:a, s(:b))). gsub(s(:b), s(:c)))
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
- assert_nil @sexp.not_there
263
- assert_equal s(:lit, 42), @basic_sexp.lit
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
- sexp = s(:blah, s(:a, s(:b, s(:c, :yay!))))
275
- assert_equal(s(:c, :yay!), sexp.a.b.c)
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
- assert_equal(s(:c, :yay!), sexp.a.b.c(true))
282
- assert_equal(s(:blah, s(:a, s(:b))), sexp)
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
- util_pretty_print("s()",
287
- s())
288
- util_pretty_print("s(:a)",
289
- s(:a))
290
- util_pretty_print("s(:a, :b)",
291
- s(:a, :b))
292
- util_pretty_print("s(:a, s(:b))",
293
- s(:a, s(:b)))
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
- assert_equal(s(:a, s(:c, s(:b))), s(:a, s(:b)). sub(s(:b), s(:c, s(:b))))
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.first == :if }
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 TestSexpAny < SexpTestCase
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
- super
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 test_equals
394
- util_equals @any, s()
395
- util_equals @any, s(:a)
396
- util_equals @any, s(:a, :b, s(:c))
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 test_equals3
400
- util_equals3 @any, s()
401
- util_equals3 @any, s(:a)
402
- util_equals3 @any, s(:a, :b, s(:c))
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)))))