1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import dircache
22 import os
23 import os.path
24 from qm.test.database import *
25 from qm.test.directory_suite import *
26
27
28
29
30
32 """A 'FileDatabase' stores each test as a single file.
33
34 A 'FileDatabase' is a 'Database' that stores each test, suite,
35 or resource as a single file. In addition, some subdirectories
36 can be considered implicit suites. The contents of the
37 implicit suite are all of the tests and suites contained in the
38 subdirectory.
39
40 'FileDatabase' is an abstract class."""
41
42
43
45 """Return the 'TestDescriptor' for the test named 'test_id'.
46
47 'test_id' -- A label naming the test.
48
49 returns -- A 'TestDescriptor' corresponding to 'test_id'.
50
51 raises -- 'NoSuchTestError' if there is no test in the database
52 named 'test_id'."""
53
54 path = self.GetTestPath(test_id)
55 if not self._IsTestFile(path):
56 raise NoSuchTestError, test_id
57
58 return self._GetTestFromPath(test_id, os.path.normpath(path))
59
60
62 """Return the file containing 'test_id'.
63
64 'test_id' -- The name of a test.
65
66 returns -- The absolute file name of the file that contains, or
67 would contain, 'test_id'. This method works even if no test
68 named 'test_id' exists.
69
70 Derived classes may override this method."""
71
72 return self._GetPathFromLabel(test_id)
73
74
76 """Returns true if 'path' is a test file.
77
78 'path' -- The absolute name of a file. All relevant
79 components in the path name have already been checked to
80 ensure that they are valid labels.
81
82 returns -- True iff the file corresponds to a test.
83
84 Derived classes must override this method."""
85
86 raise NotImplementedError
87
88
89
91 """Return the 'Suite' for the suite named 'suite_id'.
92
93 'suite_id' -- A label naming the suite.
94
95 returns -- An instance of 'Suite' (or a derived class of
96 'Suite') corresponding to 'suite_id'.
97
98 raises -- 'NoSuchSuiteError' if there is no suite in the database
99 named 'suite_id'."""
100
101 path = self.GetSuitePath(suite_id)
102 if not self._IsSuiteFile(path):
103 raise NoSuchSuiteError, suite_id
104
105
106
107 if os.path.isdir(path):
108 return DirectorySuite(self, suite_id)
109 else:
110 return self._GetSuiteFromPath(suite_id, os.path.normpath(path))
111
112
114 """Return the file containing 'suite_id'.
115
116 'suite_id' -- The name of a suite.
117
118 returns -- The absolute file name of the file (or directory)
119 that contains, or would contain, 'suite_id'. This method works
120 even if no suite named 'suite_id' exists.
121
122 Derived classes may override this method."""
123
124 return self._GetPathFromLabel(suite_id)
125
126
128 """Returns true if 'path' is a test suite file or directory.
129
130 'path' -- The absolute name of a file. All relevant
131 components in the path name have already been checked to
132 ensure that they are valid labels.
133
134 returns -- True iff the file corresponds to a test.
135
136 Derived classes may override this method, but only to restrict
137 the set of suites. In particular, a derived class method
138 may return false where this method would return true, but
139 never vice versa.
140
141 Derived classes must override this method."""
142
143 raise NotImplementedError
144
145
146
148 """Return the 'ResourceDescriptor' for the resource named
149 'resource_id'.
150
151 'resource_id' -- A label naming the resource.
152
153 returns -- A 'ResourceDescriptor' corresponding to 'resource_id'.
154
155 raises -- 'NoSuchResourceError' if there is no resource in the
156 database named 'resource_id'."""
157
158 path = self.GetResourcePath(resource_id)
159 if not self._IsResourceFile(path):
160 raise NoSuchResourceError, resource_id
161
162 return self._GetResourceFromPath(resource_id, os.path.normpath(path))
163
164
166 """Return the file containing 'resource_id'.
167
168 'resource_id' -- The name of a resource.
169
170 returns -- The absolute file name of the file that contains, or
171 would contain, 'resource_id'. This method works even if no
172 Resource named 'resource_id' exists.
173
174 Derived classes may override this method."""
175
176 return self._GetPathFromLabel(resource_id)
177
178
180 """Returns true if 'path' is a resource file.
181
182 'path' -- The absolute name of a file. All relevant
183 components in the path name have already been checked to
184 ensure that they are valid labels.
185
186 returns -- True iff the file corresponds to a resource.
187
188 Derived classes must override this method."""
189
190 raise NotImplementedError
191
192
193
195 """Return the root of the test database.
196
197 returns -- The directory that serves as the root of the test
198 database. All paths are relative to this directory.
199
200 Derived classes may override this method."""
201
202 return self.GetPath()
203
204
206 """Return the subdirectories of 'directory'.
207
208 'directory' -- A label indicating a directory in the database.
209
210 returns -- A sequence of (relative) labels indictating the
211 subdirectories of 'directory'. For example, if "a.b" and "a.c"
212 are directories in the database, this method will return "b" and
213 "c" given "a" as 'directory'."""
214
215 subdirs = []
216 file_dir = self.GetSuitePath(directory)
217 for entry in dircache.listdir(file_dir):
218 if not self._AreLabelsPaths():
219 root = os.path.splitext(entry)[0]
220 else:
221 root = entry
222 if not self.IsValidLabel(root):
223 continue
224 entry_path = os.path.join(file_dir, entry)
225 if (self._IsSuiteFile(entry_path)
226 and os.path.isdir(entry_path)):
227 subdirs.append(root)
228 return subdirs
229
230
231 - def GetIds(self, kind, directory = "", scan_subdirs = 1):
238
239
252
253
255 """Returns true if 'path' is a file of the indicated 'kind'.
256
257 'kind' -- One of 'Database.ITEM_KINDS'.
258
259 'path' -- The path to a file.
260
261 returns -- True iff 'path' is a file of the indicated kind.
262
263 Derived classes must override this method."""
264
265 return { Database.TEST : self._IsTestFile,
266 Database.RESOURCE : self._IsResourceFile,
267 Database.SUITE : self._IsSuiteFile } [kind] (path)
268
269
270
272 """Return a descriptor for the test given by 'path'.
273
274 'test_id' -- The label naming the test.
275
276 'path' -- An absolute path to a test file. The 'path' satisfies
277 '_IsTestFile'.
278
279 returns -- A 'TestDescriptor' corresponding to 'test_id'.
280
281 Derived classes must override this method."""
282
283 raise NotImplementedError
284
285
287 """Return a the 'Suite' given by 'path'.
288
289 'suite_id' -- The label naming the suite.
290
291 'path' -- An absolute path to a suite file. The 'path'
292 satisfies '_IsSuiteFile' and is a file, not a directory.
293
294 returns -- A 'Suite' corresponding to 'suite_id'.
295
296 Derived classes must override this method."""
297
298 raise NotImplementedError
299
300
302 """Return a descriptor for the resource given by 'path'.
303
304 'resource_id' -- The label naming the resource.
305
306 'path' -- An absolute path to a resource file. The 'path'
307 satisfies '_IsResourceFile'.
308
309 returns -- A 'ResourceDescriptor' corresponding to
310 'resource_id'.
311
312 Derived classes must override this method."""
313
314 raise NotImplementedError
315
316
318 """Returns the file system path corresponding to 'label'.
319
320 'label' -- The id for a test, test suite, or similar entity.
321
322 returns -- The absolute path for the corresponding entry in
323 the file system, but without any required extension."""
324
325 return os.path.join(self.GetRoot(),
326 self._GetRelativeLabelPath(label))
327
328
330 """Returns the label associated with a file named 'basename'.
331
332 'basename' -- The basename of a file, including the extension.
333
334 returns -- The corresponding label.
335
336 Derived classes may override this method."""
337
338 return basename
339
340
341 - def _GetLabels(self, directory, scan_subdirs, label, predicate):
342 """Returns the labels of entities in 'directory'.
343
344 'directory' -- The absolute path name of the directory in
345 which to begin the search.
346
347 'scan_subdirs' -- True if (and only if) subdirectories of
348 'directory' should be scanned.
349
350 'label' -- The label that corresponds to 'directory'.
351
352 'predicate' -- A function that takes a file name and returns
353 a boolean.
354
355 returns -- Labels for all file names in 'directory'. that
356 satisfy 'predicate' If 'scan_subdirs' is true, subdirectories
357 are scanned as well."""
358
359 labels = []
360
361
362
363 for entry in dircache.listdir(directory):
364 entry_label = self._GetLabelFromBasename(entry)
365
366
367
368 if not self.IsValidLabel(entry_label):
369 continue
370
371 entry_path = os.path.join(directory, entry)
372
373 if predicate(entry_path):
374 labels.append(self.JoinLabels(label, entry_label))
375
376 if (scan_subdirs and os.path.isdir(entry_path)
377 and self._IsSuiteFile(entry_path)):
378 labels.extend(self._GetLabels(entry_path,
379 scan_subdirs,
380 self.JoinLabels(label,
381 entry_label),
382 predicate))
383
384 return labels
385
386
396
397
399 """Returns true if labels are to be thought of as file names.
400
401 returns -- True if labels are to be thought of as file names.
402 If this predicate holds, every label is a path, relative to the
403 root of the database. If false, the labels are translated to
404 paths by adding the 'suite_extension' between directories and
405 the 'test_extension' or 'resource_extension' at the end of the
406 name."""
407
408 return self.label_class == "file_label.FileLabel"
409
410
412 """Returns a representation of 'label' as a relative filename.
413
414 returns -- A relative filename corresponding to 'label'."""
415
416 if self._AreLabelsPaths():
417 return label
418
419 return os.path.join(*self.GetLabelComponents(label))
420
421
422
424 """An 'ExtensionDatabase' is a 'FileDatabase' where each kind of
425 entity (test, suite, resource) has a particular extension. For
426 example, if tests have the extension '.qmt', then all files ending
427 with '.qmt' are considered tests. If an extension for a particular
428 kind of entity is not specified or is the empty string, then all files
429 will be considered to be that kind of entity.
430
431 'ExtensionDatabase' is an abstract class."""
432
433 arguments = [
434 qm.fields.TextField(
435 name="test_extension",
436 title="Test Extension",
437 description="""The extension for test files.
438
439 The extension (including the leading period) used for files
440 containing tests.""",
441 default_value=".qmt"),
442 qm.fields.TextField(
443 name="suite_extension",
444 title="Suite Extension",
445 description="""The extension for suite files.
446
447 The extension (including the leading period) used for files
448 containing suites.""",
449 default_value=".qms"),
450 qm.fields.TextField(
451 name="resource_extension",
452 title="Resource Extension",
453 description="""The extension for resource files.
454
455 The extension (including the leading period) used for files
456 containing resources.""",
457 default_value=".qma"),
458 ]
459
466
468 """Return the extension that indicates a file is a test.
469
470 returns -- The extension (including the leading period) that
471 indicates that a file is a test."""
472
473 return self.test_extension
474
475
477 """Return the extension that indicates a file is a suite.
478
479 returns -- The extension (including the leading period) that
480 indicates that a file is a suite."""
481
482 return self.suite_extension
483
484
486 """Return the extension that indicates a file is a resource.
487
488 returns -- The extension (including the leading period) that
489 indicates that a file is a resource."""
490
491 return self.resource_extension
492
493
500
501
511
512
524
525
538
539
546
547
557
558
567
568
570
571 if self._AreLabelsPaths():
572 return basename
573 else:
574 return os.path.splitext(basename)[0]
575
576
578 """Returns a representation of 'label' as a filename.
579
580 returns -- A filename corresponding to 'label'."""
581
582 if self._AreLabelsPaths():
583 return label
584
585 path = ""
586 components = self.GetLabelComponents(label)
587 if not components:
588 return path
589
590 for c in components[:-1]:
591 path = os.path.join(path, c + self.suite_extension)
592 path = os.path.join(path, components[-1])
593 return path
594
595
596
597
598
599
600
601
602