Skip to content

Commit

Permalink
Updated FaultReport class to handle the csv summary/report & updated …
Browse files Browse the repository at this point in the history
…unittests
  • Loading branch information
NikosDelijohn committed Sep 3, 2024
1 parent 910b273 commit 104332b
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 24 deletions.
62 changes: 49 additions & 13 deletions src/unit_tests/test_zoix.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,33 @@
import subprocess
import re

class FaultReportTest(unittest.TestCase):
class CSVFaultReportTest(unittest.TestCase):

def test_constructor(self):

test_obj = zoix.FaultReport(pathlib.Path("mock_report"))
self.assertEqual(test_obj.fault_report, pathlib.Path("mock_report").absolute())
test_obj = zoix.CSVFaultReport(pathlib.Path("mock_fault_summary"), pathlib.Path("mock_fault_report"))
self.assertEqual(test_obj.fault_summary, pathlib.Path("mock_fault_summary").absolute())
self.assertEqual(test_obj.fault_report, pathlib.Path("mock_fault_report").absolute())

def test_set_fault_summary(self):

test_obj = zoix.CSVFaultReport(pathlib.Path("mock_fault_summary"), pathlib.Path("mock_fault_report"))

with self.assertRaises(FileExistsError) as cm:

test_obj.set_fault_summary("new_mock_summary")

self.assertEqual(str(cm.exception), f"Fault summary new_mock_summary does not exist!")

with mock.patch("pathlib.Path.exists", return_value = True):

test_obj.set_fault_summary("new_mock_summary")

self.assertEqual(test_obj.fault_summary, pathlib.Path("new_mock_summary").absolute())

def test_set_fault_report(self):

test_obj = zoix.FaultReport(pathlib.Path("mock_report"))
test_obj = zoix.CSVFaultReport(pathlib.Path("mock_fault_summary"), pathlib.Path("mock_fault_report"))

with self.assertRaises(FileExistsError) as cm:

Expand All @@ -32,9 +49,9 @@ def test_set_fault_report(self):

self.assertEqual(test_obj.fault_report, pathlib.Path("new_mock_report").absolute())

def test_extract_fault_report_cell(self):
def test_extract_summary_cells_from_row(self):

test_obj = zoix.FaultReport(pathlib.Path("mock_report"))
test_obj = zoix.CSVFaultReport(pathlib.Path("mock_fault_summary"), pathlib.Path("mock_fault_report"))

with mock.patch("builtins.open", mock.mock_open(read_data="""\
"Category","Name","Label","Prime Cnt","Prime Pct","Prime Sub Pct","Total Cnt","Total Pct","Total Sub Pct"
Expand All @@ -54,9 +71,9 @@ def test_extract_fault_report_cell(self):
"Coverage","Diagnostic Coverage","","","0.00%","","","0.00%",""
"Coverage","Observational Coverage","","","67.58%","","","68.00%",""""")):

diagnostic_coverage = test_obj.extract_fault_report_cells(15,8)
observationL_coverage = test_obj.extract_fault_report_cells(16,8)
total_faults = test_obj.extract_fault_report_cells(2,2,4,7)
diagnostic_coverage = test_obj.extract_summary_cells_from_row(15,8)
observationL_coverage = test_obj.extract_summary_cells_from_row(16,8)
total_faults = test_obj.extract_summary_cells_from_row(2,2,4,7)

self.assertEqual(diagnostic_coverage, ["0.00%"])
self.assertEqual(observationL_coverage, ["68.00%"])
Expand All @@ -65,16 +82,35 @@ def test_extract_fault_report_cell(self):
# Row is out of bounds
with self.assertRaises(IndexError) as cm:

test_obj.extract_fault_report_cells(20,1)
test_obj.extract_summary_cells_from_row(20,1)

self.assertEqual(str(cm.exception), f"Row 20 is out of bounds for fault report {test_obj.fault_report}.")
self.assertEqual(str(cm.exception), f"Row 20 is out of bounds for fault summary {test_obj.fault_summary}.")

# Column is out of bounds
with self.assertRaises(IndexError) as cm:

test_obj.extract_fault_report_cells(10,1,20)
test_obj.extract_summary_cells_from_row(10,1,20)

self.assertEqual(str(cm.exception), f"A column in (1, 20) is out of bounds for row 10 of fault summary {test_obj.fault_summary}.")

def test_parse_fault_report(self):

test_obj = zoix.CSVFaultReport(pathlib.Path("mock_fault_summary"), pathlib.Path("mock_fault_report"))

with mock.patch("builtins.open", mock.mock_open(read_data='''\
"FID","Test Name","Prime","Status","Model","Timing","Cycle Injection","Cycle End","Class","Location"
1,"test1","yes","ON","0","","","","PORT","path_to_fault_1.portA"
2,"test1",1,"ON","0","","","","PORT","path_to_fault_2.portB"
3,"test1","yes","ON","1","","","","PORT","path_to_fault_3.portC"''')):

