Skip to content
Merged
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
2 changes: 1 addition & 1 deletion pretext/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
VERSION = get_version("pretext", Path(__file__).parent.parent)


CORE_COMMIT = "4e4ff13706654ca5eb4ff9936bc2acddbd4aa648"
CORE_COMMIT = "8cc838f3fad87b51b2f3ba76ec9ca63fce8978ea"


def activate() -> None:
Expand Down
8 changes: 8 additions & 0 deletions tests/examples/projects/prefigure/project.ptx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This file, the project manifest, provides the overall configuration for your PreTeXt project. -->
<project ptx-version="2">
<targets>
<target name="web" format="html" />
<target name="print" format="pdf" />
</targets>
</project>
34 changes: 34 additions & 0 deletions tests/examples/projects/prefigure/source/main.ptx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>

<pretext>
<book>
<title>Prefigure</title>
<chapter xml:id="ch-prefigure">
<title>prefigure</title>
<image width="60%">
<prefigure label="pftest"
xmlns="https://prefigure.org">
<diagram dimensions="(300,300)" margins="5">
<definition>f(t,y) = (y[1], -pi*y[0]-0.3*y[1])</definition>
<coordinates bbox="[-1,-3,6,3]">
<grid-axes xlabel="t"/>
<de-solve function="f" t0="0" t1="bbox[2]"
y0="(0,2)" name="oscillator"
N="200"/>
<plot-de-solution at="x" solution="oscillator"
axes="(t,y0)" />
<plot-de-solution at="xprime" solution="oscillator"
axes="(t,y1)" stroke="red"
tactile-dash="9 9"/>
<legend at="legend" anchor="(bbox[2], bbox[3])"
alignment="sw" scale="0.9" opacity="0.5">
<item ref="x"><m>x(t)</m></item>
<item ref="xprime"><m>x'(t)</m></item>
</legend>
</coordinates>
</diagram>
</prefigure>
</image>
</chapter>
</book>
</pretext>
154 changes: 149 additions & 5 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

HAS_XELATEX = check_installed(["xelatex", "--version"])
HAS_ASY = check_installed(["asy", "--version"])
HAS_SAGE = check_installed(["sage", "--version"])


@contextmanager
Expand Down Expand Up @@ -88,6 +89,10 @@ def test_devscript(script_runner: ScriptRunner) -> None:
not HAS_XELATEX,
reason="Skipped since xelatex isn't found.",
)
@pytest.mark.skipif(
not HAS_SAGE,
reason="Skipped since sage isn't found.",
)
@pytest.mark.skipif(
not HAS_ASY,
reason="Skipped since asy isn't found.",
Expand Down Expand Up @@ -131,7 +136,6 @@ def test_build(tmp_path: Path, script_runner: ScriptRunner) -> None:
/ "fig_tikz-example-diagram.svg"
).exists()

# Do a full build.
assert script_runner.run(
[PTX_CMD, "-v", "debug", "build", "web"], cwd=project_path
).success
Expand Down Expand Up @@ -242,13 +246,137 @@ def test_init_and_update_with_git(tmp_path: Path, script_runner: ScriptRunner) -
assert f"pretext == {pretext.VERSION}\n" in lines[1]


def test_build_no_generate(tmp_path: Path, script_runner: ScriptRunner) -> None:
"""
Test the behavior of `pretext build -q` (no generate) and -g -q together.

Expected behaviors (per docs/asset-generation.md):
- `pretext build -q`: no assets are generated, even if source has changed.
- `pretext build -g -q`: warning issued; proceeds as if neither flag was set.
"""
prefigure_path = tmp_path / "prefigure"
shutil.copytree(EXAMPLES_DIR / "projects" / "prefigure", prefigure_path)

prefigure_asset = prefigure_path / "generated-assets" / "prefigure" / "pftest.svg"

# --- Test -q: build without generating any assets ---
result = script_runner.run(
[PTX_CMD, "-v", "debug", "build", "-q"], cwd=prefigure_path
)
assert result.success
assert (
not prefigure_asset.exists()
), "Prefigure assets should NOT be generated when using -q (no-generate)"

# --- Test -g -q together: warning issued, behaves like normal build ---
result = script_runner.run(
[PTX_CMD, "-v", "debug", "build", "-g", "-q"], cwd=prefigure_path
)
assert result.success
# The warning message about conflicting flags should appear in the output.
combined_output = result.stdout + result.stderr
assert (
"doesn't make sense" in combined_output
), "A warning about using -g and -q together should be emitted"
# Since the flags cancel each other, behavior is like a normal build.
# On a clean project, that means the missing prefigure asset should be generated.
assert (
prefigure_asset.exists()
), "With -g and -q together, prefigure assets should be generated on a clean project (flags cancel each other)"


def test_build_force_generate_prefigure(
tmp_path: Path, script_runner: ScriptRunner
) -> None:
"""
Test the behavior of `pretext build -g` (force generate) and regular builds.

Expected behaviors (per docs/asset-generation.md):
- `pretext build -g`: all assets generated regardless of whether source has changed.
- Regular `pretext build` after a successful build: assets NOT regenerated when source is unchanged.
"""
prefigure_path = tmp_path / "prefigure"
shutil.copytree(EXAMPLES_DIR / "projects" / "prefigure", prefigure_path)

