Coverage for pyEDAA/Reports/CodeCoverage/UCIS/HistoryNodes.py: 76%

230 statements  

« prev     ^ index     » next       coverage.py v7.17.3, created at 2026-11-14 02:26 +0000

1# ==================================================================================================================== # 

2# _____ ____ _ _ ____ _ # 

3# _ __ _ _| ____| _ \ / \ / \ | _ \ ___ _ __ ___ _ __| |_ ___ # 

4# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) / _ \ '_ \ / _ \| '__| __/ __| # 

5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| _ < __/ |_) | (_) | | | |_\__ \ # 

6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| \_\___| .__/ \___/|_| \__|___/ # 

7# |_| |___/ |_| # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

13# ==================================================================================================================== # 

14# Copyright 2026-2026 Electronic Design Automation Abstraction (EDA²) # 

15# # 

16# Licensed under the Apache License, Version 2.0 (the "License"); # 

17# you may not use this file except in compliance with the License. # 

18# You may obtain a copy of the License at # 

19# # 

20# http://www.apache.org/licenses/LICENSE-2.0 # 

21# # 

22# Unless required by applicable law or agreed to in writing, software # 

23# distributed under the License is distributed on an "AS IS" BASIS, # 

24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

25# See the License for the specific language governing permissions and # 

26# limitations under the License. # 

27# # 

28# SPDX-License-Identifier: Apache-2.0 # 

29# ==================================================================================================================== # 

30# 

31""" 

32The history nodes of the UCIS XML interchange format: the tests, which measured the coverage, and the merges of their 

33coverage, with the tool, the date and how the test ran. 

34""" 

35from __future__ import annotations 

36 

37from datetime import datetime 

38from decimal import Decimal 

39from pathlib import Path 

40from typing import TYPE_CHECKING, Iterable, Optional as Nullable, Self 

41 

42from lxml.etree import _Element 

43from pyTooling.Common import getFullyQualifiedName 

44from pyTooling.Decorators import export, readonly 

45 

46from pyEDAA.Reports.CodeCoverage.UCIS.Elements import Base, UserAttribute 

47 

48if TYPE_CHECKING: 48 ↛ 49line 48 didn't jump to line 49 because the condition on line 48 was never true

49 from pyEDAA.Reports.CodeCoverage.UCIS import Report 

50 

51 

52@export 

53class HistoryNode(Base): 

54 """ 

55 A ``<historyNodes>`` of the report: a test, which measured coverage, or a merge of coverage, its tool, its date and - 

56 if the report says - how the test ran. 

57 

58 A history node names the node it belongs to - e.g. the merge, which merged it - by the ID of that node. 

59 """ 

60 

61 _parent: Nullable[Report] #: The report the history node belongs to. 

62 _historyNodeID: int #: ID of the history node. 

63 _logicalName: str #: Name of the history node, e.g. of the test. 

64 _testStatus: bool #: Whether the test passed. 

65 _date: datetime #: When the test ran. 

66 _toolCategory: str #: Kind of the tool, e.g. ``simulator``. 

67 _ucisVersion: str #: Version of the UCIS, in which the tool measured the coverage. 

68 _vendorID: str #: ID of the tool's vendor. 

69 _vendorTool: str #: Name of the tool. 

70 _vendorToolVersion: str #: Version of the tool. 

71 _parentID: Nullable[int] #: ID of the history node this one belongs to. 

72 _physicalName: Nullable[Path] #: Path of the coverage database the history node wrote. 

73 _kind: Nullable[str] #: Kind of the history node, e.g. a test or a merge. 

74 _simulationTime: Nullable[float] #: How long the test ran, in simulated time. 

75 _timeUnit: Nullable[str] #: Unit of the simulated time. 

76 _runDirectory: Nullable[Path] #: The directory the test ran in. 

77 _cpuTime: Nullable[float] #: How long the test ran, in CPU time. 

78 _seed: Nullable[str] #: The seed of the test's random numbers. 

79 _command: Nullable[str] #: The command, which ran the test. 

