|
44 | 44 | # --------------------------------------------------------------------------- |
45 | 45 | # Builders — a template.output "OrderOut" over an "Order" payload with a |
46 | 46 | # REQUIRED single nested object, a REQUIRED array-of-objects, a REQUIRED |
47 | | -# scalar-array, an OPTIONAL scalar, and an OPTIONAL single nested object. |
| 47 | +# scalar-array, an OPTIONAL scalar, an OPTIONAL scalar-array, and an OPTIONAL |
| 48 | +# single nested object. |
48 | 49 | # --------------------------------------------------------------------------- |
49 | 50 |
|
50 | 51 |
|
@@ -110,6 +111,11 @@ def _order_root() -> MetaRoot: |
110 | 111 | **{fc.FIELD_ATTR_REQUIRED: True, KEY_IS_ARRAY: True}, |
111 | 112 | ), |
112 | 113 | _field("note", fc.FIELD_SUBTYPE_STRING), # optional scalar |
| 114 | + _field( |
| 115 | + "aliases", |
| 116 | + fc.FIELD_SUBTYPE_STRING, |
| 117 | + **{KEY_IS_ARRAY: True}, # optional scalar-array (non-@required) |
| 118 | + ), |
113 | 119 | _field( |
114 | 120 | "ship_to", |
115 | 121 | fc.FIELD_SUBTYPE_OBJECT, |
@@ -253,6 +259,59 @@ def test_extract_extracts_dirty_into_strict_payload(tmp_path, monkeypatch) -> No |
253 | 259 | assert all(isinstance(s, int) for s in order.scores) |
254 | 260 | # optional nested absent → None. |
255 | 261 | assert order.ship_to is None |
| 262 | + # optional scalar-array absent → None (the `if m.f is not None else None` branch). |
| 263 | + assert order.aliases is None |
| 264 | + |
| 265 | + |
| 266 | +def test_extract_populates_optional_nested_when_present(tmp_path, monkeypatch) -> None: |
| 267 | + """Exercise the OPTIONAL single-nested PRESENT branch: |
| 268 | + ``(_to_strict_customer(m.ship_to) if m.ship_to is not None else None)``.""" |
| 269 | + from importlib import import_module |
| 270 | + |
| 271 | + root = _order_root() |
| 272 | + pkg_dir = _materialize_package(_all_files(root), tmp_path) |
| 273 | + _import_package(pkg_dir, monkeypatch) |
| 274 | + ex = import_module("_gen_pkg.order_out_extractor") |
| 275 | + |
| 276 | + dirty = ( |
| 277 | + "Sure, here you go!\n```json\n" |
| 278 | + '{ "customer": {"name": "Ada"}, ' |
| 279 | + '"lines": [{"sku":"A","qty":2}], ' |
| 280 | + '"tags": ["x"], ' |
| 281 | + '"scores": [3], ' |
| 282 | + '"ship_to": {"name": "Grace"} }\n```' |
| 283 | + ) |
| 284 | + order = ex.extract_order_out(root, dirty) |
| 285 | + # optional nested PRESENT → mapped through _to_strict_customer + strictly typed. |
| 286 | + assert order.ship_to is not None |
| 287 | + assert order.ship_to.name == "Grace" |
| 288 | + assert isinstance(order.ship_to, type(order.customer)) |
| 289 | + |
| 290 | + |
| 291 | +def test_extract_populates_optional_scalar_array_when_present( |
| 292 | + tmp_path, monkeypatch |
| 293 | +) -> None: |
| 294 | + """Exercise the OPTIONAL scalar-array PRESENT branch: |
| 295 | + ``[x for x in m.aliases if x is not None] if m.aliases is not None else None``.""" |
| 296 | + from importlib import import_module |
| 297 | + |
| 298 | + root = _order_root() |
| 299 | + pkg_dir = _materialize_package(_all_files(root), tmp_path) |
| 300 | + _import_package(pkg_dir, monkeypatch) |
| 301 | + ex = import_module("_gen_pkg.order_out_extractor") |
| 302 | + |
| 303 | + dirty = ( |
| 304 | + "Sure, here you go!\n```json\n" |
| 305 | + '{ "customer": {"name": "Ada"}, ' |
| 306 | + '"lines": [{"sku":"A","qty":2}], ' |
| 307 | + '"tags": ["x"], ' |
| 308 | + '"scores": [3], ' |
| 309 | + '"aliases": ["ada", "lovelace"] }\n```' |
| 310 | + ) |
| 311 | + order = ex.extract_order_out(root, dirty) |
| 312 | + # optional scalar-array PRESENT → populated list[str]. |
| 313 | + assert order.aliases == ["ada", "lovelace"] |
| 314 | + assert all(isinstance(a, str) for a in order.aliases) |
256 | 315 |
|
257 | 316 |
|
258 | 317 | def test_extract_raises_on_lost_required(tmp_path, monkeypatch) -> None: |
|
0 commit comments