cmCTestTestHandler.cxx 61.5 KB
Newer Older
Ken Martin's avatar
Ken Martin committed
1
2
3
4
5
6
7
8
9
10
11
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

Andy Cedilnik's avatar
Andy Cedilnik committed
12
13
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Ken Martin's avatar
Ken Martin committed
14
15
16
17
18
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "cmCTestTestHandler.h"
19
#include "cmCTestMultiProcessHandler.h"
Ken Martin's avatar
Ken Martin committed
20
#include "cmCTest.h"
21
#include "cmCTestRunTest.h"
Ken Martin's avatar
Ken Martin committed
22
#include "cmake.h"
23
#include "cmGeneratedFileStream.h"
Ken Martin's avatar
Ken Martin committed
24
25
26
27
#include <cmsys/Process.h>
#include <cmsys/RegularExpression.hxx>
#include <cmsys/Base64.h>
#include "cmMakefile.h"
28
29
30
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmCommand.h"
31
#include "cmSystemTools.h"
32
#include "cmXMLSafe.h"
Ken Martin's avatar
Ken Martin committed
33

Andy Cedilnik's avatar
Andy Cedilnik committed
34
#include <stdlib.h>
Ken Martin's avatar
Ken Martin committed
35
36
37
#include <math.h>
#include <float.h>

38
39
#include <memory> // auto_ptr

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//----------------------------------------------------------------------
class cmCTestSubdirCommand : public cmCommand
{
public:
  /**
   * This is a virtual constructor for the command.
   */
  virtual cmCommand* Clone()
    {
    cmCTestSubdirCommand* c = new cmCTestSubdirCommand;
    c->TestHandler = this->TestHandler;
    return c;
    }

  /**
   * This is called when the command is first encountered in
   * the CMakeLists.txt file.
   */
58
59
  virtual bool InitialPass(std::vector<std::string> const& args,
                           cmExecutionStatus &);
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

  /**
   * The name of the command as specified in CMakeList.txt.
   */
  virtual const char* GetName() { return "subdirs";}

  // Unused methods
  virtual const char* GetTerseDocumentation() { return ""; }
  virtual const char* GetFullDocumentation() { return ""; }

  cmTypeMacro(cmCTestSubdirCommand, cmCommand);

  cmCTestTestHandler* TestHandler;
};

//----------------------------------------------------------------------
76
77
bool cmCTestSubdirCommand
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
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
{
  if(args.size() < 1 )
    {
    this->SetError("called with incorrect number of arguments");
    return false;
    }
  std::vector<std::string>::const_iterator it;
  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
  for ( it = args.begin(); it != args.end(); ++ it )
    {
    cmSystemTools::ChangeDirectory(cwd.c_str());
    std::string fname = cwd;
    fname += "/";
    fname += *it;

    if ( !cmSystemTools::FileExists(fname.c_str()) )
      {
      // No subdirectory? So what...
      continue;
      }
    cmSystemTools::ChangeDirectory(fname.c_str());
    const char* testFilename;
    if( cmSystemTools::FileExists("CTestTestfile.cmake") )
      {
      // does the CTestTestfile.cmake exist ?
      testFilename = "CTestTestfile.cmake";
      }
105
106
107
108
109
    else if( cmSystemTools::FileExists("DartTestfile.txt") ) 
      {
      // does the DartTestfile.txt exist ?
      testFilename = "DartTestfile.txt";
      }
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    else
      {
      // No CTestTestfile? Who cares...
      cmSystemTools::ChangeDirectory(cwd.c_str());
      continue;
      }
    fname += "/";
    fname += testFilename;
    bool readit = 
      this->Makefile->ReadListFile(this->Makefile->GetCurrentListFile(),
                                   fname.c_str());
    cmSystemTools::ChangeDirectory(cwd.c_str());
    if(!readit)
      {
      std::string m = "Could not find include file: ";
      m += fname;
      this->SetError(m.c_str());
      return false;
      }
    }
  return true;
}

133
//----------------------------------------------------------------------
134
class cmCTestAddSubdirectoryCommand : public cmCommand
135
136
137
138
139
{
public:
  /**
   * This is a virtual constructor for the command.
   */
Andy Cedilnik's avatar
Andy Cedilnik committed
140
  virtual cmCommand* Clone()
141
    {
142
    cmCTestAddSubdirectoryCommand* c = new cmCTestAddSubdirectoryCommand;
Andy Cedilnik's avatar
Andy Cedilnik committed
143
    c->TestHandler = this->TestHandler;
144
145
146
147
148
149
150
    return c;
    }

  /**
   * This is called when the command is first encountered in
   * the CMakeLists.txt file.
   */
151
152
  virtual bool InitialPass(std::vector<std::string> const& args,
                           cmExecutionStatus &);
153
154
155
156

  /**
   * The name of the command as specified in CMakeList.txt.
   */
157
  virtual const char* GetName() { return "add_subdirectory";}
158
159
160
161
162

  // Unused methods
  virtual const char* GetTerseDocumentation() { return ""; }
  virtual const char* GetFullDocumentation() { return ""; }

163
  cmTypeMacro(cmCTestAddSubdirectoryCommand, cmCommand);
164

Andy Cedilnik's avatar
Andy Cedilnik committed
165
  cmCTestTestHandler* TestHandler;
166
167
168
};

