summaryrefslogtreecommitdiff
path: root/test/testcpp.py
blob: dbfb3e4d7f120a3b2fe6f3ed60c1f64412434918 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
from unittest import TestCase, main

from multiprocessing import Process, Queue
from six.moves.queue import Empty

import sys
import locale

if ".." not in sys.path:
    sys.path.insert(0, "..")

from ply.lex import lex
from ply.cpp import *


def preprocessing(in_, out_queue):
    out = None

    try:
        p = Preprocessor(lex())
        p.parse(in_)
        tokens = [t.value for t in p.parser]
        out = "".join(tokens)
    finally:
        out_queue.put(out)

class CPPTests(TestCase):
    "Tests related to ANSI-C style lexical preprocessor."

    def __test_preprocessing(self, in_, expected, time_limit = 1.0):
        out_queue = Queue()

        preprocessor = Process(
            name = "PLY`s C preprocessor",
            target = preprocessing,
            args = (in_, out_queue)
        )

        preprocessor.start()

        try:
            out = out_queue.get(timeout = time_limit)
        except Empty:
            preprocessor.terminate()
            raise RuntimeError("Time limit exceeded!")
        else:
            self.assertMultiLineEqual(out, expected)

    def test_infinite_argument_expansion(self):
        # CPP does not drags set of currently expanded macros through macro
        # arguments expansion. If there is a match between an argument value
        # and name of an already expanded macro then CPP falls into infinite
        # recursion.
        self.__test_preprocessing("""\
#define a(x) x
#define b a(b)
b
"""         , """\


b"""
        )


    def test_concatenation(self):
        self.__test_preprocessing("""\
#define a(x) x##_
#define b(x) _##x
#define c(x) _##x##_
#define d(x,y) _##x##y##_

a(i)
b(j)
c(k)
d(q,s)"""
            , """\





i_
_j
_k_
_qs_"""
        )

    def test_deadloop_macro(self):
        # If there is a word which equals to name of a parametrized macro, then
        # attempt to expand such word as a macro manages the parser to fall
        # into an infinite loop.

        self.__test_preprocessing("""\
#define a(x) x

a;"""
            , """\


a;"""
        )

    def test_index_error(self):
        # If there are no tokens after a word ("a") which equals to name of
        # a parameterized macro, then attempt to expand this word leads to
        # IndexError.

        self.__test_preprocessing("""\
#define a(x) x

a"""
            , """\


a"""
        )

    def test_evalexpr(self):
        # #if 1 != 2 is not processed correctly; undefined values are converted
        # to 0L instead of 0 (issue #195)
        #
        self.__test_preprocessing("""\
#if (1!=0) && (!x || (!(1==2)))
a;
#else
b;
#endif
"""
            , """\

a;

"""
        )

    def test_include_nonascii(self):
        # Issue #196: #included files are read using the current locale's
        # getdefaultencoding. if a #included file contains non-ascii characters,
        # while default encoding is e.g. US_ASCII, this causes an error
        locale.setlocale(locale.LC_ALL, 'C')
        self.__test_preprocessing("""\
#include "test_cpp_nonascii.c"
x;

"""
            , """\

 
1;
"""
        )

main()