80 _arguments: Nullable[str] #: The command line arguments of the test. 

81 _compulsory: Nullable[str] #: Whether the test must run. 

82 _userName: Nullable[str] #: Name of the user, who ran the test. 

83 _cost: Nullable[Decimal] #: Cost of the test. 

84 _sameTests: Nullable[int] #: ID of a test this one is equivalent to. 

85 _comment: Nullable[str] #: A comment. 

86 

87 def __init__( 

88 self, 

89 historyNodeID: int, 

90 logicalName: str, 

91 testStatus: bool, 

92 date: datetime, 

93 toolCategory: str, 

94 ucisVersion: str, 

95 vendorID: str, 

96 vendorTool: str, 

97 vendorToolVersion: str, 

98 parentID: Nullable[int] = None, 

99 physicalName: Nullable[Path] = None, 

100 kind: Nullable[str] = None, 

101 simulationTime: Nullable[float] = None, 

102 timeUnit: Nullable[str] = None, 

103 runDirectory: Nullable[Path] = None, 

104 cpuTime: Nullable[float] = None, 

105 seed: Nullable[str] = None, 

106 command: Nullable[str] = None, 

107 arguments: Nullable[str] = None, 

108 compulsory: Nullable[str] = None, 

109 userName: Nullable[str] = None, 

110 cost: Nullable[Decimal] = None, 

111 sameTests: Nullable[int] = None, 

112 comment: Nullable[str] = None, 

113 userAttributes: Nullable[Iterable[UserAttribute]] = None, 

114 *, 

115 parent: Nullable[Report] = None 

116 ) -> None: 