//----------------------------------------------------------------------
169
bool cmCTestAddSubdirectoryCommand
170
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
171
172
173
174
175
176
{
  if(args.size() < 1 )
    {
    this->SetError("called with incorrect number of arguments");
    return false;
    }
177

Andy Cedilnik's avatar
Andy Cedilnik committed
178
  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
179
180
181
182
  cmSystemTools::ChangeDirectory(cwd.c_str());
  std::string fname = cwd;
  fname += "/";
  fname += args[1];
Andy Cedilnik's avatar
Andy Cedilnik committed
183

184
185
186
187
188
189
190
191
192
193
194
195
  if ( !cmSystemTools::FileExists(fname.c_str()) )
    {
    // No subdirectory? So what...
    return true;
    }
  cmSystemTools::ChangeDirectory(fname.c_str());
  const char* testFilename;
  if( cmSystemTools::FileExists("CTestTestfile.cmake") )
    {
    // does the CTestTestfile.cmake exist ?
    testFilename = "CTestTestfile.cmake";
    }
196
197
198
199
200
  else if( cmSystemTools::FileExists("DartTestfile.txt") )
    {
    // does the DartTestfile.txt exist ?
    testFilename = "DartTestfile.txt";
    }
201
202
203
  else
    {
    // No CTestTestfile? Who cares...
204
    cmSystemTools::ChangeDirectory(cwd.c_str());
205
206
207
208
209
210
211
212
213
214
215
216
217
218
    return true;
    }
  fname += "/";
  fname += testFilename;
  bool readit = 
    this->Makefile->ReadListFile(this->Makefile->GetCurrentListFile(),
                                 fname.c_str());
  cmSystemTools::ChangeDirectory(cwd.c_str());
  if(!readit)
    {
    std::string m = "Could not find include file: ";
    m += fname;
    this->SetError(m.c_str());
    return false;
219
220
221
222
223
224
225
226
227
228
229
    }
  return true;
}

//----------------------------------------------------------------------
class cmCTestAddTestCommand : public cmCommand
{
public:
  /**
   * This is a virtual constructor for the command.
   */
Andy Cedilnik's avatar
Andy Cedilnik committed
230
  virtual cmCommand* Clone()
231
232
    {
    cmCTestAddTestCommand* c = new cmCTestAddTestCommand;
Andy Cedilnik's avatar
Andy Cedilnik committed
233
    c->TestHandler = this->TestHandler;
234
235
236
237
238
239
240
    return c;
    }

  /**
   * This is called when the command is first encountered in
   * the CMakeLists.txt file.
   */
241
242
  virtual bool InitialPass(std::vector<std::string> const&,
                           cmExecutionStatus &);
243
244
245
246
247
248
249
250
251
252
253
254

  /**
   * The name of the command as specified in CMakeList.txt.
   */
  virtual const char* GetName() { return "ADD_TEST";}

  // Unused methods
  virtual const char* GetTerseDocumentation() { return ""; }
  virtual const char* GetFullDocumentation() { return ""; }

  cmTypeMacro(cmCTestAddTestCommand, cmCommand);

Andy Cedilnik's avatar
Andy Cedilnik committed
255
  cmCTestTestHandler* TestHandler;
256
257
258
};

//----------------------------------------------------------------------
259
260
bool cmCTestAddTestCommand
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
261
262
263
264
265
266
{
  if ( args.size() < 2 )
    {
    this->SetError("called with incorrect number of arguments");
    return false;
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
267
  return this->TestHandler->AddTest(args);
268
269
}

270
271
272
273
274
275
276
//----------------------------------------------------------------------
class cmCTestSetTestsPropertiesCommand : public cmCommand
{
public:
  /**
   * This is a virtual constructor for the command.
   */
Andy Cedilnik's avatar
Andy Cedilnik committed
277
  virtual cmCommand* Clone()
278
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
279
280
    cmCTestSetTestsPropertiesCommand* c
      = new cmCTestSetTestsPropertiesCommand;
Andy Cedilnik's avatar
Andy Cedilnik committed
281
    c->TestHandler = this->TestHandler;
282
283
284
285
286
287
    return c;
    }

  /**
   * This is called when the command is first encountered in
   * the CMakeLists.txt file.
288
289
290
  */
  virtual bool InitialPass(std::vector<std::string> const&,
                           cmExecutionStatus &);
291
292
293
294
295
296
297
298
299
300
301
302

  /**
   * The name of the command as specified in CMakeList.txt.
   */
  virtual const char* GetName() { return "SET_TESTS_PROPERTIES";}

  // Unused methods
  virtual const char* GetTerseDocumentation() { return ""; }
  virtual const char* GetFullDocumentation() { return ""; }

  cmTypeMacro(cmCTestSetTestsPropertiesCommand, cmCommand);

Andy Cedilnik's avatar
Andy Cedilnik committed
303
  cmCTestTestHandler* TestHandler;
304
305
306
};

//----------------------------------------------------------------------
307
308
bool cmCTestSetTestsPropertiesCommand
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
309
{
Andy Cedilnik's avatar
Andy Cedilnik committed
310
  return this->TestHandler->SetTestsProperties(args);
311
312
}

313
//----------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
314
315
// get the next number in a string with numbers separated by ,
// pos is the start of the search and pos2 is the end of the search
Andy Cedilnik's avatar
Andy Cedilnik committed
316
// pos becomes pos2 after a call to GetNextNumber.
Ken Martin's avatar
Ken Martin committed
317
// -1 is returned at the end of the list.
Andy Cedilnik's avatar
Andy Cedilnik committed
318
inline int GetNextNumber(std::string const& in,
Ken Martin's avatar
Ken Martin committed
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
                         int& val,
                         std::string::size_type& pos,
                         std::string::size_type& pos2)
{
  pos2 = in.find(',', pos);
  if(pos2 != in.npos)
    {
    if(pos2-pos == 0)
      {
      val = -1;
      }
    else
      {
      val = atoi(in.substr(pos, pos2-pos).c_str());
      }
    pos = pos2+1;
    return 1;
    }
  else
    {
    if(in.size()-pos == 0)
      {
       val = -1;
      }
    else
      {
      val = atoi(in.substr(pos, in.size()-pos).c_str());
      }
    return 0;
    }
}

