Skip to content

Commit 290f547

Browse files
committed
Add tests for executable
1 parent 08dcd9c commit 290f547

File tree

11 files changed

+273
-5
lines changed

11 files changed

+273
-5
lines changed

.dockerignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@ INCHI-1-TEST/data/
33
INCHI-1-TEST/docs/
44
INCHI-1-TEST/libs/
55
INCHI-1-TEST/exes/
6-
INCHI-1-TEST/tests/
76
**/__pycache__/
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: Compile InChI executable from triggering commit
2+
3+
runs:
4+
using: "composite"
5+
steps:
6+
- run: |
7+
git config --global --add safe.directory "$GITHUB_WORKSPACE" # https://github.com/actions/runner-images/issues/6775
8+
mkdir "$GITHUB_WORKSPACE/$EXE_DIR"
9+
./INCHI-1-TEST/compile_inchi.sh $COMMIT "$GITHUB_WORKSPACE/$EXE_DIR" exe
10+
shell: bash
11+
env:
12+
COMMIT: ${{ github.sha }}
13+
EXE_DIR: INCHI-1-TEST/exes

.github/workflows/ci.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ jobs:
2121
run: |
2222
python -m pip install --upgrade pip
2323
python -m pip install -e INCHI-1-TEST[invariance-tests]
24+
25+
- uses: ./.github/actions/compile_inchi_exe
26+
- name: Run executable tests
27+
run: pytest INCHI-1-TEST/tests/test_executable
28+
2429
- uses: ./.github/actions/compile_inchi_lib
2530
- uses: ./.github/actions/regression_tests
2631
with:
@@ -41,7 +46,7 @@ jobs:
4146
steps:
4247
- name: Install build and test environment
4348
run: |
44-
apk add bash git musl-dev gcc make python3 py-pip
49+
apk add bash git musl-dev gcc g++ make python3 py-pip
4550
# We need to install git before checking out the repository.
4651
# Otherwise, the repository will be downloaded using the GitHub REST API instead of git.
4752
- uses: actions/checkout@v4
@@ -59,6 +64,11 @@ jobs:
5964
run: |
6065
python -m pip install --upgrade pip
6166
python -m pip install -e INCHI-1-TEST
67+
68+
- uses: ./.github/actions/compile_inchi_exe
69+
- name: Run executable tests
70+
run: pytest INCHI-1-TEST/tests/test_executable
71+
6272
- uses: ./.github/actions/compile_inchi_lib
6373
- uses: ./.github/actions/regression_tests
6474
with:

INCHI-1-TEST/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,22 @@ RUN mkdir $lib_dir && for version in $inchi_versions; do \
3232
/inchi/INCHI-1-TEST/compile_inchi.sh "$version" "$lib_dir" lib || exit 1; \
3333
done
3434

35+
ENV exe_dir="/inchi/INCHI-1-TEST/exes"
36+
RUN for version in $inchi_versions; do \
37+
version_dir="${exe_dir}/${version}"; \
38+
mkdir -p $version_dir; \
39+
/inchi/INCHI-1-TEST/compile_inchi.sh "$version" "$version_dir" exe || exit 1; \
40+
done
41+
3542
FROM gcc:14-bookworm AS inchi_test
3643

3744
WORKDIR /inchi
3845

3946
# Include only what's necessary for running the tests.
4047
COPY --from=inchi_compilation /inchi/INCHI-1-TEST/src /inchi/INCHI-1-TEST/src
4148
COPY --from=inchi_compilation /inchi/INCHI-1-TEST/libs /inchi/INCHI-1-TEST/libs
49+
COPY --from=inchi_compilation /inchi/INCHI-1-TEST/exes /inchi/INCHI-1-TEST/exes
50+
COPY --from=inchi_compilation /inchi/INCHI-1-TEST/tests /inchi/INCHI-1-TEST/tests
4251
COPY --from=inchi_compilation /inchi/INCHI-1-TEST/pyproject.toml /inchi/INCHI-1-TEST/pyproject.toml
4352
COPY --from=inchi_compilation /inchi/INCHI-1-TEST/install.sh /inchi/INCHI-1-TEST/install.sh
4453