117 """ 

118 Initialize the history node, and add it to the history nodes of its report. 

119 

120 :param historyNodeID: ID of the history node. 

121 :param logicalName: Name of the history node, e.g. of the test. 

122 :param testStatus: Whether the test passed. 

123 :param date: When the test ran. 

124 :param toolCategory: Kind of the tool, e.g. ``simulator``. 

125 :param ucisVersion: Version of the UCIS, in which the tool measured the coverage, e.g. ``1.0``. 

126 :param vendorID: ID of the tool's vendor. 

127 :param vendorTool: Name of the tool. 

128 :param vendorToolVersion: Version of the tool. 

129 :param parentID: Optional, ID of the history node this one belongs to. Default: ``None``. 

130 :param physicalName: Optional, path of the coverage database the history node wrote. Default: ``None``. 

131 :param kind: Optional, kind of the history node, e.g. a test or a merge. Default: ``None``. 

132 :param simulationTime: Optional, how long the test ran, in simulated time. Default: ``None``. 

133 :param timeUnit: Optional, unit of the simulated time, e.g. ``ns``. Default: ``None``. 

134 :param runDirectory: Optional, the directory the test ran in. Default: ``None``. 

135 :param cpuTime: Optional, how long the test ran, in CPU time. Default: ``None``. 

136 :param seed: Optional, the seed of the test's random numbers. Default: ``None``. 

137 :param command: Optional, the command, which ran the test. Default: ``None``. 

138 :param arguments: Optional, the command line arguments of the test. Default: ``None``. 

139 :param compulsory: Optional, whether the test must run. Default: ``None``. 

140 :param userName: Optional, name of the user, who ran the test. Default: ``None``. 

141 :param cost: Optional, cost of the test. Default: ``None``. 

142 :param sameTests: Optional, ID of a test this one is equivalent to. Default: ``None``. 

143 :param comment: Optional, a comment. Default: ``None``. 

144 :param userAttributes: Optional, the user-defined attributes. Default: ``None``. 

145 :param parent: Optional, the report the history node belongs to; the history node is added to its 

146 history nodes. Default: ``None``. 

147 :raises ValueError: If parameter ``historyNodeID`` is ``None``. 

148 :raises TypeError: If parameter ``historyNodeID`` isn't of type :class:`int`. 

149 :raises ValueError: If parameter ``historyNodeID`` is negative. 

150 :raises ValueError: If parameter ``logicalName`` is ``None``. 

151 :raises TypeError: If parameter ``logicalName`` isn't of type :class:`str`. 

152 :raises ValueError: If parameter ``testStatus`` is ``None``. 

153 :raises TypeError: If parameter ``testStatus`` isn't of type :class:`bool`. 

154 :raises ValueError: If parameter ``date`` is ``None``. 

155 :raises TypeError: If parameter ``date`` isn't of type :class:`~datetime.datetime`. 

156 :raises ValueError: If parameter ``toolCategory`` is ``None``. 

157 :raises TypeError: If parameter ``toolCategory`` isn't of type :class:`str`. 

158 :raises ValueError: If parameter ``ucisVersion`` is ``None``. 

159 :raises TypeError: If parameter ``ucisVersion`` isn't of type :class:`str`. 

160 :raises ValueError: If parameter ``vendorID`` is ``None``. 

161 :raises TypeError: If parameter ``vendorID`` isn't of type :class:`str`. 

162 :raises ValueError: If parameter ``vendorTool`` is ``None``. 

163 :raises TypeError: If parameter ``vendorTool`` isn't of type :class:`str`. 

164 :raises ValueError: If parameter ``vendorToolVersion`` is ``None``. 

165 :raises TypeError: If parameter ``vendorToolVersion`` isn't of type :class:`str`. 

166 :raises TypeError: If parameter ``parentID`` isn't of type :class:`int`. 

167 :raises ValueError: If parameter ``parentID`` is negative. 

168 :raises TypeError: If parameter ``physicalName`` isn't of type :class:`~pathlib.Path`. 

169 :raises TypeError: If parameter ``kind`` isn't of type :class:`str`. 

170 :raises TypeError: If parameter ``simulationTime`` isn't of type :class:`float`. 

171 :raises TypeError: If parameter ``timeUnit`` isn't of type :class:`str`. 

172 :raises TypeError: If parameter ``runDirectory`` isn't of type :class:`~pathlib.Path`. 

173 :raises TypeError: If parameter ``cpuTime`` isn't of type :class:`float`. 

174 :raises TypeError: If parameter ``seed`` isn't of type :class:`str`. 

175 :raises TypeError: If parameter ``command`` isn't of type :class:`str`. 

176 :raises TypeError: If parameter ``arguments`` isn't of type :class:`str`. 

177 :raises TypeError: If parameter ``compulsory`` isn't of type :class:`str`. 

178 :raises TypeError: If parameter ``userName`` isn't of type :class:`str`. 

179 :raises TypeError: If parameter ``cost`` isn't of type :class:`~decimal.Decimal`. 

180 :raises TypeError: If parameter ``sameTests`` isn't of type :class:`int`. 

181 :raises ValueError: If parameter ``sameTests`` is negative. 

182 :raises TypeError: If parameter ``comment`` isn't of type :class:`str`. 

183 :raises TypeError: If parameter ``userAttributes`` isn't iterable. 

184 :raises TypeError: If parameter ``userAttributes`` contains an element not of type 

185 :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Elements.UserAttribute`. 

186 :raises TypeError: If parameter ``parent`` isn't of type :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Report`. 

187 """ 

188 from pyEDAA.Reports.CodeCoverage.UCIS import Report 

189 

190 super().__init__(userAttributes) 

191 

192 if historyNodeID is None: 192 ↛ 193line 192 didn't jump to line 193 because the condition on line 192 was never true

193 raise ValueError("Parameter 'historyNodeID' is None.") 

194 elif not isinstance(historyNodeID, int) or isinstance(historyNodeID, bool): 194 ↛ 195line 194 didn't jump to line 195 because the condition on line 194 was never true

195 ex = TypeError("Parameter 'historyNodeID' is not of type 'int'.") 

196 ex.add_note(f"Got type '{getFullyQualifiedName(historyNodeID)}'.") 

197 raise ex 

198 elif historyNodeID < 0: 198 ↛ 199line 198 didn't jump to line 199 because the condition on line 198 was never true