351
//----------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
352
353
// get the next number in a string with numbers separated by ,
// pos is the start of the search and pos2 is the end of the search
Andy Cedilnik's avatar
Andy Cedilnik committed
354
// pos becomes pos2 after a call to GetNextNumber.
Ken Martin's avatar
Ken Martin committed
355
// -1 is returned at the end of the list.
Andy Cedilnik's avatar
Andy Cedilnik committed
356
inline int GetNextRealNumber(std::string const& in,
Ken Martin's avatar
Ken Martin committed
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
                             double& val,
                             std::string::size_type& pos,
                             std::string::size_type& pos2)
{
  pos2 = in.find(',', pos);
  if(pos2 != in.npos)
    {
    if(pos2-pos == 0)
      {
      val = -1;
      }
    else
      {
      val = atof(in.substr(pos, pos2-pos).c_str());
      }
    pos = pos2+1;
    return 1;
    }
  else
    {
    if(in.size()-pos == 0)
      {
       val = -1;
      }
    else
      {
      val = atof(in.substr(pos, in.size()-pos).c_str());
      }
    return 0;
    }
}

Andy Cedilnik's avatar
Andy Cedilnik committed
389

Ken Martin's avatar
Ken Martin committed
390
391
392
//----------------------------------------------------------------------
cmCTestTestHandler::cmCTestTestHandler()
{
Andy Cedilnik's avatar
Andy Cedilnik committed
393
  this->UseUnion = false;
Andy Cedilnik's avatar
Andy Cedilnik committed
394

395
396
  this->UseIncludeLabelRegExpFlag   = false;
  this->UseExcludeLabelRegExpFlag   = false;
Andy Cedilnik's avatar
Andy Cedilnik committed
397
398
399
  this->UseIncludeRegExpFlag   = false;
  this->UseExcludeRegExpFlag   = false;
  this->UseExcludeRegExpFirst  = false;
400

Andy Cedilnik's avatar
Andy Cedilnik committed
401
402
  this->CustomMaximumPassedTestOutputSize = 1 * 1024;
  this->CustomMaximumFailedTestOutputSize = 300 * 1024;
Andy Cedilnik's avatar
Andy Cedilnik committed
403

Andy Cedilnik's avatar
Andy Cedilnik committed
404
  this->MemCheck = false;
405

Andy Cedilnik's avatar
Andy Cedilnik committed
406
  this->LogFile = 0;
Andy Cedilnik's avatar
Andy Cedilnik committed
407

Bill Hoffman's avatar
Bill Hoffman committed
408
409
410
411
412
413
  // regex to detect <DartMeasurement>...</DartMeasurement>
  this->DartStuff.compile(
    "(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
  // regex to detect each individual <DartMeasurement>...</DartMeasurement>
  this->DartStuff1.compile(
    "(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)");
Ken Martin's avatar
Ken Martin committed
414
415
}

416
417
418
//----------------------------------------------------------------------
void cmCTestTestHandler::Initialize()
{
419
420
  this->Superclass::Initialize();

Andy Cedilnik's avatar
Andy Cedilnik committed
421
  this->ElapsedTestingTime = -1;
422

Andy Cedilnik's avatar
Andy Cedilnik committed
423
  this->TestResults.clear();
424

Andy Cedilnik's avatar
Andy Cedilnik committed
425
426
427
  this->CustomTestsIgnore.clear();
  this->StartTest = "";
  this->EndTest = "";
428

Andy Cedilnik's avatar
Andy Cedilnik committed
429
430
431
432
  this->CustomPreTest.clear();
  this->CustomPostTest.clear();
  this->CustomMaximumPassedTestOutputSize = 1 * 1024;
  this->CustomMaximumFailedTestOutputSize = 300 * 1024;
433

Andy Cedilnik's avatar
Andy Cedilnik committed
434
  this->TestsToRun.clear();
435

Andy Cedilnik's avatar
Andy Cedilnik committed
436
437
438
  this->UseIncludeRegExpFlag = false;
  this->UseExcludeRegExpFlag = false;
  this->UseExcludeRegExpFirst = false;
439
440
  this->IncludeLabelRegularExpression = "";
  this->ExcludeLabelRegularExpression = "";
Andy Cedilnik's avatar
Andy Cedilnik committed
441
442
  this->IncludeRegExp = "";
  this->ExcludeRegExp = "";
443
444

  TestsToRunString = "";
Andy Cedilnik's avatar
Andy Cedilnik committed
445
446
  this->UseUnion = false;
  this->TestList.clear();
447
448
}

Ken Martin's avatar
Ken Martin committed
449
450
451
//----------------------------------------------------------------------
void cmCTestTestHandler::PopulateCustomVectors(cmMakefile *mf)
{
452
  this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_TEST",
Andy Cedilnik's avatar
Andy Cedilnik committed
453
                                this->CustomPreTest);
454
  this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_POST_TEST",
Andy Cedilnik's avatar
Andy Cedilnik committed
455
                                this->CustomPostTest);
456
  this->CTest->PopulateCustomVector(mf,
Andy Cedilnik's avatar
Andy Cedilnik committed
457
                             "CTEST_CUSTOM_TESTS_IGNORE",
Andy Cedilnik's avatar
Andy Cedilnik committed
458
                             this->CustomTestsIgnore);
459
  this->CTest->PopulateCustomInteger(mf,
Andy Cedilnik's avatar
Andy Cedilnik committed
460
                             "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE",
Andy Cedilnik's avatar
Andy Cedilnik committed
461
                             this->CustomMaximumPassedTestOutputSize);
462
  this->CTest->PopulateCustomInteger(mf,
Andy Cedilnik's avatar
Andy Cedilnik committed
463
                             "CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE",
Andy Cedilnik's avatar
Andy Cedilnik committed
464
                             this->CustomMaximumFailedTestOutputSize);
Ken Martin's avatar
Ken Martin committed
465
466
467
}

//----------------------------------------------------------------------
468
int cmCTestTestHandler::PreProcessHandler()
Ken Martin's avatar
Ken Martin committed
469
{
Andy Cedilnik's avatar
Andy Cedilnik committed
470
  if ( !this->ExecuteCommands(this->CustomPreTest) )
Ken Martin's avatar
Ken Martin committed
471
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
472
    cmCTestLog(this->CTest, ERROR_MESSAGE,
Andy Cedilnik's avatar
Andy Cedilnik committed
473
      "Problem executing pre-test command(s)." << std::endl);
474
    return 0;
Ken Martin's avatar
Ken Martin committed
475
    }