prefigure_asset = prefigure_path / "generated-assets" / "prefigure" / "pftest.svg"

# --- Test -g: build with force-generate ---
result = script_runner.run(
[PTX_CMD, "-v", "debug", "build", "-g"], cwd=prefigure_path
)
assert result.success
assert (
prefigure_asset.exists()
), "Prefigure asset should be generated when using -g (force generate)"
assert (
prefigure_path / "output" / "web"
).exists(), "Build output should exist after `pretext build -g`"

# --- Test regular build does NOT regenerate when source is unchanged ---
# Delete the generated asset to simulate a missing file after a previous build.
prefigure_asset.unlink()
assert not prefigure_asset.exists()

# A regular build (no -g flag) should NOT regenerate since source hash has not changed.
result = script_runner.run([PTX_CMD, "-v", "debug", "build"], cwd=prefigure_path)
assert result.success
assert (
not prefigure_asset.exists()
), "Regular `pretext build` should NOT regenerate prefigure assets when source is unchanged"

# --- Test -g regenerates even though source is unchanged ---
result = script_runner.run(
[PTX_CMD, "-v", "debug", "build", "-g"], cwd=prefigure_path
)
assert result.success
assert (
prefigure_asset.exists()
), "`pretext build -g` should regenerate prefigure assets even when source is unchanged"


@pytest.mark.skipif(
not HAS_ASY,
reason="Skipped since asy isn't found.",
)
def test_generate_graphics(tmp_path: Path, script_runner: ScriptRunner) -> None:
def test_build_force_generate_asymptote(
tmp_path: Path, script_runner: ScriptRunner
) -> None:
graphics_path = tmp_path / "graphics"
shutil.copytree(EXAMPLES_DIR / "projects" / "graphics", graphics_path)

asymptote_asset = graphics_path / "generated-assets" / "asymptote" / "test.html"

result = script_runner.run(
[PTX_CMD, "-v", "debug", "build", "-g"], cwd=graphics_path
)
assert result.success
assert (
asymptote_asset.exists()
), "Asymptote asset should be generated when using -g (force generate)"


def test_generate_graphics_prefigure(
tmp_path: Path, script_runner: ScriptRunner
) -> None:
prefigure_path = tmp_path / "prefigure"
shutil.copytree(EXAMPLES_DIR / "projects" / "prefigure", prefigure_path)

assert script_runner.run(
[PTX_CMD, "-v", "debug", "generate", "prefigure"], cwd=prefigure_path
).success
assert (prefigure_path / "generated-assets" / "prefigure" / "pftest.svg").exists()


@pytest.mark.skipif(
not HAS_ASY,
reason="Skipped since asy isn't found.",
)
def test_generate_graphics_asymptote_local(
tmp_path: Path, script_runner: ScriptRunner
) -> None:
graphics_path = tmp_path / "graphics"
shutil.copytree(EXAMPLES_DIR / "projects" / "graphics", graphics_path)

assert script_runner.run(
[PTX_CMD, "-v", "debug", "generate", "asymptote"], cwd=graphics_path
).success
Expand All @@ -263,11 +391,27 @@ def test_generate_graphics(tmp_path: Path, script_runner: ScriptRunner) -> None:
[PTX_CMD, "-v", "debug", "generate", "asymptote", "-t", "web"],
cwd=graphics_path,
).success
os.remove(graphics_path / "generated-assets" / "asymptote" / "test.html")


def test_generate_graphics_asymptote_server(
tmp_path: Path, script_runner: ScriptRunner
) -> None:
graphics_path = tmp_path / "graphics"
shutil.copytree(EXAMPLES_DIR / "projects" / "graphics", graphics_path)

# Force server-backed asymptote generation so this test is independent of local asy.
project_manifest = graphics_path / "project.ptx"
project_manifest.write_text(
project_manifest.read_text().replace(
'<project ptx-version="2">',
'<project ptx-version="2" asy-method="server">',
)
)

assert script_runner.run(
[PTX_CMD, "-v", "debug", "generate", "prefigure"], cwd=graphics_path
[PTX_CMD, "-v", "debug", "generate", "asymptote"], cwd=graphics_path
).success
assert (graphics_path / "generated-assets" / "prefigure" / "pftest.svg").exists()
assert (graphics_path / "generated-assets" / "asymptote" / "test.html").exists()


# @pytest.mark.skip(
Expand Down
5 changes: 5 additions & 0 deletions tests/test_sample_article.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

HAS_XELATEX = check_installed(["xelatex", "--version"])
HAS_ASY = check_installed(["asy", "--version"])
HAS_SAGE = check_installed(["sage", "--version"])


@pytest.mark.skipif(
Expand All @@ -18,6 +19,10 @@
not HAS_ASY,
reason="Skipped since asy isn't found.",
)
@pytest.mark.skipif(
not HAS_SAGE,
reason="Skipped since sage isn't found.",
)
def test_sample_article(tmp_path: Path) -> None:
error_checker = errorhandler.ErrorHandler(logger="ptxlogger")
prj_path = tmp_path / "sample"
Expand Down
Loading