199 ex = ValueError("Parameter 'historyNodeID' is negative.") 

200 ex.add_note(f"Got value '{historyNodeID}'.") 

201 raise ex 

202 

203 if testStatus is None: 203 ↛ 204line 203 didn't jump to line 204 because the condition on line 203 was never true

204 raise ValueError("Parameter 'testStatus' is None.") 

205 elif not isinstance(testStatus, bool): 205 ↛ 206line 205 didn't jump to line 206 because the condition on line 205 was never true

206 ex = TypeError("Parameter 'testStatus' is not of type 'bool'.") 

207 ex.add_note(f"Got type '{getFullyQualifiedName(testStatus)}'.") 

208 raise ex 

209 

210 if date is None: 210 ↛ 211line 210 didn't jump to line 211 because the condition on line 210 was never true

211 raise ValueError("Parameter 'date' is None.") 

212 elif not isinstance(date, datetime): 

213 ex = TypeError("Parameter 'date' is not of type 'datetime'.") 

214 ex.add_note(f"Got type '{getFullyQualifiedName(date)}'.") 

215 raise ex 

216 

217 for name, value in ( 

218 ("logicalName", logicalName), 

219 ("toolCategory", toolCategory), 

220 ("ucisVersion", ucisVersion), 

221 ("vendorID", vendorID), 

222 ("vendorTool", vendorTool), 

223 ("vendorToolVersion", vendorToolVersion) 

224 ): 

225 if value is None: 

226 raise ValueError(f"Parameter '{name}' is None.") 

227 elif not isinstance(value, str): 227 ↛ 228line 227 didn't jump to line 228 because the condition on line 227 was never true

228 ex = TypeError(f"Parameter '{name}' is not of type 'str'.") 

229 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") 

230 raise ex 

231 

232 if parentID is not None: 

233 if not isinstance(parentID, int) or isinstance(parentID, bool): 233 ↛ 234line 233 didn't jump to line 234 because the condition on line 233 was never true

234 ex = TypeError("Parameter 'parentID' is not of type 'int'.") 

235 ex.add_note(f"Got type '{getFullyQualifiedName(parentID)}'.") 

236 raise ex 

237 elif parentID < 0: 237 ↛ 242line 237 didn't jump to line 242 because the condition on line 237 was always true

238 ex = ValueError("Parameter 'parentID' is negative.") 

239 ex.add_note(f"Got value '{parentID}'.") 

240 raise ex 

241 

242 if sameTests is not None: 242 ↛ 243line 242 didn't jump to line 243 because the condition on line 242 was never true

243 if not isinstance(sameTests, int) or isinstance(sameTests, bool): 

244 ex = TypeError("Parameter 'sameTests' is not of type 'int'.") 

245 ex.add_note(f"Got type '{getFullyQualifiedName(sameTests)}'.") 

246 raise ex 

247 elif sameTests < 0: 

248 ex = ValueError("Parameter 'sameTests' is negative.") 

249 ex.add_note(f"Got value '{sameTests}'.") 

250 raise ex 

251 

252 if physicalName is not None and not isinstance(physicalName, Path): 252 ↛ 253line 252 didn't jump to line 253 because the condition on line 252 was never true

253 ex = TypeError("Parameter 'physicalName' is not of type 'Path'.") 

254 ex.add_note(f"Got type '{getFullyQualifiedName(physicalName)}'.") 

255 raise ex 

256 

257 if runDirectory is not None and not isinstance(runDirectory, Path): 257 ↛ 258line 257 didn't jump to line 258 because the condition on line 257 was never true

258 ex = TypeError("Parameter 'runDirectory' is not of type 'Path'.") 

259 ex.add_note(f"Got type '{getFullyQualifiedName(runDirectory)}'.") 

260 raise ex 

261 

262 if simulationTime is not None and not isinstance(simulationTime, float): 

263 ex = TypeError("Parameter 'simulationTime' is not of type 'float'.") 

