Skip to content

test_json_schema - #452

Open
Niccolum wants to merge 6 commits into
reagento:developfrom
Niccolum:test_json_schema
Open

Niccolum wants to merge 6 commits into
reagento:developfrom
Niccolum:test_json_schema

Conversation

@Niccolum

Copy link
Copy Markdown
Contributor

No description provided.

@zhPavel
zhPavel changed the base branch from main to develop July 12, 2026 20:22
Comment thread src/adaptix/_internal/morphing/facade/func.py Outdated
Comment thread src/adaptix/_internal/morphing/json_schema/patch.py Outdated
Comment thread tests/integration/morphing/test_json_schema_facade.py Outdated
Comment thread tests/tests_helpers/tests_helpers/structure_tools.py Outdated
Comment thread tests/integration/morphing/test_json_schema_facade.py Outdated
Comment thread tests/integration/morphing/test_json_schema_facade.py Outdated
Comment thread tests/unit/morphing/json_schema/test_schema_tools.py Outdated
Comment thread tests/unit/morphing/json_schema/test_patch.py Outdated
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  src/adaptix/_internal/morphing/facade
  func.py 57, 65
  src/adaptix/_internal/morphing/json_schema
  patch.py
  schema_tools.py
Project Total  

This report was generated by python-coverage-comment-action

def _append_with_patcher(self: S, patcher: Callable[[JSONSchema], JSONSchema]) -> S:
self_copy = copy(self)
self_copy._patchers.append(patcher)
self_copy._patchers = [*self._patchers, patcher]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What was this change necessary for?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It fixes a shared-state bug in JSONSchemaPatch. copy(self) is a shallow copy, so self_copy._patchers and self._patchers pointed to the same list. The old .append(patcher) therefore also added the patcher to the original object, and to every other copy made from it.

Example of the bug:

  base = JSONSchemaPatch()
  a = base.mutate_copy(...)   # base._patchers now contains a's patcher too
  b = base.mutate_copy(...)   # b gets a's patcher as well

The patch methods are meant to be immutable and return a new object. With the old code, using a patch as a base for several variants produced wrong schemas. Building a new list for the copy fixes this, and the original is never mutated.

from adaptix import Retort, name_mapping
from adaptix._internal.definitions import Direction
from adaptix._internal.morphing.facade.func import (
DIALECT_2020_12 as DIALECT_URI,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What was this renaming needed for?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

really. fixed

Comment thread .gitignore Outdated
/docs/build

.venv/
uv.lock No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why uv.lock is gitignored?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

really. Maybe i forgot remove it when testing

Comment on lines +35 to +37
def test_load_json_schema_strict_unknown_field_raises():
with pytest.raises(AggregateLoadError):
load_json_schema({"type": "string", "x-custom": "value"}, error_on_extra=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There are raises_exc helper function that can compare exceptions by its fields

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, thanks. Fixed

Comment on lines +88 to +97
assert_morphing(
retort=Retort(),
tp=SimpleModel,
data={"name": "foo", "value": 1},
loaded=SimpleModel(name="foo", value=1),
json_schema=JSONSchemaFork(
input=_make({"additionalProperties": True}),
output=_make({}),
),
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You can use "additionalProperties": JSONSchemaOptItem(input=True), for these forked tests. Other tests already use it

@Niccolum Niccolum Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

thanks. done.

Comment on lines +120 to +126
def test_generate_json_schema_custom_resolver():
schema = generate_json_schema(
Retort(), SimpleModel, Direction.INPUT,
resolver=BuiltinJSONSchemaResolver(BuiltinRefGenerator(), IndexRefMangler()),
)

assert "SimpleModel" in schema["$defs"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test does not assert that custom resolver is used

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

hm, really. add parametrized test for that case

Comment on lines +129 to +163
def test_generate_json_schema_optional_field_not_required_on_input():
def _make(required: list, extra: dict) -> dict:
return {
"$ref": "#/$defs/ModelWithOptional",
"$schema": DIALECT_URI,
"$defs": {
"ModelWithOptional": {
"title": "ModelWithOptional",
"type": "object",
"required": required,
"properties": {
"required_field": {"type": "string"},
"optional_field": {
"default": None,
"anyOf": [{"type": "string"}, {"type": "null"}],
},
},
**extra,
},
},
}

assert_morphing(
retort=Retort(),
tp=ModelWithOptional,
data={"required_field": "x"},
loaded=ModelWithOptional(required_field="x"),
dumped={"required_field": "x", "optional_field": None},
json_schema=JSONSchemaFork(
# Input schema: only required_field is required (optional_field has a default)
input=_make(["required_field"], {"additionalProperties": True}),
# Output schema: both fields are required (dumping doesn't care about defaults)
output=_make(["required_field", "optional_field"], {}),
),
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There is JSONSchemaOptItem(input=True) for such tests

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I do not think that such unit tests can be useful. I would advise to test actual system behaviour

@Niccolum Niccolum Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

delete because test tests/integration/morphing/test_examples.py::test_readme already check this

Comment on lines +212 to +257
@pytest.mark.parametrize(
"resolver",
[
pytest.param(None, id="default"),
pytest.param(
BuiltinJSONSchemaResolver(BuiltinRefGenerator(), IndexRefMangler()),
id="custom_resolver",
),
],
)
def test_generate_schemas_namespace_deduplicates_shared_types(resolver):
query = _namespace_query()
kwargs = {"resolver": resolver} if resolver else {}

defs, schemas = generate_json_schemas_namespace(query, **kwargs)

assert len(schemas) == 2
assert defs.keys() == {"Article", "Post", "Tag"}


@pytest.mark.parametrize(
"with_dialect_uri",
[
pytest.param(True, id="with_uri"),
pytest.param(False, id="without_uri"),
],
)
def test_generate_schemas_namespace_dialect_uri(with_dialect_uri: bool): # noqa: FBT001
query = _namespace_query()
_, schemas = generate_json_schemas_namespace(query, with_dialect_uri=with_dialect_uri)

for schema in schemas:
assert ("$schema" in schema) == with_dialect_uri
assert "$ref" in schema


def test_generate_schemas_namespace_custom_ref_prefix():
query = _namespace_query()
_, schemas = generate_json_schemas_namespace(
query, local_ref_prefix="#/components/schemas/",
)

assert [schema["$ref"] for schema in schemas] == [
"#/components/schemas/Article",
"#/components/schemas/Post",
]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These tests duplicate previous tests, but they only use another facade

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

removed test_generate_schemas_namespace_dialect_uri and test_generate_schemas_namespace_custom_ref_prefix. Kept test_generate_schemas_namespace_deduplicates_shared_types, because nothing else covers it. Every other test uses a single query, and only this one checks that a type shared between several queries (Tag) lands in $defs once.

Comment on lines +25 to +47
def _product_schema(name_prop: dict, price_prop: dict) -> JSONSchemaFork:
def _make(product_extra: dict = {}) -> dict: # noqa: B006
return {
"$ref": "#/$defs/Product",
"$schema": DIALECT_2020_12,
"$defs": {
"Product": {
"title": "Product",
"type": "object",
"required": ["name", "price"],
"properties": {
"name": name_prop,
"price": price_prop,
},
**product_extra,
},
},
}

return JSONSchemaFork(
input=_make({"additionalProperties": True}),
output=_make(),
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

JSONSchemaOptItem(input=True)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

@sonarqubecloud

sonarqubecloud Bot commented Oct 6, 2026

Copy link
Copy Markdown

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