feat: integrate SimpleCADAPI 2.0.2 CAD workflows
This commit is contained in:
@@ -0,0 +1,710 @@
|
||||
"""Resource-limit fixture case construction."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from copy import deepcopy
|
||||
from dataclasses import replace
|
||||
from typing import Any, Callable
|
||||
|
||||
from simplecadapi.scene import (
|
||||
BASE_LIMITS,
|
||||
SceneResourceLimits,
|
||||
canonical_archive_size,
|
||||
json_resource_issues,
|
||||
preflight_aggregate_compression_ratio,
|
||||
preflight_archive_member_sizes,
|
||||
preflight_glb_counts,
|
||||
preflight_input_archive_size,
|
||||
preflight_member_compression_ratio,
|
||||
resource_count_issues,
|
||||
validate_scene_manifest,
|
||||
with_scene_revision,
|
||||
)
|
||||
from simplecadapi.scene.validation import (
|
||||
_compute_package_budget_totals,
|
||||
_package_budget_issues,
|
||||
_report,
|
||||
)
|
||||
|
||||
from .common import JsonObject, first_issue
|
||||
|
||||
|
||||
def _limits(overrides: dict[str, int]) -> SceneResourceLimits:
|
||||
return replace(BASE_LIMITS, **overrides)
|
||||
|
||||
|
||||
def _preflight_case(
|
||||
name: str,
|
||||
operation: str,
|
||||
parameters: dict[str, object],
|
||||
callback: Callable[[], object],
|
||||
) -> dict[str, object]:
|
||||
try:
|
||||
callback()
|
||||
except ValueError as exc:
|
||||
valid, error = False, str(exc)
|
||||
else:
|
||||
valid, error = True, None
|
||||
return {
|
||||
"error": error,
|
||||
"name": name,
|
||||
"operation": operation,
|
||||
"parameters": parameters,
|
||||
"valid": valid,
|
||||
}
|
||||
|
||||
|
||||
def _issues_case(
|
||||
name: str,
|
||||
operation: str,
|
||||
parameters: dict[str, object],
|
||||
issues: tuple[Any, ...] | list[Any],
|
||||
) -> dict[str, object]:
|
||||
first = issues[0] if issues else None
|
||||
return {
|
||||
"expected": (
|
||||
None if first is None else {"code": first.code, "path": first.path}
|
||||
),
|
||||
"name": name,
|
||||
"operation": operation,
|
||||
"parameters": parameters,
|
||||
"valid": not issues,
|
||||
}
|
||||
|
||||
|
||||
def _validation_case(
|
||||
name: str,
|
||||
operation: str,
|
||||
parameters: dict[str, object],
|
||||
report: Any,
|
||||
) -> dict[str, object]:
|
||||
return {
|
||||
"expected": first_issue(report),
|
||||
"name": name,
|
||||
"operation": operation,
|
||||
"parameters": parameters,
|
||||
"valid": report.valid,
|
||||
}
|
||||
|
||||
|
||||
def _input_size_case(name: str, size: int, overrides: dict[str, int]) -> dict[str, object]:
|
||||
parameters: dict[str, object] = {"limits": overrides, "size": size}
|
||||
return _preflight_case(
|
||||
name,
|
||||
"input_archive_size",
|
||||
parameters,
|
||||
lambda: preflight_input_archive_size(size, limits=_limits(overrides)),
|
||||
)
|
||||
|
||||
|
||||
def _archive_sizes_case(
|
||||
name: str, sizes: dict[str, int], overrides: dict[str, int]
|
||||
) -> dict[str, object]:
|
||||
parameters: dict[str, object] = {"limits": overrides, "sizes": sizes}
|
||||
return _preflight_case(
|
||||
name,
|
||||
"archive_member_sizes",
|
||||
parameters,
|
||||
lambda: preflight_archive_member_sizes(sizes, limits=_limits(overrides)),
|
||||
)
|
||||
|
||||
|
||||
def _archive_count_case(
|
||||
name: str, count: int, overrides: dict[str, int]
|
||||
) -> dict[str, object]:
|
||||
sizes = {"scene.json": 0}
|
||||
sizes.update({f"x/{index}": 0 for index in range(count - 1)})
|
||||
parameters: dict[str, object] = {"count": count, "limits": overrides}
|
||||
return _preflight_case(
|
||||
name,
|
||||
"archive_member_count",
|
||||
parameters,
|
||||
lambda: preflight_archive_member_sizes(sizes, limits=_limits(overrides)),
|
||||
)
|
||||
|
||||
|
||||
def _compression_case(
|
||||
name: str,
|
||||
operation: str,
|
||||
uncompressed_size: int,
|
||||
compressed_size: int,
|
||||
) -> dict[str, object]:
|
||||
overrides = {"compression_ratio": 2}
|
||||
parameters = {
|
||||
"compressed_size": compressed_size,
|
||||
"limits": overrides,
|
||||
"uncompressed_size": uncompressed_size,
|
||||
}
|
||||
if operation == "aggregate_compression_ratio":
|
||||
callback = lambda: preflight_aggregate_compression_ratio(
|
||||
uncompressed_size, compressed_size, limits=_limits(overrides)
|
||||
)
|
||||
else:
|
||||
callback = lambda: preflight_member_compression_ratio(
|
||||
uncompressed_size, compressed_size, limits=_limits(overrides)
|
||||
)
|
||||
return _preflight_case(name, operation, parameters, callback)
|
||||
|
||||
|
||||
def _json_value(kind: str, text: str, field: str | None = None) -> object:
|
||||
if kind == "value":
|
||||
return {"value": text}
|
||||
if kind == "object_key":
|
||||
return {text: 0}
|
||||
if kind == "metadata_key":
|
||||
return {"metadata": {text: 0}}
|
||||
if kind == "sdk_metadata_key":
|
||||
return {"sdk_metadata": {text: 0}}
|
||||
if kind == "identifier":
|
||||
return {field or "node_id": text}
|
||||
if kind == "identifier_array":
|
||||
return {field or "component_path": [text]}
|
||||
if kind == "uri":
|
||||
return {"uri": text}
|
||||
raise AssertionError(kind)
|
||||
|
||||
|
||||
def _json_domain_case(
|
||||
name: str,
|
||||
kind: str,
|
||||
text: str,
|
||||
overrides: dict[str, int],
|
||||
*,
|
||||
field: str | None = None,
|
||||
) -> dict[str, object]:
|
||||
parameters: dict[str, object] = {
|
||||
"field": field,
|
||||
"kind": kind,
|
||||
"limits": overrides,
|
||||
"text": text,
|
||||
}
|
||||
issues = json_resource_issues(
|
||||
_json_value(kind, text, field), limits=_limits(overrides)
|
||||
)
|
||||
return _issues_case(name, "json_domain", parameters, issues)
|
||||
|
||||
|
||||
def _nested_value(depth: int) -> object:
|
||||
value: dict[str, object] = {}
|
||||
current = value
|
||||
for _index in range(depth):
|
||||
current["x"] = {}
|
||||
current = current["x"] # type: ignore[assignment]
|
||||
return value
|
||||
|
||||
|
||||
def _json_depth_case(name: str, depth: int) -> dict[str, object]:
|
||||
overrides = {"json_depth": 2}
|
||||
parameters: dict[str, object] = {"depth": depth, "limits": overrides}
|
||||
issues = json_resource_issues(_nested_value(depth), limits=_limits(overrides))
|
||||
return _issues_case(name, "json_depth", parameters, issues)
|
||||
|
||||
|
||||
def _resource_count_value(
|
||||
artifact: str, kind: str, count: int, field: str | None
|
||||
) -> object:
|
||||
if kind == "collection":
|
||||
assert field is not None
|
||||
return {field: [None] * count}
|
||||
if kind == "hierarchy":
|
||||
return {"nodes": [{"source": {"component_path": ["x"] * count}}]}
|
||||
if kind == "forwarded":
|
||||
return {
|
||||
"connectors": [
|
||||
{
|
||||
"anchor_kind": "forwarded",
|
||||
"connector_snapshot_id": f"c{index}",
|
||||
"forwarded_from": {
|
||||
"source_connector_snapshot_id": f"c{index + 1}"
|
||||
},
|
||||
}
|
||||
for index in range(count)
|
||||
]
|
||||
}
|
||||
raise AssertionError((artifact, kind))
|
||||
|
||||
|
||||
def _resource_count_case(
|
||||
name: str,
|
||||
artifact: str,
|
||||
kind: str,
|
||||
count: int,
|
||||
overrides: dict[str, int],
|
||||
*,
|
||||
field: str | None = None,
|
||||
) -> dict[str, object]:
|
||||
parameters: dict[str, object] = {
|
||||
"artifact": artifact,
|
||||
"count": count,
|
||||
"field": field,
|
||||
"kind": kind,
|
||||
"limits": overrides,
|
||||
}
|
||||
issues = resource_count_issues(
|
||||
_resource_count_value(artifact, kind, count, field),
|
||||
artifact,
|
||||
limits=_limits(overrides),
|
||||
)
|
||||
return _issues_case(name, "resource_count", parameters, issues)
|
||||
|
||||
|
||||
def _glb_count_case(
|
||||
name: str,
|
||||
kind: str,
|
||||
vertex_count: int,
|
||||
index_count: int,
|
||||
overrides: dict[str, int],
|
||||
) -> dict[str, object]:
|
||||
parameters: dict[str, object] = {
|
||||
"index_count": index_count,
|
||||
"kind": kind,
|
||||
"limits": overrides,
|
||||
"vertex_count": vertex_count,
|
||||
}
|
||||
return _preflight_case(
|
||||
name,
|
||||
"glb_counts",
|
||||
parameters,
|
||||
lambda: preflight_glb_counts(
|
||||
kind, # type: ignore[arg-type]
|
||||
vertex_count,
|
||||
index_count,
|
||||
limits=_limits(overrides),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
_BUDGET_FIELDS = {
|
||||
"entities_total": "entity_count",
|
||||
"line_segments_total": "line_segment_count",
|
||||
"line_vertices_total": "line_vertex_count",
|
||||
"static_decoded_buffer_bytes": "scene_json_bytes",
|
||||
"triangle_vertices_total": "triangle_vertex_count",
|
||||
"triangles_total": "triangle_count",
|
||||
}
|
||||
|
||||
|
||||
def _package_budget_case(
|
||||
name: str, limit_name: str, value: int
|
||||
) -> dict[str, object]:
|
||||
contributions = {
|
||||
"scene_json_bytes": 0,
|
||||
"glb_decoded_buffer_bytes": 0,
|
||||
"entity_json_bytes": 0,
|
||||
"other_immutable_json_bytes": 0,
|
||||
"entity_count": 0,
|
||||
"entity_vertex_count": 0,
|
||||
"triangle_vertex_count": 0,
|
||||
"triangle_count": 0,
|
||||
"line_vertex_count": 0,
|
||||
"line_segment_count": 0,
|
||||
}
|
||||
contributions[_BUDGET_FIELDS[limit_name]] = value
|
||||
overrides = {limit_name: 2}
|
||||
totals = _compute_package_budget_totals(**contributions)
|
||||
budget_report = _report(
|
||||
_package_budget_issues(totals, limits=_limits(overrides)), artifact="package"
|
||||
)
|
||||
return _validation_case(
|
||||
name,
|
||||
"package_budget",
|
||||
{"contributions": contributions, "limits": overrides},
|
||||
budget_report,
|
||||
)
|
||||
|
||||
|
||||
def build_resource_cases(
|
||||
scene: JsonObject,
|
||||
normalized_part: JsonObject,
|
||||
) -> list[dict[str, object]]:
|
||||
input_limits = {"input_archive_bytes": 8}
|
||||
role_limits = {
|
||||
"canonical_archive_bytes": 1_000,
|
||||
"one_member_bytes": 100,
|
||||
"total_uncompressed_bytes": 100,
|
||||
}
|
||||
canonical_limits = {
|
||||
"canonical_archive_bytes": 256,
|
||||
"one_member_bytes": 100,
|
||||
"total_uncompressed_bytes": 100,
|
||||
}
|
||||
canonical_envelope = canonical_archive_size(
|
||||
{"geometry/a.glb": 0, "scene.json": 0}
|
||||
)
|
||||
canonical_payload = canonical_limits["canonical_archive_bytes"] - canonical_envelope
|
||||
one_member_limits = {
|
||||
"canonical_archive_bytes": 1_000,
|
||||
"one_member_bytes": 8,
|
||||
"total_uncompressed_bytes": 100,
|
||||
}
|
||||
total_limits = {
|
||||
"canonical_archive_bytes": 1_000,
|
||||
"one_member_bytes": 8,
|
||||
"total_uncompressed_bytes": 16,
|
||||
}
|
||||
count_limits = {"canonical_archive_bytes": 10_000, "zip_members": 3}
|
||||
cases = [
|
||||
_input_size_case("input_archive_exact_limit", 8, input_limits),
|
||||
_input_size_case("input_archive_over_limit", 9, input_limits),
|
||||
_archive_sizes_case(
|
||||
"scene_json_exact_limit",
|
||||
{"scene.json": 8},
|
||||
{**role_limits, "scene_json_bytes": 8},
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"scene_json_over_limit",
|
||||
{"scene.json": 9},
|
||||
{**role_limits, "scene_json_bytes": 8},
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"entity_json_exact_limit",
|
||||
{"entities/a.json": 8, "scene.json": 0},
|
||||
{**role_limits, "entity_json_bytes": 8},
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"entity_json_over_limit",
|
||||
{"entities/a.json": 9, "scene.json": 0},
|
||||
{**role_limits, "entity_json_bytes": 8},
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"model_json_exact_limit",
|
||||
{"model/model.json": 8, "scene.json": 0},
|
||||
{**role_limits, "model_json_bytes": 8},
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"model_json_over_limit",
|
||||
{"model/model.json": 9, "scene.json": 0},
|
||||
{**role_limits, "model_json_bytes": 8},
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"presentation_json_exact_limit",
|
||||
{"presentation/presentation.json": 8, "scene.json": 0},
|
||||
{**role_limits, "presentation_json_bytes": 8},
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"presentation_json_over_limit",
|
||||
{"presentation/presentation.json": 9, "scene.json": 0},
|
||||
{**role_limits, "presentation_json_bytes": 8},
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"canonical_archive_exact_limit",
|
||||
{"geometry/a.glb": canonical_payload, "scene.json": 0},
|
||||
canonical_limits,
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"canonical_archive_over_limit",
|
||||
{"geometry/a.glb": canonical_payload + 1, "scene.json": 0},
|
||||
canonical_limits,
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"one_member_exact_limit",
|
||||
{"geometry/a.glb": 8, "scene.json": 0},
|
||||
one_member_limits,
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"one_member_over_limit",
|
||||
{"geometry/a.glb": 9, "scene.json": 0},
|
||||
one_member_limits,
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"total_uncompressed_exact_limit",
|
||||
{"geometry/a.glb": 8, "geometry/b.glb": 8, "scene.json": 0},
|
||||
total_limits,
|
||||
),
|
||||
_archive_sizes_case(
|
||||
"total_uncompressed_over_limit",
|
||||
{
|
||||
"geometry/a.glb": 8,
|
||||
"geometry/b.glb": 8,
|
||||
"geometry/c.glb": 1,
|
||||
"scene.json": 0,
|
||||
},
|
||||
total_limits,
|
||||
),
|
||||
_archive_count_case("archive_member_count_exact_limit", 3, count_limits),
|
||||
_archive_count_case("archive_member_count_over_limit", 4, count_limits),
|
||||
_compression_case(
|
||||
"aggregate_compression_ratio_exact_limit",
|
||||
"aggregate_compression_ratio",
|
||||
4,
|
||||
2,
|
||||
),
|
||||
_compression_case(
|
||||
"aggregate_compression_ratio_over_limit",
|
||||
"aggregate_compression_ratio",
|
||||
5,
|
||||
2,
|
||||
),
|
||||
_compression_case(
|
||||
"member_compression_ratio_exact_limit",
|
||||
"member_compression_ratio",
|
||||
4,
|
||||
2,
|
||||
),
|
||||
_compression_case(
|
||||
"member_compression_ratio_over_limit",
|
||||
"member_compression_ratio",
|
||||
5,
|
||||
2,
|
||||
),
|
||||
_json_depth_case("json_depth_exact_limit", 2),
|
||||
_json_depth_case("json_depth_over_limit", 3),
|
||||
]
|
||||
|
||||
for kind, overrides in (
|
||||
("value", {"json_string_bytes": 4}),
|
||||
("object_key", {"json_string_bytes": 4}),
|
||||
(
|
||||
"metadata_key",
|
||||
{"json_string_bytes": 100, "structural_id_bytes": 4},
|
||||
),
|
||||
(
|
||||
"sdk_metadata_key",
|
||||
{"json_string_bytes": 100, "structural_id_bytes": 4},
|
||||
),
|
||||
("uri", {"json_string_bytes": 100, "uri_bytes": 4}),
|
||||
):
|
||||
cases.append(
|
||||
_json_domain_case(
|
||||
f"utf8_{kind}_exact_limit", kind, "éé", overrides
|
||||
)
|
||||
)
|
||||
cases.append(
|
||||
_json_domain_case(
|
||||
f"utf8_{kind}_over_limit", kind, "ééa", overrides
|
||||
)
|
||||
)
|
||||
|
||||
identifier_fields = (
|
||||
"definition_ref",
|
||||
"node_id",
|
||||
"source_element_id",
|
||||
"topo_id",
|
||||
)
|
||||
for field in identifier_fields:
|
||||
overrides = {"json_string_bytes": 100, "structural_id_bytes": 4}
|
||||
cases.append(
|
||||
_json_domain_case(
|
||||
f"utf8_{field}_exact_limit",
|
||||
"identifier",
|
||||
"éé",
|
||||
overrides,
|
||||
field=field,
|
||||
)
|
||||
)
|
||||
cases.append(
|
||||
_json_domain_case(
|
||||
f"utf8_{field}_over_limit",
|
||||
"identifier",
|
||||
"ééa",
|
||||
overrides,
|
||||
field=field,
|
||||
)
|
||||
)
|
||||
|
||||
for field in (
|
||||
"child_entity_ids",
|
||||
"component_path",
|
||||
"evaluated_tags",
|
||||
"grounded_component_ids",
|
||||
"parent_entity_ids",
|
||||
"semantic_binding_ids",
|
||||
):
|
||||
overrides = {"json_string_bytes": 100, "structural_id_bytes": 4}
|
||||
cases.append(
|
||||
_json_domain_case(
|
||||
f"utf8_{field}_item_exact_limit",
|
||||
"identifier_array",
|
||||
"éé",
|
||||
overrides,
|
||||
field=field,
|
||||
)
|
||||
)
|
||||
cases.append(
|
||||
_json_domain_case(
|
||||
f"utf8_{field}_item_over_limit",
|
||||
"identifier_array",
|
||||
"ééa",
|
||||
overrides,
|
||||
field=field,
|
||||
)
|
||||
)
|
||||
|
||||
collection_limits = (
|
||||
("scene", "definitions", "definitions"),
|
||||
("scene", "nodes", "nodes"),
|
||||
("scene", "geometry_assets", "assets_per_kind"),
|
||||
("scene", "edge_assets", "assets_per_kind"),
|
||||
("scene", "entity_assets", "assets_per_kind"),
|
||||
("scene", "appearances", "appearances"),
|
||||
("scene", "connectors", "connectors"),
|
||||
("scene", "cameras", "cameras"),
|
||||
("entities", "entities", "entities_per_sidecar"),
|
||||
("entities", "face_groups", "entities_per_sidecar"),
|
||||
("entities", "edge_groups", "entities_per_sidecar"),
|
||||
("presentation", "node_overrides", "nodes"),
|
||||
("presentation", "appearances", "appearances"),
|
||||
("presentation", "cameras", "cameras"),
|
||||
)
|
||||
for artifact, field, limit_name in collection_limits:
|
||||
overrides = {limit_name: 2}
|
||||
cases.append(
|
||||
_resource_count_case(
|
||||
f"{artifact}_{field}_exact_limit",
|
||||
artifact,
|
||||
"collection",
|
||||
2,
|
||||
overrides,
|
||||
field=field,
|
||||
)
|
||||
)
|
||||
cases.append(
|
||||
_resource_count_case(
|
||||
f"{artifact}_{field}_over_limit",
|
||||
artifact,
|
||||
"collection",
|
||||
3,
|
||||
overrides,
|
||||
field=field,
|
||||
)
|
||||
)
|
||||
|
||||
cases.extend(
|
||||
[
|
||||
_resource_count_case(
|
||||
"hierarchy_depth_exact_limit",
|
||||
"scene",
|
||||
"hierarchy",
|
||||
2,
|
||||
{"hierarchy_depth": 2, "nodes": 10},
|
||||
),
|
||||
_resource_count_case(
|
||||
"hierarchy_depth_over_limit",
|
||||
"scene",
|
||||
"hierarchy",
|
||||
3,
|
||||
{"hierarchy_depth": 2, "nodes": 10},
|
||||
),
|
||||
_resource_count_case(
|
||||
"forwarded_connector_depth_exact_limit",
|
||||
"scene",
|
||||
"forwarded",
|
||||
2,
|
||||
{"connectors": 10, "forwarded_connector_depth": 2},
|
||||
),
|
||||
_resource_count_case(
|
||||
"forwarded_connector_depth_over_limit",
|
||||
"scene",
|
||||
"forwarded",
|
||||
3,
|
||||
{"connectors": 10, "forwarded_connector_depth": 2},
|
||||
),
|
||||
_glb_count_case(
|
||||
"triangle_vertices_per_asset_exact_limit",
|
||||
"triangle",
|
||||
2,
|
||||
3,
|
||||
{"triangle_vertices_per_asset": 2},
|
||||
),
|
||||
_glb_count_case(
|
||||
"triangle_vertices_per_asset_over_limit",
|
||||
"triangle",
|
||||
3,
|
||||
3,
|
||||
{"triangle_vertices_per_asset": 2},
|
||||
),
|
||||
_glb_count_case(
|
||||
"triangles_per_asset_exact_limit",
|
||||
"triangle",
|
||||
3,
|
||||
6,
|
||||
{"triangles_per_asset": 2},
|
||||
),
|
||||
_glb_count_case(
|
||||
"triangles_per_asset_over_limit",
|
||||
"triangle",
|
||||
3,
|
||||
9,
|
||||
{"triangles_per_asset": 2},
|
||||
),
|
||||
_glb_count_case(
|
||||
"line_vertices_per_asset_exact_limit",
|
||||
"line",
|
||||
2,
|
||||
2,
|
||||
{"line_vertices_per_asset": 2},
|
||||
),
|
||||
_glb_count_case(
|
||||
"line_vertices_per_asset_over_limit",
|
||||
"line",
|
||||
3,
|
||||
2,
|
||||
{"line_vertices_per_asset": 2},
|
||||
),
|
||||
_glb_count_case(
|
||||
"line_segments_per_asset_exact_limit",
|
||||
"line",
|
||||
2,
|
||||
4,
|
||||
{"line_segments_per_asset": 2},
|
||||
),
|
||||
_glb_count_case(
|
||||
"line_segments_per_asset_over_limit",
|
||||
"line",
|
||||
2,
|
||||
6,
|
||||
{"line_segments_per_asset": 2},
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
for limit_name in _BUDGET_FIELDS:
|
||||
cases.append(
|
||||
_package_budget_case(f"{limit_name}_exact_limit", limit_name, 2)
|
||||
)
|
||||
cases.append(
|
||||
_package_budget_case(f"{limit_name}_over_limit", limit_name, 3)
|
||||
)
|
||||
|
||||
for name, value_number in (
|
||||
("safe_integer_exact_limit", 9_007_199_254_740_991),
|
||||
("safe_integer_over_limit", 9_007_199_254_740_992),
|
||||
):
|
||||
value = deepcopy(scene)
|
||||
value["geometry_assets"][0]["byte_length"] = value_number
|
||||
if value_number <= 9_007_199_254_740_991:
|
||||
value = with_scene_revision(value)
|
||||
cases.append(
|
||||
_validation_case(
|
||||
name,
|
||||
"scene_geometry_byte_length",
|
||||
{"value": str(value_number)},
|
||||
validate_scene_manifest(value),
|
||||
)
|
||||
)
|
||||
|
||||
for name, field, value_number in (
|
||||
("linear_tolerance_exact_max", "linear_tolerance", 1_000_000),
|
||||
("linear_tolerance_over_max", "linear_tolerance", 1_000_001),
|
||||
("angular_tolerance_exact_max", "angular_tolerance", 3.141592653589793),
|
||||
("angular_tolerance_over_max", "angular_tolerance", 3.1415926535897936),
|
||||
):
|
||||
value = deepcopy(scene)
|
||||
value["compile_options"][field] = value_number
|
||||
value["geometry_assets"][0]["tessellation"][field] = value_number
|
||||
if field == "linear_tolerance":
|
||||
value["edge_assets"][0]["tessellation"][field] = value_number
|
||||
value = with_scene_revision(value)
|
||||
cases.append(
|
||||
_validation_case(
|
||||
name,
|
||||
"scene_compile_option",
|
||||
{"field": field, "value": value_number},
|
||||
validate_scene_manifest(value),
|
||||
)
|
||||
)
|
||||
|
||||
# Keep the argument in active use so fixture construction catches drift in
|
||||
# the valid normalized product even though resource probes are synthetic.
|
||||
assert normalized_part
|
||||
return cases
|
||||
Reference in New Issue
Block a user