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