Skip to content

Commit

Permalink
Modular binfile download in CI. Tests now expect binfile directory pa…
Browse files Browse the repository at this point in the history
…rameter.
  • Loading branch information
disinvite committed Mar 9, 2025
1 parent 0bdcc1b commit d3289d1
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 81 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/binfile-lego.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Download LEGO binaries

on:
workflow_call:

jobs:
lego:
runs-on: ubuntu-latest
steps:

- name: Restore original binaries
id: cache
uses: actions/cache@v3
with:
path: binfiles
key: legobin

- name: Download original island binaries
if: ${{ !steps.cache.outputs.cache-hit }}
run: |
wget https://legoisland.org/download/CONFIG.EXE --directory-prefix=binfiles
wget https://legoisland.org/download/ISLE.EXE --directory-prefix=binfiles
wget https://legoisland.org/download/LEGO1.DLL --directory-prefix=binfiles
- name: Verify files
run: |
echo "864766d024d78330fed5e1f6efb2faf815f1b1c3405713a9718059dc9a54e52c binfiles/CONFIG.EXE" | sha256sum --check
echo "5cf57c284973fce9d14f5677a2e4435fd989c5e938970764d00c8932ed5128ca binfiles/ISLE.EXE" | sha256sum --check
echo "14645225bbe81212e9bc1919cd8a692b81b8622abb6561280d99b0fc4151ce17 binfiles/LEGO1.DLL" | sha256sum --check
26 changes: 26 additions & 0 deletions .github/workflows/binfile-ski.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Download SKI binary

on:
workflow_call:

jobs:
ski:
runs-on: ubuntu-latest
steps:

- name: Restore original binaries
id: cache
uses: actions/cache@v3
with:
path: binfiles
key: skibin

- name: Download original ski binaries
if: ${{ !steps.cache.outputs.cache-hit }}
run: |
wget https://archive.org/download/win3_SKIFREE/SKIFREE.ZIP
unzip -d binfiles SKIFREE.ZIP SKI.EXE
- name: Verify files
run: |
echo "0b97b99fcf34af5f5d624080417c79c7d36ae11351a7870ce6e0a476f03515c2 binfiles/SKI.EXE" | sha256sum --check
40 changes: 40 additions & 0 deletions .github/workflows/binfiles.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Prepare sample binaries

on:
workflow_call:

jobs:
lego:
name: Download LEGO
uses: ./.github/workflows/binfile-lego.yml

ski:
name: Download SKI
uses: ./.github/workflows/binfile-ski.yml

merge:
needs: [lego, ski]
runs-on: ubuntu-latest
steps:

- name: Restore LEGO
uses: actions/cache/restore@v3
with:
path: binfiles
key: legobin
fail-on-cache-miss: true

- name: Restore SKI
uses: actions/cache/restore@v3
with:
path: binfiles
key: skibin
fail-on-cache-miss: true

- name: Cache binfiles
uses: actions/cache@v3
with:
enableCrossOsArchive: true
path: binfiles
key: binfiles-${{ hashFiles('binfiles/*') }}
restore-keys: binfiles
42 changes: 0 additions & 42 deletions .github/workflows/legobin.yml

This file was deleted.

12 changes: 6 additions & 6 deletions .github/workflows/unittest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on: [push, pull_request]
jobs:
fetch-deps:
name: Prepare sample binary files
uses: ./.github/workflows/legobin.yml
uses: ./.github/workflows/binfiles.yml

test:
name: '${{ matrix.platform.name }} ${{ matrix.python-version }}'
Expand All @@ -28,13 +28,13 @@ jobs:
python-version: ${{ matrix.python-version }}
cache: 'pip'

- name: Restore lego files
id: cache-lego
- name: Restore sample binaries
id: cache
uses: actions/cache/restore@v3
with:
enableCrossOsArchive: true
path: legobin
key: legobin
path: binfiles
key: binfiles

- name: Restore skifree files
id: cache-skifree
Expand All @@ -52,4 +52,4 @@ jobs:
- name: Run unit tests
shell: bash
run: |
pytest . --lego1=legobin/LEGO1.DLL --ski=skifree/SKI.EXE
pytest . --binfiles=binfiles --require-binfiles
2 changes: 2 additions & 0 deletions tests/binfiles/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
83 changes: 51 additions & 32 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,77 @@
import hashlib
from pathlib import Path
from typing import Iterator
from typing import Callable, Iterator
import pytest

from reccmp.isledecomp import NEImage, PEImage, detect_image
from reccmp.isledecomp import Image, NEImage, PEImage, detect_image


