Skip to content

Commit 018e2ed

Browse files
Enabling Test Framework for the assembler (#84)
* Adding test framework * Fixing Github actions * Adding PyTest dependency * Added path to pytest.ini --------- Co-authored-by: christopherngutierrez <[email protected]>
1 parent eea0c13 commit 018e2ed

File tree

9 files changed

+248
-2
lines changed

9 files changed

+248
-2
lines changed

.github/workflows/format.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,15 @@ jobs:
2020
with:
2121
python-version: '3.10'
2222

23+
- name: Install dependencies
24+
run: pip install -r assembler_tools/hec-assembler-tools/requirements.txt
25+
2326
- name: Install pre-commit
2427
run: pip install pre-commit
2528

29+
- name: Install pylint
30+
run: pip install pylint
31+
2632
- name: Fetch main branch for diff
2733
run: git fetch origin main
2834

.github/workflows/hec-asm-test.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: HEC Assembler Tools Tests
2+
on:
3+
push:
4+
branches: [main]
5+
paths:
6+
- 'assembler_tools/hec-assembler-tools/**'
7+
pull_request:
8+
branches: [main]
9+
paths:
10+
- 'assembler_tools/hec-assembler-tools/**'
11+
12+
permissions:
13+
contents: read
14+
15+
jobs:
16+
test:
17+
runs-on: ubuntu-latest
18+
defaults:
19+
run:
20+
working-directory: assembler_tools/hec-assembler-tools
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- name: Set up Python
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: '3.10'
28+
29+
- name: Install dependencies
30+
run: |
31+
pip install -r requirements.txt
32+
pip install pytest
33+
34+
- name: Check for changes in hec-assembler-tools
35+
id: changes
36+
uses: dorny/paths-filter@v3
37+
with:
38+
filters: |
39+
module:
40+
- '**'
41+
42+
- name: Run unit tests
43+
if: steps.changes.outputs.module == 'true'
44+
run: pytest tests

HEADER

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Copyright (C) 2024 Intel Corporation
1+
Copyright (C) 2025 Intel Corporation
22
SPDX-License-Identifier: Apache-2.0
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[run]
2+
branch = True
3+
source = .
4+
omit =
5+
tests/*
6+
7+
[report]
8+
show_missing = True
9+
skip_covered = True
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[pytest]
2+
pythonpath = .
3+
testpaths = tests
4+
#addopts = --cov=.

assembler_tools/hec-assembler-tools/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ networkx==3.0
88
numpy==1.24.2
99
packaging==23.0
1010
Pillow==10.3.0
11+
pytest==8.4.0
1112
python-dateutil==2.8.2
1213
PyYAML==6.0
1314
six==1.16.0
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright (C) 2025 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""
5+
Pytest configuration and fixtures for assembler_tools tests.
6+
"""
7+
8+
import os
9+
import pytest
10+
from assembler.spec_config.isa_spec import ISASpecConfig
11+
from assembler.spec_config.mem_spec import MemSpecConfig
12+
13+
14+
@pytest.fixture(scope="session", autouse=True)
15+
def initialize_specs():
16+
"""
17+
Fixture to initialize ISA and memory specifications for test session.
18+
19+
This fixture is automatically used for the entire test session and ensures that
20+
the ISA and memory specifications are initialized before any tests are run.
21+
It determines the module directory relative to the current file and calls the
22+
initialization methods for both ISASpecConfig and MemSpecConfig.
23+
24+
Note:
25+
This fixture is intended to be run from the assembler root directory.
26+
27+
Yields:
28+
None
29+
30+
Raises:
31+
Any exceptions raised by ISASpecConfig.initialize_isa_spec or
32+
MemSpecConfig.initialize_mem_spec will propagate.
33+
"""
34+
module_dir = os.path.dirname(os.path.dirname(__file__))
35+
ISASpecConfig.initialize_isa_spec(module_dir, "")
36+
MemSpecConfig.initialize_mem_spec(module_dir, "")
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Copyright (C) 2025 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""
5+
Unit tests for he_prep module.
6+
"""
7+
8+
from unittest import mock
9+
import os
10+
import sys
11+
import pathlib
12+
import pytest
13+
import he_prep
14+
15+
16+
def test_main_assigns_and_saves(monkeypatch, tmp_path):
17+
"""
18+
Test that the main function assigns register banks, processes instructions, and saves the output.
19+
20+
This test uses monkeypatching to mock dependencies and verifies that the output file
21+
contains the expected instruction after processing a dummy input file.
22+
"""
23+
# Prepare dummy input file
24+
input_file = tmp_path / "input.csv"
25+
input_file.write_text("dummy")
26+
output_file = tmp_path / "output.csv"
27+
28+
dummy_model = object()
29+
dummy_insts = [mock.Mock(toPISAFormat=mock.Mock(return_value="inst1"))]
30+
31+
monkeypatch.setattr(he_prep, "MemoryModel", mock.Mock(return_value=dummy_model))
32+
monkeypatch.setattr(
33+
he_prep.preprocessor,
34+
"preprocessPISAKernelListing",
35+
mock.Mock(return_value=dummy_insts),
36+
)
37+
monkeypatch.setattr(he_prep.preprocessor, "assignRegisterBanksToVars", mock.Mock())
38+
39+
he_prep.main(str(output_file), str(input_file), b_verbose=False)
40+
# Output file should contain the instruction
41+
assert output_file.read_text().strip() == "inst1"
42+
43+
44+
def test_main_no_input_file():
45+
"""
46+
Test that main raises an error when no input file is provided.
47+
"""
48+
with pytest.raises(FileNotFoundError):
49+
he_prep.main(
50+
"", "", b_verbose=False
51+
) # Should raise an error due to missing input file
52+
53+
54+
def test_main_no_output_file():
55+
"""
56+
Test that main raises an error when no output file is provided.
57+
"""
58+
with pytest.raises(FileNotFoundError):
59+
he_prep.main(
60+
"", "input.csv", b_verbose=False
61+
) # Should raise an error due to missing output file
62+
63+
64+
def test_main_no_instructions(monkeypatch):
65+
"""
66+
Test that main handles the case where no instructions are processed.
67+
68+
This test checks that the function can handle an empty instruction list without errors.
69+
"""
70+
input_file = "empty_input.csv"
71+
output_file = "empty_output.csv"
72+
73+
with open(input_file, "w", encoding="utf-8") as f:
74+
f.write("") # Create an empty input file
75+
76+
dummy_model = object()
77+
monkeypatch.setattr(he_prep, "MemoryModel", mock.Mock(return_value=dummy_model))
78+
monkeypatch.setattr(
79+
he_prep.preprocessor, "preprocessPISAKernelListing", mock.Mock(return_value=[])
80+
)
81+
monkeypatch.setattr(he_prep.preprocessor, "assignRegisterBanksToVars", mock.Mock())
82+
83+
he_prep.main(output_file, input_file, b_verbose=False)
84+
85+
# Output file should be empty
86+
output_file_path = pathlib.Path(output_file)
87+
assert (
88+
not output_file_path.exists()
89+
or output_file_path.read_text(encoding="utf-8").strip() == ""
90+
)
91+
92+
93+
def test_main_invalid_input_file(tmp_path):
94+
"""
95+
Test that main raises an error when the input file does not exist.
96+
"""
97+
input_file = tmp_path / "non_existent.csv"
98+
output_file = tmp_path / "output.csv"
99+
100+
with pytest.raises(FileNotFoundError):
101+
he_prep.main(
102+
str(output_file), str(input_file), b_verbose=False
103+
) # Should raise an error due to missing input file
104+
105+
106+
def test_main_invalid_output_file(tmp_path):
107+
"""
108+
Test that main raises an error when the output file cannot be created.
109+
This test checks that the function handles file permission errors gracefully.
110+
"""
111+
input_file = tmp_path / "input.csv"
112+
input_file.write_text("") # Write empty string to avoid SyntaxError
113+
output_file = tmp_path / "output.csv"
114+
115+
# Make the output file read-only
116+
output_file.touch()
117+
os.chmod(output_file, 0o444) # Read-only permissions
118+
119+
with pytest.raises(PermissionError):
120+
he_prep.main(
121+
str(output_file), str(input_file), b_verbose=False
122+
) # Should raise an error due to permission issues
123+
124+
125+
def test_parse_args():
126+
"""
127+
Test that parse_args returns the expected arguments.
128+
"""
129+
test_args = [
130+
"prog",
131+
"input.csv",
132+
"output.csv",
133+
"--isa_spec",
134+
"isa.json",
135+
"--mem_spec",
136+
"mem.json",
137+
"--verbose",
138+
]
139+
with mock.patch.object(sys, "argv", test_args):
140+
args = he_prep.parse_args()
141+
142+
assert args.output_file_name == "output.csv"
143+
assert args.input_file_name == "input.csv"
144+
assert args.isa_spec_file == "isa.json"
145+
assert args.mem_spec_file == "mem.json"
146+
assert args.verbose == 1

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[pytest]
2-
pythonpath = p-isa_tools/kerngen
2+
pythonpath = p-isa_tools/kerngen assembler_tools/hec-assembler-tools

0 commit comments

Comments
 (0)