Ticket #4421: testseq.sh

File testseq.sh, 8.3 KB (added by Wolf Lammen <ookami1@…>, 12 years ago)

test suite

Line 
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
26testPath="$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='((,))' # ((,))((,))((,))...
37eFormat='(() %s)' # (() 1)(() 2)(() 3)...
38
39# a replacement is made using the following contents. Omit the enclosing
40# parentheses
41eReplacement='x'
42
43# start with sequences of size (inclusive, > 0)...
44szBegin=1
45
46# ...and stop with sequences of size (inclusive, <= BOOST_PP_LIMIT_SEQ)
47szEnd=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
52boostFlags=''
53#boostFlags='(BOOST_PP_CONFIG_EDG() | BOOST_PP_CONFIG_STRICT())'
54#boostFlags='0x0003'
55
56# invoking compiler
57boostIncludePath="$HOME/programs/boost_1_43_0"
58cppFile="$testPath/testseq.cpp"
59exeFile='testseq'
60cc="g++ -Wall -I$boostIncludePath -o $exeFile $cppFile"
61
62#tests
63
64LF='
65'
66cd "$testPath"
67
68for seqsz in `seq -s ' ' $szBegin $szEnd`
69do
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
81END
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
109using std::string;
110using std::cout;
111using 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
127END
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
143char const elemPattern[] = "$eFormat";
144char const replacement[] = "$eReplacement";
145
146END
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
173void trimLeft(char const** str)
174{
175 // advances *str by the number of leading spaces
176 while(**str == ' ')
177 ++*str;
178}
179
180string 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
188string 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
199bool 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
214bool 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
223bool 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
232int 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
245int 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}
268END
269if $cc
270then
271 ./$exeFile | tee testresults.log
272else
273 break
274fi
275done