476
477
  return 1;
}
Ken Martin's avatar
Ken Martin committed
478

479
480
481
//----------------------------------------------------------------------
int cmCTestTestHandler::PostProcessHandler()
{
Andy Cedilnik's avatar
Andy Cedilnik committed
482
  if ( !this->ExecuteCommands(this->CustomPostTest) )
Ken Martin's avatar
Ken Martin committed
483
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
484
    cmCTestLog(this->CTest, ERROR_MESSAGE,
Andy Cedilnik's avatar
Andy Cedilnik committed
485
      "Problem executing post-test command(s)." << std::endl);
486
    return 0;
Ken Martin's avatar
Ken Martin committed
487
    }
488
489
490
491
492
493
494
495
  return 1;
}

//----------------------------------------------------------------------
//clearly it would be nice if this were broken up into a few smaller
//functions and commented...
int cmCTestTestHandler::ProcessHandler()
{
Andy Cedilnik's avatar
Andy Cedilnik committed
496
497
498
499
  // Update internal data structure from generic one
  this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation"));
  this->SetUseUnion(cmSystemTools::IsOn(this->GetOption("UseUnion")));
  const char* val;
500
501
502
503
504
505
506
507
508
509
510
511
  val = this->GetOption("LabelRegularExpression");
  if ( val )
    {
    this->UseIncludeLabelRegExpFlag = true;
    this->IncludeLabelRegExp = val;
    }
  val = this->GetOption("ExcludeLabelRegularExpression");
  if ( val )
    {
    this->UseExcludeLabelRegExpFlag = true;
    this->ExcludeLabelRegularExpression = val;
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
512
513
514
515
516
517
518
519
520
521
522
523
  val = this->GetOption("IncludeRegularExpression");
  if ( val )
    {
    this->UseIncludeRegExp();
    this->SetIncludeRegExp(val);
    }
  val = this->GetOption("ExcludeRegularExpression");
  if ( val )
    {
    this->UseExcludeRegExp();
    this->SetExcludeRegExp(val);
    }
524
  
Andy Cedilnik's avatar
Andy Cedilnik committed
525
  this->TestResults.clear();
526
527
528
529
530

  cmCTestLog(this->CTest, HANDLER_OUTPUT,
             (this->MemCheck ? "Memory check" : "Test")
             << " project " << cmSystemTools::GetCurrentWorkingDirectory()
             << std::endl);
531
  if ( ! this->PreProcessHandler() )
Ken Martin's avatar
Ken Martin committed
532
    {
533
    return -1;
Ken Martin's avatar
Ken Martin committed
534
535
    }

Andy Cedilnik's avatar
Andy Cedilnik committed
536
  cmGeneratedFileStream mLogFile;
537
  this->StartLogFile((this->MemCheck ? "DynamicAnalysis" : "Test"), mLogFile);
Andy Cedilnik's avatar
Andy Cedilnik committed
538
  this->LogFile = &mLogFile;
Andy Cedilnik's avatar
Andy Cedilnik committed
539

Ken Martin's avatar
Ken Martin committed
540
541
542
  std::vector<cmStdString> passed;
  std::vector<cmStdString> failed;
  int total;
543
544
545
546
547

  //start the real time clock
  double clock_start, clock_finish;
  clock_start = cmSystemTools::GetTime();

548
  this->ProcessDirectory(passed, failed);
Ken Martin's avatar
Ken Martin committed
549

550
551
  clock_finish = cmSystemTools::GetTime();

Ken Martin's avatar
Ken Martin committed
552
553
554
555
  total = int(passed.size()) + int(failed.size());

  if (total == 0)
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
556
    if ( !this->CTest->GetShowOnly() )
Ken Martin's avatar
Ken Martin committed
557
      {
Andy Cedilnik's avatar
Andy Cedilnik committed
558
      cmCTestLog(this->CTest, ERROR_MESSAGE, "No tests were found!!!"
Andy Cedilnik's avatar
Andy Cedilnik committed
559
        << std::endl);
Ken Martin's avatar
Ken Martin committed
560
561
562
563
      }
    }
  else
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
564
565
    if (this->HandlerVerbose && passed.size() &&
      (this->UseIncludeRegExpFlag || this->UseExcludeRegExpFlag))
Ken Martin's avatar
Ken Martin committed
566
      {
Andy Cedilnik's avatar
Andy Cedilnik committed
567
      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
Andy Cedilnik's avatar
Andy Cedilnik committed
568
        << "The following tests passed:" << std::endl);
Ken Martin's avatar
Ken Martin committed
569
570
      for(std::vector<cmStdString>::iterator j = passed.begin();
          j != passed.end(); ++j)
Andy Cedilnik's avatar
Andy Cedilnik committed
571
        {
Andy Cedilnik's avatar
Andy Cedilnik committed
572
573
        cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "\t" << *j
          << std::endl);
Ken Martin's avatar
Ken Martin committed
574
575
576
577
578
579
580
581
        }
      }

    float percent = float(passed.size()) * 100.0f / total;
    if ( failed.size() > 0 &&  percent > 99)
      {
      percent = 99;
      }
582
    
583
584
585
586
587
588
589
590
    cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
               << static_cast<int>(percent + .5) << "% tests passed, "
               << failed.size() << " tests failed out of " 
               << total << std::endl); 
    double totalTestTime = 0;

    for(cmCTestTestHandler::TestResultsVector::size_type cc = 0;
        cc < this->TestResults.size(); cc ++ )
591
      {
592
593
      cmCTestTestResult *result = &this->TestResults[cc];
      totalTestTime += result->ExecutionTime;
594
      }
595
596
597
598
599
600
601
602
603
604
    
    char realBuf[1024];
    sprintf(realBuf, "%6.2f sec", (double)(clock_finish - clock_start));
    cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (real) = "
               << realBuf << "\n" );

    char totalBuf[1024];
    sprintf(totalBuf, "%6.2f sec", totalTestTime); 
    cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (parallel) = "
               <<  totalBuf << "\n" );
