Skip to content

tests: parameterize - #6

Open
jkowalleck wants to merge 10 commits into
willynilly:mainfrom
jkowalleck:tests/parameterize
Open

tests: parameterize#6
jkowalleck wants to merge 10 commits into
willynilly:mainfrom
jkowalleck:tests/parameterize

Conversation

@jkowalleck

Copy link
Copy Markdown
Collaborator

i found it annoying that tests stopped on the first error.

so i changed the tests to be properly parameterized. this way, tests can run in parallel and dont fail fast - so that ALL errors are found, not only the first one ...

@jkowalleck

Copy link
Copy Markdown
Collaborator Author

@willynilly please review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the syntax validation test suite to use pytest parameterization so each JSON test vector runs as an individual test case, improving failure reporting granularity.

Changes:

  • Replaces nested loops in test_is_valid_syntax / test_not_is_valid_syntax with @pytest.mark.parametrize cases generated from JSON data.
  • Introduces a shared syntax_data_as_params generator to build parameter sets and test ids.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/test_syntax.py
Comment on lines +17 to +20
def syntax_data_as_params(src_cb):
for term, examples in src_cb().items():
for example in examples:
yield pytest.param(term, example, id=f"{term}-{example['value']}")

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pytest.param(..., id=f"{term}-{example['value']}") will embed raw example values into the test id. The JSON test data includes control characters and newlines/tabs (e.g., "\t", "\n", "\u001f"), which can produce unreadable or even multi-line nodeids and make CI output/log parsing brittle. Consider escaping/sanitizing and truncating the value (e.g., using a repr/escaped form plus an index) when building the id.

Suggested change
def syntax_data_as_params(src_cb):
for term, examples in src_cb().items():
for example in examples:
yield pytest.param(term, example, id=f"{term}-{example['value']}")
def _syntax_param_id(term, value, index, max_length=40):
safe_value = str(value).encode("unicode_escape").decode("ascii")
if len(safe_value) > max_length:
safe_value = f"{safe_value[: max_length - 3]}..."
return f"{term}-{index}-{safe_value}"
def syntax_data_as_params(src_cb):
for term, examples in src_cb().items():
for index, example in enumerate(examples):
yield pytest.param(
term,
example,
id=_syntax_param_id(term, example["value"], index),
)

Copilot uses AI. Check for mistakes.
Comment thread tests/test_syntax.py
Comment on lines +28 to +43
f"Testing {term} with {valid_example['value']} : {valid_example['reason']}"
)
assert (
actual is True
), f"Failed term: {term} for '{valid_example['value']}' : {valid_example['reason']}"

@pytest.mark.parametrize("term,invalid_example", syntax_data_as_params(invalid_syntax_data))
def test_not_is_valid_syntax(term, invalid_example):
actual = h.is_valid_syntax(term=term, value=invalid_example["value"])
print("")
print(
f"Testing {term} with {invalid_example['value']} : {invalid_example['reason']}"
)
assert (
actual is False
), f"Failed term: {term} for '{invalid_example['value']}' : {invalid_example['reason']}"

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The debug output / failure messages interpolate *_example['value'] directly. Since the test vectors include whitespace/control characters, this can make the printed line and assertion message hard to read (or span multiple lines). Consider formatting the value as an escaped/repr form in both the print and the assertion message so failures are diagnosable.

Suggested change
f"Testing {term} with {valid_example['value']} : {valid_example['reason']}"
)
assert (
actual is True
), f"Failed term: {term} for '{valid_example['value']}' : {valid_example['reason']}"
@pytest.mark.parametrize("term,invalid_example", syntax_data_as_params(invalid_syntax_data))
def test_not_is_valid_syntax(term, invalid_example):
actual = h.is_valid_syntax(term=term, value=invalid_example["value"])
print("")
print(
f"Testing {term} with {invalid_example['value']} : {invalid_example['reason']}"
)
assert (
actual is False
), f"Failed term: {term} for '{invalid_example['value']}' : {invalid_example['reason']}"
f"Testing {term} with {valid_example['value']!r} : {valid_example['reason']}"
)
assert (
actual is True
), f"Failed term: {term} for {valid_example['value']!r} : {valid_example['reason']}"
@pytest.mark.parametrize("term,invalid_example", syntax_data_as_params(invalid_syntax_data))
def test_not_is_valid_syntax(term, invalid_example):
actual = h.is_valid_syntax(term=term, value=invalid_example["value"])
print("")
print(
f"Testing {term} with {invalid_example['value']!r} : {invalid_example['reason']}"
)
assert (
actual is False
), f"Failed term: {term} for {invalid_example['value']!r} : {invalid_example['reason']}"