264 ex.add_note(f"Got type '{getFullyQualifiedName(simulationTime)}'.") 

265 raise ex 

266 

267 if cpuTime is not None and not isinstance(cpuTime, float): 267 ↛ 268line 267 didn't jump to line 268 because the condition on line 267 was never true

268 ex = TypeError("Parameter 'cpuTime' is not of type 'float'.") 

269 ex.add_note(f"Got type '{getFullyQualifiedName(cpuTime)}'.") 

270 raise ex 

271 

272 for name, value in ( 

273 ("kind", kind), 

274 ("timeUnit", timeUnit), 

275 ("seed", seed), 

276 ("command", command), 

277 ("arguments", arguments), 

278 ("compulsory", compulsory), 

279 ("userName", userName), 

280 ("comment", comment) 

281 ): 

282 if value is not None and not isinstance(value, str): 282 ↛ 283line 282 didn't jump to line 283 because the condition on line 282 was never true

283 ex = TypeError(f"Parameter '{name}' is not of type 'str'.") 

284 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") 

285 raise ex 

286 

287 if cost is not None and not isinstance(cost, Decimal): 287 ↛ 288line 287 didn't jump to line 288 because the condition on line 287 was never true

288 ex = TypeError("Parameter 'cost' is not of type 'Decimal'.") 

289 ex.add_note(f"Got type '{getFullyQualifiedName(cost)}'.") 

290 raise ex 

291 

292 if parent is not None and not isinstance(parent, Report): 292 ↛ 293line 292 didn't jump to line 293 because the condition on line 292 was never true

293 ex = TypeError("Parameter 'parent' is not of type 'Report'.") 

294 ex.add_note(f"Got type '{getFullyQualifiedName(parent)}'.") 

295 raise ex 

296 

297 self._parent = parent 

298 self._historyNodeID = historyNodeID 

299 self._logicalName = logicalName 

300 self._testStatus = testStatus 

301 self._date = date 

302 self._toolCategory = toolCategory 

303 self._ucisVersion = ucisVersion 

304 self._vendorID = vendorID 

305 self._vendorTool = vendorTool 

306 self._vendorToolVersion = vendorToolVersion 

307 self._parentID = parentID 

308 self._physicalName = physicalName 

309 self._kind = kind 

310 self._simulationTime = simulationTime 

311 self._timeUnit = timeUnit 

312 self._runDirectory = runDirectory 

313 self._cpuTime = cpuTime 

314 self._seed = seed 

315 self._command = command 

316 self._arguments = arguments 

317 self._compulsory = compulsory 

318 self._userName = userName 

319 self._cost = cost 

320 self._sameTests = sameTests 

321 self._comment = comment 

322 

323 if parent is not None: 

324 parent._historyNodes[historyNodeID] = self 

325 

326 @classmethod 

327 def Parse(cls, element: _Element, *, parent: Nullable[Report] = None) -> Self: 

328 """ 

329 Parse a history node from its ``<historyNodes>`` element. 

330 

331 :param element: The ``<historyNodes>`` element. 

332 :param parent: Optional, the report the history node belongs to. Default: ``None``. 

333 :returns: The history node. 

334 :raises CodeCoverageError: If a user-defined attribute's value isn't of the type the attribute states. 

335 """ 

336 attributes = element.attrib 

337 parentID = attributes.get("parentId") 

338 physicalName = attributes.get("physicalName") 

339 simulationTime = attributes.get("simtime") 

340 runDirectory = attributes.get("runCwd") 

341 cpuTime = attributes.get("cpuTime") 

342 cost = attributes.get("cost") 

343 sameTests = attributes.get("sameTests") 

344 

