Skip to content

Commit 3f85c52

Browse files
authored
Fix #27: incorrect jing command arguments in validate_rng
bugfix: Fixes incorrect jing command arguments in validate_rng (#80) Signed-off-by: sushant-suse <[email protected]>
1 parent 65b6731 commit 3f85c52

4 files changed

Lines changed: 63 additions & 7 deletions

File tree

changelog.d/80.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes incorrect jing command arguments in validate_rng function.

src/docbuild/cli/cmd_validate/process.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ async def validate_rng(
106106
rng_schema_path: Path = PRODUCT_CONFIG_SCHEMA,
107107
*,
108108
xinclude: bool = True,
109+
idcheck: bool = True
109110
) -> tuple[bool, str]:
110111
"""Validate an XML file against a RELAX NG schema using jing.
111112
@@ -114,12 +115,14 @@ async def validate_rng(
114115
more robust for complex XInclude statements, including those with XPointer.
115116
116117
:param xmlfile: The path to the XML file to validate.
117-
:param rng_schema_path: The path to the RELAX NG schema file. It supports
118-
both RNC and RNG formats.
118+
:param rng_schema_path: The path to the RELAX NG schema file. It supports both RNC and RNG formats.
119119
:param xinclude: If True, resolve XIncludes with `xmllint` before validation.
120+
:param idcheck: If True, perform ID uniqueness checks.
120121
:return: A tuple containing a boolean success status and any output message.
121122
"""
122123
jing_cmd = ['jing']
124+
if idcheck:
125+
jing_cmd.append('-i')
123126
if rng_schema_path.suffix == '.rnc':
124127
jing_cmd.append('-c')
125128
jing_cmd.append(str(rng_schema_path))
@@ -262,7 +265,7 @@ async def process_file(
262265
)
263266
elif validation_method == 'jing':
264267
# Use existing jing-based validator (.rnc or .rng)
265-
rng_success, rng_output = await validate_rng(path_obj)
268+
rng_success, rng_output = await validate_rng(path_obj, idcheck=True)
266269
else:
267270
console_err.print(
268271
f'{shortname:<{max_len}}: RNG validation => [red]failed[/red]'

tests/cli/cmd_validate/test_process.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
process_file,
1313
registry,
1414
run_python_checks,
15+
validate_rng,
1516
validate_rng_lxml,
1617
)
1718
from docbuild.cli.context import DocBuildContext
@@ -113,3 +114,54 @@ async def test_process_file_with_unknown_validation_method(mock_context, tmp_pat
113114
exit_code = await process_file(xml_file, mock_context, max_len=20)
114115

115116
assert exit_code == 11
117+
118+
119+
@patch.object(process_module, 'run_command', new_callable=AsyncMock)
120+
async def test_validate_rng_with_idcheck_success(mock_run_command, tmp_path):
121+
"""Test that validate_rng with idcheck=True succeeds for a valid XML."""
122+
mock_run_command.return_value = (0, '', '')
123+
xml_file = tmp_path / 'valid.xml'
124+
xml_file.touch()
125+
rng_schema = tmp_path / 'schema.rnc'
126+
rng_schema.touch()
127+
128+
is_valid, message = await validate_rng(xml_file, rng_schema, xinclude=False, idcheck=True)
129+
130+
assert is_valid is True
131+
assert message == ''
132+
# Ensure -i flag is passed to jing
133+
assert '-i' in mock_run_command.call_args[0]
134+
135+
136+
@patch.object(process_module, 'run_command', new_callable=AsyncMock)
137+
async def test_validate_rng_with_idcheck_duplicate_failure(mock_run_command, tmp_path):
138+
"""Test that validate_rng with idcheck=True fails for a duplicate ID."""
139+
mock_run_command.return_value = (1, '', 'error: duplicate ID "test-id"')
140+
xml_file = tmp_path / 'duplicate_id.xml'
141+
xml_file.touch()
142+
rng_schema = tmp_path / 'schema.rnc'
143+
rng_schema.touch()
144+
145+
is_valid, message = await validate_rng(xml_file, rng_schema, xinclude=False, idcheck=True)
146+
147+
assert is_valid is False
148+
assert 'duplicate ID' in message
149+
# Ensure -i flag is passed to jing
150+
assert '-i' in mock_run_command.call_args[0]
151+
152+
153+
@patch.object(process_module, 'run_command', new_callable=AsyncMock)
154+
async def test_validate_rng_without_idcheck_success(mock_run_command, tmp_path):
155+
"""Test that validate_rng with idcheck=False succeeds despite a duplicate ID."""
156+
mock_run_command.return_value = (0, '', '')
157+
xml_file = tmp_path / 'duplicate_id.xml'
158+
xml_file.touch()
159+
rng_schema = tmp_path / 'schema.rnc'
160+
rng_schema.touch()
161+
162+
is_valid, message = await validate_rng(xml_file, rng_schema, xinclude=False, idcheck=False)
163+
164+
assert is_valid is True
165+
assert message == ''
166+
# Ensure -i flag is NOT passed to jing
167+
assert '-i' not in mock_run_command.call_args[0]

tests/cli/cmd_validate/validate/test_process_validation.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,19 @@ async def test_validate_rng_jing_failure():
9999
rng_schema = MagicMock(spec=Path)
100100
xmlfile.__str__.return_value = '/mocked/path/to/file.xml'
101101
rng_schema.__str__.return_value = '/mocked/path/to/schema.rng'
102-
102+
103103
with patch.object(
104104
process_mod,
105105
'run_command',
106106
new=AsyncMock(return_value=(1, 'Error in jing', '')),
107107
) as mock_run_command:
108108
success, output = await process_mod.validate_rng(
109-
xmlfile, rng_schema_path=rng_schema, xinclude=False
109+
xmlfile, rng_schema_path=rng_schema, xinclude=False, idcheck=False
110110
)
111-
111+
112112
assert not success, 'Expected validation to fail.'
113113
assert output == 'Error in jing', f'Unexpected output: {output}'
114-
114+
115115
mock_run_command.assert_called_once_with('jing', str(rng_schema), str(xmlfile))
116116

117117

0 commit comments

Comments
 (0)