report = test_obj.parse_fault_report()
expected_report = [
zoix.SffFault("1", "test1", "yes", "ON", "0", "", "", "", "PORT", "path_to_fault_1.portA"),
zoix.SffFault("2", "test1", "1", "ON", "0", "", "", "", "PORT", "path_to_fault_2.portB"),
zoix.SffFault("3", "test1", "yes", "ON", "1", "", "", "", "PORT", "path_to_fault_3.portC"),
]

self.assertEqual(str(cm.exception), f"A column in (1, 20) is out of bounds for row 10 of fault report {test_obj.fault_report}.")
self.assertEqual(report, expected_report)

class ZoixInvokerTest(unittest.TestCase):

Expand Down
74 changes: 63 additions & 11 deletions src/zoix.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import enum
import pathlib
import csv
from dataclasses import dataclass

######## TEMPORARY ########
log = logging.getLogger("testcrush logger")
Expand Down Expand Up @@ -267,11 +268,40 @@ def fault_simulate(self, *instructions : str, **kwargs) -> FaultSimulation:

return fault_simulation_status

class FaultReport():

def __init__(self, fault_report : pathlib.Path) -> "FaultReport":
@dataclass
class SffFault():
"""Represents a fault which is compliant with the standard fault format of Synopsys."""
fid : str
test_name : str
prime : str
status : str
model : str
timing : str
cycle_injection : str
cycle_end : str
fault_class : str
location : str

class CSVFaultReport():

def __init__(self, fault_summary : pathlib.Path, fault_report : pathlib.Path) -> "FaultReport":
self.fault_summary : pathlib.Path = fault_summary.absolute()
self.fault_report : pathlib.Path = fault_report.absolute()

def set_fault_summary(self, fault_summary : str) -> None:
"""Setter method for fault summary.
- Parameters:
- fault_summary (str): The new fault summary filename.
- Returns:
- None. Raises FileExistsError if the file does not exist."""

if not pathlib.Path(fault_summary).exists():
raise FileExistsError(f"Fault summary {fault_summary} does not exist!")

self.fault_summary = pathlib.Path(fault_summary).absolute()

def set_fault_report(self, fault_report : str) -> None:
"""Setter method for fault report.
Expand All @@ -286,17 +316,17 @@ def set_fault_report(self, fault_report : str) -> None:

self.fault_report = pathlib.Path(fault_report).absolute()

def extract_fault_report_cells(self, row : int, *cols : int) -> list[str]:
"""Returns a sequence of cells from a row of the CSV fault report.
def extract_summary_cells_from_row(self, row : int, *cols : int) -> list[str]:
"""Returns a sequence of cells from a row of the `self.fault_summary` **CSV** file.
- Parameters:
- row (int): the row number (1-based indexing).
- *cols (ints): the columns' numbers (1-based indexing).
- Returns:
list[str]: The cells of the fault report."""
- list[str]: The cells of the fault summary."""

with open(self.fault_report) as csv_source:
with open(self.fault_summary) as csv_source:

reader = csv.reader(csv_source)

Expand All @@ -308,9 +338,29 @@ def extract_fault_report_cells(self, row : int, *cols : int) -> list[str]:
try:
return [csv_row[col - 1] for col in cols]
except:
raise IndexError(f"A column in {cols} is out of bounds for row {row} of fault report {self.fault_report}.")
raise IndexError(f"A column in {cols} is out of bounds for row {row} of fault summary {self.fault_summary}.")

raise IndexError(f"Row {row} is out of bounds for fault summary {self.fault_summary}.")

def parse_fault_report(self) -> list[SffFault]:
"""Parses the `self.fault_report` **CSV** file and returns a dictionary with its
contents, ommiting any column if specified.
- Parameters:
- None:
- Returns:
- list[SffFault]: A list with synopys fault format objects.
"""

with open(self.fault_report) as csv_source:

reader = csv.reader(csv_source)

# Skip header
next(reader)

raise IndexError(f"Row {row} is out of bounds for fault report {self.fault_report}.")
return [ SffFault(*csv_row) for csv_row in reader ]

def main():

Expand Down Expand Up @@ -341,9 +391,11 @@ def main():
print(tat_dict['tat_value'])
print(res)

B = FaultReport("summary.csv.log")
print(B.extract_csv_cell(16,8))
B = CSVFaultReport(pathlib.Path("summary.csv.log"), pathlib.Path("sample.csv"))
print(B.extract_summary_cells_from_row(16,8))
report = B.parse_fault_report()

print(report)
if __name__ == "__main__":

main()

0 comments on commit 104332b

Please sign in to comment.