1 Let's pick test/settings/TestSettings.py as our example. First, notice the file
2 name "TestSettings.py", the Test*.py pattern is the default mechanism that the
3 test driver uses for discovery of tests. As to TestSettings.py, it defines a
6 class SettingsCommandTestCase(TestBase):
8 derived from TestBase, which is defined in test/lldbtest.py and is itself
9 derived from Python's unittest framework's TestCase class. See also
10 http://docs.python.org/library/unittest.html for more details.
12 To just run the TestSettings.py test, chdir to the lldb test directory, and then
13 type the following command:
15 /Volumes/data/lldb/svn/trunk/test $ ./dotest.py settings
16 ----------------------------------------------------------------------
19 ----------------------------------------------------------------------
22 OK (expected failures=1)
23 /Volumes/data/lldb/svn/trunk/test $
25 Pass '-v' option to the test driver to also output verbose descriptions of the
26 individual test cases and their test status:
28 /Volumes/data/lldb/svn/trunk/test $ ./dotest.py -v settings
29 ----------------------------------------------------------------------
32 test_set_auto_confirm (TestSettings.SettingsCommandTestCase)
33 Test that after 'set auto-confirm true', manual confirmation should not kick in. ... ok
34 test_set_output_path (TestSettings.SettingsCommandTestCase)
35 Test that setting target.process.output-path for the launched process works. ... expected failure
36 test_set_prompt (TestSettings.SettingsCommandTestCase)
37 Test that 'set prompt' actually changes the prompt. ... ok
38 test_set_term_width (TestSettings.SettingsCommandTestCase)
39 Test that 'set term-width' actually changes the term-width. ... ok
40 test_with_dsym (TestSettings.SettingsCommandTestCase)
41 Test that run-args and env-vars are passed to the launched process. ... ok
42 test_with_dwarf (TestSettings.SettingsCommandTestCase)
43 Test that run-args and env-vars are passed to the launched process. ... ok
45 ----------------------------------------------------------------------
48 OK (expected failures=1)
49 /Volumes/data/lldb/svn/trunk/test $
51 Underneath, the '-v' option passes keyword argument verbosity=2 to the
52 Python's unittest.TextTestRunner (see also
53 http://docs.python.org/library/unittest.html#unittest.TextTestRunner). For very
54 detailed descriptions about what's going on during the test, pass '-t' to the
55 test driver, which asks the test driver to trace the commands executed and to
56 display their output. For brevity, the '-t' output is not included here.
58 Notice the 'expected failures=1' message at the end of the run. This is because
59 of a bug currently in lldb such that setting target.process.output-path to
60 'stdout.txt' does not have any effect on the redirection of the standard output
61 of the subsequent launched process. We are using unittest2 (a backport of new
62 unittest features for Python 2.4-2.6) to decorate (mark) the particular test
65 @unittest2.expectedFailure
66 # rdar://problem/8435794
67 # settings set target.process.output-path does not seem to work
68 def test_set_output_path(self):
70 See http://pypi.python.org/pypi/unittest2 for more details.
72 Now let's look inside the test method:
74 def test_set_output_path(self):
75 """Test that setting target.process.output-path for the launched process works."""
78 exe = os.path.join(os.getcwd(), "a.out")
79 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
81 # Set the output-path and verify it is set.
82 self.runCmd("settings set target.process.output-path 'stdout.txt'")
83 self.expect("settings show target.process.output-path",
84 startstr = "target.process.output-path (string) = 'stdout.txt'")
86 self.runCmd("run", RUN_SUCCEEDED)
88 # The 'stdout.txt' file should now exist.
89 self.assertTrue(os.path.isfile("stdout.txt"),
90 "'stdout.txt' exists due to target.process.output-path.")
92 # Read the output file produced by running the program.
93 with open('stdout.txt', 'r') as f:
96 self.expect(output, exe=False,
97 startstr = "This message should go to standard out.")
99 The self.build() statement is used to build a binary for this
100 test instance. This will build the binary for the current debug info format. If
101 we wanted to avoid running the test for every supported debug info format we
102 could annotate it with @no_debug_info_test. The test would then only be run for
103 the default format. The logic for building a test binary resides in the builder
104 modules (packages/Python/lldbsuite/test/builders/builder.py)
106 After the binary is built, it is time to specify the file to be used as the main
109 # Construct the path to a file "a.out" inside the test's build folder.
110 exe = self.getBuildArtifact("a.out")
111 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
113 The runCmd() method is defined in the TestBase base class and its purpose is to
114 pass the specified command to the lldb command interpreter. It's like you're
115 typing the command within an interactive lldb session.
117 The CURRENT_EXECUTABLE_SET is an assert message defined in the lldbtest module
118 so that it can be reused from other test modules.
120 By default, the runCmd() is going to check the return status of the command
121 execution and fails the test if it is not a success. The assert message, in our
122 case CURRENT_EXECUTABLE_SET, is used in the exception printout if this happens.
124 There are cases when we don't care about the return status from the command
125 execution. This can be accomplished by passing the keyword argument pair
126 'check=False' to the method.
128 After the current executable is set, we'll then execute two more commands:
130 # Set the output-path and verify it is set.
131 stdout = self.getBuildArtifact('stdout.txt')
132 self.runCmd("settings set target.process.output-path '%s'" %stdout)
133 self.expect("settings show target.process.output-path",
134 SETTING_MSG("target.process.output-path"),
135 startstr = "target.process.output-path (string) = '.*stdout.txt'")
137 The first uses the 'settings set' command to set the static setting
138 target.process.output-path to be 'stdout.txt', instead of the default
139 '/dev/stdout'. We then immediately issue a 'settings show' command to check
140 that, indeed, the setting did take place. Notice that we use a new method
141 expect() to accomplish the task, which in effect issues a runCmd() behind the
142 door and grabs the output from the command execution and expects to match the
143 start string of the output against what we pass in as the value of the keyword
146 startstr = "target.process.output-path (string) = '%s'" %stdout
148 Take a look at TestBase.expect() within lldbtest.py for more details. Among
149 other things, it can also match against a list of regexp patterns as well as a
150 list of sub strings. And it can also perform negative matching, i.e., instead
151 of expecting something from the output of command execution, it can perform the
152 action of 'not expecting' something.
154 This will launch/run the program:
156 self.runCmd("run", RUN_SUCCEEDED)
158 And this asserts that the file 'stdout.txt' should be present after running the
161 # The 'stdout.txt' file should now exist.
162 self.assertTrue(os.path.isfile(stdout),
163 "stdout.txt' exists due to target.process.output-path.")
165 Also take a look at main.cpp which emits some message to the stdout. Now, if we
166 pass this assertion, it's time to examine the contents of the file to make sure
167 it contains the same message as programmed in main.cpp:
169 # Read the output file produced by running the program.
170 with open(stdout, 'r') as f:
173 self.expect(output, exe=False,
174 startstr = "This message should go to standard out.")
176 We open the file and read its contents into output, then issue an expect()
177 method. The 'exe=False' keyword argument pair tells expect() that don't try to
178 execute the first arg as a command at all. Instead, treat it as a string to
179 match against whatever is thrown in as keyword argument pairs!
181 There are also other test methods present in the TestSettings.py mode:
182 test_set_prompt(), test_set_term_width(), test_set_auto_confirm(),
183 test_with_dsym(), and test_with_dwarf(). We are using the default test loader
184 from unittest framework, which uses the 'test' method name prefix to identify
185 test methods automatically.
187 This finishes the walkthrough of the test method test_set_output_path(self).
188 Before we say goodbye, notice the little method definition at the top of the
192 def classCleanup(cls):
193 system(["/bin/sh", "-c", "rm -f "+self.getBuildArtifact("output.txt")])
194 system(["/bin/sh", "-c", "rm -f "+self.getBuildArtifact("stdout.txt")])
196 This is a classmethod (as shown by the @classmethod decorator) which allows the
197 individual test class to perform cleanup actions after the test harness finishes
198 with the particular test class. This is part of the so-called test fixture in
199 the unittest framework. From http://docs.python.org/library/unittest.html:
201 A test fixture represents the preparation needed to perform one or more tests,
202 and any associate cleanup actions. This may involve, for example, creating
203 temporary or proxy databases, directories, or starting a server process.
205 The TestBase class uses such fixture with setUp(self), tearDown(self),
206 setUpClass(cls), and tearDownClass(cls). And within teraDownClass(cls), it
207 checks whether the current class has an attribute named 'classCleanup', and
208 executes as a method if present. In this particular case, the classCleanup()
209 calls a utility function system() defined in lldbtest.py in order to remove the
210 files created by running the program as the tests are executed.
212 This system() function uses the Python subprocess module to spawn the process
213 and to retrieve its results. If the test instance passes the keyword argument
214 pair 'sender=self', the detailed command execution through the operating system
215 also gets recorded in a session object. If the test instance fails or errors,
216 the session info automatically gets dumped to a file grouped under a directory
217 named after the timestamp of the particular test suite run.
219 For simple cases, look for the timestamp directory in the same directory of the
220 test driver program dotest.py. For example, if we comment out the
221 @expectedFailure decorator for TestSettings.py, and then run the test module:
223 /Volumes/data/lldb/svn/trunk/test $ ./dotest.py -v settings
224 ----------------------------------------------------------------------
227 test_set_auto_confirm (TestSettings.SettingsCommandTestCase)
228 Test that after 'set auto-confirm true', manual confirmation should not kick in. ... ok
229 test_set_output_path (TestSettings.SettingsCommandTestCase)
230 Test that setting target.process.output-path for the launched process works. ... FAIL
231 test_set_prompt (TestSettings.SettingsCommandTestCase)
232 Test that 'set prompt' actually changes the prompt. ... ok
233 test_set_term_width (TestSettings.SettingsCommandTestCase)
234 Test that 'set term-width' actually changes the term-width. ... ok
235 test_with_dsym (TestSettings.SettingsCommandTestCase)
236 Test that run-args and env-vars are passed to the launched process. ... ok
237 test_with_dwarf (TestSettings.SettingsCommandTestCase)
238 Test that run-args and env-vars are passed to the launched process. ... ok
240 ======================================================================
241 FAIL: test_set_output_path (TestSettings.SettingsCommandTestCase)
242 Test that setting target.process.output-path for the launched process works.
243 ----------------------------------------------------------------------
244 Traceback (most recent call last):
245 File "/Volumes/data/lldb/svn/trunk/test/settings/TestSettings.py", line 125, in test_set_output_path
246 "'stdout.txt' exists due to target.process.output-path.")
247 AssertionError: False is not True : 'stdout.txt' exists due to target.process.output-path.
249 ----------------------------------------------------------------------
250 Ran 6 tests in 8.219s
253 /Volumes/data/lldb/svn/trunk/test $ ls 2010-10-19-14:10:49.059609
255 NOTE: This directory name has been changed to not contain the ':' character
256 which is not allowed in windows platforms. We'll change the ':' to '_'
257 and get rid of the microsecond resolution by modifying the test driver.
259 TestSettings.SettingsCommandTestCase.test_set_output_path.log
260 /Volumes/data/lldb/svn/trunk/test $
262 We get one failure and a timestamp directory 2010-10-19-14:10:49.059609.
263 For education purposes, the directory and its contents are reproduced here in
264 the same directory as the current file.