Skip to content

Commit 2f179b4

Browse files
committed
JULIET: add more commands
1 parent 0492acf commit 2f179b4

File tree

4 files changed

+81
-7
lines changed

4 files changed

+81
-7
lines changed

chc/cmdline/chkc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,20 @@ def parse() -> argparse.Namespace:
525525

526526
julietscore.set_defaults(func=J.juliet_score)
527527

528+
# --- score-sets
529+
julietscoresets = julietparsers.add_parser("score-sets")
530+
julietscoresets.add_argument(
531+
"--maxprocesses",
532+
type=int,
533+
default=1,
534+
help="maximum number of processors to use")
535+
julietscoresets.add_argument(
536+
"--cwes",
537+
nargs="*",
538+
default=[],
539+
help="only score the tests with the given cwe's (default is all)")
540+
julietscoresets.set_defaults(func=J.juliet_score_sets)
541+
528542
# --- investigate
529543
julietinvestigate = julietparsers.add_parser("investigate")
530544
julietinvestigate.add_argument("cwe", help="name of cwe, e.g., CWE121")

chc/cmdline/juliet/JulietTestRef.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2727
# SOFTWARE.
2828
# ------------------------------------------------------------------------------
29+
"""Access to the reference results for a Juliet Test ."""
2930

3031
from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING
3132

@@ -39,6 +40,7 @@
3940

4041

4142
class JulietTestRef:
43+
4244
def __init__(
4345
self,
4446
testsetref: "JulietTestSetRef",

chc/cmdline/juliet/JulietTestSetRef.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2727
# SOFTWARE.
2828
# ------------------------------------------------------------------------------
29+
"""Access to the reference results for all Juliet Tests."""
2930

3031
from typing import Any, Callable, cast, Dict, List, Optional, TYPE_CHECKING
3132

chc/cmdline/juliet/julietutil.py

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2525
# SOFTWARE.
2626
# ------------------------------------------------------------------------------
27-
"""Implementation of juliet commands in the command-line interpreter."""
27+
"""Implementation of juliet commands in the CLI."""
2828

2929
import argparse
3030
import json
@@ -38,7 +38,7 @@
3838
from multiprocessing import Pool
3939

4040
from typing import (
41-
Any, Callable, Dict, List, NoReturn, Optional, Tuple, TYPE_CHECKING)
41+
Any, Callable, cast, Dict, List, NoReturn, Optional, Tuple, TYPE_CHECKING)
4242

4343
from chc.app.CApplication import CApplication
4444

@@ -382,7 +382,7 @@ def save_xrefs(f: "CFile") -> None:
382382
am.generate_and_check_app("llrvisp", processes=jmaxproc)
383383
capp.reinitialize_tables()
384384

385-
def filefilter(filename):
385+
def filefilter(filename: str) -> bool:
386386
return not (filename in ["io", "main_linux", "std_thread"])
387387

388388
contractviolations = capp.get_contract_condition_violations()
@@ -403,7 +403,7 @@ def filefilter(filename):
403403
exit(0)
404404

405405

406-
def analyze_test(testdata):
406+
def analyze_test(testdata: Tuple[str, str, int]) -> int:
407407
"""CLI command to run a juliet test case.
408408
409409
Note: this function needs to be global for multiprocessing to work.
@@ -427,7 +427,7 @@ def juliet_analyze_sets(args: argparse.Namespace) -> NoReturn:
427427
pool = Pool(jmaxproc)
428428
testcases = []
429429

430-
def excluded(cwe):
430+
def excluded(cwe: str) -> bool:
431431
if len(jcwes) == 0:
432432
return False
433433
else:
@@ -616,6 +616,61 @@ def juliet_score(args: argparse.Namespace) -> NoReturn:
616616
exit(0)
617617

618618

619+
def score_test(testdata: Tuple[str, str, int]) -> int:
620+
"""CLI command to score a juliet test case.
621+
622+
Note: this function needs to be global for multiprocessing to work.
623+
"""
624+
625+
(cwe, testcase, index) = testdata
626+
cmd = ["chkc", "juliet", "score", cwe, testcase]
627+
result = subprocess.call(cmd, stderr=subprocess.STDOUT)
628+
return result
629+
630+
631+
def juliet_score_sets(args: argparse.Namespace) -> NoReturn:
632+
"""Scores all or a subset of the registered juliet tests."""
633+
634+
# arguments
635+
jmaxproc: int = args.maxprocesses
636+
jcwes: List[str] = args.cwes
637+
638+
maxptxt = "" if jmaxproc == 1 else f" (with {jmaxproc} processors)"
639+
640+
pool = Pool(jmaxproc)
641+
testcases = []
642+
643+
def excluded(cwe: str) -> bool:
644+
if len(jcwes) == 0:
645+
return False
646+
else:
647+
return cwe not in jcwes
648+
649+
with timing("score-sets" + maxptxt):
650+
count: int = 0
651+
juliettests = UF.get_juliet_testcases()
652+
for cwe in sorted(juliettests):
653+
if excluded(cwe):
654+
continue
655+
print(f"Scoring testcases for cwe {cwe}")
656+
for subdir in sorted(juliettests[cwe]):
657+
for t in juliettests[cwe][subdir]:
658+
testcases.append((cwe, t, count))
659+
660+
results = pool.map(score_test, testcases)
661+
662+
print("\n" + ("=" * 80))
663+
if len(results) == results.count(0):
664+
print("All Juliet tests cases were scored successfully.")
665+
else:
666+
for x in range(len(results)):
667+
if results[x] != 0:
668+
print(f"Error in testcase {testcases[x][0]}")
669+
print("=" * 80)
670+
671+
exit(0)
672+
673+
619674
def juliet_investigate(args: argparse.Namespace) -> NoReturn:
620675
"""Lists problematic proof obligations."""
621676

@@ -978,8 +1033,10 @@ def juliet_project_dashboard(args: argparse.Namespace) -> NoReturn:
9781033
spo_project_totals[pname] = {}
9791034

9801035
if "stats" in results:
981-
projectstats[pname] = results["stats"]
982-
analysistimes[pname] = results["timestamp"]
1036+
# use casts to handle union type in loaded dictionary
1037+
projectstats[pname] = cast(
1038+
Tuple[int, int, int], results["stats"])
1039+
analysistimes[pname] = cast(int, results["timestamp"])
9831040
else:
9841041
projectstats[pname] = (0, 0, 0)
9851042

0 commit comments

Comments
 (0)