1 | #! /bin/bash
|
---|
2 |
|
---|
3 | # (C) Copyright Wolf Lammen 2010
|
---|
4 | # Distributed under the Boost Software License, Version 1.0. (See
|
---|
5 | # copy at http://www.boost.org/LICENSE_1_0.txt)
|
---|
6 |
|
---|
7 |
|
---|
8 | # this file runs a test suite checking the validity of a BOOST_PP_SEQ_REPLACE
|
---|
9 | # implementation. It uses a brute force method, i.e. sequences of all
|
---|
10 | # possible lengths are tested, each element is replaced, and each
|
---|
11 | # replacement is individually checked.
|
---|
12 | # This is done for both 1.43.0 code and the new experimental implementation.
|
---|
13 | # In addition, this suite allows testing sequences with elements having a
|
---|
14 | # critical pattern, i.e. containing commas, parentheses and other characters
|
---|
15 | # special to the preprocessor.
|
---|
16 | # The suite has been augmented to even tell if the (irrelevant) distribution of
|
---|
17 | # space characters between elements differs in old and new code
|
---|
18 | #
|
---|
19 | # Tests are done by generating a C++ file, that is compiled and run then. The output
|
---|
20 | # of compiled program is both logged to a file, and displayed on the terminal.
|
---|
21 |
|
---|
22 | # script parameters
|
---|
23 | # fill in appropriate values here
|
---|
24 |
|
---|
25 | # temporary files, build files and result files are created here
|
---|
26 | testPath="$HOME/testseq"
|
---|
27 |
|
---|
28 | # pattern from which elements in the sequence are built
|
---|
29 | # a single occurrence of %s is replaced by the element index,
|
---|
30 | # starting with 1
|
---|
31 | # format patterns must not exceed 100 characters
|
---|
32 | #eFormat='(%s)' # (1)(2)(3)...
|
---|
33 | #eFormat='(%s) ' # (1) (2) (3)...
|
---|
34 | #eFormat='((%s)) ' # ((1)) ((2)) ((3))...
|
---|
35 | #eFormat='((%s,))' # ((1,))((2,))((3,))...
|
---|
36 | #eFormat='((,))' # ((,))((,))((,))...
|
---|
37 | eFormat='(() %s)' # (() 1)(() 2)(() 3)...
|
---|
38 |
|
---|
39 | # a replacement is made using the following contents. Omit the enclosing
|
---|
40 | # parentheses
|
---|
41 | eReplacement='x'
|
---|
42 |
|
---|
43 | # start with sequences of size (inclusive, > 0)...
|
---|
44 | szBegin=1
|
---|
45 |
|
---|
46 | # ...and stop with sequences of size (inclusive, <= BOOST_PP_LIMIT_SEQ)
|
---|
47 | szEnd=256
|
---|
48 |
|
---|
49 | # pre-defined compiler configuration according to boost/preprocessor/config/config.hpp
|
---|
50 | # if no boostFlags variable is defined, or if it is empty, the flags are automatically
|
---|
51 | # determined according to the used compiler
|
---|
52 | boostFlags=''
|
---|
53 | #boostFlags='(BOOST_PP_CONFIG_EDG() | BOOST_PP_CONFIG_STRICT())'
|
---|
54 | #boostFlags='0x0003'
|
---|
55 |
|
---|
56 | # invoking compiler
|
---|
57 | boostIncludePath="$HOME/programs/boost_1_43_0"
|
---|
58 | cppFile="$testPath/testseq.cpp"
|
---|
59 | exeFile='testseq'
|
---|
60 | cc="g++ -Wall -I$boostIncludePath -o $exeFile $cppFile"
|
---|
61 |
|
---|
62 | #tests
|
---|
63 |
|
---|
64 | LF='
|
---|
65 | '
|
---|
66 | cd "$testPath"
|
---|
67 |
|
---|
68 | for seqsz in `seq -s ' ' $szBegin $szEnd`
|
---|
69 | do
|
---|
70 |
|
---|
71 | # create C++ source file
|
---|
72 |
|
---|
73 | cat > "$cppFile" << END
|
---|
74 | /*
|
---|
75 | automatically generated file used to test replacement in BOOST sequences.
|
---|
76 | The size of the sequence tested is $seqsz.
|
---|
77 | Large parts of this file are verbatim copies from a file subject
|
---|
78 | to (C) Copyright Wolf Lammen 2010
|
---|
79 | */
|
---|
80 |
|
---|
81 | END
|
---|
82 |
|
---|
83 | if [ "${boostFlags:-x}" != 'x' ]
|
---|
84 | then
|
---|
85 | echo "#define BOOST_PP_CONFIG_FLAGS() $boostFlags" >> "$cppFile"
|
---|
86 | fi
|
---|
87 |
|
---|
88 | cat >> "$cppFile" << END
|
---|
89 |
|
---|
90 | // includes needed for test code
|
---|
91 | # include <string>
|
---|
92 | # include <stdio.h>
|
---|
93 | # include <string.h>
|
---|
94 | # include <iostream>
|
---|
95 | # include "boost/preprocessor/arithmetic/dec.hpp"
|
---|
96 | # include "boost/preprocessor/stringize.hpp"
|
---|
97 |
|
---|
98 | // includes needed for experimental PP_SEQ_REPLACE
|
---|
99 | # include "boost/preprocessor/arithmetic/inc.hpp"
|
---|
100 | # include "boost/preprocessor/config/config.hpp"
|
---|
101 | # include "boost/preprocessor/facilities/empty.hpp"
|
---|
102 | # include "boost/preprocessor/seq/first_n.hpp"
|
---|
103 | # include "boost/preprocessor/seq/detail/split.hpp"
|
---|
104 | # include "boost/preprocessor/tuple/elem.hpp"
|
---|
105 |
|
---|
106 | // includes needed for old BOOST_PP_SEQ_REPLACE
|
---|
107 | # include "boost/preprocessor/seq/replace.hpp"
|
---|
108 |
|
---|
109 | using std::string;
|
---|
110 | using std::cout;
|
---|
111 | using std::endl;
|
---|
112 |
|
---|
113 | // experimental PP_SEQ_REPLACE implementation
|
---|
114 | // to avoid name clashes, the BOOST_ prefix is omitted for macros defined here
|
---|
115 | # if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_EDG()
|
---|
116 | # define PP_SEQ_REPLACE(seq, i, elem) BOOST_PP_SEQ_FIRST_N(i, seq) (elem) PP_SEQ_REST_N_PLUS_1(i, seq)
|
---|
117 | # define PP_SEQ_REST_N_PLUS_1(n, seq) BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_SEQ_SPLIT(BOOST_PP_INC(n), seq BOOST_PP_EMPTY))()
|
---|
118 | # else
|
---|
119 | # define PP_SEQ_REPLACE(seq, i, elem) PP_SEQ_REPLACE_I(seq, i, elem)
|
---|
120 | # define PP_SEQ_REPLACE_I(seq, i, elem) BOOST_PP_SEQ_FIRST_N(i, seq) (elem) PP_SEQ_REST_N_PLUS_1(i, seq)
|
---|
121 | # define PP_SEQ_REST_N_PLUS_1(n, seq) PP_SEQ_REST_N_PLUS_1_I(n, seq)
|
---|
122 | # define PP_SEQ_REST_N_PLUS_1_I(n, seq) BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_SEQ_SPLIT(BOOST_PP_INC(n), seq BOOST_PP_EMPTY))()
|
---|
123 | # endif
|
---|
124 |
|
---|
125 | # define REPLACE $eReplacement
|
---|
126 |
|
---|
127 | END
|
---|
128 |
|
---|
129 | seqlist=`seq -s ' ' 1 $seqsz`
|
---|
130 |
|
---|
131 | # create the sequence from pattern
|
---|
132 |
|
---|
133 | echo '#define SEQ \' >> "$cppFile"
|
---|
134 | for i in $seqlist
|
---|
135 | do
|
---|
136 | printf "$eFormat\\$LF" $i >> "$cppFile"
|
---|
137 | done
|
---|
138 | echo >> "$cppFile"
|
---|
139 |
|
---|
140 | # make pattern and replacement available to the program
|
---|
141 |
|
---|
142 | cat >> "$cppFile" << END
|
---|
143 | char const elemPattern[] = "$eFormat";
|
---|
144 | char const replacement[] = "$eReplacement";
|
---|
145 |
|
---|
146 | END
|
---|
147 |
|
---|
148 | # create macro expansions with boost 1.43.0 code
|
---|
149 |
|
---|
150 | echo "char const* const oldResult[$seqsz] = {" >> "$cppFile"
|
---|
151 |
|
---|
152 | for i in $seqlist
|
---|
153 | do
|
---|
154 | echo "BOOST_PP_STRINGIZE(BOOST_PP_SEQ_REPLACE(SEQ, BOOST_PP_DEC($i), REPLACE))," >> "$cppFile"
|
---|
155 | done
|
---|
156 | echo '};' >> "$cppFile"
|
---|
157 |
|
---|
158 | # create macro expansions with new code
|
---|
159 |
|
---|
160 | echo "char const* const newResult[$seqsz] = {" >> "$cppFile"
|
---|
161 |
|
---|
162 | for i in $seqlist
|
---|
163 | do
|
---|
164 | echo "BOOST_PP_STRINGIZE(PP_SEQ_REPLACE(SEQ, BOOST_PP_DEC($i), $eReplacement))," >> "$cppFile"
|
---|
165 | done
|
---|
166 | echo '};' >> "$cppFile"
|
---|
167 | echo >> "$cppFile"
|
---|
168 |
|
---|
169 | # utility functions for runtime check
|
---|
170 |
|
---|
171 | cat >> "$cppFile" << END
|
---|
172 |
|
---|
173 | void trimLeft(char const** str)
|
---|
174 | {
|
---|
175 | // advances *str by the number of leading spaces
|
---|
176 | while(**str == ' ')
|
---|
177 | ++*str;
|
---|
178 | }
|
---|
179 |
|
---|
180 | string trim(string const& s)
|
---|
181 | {
|
---|
182 | // removes leading and trailing spaces
|
---|
183 | unsigned low = s.find_first_not_of(" ");
|
---|
184 | unsigned high = s.find_last_not_of(" ");
|
---|
185 | return s.substr(low, high + 1 - low);
|
---|
186 | }
|
---|
187 |
|
---|
188 | string elemFromPattern(unsigned i)
|
---|
189 | {
|
---|
190 | // returns the i-th element (zero-based), trimmed, according to eFormat
|
---|
191 | static string pattern = trim(elemPattern);
|
---|
192 | char buffer_i[10];
|
---|
193 | char buffer[115];
|
---|
194 | snprintf(buffer_i, sizeof(buffer_i), "%u", i + 1);
|
---|
195 | snprintf(buffer, sizeof(buffer), pattern.c_str(), buffer_i);
|
---|
196 | return buffer;
|
---|
197 | }
|
---|
198 |
|
---|
199 | bool cmpElem(char const** expansion, string const& e)
|
---|
200 | {
|
---|
201 | // checks whether the beginning of *expansion matches e
|
---|
202 | // if so advances *expansion, so that e as well as following spaces
|
---|
203 | // are skipped
|
---|
204 | unsigned sz = e.size();
|
---|
205 | bool result = e.compare(0, sz, *expansion, sz) == 0;
|
---|
206 | if (result)
|
---|
207 | {
|
---|
208 | *expansion += sz;
|
---|
209 | trimLeft(expansion);
|
---|
210 | }
|
---|
211 | return result;
|
---|
212 | }
|
---|
213 |
|
---|
214 | bool cmpOrigElem(char const** expansion, unsigned idx)
|
---|
215 | {
|
---|
216 | // checks whether the beginning of *expansion matches the element
|
---|
217 | // in the original sequence at position 'idx' (zero-based)
|
---|
218 | // if so advances *expansion, so that the first element as well as
|
---|
219 | // following spaces are skipped
|
---|
220 | return cmpElem(expansion, elemFromPattern(idx));
|
---|
221 | }
|
---|
222 |
|
---|
223 | bool cmpReplacement(char const** expansion)
|
---|
224 | {
|
---|
225 | // checks whether the beginning of *expansion matches a replaced
|
---|
226 | // element
|
---|
227 | // if so advances *expansion, so that the first element as well as
|
---|
228 | // following spaces are skipped
|
---|
229 | return cmpElem(expansion, '(' + string(replacement) + ')');
|
---|
230 | }
|
---|
231 |
|
---|
232 | int check(char const* expansion, unsigned replacepos)
|
---|
233 | {
|
---|
234 | // checks whether 'expansion' is a sequense equal to the original sequence,
|
---|
235 | // except for position 'replacepos' (zero-based) which must be the
|
---|
236 | // replaced element
|
---|
237 | trimLeft(&expansion);
|
---|
238 | bool ok = true;
|
---|
239 | unsigned i = 0;
|
---|
240 | for (; ok && ++i <= $seqsz;)
|
---|
241 | ok = i - 1 == replacepos? cmpReplacement(&expansion) : cmpOrigElem(&expansion, i - 1);
|
---|
242 | return ok && *expansion == '\0'? 0 : i;
|
---|
243 | }
|
---|
244 |
|
---|
245 | int main()
|
---|
246 | {
|
---|
247 | cout << "testing sequence of length " << $seqsz << endl;
|
---|
248 | for(unsigned i = 0; i < $seqsz; ++i)
|
---|
249 | {
|
---|
250 | // check replacement at position #i
|
---|
251 | unsigned idx1 = check(oldResult[i], i);
|
---|
252 | if (idx1 != 0)
|
---|
253 | cout << "boost 1.43.0 code failed when replacing element #" << i + 1 << endl
|
---|
254 | << "element #" << idx1 << " is not as expected" << endl
|
---|
255 | << "expansion is :" << endl
|
---|
256 | << oldResult[i] << endl;
|
---|
257 | unsigned idx2 = check(newResult[i], i);
|
---|
258 | if (idx2 != 0)
|
---|
259 | cout << "experimental code failed when replacing element #" << i + 1 << endl
|
---|
260 | << "element #" << idx2 << " is not as expected" << endl
|
---|
261 | << "expansion is :" << endl
|
---|
262 | << newResult[i] << endl;
|
---|
263 | if (idx1 == 0 && idx2 == 0 && strcmp(oldResult[i], newResult[i]) != 0)
|
---|
264 | cout << "experimental code is correct, when replacing element #" << i + 1 << endl
|
---|
265 | << "but white space distribution differs from 1.43.0 result" << endl;
|
---|
266 | }
|
---|
267 | }
|
---|
268 | END
|
---|
269 | if $cc
|
---|
270 | then
|
---|
271 | ./$exeFile | tee testresults.log
|
---|
272 | else
|
---|
273 | break
|
---|
274 | fi
|
---|
275 | done
|
---|