INCHI-1-TEST/install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
apt update && apt install -y python3-pip cmake
44
python3 -m pip install --upgrade --break-system-packages pip
5-
python3 -m pip install --break-system-packages -e .[invariance-tests,development]
5+
python3 -m pip install --break-system-packages -e .[invariance-tests]
66
# Make `python3` available as `python`.
77
update-alternatives --install /usr/bin/python python /usr/bin/python3 10

INCHI-1-TEST/pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
name = "inchi_tests"
33
version = "1.0.0"
44
requires-python = ">=3.11"
5-
dependencies = ["pydantic == 2.7.1"]
5+
dependencies = ["pydantic == 2.7.1", "pytest == 8.3.3"]
66

77
[project.optional-dependencies]
88
# FIXME: We're forcing numpy major version for now until https://github.com/kuelumbus/rdkit-pypi/issues/102 is resolved.
99
invariance-tests = ["rdkit == 2023.9.6", "numpy < 2.0.0"]
10-
development = ["pytest"]
1110

1211
[project.scripts]
1312
run-tests = "inchi_tests.run_tests:main"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Executable tests
2+
3+
Test specific behaviors of the executable.
4+
Ensure that specific input (molfile and arguments) elicits specific output (e.g., error).
5+
6+
Where possible, stick to the following principles:
7+
- Define input inline rather than using external files (having entire test scenario on screen is nice).
8+
- Keep number of tests per file to a minimum.
9+
- When replicating a bug, reference the (GitHub) issue number in the file name (e.g., `test_github_42.py`).
10+
11+
Have a look at the existing tests for examples on how to write a test.
12+
13+
Run with `pytest INCHI-1-TEST/tests/test_executable`.
14+
Note that by default, the tests expect the InChI executable to live at `INCHI-1-TEST/exes/inchi-1`.
15+
You can specify another InChI executable like so:
16+
17+
```shell
18+
pytest INCHI-1-TEST/tests/test_executable --exe-path=path/to/executable
19+
```
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import pytest
2+
import subprocess
3+
from typing import Callable
4+
from pathlib import Path
5+
6+
7+
def pytest_addoption(parser):
8+
parser.addoption(
9+
"--exe-path",
10+
action="store",
11+
default="INCHI-1-TEST/exes/inchi-1",
12+
help="Absolute path to the InChI executable.",
13+
)
14+
15+
16+
@pytest.fixture
17+
def run_inchi_exe(request) -> Callable:
18+
def _run_inchi_exe(
19+
molfile_path: str, args: str = ""
20+
) -> subprocess.CompletedProcess:
21+
22+
exe_path: str = request.config.getoption("--exe-path")
23+
if not Path(exe_path).exists():
24+
raise FileNotFoundError(f"InChI executable not found at {exe_path}.")
25+
26+
return subprocess.run(
27+
[exe_path, molfile_path, args],
28+
capture_output=True,
29+
)
30+
31+
return _run_inchi_exe
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from typing import Callable
2+
from pathlib import Path
3+
4+
5+
def tmp_molfile(molfile: Callable) -> Callable:
6+
"""
7+
Creates a temporary molfile and returns its path.
8+
9+
`molfile` must return a string.
10+
"""
11+
12+
def get_molfile_path(tmp_path: Path) -> str:
13+
molfile_path = tmp_path.joinpath("tmp.mol")
14+
molfile_path.write_text(molfile())
15+
16+
return str(molfile_path)
17+
18+
return get_molfile_path
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import pytest
2+
from helpers import tmp_molfile
3+
4+
5+
@pytest.fixture
6+
@tmp_molfile
7+
def molfile():
8+
return """(R)-SDP
9+
ChemDraw08122419562D
10+
11+
43 50 0 0 1 0 0 0 0 0999 V2000
12+
-0.7846 -1.0799 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
13+
-1.4991 -1.4924 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
14+
-2.2136 -1.0799 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
15+
-2.2136 -0.2549 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
16+
-1.4991 0.1576 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
17+
-1.7813 0.9328 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
18+
-1.2510 1.5648 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
19+
-1.5331 2.3400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
20+
-1.0028 2.9720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
21+
-0.1904 2.8288 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
22+
0.0918 2.0535 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
23+
-0.4385 1.4215 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
24+
-2.5937 1.0761 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
25+
-3.1240 0.4441 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
26+
-3.9365 0.5873 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
27+
-4.2187 1.3626 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
28+
-3.6884 1.9946 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
29+
-2.8759 1.8513 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
30+
-0.7846 -0.2549 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
31+
0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
32+
-0.4849 0.6674 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
33+
0.0000 1.3349 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
34+
0.7846 1.0799 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
35+
0.7846 0.2549 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
36+
1.4991 -0.1576 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
37+
1.7813 -0.9328 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
38+
2.5937 -1.0761 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
39+
2.8759 -1.8513 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
40+
3.6884 -1.9946 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
41+
4.2187 -1.3626 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
42+
3.9365 -0.5873 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
43+
3.1240 -0.4441 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
44+
1.2510 -1.5648 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
45+
0.4385 -1.4215 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
46+
-0.0918 -2.0535 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
47+
0.1904 -2.8288 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
48+
1.0028 -2.9720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
49+
1.5331 -2.3400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
50+
2.2136 0.2549 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
51+
2.2136 1.0799 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
52+
1.4991 1.4924 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
53+
0.4849 -0.6674 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
54+
0.0000 -1.3349 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
55+
1 2 2 0 0
56+
2 3 1 0 0
57+
3 4 2 0 0
58+
4 5 1 0 0
59+
5 6 1 0 0
60+
6 7 1 0 0
61+
7 8 2 0 0
62+
8 9 1 0 0
63+
9 10 2 0 0
64+
10 11 1 0 0
65+
11 12 2 0 0
66+
7 12 1 0 0
67+
6 13 1 0 0
68+
13 14 2 0 0
69+
14 15 1 0 0
70+
15 16 2 0 0
71+
16 17 1 0 0
72+
17 18 2 0 0
73+
13 18 1 0 0
74+
5 19 2 0 0
75+
1 19 1 0 0
76+
20 19 1 1 0
77+
20 21 1 0 0
78+
21 22 1 0 0
79+
22 23 1 0 0
80+
23 24 2 0 0
81+
20 24 1 0 0
82+
24 25 1 0 0
83+
25 26 1 0 0
84+
26 27 1 0 0
85+
27 28 2 0 0
86+
28 29 1 0 0
87+
29 30 2 0 0
88+
30 31 1 0 0
89+
31 32 2 0 0
90+
27 32 1 0 0
91+
26 33 1 0 0
92+
33 34 2 0 0
93+
34 35 1 0 0
94+
35 36 2 0 0
95+
36 37 1 0 0
96+
37 38 2 0 0
97+
33 38 1 0 0
98+
25 39 2 0 0
99+
39 40 1 0 0
100+
40 41 2 0 0
101+
23 41 1 0 0
102+
20 42 1 6 0
103+
42 43 1 0 0
104+
1 43 1 0 0
105+
M END
106+
"""
107+
108+
109+
@pytest.mark.xfail(strict=True, raises=AssertionError)
110+
def test_spiro_compound_chiral(molfile, run_inchi_exe):
111+
result = run_inchi_exe(molfile)
112+
113+
assert "Warning (Not chiral) structure #1." not in result.stderr.decode()

0 commit comments

Comments
 (0)