Ken Martin's avatar
Ken Martin committed
605

Andy Cedilnik's avatar
Andy Cedilnik committed
606
    if (failed.size())
Ken Martin's avatar
Ken Martin committed
607
      {
608
      cmGeneratedFileStream ofs;
609
610
611
612
613
614
615
      cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl
                 << "The following tests FAILED:" << std::endl);
      this->StartLogFile("TestsFailed", ofs);
      
      std::vector<cmCTestTestHandler::cmCTestTestResult>::iterator ftit;
      for(ftit = this->TestResults.begin();
          ftit != this->TestResults.end(); ++ftit)
Ken Martin's avatar
Ken Martin committed
616
        {
617
        if ( ftit->Status != cmCTestTestHandler::COMPLETED )
Ken Martin's avatar
Ken Martin committed
618
          {
619
620
621
622
623
624
          ofs << ftit->TestCount << ":" << ftit->Name << std::endl;
          cmCTestLog(this->CTest, HANDLER_OUTPUT, "\t" << std::setw(3)
                     << ftit->TestCount << " - " 
                     << ftit->Name.c_str() << " ("
                     << this->GetTestStatus(ftit->Status) << ")" 
                     << std::endl);
Ken Martin's avatar
Ken Martin committed
625
626
627
628
629
          }
        }
      }
    }

Andy Cedilnik's avatar
Andy Cedilnik committed
630
  if ( this->CTest->GetProduceXML() )
Ken Martin's avatar
Ken Martin committed
631
    {
632
    cmGeneratedFileStream xmlfile;
Andy Cedilnik's avatar
Andy Cedilnik committed
633
    if( !this->StartResultingXML(
634
          (this->MemCheck ? cmCTest::PartMemCheck : cmCTest::PartTest),
Andy Cedilnik's avatar
Andy Cedilnik committed
635
        (this->MemCheck ? "DynamicAnalysis" : "Test"), xmlfile) )
Ken Martin's avatar
Ken Martin committed
636
      {
Andy Cedilnik's avatar
Andy Cedilnik committed
637
638
      cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create "
        << (this->MemCheck ? "memory check" : "testing")
639
        << " XML file" << std::endl);
Andy Cedilnik's avatar
Andy Cedilnik committed
640
      this->LogFile = 0;
Ken Martin's avatar
Ken Martin committed
641
642
      return 1;
      }
643
    this->GenerateDartOutput(xmlfile);
Ken Martin's avatar
Ken Martin committed
644
645
    }

646
  if ( ! this->PostProcessHandler() )
Ken Martin's avatar
Ken Martin committed
647
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
648
    this->LogFile = 0;
649
    return -1;
Ken Martin's avatar
Ken Martin committed
650
    }
651
652

  if ( !failed.empty() )
Ken Martin's avatar
Ken Martin committed
653
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
654
    this->LogFile = 0;
655
    return -1;
Ken Martin's avatar
Ken Martin committed
656
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
657
  this->LogFile = 0;
658
  return 0;
Ken Martin's avatar
Ken Martin committed
659
660
}

661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
//----------------------------------------------------------------------
void cmCTestTestHandler::PrintLabelSummary()
{
  cmCTestTestHandler::ListOfTests::iterator it = this->TestList.begin();
  cmCTestTestHandler::TestResultsVector::iterator ri =
    this->TestResults.begin();
  std::map<cmStdString, double> labelTimes;
  std::set<cmStdString> labels;
  // initialize maps
  for(; it != this->TestList.end(); ++it)
    {
    cmCTestTestProperties& p = *it;
    if(p.Labels.size() != 0)
      {
      for(std::vector<std::string>::iterator l = p.Labels.begin();
          l !=  p.Labels.end(); ++l)
        {
        labels.insert(*l);
        labelTimes[*l] = 0;
        }
      }
    }
  it = this->TestList.begin();
  ri = this->TestResults.begin();
  // fill maps
  for(; it != this->TestList.end(); ++it, ++ri)
    {
    cmCTestTestProperties& p = *it;
    cmCTestTestResult &result = *ri;
    if(p.Labels.size() != 0)
      {
      for(std::vector<std::string>::iterator l = p.Labels.begin();
          l !=  p.Labels.end(); ++l)
        {
        labelTimes[*l] += result.ExecutionTime;
        }
      }
    }
  // now print times
  for(std::set<cmStdString>::const_iterator i = labels.begin();
      i != labels.end(); ++i)
    {
    cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTime in "
               << *i << " = " << labelTimes[*i] << " sec" );
    if ( this->LogFile )
        {
        *this->LogFile << "\nTime in " << *i << " = "
                       << labelTimes[*i] << " sec"  << std::endl;
        }
    }
}
712

713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
//----------------------------------------------------------------------
void cmCTestTestHandler::CheckLabelFilterInclude(cmCTestTestProperties& it)
{
  // if not using Labels to filter then return
  if (!this->UseIncludeLabelRegExpFlag )
    {
    return;
    }
  // if there are no labels and we are filtering by labels
  // then exclude the test as it does not have the label
  if(it.Labels.size() == 0 )
    {
    it.IsInBasedOnREOptions = false;
    return;
    }
  // check to see if the label regular expression matches
  bool found = false;  // assume it does not match
  // loop over all labels and look for match
  for(std::vector<std::string>::iterator l = it.Labels.begin();
      l !=  it.Labels.end(); ++l)
    {
    if(this->IncludeLabelRegularExpression.find(*l))
      {
      found = true;
      }
    }
  // if no match was found, exclude the test
  if(!found)
    {
    it.IsInBasedOnREOptions = false;
    }
}