def pytest_addoption(parser):
"""Allow the option to run tests against sample binaries."""
parser.addoption("--lego1", action="store", help="Path to LEGO1.DLL")
parser.addoption("--ski", action="store", help="Path to SKI.EXE")
parser.addoption("--binfiles", action="store", help="Path to sample binary files.")
parser.addoption(
"--require-binfiles",
action="store_true",
help="Fail tests that depend on binary samples if we cannot load them.",
)


# LEGO1.DLL: v1.1 English, September
LEGO1_SHA256 = "14645225bbe81212e9bc1919cd8a692b81b8622abb6561280d99b0fc4151ce17"
def check_hash(path: Path, hash_str: str) -> bool:
with path.open("rb") as f:
digest = hashlib.sha256(f.read()).hexdigest()
return digest == hash_str

# SkiFree 1.0
# https://ski.ihoc.net/
SKI_SHA256 = "0b97b99fcf34af5f5d624080417c79c7d36ae11351a7870ce6e0a476f03515c2"


@pytest.fixture(name="binfile", scope="session")
def fixture_binfile(pytestconfig) -> Iterator[PEImage]:
filename = pytestconfig.getoption("--lego1")
@pytest.fixture(name="bin_loader", scope="session")
def fixture_loader(pytestconfig) -> Iterator[Callable[[str, str], Image | None]]:
# Search path is ./tests/binfiles unless the user provided an alternate location.
binfiles_arg = pytestconfig.getoption("--binfiles")
if binfiles_arg is not None:
binfile_path = Path(binfiles_arg).resolve()
else:
binfile_path = Path(__file__).resolve().parent / "binfiles"

# Skip this if we have not provided the path to LEGO1.dll.
if filename is None:
pytest.skip(allow_module_level=True, reason="No path to LEGO1")
def loader(filename: str, hash_str: str) -> Image | None:
file = binfile_path / filename
if file.exists():
if not check_hash(file, hash_str):
pytest.fail(
pytrace=False, reason="Did not match expected " + filename.upper()
)

filename = Path(filename)
with filename.open("rb") as f:
digest = hashlib.sha256(f.read()).hexdigest()
if digest != LEGO1_SHA256:
pytest.fail(reason="Did not match expected LEGO1.DLL")
return detect_image(file)

image = detect_image(filename)
assert isinstance(image, PEImage)
yield image
not_found_reason = "No path to " + filename.upper()
if pytestconfig.getoption("--require-binfiles"):
pytest.fail(pytrace=False, reason=not_found_reason)

pytest.skip(allow_module_level=True, reason=not_found_reason)

@pytest.fixture(name="skifree", scope="session")
def fixture_skifree(pytestconfig) -> Iterator[NEImage]:
filename = pytestconfig.getoption("--ski")
return None

# Skip this if we have not provided the path to SKI.EXE.
if filename is None:
pytest.skip(allow_module_level=True, reason="No path to SKI")
yield loader

filename = Path(filename)
with filename.open("rb") as f:
digest = hashlib.sha256(f.read()).hexdigest()
if digest != SKI_SHA256:
pytest.fail(reason="Did not match expected SKI.EXE")

image = detect_image(filename)
@pytest.fixture(name="binfile", scope="session")
def fixture_binfile(bin_loader) -> Iterator[PEImage]:
"""LEGO1.DLL: v1.1 English, September"""
image = bin_loader(
"LEGO1.DLL", "14645225bbe81212e9bc1919cd8a692b81b8622abb6561280d99b0fc4151ce17"
)
assert isinstance(image, PEImage)
yield image


@pytest.fixture(name="skifree", scope="session")
def fixture_skifree(bin_loader) -> Iterator[NEImage]:
"""SkiFree 1.0
https://ski.ihoc.net/"""
image = bin_loader(
"SKI.EXE", "0b97b99fcf34af5f5d624080417c79c7d36ae11351a7870ce6e0a476f03515c2"
)
assert isinstance(image, NEImage)
yield image
4 changes: 3 additions & 1 deletion tests/test_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
RecCmpProjectException,
)
from reccmp.isledecomp.formats import PEImage
from .conftest import LEGO1_SHA256


LEGO1_SHA256 = "14645225bbe81212e9bc1919cd8a692b81b8622abb6561280d99b0fc4151ce17"


def test_project_loading(tmp_path_factory, binfile: PEImage):
Expand Down

0 comments on commit d3289d1

Please sign in to comment.