345 return cls( 

346 int(attributes["historyNodeId"]), 

347 attributes["logicalName"], 

348 cls._ParseBoolean(attributes["testStatus"]), 

349 datetime.fromisoformat(attributes["date"]), 

350 attributes["toolCategory"], 

351 attributes["ucisVersion"], 

352 attributes["vendorId"], 

353 attributes["vendorTool"], 

354 attributes["vendorToolVersion"], 

355 None if parentID is None else int(parentID), 

356 None if physicalName is None else Path(physicalName), 

357 attributes.get("kind"), 

358 None if simulationTime is None else float(simulationTime), 

359 attributes.get("timeunit"), 

360 None if runDirectory is None else Path(runDirectory), 

361 None if cpuTime is None else float(cpuTime), 

362 attributes.get("seed"), 

363 attributes.get("cmd"), 

364 attributes.get("args"), 

365 attributes.get("compulsory"), 

366 attributes.get("userName"), 

367 None if cost is None else Decimal(cost), 

368 None if sameTests is None else int(sameTests), 

369 attributes.get("comment"), 

370 cls._ParseUserAttributes(element), 

371 parent=parent 

372 ) 

373 

374 @readonly 

375 def Parent(self) -> Nullable[Report]: 

376 """ 

377 Read-only property to access the report the history node belongs to (:attr:`_parent`). 

378 

379 :returns: The report; ``None``, if the history node belongs to none. 

380 """ 

381 return self._parent 

382 

383 @readonly 

384 def HistoryNodeID(self) -> int: 

385 """ 

386 Read-only property to access the ID of the history node (:attr:`_historyNodeID`). 

387 

388 :returns: The ID, by which bins name the tests, which covered them. 

389 """ 

390 return self._historyNodeID 

391 

392 @readonly 

393 def LogicalName(self) -> str: 

394 """ 

395 Read-only property to access the name of the history node (:attr:`_logicalName`). 

396 

397 :returns: The name, e.g. of the test. 

398 """ 

399 return self._logicalName 

400 

401 @readonly 

402 def TestStatus(self) -> bool: 

403 """ 

404 Read-only property to access whether the test passed (:attr:`_testStatus`). 

405 

406 :returns: ``True``, if the test passed. 

407 """ 

408 return self._testStatus 

409 

410 @readonly 

411 def Date(self) -> datetime: 

412 """ 

413 Read-only property to access when the test ran (:attr:`_date`). 

414 

415 :returns: The date and time. 

416 """ 

417 return self._date 

418 

419 @readonly 

420 def ToolCategory(self) -> str: 

421 """ 

422 Read-only property to access the kind of the tool (:attr:`_toolCategory`). 

423 

424 :returns: The kind, as stated. 

425 """ 

426 return self._toolCategory 

427 

428 @readonly 

429 def UCISVersion(self) -> str: 

430 """ 

431 Read-only property to access the UCIS version, in which the tool measured the coverage (:attr:`_ucisVersion`). 

432 

433 :returns: The version, as stated. 

434 """ 

435 return self._ucisVersion 

436 

437 @readonly 

438 def VendorID(self) -> str: 

439 """ 

440 Read-only property to access the ID of the tool's vendor (:attr:`_vendorID`). 

441 

442 :returns: The ID, as stated. 

443 """ 

444 return self._vendorID 

445 

446 @readonly 

447 def VendorTool(self) -> str: 

448 """ 

449 Read-only property to access the name of the tool (:attr:`_vendorTool`). 

450 

451 :returns: The name, as stated. 

452 """ 

453 return self._vendorTool 

454 

455 @readonly 

456 def VendorToolVersion(self) -> str: 

457 """ 

458 Read-only property to access the version of the tool (:attr:`_vendorToolVersion`). 

459 

460 :returns: The version, as stated. 

461 """ 

462 return self._vendorToolVersion 

463 

464 @readonly 

465 def ParentID(self) -> Nullable[int]: 

466 """ 

467 Read-only property to access the ID of the history node this one belongs to (:attr:`_parentID`). 

468 

469 :returns: The ID, e.g. of the merge, which merged this one; ``None``, if the report states none. 

470 """ 

471 return self._parentID 

472 

473 @readonly 

474 def PhysicalName(self) -> Nullable[Path]: 

475 """ 

476 Read-only property to access the path of the coverage database the history node wrote (:attr:`_physicalName`). 

477 

478 :returns: The path, as stated; ``None``, if the report states none. 

479 """ 