//----------------------------------------------------------------------
void cmCTestTestHandler::CheckLabelFilterExclude(cmCTestTestProperties& it)
{
  // if not using Labels to filter then return
  if (!this->UseExcludeLabelRegExpFlag )
    {
    return;
    }
  // if there are no labels and we are excluding by labels
  // then do nothing as a no label can not be a match
  if(it.Labels.size() == 0 )
    {
    return;
    }
  // check to see if the label regular expression matches
  bool found = false;  // assume it does not match
  // loop over all labels and look for match
  for(std::vector<std::string>::iterator l = it.Labels.begin();
      l !=  it.Labels.end(); ++l)
    {
    if(this->ExcludeLabelRegularExpression.find(*l))
      {
      found = true;
      }
    }
  // if match was found, exclude the test
  if(found)
    {
    it.IsInBasedOnREOptions = false;
    }
}

//----------------------------------------------------------------------
void cmCTestTestHandler::CheckLabelFilter(cmCTestTestProperties& it)
{
  this->CheckLabelFilterInclude(it);
  this->CheckLabelFilterExclude(it);
}

786
//----------------------------------------------------------------------
787
void cmCTestTestHandler::ComputeTestList()
Ken Martin's avatar
Ken Martin committed
788
{
789
  this->TestList.clear(); // clear list of test
790
  this->GetListOfTests();
Andy Cedilnik's avatar
Andy Cedilnik committed
791
  cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size();
792
793
  // how many tests are in based on RegExp?
  int inREcnt = 0;
Andy Cedilnik's avatar
Andy Cedilnik committed
794
795
  cmCTestTestHandler::ListOfTests::iterator it;
  for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
796
    {
797
    this->CheckLabelFilter(*it);
Andy Cedilnik's avatar
Andy Cedilnik committed
798
    if (it->IsInBasedOnREOptions)
799
800
801
802
803
      {
      inREcnt ++;
      }
    }
  // expand the test list based on the union flag
Andy Cedilnik's avatar
Andy Cedilnik committed
804
  if (this->UseUnion)
805
806
807
808
809
810
811
    {
    this->ExpandTestsToRunInformation((int)tmsize);
    }
  else
    {
    this->ExpandTestsToRunInformation(inREcnt);
    }
812
  // Now create a final list of tests to run
Ken Martin's avatar
Ken Martin committed
813
  int cnt = 0;
814
  inREcnt = 0;
815
816
  std::string last_directory = ""; 
  ListOfTests finalList;
Andy Cedilnik's avatar
Andy Cedilnik committed
817
  for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
Ken Martin's avatar
Ken Martin committed
818
819
    {
    cnt ++;
Andy Cedilnik's avatar
Andy Cedilnik committed
820
    if (it->IsInBasedOnREOptions)
821
822
823
      {
      inREcnt++;
      }
824

Andy Cedilnik's avatar
Andy Cedilnik committed
825
    if (this->UseUnion)
Ken Martin's avatar
Ken Martin committed
826
      {
827
      // if it is not in the list and not in the regexp then skip
Andy Cedilnik's avatar
Andy Cedilnik committed
828
829
830
      if ((this->TestsToRun.size() &&
           std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt)
           == this->TestsToRun.end()) && !it->IsInBasedOnREOptions)
831
832
833
        {
        continue;
        }
Ken Martin's avatar
Ken Martin committed
834
      }
835
836
837
    else
      {
      // is this test in the list of tests to run? If not then skip it
Andy Cedilnik's avatar
Andy Cedilnik committed
838
839
      if ((this->TestsToRun.size() &&
           std::find(this->TestsToRun.begin(),
840
                     this->TestsToRun.end(), inREcnt)
Andy Cedilnik's avatar
Andy Cedilnik committed
841
           == this->TestsToRun.end()) || !it->IsInBasedOnREOptions)
842
843
844
845
        {
        continue;
        }
      }
846
847
848
849
850
851
852
    it->Index = cnt;  // save the index into the test list for this test
    finalList.push_back(*it);
    }
  // Save the total number of tests before exclusions
  this->TotalNumberOfTests = this->TestList.size();
  // Set the TestList to the final list of all test
  this->TestList = finalList;
853
  std::string::size_type max = this->CTest->GetMaxTestNameWidth();
Bill Hoffman's avatar
Bill Hoffman committed
854
  for (it = this->TestList.begin();
855
856
857
858
859
860
861
862
863
864
865
       it != this->TestList.end(); it ++ )
    {
    cmCTestTestProperties& p = *it;
    if(max < p.Name.size())
      {
      max = p.Name.size();
      }
    }
  if(static_cast<std::string::size_type>(this->CTest->GetMaxTestNameWidth()) 
     != max)
    {
Bill Hoffman's avatar
Bill Hoffman committed
866
    this->CTest->SetMaxTestNameWidth(static_cast<int>(max));
867
    }
868
869
870
871
872
873
874
}
 
bool cmCTestTestHandler::GetValue(const char* tag,
                                  int& value,
                                  std::ifstream& fin)
{
  std::string line;
Bill Hoffman's avatar
Bill Hoffman committed
875
  bool ret = true;
876
877
878
879
  cmSystemTools::GetLineFromStream(fin, line);
  if(line == tag)
    {
    fin >> value;
Bill Hoffman's avatar
Bill Hoffman committed
880
    ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
881
882
883
884
885
886
    }
  else
    {
    cmCTestLog(this->CTest, ERROR_MESSAGE,
               "parse error: missing tag: "
               << tag << " found [" << line << "]" << std::endl);
Bill Hoffman's avatar
Bill Hoffman committed
887
    ret = false;
888
    }
Bill Hoffman's avatar
Bill Hoffman committed
889
  return ret;
890
891
892
893
894
895
896
897
}

bool cmCTestTestHandler::GetValue(const char* tag,
                                  double& value,
                                  std::ifstream& fin)
{
  std::string line;
  cmSystemTools::GetLineFromStream(fin, line);
Bill Hoffman's avatar
Bill Hoffman committed
898
  bool ret = true;
899
900
901
  if(line == tag)
    {
    fin >> value;
Bill Hoffman's avatar
Bill Hoffman committed
902
    ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
903
904
905
906
907
908
    }
  else
    {
    cmCTestLog(this->CTest, ERROR_MESSAGE,
               "parse error: missing tag: "
               << tag << " found [" << line << "]" << std::endl);
Bill Hoffman's avatar
Bill Hoffman committed
909
    ret = false;
910
    }
Bill Hoffman's avatar
Bill Hoffman committed
911
  return ret;
912
913
914
915
916
917
918
919
}

