#!/usr/bin/ruby # encoding: utf-8 require 'antlr3' require 'antlr3/tree/wizard' require 'test/unit' require 'spec' include ANTLR3 include ANTLR3::AST class TestPatternLexer < Test::Unit::TestCase # vvvvvvvv tests vvvvvvvvv def test_open lexer = Wizard::PatternLexer.new( '(' ) type = lexer.next_token assert_equal( type, :open ) assert_equal( lexer.text, '' ) assert_equal( lexer.error, false ) end def test_close lexer = Wizard::PatternLexer.new(')') type = lexer.next_token assert_equal(type, :close) assert_equal(lexer.text, '') assert_equal(lexer.error, false) end def test_percent lexer = Wizard::PatternLexer.new('%') type = lexer.next_token assert_equal(type, :percent) assert_equal(lexer.text, '') assert_equal(lexer.error, false) end def test_dot lexer = Wizard::PatternLexer.new('.') type = lexer.next_token assert_equal(type, :dot) assert_equal(lexer.text, '') assert_equal(lexer.error, false) end def test_eof lexer = Wizard::PatternLexer.new(" \n \r \t ") type = lexer.next_token assert_equal(type, EOF) assert_equal(lexer.text, '') assert_equal(lexer.error, false) end def test_id lexer = Wizard::PatternLexer.new('__whatever_1__') type = lexer.next_token assert_equal(:identifier, type) assert_equal('__whatever_1__', lexer.text) assert( !(lexer.error) ) end def test_arg lexer = Wizard::PatternLexer.new('[ \]bla\n]') type = lexer.next_token assert_equal(type, :argument) assert_equal(' ]bla\n', lexer.text) assert( !(lexer.error) ) end def test_error lexer = Wizard::PatternLexer.new("1") type = lexer.next_token assert_equal(type, EOF) assert_equal(lexer.text, '') assert_equal(lexer.error, true) end end class TestPatternParser < Test::Unit::TestCase Tokens = TokenScheme.build %w(A B C D E ID VAR) include Tokens def setup @adaptor = CommonTreeAdaptor.new( Tokens.token_class ) @pattern_adaptor = Wizard::PatternAdaptor.new( Tokens.token_class ) @wizard = Wizard.new( :adaptor => @adaptor, :token_scheme => Tokens ) end # vvvvvvvv tests vvvvvvvvv def test_single_node tree = Wizard::PatternParser.parse( 'ID', Tokens, @adaptor ) assert_instance_of(CommonTree, tree) assert_equal( ID, tree.type ) assert_equal( 'ID', tree.text ) end def test_single_node_with_arg tree = Wizard::PatternParser.parse( 'ID[foo]', Tokens, @adaptor ) assert_instance_of( CommonTree, tree ) assert_equal( ID, tree.type ) assert_equal( 'foo', tree.text ) end def test_single_level_tree tree = Wizard::PatternParser.parse( '(A B)', Tokens, @adaptor ) assert_instance_of( CommonTree, tree ) assert_equal(A, tree.type) assert_equal('A', tree.text) assert_equal(tree.child_count, 1) assert_equal(tree.child(0).type, B) assert_equal(tree.child(0).text, 'B') end def test_nil tree = Wizard::PatternParser.parse( 'nil', Tokens, @adaptor ) assert_instance_of(CommonTree, tree) assert_equal(0, tree.type) assert_nil tree.text end def test_wildcard tree = Wizard::PatternParser.parse( '(.)', Tokens, @adaptor ) assert_instance_of( Wizard::WildcardPattern, tree ) end def test_label tree = Wizard::PatternParser.parse( '(%a:A)', Tokens, @pattern_adaptor ) assert_instance_of(Wizard::Pattern, tree) assert_equal('a', tree.label) end def test_error_1 tree = Wizard::PatternParser.parse( ')', Tokens, @adaptor ) assert_nil tree end def test_error_2 tree = Wizard::PatternParser.parse( '()', Tokens, @adaptor ) assert_nil tree end def test_error_3 tree = Wizard::PatternParser.parse( '(A ])', Tokens, @adaptor ) assert_nil tree end end class TestTreeWizard < Test::Unit::TestCase Tokens = TokenScheme.build %w(A B C D E ID VAR) include Tokens def setup @adaptor = CommonTreeAdaptor.new( Tokens.token_class ) @wizard = Wizard.new( :adaptor => @adaptor, :token_scheme => Tokens ) end def create_wizard( tokens ) Wizard.new( :tokens => tokens ) end # vvvvvvvv tests vvvvvvvvv def test_init @wizard = Wizard.new( :tokens => %w(A B), :adaptor => @adaptor ) assert_equal( @wizard.adaptor, @adaptor ) assert_kind_of( ANTLR3::TokenScheme, @wizard.token_scheme ) end def test_single_node t = @wizard.create("ID") assert_equal(t.inspect, 'ID') end def test_single_node_with_arg t = @wizard.create("ID[foo]") assert_equal(t.inspect, 'foo') end def test_single_node_tree t = @wizard.create("(A)") assert_equal(t.inspect, 'A') end def test_single_level_tree t = @wizard.create("(A B C D)") assert_equal(t.inspect, '(A B C D)') end def test_list_tree t = @wizard.create("(nil A B C)") assert_equal(t.inspect, 'A B C') end def test_invalid_list_tree t = @wizard.create("A B C") assert_nil t end def test_double_level_tree t = @wizard.create("(A (B C) (B D) E)") assert_equal(t.inspect, "(A (B C) (B D) E)") end SIMPLIFY_MAP = lambda do |imap| Hash[ imap.map { |type, nodes| [type, nodes.map { |n| n.to_s }] } ] end def test_single_node_index tree = @wizard.create("ID") index_map = SIMPLIFY_MAP[@wizard.index(tree)] assert_equal(index_map, ID => %w(ID)) end def test_no_repeats_index tree = @wizard.create("(A B C D)") index_map = SIMPLIFY_MAP[@wizard.index(tree)] assert_equal(index_map, D => %w(D), B => %w(B), C => %w(C), A => %w(A) ) end def test_repeats_index tree = @wizard.create("(A B (A C B) B D D)") index_map = SIMPLIFY_MAP[@wizard.index(tree)] assert_equal(index_map, D => %w(D D), B => %w(B B B), C => %w(C), A => %w(A A) ) end def test_no_repeats_visit tree = @wizard.create("(A B C D)") elements = [] @wizard.visit( tree, B ) do |node, parent, child_index, labels| elements << node.to_s end assert_equal( %w(B), elements ) end def test_no_repeats_visit2 tree = @wizard.create("(A B (A C B) B D D)") elements = [] @wizard.visit( tree, C ) do |node, parent, child_index, labels| elements << node.to_s end assert_equal(%w(C), elements) end def test_repeats_visit tree = @wizard.create("(A B (A C B) B D D)") elements = [] @wizard.visit( tree, B ) do |node, parent, child_index, labels| elements << node.to_s end assert_equal(%w(B B B), elements) end def test_repeats_visit2 tree = @wizard.create("(A B (A C B) B D D)") elements = [] @wizard.visit( tree, A ) do |node, parent, child_index, labels| elements << node.to_s end assert_equal(%w(A A), elements) end def context(node, parent, index) '%s@%s[%d]' % [node.to_s, (parent || 'nil').to_s, index] end def test_repeats_visit_with_context tree = @wizard.create("(A B (A C B) B D D)") elements = [] @wizard.visit( tree, B ) do |node, parent, child_index, labels| elements << context(node, parent, child_index) end assert_equal(['B@A[0]', 'B@A[1]', 'B@A[2]'], elements) end def test_repeats_visit_with_null_parent_and_context tree = @wizard.create("(A B (A C B) B D D)") elements = [] @wizard.visit( tree, A ) do |node, parent, child_index, labels| elements << context(node, parent, child_index) end assert_equal(['A@nil[-1]', 'A@A[1]'], elements) end def test_visit_pattern tree = @wizard.create("(A B C (A B) D)") elements = [] @wizard.visit(tree, '(A B)') do |node, parent, child_index, labels| elements << node.to_s end assert_equal(%w(A), elements) end def test_visit_pattern_multiple tree = @wizard.create("(A B C (A B) (D (A B)))") elements = [] @wizard.visit(tree, '(A B)') do |node, parent, child_index, labels| elements << context(node, parent, child_index) end assert_equal( %w(A@A[2] A@D[0]) , elements ) end def labeled_context(node, parent, index, labels, *names) suffix = names.map { |n| labels[n].to_s }.join('&') '%s@%s[%d]%s' % [node.to_s, (parent || 'nil').to_s, index, suffix] end def test_visit_pattern_multiple_with_labels tree = @wizard.create("(A B C (A[foo] B[bar]) (D (A[big] B[dog])))") elements = [] @wizard.visit(tree, '(%a:A %b:B)') do |node, parent, child_index, labels| elements << labeled_context(node, parent, child_index, labels, 'a', 'b') end assert_equal( ['foo@A[2]foo&bar', 'big@D[0]big&dog'] , elements ) end def test_match tree = @wizard.create("(A B C)") assert @wizard.match(tree, "(A B C)") end def test_match_single_node tree = @wizard.create('A') assert @wizard.match(tree, 'A') end def test_match_single_node_fails tree = @wizard.create('A') assert( !(@wizard.match(tree, 'B')) ) end def test_match_flat_tree tree = @wizard.create('(nil A B C)') assert @wizard.match(tree, '(nil A B C)') end def test_match_flat_tree_fails tree = @wizard.create('(nil A B C)') assert( !(@wizard.match(tree, '(nil A B)')) ) end def test_match_flat_tree_fails2 tree = @wizard.create('(nil A B C)') assert( !(@wizard.match(tree, '(nil A B A)')) ) end def test_wildcard tree = @wizard.create('(A B C)') assert @wizard.match(tree, '(A . .)') end def test_match_with_text tree = @wizard.create('(A B[foo] C[bar])') assert @wizard.match(tree, '(A B[foo] C)') end def test_match_with_text_fails tree = @wizard.create('(A B C)') assert( !(@wizard.match(tree, '(A[foo] B C)')) ) end def test_match_labels tree = @wizard.create('(A B C)') labels = @wizard.match( tree, '(%a:A %b:B %c:C)' ) assert_equal('A', labels['a'].to_s) assert_equal('B', labels['b'].to_s) assert_equal('C', labels['c'].to_s) end def test_match_with_wildcard_labels tree = @wizard.create('(A B C)') labels = @wizard.match(tree, '(A %b:. %c:.)') assert_kind_of( Hash, labels ) assert_equal('B', labels['b'].to_s) assert_equal('C', labels['c'].to_s) end def test_match_labels_and_test_text tree = @wizard.create('(A B[foo] C)') labels = @wizard.match( tree, '(%a:A %b:B[foo] %c:C)' ) assert_kind_of( Hash, labels ) assert_equal('A', labels['a'].to_s) assert_equal('foo', labels['b'].to_s) assert_equal('C', labels['c'].to_s) end def test_match_labels_in_nested_tree tree = @wizard.create('(A (B C) (D E))') labels = @wizard.match( tree, '(%a:A (%b:B %c:C) (%d:D %e:E))' ) assert_kind_of( Hash, labels ) assert_equal('A', labels['a'].to_s) assert_equal('B', labels['b'].to_s) assert_equal('C', labels['c'].to_s) assert_equal('D', labels['d'].to_s) assert_equal('E', labels['e'].to_s) end def test_equals tree1 = @wizard.create("(A B C)") tree2 = @wizard.create("(A B C)") assert @wizard.equals(tree1, tree2) end def test_equals_with_text tree1 = @wizard.create("(A B[foo] C)") tree2 = @wizard.create("(A B[foo] C)") assert @wizard.equals(tree1, tree2) end def test_equals_with_mismatched_text tree1 = @wizard.create("(A B[foo] C)") tree2 = @wizard.create("(A B C)") assert( !(@wizard.equals(tree1, tree2)) ) end def test_equals_with_mismatched_list tree1 = @wizard.create("(A B C)") tree2 = @wizard.create("(A B A)") assert( !(@wizard.equals(tree1, tree2)) ) end def test_equals_with_mismatched_list_length tree1 = @wizard.create("(A B C)") tree2 = @wizard.create("(A B)") assert( !(@wizard.equals(tree1, tree2)) ) end def test_find_pattern tree = @wizard.create("(A B C (A[foo] B[bar]) (D (A[big] B[dog])))") subtrees = @wizard.find(tree, "(A B)").map { |t| t.to_s } assert_equal(%w(foo big), subtrees) end def test_find_token_type tree = @wizard.create("(A B C (A[foo] B[bar]) (D (A[big] B[dog])))") subtrees = @wizard.find( tree, A ).map { |t| t.to_s } assert_equal(%w(A foo big), subtrees) end end