test_testing.py 5.19 KB
Newer Older
1
2
#!/usr/bin/python3

3
"""test_testing.py - tests of the testing-module of DHParser
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

Author: Eckhart Arnold <arnold@badw.de>

Copyright 2017 Bavarian Academy of Sciences and Humanities

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

Eckhart Arnold's avatar
Eckhart Arnold committed
22
23
import os
import re
24
import sys
25
from functools import partial
26
27
28

sys.path.extend(['../', './'])

29
from DHParser.syntaxtree import mock_syntax_tree, flatten_sxpr, TOKEN_PTYPE
30
from DHParser.transform import traverse, remove_expendables, \
31
    replace_by_single_child, content_from_sinlge_child, flatten
32
from DHParser.dsl import grammar_provider
33
from DHParser.testing import grammar_unit
34
35
36
37
38
39
40
41
42
43
44
45
46
47

ARITHMETIC_EBNF = """
    @ whitespace = linefeed
    formula = [ //~ ] expr
    expr = expr ("+"|"-") term | term
    term = term ("*"|"/") factor | factor
    factor = /[0-9]+/~
    # example:  "5 + 3 * 4"
    """


ARITHMETIC_EBNF_transformation_table = {
    # AST Transformations for the DSL-grammar
    "formula": [remove_expendables],
48
49
50
51
    "term, expr": [replace_by_single_child, flatten],
    "factor": [remove_expendables, content_from_sinlge_child],
    (TOKEN_PTYPE): [remove_expendables, content_from_sinlge_child],
    "*": [remove_expendables, replace_by_single_child]
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
}


ARITHMETIC_EBNFTransform = partial(traverse, processing_table=ARITHMETIC_EBNF_transformation_table)


class TestGrammarTest:
    cases = {
        "factor": {
            "match": {
                1: "0",
                2: "314",
            },
            "fail": {
                3: "21F",
                4: "G123"
            }
        },
        "term": {
            "match": {
                1: "4 * 5",
                2: "20 / 4",
                3: "20 / 4 * 3"
            },
            "ast": {
                1: "(term (factor 4) (:Token *) (factor 5))",
                2: "(term (factor 20) (:Token /) (factor 4))",
                3: "(term (term (factor 20) (:Token /) (factor 4)) (:Token *) (factor 3))"
            },
            "fail": {
                4: "4 + 5",
                5: "20 / 4 - 3"
            }
        }
    }

    failure_cases = {
        "term": {
            "match": {
                1: "4 + 5",     # error: this should fail
                2: "20 / 4",
                3: "20 / 4 * 3"
            },
            "ast": {
                1: "(term (factor 4) (:Token *) (factor 5))",
                2: "(term (factor 20) (:Token /) (factor 4))",
                3: "(term (term (factor 19) (:Token /) (factor 4)) (:Token *) (factor 3))"  # error 19 != 20
            },
            "fail": {
                4: "4 * 5",     # error: this should match
                5: "20 / 4 - 3"
            }
        }
    }

Eckhart Arnold's avatar
Eckhart Arnold committed
107
108
109
110
111
112
113
114
115
116
117
118
    def teardown(self):
        if os.path.exists('REPORT'):
            files = os.listdir('REPORT')
            flag = False
            for file in files:
                if re.match(r'\d+\.md', file):
                    os.remove(os.path.join('REPORT', file))
                else:
                    flag = True
            if not flag:
                os.rmdir('REPORT')

119
    def test_testing_grammar(self):
120
        parser_fac = grammar_provider(ARITHMETIC_EBNF)
121
        trans_fac = lambda : ARITHMETIC_EBNFTransform
122
        errata = grammar_unit(self.cases, parser_fac, trans_fac)
123
        assert not errata, str(errata)
124
        errata = grammar_unit(self.failure_cases, parser_fac, trans_fac)
125
126
127
128
129
130
131
132
133
134
        # for e in errata:
        #     print(e)
        assert len(errata) == 3


class TestSExpr:
    """
    Tests for S-expression handling.
    """
    def test_compact_sexpr(self):
Eckhart Arnold's avatar
Eckhart Arnold committed
135
        assert flatten_sxpr("(a\n    (b\n        c\n    )\n)\n") == "(a (b c))"
136
137
138
139

    def test_mock_syntax_tree(self):
        sexpr = '(a (b c) (d e) (f (g h)))'
        tree = mock_syntax_tree(sexpr)
Eckhart Arnold's avatar
Eckhart Arnold committed
140
        assert flatten_sxpr(tree.as_sxpr().replace('"', '')) == sexpr
141
142
143
144
145

        # test different quotation marks
        sexpr = '''(a (b """c""" 'k' "l") (d e) (f (g h)))'''
        sexpr_stripped = '(a (b c k l) (d e) (f (g h)))'
        tree = mock_syntax_tree(sexpr)
Eckhart Arnold's avatar
Eckhart Arnold committed
146
        assert flatten_sxpr(tree.as_sxpr().replace('"', '')) == sexpr_stripped
147
148
149

        sexpr_clean = '(a (b "c" "k" "l") (d "e") (f (g "h")))'
        tree = mock_syntax_tree(sexpr_clean)
Eckhart Arnold's avatar
Eckhart Arnold committed
150
        assert flatten_sxpr(tree.as_sxpr()) == sexpr_clean
151
152

        tree = mock_syntax_tree(sexpr_stripped)
Eckhart Arnold's avatar
Eckhart Arnold committed
153
        assert flatten_sxpr(tree.as_sxpr()) == '(a (b "c k l") (d "e") (f (g "h")))'
154
155
156
157
158
159
160
161
162
163
164
165
166

    def test_mock_syntax_tree_with_classes(self):
        sexpr = '(a:class1 (b:class2 x) (:class3 y) (c z))'
        tree = mock_syntax_tree(sexpr)
        assert tree.tag_name == 'a'
        assert tree.result[0].tag_name == 'b'
        assert tree.result[1].tag_name == ':class3'
        assert tree.result[2].tag_name == 'c'


if __name__ == "__main__":
    from DHParser.testing import runner
    runner("", globals())