480 return self._physicalName 

481 

482 @readonly 

483 def Kind(self) -> Nullable[str]: 

484 """ 

485 Read-only property to access the kind of the history node (:attr:`_kind`). 

486 

487 :returns: The kind, as stated; ``None``, if the report states none. 

488 """ 

489 return self._kind 

490 

491 @readonly 

492 def SimulationTime(self) -> Nullable[float]: 

493 """ 

494 Read-only property to access how long the test ran in simulated time (:attr:`_simulationTime`). 

495 

496 :returns: The time, in :attr:`TimeUnit`; ``None``, if the report states none. 

497 """ 

498 return self._simulationTime 

499 

500 @readonly 

501 def TimeUnit(self) -> Nullable[str]: 

502 """ 

503 Read-only property to access the unit of the simulated time (:attr:`_timeUnit`). 

504 

505 :returns: The unit, e.g. ``ns``; ``None``, if the report states none. 

506 """ 

507 return self._timeUnit 

508 

509 @readonly 

510 def RunDirectory(self) -> Nullable[Path]: 

511 """ 

512 Read-only property to access the directory the test ran in (:attr:`_runDirectory`). 

513 

514 It is a path on the machine the coverage was measured on, so it may not exist where the report is read. 

515 

516 :returns: The directory; ``None``, if the report states none. 

517 """ 

518 return self._runDirectory 

519 

520 @readonly 

521 def CPUTime(self) -> Nullable[float]: 

522 """ 

523 Read-only property to access how long the test ran in CPU time (:attr:`_cpuTime`). 

524 

525 :returns: The time; ``None``, if the report states none. 

526 """ 

527 return self._cpuTime 

528 

529 @readonly 

530 def Seed(self) -> Nullable[str]: 

531 """ 

532 Read-only property to access the seed of the test's random numbers (:attr:`_seed`). 

533 

534 :returns: The seed; ``None``, if the report states none. 

535 """ 

536 return self._seed 

537 

538 @readonly 

539 def Command(self) -> Nullable[str]: 

540 """ 

541 Read-only property to access the command, which ran the test (:attr:`_command`). 

542 

543 :returns: The command; ``None``, if the report states none. 

544 """ 

545 return self._command 

546 

547 @readonly 

548 def Arguments(self) -> Nullable[str]: 

549 """ 

550 Read-only property to access the command line arguments of the test (:attr:`_arguments`). 

551 

552 :returns: The arguments; ``None``, if the report states none. 

553 """ 

554 return self._arguments 

555 

556 @readonly 

557 def Compulsory(self) -> Nullable[str]: 

558 """ 

559 Read-only property to access whether the test must run (:attr:`_compulsory`). 

560 

561 :returns: The value, as stated; ``None``, if the report states none. 

562 """ 

563 return self._compulsory 

564 

565 @readonly 

566 def UserName(self) -> Nullable[str]: 

567 """ 

568 Read-only property to access the name of the user, who ran the test (:attr:`_userName`). 

569 

570 :returns: The name; ``None``, if the report states none. 

571 """ 

572 return self._userName 

573 

574 @readonly 

575 def Cost(self) -> Nullable[Decimal]: 

576 """ 

577 Read-only property to access the cost of the test (:attr:`_cost`). 

578 

579 :returns: The cost; ``None``, if the report states none. 

580 """ 

581 return self._cost 

582 

583 @readonly 

584 def SameTests(self) -> Nullable[int]: 

585 """ 

586 Read-only property to access the ID of a test this one is equivalent to (:attr:`_sameTests`). 

587 

588 :returns: The ID; ``None``, if the report states none. 

589 """ 

590 return self._sameTests 

591 

592 @readonly 

593 def Comment(self) -> Nullable[str]: 

594 """ 

595 Read-only property to access the comment (:attr:`_comment`). 

596 

597 :returns: The comment; ``None``, if the report states none. 

598 """ 

599 return self._comment