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 unittest to decorate (mark)
62 the particular test method as such:
64 @unittest.expectedFailure
65 # rdar://problem/8435794
66 # settings set target.process.output-path does not seem to work
67 def test_set_output_path(self):
69 See http://docs.python.org/library/unittest.html for more details.
71 Now let's look inside the test method:
73 def test_set_output_path(self):
74 """Test that setting target.process.output-path for the launched process works."""
77 exe = os.path.join(os.getcwd(), "a.out")
78 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
80 # Set the output-path and verify it is set.
81 self.runCmd("settings set target.process.output-path 'stdout.txt'")
82 self.expect("settings show target.process.output-path",
83 startstr = "target.process.output-path (string) = 'stdout.txt'")
85 self.runCmd("run", RUN_SUCCEEDED)
87 # The 'stdout.txt' file should now exist.
88 self.assertTrue(os.path.isfile("stdout.txt"),
89 "'stdout.txt' exists due to target.process.output-path.")
91 # Read the output file produced by running the program.
92 with open('stdout.txt', 'r') as f:
95 self.expect(output, exe=False,
96 startstr = "This message should go to standard out.")
98 The self.build() statement is used to build a binary for this
99 test instance. This will build the binary for the current debug info format. If
100 we wanted to avoid running the test for every supported debug info format we
101 could annotate it with @no_debug_info_test. The test would then only be run for
102 the default format. The logic for building a test binary resides in the builder
103 modules (packages/Python/lldbsuite/test/builders/builder.py)
105 After the binary is built, it is time to specify the file to be used as the main
108 # Construct the path to a file "a.out" inside the test's build folder.
109 exe = self.getBuildArtifact("a.out")
110 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
112 The runCmd() method is defined in the TestBase base class and its purpose is to
113 pass the specified command to the lldb command interpreter. It's like you're
114 typing the command within an interactive lldb session.
116 The CURRENT_EXECUTABLE_SET is an assert message defined in the lldbtest module
117 so that it can be reused from other test modules.
119 By default, the runCmd() is going to check the return status of the command
120 execution and fails the test if it is not a success. The assert message, in our
121 case CURRENT_EXECUTABLE_SET, is used in the exception printout if this happens.
123 There are cases when we don't care about the return status from the command
124 execution. This can be accomplished by passing the keyword argument pair
125 'check=False' to the method.
127 After the current executable is set, we'll then execute two more commands:
129 # Set the output-path and verify it is set.
130 stdout = self.getBuildArtifact('stdout.txt')
131 self.runCmd("settings set target.process.output-path '%s'" %stdout)
132 self.expect("settings show target.process.output-path",
133 SETTING_MSG("target.process.output-path"),
134 startstr = "target.process.output-path (string) = '.*stdout.txt'")
136 The first uses the 'settings set' command to set the static setting
137 target.process.output-path to be 'stdout.txt', instead of the default
138 '/dev/stdout'. We then immediately issue a 'settings show' command to check
139 that, indeed, the setting did take place. Notice that we use a new method
140 expect() to accomplish the task, which in effect issues a runCmd() behind the
141 door and grabs the output from the command execution and expects to match the
142 start string of the output against what we pass in as the value of the keyword
145 startstr = "target.process.output-path (string) = '%s'" %stdout
147 Take a look at TestBase.expect() within lldbtest.py for more details. Among
148 other things, it can also match against a list of regexp patterns as well as a
149 list of sub strings. And it can also perform negative matching, i.e., instead
150 of expecting something from the output of command execution, it can perform the
151 action of 'not expecting' something.
153 This will launch/run the program:
155 self.runCmd("run", RUN_SUCCEEDED)
157 And this asserts that the file 'stdout.txt' should be present after running the
160 # The 'stdout.txt' file should now exist.
161 self.assertTrue(os.path.isfile(stdout),
162 "stdout.txt' exists due to target.process.output-path.")
164 Also take a look at main.cpp which emits some message to the stdout. Now, if we
165 pass this assertion, it's time to examine the contents of the file to make sure
166 it contains the same message as programmed in main.cpp:
168 # Read the output file produced by running the program.
169 with open(stdout, 'r') as f:
172 self.expect(output, exe=False,
173 startstr = "This message should go to standard out.")
175 We open the file and read its contents into output, then issue an expect()
176 method. The 'exe=False' keyword argument pair tells expect() that don't try to
177 execute the first arg as a command at all. Instead, treat it as a string to
178 match against whatever is thrown in as keyword argument pairs!
180 There are also other test methods present in the TestSettings.py mode:
181 test_set_prompt(), test_set_term_width(), test_set_auto_confirm(),
182 test_with_dsym(), and test_with_dwarf(). We are using the default test loader
183 from unittest framework, which uses the 'test' method name prefix to identify
184 test methods automatically.
186 This finishes the walkthrough of the test method test_set_output_path(self).
187 Before we say goodbye, notice the little method definition at the top of the
191 def classCleanup(cls):
192 system(["/bin/sh", "-c", "rm -f "+self.getBuildArtifact("output.txt")])
193 system(["/bin/sh", "-c", "rm -f "+self.getBuildArtifact("stdout.txt")])
195 This is a classmethod (as shown by the @classmethod decorator) which allows the
196 individual test class to perform cleanup actions after the test harness finishes
197 with the particular test class. This is part of the so-called test fixture in
198 the unittest framework. From http://docs.python.org/library/unittest.html:
200 A test fixture represents the preparation needed to perform one or more tests,
201 and any associate cleanup actions. This may involve, for example, creating
202 temporary or proxy databases, directories, or starting a server process.
204 The TestBase class uses such fixture with setUp(self), tearDown(self),
205 setUpClass(cls), and tearDownClass(cls). And within teraDownClass(cls), it
206 checks whether the current class has an attribute named 'classCleanup', and
207 executes as a method if present. In this particular case, the classCleanup()
208 calls a utility function system() defined in lldbtest.py in order to remove the
209 files created by running the program as the tests are executed.
211 This system() function uses the Python subprocess module to spawn the process
212 and to retrieve its results. If the test instance passes the keyword argument
213 pair 'sender=self', the detailed command execution through the operating system
214 also gets recorded in a session object. If the test instance fails or errors,
215 the session info automatically gets dumped to a file grouped under a directory
216 named after the timestamp of the particular test suite run.
218 For simple cases, look for the timestamp directory in the same directory of the
219 test driver program dotest.py. For example, if we comment out the
220 @expectedFailure decorator for TestSettings.py, and then run the test module:
222 /Volumes/data/lldb/svn/trunk/test $ ./dotest.py -v settings
223 ----------------------------------------------------------------------
226 test_set_auto_confirm (TestSettings.SettingsCommandTestCase)
227 Test that after 'set auto-confirm true', manual confirmation should not kick in. ... ok
228 test_set_output_path (TestSettings.SettingsCommandTestCase)
229 Test that setting target.process.output-path for the launched process works. ... FAIL
230 test_set_prompt (TestSettings.SettingsCommandTestCase)
231 Test that 'set prompt' actually changes the prompt. ... ok
232 test_set_term_width (TestSettings.SettingsCommandTestCase)
233 Test that 'set term-width' actually changes the term-width. ... ok
234 test_with_dsym (TestSettings.SettingsCommandTestCase)
235 Test that run-args and env-vars are passed to the launched process. ... ok
236 test_with_dwarf (TestSettings.SettingsCommandTestCase)
237 Test that run-args and env-vars are passed to the launched process. ... ok
239 ======================================================================
240 FAIL: test_set_output_path (TestSettings.SettingsCommandTestCase)
241 Test that setting target.process.output-path for the launched process works.
242 ----------------------------------------------------------------------
243 Traceback (most recent call last):
244 File "/Volumes/data/lldb/svn/trunk/test/settings/TestSettings.py", line 125, in test_set_output_path
245 "'stdout.txt' exists due to target.process.output-path.")
246 AssertionError: False is not True : 'stdout.txt' exists due to target.process.output-path.
248 ----------------------------------------------------------------------
249 Ran 6 tests in 8.219s
252 /Volumes/data/lldb/svn/trunk/test $ ls 2010-10-19-14:10:49.059609
254 NOTE: This directory name has been changed to not contain the ':' character
255 which is not allowed in windows platforms. We'll change the ':' to '_'
256 and get rid of the microsecond resolution by modifying the test driver.
258 TestSettings.SettingsCommandTestCase.test_set_output_path.log
259 /Volumes/data/lldb/svn/trunk/test $
261 We get one failure and a timestamp directory 2010-10-19-14:10:49.059609.
262 For education purposes, the directory and its contents are reproduced here in
263 the same directory as the current file.