11import os
2+ import pytest
23from pathlib import Path
34from pretext import utils
45
@@ -10,7 +11,8 @@ def test_working_directory(tmp_path: Path) -> None:
1011 assert Path ().resolve () == tmp_path .resolve ()
1112 with utils .working_directory (subdir ):
1213 assert Path ().resolve ().parent == tmp_path .resolve ()
13- # TODO check path returns afterward
14+ # After exiting context manager, the directory should have returned to the original
15+ assert Path ().resolve () == tmp_path .resolve ()
1416
1517
1618def test_project_path (tmp_path : Path ) -> None :
@@ -73,3 +75,95 @@ def test_requirements_version(tmp_path: Path) -> None:
7375 assert (
7476 utils .requirements_version (tmp_path ) is None
7577 ), f"Should not match: { line !r} "
78+
79+
80+ def test_format_docstring_as_help_str () -> None :
81+ # Leading/trailing whitespace on each line is stripped, and single newlines
82+ # within a paragraph are collapsed to a single space.
83+ docstring = """
84+ First line of text
85+ that continues here.
86+
87+ Second paragraph.
88+ """
89+ result = utils .format_docstring_as_help_str (docstring )
90+ assert "First line of text that continues here." in result
91+ assert "Second paragraph." in result
92+ # Double newlines (paragraph breaks) are preserved as "\n\n".
93+ assert "\n \n " in result
94+
95+ # A single-line docstring has no newlines.
96+ assert "\n " not in utils .format_docstring_as_help_str ("Single line." )
97+ assert utils .format_docstring_as_help_str (" spaced " ) == "spaced"
98+
99+ # An empty string produces an empty string.
100+ assert utils .format_docstring_as_help_str ("" ) == ""
101+
102+
103+ def test_is_earlier_version () -> None :
104+ assert utils .is_earlier_version ("1.0.0" , "2.0.0" )
105+ assert utils .is_earlier_version ("2.0.0" , "2.1.0" )
106+ assert utils .is_earlier_version ("2.1.0" , "2.1.1" )
107+ assert not utils .is_earlier_version ("2.0.0" , "1.0.0" )
108+ assert not utils .is_earlier_version ("2.1.0" , "2.0.0" )
109+ assert not utils .is_earlier_version ("2.1.1" , "2.1.0" )
110+ # Equal versions are not earlier.
111+ assert not utils .is_earlier_version ("1.2.3" , "1.2.3" )
112+ # When the primary digits are equal but the strings differ only in length,
113+ # the shorter version string is treated as earlier. In pretext-cli, dev
114+ # builds (e.g. "2.11.5.dev0") are nightly POST-release builds produced
115+ # *after* the stable release, so "2.11.5" is earlier than "2.11.5.dev0".
116+ assert utils .is_earlier_version ("2.11.5" , "2.11.5.dev0" )
117+ assert not utils .is_earlier_version ("2.11.5.dev0" , "2.11.5" )
118+
119+
120+ def test_hash_path (tmp_path : Path ) -> None :
121+ # hash_path should return a 10-character hex string.
122+ result = utils .hash_path (tmp_path )
123+ assert isinstance (result , str )
124+ assert len (result ) == 10
125+ assert all (c in "0123456789abcdef" for c in result )
126+ # The same path should always produce the same hash.
127+ assert utils .hash_path (tmp_path ) == utils .hash_path (tmp_path )
128+ # Different paths should (almost certainly) produce different hashes.
129+ other_path = tmp_path / "subdir"
130+ assert utils .hash_path (tmp_path ) != utils .hash_path (other_path )
131+
132+
133+ def test_xml_syntax_is_valid (tmp_path : Path ) -> None :
134+ # A well-formed PreTeXt file should pass validation.
135+ valid_xml = tmp_path / "valid.ptx"
136+ valid_xml .write_text (
137+ "<?xml version='1.0' encoding='utf-8'?>\n "
138+ "<pretext>\n "
139+ " <article xml:id='article-id'>\n "
140+ " <title>Hello</title>\n "
141+ " <p>Content.</p>\n "
142+ " </article>\n "
143+ "</pretext>\n "
144+ )
145+ assert utils .xml_syntax_is_valid (valid_xml )
146+
147+ # A file whose root tag is not <pretext> should fail.
148+ wrong_root = tmp_path / "wrong_root.ptx"
149+ wrong_root .write_text (
150+ "<?xml version='1.0' encoding='utf-8'?>\n "
151+ "<notpretext>\n "
152+ " <p>Content.</p>\n "
153+ "</notpretext>\n "
154+ )
155+ assert not utils .xml_syntax_is_valid (wrong_root )
156+
157+ # A file with malformed XML should fail.
158+ bad_xml = tmp_path / "bad.ptx"
159+ bad_xml .write_text (
160+ "<?xml version='1.0' encoding='utf-8'?>\n "
161+ "<pretext>\n "
162+ " <unclosed-tag>\n "
163+ "</pretext>\n "
164+ )
165+ assert not utils .xml_syntax_is_valid (bad_xml )
166+
167+ # A nonexistent file should raise IOError.
168+ with pytest .raises (IOError ):
169+ utils .xml_syntax_is_valid (tmp_path / "nonexistent.ptx" )
0 commit comments