|
17 | 17 | PathDefaultDescriptionCase, |
18 | 18 | RequiredDescriptionAggregateCase, |
19 | 19 | RequiredDescriptionCase, |
| 20 | + RequiredDescriptionExactOutputCase, |
20 | 21 | RequiredDescriptionPlanCase, |
21 | 22 | ) |
22 | 23 | from tests.e2e.src.sqlbuild.cli.commands.main.compile.helpers import ( |
|
43 | 44 | ) |
44 | 45 |
|
45 | 46 |
|
| 47 | +_SHADOWED_SOURCES_YAML: str = ( |
| 48 | + "sources:\n" |
| 49 | + " - name: raw_orders\n" |
| 50 | + " schema: main\n" |
| 51 | + " table: orders\n" |
| 52 | + " columns:\n" |
| 53 | + " - name: raw_refunds\n" |
| 54 | + " type: INTEGER\n" |
| 55 | + ' - name: "raw_refunds" # refunds feed\n' |
| 56 | + " schema: main\n" |
| 57 | + " table: refunds\n" |
| 58 | + " - name: 'raw_customers'\n" |
| 59 | + " schema: main\n" |
| 60 | + " table: customers\n" |
| 61 | +) |
| 62 | +_TWO_SEEDS_YAML: str = ( |
| 63 | + "seeds:\n" |
| 64 | + " - name: product_types\n" + _SEED_COLUMNS + " - name: product_labels\n" + _SEED_COLUMNS |
| 65 | +) |
| 66 | + |
| 67 | + |
46 | 68 | _PROVIDER_DESCRIBED: str = ( |
47 | 69 | "from sqlbuild.providers import Provider\n\n\n" |
48 | 70 | "class OrdersApi(Provider):\n" |
@@ -534,6 +556,89 @@ def test_given_every_resource_kind_undescribed_when_compiling_then_one_run_repor |
534 | 556 | assert kinds == test_case.expected_kinds |
535 | 557 |
|
536 | 558 |
|
| 559 | +@pytest.mark.parametrize( |
| 560 | + "test_case", |
| 561 | + [ |
| 562 | + RequiredDescriptionExactOutputCase( |
| 563 | + description="seed and source entries located at their outermost declarations", |
| 564 | + files=( |
| 565 | + ("models/order_summary.sql", "MODEL ();\nSELECT 1 AS order_count\n"), |
| 566 | + ("seeds/product_types.csv", _SEED_CSV), |
| 567 | + ("seeds/product_labels.csv", _SEED_CSV), |
| 568 | + ("seeds/products.yml", _TWO_SEEDS_YAML), |
| 569 | + ("sources/raw.yml", _SHADOWED_SOURCES_YAML), |
| 570 | + ), |
| 571 | + expected_diagnostics=( |
| 572 | + ( |
| 573 | + "P010", |
| 574 | + "model 'order_summary' has no description", |
| 575 | + "models/order_summary.sql", |
| 576 | + 1, |
| 577 | + 1, |
| 578 | + ), |
| 579 | + ("P010", "seed 'product_types' has no description", "seeds/products.yml", 2, 1), |
| 580 | + ("P010", "seed 'product_labels' has no description", "seeds/products.yml", 8, 1), |
| 581 | + ("P010", "source 'raw_orders' has no description", "sources/raw.yml", 2, 1), |
| 582 | + ("P010", "source 'raw_refunds' has no description", "sources/raw.yml", 8, 1), |
| 583 | + ("P010", "source 'raw_customers' has no description", "sources/raw.yml", 11, 1), |
| 584 | + ), |
| 585 | + expected_help=( |
| 586 | + "to describe model 'order_summary', add this to the MODEL header in " |
| 587 | + "models/order_summary.sql:\n" |
| 588 | + " MODEL (\n" |
| 589 | + ' description "What one row of order_summary represents",\n' |
| 590 | + " ...\n" |
| 591 | + " );", |
| 592 | + ( |
| 593 | + "to describe seed 'product_types', add `description` to its entry in seeds/products.yml:\n" |
| 594 | + " - name: product_types\n" |
| 595 | + " description: What one row of product_types represents" |
| 596 | + ), |
| 597 | + ( |
| 598 | + "to describe seed 'product_labels', add `description` to its entry in seeds/products.yml:\n" |
| 599 | + " - name: product_labels\n" |
| 600 | + " description: What one row of product_labels represents" |
| 601 | + ), |
| 602 | + ( |
| 603 | + "to describe source 'raw_orders', add `description` to its entry in sources/raw.yml:\n" |
| 604 | + " - name: raw_orders\n" |
| 605 | + " description: What one row of raw_orders represents" |
| 606 | + ), |
| 607 | + ( |
| 608 | + "to describe source 'raw_refunds', add `description` to its entry in sources/raw.yml:\n" |
| 609 | + " - name: raw_refunds\n" |
| 610 | + " description: What one row of raw_refunds represents" |
| 611 | + ), |
| 612 | + ( |
| 613 | + "to describe source 'raw_customers', add `description` to its entry in sources/raw.yml:\n" |
| 614 | + " - name: raw_customers\n" |
| 615 | + " description: What one row of raw_customers represents" |
| 616 | + ), |
| 617 | + ), |
| 618 | + ), |
| 619 | + ], |
| 620 | + ids=lambda case: case.description, |
| 621 | +) |
| 622 | +def test_given_undescribed_yaml_entries_when_compiling_then_reports_exact_ordered_diagnostics( |
| 623 | + test_case: RequiredDescriptionExactOutputCase, tmp_path: Path |
| 624 | +) -> None: |
| 625 | + result: subprocess.CompletedProcess[str] = compile_inline_files( |
| 626 | + tmp_path=tmp_path, files=test_case.files |
| 627 | + ) |
| 628 | + |
| 629 | + payload: dict[str, Any] = json.loads(result.stdout) |
| 630 | + diagnostics: list[dict[str, Any]] = payload["diagnostics"] |
| 631 | + assert result.returncode == 1, result.stdout + result.stderr |
| 632 | + assert ( |
| 633 | + tuple( |
| 634 | + (item["code"], item["message"], item["path"], item["line"], item["column"]) |
| 635 | + for item in diagnostics |
| 636 | + ) |
| 637 | + == test_case.expected_diagnostics |
| 638 | + ) |
| 639 | + assert tuple(item["help"] for item in diagnostics) == test_case.expected_help |
| 640 | + |
| 641 | + |
537 | 642 | @pytest.mark.parametrize( |
538 | 643 | "test_case", |
539 | 644 | [ |
|
0 commit comments