1#!/usr/bin/ruby
2# encoding: utf-8
3
4require 'antlr3'
5require 'antlr3/tree/wizard'
6require 'test/unit'
7require 'spec'
8
9include ANTLR3
10include ANTLR3::AST
11
12class TestPatternLexer < Test::Unit::TestCase
13  
14  # vvvvvvvv tests vvvvvvvvv
15  
16  def test_open
17    lexer = Wizard::PatternLexer.new( '(' )
18    type = lexer.next_token
19    assert_equal( type, :open )
20    assert_equal( lexer.text, '' )
21    assert_equal( lexer.error, false )
22  end
23  
24  def test_close
25    lexer = Wizard::PatternLexer.new(')')
26    type = lexer.next_token
27    assert_equal(type, :close)
28    assert_equal(lexer.text, '')
29    assert_equal(lexer.error, false)
30  end
31  
32  def test_percent
33    lexer = Wizard::PatternLexer.new('%')
34    type = lexer.next_token
35    assert_equal(type, :percent)
36    assert_equal(lexer.text, '')
37    assert_equal(lexer.error, false)
38  end
39  
40  def test_dot
41    lexer = Wizard::PatternLexer.new('.')
42    type = lexer.next_token
43    assert_equal(type, :dot)
44    assert_equal(lexer.text, '')
45    assert_equal(lexer.error, false)
46  end
47  
48  def test_eof
49    lexer = Wizard::PatternLexer.new(" \n \r \t ")
50    type = lexer.next_token
51    assert_equal(type, EOF)
52    assert_equal(lexer.text, '')
53    assert_equal(lexer.error, false)
54  end
55  
56  def test_id
57    lexer = Wizard::PatternLexer.new('__whatever_1__')
58    type = lexer.next_token
59    assert_equal(:identifier, type)
60    assert_equal('__whatever_1__', lexer.text)
61    assert( !(lexer.error) )
62  end
63  
64  def test_arg
65    lexer = Wizard::PatternLexer.new('[ \]bla\n]')
66    type = lexer.next_token
67    assert_equal(type, :argument)
68    assert_equal(' ]bla\n', lexer.text)
69    assert( !(lexer.error) )
70  end
71  
72  def test_error
73    lexer = Wizard::PatternLexer.new("1")
74    type = lexer.next_token
75    assert_equal(type, EOF)
76    assert_equal(lexer.text, '')
77    assert_equal(lexer.error, true)
78  end
79  
80end
81
82
83class TestPatternParser < Test::Unit::TestCase
84  Tokens = TokenScheme.build %w(A B C D E ID VAR)
85  include Tokens
86  
87  def setup
88    @adaptor = CommonTreeAdaptor.new( Tokens.token_class )
89    @pattern_adaptor = Wizard::PatternAdaptor.new( Tokens.token_class )
90    @wizard = Wizard.new( :adaptor => @adaptor, :token_scheme => Tokens )
91  end
92  
93  # vvvvvvvv tests vvvvvvvvv
94  def test_single_node
95    tree = Wizard::PatternParser.parse( 'ID', Tokens, @adaptor )
96    
97    assert_instance_of(CommonTree, tree)
98    assert_equal( ID, tree.type )
99    assert_equal( 'ID', tree.text )
100  end
101  
102  def test_single_node_with_arg
103    tree = Wizard::PatternParser.parse( 'ID[foo]', Tokens, @adaptor )
104    
105    assert_instance_of( CommonTree, tree )
106    assert_equal( ID, tree.type )
107    assert_equal( 'foo', tree.text )
108  end
109  
110  def test_single_level_tree
111    tree = Wizard::PatternParser.parse( '(A B)', Tokens, @adaptor )
112    
113    assert_instance_of( CommonTree, tree )
114    assert_equal(A, tree.type)
115    assert_equal('A', tree.text)
116    assert_equal(tree.child_count, 1)
117    assert_equal(tree.child(0).type, B)
118    assert_equal(tree.child(0).text, 'B')
119  end
120  
121  def test_nil
122    tree = Wizard::PatternParser.parse( 'nil', Tokens, @adaptor )
123    
124    assert_instance_of(CommonTree, tree)
125    assert_equal(0, tree.type)
126    assert_nil tree.text
127  end
128  
129  def test_wildcard
130    tree = Wizard::PatternParser.parse( '(.)', Tokens, @adaptor )
131    assert_instance_of( Wizard::WildcardPattern, tree )
132  end
133  
134  def test_label
135    tree = Wizard::PatternParser.parse( '(%a:A)', Tokens, @pattern_adaptor )
136    assert_instance_of(Wizard::Pattern, tree)
137    assert_equal('a', tree.label)
138  end
139  
140  def test_error_1
141    tree = Wizard::PatternParser.parse( ')', Tokens, @adaptor )
142    assert_nil tree
143  end
144  
145  def test_error_2
146    tree = Wizard::PatternParser.parse( '()', Tokens, @adaptor )
147    assert_nil tree
148  end
149  
150  def test_error_3
151    tree = Wizard::PatternParser.parse( '(A ])', Tokens, @adaptor )
152    assert_nil tree
153  end
154  
155end
156
157
158class TestTreeWizard < Test::Unit::TestCase
159  Tokens = TokenScheme.build %w(A B C D E ID VAR)
160  include Tokens
161
162  def setup
163    @adaptor = CommonTreeAdaptor.new( Tokens.token_class )
164    @wizard = Wizard.new( :adaptor => @adaptor, :token_scheme => Tokens )
165  end
166  
167  def create_wizard( tokens )
168    Wizard.new( :tokens => tokens )
169  end
170  
171  # vvvvvvvv tests vvvvvvvvv
172  def test_init
173    @wizard = Wizard.new( :tokens => %w(A B), :adaptor => @adaptor )
174    
175    assert_equal( @wizard.adaptor, @adaptor )
176    assert_kind_of( ANTLR3::TokenScheme, @wizard.token_scheme )
177  end
178  
179  def test_single_node
180    t = @wizard.create("ID")
181    assert_equal(t.inspect, 'ID')
182  end
183  
184  def test_single_node_with_arg
185    t = @wizard.create("ID[foo]")
186    
187    assert_equal(t.inspect, 'foo')
188  end
189  
190  def test_single_node_tree
191    t = @wizard.create("(A)")
192    assert_equal(t.inspect, 'A')
193  end
194  
195  def test_single_level_tree
196    t = @wizard.create("(A B C D)")
197    assert_equal(t.inspect, '(A B C D)')
198  end
199  
200  def test_list_tree
201    t = @wizard.create("(nil A B C)")
202    assert_equal(t.inspect, 'A B C')
203  end
204  
205  def test_invalid_list_tree
206    t = @wizard.create("A B C")
207    assert_nil t
208  end
209  
210  def test_double_level_tree
211    t = @wizard.create("(A (B C) (B D) E)")
212    assert_equal(t.inspect, "(A (B C) (B D) E)")
213  end
214  
215  SIMPLIFY_MAP = lambda do |imap|
216    Hash[
217      imap.map { |type, nodes| [type, nodes.map { |n| n.to_s }] }
218    ]
219  end
220  
221  def test_single_node_index
222    tree = @wizard.create("ID")
223    index_map = SIMPLIFY_MAP[@wizard.index(tree)]
224    
225    assert_equal(index_map, ID => %w(ID))
226  end
227  
228  
229  def test_no_repeats_index
230    tree = @wizard.create("(A B C D)")
231    index_map = SIMPLIFY_MAP[@wizard.index(tree)]
232    
233    assert_equal(index_map,
234        D => %w(D), B => %w(B),
235        C => %w(C), A => %w(A)
236    )
237  end
238  
239  def test_repeats_index
240    tree = @wizard.create("(A B (A C B) B D D)")
241    index_map = SIMPLIFY_MAP[@wizard.index(tree)]
242    
243    assert_equal(index_map,
244        D => %w(D D), B => %w(B B B),
245        C => %w(C), A => %w(A A)
246    )
247  end
248  
249  
250  def test_no_repeats_visit
251    tree = @wizard.create("(A B C D)")
252    
253    elements = []
254    @wizard.visit( tree, B ) do |node, parent, child_index, labels|
255      elements << node.to_s
256    end
257    
258    assert_equal( %w(B), elements )
259  end
260  
261  
262  def test_no_repeats_visit2
263    tree = @wizard.create("(A B (A C B) B D D)")
264    
265    elements = []
266    @wizard.visit( tree, C ) do |node, parent, child_index, labels|
267      elements << node.to_s
268    end
269    
270    assert_equal(%w(C), elements)
271  end
272  
273  
274  def test_repeats_visit
275    tree = @wizard.create("(A B (A C B) B D D)")
276    
277    elements = []
278    @wizard.visit( tree, B ) do |node, parent, child_index, labels|
279      elements << node.to_s
280    end
281    
282    assert_equal(%w(B B B), elements)
283  end
284  
285  
286  def test_repeats_visit2
287    tree = @wizard.create("(A B (A C B) B D D)")
288    
289    elements = []
290    @wizard.visit( tree, A ) do |node, parent, child_index, labels|
291      elements << node.to_s
292    end
293    
294    assert_equal(%w(A A), elements)
295  end
296  
297  def context(node, parent, index)
298    '%s@%s[%d]' % [node.to_s, (parent || 'nil').to_s, index]
299  end
300  
301  def test_repeats_visit_with_context
302    tree = @wizard.create("(A B (A C B) B D D)")
303    
304    elements = []
305    @wizard.visit( tree, B ) do |node, parent, child_index, labels|
306      elements << context(node, parent, child_index)
307    end
308    
309    assert_equal(['B@A[0]', 'B@A[1]', 'B@A[2]'], elements)
310  end
311  
312  
313  def test_repeats_visit_with_null_parent_and_context
314    tree = @wizard.create("(A B (A C B) B D D)")
315    
316    elements = []
317    @wizard.visit( tree, A ) do |node, parent, child_index, labels|
318      elements << context(node, parent, child_index)
319    end
320    
321    assert_equal(['A@nil[-1]', 'A@A[1]'], elements)
322  end
323  
324  def test_visit_pattern
325    tree = @wizard.create("(A B C (A B) D)")
326    
327    elements = []
328    @wizard.visit(tree, '(A B)') do |node, parent, child_index, labels|
329      elements << node.to_s
330    end
331    
332    assert_equal(%w(A), elements)
333  end
334  
335  
336  def test_visit_pattern_multiple
337    tree = @wizard.create("(A B C (A B) (D (A B)))")
338    
339    elements = []
340    @wizard.visit(tree, '(A B)') do |node, parent, child_index, labels|
341      elements << context(node, parent, child_index)
342    end
343    
344    assert_equal( %w(A@A[2] A@D[0]) , elements )
345  end
346  
347  def labeled_context(node, parent, index, labels, *names)
348    suffix = names.map { |n| labels[n].to_s }.join('&')
349    '%s@%s[%d]%s' % [node.to_s, (parent || 'nil').to_s, index, suffix]
350  end
351    
352  def test_visit_pattern_multiple_with_labels
353    tree = @wizard.create("(A B C (A[foo] B[bar]) (D (A[big] B[dog])))")
354    
355    elements = []
356    @wizard.visit(tree, '(%a:A %b:B)') do |node, parent, child_index, labels|
357      elements << labeled_context(node, parent, child_index, labels, 'a', 'b')
358    end
359    
360    assert_equal( ['foo@A[2]foo&bar', 'big@D[0]big&dog'] , elements )
361  end
362  
363  
364  def test_match
365    tree = @wizard.create("(A B C)")
366    assert @wizard.match(tree, "(A B C)")
367  end
368  
369  def test_match_single_node
370    tree = @wizard.create('A')
371    assert @wizard.match(tree, 'A')
372  end
373  
374  def test_match_single_node_fails
375    tree = @wizard.create('A')
376    assert( !(@wizard.match(tree, 'B')) )
377  end
378  
379  
380  def test_match_flat_tree
381    tree = @wizard.create('(nil A B C)')
382    assert @wizard.match(tree, '(nil A B C)')
383  end
384  
385  def test_match_flat_tree_fails
386    tree = @wizard.create('(nil A B C)')
387    assert( !(@wizard.match(tree, '(nil A B)')) )
388  end
389
390  def test_match_flat_tree_fails2
391    tree = @wizard.create('(nil A B C)')
392    assert( !(@wizard.match(tree, '(nil A B A)')) )
393  end
394  
395  def test_wildcard
396    tree = @wizard.create('(A B C)')
397    assert @wizard.match(tree, '(A . .)')
398  end
399  
400  def test_match_with_text
401    tree = @wizard.create('(A B[foo] C[bar])')
402    assert @wizard.match(tree, '(A B[foo] C)')
403  end
404  
405  def test_match_with_text_fails
406    tree = @wizard.create('(A B C)')
407    assert( !(@wizard.match(tree, '(A[foo] B C)')) )
408  end
409  
410  def test_match_labels
411    tree = @wizard.create('(A B C)')
412    labels = @wizard.match( tree, '(%a:A %b:B %c:C)' )
413    
414    assert_equal('A', labels['a'].to_s)
415    assert_equal('B', labels['b'].to_s)
416    assert_equal('C', labels['c'].to_s)
417  end
418  
419  def test_match_with_wildcard_labels
420    tree = @wizard.create('(A B C)')
421    labels = @wizard.match(tree, '(A %b:. %c:.)')
422    assert_kind_of( Hash, labels )
423    assert_equal('B', labels['b'].to_s)
424    assert_equal('C', labels['c'].to_s)
425  end
426  
427  
428  def test_match_labels_and_test_text
429    tree = @wizard.create('(A B[foo] C)')
430    labels = @wizard.match( tree, '(%a:A %b:B[foo] %c:C)' )
431    assert_kind_of( Hash, labels )
432    assert_equal('A', labels['a'].to_s)
433    assert_equal('foo', labels['b'].to_s)
434    assert_equal('C', labels['c'].to_s)
435  end
436  
437  def test_match_labels_in_nested_tree
438    tree = @wizard.create('(A (B C) (D E))')
439    labels = @wizard.match( tree, '(%a:A (%b:B %c:C) (%d:D %e:E))' )
440    assert_kind_of( Hash, labels )
441    assert_equal('A', labels['a'].to_s)
442    assert_equal('B', labels['b'].to_s)
443    assert_equal('C', labels['c'].to_s)
444    assert_equal('D', labels['d'].to_s)
445    assert_equal('E', labels['e'].to_s)
446  end
447  
448  
449  def test_equals
450    tree1 = @wizard.create("(A B C)")
451    tree2 = @wizard.create("(A B C)")
452    assert @wizard.equals(tree1, tree2)
453  end
454  
455  
456  def test_equals_with_text
457    tree1 = @wizard.create("(A B[foo] C)")
458    tree2 = @wizard.create("(A B[foo] C)")
459    assert @wizard.equals(tree1, tree2)
460  end
461  
462  
463  def test_equals_with_mismatched_text
464    tree1 = @wizard.create("(A B[foo] C)")
465    tree2 = @wizard.create("(A B C)")
466    assert( !(@wizard.equals(tree1, tree2)) )
467  end
468  
469  
470  def test_equals_with_mismatched_list
471    tree1 = @wizard.create("(A B C)")
472    tree2 = @wizard.create("(A B A)")
473    assert( !(@wizard.equals(tree1, tree2)) )
474  end
475  
476  def test_equals_with_mismatched_list_length
477    tree1 = @wizard.create("(A B C)")
478    tree2 = @wizard.create("(A B)")
479    assert( !(@wizard.equals(tree1, tree2)) )
480  end
481  
482  def test_find_pattern
483    tree = @wizard.create("(A B C (A[foo] B[bar]) (D (A[big] B[dog])))")
484    subtrees = @wizard.find(tree, "(A B)").map { |t| t.to_s }
485    assert_equal(%w(foo big), subtrees)
486  end
487  
488  def test_find_token_type
489    tree = @wizard.create("(A B C (A[foo] B[bar]) (D (A[big] B[dog])))")
490    subtrees = @wizard.find( tree, A ).map { |t| t.to_s }
491    assert_equal(%w(A foo big), subtrees)
492  end
493end
494
495