1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Base options for testing tools.
19 private import parser_util
22 redef class ToolContext
24 var opt_full
= new OptionBool("Process also imported modules", "--full")
26 var opt_output
= new OptionString("Output name (default is 'nitunit.xml')", "-o", "--output")
28 var opt_dir
= new OptionString("Working directory (default is '.nitunit')", "--dir")
30 var opt_noact
= new OptionBool("Does not compile and run tests", "--no-act")
32 var opt_nitc
= new OptionString("nitc compiler to use", "--nitc")
34 # Working directory for testing.
35 fun test_dir
: String do
36 var dir
= opt_dir
.value
37 if dir
== null then return ".nitunit"
41 # Search the `nitc` compiler to use
43 # If not `nitc` is suitable, then prints an error and quit.
46 var nitc
= opt_nitc
.value
48 if not nitc
.file_exists
then
49 fatal_error
(null, "error: cannot find `{nitc}` given by --nitc.")
57 if not nitc
.file_exists
then
58 fatal_error
(null, "error: cannot find `{nitc}` given by NITC.")
65 nitc
= nit_dir
/"bin/nitc"
66 if not nitc
.file_exists
then
67 fatal_error
(null, "Error: cannot find nitc. Set envvar NIT_DIR or NITC or use the --nitc option.")
73 # Execute a system command in a more safe context than `Sys::system`.
74 fun safe_exec
(command
: String): Int
77 var real_command
= """
79 ulimit -f {{{ulimit_file}}} 2> /dev/null
80 ulimit -t {{{ulimit_usertime}}} 2> /dev/null
84 return system
(real_command
)
87 # The maximum size (in KB) of files written by a command executed trough `safe_exec`
90 var ulimit_file
= 65536 is writable
92 # The maximum amount of cpu time (in seconds) for a command executed trough `safe_exec`
94 # Default: 10 CPU minute
95 var ulimit_usertime
= 600 is writable
98 # A unit test is an elementary test discovered, run and reported bu nitunit.
100 # This class factorizes `DocUnit` and `TestCase`.
101 abstract class UnitTest
103 # Error occurred during test-case execution.
104 var error
: nullable String = null is writable
106 # Was the test case executed at least once?
107 var was_exec
= false is writable
109 # Return the `TestCase` in XML format compatible with Jenkins.
112 fun to_xml
: HTMLTag do
113 var tc
= new HTMLTag("testcase")
114 tc
.attr
("classname", xml_classname
)
115 tc
.attr
("name", xml_name
)
116 var error
= self.error
117 if error
!= null then
119 tc
.open
("error").append
("Runtime Error")
121 tc
.open
("failure").append
("Compilation Error")
123 tc
.open
("system-err").append
(error
.trunc
(8192).filter_nonprintable
)
128 # The `classname` attribute of the XML format.
130 # NOTE: jenkins expects a '.' in the classname attr
131 fun xml_classname
: String is abstract
133 # The `name` attribute of the XML format.
136 fun xml_name
: String is abstract
140 # If needed, truncate `self` at `max_length` characters and append an informative `message`.
143 # assert "hello".trunc(10) == "hello"
144 # assert "hello".trunc(2) == "he[truncated. Full size is 5]"
145 # assert "hello".trunc(2, "...") == "he..."
147 fun trunc
(max_length
: Int, message
: nullable String): String
149 if length
<= max_length
then return self
150 if message
== null then message
= "[truncated. Full size is {length}]"
151 return substring
(0, max_length
) + message
154 # Use a special notation for whitespace characters that are not `'\n'` (LFD) or `' '` (space).
157 # assert "hello".filter_nonprintable == "hello"
158 # assert "\r\n\t".filter_nonprintable == "^13\n^9"
160 fun filter_nonprintable
: String
164 var cp
= c
.code_point
165 if cp
< 32 and c
!= '\n' then