|
10 | 10 | FloatTaskParameterDefinition, |
11 | 11 | IntTaskParameterDefinition, |
12 | 12 | PathTaskParameterDefinition, |
| 13 | + RangeExpressionTaskParameterDefinition, |
| 14 | + RangeListTaskParameterDefinition, |
13 | 15 | StepParameterSpaceDefinition, |
14 | 16 | StringTaskParameterDefinition, |
15 | 17 | ) |
@@ -329,6 +331,10 @@ class TestRangeExpressionTaskParameterDefinition: |
329 | 331 | }, |
330 | 332 | id="format string with multiple", |
331 | 333 | ), |
| 334 | + pytest.param( |
| 335 | + {"name": "foo", "type": "INT", "range": "1-5000"}, |
| 336 | + id="expansion past the list-form cap", |
| 337 | + ), |
332 | 338 | ), |
333 | 339 | ) |
334 | 340 | def test_parse_success(self, data: dict[str, str]) -> None: |
@@ -375,6 +381,64 @@ def test_parse_fails(self, data: dict[str, Any]) -> None: |
375 | 381 | assert len(excinfo.value.errors()) > 0 |
376 | 382 |
|
377 | 383 |
|
| 384 | +class TestTaskParameterRangeLength: |
| 385 | + """§3.4 caps the number of elements in the *list* forms of a task parameter's |
| 386 | + range. §3.4.1.1.1 `<IntRangeExpr>` carries no element cap, so an expression's |
| 387 | + expansion must not be capped — the form exists to express frame ranges, which |
| 388 | + routinely run to thousands of values. |
| 389 | + """ |
| 390 | + |
| 391 | + @pytest.mark.parametrize( |
| 392 | + "range_expr,expected_len", |
| 393 | + ( |
| 394 | + pytest.param("1-1024", 1024, id="at the list-form cap"), |
| 395 | + pytest.param("1-1025", 1025, id="one past the list-form cap"), |
| 396 | + pytest.param("1-5000", 5000, id="ordinary frame range"), |
| 397 | + pytest.param("1-100000:2", 50000, id="large range with a step"), |
| 398 | + ), |
| 399 | + ) |
| 400 | + def test_range_expression_expansion_is_not_capped( |
| 401 | + self, range_expr: str, expected_len: int |
| 402 | + ) -> None: |
| 403 | + # WHEN the template-layer definition parses a literal range expression |
| 404 | + _parse_model( |
| 405 | + model=IntTaskParameterDefinition, |
| 406 | + obj={"name": "foo", "type": "INT", "range": range_expr}, |
| 407 | + ) |
| 408 | + |
| 409 | + # AND the instantiation target parses the same expression |
| 410 | + instantiated = _parse_model( |
| 411 | + model=RangeExpressionTaskParameterDefinition, |
| 412 | + obj={"type": "INT", "range": range_expr}, |
| 413 | + ) |
| 414 | + |
| 415 | + # THEN neither rejects it, and the range expands in full |
| 416 | + assert len(instantiated.range) == expected_len |
| 417 | + |
| 418 | + @pytest.mark.parametrize( |
| 419 | + "model,obj", |
| 420 | + ( |
| 421 | + pytest.param( |
| 422 | + IntTaskParameterDefinition, |
| 423 | + {"name": "foo", "type": "INT", "range": [1] * 1025}, |
| 424 | + id="template layer", |
| 425 | + ), |
| 426 | + pytest.param( |
| 427 | + RangeListTaskParameterDefinition, |
| 428 | + {"type": "INT", "range": [1] * 1025}, |
| 429 | + id="instantiation layer", |
| 430 | + ), |
| 431 | + ), |
| 432 | + ) |
| 433 | + def test_list_form_range_is_still_capped(self, model: Any, obj: dict[str, Any]) -> None: |
| 434 | + # WHEN a list-form range one element past the §3.4 cap is parsed |
| 435 | + with pytest.raises(ValidationError) as excinfo: |
| 436 | + _parse_model(model=model, obj=obj) |
| 437 | + |
| 438 | + # THEN it is rejected |
| 439 | + assert len(excinfo.value.errors()) > 0 |
| 440 | + |
| 441 | + |
378 | 442 | class TestStepParameterSpaceDefinition: |
379 | 443 | @pytest.mark.parametrize( |
380 | 444 | "data", |
|
0 commit comments