bool cmCTestTestHandler::GetValue(const char* tag,
                                  bool& value,
                                  std::ifstream& fin)
{
  std::string line;
  cmSystemTools::GetLineFromStream(fin, line);
Bill Hoffman's avatar
Bill Hoffman committed
920
  bool ret = true;
921
922
  if(line == tag)
    {
923
924
925
926
927
928
929
930
931
#ifdef __HAIKU__
    int tmp = 0;
    fin >> tmp;
    value = false;
    if(tmp)
      {
      value = true;
      }
#else
932
    fin >> value;
933
#endif
Bill Hoffman's avatar
Bill Hoffman committed
934
    ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
935
936
937
938
939
940
    }
  else
    {
    cmCTestLog(this->CTest, ERROR_MESSAGE,
               "parse error: missing tag: "
               << tag << " found [" << line << "]" << std::endl);
Bill Hoffman's avatar
Bill Hoffman committed
941
    ret = false;
942
    }
Bill Hoffman's avatar
Bill Hoffman committed
943
  return ret;
944
945
946
947
948
949
950
951
}

bool cmCTestTestHandler::GetValue(const char* tag,
                                  size_t& value,
                                  std::ifstream& fin)
{
  std::string line;
  cmSystemTools::GetLineFromStream(fin, line);
Bill Hoffman's avatar
Bill Hoffman committed
952
  bool ret = true;
953
954
955
  if(line == tag)
    {
    fin >> value;
Bill Hoffman's avatar
Bill Hoffman committed
956
    ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
957
958
959
960
961
962
    }
  else
    { 
    cmCTestLog(this->CTest, ERROR_MESSAGE,
               "parse error: missing tag: "
               << tag << " found [" << line.c_str() << "]" << std::endl);
Bill Hoffman's avatar
Bill Hoffman committed
963
    ret = false;
964
    }
Bill Hoffman's avatar
Bill Hoffman committed
965
  return ret;
966
967
968
969
970
971
972
973
}

bool cmCTestTestHandler::GetValue(const char* tag,
                                  std::string& value,
                                  std::ifstream& fin)
{
  std::string line;
  cmSystemTools::GetLineFromStream(fin, line);
Bill Hoffman's avatar
Bill Hoffman committed
974
  bool ret = true;
975
976
  if(line == tag)
    {
Bill Hoffman's avatar
Bill Hoffman committed
977
    ret =  cmSystemTools::GetLineFromStream(fin, value);
978
979
980
981
982
983
    }
  else
    {
    cmCTestLog(this->CTest, ERROR_MESSAGE,
               "parse error: missing tag: "
               << tag << " found [" << line << "]" << std::endl);
Bill Hoffman's avatar
Bill Hoffman committed
984
    ret = false;
985
    }
Bill Hoffman's avatar
Bill Hoffman committed
986
  return ret;
987
988
}

989
//---------------------------------------------------------------------
990
void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
991
992
993
                                         std::vector<cmStdString> &failed)
{
  this->ComputeTestList();
Zach's avatar
Zach committed
994
995
996
  this->StartTest = this->CTest->CurrentTime();
  this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
  double elapsed_time_start = cmSystemTools::GetTime();
997

998
999
  cmCTestMultiProcessHandler parallel;
  parallel.SetCTest(this->CTest);
1000
1001
1002
1003
1004
1005
1006
1007
  parallel.SetParallelLevel(this->CTest->GetParallelLevel());
  parallel.SetTestHandler(this);

  *this->LogFile << "Start testing: "
    << this->CTest->CurrentTime() << std::endl
    << "----------------------------------------------------------"
    << std::endl;

1008
1009
  cmCTestMultiProcessHandler::TestSet depends;
  cmCTestMultiProcessHandler::TestMap tests;
1010
  cmCTestMultiProcessHandler::PropertiesMap properties;
1011
1012
1013
1014
  for (ListOfTests::iterator it = this->TestList.begin();
       it != this->TestList.end(); it ++ )
    { 
    cmCTestTestProperties& p = *it;
1015
    
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
    if(p.Depends.size())
      {
      for(std::vector<std::string>::iterator i = p.Depends.begin();
        i != p.Depends.end(); ++i)
        {
        for(ListOfTests::iterator it2 = this->TestList.begin();
            it2 != this->TestList.end(); it2 ++ )
          {
          if(it2->Name == *i)
            {
            depends.insert(it2->Index);
            break; // break out of test loop as name can only match 1
            }
          }
        }
      }
    tests[it->Index] = depends;
1033
    properties[it->Index] = &*it;
1034
    }
1035
  parallel.SetTests(tests, properties);
1036
1037
1038
  parallel.SetPassFailVectors(&passed, &failed);
  this->TestResults.clear();
  parallel.SetTestResults(&this->TestResults);
1039
1040
1041
1042
1043
1044
1045
1046
  if(this->CTest->GetShowOnly())
    {
    parallel.PrintTestList();
    }
  else
    {
    parallel.RunTests();
    }
Zach's avatar
Zach committed
1047
1048
1049
  this->EndTest = this->CTest->CurrentTime();
  this->EndTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
  this->ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start;
1050
1051
  *this->LogFile << "End testing: "
     << this->CTest->CurrentTime() << std::endl;
Ken Martin's avatar
Ken Martin committed
1052
1053
}

1054
//----------------------------------------------------------------------
Zach's avatar
Zach committed
1055
void cmCTestTestHandler::GenerateTestCommand(std::vector<std::string>&)
Ken Martin's avatar
Ken Martin committed
1056
1057
1058
{
}

