Improved test_run to fail when a test generates an error on create_ref or no_check_ref
[scilab.git] / scilab / modules / development_tools / macros / test_run.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 2007-2008 - INRIA - Pierre MARECHAL
3 // Copyright (C) 2009-2011 - DIGITEO - Michael Baudin
4 // Copyright (C) 2010-2012 - DIGITEO - Antoine ELIAS
5 // Copyright (C) 2011 - DIGITEO - Allan CORNET
6 //
7 // This file must be used under the terms of the CeCILL.
8 // This source file is licensed as described in the file COPYING, which
9 // you should have received as part of this distribution.  The terms
10 // are also available at
11 // http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
12
13 // test_run  --
14 //   Launch unit tests.
15
16 function test_run_result = test_run(varargin)
17     lhs     = argn(1);
18     rhs     = argn(2);
19     test_run_result = %f;
20     // =========================================================================
21     // Print test_run help
22     // =========================================================================
23     if (rhs >= 3) & (~ isempty(grep(varargin(3),"help"))) then
24         example = test_examples();
25         printf("%s\n",example);
26         return;
27     end
28
29     status.detailled_failures     = "";
30     status.testsuites             = [];
31     status.test_count             = 0;
32     status.test_passed_count      = 0;
33     status.test_failed_count      = 0;
34     status.test_skipped_count     = 0;
35     status.totalTime              = 0;
36     status.list                   = [];
37
38     params.longtime               = %f;
39     params.wanted_mode            = "";
40     params.error_output           = "check";
41     params.reference              = "check";
42     params.testTypes              = "all_tests";
43     params.skip_mat               = [];
44     params.tests_mat              = [];
45     params.test_passed_percent    = 0;
46     params.test_failed_percent    = 0;
47     params.test_skipped_percent   = 0;
48     params.full_summary           = %t;
49     params.show_diff              = %f;
50     params.show_error             = %f;
51
52     // =======================================================
53     // Management of the kind of tests to run and the options
54     // =======================================================
55     if rhs >= 3 then
56
57         option_mat = varargin(3);
58         if (check_option(option_mat, "unit_tests") & check_option(option_mat, "nonreg_tests")) | check_option(option_mat, "all_tests") then
59             params.testTypes = "all_tests";
60         elseif check_option(option_mat, "unit_tests") then
61             params.testTypes = "unit_tests";
62         elseif check_option(option_mat, "nonreg_tests") then
63             params.testTypes = "nonreg_tests";
64         end
65
66         option_mat = clean_option(option_mat, "unit_tests");
67         option_mat = clean_option(option_mat, "nonreg_tests");
68         option_mat = clean_option(option_mat, "all_tests");
69
70         // Skip tests
71         params.skip_mat     = assign_option(option_mat, "skip_tests", varargin(2), params.skip_mat);
72         option_mat          = clean_option(option_mat, "skip_tests");
73
74         // Mode
75         params.wanted_mode  = assign_option(option_mat, "mode_nw", "NW", params.wanted_mode);
76         option_mat          = clean_option(option_mat, "mode_nw");
77
78         params.wanted_mode  = assign_option(option_mat, "mode_nwni", "NWNI", params.wanted_mode);
79         option_mat          = clean_option(option_mat, "mode_nwni");
80
81         params.wanted_mode  = assign_option(option_mat, "mode_nwni_profiling", ["NWNI" "PROFILING"], params.wanted_mode);
82         option_mat          = clean_option(option_mat, "mode_nwni_profiling");
83
84         // Reference
85         params.reference    = assign_option(option_mat, "no_check_ref", "skip", params.reference);
86         option_mat          = clean_option(option_mat, "no_check_ref");
87
88         params.reference    = assign_option(option_mat, "create_ref", "create", params.reference);
89         option_mat          = clean_option(option_mat, "create_ref");
90
91         params.reference    = assign_option(option_mat, "list", "list", params.reference);
92         option_mat          = clean_option(option_mat, "list");
93
94         // Error Output
95         params.error_output = assign_option(option_mat, "no_check_error_output", "skip", params.error_output);
96         option_mat          = clean_option(option_mat, "no_check_error_output");
97
98         // Enable long-time tests
99         params.longtime     = assign_option(option_mat, "disable_lt", %f, params.longtime);
100         option_mat          = clean_option(option_mat, "disable_lt");
101
102         params.longtime     = assign_option(option_mat, "enable_lt", %t, params.longtime);
103         option_mat          = clean_option(option_mat, "enable_lt");
104
105         // Summary display management
106         params.full_summary = assign_option(option_mat, "short_summary", %f, params.full_summary);
107         option_mat          = clean_option(option_mat, "short_summary");
108
109         params.show_diff = assign_option(option_mat, "show_diff", %t, params.show_diff);
110         option_mat          = clean_option(option_mat, "show_diff");
111
112         params.show_error = assign_option(option_mat, "show_error", %t, params.show_error);
113         option_mat          = clean_option(option_mat, "show_error");
114
115         if option_mat <> [] then
116             printf("\nUnrecognized option(s): \n\n");
117             for i=1:size(option_mat, "*")
118                 printf("  - ""%s""\n", option_mat(i));
119             end
120
121             return;
122         end
123
124         if rhs == 4 then
125             params.exportFile = varargin(4);
126             // Doing the XML export, force the display of the error and diff
127             params.show_diff = %t;
128             params.show_error = %t;
129         end
130     end
131
132
133     if params.reference <> "list" & params.full_summary then
134         printf("   TMPDIR = %s\n",TMPDIR);
135         printf("\n");
136     end
137     // =======================================================
138     // Management of the tests to run
139     // =======================================================
140     if (rhs == 0) ..
141         | ((rhs == 1) & (varargin(1)==[])) ..
142         | (((rhs == 2)|(rhs == 3)|(rhs == 4)) & (varargin(1)==[]) & (varargin(2)==[])) then
143
144
145         // No input argument
146         // test_run()
147         // test_run([])
148         // => Launch each test of each module
149
150         module_list = getmodules();
151         module_list = gsort(module_list,"lr","i");
152
153         test_count = size(module_list,"*");
154         for i=1:test_count
155             if params.reference <> "list" then
156                 printf("   %03d/%03d - [%s] : \n\n", i, test_count, module_list(i));
157             end
158
159             params.tests_mat    = [];
160             params.moduleName   =  module_list(i);
161
162             result              = test_module(params);
163
164             if params.reference <> "list" then
165                 status.detailled_failures   = [status.detailled_failures; result.detailled_failures];
166                 status.testsuites(size(status.testsuites,"*")+1) = result.testsuite
167                 status.test_skipped_count   = status.test_skipped_count + result.test_skipped_count;
168
169                 // Do not take in account skipped tests
170                 status.test_count           = status.test_count + result.test_count - status.test_skipped_count;
171                 status.test_passed_count    = status.test_passed_count + result.test_passed_count;
172                 status.test_failed_count    = status.test_failed_count + result.test_failed_count;
173                 status.totalTime            = status.totalTime + result.totalTime;
174                 printf("\n");
175             else
176                 status.test_count           = status.test_count + result.test_count;
177                 status.list                 = [status.list; result.list];
178             end
179         end
180
181     elseif (rhs == 1) ..
182         | ((rhs == 2) & (varargin(2)==[])) ..
183         | ((rhs == 3) & (varargin(2)==[])) ..
184         | ((rhs == 4) & (varargin(2)==[])) ..
185         | ( ~ isempty(params.skip_mat)) then
186
187         // One input argument
188         // test_run(<module_name>)
189         // test_run([<module_name_1>,<module_name_2>])
190         // varargin(1) = [<module_name_1>,<module_name_2>]
191
192         module_mat = varargin(1);
193
194         test_count = size(module_mat,"*");
195         for i = 1:test_count
196             if params.reference <> "list" then
197                 printf("   %03d/%03d - [%s] : \n\n", i, test_count, module_mat(i));
198             end
199
200             params.tests_mat    = [];
201             params.moduleName   =  module_mat(i);
202
203             result              = test_module(params);
204
205             status.test_count   = status.test_count + result.test_count;
206             if params.reference <> "list" then
207                 status.detailled_failures       = [status.detailled_failures; result.detailled_failures];
208                 status.testsuites(size(status.testsuites,"*")+1) = result.testsuite
209
210                 status.test_skipped_count   = status.test_skipped_count + result.test_skipped_count;
211                 status.test_passed_count    = status.test_passed_count + result.test_passed_count;
212                 status.test_failed_count    = status.test_failed_count + result.test_failed_count;
213                 status.totalTime            = status.totalTime + result.totalTime;
214
215                 printf("\n");
216             else
217                 status.test_count           = status.test_count + result.test_count;
218                 status.list                 = [status.list; result.list];
219             end
220         end
221         // Do not take in account skipped tests
222         status.test_count = status.test_count - status.test_skipped_count;
223     elseif or(rhs==[2 3 4]) then
224         // Two input arguments
225         // test_run(<module_name>,<test_name>)
226         // test_run(<module_name>,[<test_name_1>,<test_name_2>] )
227
228         // varargin(1) = <module_name> ==> string 1x1
229         // varargin(2) = <test_name_1> ==> mat nl x nc
230
231         params.tests_mat    = varargin(2);
232         params.moduleName   = varargin(1);
233
234         if ((or(size(params.moduleName) <> [1,1])) & (params.tests_mat <> [])) then
235             example = test_examples();
236             err   = ["" ; msprintf(gettext("%s: Wrong size for input argument."),"test_run") ; "" ; example ];
237             printf("%s\n",err);
238             return;
239         end
240
241         result = test_module(params);
242
243         if params.reference <> "list" then
244             status.totalTime            = result.totalTime;
245             status.detailled_failures   = [status.detailled_failures; result.detailled_failures];
246             status.testsuites(size(status.testsuites,"*")+1) = result.testsuite
247             status.test_skipped_count   = status.test_skipped_count + result.test_skipped_count;
248
249             // Do not take in account skipped tests
250             status.test_count           = status.test_count + result.test_count - status.test_skipped_count;
251             status.test_passed_count    = status.test_passed_count + result.test_passed_count;
252             status.test_failed_count    = status.test_failed_count + result.test_failed_count;
253         else
254             status.test_count           = status.test_count + result.test_count;
255             status.list                 = [status.list; result.list];
256         end
257     else
258         error(msprintf(gettext("%s: Wrong number of input arguments."),"test_run"));
259     end
260
261     if params.reference == "list" then
262         test_count = size(status.list, "r");
263         for i=1:test_count
264             printf("   %4.d - [%s] %s\n", i, status.list(i, 1), status.list(i,2));
265         end
266         return;
267     end
268
269     // percent computation
270     if status.test_count <> 0 then
271         test_passed_percent  = status.test_passed_count  / status.test_count * 100;
272         test_failed_percent  = status.test_failed_count  / status.test_count * 100;
273     else
274         test_passed_percent  = 0;
275         test_failed_percent  = 0;
276     end
277
278     if isfield(params, "exportFile") then
279         exportToXUnitFormat(params.exportFile, status.testsuites);
280     end
281
282     if params.full_summary then
283         printf("\n");
284         printf("   --------------------------------------------------------------------------\n");
285         printf("   Summary\n\n");
286         printf("   tests           %4d - 100 %%\n", status.test_count);
287         printf("   passed          %4d - %3d %%\n", status.test_passed_count, test_passed_percent);
288         printf("   failed          %4d - %3d %%\n", status.test_failed_count, test_failed_percent);
289         printf("   skipped         %4d\n", status.test_skipped_count);
290         printf("   length             %4.2f sec\n", status.totalTime);
291         printf("   --------------------------------------------------------------------------\n");
292
293         if isfield(params, "exportFile") then
294             printf("   Export to          %s\n", params.exportFile);
295             printf("   --------------------------------------------------------------------------\n");
296         end
297
298         if status.test_failed_count > 0 then
299             printf("   Details\n\n");
300             printf("%s\n",status.detailled_failures);
301             printf("\n");
302             printf("   --------------------------------------------------------------------------\n");
303         end
304     else
305         printf("\n");
306         printf("   --------------------------------------------------------------------------\n");
307         printf("   Tests: %4d, ", status.test_count);
308         printf("   Passed: %4d, ", status.test_passed_count);
309         printf("   Failed: %4d, ", status.test_failed_count);
310         printf("   Skipped: %4d\n", status.test_skipped_count);
311         printf("   --------------------------------------------------------------------------\n");
312     end
313
314     //   Returns %t if no error has been detected
315     //   Returns %f if any error has been detected
316     test_run_result = (status.test_failed_count == 0);
317
318 endfunction
319
320
321
322 function status = test_module(_params)
323     name = splitModule(_params.moduleName);
324
325     if with_module(name(1)) then
326         // It's a scilab internal module
327         module.path = pathconvert(SCI + "/modules/" + name(1), %F);
328     elseif or(librarieslist() == "atomslib") & atomsIsLoaded(name(1)) then
329         // It's an ATOMS module
330         module.path = pathconvert(atomsGetLoadedPath(name(1)) , %F, %T);
331     elseif isdir(name(1)) then
332         // It's an external module
333         module.path = pathconvert(name(1), %F);
334     else
335         // It's an error
336         error(sprintf(gettext("%s is not an installed module or toolbox"), name(1)));
337     end
338
339     //get tests from path
340     my_types = ["unit_tests","nonreg_tests"];
341
342     directories = [];
343     for i=1:size(my_types,"*")
344         if (_params.testTypes == "all_tests") | (_params.testTypes == my_types(i)) then
345             directory_path = module.path + "/tests/" + my_types(i);
346             for j=2:size(name,"*")
347                 directory_path = directory_path + filesep() + name(j);
348             end
349
350             if isdir(directory_path) then
351                 directories = [directories;getDirectories(directory_path + filesep())];
352             end
353         end
354     end
355
356     tests = [];
357     if( _params.tests_mat == [])
358         for i=1:size(directories, "*")
359             currentDir = directories(i);
360             tests_mat = gsort(basename(listfiles(currentDir + filesep() + "*.tst")),"lr","i");
361
362             for j = 1:size(tests_mat, "*")
363                 if or(tests_mat(j) == _params.skip_mat) == %f then
364                     tests($+1, [1,2]) = [currentDir, tests_mat(j)];
365                 end
366             end
367         end
368     else
369         //not empty tests_mat
370         for i = 1:size(_params.tests_mat, "*")
371             bFind = %f;
372             for j = 1:size(directories, "*")
373                 currentDir = directories(j);
374                 testFile = currentDir + filesep() + _params.tests_mat(i) + ".tst";
375                 if isfile(testFile) then
376                     tests($+1, [1,2]) = [currentDir, _params.tests_mat(i)];
377                     bFind = %t;
378                 end
379             end
380
381             if bFind == %f then
382                 error(sprintf(gettext("The test ""%s"" is not available from the ""%s"" module"), _params.tests_mat(i), name(1)));
383             end
384         end
385     end
386
387     //initialize counter
388     detailled_failures      = "";
389     test_count          = size(tests, "r");
390     test_passed_count   = 0;
391     test_failed_count   = 0;
392     test_skipped_count  = 0;
393
394     moduleName          = _params.moduleName;
395     // Improve the display of the module
396     if isdir(moduleName) then
397         if part(moduleName,1:length(SCI)) == SCI then
398             moduleName = "SCI" + part(moduleName,length(SCI)+1:length(moduleName));
399         elseif part(moduleName,1:length(SCIHOME)) == SCIHOME then
400             moduleName = "SCIHOME" + part(moduleName,length(SCIHOME)+1:length(moduleName));
401         end
402     end
403
404     // For the XML export
405     testsuite.name=moduleName
406     testsuite.time=0
407     testsuite.tests=0
408     testsuite.errors=0
409
410     //don't test only return list of tests.
411     if _params.reference == "list" then
412         for i = 1:test_count
413             if size(name, "*") > 1 then
414                 displayModuleName = sprintf("%s", name(1));
415                 for j=2:size(name, "*")
416                     displayModuleName = displayModuleName + sprintf("|%s", name(j));
417                 end
418             else
419                 displayModuleName = sprintf("%s", name(1));
420             end
421             tests(i,1) = displayModuleName;
422         end
423         status.list         = tests;
424         status.test_count   = test_count;
425         return;
426     end
427
428     tic();
429     for i = 1:test_count
430         printf("   %03d/%03d - ",i, test_count);
431
432         if size(name, "*") > 1 then
433             displayModuleName = sprintf("[%s", name(1));
434             for j=2:size(name, "*")
435                 displayModuleName = displayModuleName + sprintf("|%s", name(j));
436             end
437             displayModuleName = displayModuleName + sprintf("] %s", tests(i,2));
438         else
439             displayModuleName = sprintf("[%s] %s", name(1), tests(i,2));
440         end
441
442         printf("%s", displayModuleName);
443         if length(displayModuleName) >= 50 then
444             printf(" ");
445         end
446         for j = length(displayModuleName):50
447             printf(".");
448         end
449
450         elapsedTimeBefore=toc();
451         result = test_single(_params, tests(i,1), tests(i,2));
452         elapsedTimeAfter=toc();
453
454
455         testsuite.tests = testsuite.tests + 1
456
457         testsuite.testcase(i).name=tests(i,2);
458         testsuite.testcase(i).time=elapsedTimeAfter-elapsedTimeBefore;
459         testsuite.testcase(i).skipped=(result.id >= 10) & (result.id < 20);
460
461         if result.id == 0 then
462             printf("passed\n");
463             test_passed_count = test_passed_count + 1;
464         else
465             msg = sprintf(result.message);
466             printf("%s \n", msg(1));
467             for kline = 2:size(msg, "*")
468                 printf(part(" ", 1:62) + "%s \n", msg(2));
469             end
470
471             if result.id < 10 then
472                 //failed
473                 test_failed_count = test_failed_count + 1;
474                 detailled_failures = [ detailled_failures ; sprintf("   TEST : [%s] %s", _params.moduleName, tests(i,2))];
475                 detailled_failures = [ detailled_failures ; sprintf("   %s", result.message) ];
476                 detailled_failures = [ detailled_failures ; result.details ];
477                 detailled_failures = [ detailled_failures ; "" ];
478
479                 testsuite.errors = testsuite.errors + 1
480                 testsuite.testcase(i).failure.type=result.message
481                 testsuite.testcase(i).failure.content=result.details
482
483             elseif (result.id >= 10) & (result.id < 20) then
484                 // skipped
485                 test_skipped_count = test_skipped_count + 1;
486             end
487         end
488
489         if ~isempty(result.warning) then
490             warning(result.warning);
491         end
492     end
493
494     status.totalTime = toc();
495
496     testsuite.time=status.totalTime;
497
498     clearglobal TICTOC;
499     status.test_passed_count  = test_passed_count;
500     status.test_failed_count  = test_failed_count;
501     status.test_skipped_count = test_skipped_count;
502
503     // Summary
504     status.test_count     = test_count;
505     status.detailled_failures   = detailled_failures;
506     status.testsuite   = testsuite;
507 endfunction
508
509 function status = test_single(_module, _testPath, _testName)
510     //option flag
511
512     skip          = %F;
513     interactive   = %F;
514     notyetfixed   = %F;
515     longtime      = %F;
516     reopened      = %F;
517     jvm           = %T;
518     graphic       = %F;
519     mpi           = %F;
520     execMode      = "";
521     platform      = "all";
522     language      = "any";
523     //try_catch     = %T; // Scilab 5.4.0
524     try_catch     = %f; // see comment about "dia(find(dia == '')) = [];" (~line 890)
525     error_output  = "check";
526     reference     = "check";
527     xcosNeeded    = %F;
528
529     //some paths
530     tmp_tst     = pathconvert( TMPDIR + "/" + _testName + ".tst", %F);
531     tmp_dia     = pathconvert( TMPDIR + "/" + _testName + ".dia.tmp", %F);
532     tmp_res     = pathconvert( TMPDIR + "/" + _testName + ".res", %F);
533     tmp_err     = pathconvert( TMPDIR + "/" + _testName + ".err", %F);
534     path_dia    = pathconvert( TMPDIR + "/" + _testName + ".dia", %F);
535     tmp_prof    = pathconvert( TMPDIR + "/" + _testName + ".prof", %F);
536
537     path_dia_ref  = _testPath + _testName + ".dia.ref";
538     // Reference file management OS by OS
539     if getos() == "Windows" then
540         [branch info] = getversion();
541         if info(2) == "x86" then // Look for a 32bits-specific reference file
542             altreffile  = [ _testPath + _testName + ".win.dia.ref" ; _testPath + _testName + ".win32.dia.ref" ];
543         else
544             altreffile  = [ _testPath + _testName + ".win.dia.ref" ];
545         end
546     elseif getos() == "Darwin" then
547         altreffile  = [ _testPath + _testName + ".unix.dia.ref" ; _testPath + _testName + ".macosx.dia.ref" ];
548     elseif getos() == "Linux" then
549         [branch info] = getversion();
550         if info(2) == "x86" then // Look for a 32bits-specific reference file
551             altreffile  = [ _testPath + _testName + ".unix.dia.ref" ; _testPath + _testName + ".linux.dia.ref" ; _testPath + _testName + ".linux32.dia.ref" ];
552         else
553             altreffile  = [ _testPath + _testName + ".unix.dia.ref" ; _testPath + _testName + ".linux.dia.ref" ];
554         end
555     else
556         altreffile  = [ _testPath + _testName + ".unix.dia.ref" ];
557     end
558
559     for i=1:size(altreffile,"*")
560         if isfile(altreffile(i)) then
561             path_dia_ref = altreffile(i);
562         end
563     end
564
565     //output structure
566     status.id = 0;
567     status.message = "";
568     status.details = "";
569     status.warning = "";
570
571     //Reset standard globals
572     rand("seed",0);
573     rand("uniform");
574
575     //load file
576     testFile = _testPath + _testName + ".tst";
577     sciFile = mgetl(testFile);
578
579     //read options
580     if ~isempty(grep(sciFile, "<-- NOT FIXED -->")) then
581         status.id = 10;
582         status.message = "skipped: not yet fixed";
583         return;
584     end
585
586     if ~isempty(grep(sciFile, "<-- REOPENED -->")) then
587         status.id = 10;
588         status.message = "skipped: Bug reopened";
589         return;
590     end
591
592     // platform
593     if ~isempty(grep(sciFile, "<-- WINDOWS ONLY -->")) & getos() <> "Windows" then
594         status.id = 10;
595         status.message = "skipped: Windows only";
596         return;
597     end
598
599     if ~isempty(grep(sciFile, "<-- UNIX ONLY -->")) & getos() == "Windows" then
600         status.id = 10;
601         status.message = "skipped: Unix only";
602         return;
603     end
604
605     if ~isempty(grep(sciFile, "<-- LINUX ONLY -->")) & getos() <> "Linux" then
606         status.id = 10;
607         status.message = "skipped: Linux only";
608         return;
609     end
610
611     if ~isempty(grep(sciFile, "<-- MACOSX ONLY -->")) & getos() <> "Darwin" then
612         status.id = 10;
613         status.message = "skipped: MacOSX only";
614         return;
615     end
616
617     // Test execution
618     if ~isempty(grep(sciFile, "<-- INTERACTIVE TEST -->")) then
619         status.id = 10;
620         status.message = "skipped: interactive test";
621         return;
622     end
623
624     if ~isempty(grep(sciFile, "<-- LONG TIME EXECUTION -->")) & ~_module.longtime then
625         status.id = 10;
626         status.message = "skipped: Long time duration";
627         return;
628     end
629
630     if ~isempty(grep(sciFile, "<-- TEST WITH GRAPHIC -->")) then
631         if or(_module.wanted_mode == "NWNI") then
632             status.id = 10;
633             status.message = "skipped: Test with graphic";
634             return;
635         end
636
637         graphic = %T;
638         jvm = %T;
639         execMode = "NW";
640     end
641
642     if or(_module.wanted_mode == "NWNI") & isempty(grep(sciFile, "<-- CLI SHELL MODE -->")) then
643         status.id = 10;
644         status.message = "skipped: not CLI SHELL MODE test";
645         return;
646     end
647
648     if ~isempty(grep(sciFile, "<-- JVM NOT MANDATORY -->")) then
649         status.warning = _("option ""JVM NOT MANDATORY"" is deprecated, please use ""CLI SHELL MODE"" instead");
650         jvm = %F;
651         execMode = "NWNI";
652     end
653
654     if ~isempty(grep(sciFile, "<-- CLI SHELL MODE -->")) then
655         jvm = %F;
656         execMode = "NWNI";
657     end
658
659     MPITestPos=grep(sciFile, "<-- MPI TEST")
660     if ~isempty(MPITestPos) then
661         mpi_node=msscanf(sciFile(MPITestPos), "// <-- MPI TEST %d -->")
662         if mpi_node == [] then
663             // No node found ? No worries, default to 2
664             mpi_node = 2
665         end
666         mpi = %t;
667         execMode = "NWNI";
668         reference = "skip";
669     end
670     clear MPITestPos
671
672     if ~isempty(grep(sciFile, "<-- XCOS TEST -->")) then
673         if or(_module.wanted_mode == "NWNI") then
674             status.id = 10;
675             status.message = "skipped: Test with xcos";
676             return;
677         end
678         xcosNeeded = %T;
679         jvm = %T;
680     end
681
682     // Language
683     if ~isempty(grep(sciFile, "<-- FRENCH IMPOSED -->")) then
684         language = "fr_FR";
685     end
686
687
688     if ~isempty(grep(sciFile, "<-- ENGLISH IMPOSED -->")) then
689         language = "en_US";
690     end
691
692     // Test building
693     if ~isempty(grep(sciFile, "<-- NO TRY CATCH -->")) then
694         try_catch = %F;
695     end
696
697     // Test result
698     if ~isempty(grep(sciFile, "<-- NO CHECK ERROR OUTPUT -->")) then
699         error_output = "skip";
700     end
701
702     if ~isempty(grep(sciFile, "<-- NO CHECK REF -->")) then
703         reference = "skip";
704     end
705
706     //build real test file
707
708     // Do some modification in tst file
709     //replace "pause,end" by "bugmes();quit;end"
710     sciFile = strsubst(sciFile, "pause,end", "bugmes();quit;end");
711     sciFile = strsubst(sciFile, "pause, end", "bugmes();quit;end");
712     sciFile = strsubst(sciFile, "pause;end", "bugmes();quit;end");
713     sciFile = strsubst(sciFile, "pause; end", "bugmes();quit;end");
714
715     //to avoid suppression of input --> with prompts
716     sciFile = strsubst(sciFile, "--> ", "@#> ");
717     //remove halt calls
718     sciFile = strsubst(sciFile, "halt();", "");
719
720     // Build test header
721     head = [
722     "// <-- HEADER START -->";
723     "mode(3);" ;
724     "lines(28,72);";
725     "lines(0);" ;
726     "function []=bugmes(), printf(''error on test'');endfunction"
727     "function %onprompt" ;
728     "   [msg, num] = lasterror();" ;
729     "   if (num <> 0) then" ;
730     "       bugmes()" ;
731     "   end" ;
732     "   quit;" ;
733     "endfunction" ;
734     "predef(''all'');";
735     "tmpdirToPrint = msprintf(''TMPDIR1=''''%s'''';//\n'',TMPDIR);"
736     ];
737
738     if xcosNeeded then
739         head = [
740         head;
741         "prot=funcprot(); funcprot(0);";
742         "loadXcosLibs(); loadScicos();";
743         "funcprot(prot);";
744         ];
745     end
746
747     if try_catch then
748         head = [ head ; "try" ];
749     end
750
751     head = [
752     head;
753     "diary(''" + tmp_dia + "'');";
754     "printf(''%s\n'',tmpdirToPrint);";
755     "// <-- HEADER END -->"
756     ];
757
758     // Build test footer
759     tail = [ "// <-- FOOTER START -->" ];
760
761     if try_catch then
762         tail = [
763         tail;
764         "catch";
765         "   errmsg = ""<--""+""Error on the test script file""+""-->"";";
766         "   printf(""%s\n"",errmsg);";
767         "   lasterror()";
768         "end";
769         ];
770     end
771
772     tail = [ tail; "diary(0);" ];
773
774     if graphic then
775         tail = [ tail; "xdel(winsid());sleep(1000);" ];
776     end
777
778     tail = [ tail; "exit(0);" ; "// <-- FOOTER END -->" ];
779
780     //Build final test
781     sciFile = [head ; sciFile ; tail];
782
783
784     //Build command to execute
785
786     //scilab path
787     if (getos() <> "Windows") & ~isfile(SCI+"/bin/scilab") then
788         SCI_BIN = strsubst(SCI,"share/scilab","");
789     else
790         SCI_BIN = SCI;
791     end
792
793     //mode
794     valgrind_opt = "";
795     winbin = "wscilex.exe";
796     if _module.wanted_mode == "NW" then
797         mode_arg = "-nw";
798     elseif _module.wanted_mode == "NWNI" then
799         winbin = "scilex.exe";
800         mode_arg = "-nwni";
801     elseif _module.wanted_mode == ["NWNI" "PROFILING"] && getos() == "Linux" then
802         mode_arg = "-nwni -profiling";
803         valgrind_opt = "SCILAB_VALGRIND_OPT=""--log-file=" + tmp_prof + " """;
804     else
805         if execMode == "NWNI" then
806             winbin = "scilex.exe";
807             mode_arg = "-nwni";
808         elseif execMode == "NW" then
809             mode_arg = "-nw";
810         else
811             mode_arg = "-nw";
812         end
813     end
814
815     if mpi == %t then
816         prefix_bin="mpirun -c " + string(mpi_node) + "  -bynode"
817     else
818         prefix_bin=""
819     end
820
821
822     //language
823     if language == "any" then
824         language_arg = "";
825     else
826         language_arg = "-l "+ language;
827     end
828
829     loader_path = pathconvert(fullfile(_module.moduleName, "loader.sce"), %f);
830
831     // Build final command
832     if getos() == "Windows" then
833         if (isdir(_module.moduleName) & isfile(loader_path)) // external module not in Scilab
834             test_cmd = "( """ + SCI_BIN + "\bin\" + winbin + """" + " " + mode_arg + " " + language_arg + " -nb -e ""exec(""""" + loader_path + """"");exec(""""" + tmp_tst + """"", -1);"" > """ + tmp_res + """ ) 2> """ + tmp_err + """";
835         else // standard module
836             test_cmd = "( """ + SCI_BIN + "\bin\" + winbin + """" + " " + mode_arg + " " + language_arg + " -nb -e ""exec(""""" + tmp_tst + """"", -1);"" > """ + tmp_res + """ ) 2> """ + tmp_err + """";
837         end
838     else
839         if (isdir(_module.moduleName) & isfile(loader_path))
840             test_cmd = "( " + valgrind_opt + " " + SCI_BIN + "/bin/scilab " + mode_arg + " " + language_arg + " -nb -e ""exec(''" + loader_path + "'');exec(''" + tmp_tst +"'');""" + " > " + tmp_res + " ) 2> " + tmp_err;
841         else
842             test_cmd = "( " + valgrind_opt + " " + prefix_bin + " " + SCI_BIN + "/bin/scilab " + mode_arg + " " + language_arg + " -nb -f " + tmp_tst + " > " + tmp_res + " ) 2> " + tmp_err;
843         end
844     end
845
846     //clean previous tmp files
847     if isfile(tmp_tst) then
848         deletefile(tmp_tst);
849     end
850
851     if isfile(tmp_dia) then
852         deletefile(tmp_dia);
853     end
854
855     if isfile(tmp_res) then
856         deletefile(tmp_res);
857     end
858
859     if isfile(tmp_err) then
860         deletefile(tmp_err);
861     end
862
863     //create tmp test file
864     mputl(sciFile, tmp_tst);
865
866     //execute test
867     returnStatus = host(test_cmd);
868     //Check return status
869     if (returnStatus <> 0)
870         status.id = 5;
871         status.message = "failed: Slave Scilab exited with error code " + string(returnStatus);
872         return;
873     end
874
875     //Check errors
876     if (error_output == "check") & (_module.error_output == "check") then
877         if getos() == "Darwin" then
878             tmp_errfile_info = fileinfo(tmp_err);
879             msg = "Picked up _JAVA_OPTIONS:"; // When -Djava.awt.headless=false is forced for example
880
881             if ~isempty(tmp_errfile_info) then
882                 txt = mgetl(tmp_err);
883                 toRemove = grep(txt, msg);
884                 txt(toRemove) = [];
885                 if isempty(txt) then
886                     deletefile(tmp_err);
887                 else // Remove messages due to JOGL2 RC8
888                     toRemove = grep(txt, "__NSAutoreleaseNoPool()");
889                     txt(toRemove) = [];
890                     if isempty(txt) then
891                         deletefile(tmp_err);
892                     end
893                 end
894             end
895         end
896
897         if getos() == "Linux" then // Ignore JOGL2 debug message
898             tmp_errfile_info = fileinfo(tmp_err);
899             msg = "Error: unable to open display (null)"
900
901             if ~isempty(tmp_errfile_info) then
902                 txt = mgetl(tmp_err);
903                 txt(txt==msg) = [];
904                 if isempty(txt) then
905                     deletefile(tmp_err);
906                 else // Remove messages due to warning message from library
907                     toRemove = grep(txt, "libEGL warning: failed to find any driver");
908                     txt(toRemove) = [];
909
910                     if ~isempty(txt) then
911                         toRemove = grep(txt, "extension ""RANDR"" missing on display");
912                         txt(toRemove) = [];
913                     end
914
915                     if isempty(txt) then
916                         deletefile(tmp_err);
917                     end
918                 end
919             end
920         end
921
922         if getos() == "Windows" then // Ignore JOGL 2.2.4 debug message
923             tmp_errfile_info = fileinfo(tmp_err);
924             msg = "Info: GLReadBufferUtil.readPixels: pre-exisiting GL error 0x500";
925
926             if ~isempty(tmp_errfile_info) then
927                 txt = mgetl(tmp_err);
928                 txt(txt==msg) = [];
929                 if isempty(txt) then
930                     deletefile(tmp_err);
931                 else // Ignore JOGL 2.1.4 debug message
932                     msg = "Info: GLDrawableHelper.reshape: pre-exisiting GL error 0x500";
933                     txt(txt==msg) = [];
934                     if isempty(txt) then
935                         deletefile(tmp_err);
936                     end
937                 end
938             end
939         end
940
941         if isfile(tmp_prof) then
942             txt = mgetl(tmp_prof);
943             if grep(txt($), "ERROR SUMMARY: 0 errors from 0 contexts") then
944                 deletefile(tmp_prof);
945             else
946                 status.id = 5;
947                 status.message = "failed: Valgrind error detected";
948                 status.details = checkthefile(tmp_prof);
949                 return;
950             end
951         end
952
953
954         tmp_errfile_info = fileinfo(tmp_err);
955
956         if isfile(tmp_err) & tmp_errfile_info(1) <> 0 then
957             status.id = 5;
958             status.message = "failed: error_output not empty\n   Use ''no_check_error_output'' option to disable this check.";
959             status.details = checkthefile(tmp_err);
960             return;
961         end
962     end
963
964     //Process output files
965
966     //Get the dia file
967     if isfile(tmp_dia) then
968         dia = mgetl(tmp_dia);
969     else
970         status.id = 6;
971         status.message = "failed: Cannot find the dia file: " + tmp_dia + "\nCheck if the Scilab used correctly starts";
972         status.details = checkthefile(tmp_dia);
973         return;
974     end
975
976     // To get TMPDIR value
977     tmpdir1_line = grep(dia, "TMPDIR1");
978     execstr(dia(tmpdir1_line));
979
980     //Check for execution errors
981     if try_catch & grep(dia,"<--Error on the test script file-->") <> [] then
982         details = [ checkthefile(tmp_dia); ..
983         launchthecommand(testFile)];
984         status.id = 3;
985         status.message = "failed: premature end of the test script";
986         status.details = details;
987         if params.show_error == %t then
988             status.details = [ status.details; dia($-10:$) ]
989         end
990
991         return;
992     end
993
994     // Remove Header and Footer
995     dia = remove_headers(dia);
996
997     // Remove empty lines
998     // In scilab 5, the test is executed in a try/catch
999     // which remove empty lines.
1000     // In scilab 6, we can't execute the test in a try/catch
1001     // because it will be parsed first then executed
1002     // so the diary will contain all the script followed by the display
1003     // of the execution.
1004     // The try/catch is desactived ~line 513 by "try_catch     = %f;"
1005     // and the following line remove empty lines to reproduce the old operation.
1006     dia(find(dia == "")) = [];
1007
1008     //Check for execution errors
1009     dia_tmp = dia;
1010
1011     // remove commented lines
1012     dia_tmp(grep(dia_tmp, "//")) = [];
1013
1014     if try_catch & grep(dia_tmp, "!--error") <> [] then
1015         details = [ checkthefile(tmp_dia); ..
1016         launchthecommand(testFile) ];
1017         status.id = 1;
1018         status.message = "failed: the string (!--error) has been detected";
1019         status.details = details;
1020         return;
1021     end
1022
1023
1024     if grep(dia_tmp,"error on test")<>[] then
1025         details = [ checkthefile(tmp_dia); ..
1026         launchthecommand(testFile) ];
1027         status.id = 2;
1028         status.message = "failed: one or several tests failed";
1029         status.details = details;
1030         if params.show_error == %t then
1031             status.details = [ status.details; dia($-min(10, size(dia, "*")-1):$) ]
1032         end
1033         return;
1034     end
1035
1036
1037     if tmpdir1_line == [] then
1038         status.id = 6;
1039         status.message = "failed: the dia file is not correct";
1040         status.details = checkthefile(tmp_dia);
1041         return;
1042     end
1043
1044
1045     // Check the reference file only if check_ref (i.e. for the whole
1046     // test sequence) is true and this_check_ref (i.e. for the specific current .tst)
1047     // is true.
1048
1049     if (reference=="check") & (_module.reference=="check")  then
1050         if isfile(path_dia_ref) == %f then
1051             status.id = 5;
1052             status.message = "failed: the ref file doesn''t exist\n   Use ''no_check_ref'' option to disable this check.";
1053             status.details = createthefile(path_dia_ref);
1054             return;
1055         end
1056     end
1057
1058     // Comparaison ref <--> dia
1059
1060     if ( (reference=="check") & (_module.reference=="check") ) | (_module.reference=="create") then
1061         //  Do some modification in  dia file
1062
1063         dia(grep(dia, "printf(''%s\n'',tmpdirToPrint);")) = [];
1064         dia(grep(dia, "TMPDIR1")) = [];
1065         dia(grep(dia, "diary(0)")) = [];
1066
1067         if getos() == "Darwin" then // TMPDIR is a symblic link
1068             dia = strsubst(dia,"/private" + TMPDIR1, "TMPDIR");
1069             dia = strsubst(dia,"/private" + TMPDIR, "TMPDIR");
1070         end
1071         dia = strsubst(dia,TMPDIR ,"TMPDIR");
1072         dia = strsubst(dia,TMPDIR1, "TMPDIR");
1073
1074         if getos() == "Windows" then
1075             dia = strsubst(dia, strsubst(TMPDIR, "\","/"), "TMPDIR");
1076             dia = strsubst(dia, strsubst(TMPDIR1, "\","/"), "TMPDIR");
1077             dia = strsubst(dia, strsubst(TMPDIR, "/","\"), "TMPDIR");
1078             dia = strsubst(dia, strsubst(TMPDIR1, "/","\"), "TMPDIR");
1079             dia = strsubst(dia, strsubst(getshortpathname(TMPDIR), "\","/"), "TMPDIR");
1080             dia = strsubst(dia, strsubst(getshortpathname(TMPDIR1), "\","/"), "TMPDIR");
1081             dia = strsubst(dia, getshortpathname(TMPDIR), "TMPDIR");
1082             dia = strsubst(dia, getshortpathname(TMPDIR1), "TMPDIR");
1083         end
1084
1085         dia = strsubst(dia, SCI, "SCI");
1086
1087         if getos() == "Windows" then
1088             dia = strsubst(dia, strsubst(SCI, "\","/"), "SCI");
1089             dia = strsubst(dia, strsubst(SCI, "/","\"), "SCI");
1090             dia = strsubst(dia, strsubst(getshortpathname(SCI), "\","/"), "SCI");
1091             dia = strsubst(dia, getshortpathname(SCI), "SCI");
1092         end
1093
1094         //suppress the prompts
1095         dia = strsubst(dia, "--> ", "");
1096         dia = strsubst(dia, "@#> ", "--> ");
1097         dia = strsubst(dia, "-1-> ", "");
1098
1099         //standardise  number display
1100
1101         // strsubst(dia, " .", "0.");
1102         // strsubst(dia, "-.", "-0.")
1103         // strsubst(dia, "E+", "D+");
1104         // strsubst(dia, "E-", "D-");
1105
1106         //not to change the ref files
1107         dia = strsubst(dia ,"bugmes();return", "bugmes();quit");
1108
1109         if _module.reference=="create" then
1110             // Delete previous .dia.ref file
1111             if isfile(path_dia_ref) then
1112                 deletefile(path_dia_ref)
1113             end
1114
1115             mputl(dia, path_dia_ref);
1116             status.id = 20;
1117             status.message = "passed: ref created";
1118             return;
1119         else
1120             // write down the resulting dia file
1121             mputl(dia, path_dia);
1122
1123             //Check for diff with the .ref file
1124             [u,ierr] = mopen(path_dia_ref, "r");
1125             if ierr== 0 then //ref file exists
1126                 ref=mgetl(u);
1127                 mclose(u)
1128
1129                 // suppress blank (diff -nw)
1130                 dia = strsubst(dia, " ", "")
1131                 ref = strsubst(ref, " ", "")
1132
1133                 dia(find(dia == "")) = [];
1134                 ref(find(ref == "")) = [];
1135
1136                 dia(find(dia == "")) = [];
1137                 ref(find(ref == "")) = [];
1138
1139                 dia(find(part(dia, (1:2)) == "//")) = [];
1140                 ref(find(part(ref, (1:2)) == "//")) = [];
1141
1142                 if or(ref <> dia) then
1143                     status.id = 4;
1144                     status.message = "failed: dia and ref are not equal";
1145                     status.details = comparethefiles(path_dia, path_dia_ref);
1146                     return;
1147                 end
1148
1149             else
1150                 error(sprintf(gettext("The ref file (%s) doesn''t exist"), path_dia_ref));
1151             end
1152         end
1153     end
1154 endfunction
1155
1156 // checkthefile
1157 function msg = checkthefile( filename )
1158     // Returns a 2-by-1 matrix of strings, containing a message such as:
1159     //   Check the following file :
1160     //   - C:\path\scilab\modules\optimization\tests\unit_testseldermeadeldermead_configure.tst
1161     // Workaround for bug #4827
1162     msg(1) = "   Check the following file :"
1163     msg(2) = "   - "+filename
1164     if params.show_error == %t then
1165         msg=[msg; mgetl(filename)]
1166     end
1167
1168 endfunction
1169
1170 // launchthecommand
1171 function msg = launchthecommand( filename )
1172     // Returns a 2-by-1 matrix of strings, containing a message such as:
1173     //   Or launch the following command :
1174     //   - exec("C:\path\scilab\modules\optimization\tests\unit_testseldermeadeldermead_configure.tst")
1175     // Workaround for bug #4827
1176     msg(1) = "   Or launch the following command :"
1177     msg(2) = "   - exec(""" + fullpath(filename) + """);"
1178 endfunction
1179
1180 // => remove header from the diary txt
1181 function dia_out = remove_headers(dia_in)
1182     dia_out = dia_in;
1183     body_start = grep(dia_out,"// <-- HEADER END -->");
1184     if body_start <> [] then
1185         dia_out(1:body_start(1)) = [];
1186     end
1187
1188     body_end   = grep(dia_out,"// <-- FOOTER START -->");
1189     if body_end <> [] then
1190         [dia_nl,dia_nc] = size(dia);
1191         dia_out(body_end(1):dia_nl) = [];
1192     end
1193 endfunction
1194
1195 //createthefile
1196 function msg = createthefile ( filename )
1197     // Returns a 2-by-1 matrix of strings, containing a message such as:
1198     //   Add or create the following file :
1199     //   - C:\path\scilab\modules\optimization\tests\unit_testseldermeadeldermead_configure.dia.ref
1200     // Workaround for bug #4827
1201     msg(1) = "   Add or create the following file: "
1202     msg(2) = "   - "+filename
1203 endfunction
1204
1205 // comparethefiles
1206 function msg = comparethefiles ( filename1 , filename2 )
1207     // Returns a 3-by-1 matrix of strings, containing a message such as:
1208     //   Compare the following files :
1209     //   - C:\path\scilab\modules\optimization\tests\unit_testseldermeadeldermead_configure.dia
1210     //   - C:\path\scilab\modules\optimization\tests\unit_testseldermeadeldermead_configure.dia.ref
1211     // Workaround for bug #4827
1212     msg(1) = "   Compare the following files:"
1213     msg(2) = "   - "+filename1
1214     msg(3) = "   - "+filename2
1215     if params.show_diff == %t then
1216         if getos() == "Windows" then
1217             diffTool = SCI + "\tools\diff\diff.exe";
1218         else
1219             diffTool = "diff";
1220         end
1221         targetFile=TMPDIR + filesep() + "tempdiff.diff";
1222         unix(diffTool + " -u " + filename1 + " " + filename2 + " > " + targetFile);
1223         // unix_g is failing to return the output into a variable
1224         msg=[msg; mgetl(targetFile)]
1225         deletefile(targetFile);
1226     end
1227 endfunction
1228
1229 function directories = getDirectories(directory)
1230     directories = directory;
1231     items = gsort(listfiles(directory),"lr","i");
1232
1233     for i=1:size(items,"*")
1234         if isdir(directory + items(i)) then
1235             directories = [directories; getDirectories(directory + items(i) + filesep())];
1236         end
1237     end
1238 endfunction
1239
1240 function name = splitModule(name)
1241     if ~isempty( regexp(stripblanks(name),"/\|/") ) then
1242         name = stripblanks( strsubst( strsplit(name,regexp(stripblanks(name),"/\|/")) , "/\|$/","","r" ) );
1243     end
1244 endfunction
1245
1246 function example = test_examples()
1247     example = [ sprintf("Examples :\n\n") ];
1248     example = [ example ; sprintf("// Launch all tests\n") ];
1249     example = [ example ; sprintf("test_run();\n") ];
1250     example = [ example ; sprintf("test_run([]);\n") ];
1251     example = [ example ; sprintf("test_run([],[]);\n") ];
1252     example = [ example ; "" ];
1253     example = [ example ; sprintf("// Test one or several module\n") ];
1254     example = [ example ; sprintf("test_run(''core'');\n") ];
1255     example = [ example ; sprintf("test_run(''core'',[]);\n") ];
1256     example = [ example ; sprintf("test_run([''core'',''string'']);\n") ];
1257     example = [ example ; "" ];
1258     example = [ example ; sprintf("// Launch one or several test in a specified module\n") ];
1259     example = [ example ; sprintf("test_run(''core'',[''trycatch'',''opcode'']);\n") ];
1260     example = [ example ; "" ];
1261     example = [ example ; sprintf("// With options\n") ];
1262     example = [ example ; sprintf("test_run([],[],''no_check_ref'');\n") ];
1263     example = [ example ; sprintf("test_run([],[],''no_check_error_output'');\n") ];
1264     example = [ example ; sprintf("test_run([],[],''create_ref'');\n") ];
1265     example = [ example ; sprintf("test_run([],[],''list'');\n") ];
1266     example = [ example ; sprintf("test_run([],[],''help'');\n") ];
1267     example = [ example ; sprintf("test_run([],[],[''no_check_ref'',''mode_nw'']);\n") ];
1268     example = [ example ; "" ];
1269 endfunction
1270
1271 function newOption = clean_option(var, option)
1272     newOption = var;
1273     newOption(newOption == option) = [];
1274 endfunction
1275
1276 function result = check_option(var, option)
1277     result = or(var == option);
1278 endfunction
1279
1280 function value = assign_option(var, option, truevalue, falsevalue)
1281     if check_option(var, option) then
1282         value = truevalue;
1283     else
1284         value = falsevalue;
1285     end
1286 endfunction
1287
1288
1289 function exportToXUnitFormat(exportToFile, testsuites)
1290
1291     if isfile(exportToFile) then
1292         // File already existing. Append the results
1293         doc = xmlRead(exportToFile);
1294         appendIntoFile = %t;
1295         node = xmlXPath(doc, "//testsuites");
1296         if node.size == 0 then
1297             error(msprintf(gettext("The file ''%s'' is not following the XUnit XML format. Root tag expected ''testsuites''.\n"),exportToFile))
1298         end
1299     else
1300         doc = xmlDocument(exportToFile);
1301
1302         appendIntoFile = %f;
1303     end
1304     root = xmlElement(doc, "testsuites");
1305
1306     for i=1:size(testsuites, "*") // Export module by module
1307         module = testsuites(i);
1308         testsuite = xmlElement(doc,"testsuite");
1309         testsuite.attributes.name = module.name;
1310
1311         testsuite.attributes.time  = string(module.time);
1312
1313         testsuite.attributes.tests = string(module.tests);
1314         testsuite.attributes.errors = string(module.errors);
1315
1316         for j=1:size(module.testcase,"*") // Export test by test
1317             testsuite.children(j) = xmlElement(doc,"testcase");
1318             unitTest = module.testcase(j);
1319             testsuite.children(j).attributes.name = unitTest.name;
1320             testsuite.children(j).attributes.time = string(unitTest.time);
1321             testsuite.children(j).attributes.classname = getversion()+"."+module.name;
1322             if isfield(unitTest,"failure") & size(unitTest.failure,"*") >= 1 then
1323                 testsuite.children(j).children(1) = xmlElement(doc,"failure");
1324                 testsuite.children(j).children(1).attributes.type = unitTest.failure.type;
1325                 content = unitTest.failure.content;
1326                 for kL=1:size(content, "*")
1327                     ampIdx = strindex(content(kL), "&");
1328                     while ~isempty(ampIdx)
1329                         cur = ampIdx(1);
1330                         ampIdx(1) = [];
1331                         if or(part(content(kL), (cur+1):(cur+3))==["gt;" "lt"]) then
1332                             // Ignored
1333                         else
1334                             content(kL) = part(content(kL), 1:cur) + "amp;" + part(content(kL), (cur+1):$);
1335                             ampIdx = strindex(part(content(kL), (cur+1):$), "&");
1336                         end
1337                     end
1338                 end
1339                 testsuite.children(j).children(1).content = content;
1340             elseif unitTest.skipped then
1341                 testsuite.children(j).children(1) = xmlElement(doc,"skipped");
1342             end
1343         end
1344
1345         if appendIntoFile then
1346             // We will add the new elements into 'testsuites'
1347             c=node(1).children;
1348             nb=size(c,"*");
1349             c(nb + 1)=testsuite; // Add the new results into the list of results
1350             root.children=c;
1351         else
1352             root.children(i)=testsuite
1353         end
1354     end // list of modules
1355
1356     doc.root=root
1357
1358     xmlWrite(doc);
1359 endfunction