File size: 4,323 Bytes
efb7599
 
 
 
 
 
 
 
 
 
b966cbf
efb7599
3b06380
efb7599
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b06380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b966cbf
efb7599
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
from __future__ import annotations

import json
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

from packing_benchmark.renderer import svg_markup  # noqa: E402
from packing_benchmark.store import SolutionStore  # noqa: E402
from packing_benchmark.verifier import load_solution_json, verify_record_solution, verify_solution  # noqa: E402


def test_seed_records_verify() -> None:
    for path in sorted((ROOT / "data" / "solutions").glob("*.json")):
        result = verify_solution(json.loads(path.read_text()))
        assert result.ok, (path.name, result.errors)


def test_rejects_overlapping_pair() -> None:
    solution = {
        "case": "squinsqu@2",
        "item": {"type": "regular_polygon", "sides": 4, "side_length": 1},
        "container": {"type": "regular_polygon", "sides": 4, "side_length": 3},
        "placements": [
            {"x": 0, "y": 0, "rotation_radians": 0},
            {"x": 0, "y": 0, "rotation_radians": 0},
        ],
    }
    result = verify_solution(solution)
    assert not result.ok
    assert result.max_pair_overlap_depth > 0


def test_rejects_boundary_protrusion() -> None:
    solution = {
        "case": "squinsqu@1",
        "item": {"type": "regular_polygon", "sides": 4, "side_length": 1},
        "container": {"type": "regular_polygon", "sides": 4, "side_length": 1},
        "placements": [
            {"x": 0.6, "y": 0.0, "rotation_radians": 0},
        ],
    }
    result = verify_solution(solution)
    assert not result.ok
    assert result.max_boundary_excess > 0


def test_rejects_wrong_case_family() -> None:
    solution = {
        "case": "triintri@1",
        "item": {"type": "circle", "radius": 0.5},
        "container": {"type": "regular_polygon", "sides": 4, "side_length": 2},
        "placements": [
            {"x": 0.0, "y": 0.0, "rotation_radians": 0},
        ],
    }
    result = verify_solution(solution)
    assert not result.ok
    assert any("does not match item/container geometry" in error for error in result.errors)


def test_rejects_wrong_setup_field() -> None:
    solution = {
        "case": "cirinsqu@1",
        "setup": "triintri",
        "item": {"type": "circle", "radius": 0.5},
        "container": {"type": "rectangle", "width": 2.0, "height": 2.0},
        "placements": [
            {"x": 0.0, "y": 0.0, "rotation_radians": 0},
        ],
    }
    result = verify_solution(solution)
    assert not result.ok
    assert any("setup" in error and "does not match" in error for error in result.errors)


def test_circle_container_metric_is_radius() -> None:
    solution = {
        "case": "triincir@1",
        "item": {"type": "regular_polygon", "sides": 3, "side_length": 1},
        "container": {"type": "circle", "radius": 1.0},
        "placements": [
            {"x": 0.0, "y": 0.0, "rotation_radians": 0},
        ],
    }
    result = verify_solution(solution)
    assert result.ok
    assert result.side == 2.0
    assert result.metric_symbol == "r"
    assert result.metric_value == 1.0


def test_rejects_non_finite_json_numbers() -> None:
    try:
        load_solution_json('{"case": "cirincir@1", "item": {"type": "circle", "radius": NaN}}')
    except ValueError as exc:
        assert "invalid JSON numeric constant" in str(exc)
    else:
        raise AssertionError("NaN JSON was accepted")


def test_record_solution_mismatch_is_detected() -> None:
    solution = {
        "case": "cirinsqu@1",
        "item": {"type": "circle", "radius": 0.5},
        "container": {"type": "rectangle", "width": 2.0, "height": 2.0},
        "placements": [
            {"x": 0.0, "y": 0.0, "rotation_radians": 0},
        ],
    }
    errors = verify_record_solution(
        {
            "case": "cirinsqu@1",
            "setup": "cirinsqu",
            "n": 1,
            "side": 3.0,
            "metric_symbol": "s",
            "metric_value": 3.0,
        },
        solution,
    )
    assert any("record side" in error for error in errors)


def test_store_and_svg_paths_exist() -> None:
    store = SolutionStore(ROOT / "data")
    records = store.best_records("All")
    assert records
    record = records[0]
    assert store.ensure_svg(record).exists()
    assert svg_markup(store.solution_for_record(record)).startswith("<svg")