1059
1060
//----------------------------------------------------------------------
void cmCTestTestHandler::GenerateDartOutput(std::ostream& os)
Ken Martin's avatar
Ken Martin committed
1061
{
Andy Cedilnik's avatar
Andy Cedilnik committed
1062
  if ( !this->CTest->GetProduceXML() )
Ken Martin's avatar
Ken Martin committed
1063
1064
1065
1066
    {
    return;
    }

1067
  this->CTest->StartXML(os, this->AppendXML);
Ken Martin's avatar
Ken Martin committed
1068
  os << "<Testing>\n"
Andy Cedilnik's avatar
Andy Cedilnik committed
1069
    << "\t<StartDateTime>" << this->StartTest << "</StartDateTime>\n"
1070
    << "\t<StartTestTime>" << this->StartTestTime << "</StartTestTime>\n"
Ken Martin's avatar
Ken Martin committed
1071
    << "\t<TestList>\n";
Andy Cedilnik's avatar
Andy Cedilnik committed
1072
1073
  cmCTestTestHandler::TestResultsVector::size_type cc;
  for ( cc = 0; cc < this->TestResults.size(); cc ++ )
Ken Martin's avatar
Ken Martin committed
1074
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
1075
1076
    cmCTestTestResult *result = &this->TestResults[cc];
    std::string testPath = result->Path + "/" + result->Name;
1077
    os << "\t\t<Test>" << cmXMLSafe(
Andy Cedilnik's avatar
Andy Cedilnik committed
1078
      this->CTest->GetShortPathToFile(testPath.c_str()))
Ken Martin's avatar
Ken Martin committed
1079
1080
1081
      << "</Test>" << std::endl;
    }
  os << "\t</TestList>\n";
Andy Cedilnik's avatar
Andy Cedilnik committed
1082
  for ( cc = 0; cc < this->TestResults.size(); cc ++ )
Ken Martin's avatar
Ken Martin committed
1083
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
1084
    cmCTestTestResult *result = &this->TestResults[cc];
1085
1086
    this->WriteTestResultHeader(os, result);
    os << "\t\t<Results>" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
1087
    if ( result->Status != cmCTestTestHandler::NOT_RUN )
Ken Martin's avatar
Ken Martin committed
1088
      {
Andy Cedilnik's avatar
Andy Cedilnik committed
1089
1090
      if ( result->Status != cmCTestTestHandler::COMPLETED ||
        result->ReturnValue )
Ken Martin's avatar
Ken Martin committed
1091
        {
Andy Cedilnik's avatar
Andy Cedilnik committed
1092
1093
        os << "\t\t\t<NamedMeasurement type=\"text/string\" "
          "name=\"Exit Code\"><Value>"
1094
          << cmXMLSafe(this->GetTestStatus(result->Status))
1095
          << "</Value>"
Andy Cedilnik's avatar
Andy Cedilnik committed
1096
1097
1098
          "</NamedMeasurement>\n"
          << "\t\t\t<NamedMeasurement type=\"text/string\" "
          "name=\"Exit Value\"><Value>"
1099
1100
          << result->ReturnValue
          << "</Value></NamedMeasurement>"
Andy Cedilnik's avatar
Andy Cedilnik committed
1101
          << std::endl;
Ken Martin's avatar
Ken Martin committed
1102
        }
Andy Cedilnik's avatar
Andy Cedilnik committed
1103
      os << result->RegressionImages;
Ken Martin's avatar
Ken Martin committed
1104
1105
      os << "\t\t\t<NamedMeasurement type=\"numeric/double\" "
        << "name=\"Execution Time\"><Value>"
1106
1107
        << result->ExecutionTime
        << "</Value></NamedMeasurement>\n";
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
      if(result->Reason.size())
        { 
        const char* reasonType = "Pass Reason";
        if(result->Status != cmCTestTestHandler::COMPLETED &&
           result->Status != cmCTestTestHandler::NOT_RUN)
          {
          reasonType = "Fail Reason";
          }
        os << "\t\t\t<NamedMeasurement type=\"text/string\" "
           << "name=\"" << reasonType << "\"><Value>"
           << cmXMLSafe(result->Reason)
           << "</Value></NamedMeasurement>\n";
        }
Andy Cedilnik's avatar
Andy Cedilnik committed
1121
      os
Ken Martin's avatar
Ken Martin committed
1122
1123
        << "\t\t\t<NamedMeasurement type=\"text/string\" "
        << "name=\"Completion Status\"><Value>"
1124
        << cmXMLSafe(result->CompletionStatus)
1125
        << "</Value></NamedMeasurement>\n";
Ken Martin's avatar
Ken Martin committed
1126
      }
1127
1128
1129
    os
      << "\t\t\t<NamedMeasurement type=\"text/string\" "
      << "name=\"Command Line\"><Value>"
1130
      << cmXMLSafe(result->FullCommandLine)
1131
      << "</Value></NamedMeasurement>\n";
1132
1133
1134
1135
1136
1137
1138
1139
    std::map<cmStdString,cmStdString>::iterator measureIt;
    for ( measureIt = result->Properties->Measurements.begin();
      measureIt != result->Properties->Measurements.end();
      ++ measureIt )
      {
      os
        << "\t\t\t<NamedMeasurement type=\"text/string\" "
        << "name=\"" << measureIt->first.c_str() << "\"><Value>"
1140
        << cmXMLSafe(measureIt->second)
1141
        << "</Value></NamedMeasurement>\n";
1142
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
1143
    os
Ken Martin's avatar
Ken Martin committed
1144
1145
      << "\t\t\t<Measurement>\n"
      << "\t\t\t\t<Value>";
1146
    os << cmXMLSafe(result->Output);
Ken Martin's avatar
Ken Martin committed
1147
1148
1149
    os
      << "</Value>\n"
      << "\t\t\t</Measurement>\n"
1150
      << "\t\t</Results>\n";
1151
    this->WriteTestResultFooter(os, result);
Ken Martin's avatar
Ken Martin committed
1152
1153
    }

Andy Cedilnik's avatar
Andy Cedilnik committed
1154