Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ jobs:
uses: r-lib/actions/setup-pandoc@v2
- name: Linting Checks
run: |
poetry run black .
poetry run isort --check-only in2lambda docs
poetry run pydocstyle --convention=google in2lambda
poetry run black --check .
poetry run isort --check-only in2lambda docs tests
poetry run pydocstyle --convention=google in2lambda tests
- name: pytest
run: poetry run pytest --cov-report=xml:coverage.xml --cov=in2lambda --doctest-modules in2lambda
run: poetry run pytest --cov-report=xml:coverage.xml --cov=in2lambda
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
Expand Down
1 change: 1 addition & 0 deletions in2lambda/api/visibility_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from enum import Enum


class VisibilityStatus(Enum):
"""Enum representing the visibility status of a question or set."""

Expand Down
5 changes: 4 additions & 1 deletion in2lambda/json_convert/json_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ def converter(

# Output file
filename = (
"question_" + str(i).zfill(3) + "_" + re.sub(r'[^\w\-_.]', '_', output['title'].strip())
"question_"
+ str(i).zfill(3)
+ "_"
+ re.sub(r"[^\w\-_.]", "_", output["title"].strip())
)

# write questions into directory
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ ignore_missing_imports = true
[tool.isort]
profile = "black"

[tool.pytest.ini_options]
# Collect both the unit tests in tests/ and the doctests embedded in the package.
testpaths = ["tests", "in2lambda"]
addopts = "--doctest-modules"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
16 changes: 16 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Shared pytest fixtures for the in2lambda test suite."""

import os

import pytest

import in2lambda


@pytest.fixture(scope="session")
def filters_dir() -> str:
"""Absolute path to the packaged ``filters`` directory.

Each filter ships a self-contained ``example.tex`` used by the end-to-end tests.
"""
return os.path.join(os.path.dirname(in2lambda.__file__), "filters")
57 changes: 57 additions & 0 deletions tests/test_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""End-to-end tests for :func:`in2lambda.main.runner` across the built-in filters.

Each built-in filter ships a self-contained ``example.tex`` that exercises the
document structure it targets. These tests run every filter over its own example
and check both the in-memory :class:`~in2lambda.api.set.Set` and the JSON/ZIP
files written to disk.
"""

import json
import os

import pytest

from in2lambda.api.set import Set
from in2lambda.main import runner

BUILTIN_FILTERS = ["PartsSepSol", "PartsOneSol", "PartPartSolSol", "PartSolPartSol"]


@pytest.mark.parametrize("filter_name", BUILTIN_FILTERS)
def test_runner_returns_populated_set(filter_name: str, filters_dir: str) -> None:
"""Every filter turns its example into a Set with at least one usable question."""
result = runner(os.path.join(filters_dir, filter_name, "example.tex"), filter_name)

assert isinstance(result, Set)
assert result.questions, f"{filter_name} produced no questions"
for question in result.questions:
# A question is only useful if it has top-level text or at least one part.
assert question.main_text or question.parts


@pytest.mark.parametrize("filter_name", BUILTIN_FILTERS)
def test_runner_writes_importable_json(
filter_name: str, filters_dir: str, tmp_path
) -> None:
"""Passing an output directory produces the Lambda Feedback set/ dir and zip."""
out_dir = tmp_path / "out"
result = runner(
os.path.join(filters_dir, filter_name, "example.tex"),
filter_name,
str(out_dir),
)

set_dir = out_dir / "set"
assert set_dir.is_dir()
assert (out_dir / "set.zip").is_file()

set_json = json.loads((set_dir / "set_set.json").read_text())
assert set_json["name"] == "set"

question_files = sorted(set_dir.glob("question_*.json"))
assert len(question_files) == len(result.questions)
for question_file in question_files:
question_json = json.loads(question_file.read_text())
assert question_json["title"]
assert "masterContent" in question_json
assert "parts" in question_json
Loading