|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <assert.h> |
|
19 #include <errno.h> |
|
20 #include <fcntl.h> |
|
21 #include <unistd.h> |
|
22 #include <stdio.h> |
|
23 #include <sys/types.h> |
|
24 #include <sys/stat.h> |
|
25 |
|
26 #include <fstream> |
|
27 |
|
28 #include "cpixfstools.h" |
|
29 |
|
30 #include "itktesters.h" |
|
31 #include "itktestmgr.h" |
|
32 #include "itkimpl.h" |
|
33 |
|
34 namespace |
|
35 { |
|
36 // suffix for 'in' (input to be redirected) files |
|
37 const char IN_SFX[] = "_in.txt"; |
|
38 |
|
39 // suffixes for 'res' / 'exp' (RESult and EXPected) files for |
|
40 // stdandard OUTput and ERRor. |
|
41 const char RES_OUT_SFX[] = "_res_out.txt"; |
|
42 const char RES_ERR_SFX[] = "_res_err.txt"; |
|
43 const char EXP_OUT_SFX[] = "_exp_out.txt"; |
|
44 const char EXP_ERR_SFX[] = "_exp_err.txt"; |
|
45 } |
|
46 |
|
47 |
|
48 |
|
49 namespace Itk |
|
50 { |
|
51 namespace Impl |
|
52 { |
|
53 |
|
54 |
|
55 /**** |
|
56 * InputRedirector |
|
57 */ |
|
58 InputRedirector::InputRedirector(const std::string & defFilesBasePath) |
|
59 : duplicatedStdInFD_(-1), |
|
60 inFileFD_(-1) |
|
61 { |
|
62 using namespace std; |
|
63 using namespace Cpt; |
|
64 |
|
65 string |
|
66 inFilePath = defFilesBasePath; |
|
67 inFilePath += IN_SFX; |
|
68 |
|
69 if (isreadable(inFilePath.c_str())) |
|
70 { |
|
71 |
|
72 duplicatedStdInFD_ = dup(STDIN_FILENO); |
|
73 if (duplicatedStdInFD_ == -1) |
|
74 { |
|
75 throw IOCaptureExc("Can't dup(stdin)"); |
|
76 } |
|
77 |
|
78 Cpt_EINTR_RETRY(inFileFD_, |
|
79 open(inFilePath.c_str(),O_RDONLY)); |
|
80 if (inFileFD_ == -1) |
|
81 { |
|
82 Cpt_EINTR_RETRY_SP(close(duplicatedStdInFD_)); |
|
83 throw IOCaptureExc(inFilePath.c_str()); |
|
84 } |
|
85 int |
|
86 newStdIn = dup2(inFileFD_, |
|
87 STDIN_FILENO); |
|
88 if (newStdIn == -1) |
|
89 { |
|
90 Cpt_EINTR_RETRY_SP(close(inFileFD_)); |
|
91 Cpt_EINTR_RETRY_SP(close(duplicatedStdInFD_)); |
|
92 throw IOCaptureExc("Can't dup2(infile,stdin)"); |
|
93 } |
|
94 } |
|
95 } |
|
96 |
|
97 |
|
98 InputRedirector::~InputRedirector() |
|
99 { |
|
100 if (duplicatedStdInFD_ != -1) |
|
101 { |
|
102 int |
|
103 fd = dup2(duplicatedStdInFD_, |
|
104 STDIN_FILENO); |
|
105 // we can't possibly do anything sensible about these |
|
106 // failures here, but they must not go unnoticed |
|
107 assert(fd != -1); |
|
108 |
|
109 Cpt_EINTR_RETRY_SP(close(inFileFD_)); |
|
110 Cpt_EINTR_RETRY_SP(close(duplicatedStdInFD_)); |
|
111 } |
|
112 } |
|
113 |
|
114 |
|
115 |
|
116 /**** |
|
117 * OutputRedirector |
|
118 */ |
|
119 OutputRedirector::OutputRedirector(const std::string & defFilesBasePath, |
|
120 TestMgr * testMgr) |
|
121 : duplicatedStdOutFD_(-1), |
|
122 outFileFD_(-1), |
|
123 stdErr_(testMgr == NULL ? true : false), |
|
124 testMgr_(testMgr) |
|
125 { |
|
126 // flushing possible STD IO stream buffers before swapping |
|
127 int |
|
128 res = fflush(stdErr_ ? stderr : stdout); |
|
129 assert(res != EOF); |
|
130 |
|
131 using namespace std; |
|
132 |
|
133 string |
|
134 outFilePath = defFilesBasePath; |
|
135 outFilePath += (stdErr_ ? RES_ERR_SFX : RES_OUT_SFX); |
|
136 |
|
137 int |
|
138 stdFD = stdErr_ ? STDERR_FILENO : STDOUT_FILENO; |
|
139 |
|
140 duplicatedStdOutFD_ = dup(stdFD); |
|
141 if (duplicatedStdOutFD_ == -1) |
|
142 { |
|
143 const char |
|
144 * msg = stdErr_ ? "Can't dup(stdErr)" |
|
145 : "Can't dup(stdout)"; |
|
146 |
|
147 throw IOCaptureExc(msg); |
|
148 } |
|
149 Cpt_EINTR_RETRY(outFileFD_, |
|
150 open(outFilePath.c_str(), |
|
151 O_CREAT | O_TRUNC | O_WRONLY, |
|
152 0666)); |
|
153 if (outFileFD_ == -1) |
|
154 { |
|
155 Cpt_EINTR_RETRY(res,close(duplicatedStdOutFD_)); |
|
156 throw IOCaptureExc(outFilePath.c_str()); |
|
157 } |
|
158 int |
|
159 newStdOut = dup2(outFileFD_, |
|
160 stdFD); |
|
161 if (newStdOut == -1) |
|
162 { |
|
163 Cpt_EINTR_RETRY(res,close(outFileFD_)); |
|
164 Cpt_EINTR_RETRY(res,close(duplicatedStdOutFD_)); |
|
165 throw IOCaptureExc("Can't dup2(outfile,stdout)"); |
|
166 } |
|
167 |
|
168 if (!stdErr_) |
|
169 { |
|
170 testMgr_->setDbgConsoleFd(duplicatedStdOutFD_); |
|
171 } |
|
172 } |
|
173 |
|
174 |
|
175 OutputRedirector::~OutputRedirector() |
|
176 { |
|
177 // flushing possible STD IO stream buffers before swapping |
|
178 int |
|
179 res = fflush(stdErr_ ? stderr : stdout); |
|
180 assert(res != EOF); |
|
181 |
|
182 int |
|
183 stdFD = stdErr_ ? STDERR_FILENO : STDOUT_FILENO; |
|
184 |
|
185 if (!stdErr_) |
|
186 { |
|
187 testMgr_->setDbgConsoleFd(stdFD); |
|
188 } |
|
189 |
|
190 int |
|
191 fd = dup2(duplicatedStdOutFD_, |
|
192 stdFD); |
|
193 // we can't possibly do anything sensible about these |
|
194 // failures here, but they must not go unnoticed |
|
195 assert(fd != -1); |
|
196 |
|
197 Cpt_EINTR_RETRY(res,close(outFileFD_)); |
|
198 Cpt_EINTR_RETRY(res,close(duplicatedStdOutFD_)); |
|
199 } |
|
200 |
|
201 |
|
202 /**** |
|
203 * IOCaptureEvaluator |
|
204 */ |
|
205 void IOCaptureEvaluator::evaluate() |
|
206 { |
|
207 evaluate(false); // std out |
|
208 evaluate(true); // std err |
|
209 } |
|
210 |
|
211 |
|
212 IOCaptureEvaluator |
|
213 ::IOCaptureEvaluator(const std::string & defFileBasePath, |
|
214 TestMgr * testMgr, |
|
215 const std::string & lenience) |
|
216 : defFileBasePath_(defFileBasePath), |
|
217 testMgr_(testMgr), |
|
218 lenience_(lenience) |
|
219 { |
|
220 ; |
|
221 } |
|
222 |
|
223 void IOCaptureEvaluator::copyContent(const char * dstPath, |
|
224 const char * srcPath) |
|
225 { |
|
226 int |
|
227 result = Cpt::copyFile(dstPath, |
|
228 srcPath); |
|
229 |
|
230 switch (result) |
|
231 { |
|
232 case Cpt::CPT_CPF_OK: |
|
233 testMgr_->ioCaptureDefined(dstPath, |
|
234 "IO test case defined."); |
|
235 break; |
|
236 case Cpt::CPT_CPF_DST_OPEN_ERROR: |
|
237 testMgr_->ioCaptureError(dstPath, |
|
238 "Could not open for writing"); |
|
239 break; |
|
240 case Cpt::CPT_CPF_SRC_OPEN_ERROR: |
|
241 testMgr_->ioCaptureError(srcPath, |
|
242 "Could not open for reading"); |
|
243 break; |
|
244 case Cpt::CPT_CPF_DST_WRITE_ERROR: |
|
245 testMgr_->ioCaptureError(dstPath, |
|
246 "Writing failed"); |
|
247 break; |
|
248 case Cpt::CPT_CPF_SRC_READ_ERROR: |
|
249 testMgr_->ioCaptureError(srcPath, |
|
250 "Reading failed"); |
|
251 break; |
|
252 }; |
|
253 } |
|
254 |
|
255 |
|
256 void IOCaptureEvaluator::compareContent(const char * expPath, |
|
257 const char * resPath) |
|
258 { |
|
259 using namespace std; |
|
260 |
|
261 FILE* |
|
262 expFs; |
|
263 expFs = fopen(expPath, "r"); |
|
264 if (!expFs) |
|
265 { |
|
266 testMgr_->ioCaptureError(expPath, |
|
267 "Could not open for reading"); |
|
268 return; |
|
269 } |
|
270 Cpt::FileSentry expFsSentry( expFs ); |
|
271 |
|
272 |
|
273 FILE* |
|
274 resFs; |
|
275 resFs = fopen(resPath, "r"); |
|
276 if (!resFs) |
|
277 { |
|
278 testMgr_->ioCaptureError(resPath, |
|
279 "Could not open for reading"); |
|
280 return; |
|
281 } |
|
282 Cpt::FileSentry resFsSentry( resFs ); |
|
283 |
|
284 ssize_t |
|
285 firstDifferingLine = -1, |
|
286 currentLine = 1; |
|
287 string |
|
288 expLine, |
|
289 resLine; |
|
290 bool |
|
291 lenient = lenience_.length() > 0; |
|
292 |
|
293 while (firstDifferingLine == -1 && Cpt::fgetline(expFs, expLine)) |
|
294 { |
|
295 if (!Cpt::fgetline(resFs, resLine)) |
|
296 { |
|
297 firstDifferingLine = currentLine; |
|
298 } |
|
299 else if (expLine != resLine) |
|
300 { |
|
301 if (!(lenient |
|
302 && expLine.find(lenience_) != string::npos)) |
|
303 { |
|
304 firstDifferingLine = currentLine; |
|
305 } |
|
306 } |
|
307 |
|
308 ++currentLine; |
|
309 } |
|
310 |
|
311 if (firstDifferingLine == -1) |
|
312 { |
|
313 // If the contents were identical so far, then we |
|
314 // have terminated the previous loop with |
|
315 // exhausting the entire EXPected content. At this |
|
316 // point, therefore, nothing should be left from |
|
317 // RESult content, either. |
|
318 if (Cpt::fgetline(resFs, resLine)) |
|
319 { |
|
320 firstDifferingLine = currentLine; |
|
321 } |
|
322 } |
|
323 |
|
324 bool |
|
325 succeeded = firstDifferingLine == -1; |
|
326 |
|
327 testMgr_->expecting(succeeded, |
|
328 "(IO Capture)", |
|
329 expPath, |
|
330 succeeded ? 0 : firstDifferingLine, |
|
331 "IO Capture test."); |
|
332 } |
|
333 |
|
334 |
|
335 void IOCaptureEvaluator::evaluate(bool stdErr) |
|
336 { |
|
337 using namespace std; |
|
338 using namespace Cpt; |
|
339 |
|
340 string |
|
341 resPath = defFileBasePath_, |
|
342 expPath = defFileBasePath_; |
|
343 |
|
344 resPath += (stdErr ? RES_ERR_SFX : RES_OUT_SFX); |
|
345 expPath += (stdErr ? EXP_ERR_SFX : EXP_OUT_SFX); |
|
346 |
|
347 bool |
|
348 redirectOnly = (lenience_ == SuiteTester::REDIRECT_ONLY); |
|
349 |
|
350 if (!isreadable(resPath.c_str())) |
|
351 { |
|
352 testMgr_->ioCaptureError(resPath.c_str(), |
|
353 "Cannot open RESult file."); |
|
354 } |
|
355 else if (isreadable(expPath.c_str())) |
|
356 { |
|
357 if (!redirectOnly) |
|
358 { |
|
359 compareContent(expPath.c_str(), |
|
360 resPath.c_str()); |
|
361 } |
|
362 } |
|
363 else if (stdErr |
|
364 && !isreadable(expPath.c_str())) |
|
365 { |
|
366 bool |
|
367 succeeded = filesize(resPath.c_str()) == 0; |
|
368 |
|
369 // if we are doing std err, and if there is no |
|
370 // EXPected output then we fail or succeed by |
|
371 // looking already at the size of the RESulting |
|
372 // error |
|
373 testMgr_->expecting(succeeded, |
|
374 "(IO Capture)", |
|
375 expPath.c_str(), |
|
376 0, |
|
377 "IO Capture test."); |
|
378 } |
|
379 else |
|
380 { |
|
381 if (!redirectOnly) |
|
382 { |
|
383 copyContent(expPath.c_str(), |
|
384 resPath.c_str()); |
|
385 } |
|
386 } |
|
387 } |
|
388 |
|
389 |
|
390 |
|
391 } |
|
392 } |