Copilot uses AI. Check for mistakes.
Comment thread tests/test_syntax.py
Comment on lines +23 to +24
@pytest.mark.parametrize("term,valid_example", syntax_data_as_params(valid_syntax_data))
def test_is_valid_syntax(term, valid_example):

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description mentions tests "can run in parallel", but the repo's testing extras currently only declare pytest (no pytest-xdist), so parametrization alone won't make the suite run in parallel by default. Either adjust the description/expectation, or add xdist to the testing extras / CI if parallel execution is a goal.

Copilot uses AI. Check for mistakes.
Comment thread tests/test_syntax.py
Comment on lines +17 to +43
def syntax_data_as_params(src_cb):
for term, examples in src_cb().items():
for example in examples:
yield pytest.param(term, example, id=f"{term}-{example['value']}")


@pytest.mark.parametrize("term,valid_example", syntax_data_as_params(valid_syntax_data))
def test_is_valid_syntax(term, valid_example):
actual = h.is_valid_syntax(term=term, value=valid_example["value"])
print("")
print(
f"Testing {term} with {valid_example['value']} : {valid_example['reason']}"
)
assert (
actual is True
), f"Failed term: {term} for '{valid_example['value']}' : {valid_example['reason']}"

@pytest.mark.parametrize("term,invalid_example", syntax_data_as_params(invalid_syntax_data))
def test_not_is_valid_syntax(term, invalid_example):
actual = h.is_valid_syntax(term=term, value=invalid_example["value"])
print("")
print(
f"Testing {term} with {invalid_example['value']} : {invalid_example['reason']}"
)
assert (
actual is False
), f"Failed term: {term} for '{invalid_example['value']}' : {invalid_example['reason']}"

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parametrizing every example creates one pytest test case per JSON entry; with invalid_syntax.json being large, this can significantly increase collection time and per-test overhead compared to a single loop-based test. If runtime becomes an issue, consider parametrizing at a coarser granularity (e.g., per term) while still aggregating failures within the test, so you keep the "report all failures" behavior without thousands of separate test nodes.

Suggested change
def syntax_data_as_params(src_cb):
for term, examples in src_cb().items():
for example in examples:
yield pytest.param(term, example, id=f"{term}-{example['value']}")
@pytest.mark.parametrize("term,valid_example", syntax_data_as_params(valid_syntax_data))
def test_is_valid_syntax(term, valid_example):
actual = h.is_valid_syntax(term=term, value=valid_example["value"])
print("")
print(
f"Testing {term} with {valid_example['value']} : {valid_example['reason']}"
)
assert (
actual is True
), f"Failed term: {term} for '{valid_example['value']}' : {valid_example['reason']}"
@pytest.mark.parametrize("term,invalid_example", syntax_data_as_params(invalid_syntax_data))
def test_not_is_valid_syntax(term, invalid_example):
actual = h.is_valid_syntax(term=term, value=invalid_example["value"])
print("")
print(
f"Testing {term} with {invalid_example['value']} : {invalid_example['reason']}"
)
assert (
actual is False
), f"Failed term: {term} for '{invalid_example['value']}' : {invalid_example['reason']}"
def syntax_data_by_term(src_cb):
for term, examples in src_cb().items():
yield pytest.param(term, examples, id=term)
@pytest.mark.parametrize("term,valid_examples", syntax_data_by_term(valid_syntax_data))
def test_is_valid_syntax(term, valid_examples):
failures = []
for valid_example in valid_examples:
actual = h.is_valid_syntax(term=term, value=valid_example["value"])
print("")
print(
f"Testing {term} with {valid_example['value']} : {valid_example['reason']}"
)
if actual is not True:
failures.append(
f"Failed term: {term} for '{valid_example['value']}' : {valid_example['reason']}"
)
if failures:
pytest.fail("\n".join(failures))
@pytest.mark.parametrize("term,invalid_examples", syntax_data_by_term(invalid_syntax_data))
def test_not_is_valid_syntax(term, invalid_examples):
failures = []
for invalid_example in invalid_examples:
actual = h.is_valid_syntax(term=term, value=invalid_example["value"])
print("")
print(
f"Testing {term} with {invalid_example['value']} : {invalid_example['reason']}"
)
if actual is not False:
failures.append(
f"Failed term: {term} for '{invalid_example['value']}' : {invalid_example['reason']}"
)
if failures:
pytest.fail("\n".join(failures))

Copilot uses AI. Check for mistakes.
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
@jkowalleck

Copy link
Copy Markdown
Collaborator Author

Hi! Since this repository is no longer actively maintained, I created and now maintain a fork of this package long-term:

Would you mind retargeting (or reopening) this pull request against the maintained fork so your fix/feature can be reviewed and merged there?

Thank you!

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
@jkowalleck
jkowalleck force-pushed the tests/parameterize branch from 1d64a6f to 5c3c7b6 Compare July 16, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants