1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
# ==================================================================================================================== #
# _____ ____ _ _ ___ ______ ____ ____ __ #
# _ __ _ _| ____| _ \ / \ / \ / _ \/ ___\ \ / /\ \ / / \/ | #
# | '_ \| | | | _| | | | |/ _ \ / _ \ | | | \___ \\ \ / / \ \ / /| |\/| | #
# | |_) | |_| | |___| |_| / ___ \ / ___ \ | |_| |___) |\ V / \ V / | | | | #
# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)___/|____/ \_/ \_/ |_| |_| #
# |_| |___/ #
# ==================================================================================================================== #
# Authors: #
# Patrick Lehmann #
# #
# License: #
# ==================================================================================================================== #
# Copyright 2025-2025 Patrick Lehmann - Boetzingen, Germany #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); #
# you may not use this file except in compliance with the License. #
# You may obtain a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
# #
# SPDX-License-Identifier: Apache-2.0 #
# ==================================================================================================================== #
#
from argparse import Namespace
from pathlib import Path
from sys import stdin
from typing import NoReturn
from pyTooling.Decorators import readonly
from pyTooling.MetaClasses import ExtendedType
from pyTooling.Common import count
from pyTooling.Attributes.ArgParse import CommandHandler
from pyTooling.Attributes.ArgParse.Flag import LongFlag
from pyTooling.Attributes.ArgParse.ValuedFlag import LongValuedFlag
from pyTooling.Stopwatch import Stopwatch
from pyEDAA.OSVVM.Project.TCL import OsvvmProFileProcessor
class ProjectHandlers(metaclass=ExtendedType, mixin=True):
@CommandHandler("project", help="Parse OSVVM project description.", description="Merge and/or transform unit testing results.")
@LongFlag("--stdin", dest="stdin", help="OSVVM build file (PRO).")
@LongValuedFlag("--regressionTCL", dest="regressionTCL", metaName='TCL file', optional=True, help="Regression file (TCL).")
@LongValuedFlag("--buildPro", dest="buildPro", metaName='PRO file', optional=True, help="OSVVM build file (PRO).")
@LongValuedFlag("--render", dest="render", metaName='format', optional=True, help="Render unit testing results to <format>.")
def HandleUnittest(self, args: Namespace) -> None:
"""Handle program calls with command ``unittest``."""
self._PrintHeadline()
returnCode = 0
if (args.stdin is None and args.regressionTCL is None and args.buildPro is None):
self.WriteError(f"Either option '--stdin' or '--regressionTCL=<TCL file>' or '--buildPro=<PRO file>' is missing.")
returnCode = 3
if returnCode != 0:
self.Exit(returnCode)
sw = Stopwatch(preferPause=True)
processor = OsvvmProFileProcessor()
if args.stdin is True:
self.WriteNormal(f"Reading TCL code from STDIN ...")
tclCode = stdin.read()
with sw:
processor.EvaluateTclCode(tclCode)
project = processor.Context.ToProject("unnamed")
elif args.regressionTCL is not None:
self.WriteNormal(f"Reading regression TCL file ...")
with sw:
project = processor.LoadRegressionFile(Path(args.regressionTCL))
elif args.buildPro is not None:
for proFile in args.buildPro.split(":"):
file = Path(proFile)
self.WriteNormal(f"Reading OSVVM build file '{file}' ...")
with sw:
processor.LoadBuildFile(file)
project = processor.Context.ToProject("unnamed")
else:
self.Exit(1)
self.WriteNormal(f" Parsing duration: {sw.Duration:.3f} s")
self.WriteNormal(f" Builds: {len(project.Builds)}")
self.WriteNormal(f" Processed files: {count(project.IncludedFiles)}")
if args.render == "all":
for build in project.Builds.values():
print(f"Build: {build.Name}")
for libraryName, lib in build.VHDLLibraries.items():
print(f" Library: {libraryName} ({len(lib.Files)})")
for file in lib.Files:
print(f" {file}")
print("-" * 60)
for testsuiteName, ts in build.Testsuites.items():
print(f" Testsuite: {testsuiteName} ({len(ts.Testcases)})")
for tc in ts.Testcases.values():
print(f" {tc.Name}")
print("=" * 60)
self.ExitOnPreviousErrors()
|