Replace LeetCode fixtures with synthetic ones

Public repo: statements are original, in LeetCode's layout. Real problems are fetched at runtime by network-marked tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWYGW5NZL5uVpnqmNKo
This commit is contained in:
Krzysztof Rudnicki 2026-11-02 15:04:26 +01:00
parent 716231a7f3
commit 737bf624ca
11 changed files with 318 additions and 260 deletions

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "sql_drills"
version = "0.2.0"
version = "0.2.1"
description = "SQL drills (MySQL, PostgreSQL): sandboxed grading, LeetCode statement examples"
requires-python = ">=3.14"
# Stdlib only on purpose: the tutor server imports it from the system python.
@ -144,7 +144,10 @@ generated-members = [
exclude_dirs = ["tests", ".venv"]
[tool.pytest.ini_options]
markers = ["docker: needs a live sql-drills MySQL or PostgreSQL container (skipped when it is down)"]
markers = [
"docker: needs a live sql-drills MySQL or PostgreSQL container (skipped when it is down)",
"network: fetches a real LeetCode statement at runtime (skipped when unavailable)",
]
testpaths = ["sql_drills/tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]

View File

@ -1,62 +0,0 @@
# 1193. Monthly Transactions I (Medium)
Tags: Database
Languages available: mysql, mssql, postgresql, oraclesql, pythondata
Table: `Transactions`
```
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| country | varchar |
| state | enum |
| amount | int |
| trans_date | date |
+---------------+---------+
id is the primary key of this table.
The table has information about incoming transactions.
The state column is an enum of type ["approved", "declined"].
```
Write an SQL query to find for each month and country, the number of transactions and their total amount, the number of approved transactions and their total amount.
Return the result table in **any order**.
The query result format is in the following example.
**Example 1:**
```
**Input:**
Transactions table:
+------+---------+----------+--------+------------+
| id | country | state | amount | trans_date |
+------+---------+----------+--------+------------+
| 121 | US | approved | 1000 | 2018-12-18 |
| 122 | US | declined | 2000 | 2018-12-19 |
| 123 | US | approved | 2000 | 2019-01-01 |
| 124 | DE | approved | 2000 | 2019-01-07 |
+------+---------+----------+--------+------------+
**Output:**
+----------+---------+-------------+----------------+--------------------+-----------------------+
| month | country | trans_count | approved_count | trans_total_amount | approved_total_amount |
+----------+---------+-------------+----------------+--------------------+-----------------------+
| 2018-12 | US | 2 | 1 | 3000 | 1000 |
| 2019-01 | US | 1 | 1 | 2000 | 2000 |
| 2019-01 | DE | 1 | 1 | 2000 | 2000 |
+----------+---------+-------------+----------------+--------------------+-----------------------+
```
## Starter code (mysql)
```
# Write your MySQL query statement below
```

View File

@ -1,63 +0,0 @@
# 1179. Reformat Department Table (Easy)
Tags: Database
Languages available: mysql, mssql, postgresql, oraclesql, pythondata
Table: `Department`
```
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| revenue | int |
| month | varchar |
+-------------+---------+
In SQL,(id, month) is the primary key of this table.
The table has information about the revenue of each department per month.
The month has values in ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"].
```
Reformat the table such that there is a department id column and a revenue column **for each month**.
Return the result table in **any order**.
The result format is in the following example.
**Example 1:**
```
**Input:**
Department table:
+------+---------+-------+
| id | revenue | month |
+------+---------+-------+
| 1 | 8000 | Jan |
| 2 | 9000 | Jan |
| 3 | 10000 | Feb |
| 1 | 7000 | Feb |
| 1 | 6000 | Mar |
+------+---------+-------+
**Output:**
+------+-------------+-------------+-------------+-----+-------------+
| id | Jan_Revenue | Feb_Revenue | Mar_Revenue | ... | Dec_Revenue |
+------+-------------+-------------+-------------+-----+-------------+
| 1 | 8000 | 7000 | 6000 | ... | null |
| 2 | 9000 | null | null | ... | null |
| 3 | null | 10000 | null | ... | null |
+------+-------------+-------------+-------------+-----+-------------+
**Explanation:** The revenue from Apr to Dec is null.
Note that the result table has 13 columns (1 for the department id + 12 for the months).
```
## Starter code (mysql)
```
# Write your MySQL query statement below
```

View File

@ -3,40 +3,19 @@
from __future__ import annotations
from contextlib import contextmanager
from pathlib import Path
from typing import TYPE_CHECKING
from sql_drills import _dialect
from sql_drills._sandbox import Executed
from sql_drills.tests import synthetic
if TYPE_CHECKING:
from collections.abc import Callable, Iterator
import pytest
STATEMENTS = Path(__file__).parent / "statements"
MONTHS = [
f"{m}_Revenue"
for m in [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
]
]
GOOD_ROWS = [
["1", "8000", "7000", "6000", *["NULL"] * 9],
["2", "9000", *["NULL"] * 11],
["3", "NULL", "10000", *["NULL"] * 10],
]
MONTHS = [f"{m}_Weight" for m in synthetic.MONTHS]
GOOD_ROWS = synthetic.PIVOT_GOOD_ROWS
class StubBox:
@ -72,7 +51,3 @@ def install(
def done(columns: list[str], rows: list[list[str]]) -> Executed:
return Executed(ok=True, error=None, code=None, rows=rows, columns=columns)
def statement(slug: str) -> str:
return (STATEMENTS / f"{slug}.txt").read_text()

View File

@ -0,0 +1,158 @@
"""Original statements in LeetCode's layout; real problem text is never stored."""
from __future__ import annotations
MONTHS = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
]
PIVOT = """# 9001. Pivot Shipments (Easy)
Tags: Database
Languages available: mysql, postgresql
Table: `Shipments`
```
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| weight | int |
| month | varchar |
+-------------+---------+
(id, month) is the primary key of this table.
Each row is the weight a depot shipped in one month.
The month is one of ["Jan","Feb","Mar","Apr","May","Jun",
"Jul","Aug","Sep","Oct","Nov","Dec"].
```
Turn the table into one row per depot, with a weight column **for each month**.
Rows may come back in **any order**.
**Example 1:**
```
**Input:**
Shipments table:
+------+--------+-------+
| id | weight | month |
+------+--------+-------+
| 1 | 400 | Jan |
| 2 | 900 | Jan |
| 3 | 150 | Feb |
| 1 | 250 | Feb |
| 1 | 70 | Mar |
+------+--------+-------+
**Output:**
+------+------------+------------+------------+-----+------------+
| id | Jan_Weight | Feb_Weight | Mar_Weight | ... | Dec_Weight |
+------+------------+------------+------------+-----+------------+
| 1 | 400 | 250 | 70 | ... | null |
| 2 | 900 | null | null | ... | null |
| 3 | null | 150 | null | ... | null |
+------+------------+------------+------------+-----+------------+
**Explanation:** Depots ship nothing from Apr to Dec.
```
## Starter code (mysql)
```
# Write your MySQL query statement below
```
"""
ORDERS = """# 9002. Monthly Orders (Medium)
Tags: Database
Languages available: mysql, postgresql
Table: `Orders`
```
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| region | varchar |
| status | enum |
| total | int |
| placed_on | date |
+---------------+---------+
id is the primary key of this table.
The status column is an enum of type ["shipped", "returned"].
```
For each month and region, report the number of orders and their total, plus the
number of shipped orders and their total.
Rows may come back in **any order**.
**Example 1:**
```
**Input:**
Orders table:
+------+--------+----------+-------+------------+
| id | region | status | total | placed_on |
+------+--------+----------+-------+------------+
| 121 | North | shipped | 1000 | 2018-12-18 |
| 122 | North | returned | 2000 | 2018-12-19 |
| 123 | North | shipped | 2000 | 2019-01-01 |
| 124 | South | shipped | 2000 | 2019-01-07 |
+------+--------+----------+-------+------------+
**Output:**
+---------+--------+-------------+---------------+-------------+---------------+
| month | region | order_count | shipped_count | order_total | shipped_total |
+---------+--------+-------------+---------------+-------------+---------------+
| 2018-12 | North | 2 | 1 | 3000 | 1000 |
| 2019-01 | North | 1 | 1 | 2000 | 2000 |
| 2019-01 | South | 1 | 1 | 2000 | 2000 |
+---------+--------+-------------+---------------+-------------+---------------+
```
## Starter code (mysql)
```
# Write your MySQL query statement below
```
"""
PIVOT_GOOD_ROWS = [
["1", "400", "250", "70", *["NULL"] * 9],
["2", "900", *["NULL"] * 11],
["3", "NULL", "150", *["NULL"] * 10],
]
ORDERS_GOOD_ROWS = [
["2019-01", "South", "1", "1", "2000", "2000"],
["2018-12", "North", "2", "1", "3000.00", "1000"],
["2019-01", "North", "1", "1", "2000", "2000"],
]
PIVOT_SQL = (
"SELECT id, "
+ ", ".join(
f"SUM(CASE WHEN month = '{m}' THEN weight END) AS {m}_Weight" for m in MONTHS
)
+ " FROM Shipments GROUP BY id"
)
ORDERS_SQL = {
"mysql": "DATE_FORMAT(placed_on, '%Y-%m')",
"postgresql": "TO_CHAR(placed_on, 'YYYY-MM')",
}

View File

@ -1,50 +1,43 @@
"""Statement text to a runnable spec, on real fetched LeetCode statements."""
"""Statement text to a runnable spec, on synthetic LeetCode-layout statements."""
from __future__ import annotations
from pathlib import Path
from sql_drills import _lc_problem as lp
STATEMENTS = Path(__file__).parent / "statements"
from sql_drills.tests.synthetic import ORDERS, PIVOT
def _statement(slug: str) -> str:
return (STATEMENTS / f"{slug}.txt").read_text()
def test_reformat_department_table_example() -> None:
problem = lp.parse_problem(_statement("reformat-department-table"))
assert problem.schemas["Department"] == [
def test_pivot_example() -> None:
problem = lp.parse_problem(PIVOT)
assert problem.schemas["Shipments"] == [
("id", "int"),
("revenue", "int"),
("weight", "int"),
("month", "varchar"),
]
assert not problem.ordered
(example,) = problem.examples
dept = example.inputs["Department"]
assert dept.columns == ["id", "revenue", "month"]
assert dept.rows[0] == ["1", "8000", "Jan"]
dept = example.inputs["Shipments"]
assert dept.columns == ["id", "weight", "month"]
assert dept.rows[0] == ["1", "400", "Jan"]
assert len(dept.rows) == 5
assert example.expected.columns[:2] == ["id", "Jan_Revenue"]
assert example.expected.columns[:2] == ["id", "Jan_Weight"]
assert "..." in example.expected.columns
assert example.expected.rows[1] == ["2", "9000", "null", "null", "...", "null"]
assert example.expected.rows[1] == ["2", "900", "null", "null", "...", "null"]
def test_monthly_transactions_example_and_ddl() -> None:
problem = lp.parse_problem(_statement("monthly-transactions-i"))
def test_orders_example_and_ddl() -> None:
problem = lp.parse_problem(ORDERS)
(example,) = problem.examples
assert example.expected.columns[0] == "month"
assert len(example.expected.rows) == 3
my = lp.schema_sql(problem, example, "mysql")
assert "CREATE TABLE `Transactions`" in my
assert "`state` VARCHAR(255)" in my
assert "`trans_date` DATE" in my
assert "CREATE TABLE `Orders`" in my
assert "`status` VARCHAR(255)" in my
assert "`placed_on` DATE" in my
assert "(121, " not in my # values are quoted literals
assert "('121', 'US', 'approved', '1000', '2018-12-18')" in my
assert "('121', 'North', 'shipped', '1000', '2018-12-18')" in my
pg = lp.schema_sql(problem, example, "postgresql")
assert 'CREATE TABLE "transactions"' in pg
assert '"trans_date" DATE' in pg
assert 'CREATE TABLE "orders"' in pg
assert '"placed_on" DATE' in pg
def test_schema_nulls_and_quotes() -> None:

View File

@ -143,7 +143,7 @@ Output: 3
def test_order_detection_ignores_schema_blocks_and_any_order() -> None:
base = "Return the result table in **any order**.\nExample 1:\n"
base = "Rows may come back in **any order**.\nExample 1:\n"
sorted_by = "Return the result sorted by id.\nExample 1:\n"
in_block = "```\nthe table is ordered by id\n```\n" + base
assert not lp.is_ordered(base)

View File

@ -6,7 +6,8 @@ from typing import TYPE_CHECKING
import sql_drills as sd
from sql_drills._sandbox import Executed
from sql_drills.tests.stubs import GOOD_ROWS, MONTHS, done, install, statement
from sql_drills.tests.stubs import GOOD_ROWS, MONTHS, done, install
from sql_drills.tests.synthetic import ORDERS, PIVOT
if TYPE_CHECKING:
import pytest
@ -16,13 +17,13 @@ def test_elided_columns_compare_only_the_named_ones(
monkeypatch: pytest.MonkeyPatch,
) -> None:
schemas, boxes = install(monkeypatch, done(["id", *MONTHS], GOOD_ROWS))
(res,) = sd.run_problem(statement("reformat-department-table"), "SELECT 1", "mysql")
(res,) = sd.run_problem(PIVOT, "SELECT 1", "mysql")
assert res.ok
assert res.match, res.cell_diff
assert res.note is not None
assert "..." in res.note
assert schemas[0] == "dialect=mysql"
assert schemas[1].startswith("CREATE TABLE `Department`")
assert schemas[1].startswith("CREATE TABLE `Shipments`")
assert boxes[0].sqls == ["SELECT 1"]
assert res.columns == ["id", *MONTHS]
@ -32,9 +33,7 @@ def test_postgres_lowercase_names_and_row_order_are_fine(
) -> None:
cols = ["id", *[m.lower() for m in MONTHS]]
install(monkeypatch, done(cols, list(reversed(GOOD_ROWS))))
(res,) = sd.run_problem(
statement("reformat-department-table"), "SELECT 1", "postgresql"
)
(res,) = sd.run_problem(PIVOT, "SELECT 1", "postgresql")
assert res.match
@ -42,7 +41,7 @@ def test_wrong_value_gives_a_cell_diff(monkeypatch: pytest.MonkeyPatch) -> None:
bad = [list(r) for r in GOOD_ROWS]
bad[0][1] = "1"
install(monkeypatch, done(["id", *MONTHS], bad))
(res,) = sd.run_problem(statement("reformat-department-table"), "x", "mysql")
(res,) = sd.run_problem(PIVOT, "x", "mysql")
assert not res.match
assert res.cell_diff
assert res.missing_rows
@ -52,7 +51,7 @@ def test_wrong_value_gives_a_cell_diff(monkeypatch: pytest.MonkeyPatch) -> None:
def test_missing_named_column_does_not_match(monkeypatch: pytest.MonkeyPatch) -> None:
rows = [r[:-1] for r in GOOD_ROWS]
install(monkeypatch, done(["id", *MONTHS[:-1]], rows))
(res,) = sd.run_problem(statement("reformat-department-table"), "x", "mysql")
(res,) = sd.run_problem(PIVOT, "x", "mysql")
assert not res.match
@ -61,7 +60,7 @@ def test_query_error_is_reported_per_example(monkeypatch: pytest.MonkeyPatch) ->
ok=False, error='ERROR: column "Jan" does not exist', code=None, rows=[]
)
install(monkeypatch, err)
(res,) = sd.run_problem(statement("reformat-department-table"), "x", "postgresql")
(res,) = sd.run_problem(PIVOT, "x", "postgresql")
assert not res.ok
assert not res.match
assert res.error == 'ERROR: column "Jan" does not exist'
@ -69,27 +68,25 @@ def test_query_error_is_reported_per_example(monkeypatch: pytest.MonkeyPatch) ->
assert res.expected_rows[0][0] == "1"
def test_monthly_transactions_unordered_match(monkeypatch: pytest.MonkeyPatch) -> None:
def test_orders_unordered_match(monkeypatch: pytest.MonkeyPatch) -> None:
rows = [
["2019-01", "DE", "1", "1", "2000", "2000"],
["2018-12", "US", "2", "1", "3000.00", "1000"],
["2019-01", "US", "1", "1", "2000", "2000"],
["2019-01", "South", "1", "1", "2000", "2000"],
["2018-12", "North", "2", "1", "3000.00", "1000"],
["2019-01", "North", "1", "1", "2000", "2000"],
]
cols = ["month", "country", "trans_count", "approved_count", "a", "b"]
cols = ["month", "region", "order_count", "shipped_count", "a", "b"]
install(monkeypatch, done(cols, rows))
(res,) = sd.run_problem(statement("monthly-transactions-i"), "x", "mysql")
(res,) = sd.run_problem(ORDERS, "x", "mysql")
assert res.match
assert res.note is None
def test_ordered_statement_demands_order(monkeypatch: pytest.MonkeyPatch) -> None:
text = statement("monthly-transactions-i").replace(
"**any order**", "ordered by month"
)
text = ORDERS.replace("**any order**", "ordered by month")
rows = [
["2019-01", "DE", "1", "1", "2000", "2000"],
["2018-12", "US", "2", "1", "3000", "1000"],
["2019-01", "US", "1", "1", "2000", "2000"],
["2019-01", "South", "1", "1", "2000", "2000"],
["2018-12", "North", "2", "1", "3000", "1000"],
["2019-01", "North", "1", "1", "2000", "2000"],
]
install(monkeypatch, done(["a"] * 6, rows))
(res,) = sd.run_problem(text, "x", "mysql")

View File

@ -7,7 +7,8 @@ from typing import TYPE_CHECKING, cast
import pytest
import sql_drills as sd
from sql_drills.tests.stubs import GOOD_ROWS, MONTHS, done, install, statement
from sql_drills.tests.stubs import GOOD_ROWS, MONTHS, done, install
from sql_drills.tests.synthetic import PIVOT
if TYPE_CHECKING:
from sql_drills._dialect import Dialect
@ -64,8 +65,8 @@ def test_statement_without_examples_raises(monkeypatch: pytest.MonkeyPatch) -> N
@pytest.mark.parametrize(
"arg",
[
"reformat-department-table",
"https://leetcode.com/problems/reformat-department-table/description/",
"pivot-shipments",
"https://leetcode.com/problems/pivot-shipments/description/",
],
)
def test_slug_and_url_are_fetched(monkeypatch: pytest.MonkeyPatch, arg: str) -> None:
@ -73,9 +74,9 @@ def test_slug_and_url_are_fetched(monkeypatch: pytest.MonkeyPatch, arg: str) ->
def fetch(slug: str, dialect: str) -> str:
asked.append((slug, dialect))
return statement("reformat-department-table")
return PIVOT
install(monkeypatch, done(["id", *MONTHS], GOOD_ROWS))
(res,) = sd.run_problem(arg, "x", "postgresql", fetch=fetch)
assert res.match
assert asked == [("reformat-department-table", "postgresql")]
assert asked == [("pivot-shipments", "postgresql")]

View File

@ -0,0 +1,91 @@
"""Real LeetCode problems, fetched at runtime and never stored in the repo.
Needs the network and the live containers; skipped when either is missing.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
import sql_drills as sd
from sql_drills import _engine, _lc_run, _pg_engine
if TYPE_CHECKING:
from collections.abc import Callable
from sql_drills._dialect import Dialect
MONTHS = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
]
PIVOT_SQL = (
"SELECT id, "
+ ", ".join(
f"SUM(CASE WHEN month = '{m}' THEN revenue END) AS {m}_Revenue" for m in MONTHS
)
+ " FROM Department GROUP BY id"
)
MONTHLY_SQL = {
"mysql": "DATE_FORMAT(trans_date, '%Y-%m')",
"postgresql": "TO_CHAR(trans_date, 'YYYY-MM')",
}
def _ready(check: Callable[[], bool]) -> bool:
try:
return check()
except _engine.EngineError:
return False
pytestmark = [
pytest.mark.docker,
pytest.mark.network,
pytest.mark.skipif(
not _ready(_pg_engine.is_ready), reason="sql-drills-postgres is not running"
),
]
def _fetch(slug: str, dialect: str) -> str:
try:
return _lc_run.default_fetch(slug, dialect)
except sd.ProblemUnavailableError as exc:
return pytest.skip(str(exc))
def test_reformat_department_table() -> None:
text = _fetch("reformat-department-table", "postgresql")
(res,) = sd.run_problem(text, PIVOT_SQL, "postgresql")
assert res.match, (res.error, res.cell_diff)
quoted = PIVOT_SQL.replace("month = 'Jan'", 'month = "Jan"')
(bad,) = sd.run_problem(text, quoted, "postgresql")
assert 'column "Jan" does not exist' in (bad.error or "")
@pytest.mark.parametrize("dialect", ["postgresql", "mysql"])
def test_monthly_transactions_i(dialect: Dialect) -> None:
if dialect == "mysql" and not _ready(_engine.is_ready):
pytest.skip("mysql container is down")
month = MONTHLY_SQL[dialect]
sql = (
f"SELECT {month}, country, COUNT(*), "
"SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END), SUM(amount), "
"SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) "
f"FROM Transactions GROUP BY {month}, country"
)
(res,) = sd.run_problem(_fetch("monthly-transactions-i", dialect), sql, dialect)
assert res.match, (res.error, res.cell_diff)

View File

@ -6,44 +6,19 @@ touch the MySQL container's data, and only use their own ``drill_*`` databases.
from __future__ import annotations
from pathlib import Path
from typing import TYPE_CHECKING
import pytest
import sql_drills as sd
from sql_drills import _engine, _pg_engine, _pg_sandbox
from sql_drills.tests.synthetic import ORDERS, ORDERS_SQL, PIVOT, PIVOT_SQL
if TYPE_CHECKING:
from collections.abc import Callable
from sql_drills._dialect import Dialect
STATEMENTS = Path(__file__).parent / "statements"
MONTHS = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
]
_PIVOT_COLS = ", ".join(
f"SUM(CASE WHEN month = '{m}' THEN revenue END) AS {m}_Revenue" for m in MONTHS
)
PIVOT = f"SELECT id, {_PIVOT_COLS} FROM Department GROUP BY id"
PIVOT_JAN_QUOTED = PIVOT.replace("month = 'Jan'", 'month = "Jan"')
MONTHLY = {
"mysql": "DATE_FORMAT(trans_date, '%Y-%m')",
"postgresql": "TO_CHAR(trans_date, 'YYYY-MM')",
}
def _up(check: Callable[[], bool]) -> bool:
try:
@ -60,56 +35,48 @@ pytestmark = [
]
def _text(slug: str) -> str:
return (STATEMENTS / f"{slug}.txt").read_text()
def _monthly(dialect: Dialect) -> str:
return (
f"SELECT {MONTHLY[dialect]} AS month, country, COUNT(*), "
"SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END), SUM(amount), "
"SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) "
f"FROM Transactions GROUP BY {MONTHLY[dialect]}, country"
)
def _roles_and_databases() -> tuple[set[str], set[str]]:
dbs = _pg_engine.run_sql("SELECT datname FROM pg_database", header=False)
roles = _pg_engine.run_sql("SELECT rolname FROM pg_roles", header=False)
return set(dbs.stdout.split()), set(roles.stdout.split())
def test_reformat_department_table_passes_in_postgres() -> None:
(res,) = sd.run_problem(_text("reformat-department-table"), PIVOT, "postgresql")
def test_pivot_passes_in_postgres() -> None:
(res,) = sd.run_problem(PIVOT, PIVOT_SQL, "postgresql")
assert res.ok, res.error
assert res.match, res.cell_diff
assert len(res.columns) == 13
def test_double_quoted_month_fails_in_postgres_but_passes_in_mysql() -> None:
statement = _text("reformat-department-table")
(pg,) = sd.run_problem(statement, PIVOT_JAN_QUOTED, "postgresql")
quoted = PIVOT_SQL.replace("month = 'Jan'", 'month = "Jan"')
(pg,) = sd.run_problem(PIVOT, quoted, "postgresql")
assert not pg.ok
assert 'column "Jan" does not exist' in (pg.error or "")
if not _up(_engine.is_ready):
pytest.skip("mysql container is down")
(my,) = sd.run_problem(statement, PIVOT_JAN_QUOTED, "mysql")
(my,) = sd.run_problem(PIVOT, quoted, "mysql")
assert my.match
@pytest.mark.parametrize("dialect", ["postgresql", "mysql"])
def test_monthly_transactions_passes_in_both_dialects(dialect: Dialect) -> None:
def test_orders_pass_in_both_dialects(dialect: Dialect) -> None:
if dialect == "mysql" and not _up(_engine.is_ready):
pytest.skip("mysql container is down")
(res,) = sd.run_problem(_text("monthly-transactions-i"), _monthly(dialect), dialect)
month = ORDERS_SQL[dialect]
sql = (
f"SELECT {month}, region, COUNT(*), "
"SUM(CASE WHEN status = 'shipped' THEN 1 ELSE 0 END), SUM(total), "
"SUM(CASE WHEN status = 'shipped' THEN total ELSE 0 END) "
f"FROM Orders GROUP BY {month}, region"
)
(res,) = sd.run_problem(ORDERS, sql, dialect)
assert res.ok, res.error
assert res.match, (res.cell_diff, res.rows)
def test_wrong_answer_reports_cells() -> None:
(res,) = sd.run_problem(
_text("monthly-transactions-i"), "SELECT 1, 2, 3, 4, 5, 6", "postgresql"
)
(res,) = sd.run_problem(ORDERS, "SELECT 1, 2, 3, 4, 5, 6", "postgresql")
assert res.ok
assert not res.match
assert res.cell_diff
@ -117,9 +84,7 @@ def test_wrong_answer_reports_cells() -> None:
def test_runs_are_isolated_and_leave_nothing_behind() -> None:
before = _roles_and_databases()
sd.run_problem(
_text("monthly-transactions-i"), "DELETE FROM Transactions", "postgresql"
)
sd.run_problem(ORDERS, "DELETE FROM Orders", "postgresql")
assert _roles_and_databases() == before