]> git.ipfire.org Git - thirdparty/fastapi/sqlmodel.git/commitdiff
✅ Add tests
authorSebastián Ramírez <tiangolo@gmail.com>
Tue, 24 Aug 2021 13:15:26 +0000 (15:15 +0200)
committerSebastián Ramírez <tiangolo@gmail.com>
Tue, 24 Aug 2021 13:15:26 +0000 (15:15 +0200)
114 files changed:
tests/__init__.py [new file with mode: 0644]
tests/conftest.py [new file with mode: 0644]
tests/test_default.py [new file with mode: 0644]
tests/test_instance_no_args.py [new file with mode: 0644]
tests/test_query.py [new file with mode: 0644]
tests/test_tutorial/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_automatic_id_none_refresh/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_automatic_id_none_refresh/test_tutorial001_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_code_structure/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_code_structure/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_code_structure/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_connect/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_create_connected_tables/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_create_connected_tables/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_delete/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_delete/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_insert/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_insert/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_select/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_select/test_tutorial001_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_select/test_tutorial003.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_select/test_tutorial004.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_select/test_tutorial005.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_update/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_connect/test_update/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_create_db_and_table/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_create_db_and_table/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_create_db_and_table/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_create_db_and_table/test_tutorial003.py [new file with mode: 0644]
tests/test_tutorial/test_delete/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_delete/test_tutorial001_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_app_testing/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests002.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests003.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests004.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests005.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests006.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests_main.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_delete/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_limit_and_offset/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_multiple_models/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_read_one/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_relationships/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_response_model/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_session_with_dependency/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_simple_hero_api/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_teams/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_update/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_insert/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_insert/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_insert/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_insert/test_tutorial003.py [new file with mode: 0644]
tests/test_tutorial/test_limit_and_offset/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_limit_and_offset/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_limit_and_offset/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_limit_and_offset/test_tutorial003.py [new file with mode: 0644]
tests/test_tutorial/test_limit_and_offset/test_tutorial004.py [new file with mode: 0644]
tests/test_tutorial/test_many_to_many/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_many_to_many/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_many_to_many/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_many_to_many/test_tutorial003.py [new file with mode: 0644]
tests/test_tutorial/test_one/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_one/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_one/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_one/test_tutorial003.py [new file with mode: 0644]
tests/test_tutorial/test_one/test_tutorial004.py [new file with mode: 0644]
tests/test_tutorial/test_one/test_tutorial005.py [new file with mode: 0644]
tests/test_tutorial/test_one/test_tutorial006.py [new file with mode: 0644]
tests/test_tutorial/test_one/test_tutorial007.py [new file with mode: 0644]
tests/test_tutorial/test_one/test_tutorial008.py [new file with mode: 0644]
tests/test_tutorial/test_one/test_tutorial009.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_back_populates/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial003.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_create_and_update_relationships/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_create_and_update_relationships/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_define_relationship_attributes/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_define_relationship_attributes/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_read_relationships/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_read_relationships/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_relationship_attributes/test_read_relationships/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_select/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_select/test_tutorial001_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_select/test_tutorial003_tutorial004.py [new file with mode: 0644]
tests/test_tutorial/test_update/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_update/test_tutorial001_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_update/test_tutorial003_tutorial004.py [new file with mode: 0644]
tests/test_tutorial/test_where/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial002.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial003.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial004.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial005.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial006.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial007.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial008.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial009.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial010.py [new file with mode: 0644]
tests/test_tutorial/test_where/test_tutorial011.py [new file with mode: 0644]

diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644 (file)
index 0000000..15c7cac
--- /dev/null
@@ -0,0 +1,69 @@
+import shutil
+import subprocess
+from pathlib import Path
+from typing import Any, Callable, Dict, List, Union
+import pytest
+from sqlmodel import SQLModel
+from sqlmodel.main import default_registry
+from pydantic import BaseModel
+
+top_level_path = Path(__file__).resolve().parent.parent
+docs_src_path = top_level_path / "docs_src"
+
+
+@pytest.fixture()
+def clear_sqlmodel():
+    # Clear the tables in the metadata for the default base model
+    SQLModel.metadata.clear()
+    # Clear the Models associated with the registry, to avoid warnings
+    default_registry.dispose()
+    yield
+    SQLModel.metadata.clear()
+    default_registry.dispose()
+
+
+@pytest.fixture()
+def cov_tmp_path(tmp_path: Path):
+    yield tmp_path
+    for coverage_path in tmp_path.glob(".coverage*"):
+        coverage_destiny_path = top_level_path / coverage_path.name
+        shutil.copy(coverage_path, coverage_destiny_path)
+
+
+def coverage_run(*, module: str, cwd: Union[str, Path]) -> subprocess.CompletedProcess:
+    result = subprocess.run(
+        [
+            "coverage",
+            "run",
+            "--parallel-mode",
+            "--source=docs_src,tests,sqlmodel",
+            "-m",
+            module,
+        ],
+        cwd=str(cwd),
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        encoding="utf-8",
+    )
+    return result
+
+
+def get_testing_print_function(
+    calls: List[List[Union[str, Dict[str, Any]]]]
+) -> Callable[..., Any]:
+    def new_print(*args):
+        data = []
+        for arg in args:
+            if isinstance(arg, BaseModel):
+                data.append(arg.dict())
+            elif isinstance(arg, list):
+                new_list = []
+                for item in arg:
+                    if isinstance(item, BaseModel):
+                        new_list.append(item.dict())
+                data.append(new_list)
+            else:
+                data.append(arg)
+        calls.append(data)
+
+    return new_print
diff --git a/tests/test_default.py b/tests/test_default.py
new file mode 100644 (file)
index 0000000..cf61cf8
--- /dev/null
@@ -0,0 +1,44 @@
+from sqlmodel.default import Default
+
+
+def test_default_bool() -> None:
+    dt1 = Default(True)
+    dt2 = Default(1)
+    dt3 = Default("foo")
+    dt4 = Default(["foo"])
+    df1 = Default(False)
+    df2 = Default(0)
+    df3 = Default("")
+    df4: list = Default([])
+    df5 = Default(None)
+
+    assert not not dt1
+    assert not not dt2
+    assert not not dt3
+    assert not not dt4
+    assert not df1
+    assert not df2
+    assert not df3
+    assert not df4
+    assert not df5
+
+
+def test_equality() -> None:
+    value1 = Default("foo")
+    value2 = Default("foo")
+
+    assert value1 == value2
+
+
+def test_not_equality() -> None:
+    value1 = Default("foo")
+    value2 = Default("bar")
+
+    assert not (value1 == value2)
+
+
+def test_not_equality_other() -> None:
+    value1 = Default("foo")
+    value2 = "foo"
+
+    assert not (value1 == value2)
diff --git a/tests/test_instance_no_args.py b/tests/test_instance_no_args.py
new file mode 100644 (file)
index 0000000..14d5606
--- /dev/null
@@ -0,0 +1,27 @@
+from typing import Optional
+
+from sqlalchemy import create_engine, select
+from sqlalchemy.orm import Session
+from sqlmodel import Field, SQLModel
+
+
+def test_allow_instantiation_without_arguments(clear_sqlmodel):
+    class Item(SQLModel):
+        id: Optional[int] = Field(default=None, primary_key=True)
+        name: str
+        description: Optional[str] = None
+
+        class Config:
+            table = True
+
+    engine = create_engine("sqlite:///:memory:")
+    SQLModel.metadata.create_all(engine)
+    with Session(engine) as db:
+        item = Item()
+        item.name = "Rick"
+        db.add(item)
+        db.commit()
+        result = db.execute(select(Item)).scalars().all()
+    assert len(result) == 1
+    assert isinstance(item.id, int)
+    SQLModel.metadata.clear()
diff --git a/tests/test_query.py b/tests/test_query.py
new file mode 100644 (file)
index 0000000..abca972
--- /dev/null
@@ -0,0 +1,26 @@
+from typing import Optional
+
+from sqlmodel import Field, Session, SQLModel, create_engine
+
+
+def test_query(clear_sqlmodel):
+    class Hero(SQLModel, table=True):
+        id: Optional[int] = Field(default=None, primary_key=True)
+        name: str
+        secret_name: str
+        age: Optional[int] = None
+
+    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
+
+    engine = create_engine("sqlite://")
+
+    SQLModel.metadata.create_all(engine)
+    with Session(engine) as session:
+        session.add(hero_1)
+        session.commit()
+        session.refresh(hero_1)
+
+    with Session(engine) as session:
+        query_hero = session.query(Hero).first()
+        assert query_hero
+        assert query_hero.name == hero_1.name
diff --git a/tests/test_tutorial/__init__.py b/tests/test_tutorial/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_automatic_id_none_refresh/__init__.py b/tests/test_tutorial/test_automatic_id_none_refresh/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_automatic_id_none_refresh/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_automatic_id_none_refresh/test_tutorial001_tutorial002.py
new file mode 100644 (file)
index 0000000..c91637f
--- /dev/null
@@ -0,0 +1,160 @@
+from tests.conftest import get_testing_print_function
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+
+
+def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]):
+    assert calls[0] == ["Before interacting with the database"]
+    assert calls[1] == [
+        "Hero 1:",
+        {
+            "id": None,
+            "name": "Deadpond",
+            "secret_name": "Dive Wilson",
+            "age": None,
+        },
+    ]
+    assert calls[2] == [
+        "Hero 2:",
+        {
+            "id": None,
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "age": None,
+        },
+    ]
+    assert calls[3] == [
+        "Hero 3:",
+        {
+            "id": None,
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+        },
+    ]
+    assert calls[4] == ["After adding to the session"]
+    assert calls[5] == [
+        "Hero 1:",
+        {
+            "id": None,
+            "name": "Deadpond",
+            "secret_name": "Dive Wilson",
+            "age": None,
+        },
+    ]
+    assert calls[6] == [
+        "Hero 2:",
+        {
+            "id": None,
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "age": None,
+        },
+    ]
+    assert calls[7] == [
+        "Hero 3:",
+        {
+            "id": None,
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+        },
+    ]
+    assert calls[8] == ["After committing the session"]
+    assert calls[9] == ["Hero 1:", {}]
+    assert calls[10] == ["Hero 2:", {}]
+    assert calls[11] == ["Hero 3:", {}]
+    assert calls[12] == ["After committing the session, show IDs"]
+    assert calls[13] == ["Hero 1 ID:", 1]
+    assert calls[14] == ["Hero 2 ID:", 2]
+    assert calls[15] == ["Hero 3 ID:", 3]
+    assert calls[16] == ["After committing the session, show names"]
+    assert calls[17] == ["Hero 1 name:", "Deadpond"]
+    assert calls[18] == ["Hero 2 name:", "Spider-Boy"]
+    assert calls[19] == ["Hero 3 name:", "Rusty-Man"]
+    assert calls[20] == ["After refreshing the heroes"]
+    assert calls[21] == [
+        "Hero 1:",
+        {
+            "id": 1,
+            "name": "Deadpond",
+            "secret_name": "Dive Wilson",
+            "age": None,
+        },
+    ]
+    assert calls[22] == [
+        "Hero 2:",
+        {
+            "id": 2,
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "age": None,
+        },
+    ]
+    assert calls[23] == [
+        "Hero 3:",
+        {
+            "id": 3,
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+        },
+    ]
+    assert calls[24] == ["After the session closes"]
+    assert calls[21] == [
+        "Hero 1:",
+        {
+            "id": 1,
+            "name": "Deadpond",
+            "secret_name": "Dive Wilson",
+            "age": None,
+        },
+    ]
+    assert calls[22] == [
+        "Hero 2:",
+        {
+            "id": 2,
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "age": None,
+        },
+    ]
+    assert calls[23] == [
+        "Hero 3:",
+        {
+            "id": 3,
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+        },
+    ]
+
+
+def test_tutorial_001(clear_sqlmodel):
+    from docs_src.tutorial.automatic_id_none_refresh import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    check_calls(calls)
+
+
+def test_tutorial_002(clear_sqlmodel):
+    from docs_src.tutorial.automatic_id_none_refresh import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    check_calls(calls)
diff --git a/tests/test_tutorial/test_code_structure/__init__.py b/tests/test_tutorial/test_code_structure/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_code_structure/test_tutorial001.py b/tests/test_tutorial/test_code_structure/test_tutorial001.py
new file mode 100644 (file)
index 0000000..ec0990d
--- /dev/null
@@ -0,0 +1,41 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ...conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "id": 1,
+            "name": "Deadpond",
+            "age": None,
+            "secret_name": "Dive Wilson",
+            "team_id": 1,
+        },
+    ],
+    [
+        "Hero's team:",
+        {"name": "Z-Force", "headquarters": "Sister Margaret’s Bar", "id": 1},
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.code_structure.tutorial001 import app, database
+
+    database.sqlite_url = "sqlite://"
+    database.engine = create_engine(database.sqlite_url)
+    app.engine = database.engine
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        app.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_code_structure/test_tutorial002.py b/tests/test_tutorial/test_code_structure/test_tutorial002.py
new file mode 100644 (file)
index 0000000..32bdf83
--- /dev/null
@@ -0,0 +1,41 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ...conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "id": 1,
+            "name": "Deadpond",
+            "age": None,
+            "secret_name": "Dive Wilson",
+            "team_id": 1,
+        },
+    ],
+    [
+        "Hero's team:",
+        {"name": "Z-Force", "headquarters": "Sister Margaret’s Bar", "id": 1},
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.code_structure.tutorial002 import app, database
+
+    database.sqlite_url = "sqlite://"
+    database.engine = create_engine(database.sqlite_url)
+    app.engine = database.engine
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        app.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_connect/__init__.py b/tests/test_tutorial/test_connect/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_connect/test_create_connected_tables/__init__.py b/tests/test_tutorial/test_connect/test_create_connected_tables/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_connect/test_create_connected_tables/test_tutorial001.py b/tests/test_tutorial/test_connect/test_create_connected_tables/test_tutorial001.py
new file mode 100644 (file)
index 0000000..faaaa47
--- /dev/null
@@ -0,0 +1,20 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+
+def test_tutorial001(clear_sqlmodel):
+    from docs_src.tutorial.connect.create_tables import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    mod.main()
+    insp: Inspector = inspect(mod.engine)
+    assert insp.has_table(str(mod.Hero.__tablename__))
+    assert insp.has_table(str(mod.Team.__tablename__))
diff --git a/tests/test_tutorial/test_connect/test_delete/__init__.py b/tests/test_tutorial/test_connect/test_delete/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_connect/test_delete/test_tutorial001.py b/tests/test_tutorial/test_connect/test_delete/test_tutorial001.py
new file mode 100644 (file)
index 0000000..1bd0cb6
--- /dev/null
@@ -0,0 +1,76 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 2,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Updated hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 1,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "No longer Preventer:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.connect.delete import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_connect/test_insert/__init__.py b/tests/test_tutorial/test_connect/test_insert/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_connect/test_insert/test_tutorial001.py b/tests/test_tutorial/test_connect/test_insert/test_tutorial001.py
new file mode 100644 (file)
index 0000000..4496bdc
--- /dev/null
@@ -0,0 +1,56 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 2,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+]
+
+
+def test_tutorial001(clear_sqlmodel):
+    from docs_src.tutorial.connect.insert import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_connect/test_select/__init__.py b/tests/test_tutorial/test_connect/test_select/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_connect/test_select/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_connect/test_select/test_tutorial001_tutorial002.py
new file mode 100644 (file)
index 0000000..af23f93
--- /dev/null
@@ -0,0 +1,94 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 2,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 2,
+            "name": "Deadpond",
+        },
+        "Team:",
+        {"id": 2, "name": "Z-Force", "headquarters": "Sister Margaret’s Bar"},
+    ],
+    [
+        "Hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+        "Team:",
+        {"id": 1, "name": "Preventers", "headquarters": "Sharp Tower"},
+    ],
+]
+
+
+def test_tutorial001(clear_sqlmodel):
+    from docs_src.tutorial.connect.select import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
+
+
+def test_tutorial002(clear_sqlmodel):
+    from docs_src.tutorial.connect.select import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_connect/test_select/test_tutorial003.py b/tests/test_tutorial/test_connect/test_select/test_tutorial003.py
new file mode 100644 (file)
index 0000000..32b61b0
--- /dev/null
@@ -0,0 +1,92 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 2,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 2,
+            "name": "Deadpond",
+        },
+        "Team:",
+        {"id": 2, "name": "Z-Force", "headquarters": "Sister Margaret’s Bar"},
+    ],
+    [
+        "Hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+        "Team:",
+        {"id": 1, "name": "Preventers", "headquarters": "Sharp Tower"},
+    ],
+    [
+        "Hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+        "Team:",
+        None,
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.connect.select import tutorial003 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_connect/test_select/test_tutorial004.py b/tests/test_tutorial/test_connect/test_select/test_tutorial004.py
new file mode 100644 (file)
index 0000000..d796724
--- /dev/null
@@ -0,0 +1,66 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 2,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Preventer Hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.connect.select import tutorial004 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_connect/test_select/test_tutorial005.py b/tests/test_tutorial/test_connect/test_select/test_tutorial005.py
new file mode 100644 (file)
index 0000000..2418232
--- /dev/null
@@ -0,0 +1,68 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 2,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Preventer Hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+        "Team:",
+        {"id": 1, "name": "Preventers", "headquarters": "Sharp Tower"},
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.connect.select import tutorial005 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_connect/test_update/__init__.py b/tests/test_tutorial/test_connect/test_update/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_connect/test_update/test_tutorial001.py b/tests/test_tutorial/test_connect/test_update/test_tutorial001.py
new file mode 100644 (file)
index 0000000..f209a33
--- /dev/null
@@ -0,0 +1,66 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 2,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 1,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Updated hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 1,
+            "name": "Spider-Boy",
+        },
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.connect.update import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_create_db_and_table/__init__.py b/tests/test_tutorial/test_create_db_and_table/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_create_db_and_table/test_tutorial001.py b/tests/test_tutorial/test_create_db_and_table/test_tutorial001.py
new file mode 100644 (file)
index 0000000..591a51c
--- /dev/null
@@ -0,0 +1,18 @@
+from pathlib import Path
+
+from ...conftest import coverage_run
+
+
+def test_create_db_and_table(cov_tmp_path: Path):
+    module = "docs_src.tutorial.create_db_and_table.tutorial001"
+    result = coverage_run(module=module, cwd=cov_tmp_path)
+    assert "BEGIN" in result.stdout
+    assert 'PRAGMA main.table_info("hero")' in result.stdout
+    assert "CREATE TABLE hero (" in result.stdout
+    assert "id INTEGER," in result.stdout
+    assert "name VARCHAR NOT NULL," in result.stdout
+    assert "secret_name VARCHAR NOT NULL," in result.stdout
+    assert "age INTEGER," in result.stdout
+    assert "PRIMARY KEY (id)" in result.stdout
+    assert ")" in result.stdout
+    assert "COMMIT" in result.stdout
diff --git a/tests/test_tutorial/test_create_db_and_table/test_tutorial002.py b/tests/test_tutorial/test_create_db_and_table/test_tutorial002.py
new file mode 100644 (file)
index 0000000..12155f8
--- /dev/null
@@ -0,0 +1,15 @@
+from pathlib import Path
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+
+
+def test_create_db_and_table(clear_sqlmodel):
+    from docs_src.tutorial.create_db_and_table import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    mod.create_db_and_tables()
+    insp: Inspector = inspect(mod.engine)
+    assert insp.has_table(str(mod.Hero.__tablename__))
diff --git a/tests/test_tutorial/test_create_db_and_table/test_tutorial003.py b/tests/test_tutorial/test_create_db_and_table/test_tutorial003.py
new file mode 100644 (file)
index 0000000..e5c55c7
--- /dev/null
@@ -0,0 +1,13 @@
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+
+
+def test_create_db_and_table(clear_sqlmodel):
+    from docs_src.tutorial.create_db_and_table import tutorial003 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    mod.create_db_and_tables()
+    insp: Inspector = inspect(mod.engine)
+    assert insp.has_table(str(mod.Hero.__tablename__))
diff --git a/tests/test_tutorial/test_delete/__init__.py b/tests/test_tutorial/test_delete/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_delete/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_delete/test_tutorial001_tutorial002.py
new file mode 100644 (file)
index 0000000..55750ed
--- /dev/null
@@ -0,0 +1,87 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+expected_calls = [
+    [
+        "Hero 1:",
+        {"id": 2, "name": "Spider-Boy", "secret_name": "Pedro Parqueador", "age": None},
+    ],
+    [
+        "Hero 2:",
+        {
+            "id": 7,
+            "name": "Captain North America",
+            "secret_name": "Esteban Rogelios",
+            "age": 93,
+        },
+    ],
+    [
+        "Updated hero 1:",
+        {
+            "id": 2,
+            "name": "Spider-Youngster",
+            "secret_name": "Pedro Parqueador",
+            "age": 16,
+        },
+    ],
+    [
+        "Updated hero 2:",
+        {
+            "id": 7,
+            "name": "Captain North America Except Canada",
+            "secret_name": "Esteban Rogelios",
+            "age": 110,
+        },
+    ],
+    [
+        "Hero: ",
+        {
+            "id": 2,
+            "name": "Spider-Youngster",
+            "secret_name": "Pedro Parqueador",
+            "age": 16,
+        },
+    ],
+    [
+        "Deleted hero:",
+        {
+            "id": 2,
+            "name": "Spider-Youngster",
+            "secret_name": "Pedro Parqueador",
+            "age": 16,
+        },
+    ],
+    ["There's no hero named Spider-Youngster"],
+]
+
+
+def test_tutorial001(clear_sqlmodel):
+    from docs_src.tutorial.delete import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
+
+
+def test_tutorial002(clear_sqlmodel):
+    from docs_src.tutorial.delete import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_fastapi/__init__.py b/tests/test_tutorial/test_fastapi/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_app_testing/__init__.py b/tests/test_tutorial/test_fastapi/test_app_testing/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests001.py b/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests001.py
new file mode 100644 (file)
index 0000000..ac2c713
--- /dev/null
@@ -0,0 +1,24 @@
+import importlib
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import test_main_001 as test_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import main as app_mod
+
+import pytest
+
+@pytest.fixture(name="prepare", autouse=True)
+def prepare_fixture(clear_sqlmodel):
+    # Trigger side effects of registering table models in SQLModel
+    # This has to be called after clear_sqlmodel
+    importlib.reload(app_mod)
+    importlib.reload(test_mod)
+
+def test_tutorial():
+    test_mod.test_create_hero()
diff --git a/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests002.py b/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests002.py
new file mode 100644 (file)
index 0000000..ac5c16f
--- /dev/null
@@ -0,0 +1,24 @@
+import importlib
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import test_main_002 as test_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import main as app_mod
+
+import pytest
+
+@pytest.fixture(name="prepare", autouse=True)
+def prepare_fixture(clear_sqlmodel):
+    # Trigger side effects of registering table models in SQLModel
+    # This has to be called after clear_sqlmodel
+    importlib.reload(app_mod)
+    importlib.reload(test_mod)
+
+def test_tutorial():
+    test_mod.test_create_hero()
diff --git a/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests003.py b/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests003.py
new file mode 100644 (file)
index 0000000..3f6863a
--- /dev/null
@@ -0,0 +1,24 @@
+import importlib
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import test_main_003 as test_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import main as app_mod
+
+import pytest
+
+@pytest.fixture(name="prepare", autouse=True)
+def prepare_fixture(clear_sqlmodel):
+    # Trigger side effects of registering table models in SQLModel
+    # This has to be called after clear_sqlmodel
+    importlib.reload(app_mod)
+    importlib.reload(test_mod)
+
+def test_tutorial():
+    test_mod.test_create_hero()
diff --git a/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests004.py b/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests004.py
new file mode 100644 (file)
index 0000000..c5c31e0
--- /dev/null
@@ -0,0 +1,24 @@
+import importlib
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import test_main_004 as test_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import main as app_mod
+
+import pytest
+
+@pytest.fixture(name="prepare", autouse=True)
+def prepare_fixture(clear_sqlmodel):
+    # Trigger side effects of registering table models in SQLModel
+    # This has to be called after clear_sqlmodel
+    importlib.reload(app_mod)
+    importlib.reload(test_mod)
+
+def test_tutorial():
+    test_mod.test_create_hero()
diff --git a/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests005.py b/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests005.py
new file mode 100644 (file)
index 0000000..3cb360a
--- /dev/null
@@ -0,0 +1,31 @@
+import importlib
+from contextlib import contextmanager
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+import pytest
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import main as app_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import test_main_005 as test_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001.test_main_005 import (
+    session_fixture,
+)
+from fastapi.testclient import TestClient
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import Session, create_engine
+from sqlmodel.pool import StaticPool
+
+
+assert session_fixture, "This keeps the session fixture used below"
+
+
+@pytest.fixture(name="prepare")
+def prepare_fixture(clear_sqlmodel):
+    # Trigger side effects of registering table models in SQLModel
+    # This has to be called after clear_sqlmodel, but before the session_fixture
+    # That's why the extra custom fixture here
+    importlib.reload(app_mod)
+
+
+def test_tutorial(prepare, session: Session):
+    test_mod.test_create_hero(session)
diff --git a/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests006.py b/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests006.py
new file mode 100644 (file)
index 0000000..bf69aae
--- /dev/null
@@ -0,0 +1,34 @@
+import importlib
+from contextlib import contextmanager
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+import pytest
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import main as app_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import test_main_006 as test_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001.test_main_006 import (
+    session_fixture,
+    client_fixture
+)
+from fastapi.testclient import TestClient
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import Session, create_engine
+from sqlmodel.pool import StaticPool
+
+
+assert session_fixture, "This keeps the session fixture used below"
+assert client_fixture, "This keeps the client fixture used below"
+
+
+@pytest.fixture(name="prepare")
+def prepare_fixture(clear_sqlmodel):
+    # Trigger side effects of registering table models in SQLModel
+    # This has to be called after clear_sqlmodel, but before the session_fixture
+    # That's why the extra custom fixture here
+    importlib.reload(app_mod)
+
+
+def test_tutorial(prepare, session: Session, client: TestClient):
+    test_mod.test_create_hero(client)
+    
\ No newline at end of file
diff --git a/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests_main.py b/tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests_main.py
new file mode 100644 (file)
index 0000000..dec5e2e
--- /dev/null
@@ -0,0 +1,87 @@
+import importlib
+from contextlib import contextmanager
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+import pytest
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import main as app_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001 import test_main as test_mod
+from docs_src.tutorial.fastapi.app_testing.tutorial001.test_main import (
+    session_fixture,
+    client_fixture,
+)
+from fastapi.testclient import TestClient
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import Session, create_engine
+from sqlmodel.pool import StaticPool
+
+
+assert session_fixture, "This keeps the session fixture used below"
+assert client_fixture, "This keeps the client fixture used below"
+
+
+@pytest.fixture(name="prepare", autouse=True)
+def prepare_fixture(clear_sqlmodel):
+    # Trigger side effects of registering table models in SQLModel
+    # This has to be called after clear_sqlmodel, but before the session_fixture
+    # That's why the extra custom fixture here
+    importlib.reload(app_mod)
+    importlib.reload(test_mod)
+
+
+def test_create_hero(session: Session, client: TestClient):
+    test_mod.test_create_hero(client)
+
+
+def test_create_hero_incomplete(session: Session, client: TestClient):
+    test_mod.test_create_hero_incomplete(client)
+
+
+def test_create_hero_invalid(session: Session, client: TestClient):
+    test_mod.test_create_hero_invalid(client)
+
+
+def test_read_heroes(session: Session, client: TestClient):
+    test_mod.test_read_heroes(session=session, client=client)
+
+
+def test_read_hero(session: Session, client: TestClient):
+    test_mod.test_read_hero(session=session, client=client)
+
+
+def test_update_hero(session: Session, client: TestClient):
+    test_mod.test_update_hero(session=session, client=client)
+
+
+def test_delete_hero(session: Session, client: TestClient):
+    test_mod.test_delete_hero(session=session, client=client)
+
+
+def test_startup():
+    app_mod.engine = create_engine("sqlite://")
+    app_mod.on_startup()
+    insp: Inspector = inspect(app_mod.engine)
+    assert insp.has_table(str(app_mod.Hero.__tablename__))
+
+
+def test_get_session():
+    app_mod.engine = create_engine("sqlite://")
+    for session in app_mod.get_session():
+        assert isinstance(session, Session)
+        assert session.bind == app_mod.engine
+
+
+def test_read_hero_not_found(client: TestClient):
+    response = client.get("/heroes/9000")
+    assert response.status_code == 404
+
+
+def test_update_hero_not_found(client: TestClient):
+    response = client.patch("/heroes/9000", json={"name": "Very-Rusty-Man"})
+    assert response.status_code == 404
+
+
+def test_delete_hero_not_found(client: TestClient):
+    response = client.delete("/heroes/9000")
+    assert response.status_code == 404
diff --git a/tests/test_tutorial/test_fastapi/test_delete/__init__.py b/tests/test_tutorial/test_fastapi/test_delete/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py
new file mode 100644 (file)
index 0000000..4cdf7e8
--- /dev/null
@@ -0,0 +1,317 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "parameters": [
+                    {
+                        "required": False,
+                        "schema": {"title": "Offset", "type": "integer", "default": 0},
+                        "name": "offset",
+                        "in": "query",
+                    },
+                    {
+                        "required": False,
+                        "schema": {
+                            "title": "Limit",
+                            "type": "integer",
+                            "default": 100,
+                            "lte": 100,
+                        },
+                        "name": "limit",
+                        "in": "query",
+                    },
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/HeroRead"},
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/heroes/{hero_id}": {
+            "get": {
+                "summary": "Read Hero",
+                "operationId": "read_hero_heroes__hero_id__get",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "delete": {
+                "summary": "Delete Hero",
+                "operationId": "delete_hero_heroes__hero_id__delete",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "patch": {
+                "summary": "Update Hero",
+                "operationId": "update_hero_heroes__hero_id__patch",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroUpdate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "HeroCreate": {
+                "title": "HeroCreate",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "HeroRead": {
+                "title": "HeroRead",
+                "required": ["name", "secret_name", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "HeroUpdate": {
+                "title": "HeroUpdate",
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.delete import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        hero3_data = {
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+        }
+        response = client.post("/heroes/", json=hero1_data)
+        assert response.status_code == 200, response.text
+        response = client.post("/heroes/", json=hero2_data)
+        assert response.status_code == 200, response.text
+        hero2 = response.json()
+        hero2_id = hero2["id"]
+        response = client.post("/heroes/", json=hero3_data)
+        assert response.status_code == 200, response.text
+        response = client.get(f"/heroes/{hero2_id}")
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/9000")
+        assert response.status_code == 404, response.text
+        response = client.get("/openapi.json")
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data == openapi_schema
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 3
+        response = client.patch(
+            f"/heroes/{hero2_id}", json={"secret_name": "Spider-Youngster"}
+        )
+        assert response.status_code == 200, response.text
+        response = client.patch("/heroes/9001", json={"name": "Dragon Cube X"})
+        assert response.status_code == 404, response.text
+
+        response = client.delete(f"/heroes/{hero2_id}")
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 2
+
+        response = client.delete("/heroes/9000")
+        assert response.status_code == 404, response.text
diff --git a/tests/test_tutorial/test_fastapi/test_limit_and_offset/__init__.py b/tests/test_tutorial/test_fastapi/test_limit_and_offset/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py
new file mode 100644 (file)
index 0000000..867456b
--- /dev/null
@@ -0,0 +1,245 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "parameters": [
+                    {
+                        "required": False,
+                        "schema": {"title": "Offset", "type": "integer", "default": 0},
+                        "name": "offset",
+                        "in": "query",
+                    },
+                    {
+                        "required": False,
+                        "schema": {
+                            "title": "Limit",
+                            "type": "integer",
+                            "default": 100,
+                            "lte": 100,
+                        },
+                        "name": "limit",
+                        "in": "query",
+                    },
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/HeroRead"},
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/heroes/{hero_id}": {
+            "get": {
+                "summary": "Read Hero",
+                "operationId": "read_hero_heroes__hero_id__get",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            }
+        },
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "HeroCreate": {
+                "title": "HeroCreate",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "HeroRead": {
+                "title": "HeroRead",
+                "required": ["name", "secret_name", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.limit_and_offset import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        hero3_data = {
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+        }
+        response = client.post("/heroes/", json=hero1_data)
+        assert response.status_code == 200, response.text
+        response = client.post("/heroes/", json=hero2_data)
+        assert response.status_code == 200, response.text
+        hero2 = response.json()
+        hero_id = hero2["id"]
+        response = client.post("/heroes/", json=hero3_data)
+        assert response.status_code == 200, response.text
+        response = client.get(f"/heroes/{hero_id}")
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/9000")
+        assert response.status_code == 404, response.text
+        response = client.get("/openapi.json")
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data == openapi_schema
+
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 3
+
+        response = client.get("/heroes/", params={"limit": 2})
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 2
+        assert data[0]["name"] == hero1_data["name"]
+        assert data[1]["name"] == hero2_data["name"]
+
+        response = client.get("/heroes/", params={"offset": 1})
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 2
+        assert data[0]["name"] == hero2_data["name"]
+        assert data[1]["name"] == hero3_data["name"]
+
+        response = client.get("/heroes/", params={"offset": 1, "limit": 1})
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 1
+        assert data[0]["name"] == hero2_data["name"]
diff --git a/tests/test_tutorial/test_fastapi/test_multiple_models/__init__.py b/tests/test_tutorial/test_fastapi/test_multiple_models/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py
new file mode 100644 (file)
index 0000000..06570b7
--- /dev/null
@@ -0,0 +1,174 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/HeroRead"},
+                                }
+                            }
+                        },
+                    }
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        }
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "HeroCreate": {
+                "title": "HeroCreate",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "HeroRead": {
+                "title": "HeroRead",
+                "required": ["id", "name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "id": {"title": "Id", "type": "integer"},
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.multiple_models import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        response = client.post("/heroes/", json=hero1_data)
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert data["name"] == hero1_data["name"]
+        assert data["secret_name"] == hero1_data["secret_name"]
+        assert data["id"] is not None
+        assert data["age"] is None
+
+        response = client.post("/heroes/", json=hero2_data)
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert data["name"] == hero2_data["name"]
+        assert data["secret_name"] == hero2_data["secret_name"]
+        assert data["id"] != hero2_data["id"], (
+            "Now it's not possible to predefine the ID from the request, "
+            "it's now set by the database"
+        )
+        assert data["age"] is None
+
+        response = client.get("/heroes/")
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert len(data) == 2
+        assert data[0]["name"] == hero1_data["name"]
+        assert data[0]["secret_name"] == hero1_data["secret_name"]
+        assert data[1]["name"] == hero2_data["name"]
+        assert data[1]["secret_name"] == hero2_data["secret_name"]
+        assert data[1]["id"] != hero2_data["id"]
+
+        response = client.get("/openapi.json")
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+
+        assert data == openapi_schema
diff --git a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py
new file mode 100644 (file)
index 0000000..f12f6a7
--- /dev/null
@@ -0,0 +1,174 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/HeroRead"},
+                                }
+                            }
+                        },
+                    }
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        }
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "HeroCreate": {
+                "title": "HeroCreate",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "HeroRead": {
+                "title": "HeroRead",
+                "required": ["name", "secret_name", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.multiple_models import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        response = client.post("/heroes/", json=hero1_data)
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert data["name"] == hero1_data["name"]
+        assert data["secret_name"] == hero1_data["secret_name"]
+        assert data["id"] is not None
+        assert data["age"] is None
+
+        response = client.post("/heroes/", json=hero2_data)
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert data["name"] == hero2_data["name"]
+        assert data["secret_name"] == hero2_data["secret_name"]
+        assert data["id"] != hero2_data["id"], (
+            "Now it's not possible to predefine the ID from the request, "
+            "it's now set by the database"
+        )
+        assert data["age"] is None
+
+        response = client.get("/heroes/")
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert len(data) == 2
+        assert data[0]["name"] == hero1_data["name"]
+        assert data[0]["secret_name"] == hero1_data["secret_name"]
+        assert data[1]["name"] == hero2_data["name"]
+        assert data[1]["secret_name"] == hero2_data["secret_name"]
+        assert data[1]["id"] != hero2_data["id"]
+
+        response = client.get("/openapi.json")
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+
+        assert data == openapi_schema
diff --git a/tests/test_tutorial/test_fastapi/test_read_one/__init__.py b/tests/test_tutorial/test_fastapi/test_read_one/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py
new file mode 100644 (file)
index 0000000..0a4574d
--- /dev/null
@@ -0,0 +1,195 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/HeroRead"},
+                                }
+                            }
+                        },
+                    }
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/heroes/{hero_id}": {
+            "get": {
+                "summary": "Read Hero",
+                "operationId": "read_hero_heroes__hero_id__get",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            }
+        },
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "HeroCreate": {
+                "title": "HeroCreate",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "HeroRead": {
+                "title": "HeroRead",
+                "required": ["name", "secret_name", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.read_one import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        response = client.post("/heroes/", json=hero1_data)
+        assert response.status_code == 200, response.text
+        response = client.post("/heroes/", json=hero2_data)
+        assert response.status_code == 200, response.text
+        hero2 = response.json()
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 2
+
+        hero_id = hero2["id"]
+        response = client.get(f"/heroes/{hero_id}")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert data == hero2
+
+        response = client.get("/heroes/9000")
+        assert response.status_code == 404, response.text
+
+        response = client.get("/openapi.json")
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+
+        assert data == openapi_schema
diff --git a/tests/test_tutorial/test_fastapi/test_relationships/__init__.py b/tests/test_tutorial/test_fastapi/test_relationships/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py
new file mode 100644 (file)
index 0000000..1fceb7c
--- /dev/null
@@ -0,0 +1,612 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "parameters": [
+                    {
+                        "required": False,
+                        "schema": {"title": "Offset", "type": "integer", "default": 0},
+                        "name": "offset",
+                        "in": "query",
+                    },
+                    {
+                        "required": False,
+                        "schema": {
+                            "title": "Limit",
+                            "type": "integer",
+                            "default": 100,
+                            "lte": 100,
+                        },
+                        "name": "limit",
+                        "in": "query",
+                    },
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/HeroRead"},
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/heroes/{hero_id}": {
+            "get": {
+                "summary": "Read Hero",
+                "operationId": "read_hero_heroes__hero_id__get",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HeroReadWithTeam"
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "delete": {
+                "summary": "Delete Hero",
+                "operationId": "delete_hero_heroes__hero_id__delete",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "patch": {
+                "summary": "Update Hero",
+                "operationId": "update_hero_heroes__hero_id__patch",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroUpdate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/teams/": {
+            "get": {
+                "summary": "Read Teams",
+                "operationId": "read_teams_teams__get",
+                "parameters": [
+                    {
+                        "required": False,
+                        "schema": {"title": "Offset", "type": "integer", "default": 0},
+                        "name": "offset",
+                        "in": "query",
+                    },
+                    {
+                        "required": False,
+                        "schema": {
+                            "title": "Limit",
+                            "type": "integer",
+                            "default": 100,
+                            "lte": 100,
+                        },
+                        "name": "limit",
+                        "in": "query",
+                    },
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Teams Teams  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/TeamRead"},
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "post": {
+                "summary": "Create Team",
+                "operationId": "create_team_teams__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/TeamCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/TeamRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/teams/{team_id}": {
+            "get": {
+                "summary": "Read Team",
+                "operationId": "read_team_teams__team_id__get",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Team Id", "type": "integer"},
+                        "name": "team_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/TeamReadWithHeroes"
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "delete": {
+                "summary": "Delete Team",
+                "operationId": "delete_team_teams__team_id__delete",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Team Id", "type": "integer"},
+                        "name": "team_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "patch": {
+                "summary": "Update Team",
+                "operationId": "update_team_teams__team_id__patch",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Team Id", "type": "integer"},
+                        "name": "team_id",
+                        "in": "path",
+                    }
+                ],
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/TeamUpdate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/TeamRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "HeroCreate": {
+                "title": "HeroCreate",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "team_id": {"title": "Team Id", "type": "integer"},
+                },
+            },
+            "HeroRead": {
+                "title": "HeroRead",
+                "required": ["name", "secret_name", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "team_id": {"title": "Team Id", "type": "integer"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "HeroReadWithTeam": {
+                "title": "HeroReadWithTeam",
+                "required": ["name", "secret_name", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "team_id": {"title": "Team Id", "type": "integer"},
+                    "id": {"title": "Id", "type": "integer"},
+                    "team": {"$ref": "#/components/schemas/TeamRead"},
+                },
+            },
+            "HeroUpdate": {
+                "title": "HeroUpdate",
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "team_id": {"title": "Team Id", "type": "integer"},
+                },
+            },
+            "TeamCreate": {
+                "title": "TeamCreate",
+                "required": ["name", "headquarters"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "headquarters": {"title": "Headquarters", "type": "string"},
+                },
+            },
+            "TeamRead": {
+                "title": "TeamRead",
+                "required": ["name", "headquarters", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "headquarters": {"title": "Headquarters", "type": "string"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "TeamReadWithHeroes": {
+                "title": "TeamReadWithHeroes",
+                "required": ["name", "headquarters", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "headquarters": {"title": "Headquarters", "type": "string"},
+                    "id": {"title": "Id", "type": "integer"},
+                    "heroes": {
+                        "title": "Heroes",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/HeroRead"},
+                        "default": [],
+                    },
+                },
+            },
+            "TeamUpdate": {
+                "title": "TeamUpdate",
+                "type": "object",
+                "properties": {
+                    "id": {"title": "Id", "type": "integer"},
+                    "name": {"title": "Name", "type": "string"},
+                    "headquarters": {"title": "Headquarters", "type": "string"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.relationships import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+        response = client.get("/openapi.json")
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data == openapi_schema
+
+        team_preventers = {"name": "Preventers", "headquarters": "Sharp Tower"}
+        team_z_force = {"name": "Z-Force", "headquarters": "Sister Margaret’s Bar"}
+        response = client.post("/teams/", json=team_preventers)
+        assert response.status_code == 200, response.text
+        team_preventers_data = response.json()
+        team_preventers_id = team_preventers_data["id"]
+        response = client.post("/teams/", json=team_z_force)
+        assert response.status_code == 200, response.text
+        team_z_force_data = response.json()
+        team_z_force_id = team_z_force_data["id"]
+        response = client.get("/teams/")
+        data = response.json()
+        assert len(data) == 2
+        response = client.get("/teams/9000")
+        assert response.status_code == 404, response.text
+        response = client.patch(
+            f"/teams/{team_preventers_id}", json={"headquarters": "Preventers Tower"}
+        )
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data["name"] == team_preventers["name"]
+        assert data["headquarters"] == "Preventers Tower"
+        response = client.patch("/teams/9000", json={"name": "Freedom League"})
+        assert response.status_code == 404, response.text
+
+        hero1_data = {
+            "name": "Deadpond",
+            "secret_name": "Dive Wilson",
+            "team_id": team_z_force_id,
+        }
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        hero3_data = {
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+            "team_id": team_preventers_id,
+        }
+        response = client.post("/heroes/", json=hero1_data)
+        assert response.status_code == 200, response.text
+        hero1 = response.json()
+        hero1_id = hero1["id"]
+        response = client.post("/heroes/", json=hero2_data)
+        assert response.status_code == 200, response.text
+        hero2 = response.json()
+        hero2_id = hero2["id"]
+        response = client.post("/heroes/", json=hero3_data)
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/9000")
+        assert response.status_code == 404, response.text
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 3
+        response = client.get(f"/heroes/{hero1_id}")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert data["name"] == hero1_data["name"]
+        assert data["team"]["name"] == team_z_force["name"]
+        response = client.patch(
+            f"/heroes/{hero2_id}", json={"secret_name": "Spider-Youngster"}
+        )
+        assert response.status_code == 200, response.text
+        response = client.patch("/heroes/9001", json={"name": "Dragon Cube X"})
+        assert response.status_code == 404, response.text
+        response = client.delete(f"/heroes/{hero2_id}")
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 2
+        response = client.delete("/heroes/9000")
+        assert response.status_code == 404, response.text
+
+        response = client.get(f"/teams/{team_preventers_id}")
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data["name"] == team_preventers_data["name"]
+        assert data["heroes"][0]["name"] == hero3_data["name"]
+
+        response = client.delete(f"/teams/{team_preventers_id}")
+        assert response.status_code == 200, response.text
+        response = client.delete("/teams/9000")
+        assert response.status_code == 404, response.text
+        response = client.get("/teams/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 1
diff --git a/tests/test_tutorial/test_fastapi/test_response_model/__init__.py b/tests/test_tutorial/test_fastapi/test_response_model/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py
new file mode 100644 (file)
index 0000000..b60f816
--- /dev/null
@@ -0,0 +1,144 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/Hero"},
+                                }
+                            }
+                        },
+                    }
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/Hero"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/Hero"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        }
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "Hero": {
+                "title": "Hero",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "id": {"title": "Id", "type": "integer"},
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.response_model import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        response = client.post("/heroes/", json=hero_data)
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert data["name"] == hero_data["name"]
+        assert data["secret_name"] == hero_data["secret_name"]
+        assert data["id"] is not None
+        assert data["age"] is None
+
+        response = client.get("/heroes/")
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert len(data) == 1
+        assert data[0]["name"] == hero_data["name"]
+        assert data[0]["secret_name"] == hero_data["secret_name"]
+
+        response = client.get("/openapi.json")
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+
+        assert data == openapi_schema
diff --git a/tests/test_tutorial/test_fastapi/test_session_with_dependency/__init__.py b/tests/test_tutorial/test_fastapi/test_session_with_dependency/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py
new file mode 100644 (file)
index 0000000..3573d4f
--- /dev/null
@@ -0,0 +1,317 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "parameters": [
+                    {
+                        "required": False,
+                        "schema": {"title": "Offset", "type": "integer", "default": 0},
+                        "name": "offset",
+                        "in": "query",
+                    },
+                    {
+                        "required": False,
+                        "schema": {
+                            "title": "Limit",
+                            "type": "integer",
+                            "default": 100,
+                            "lte": 100,
+                        },
+                        "name": "limit",
+                        "in": "query",
+                    },
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/HeroRead"},
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/heroes/{hero_id}": {
+            "get": {
+                "summary": "Read Hero",
+                "operationId": "read_hero_heroes__hero_id__get",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "delete": {
+                "summary": "Delete Hero",
+                "operationId": "delete_hero_heroes__hero_id__delete",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "patch": {
+                "summary": "Update Hero",
+                "operationId": "update_hero_heroes__hero_id__patch",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroUpdate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "HeroCreate": {
+                "title": "HeroCreate",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "HeroRead": {
+                "title": "HeroRead",
+                "required": ["name", "secret_name", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "HeroUpdate": {
+                "title": "HeroUpdate",
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.session_with_dependency import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        hero3_data = {
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+        }
+        response = client.post("/heroes/", json=hero1_data)
+        assert response.status_code == 200, response.text
+        response = client.post("/heroes/", json=hero2_data)
+        assert response.status_code == 200, response.text
+        hero2 = response.json()
+        hero2_id = hero2["id"]
+        response = client.post("/heroes/", json=hero3_data)
+        assert response.status_code == 200, response.text
+        response = client.get(f"/heroes/{hero2_id}")
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/9000")
+        assert response.status_code == 404, response.text
+        response = client.get("/openapi.json")
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data == openapi_schema
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 3
+        response = client.patch(
+            f"/heroes/{hero2_id}", json={"secret_name": "Spider-Youngster"}
+        )
+        assert response.status_code == 200, response.text
+        response = client.patch("/heroes/9001", json={"name": "Dragon Cube X"})
+        assert response.status_code == 404, response.text
+
+        response = client.delete(f"/heroes/{hero2_id}")
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 2
+
+        response = client.delete("/heroes/9000")
+        assert response.status_code == 404, response.text
diff --git a/tests/test_tutorial/test_fastapi/test_simple_hero_api/__init__.py b/tests/test_tutorial/test_fastapi/test_simple_hero_api/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py
new file mode 100644 (file)
index 0000000..02160f5
--- /dev/null
@@ -0,0 +1,152 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    }
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/Hero"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        }
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "Hero": {
+                "title": "Hero",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "id": {"title": "Id", "type": "integer"},
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.simple_hero_api import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        response = client.post("/heroes/", json=hero1_data)
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert data["name"] == hero1_data["name"]
+        assert data["secret_name"] == hero1_data["secret_name"]
+        assert data["id"] is not None
+        assert data["age"] is None
+
+        response = client.post("/heroes/", json=hero2_data)
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert data["name"] == hero2_data["name"]
+        assert data["secret_name"] == hero2_data["secret_name"]
+        assert data["id"] == hero2_data["id"], (
+            "Up to this point it's still possible to "
+            "set the ID of the hero in the request"
+        )
+        assert data["age"] is None
+
+        response = client.get("/heroes/")
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+        assert len(data) == 2
+        assert data[0]["name"] == hero1_data["name"]
+        assert data[0]["secret_name"] == hero1_data["secret_name"]
+        assert data[1]["name"] == hero2_data["name"]
+        assert data[1]["secret_name"] == hero2_data["secret_name"]
+        assert data[1]["id"] == hero2_data["id"]
+
+        response = client.get("/openapi.json")
+        data = response.json()
+
+        assert response.status_code == 200, response.text
+
+        assert data == openapi_schema
diff --git a/tests/test_tutorial/test_fastapi/test_teams/__init__.py b/tests/test_tutorial/test_fastapi/test_teams/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py
new file mode 100644 (file)
index 0000000..76e3c0d
--- /dev/null
@@ -0,0 +1,566 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "parameters": [
+                    {
+                        "required": False,
+                        "schema": {"title": "Offset", "type": "integer", "default": 0},
+                        "name": "offset",
+                        "in": "query",
+                    },
+                    {
+                        "required": False,
+                        "schema": {
+                            "title": "Limit",
+                            "type": "integer",
+                            "default": 100,
+                            "lte": 100,
+                        },
+                        "name": "limit",
+                        "in": "query",
+                    },
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/HeroRead"},
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/heroes/{hero_id}": {
+            "get": {
+                "summary": "Read Hero",
+                "operationId": "read_hero_heroes__hero_id__get",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "delete": {
+                "summary": "Delete Hero",
+                "operationId": "delete_hero_heroes__hero_id__delete",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "patch": {
+                "summary": "Update Hero",
+                "operationId": "update_hero_heroes__hero_id__patch",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroUpdate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/teams/": {
+            "get": {
+                "summary": "Read Teams",
+                "operationId": "read_teams_teams__get",
+                "parameters": [
+                    {
+                        "required": False,
+                        "schema": {"title": "Offset", "type": "integer", "default": 0},
+                        "name": "offset",
+                        "in": "query",
+                    },
+                    {
+                        "required": False,
+                        "schema": {
+                            "title": "Limit",
+                            "type": "integer",
+                            "default": 100,
+                            "lte": 100,
+                        },
+                        "name": "limit",
+                        "in": "query",
+                    },
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Teams Teams  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/TeamRead"},
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "post": {
+                "summary": "Create Team",
+                "operationId": "create_team_teams__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/TeamCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/TeamRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/teams/{team_id}": {
+            "get": {
+                "summary": "Read Team",
+                "operationId": "read_team_teams__team_id__get",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Team Id", "type": "integer"},
+                        "name": "team_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/TeamRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "delete": {
+                "summary": "Delete Team",
+                "operationId": "delete_team_teams__team_id__delete",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Team Id", "type": "integer"},
+                        "name": "team_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "patch": {
+                "summary": "Update Team",
+                "operationId": "update_team_teams__team_id__patch",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Team Id", "type": "integer"},
+                        "name": "team_id",
+                        "in": "path",
+                    }
+                ],
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/TeamUpdate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/TeamRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "HeroCreate": {
+                "title": "HeroCreate",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "team_id": {"title": "Team Id", "type": "integer"},
+                },
+            },
+            "HeroRead": {
+                "title": "HeroRead",
+                "required": ["name", "secret_name", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "team_id": {"title": "Team Id", "type": "integer"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "HeroUpdate": {
+                "title": "HeroUpdate",
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "team_id": {"title": "Team Id", "type": "integer"},
+                },
+            },
+            "TeamCreate": {
+                "title": "TeamCreate",
+                "required": ["name", "headquarters"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "headquarters": {"title": "Headquarters", "type": "string"},
+                },
+            },
+            "TeamRead": {
+                "title": "TeamRead",
+                "required": ["name", "headquarters", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "headquarters": {"title": "Headquarters", "type": "string"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "TeamUpdate": {
+                "title": "TeamUpdate",
+                "type": "object",
+                "properties": {
+                    "id": {"title": "Id", "type": "integer"},
+                    "name": {"title": "Name", "type": "string"},
+                    "headquarters": {"title": "Headquarters", "type": "string"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.teams import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        hero3_data = {
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+        }
+        response = client.get("/openapi.json")
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data == openapi_schema
+        response = client.post("/heroes/", json=hero1_data)
+        assert response.status_code == 200, response.text
+        response = client.post("/heroes/", json=hero2_data)
+        assert response.status_code == 200, response.text
+        hero2 = response.json()
+        hero2_id = hero2["id"]
+        response = client.post("/heroes/", json=hero3_data)
+        assert response.status_code == 200, response.text
+        response = client.get(f"/heroes/{hero2_id}")
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/9000")
+        assert response.status_code == 404, response.text
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 3
+        response = client.patch(
+            f"/heroes/{hero2_id}", json={"secret_name": "Spider-Youngster"}
+        )
+        assert response.status_code == 200, response.text
+        response = client.patch("/heroes/9001", json={"name": "Dragon Cube X"})
+        assert response.status_code == 404, response.text
+        response = client.delete(f"/heroes/{hero2_id}")
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 2
+        response = client.delete("/heroes/9000")
+        assert response.status_code == 404, response.text
+
+        team_preventers = {"name": "Preventers", "headquarters": "Sharp Tower"}
+        team_z_force = {"name": "Z-Force", "headquarters": "Sister Margaret’s Bar"}
+        response = client.post("/teams/", json=team_preventers)
+        assert response.status_code == 200, response.text
+        team_preventers_data = response.json()
+        team_preventers_id = team_preventers_data["id"]
+        response = client.post("/teams/", json=team_z_force)
+        assert response.status_code == 200, response.text
+        team_z_force_data = response.json()
+        team_z_force_id = team_z_force_data["id"]
+        response = client.get("/teams/")
+        data = response.json()
+        assert len(data) == 2
+        response = client.get(f"/teams/{team_preventers_id}")
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data == team_preventers_data
+        response = client.get("/teams/9000")
+        assert response.status_code == 404, response.text
+        response = client.patch(
+            f"/teams/{team_preventers_id}", json={"headquarters": "Preventers Tower"}
+        )
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data["name"] == team_preventers["name"]
+        assert data["headquarters"] == "Preventers Tower"
+        response = client.patch("/teams/9000", json={"name": "Freedom League"})
+        assert response.status_code == 404, response.text
+        response = client.delete(f"/teams/{team_preventers_id}")
+        assert response.status_code == 200, response.text
+        response = client.delete("/teams/9000")
+        assert response.status_code == 404, response.text
+        response = client.get("/teams/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 1
diff --git a/tests/test_tutorial/test_fastapi/test_update/__init__.py b/tests/test_tutorial/test_fastapi/test_update/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py
new file mode 100644 (file)
index 0000000..9fd6ed5
--- /dev/null
@@ -0,0 +1,296 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from fastapi.testclient import TestClient
+from sqlmodel.pool import StaticPool
+
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/heroes/": {
+            "get": {
+                "summary": "Read Heroes",
+                "operationId": "read_heroes_heroes__get",
+                "parameters": [
+                    {
+                        "required": False,
+                        "schema": {"title": "Offset", "type": "integer", "default": 0},
+                        "name": "offset",
+                        "in": "query",
+                    },
+                    {
+                        "required": False,
+                        "schema": {
+                            "title": "Limit",
+                            "type": "integer",
+                            "default": 100,
+                            "lte": 100,
+                        },
+                        "name": "limit",
+                        "in": "query",
+                    },
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "title": "Response Read Heroes Heroes  Get",
+                                    "type": "array",
+                                    "items": {"$ref": "#/components/schemas/HeroRead"},
+                                }
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "post": {
+                "summary": "Create Hero",
+                "operationId": "create_hero_heroes__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroCreate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+        "/heroes/{hero_id}": {
+            "get": {
+                "summary": "Read Hero",
+                "operationId": "read_hero_heroes__hero_id__get",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+            "patch": {
+                "summary": "Update Hero",
+                "operationId": "update_hero_heroes__hero_id__patch",
+                "parameters": [
+                    {
+                        "required": True,
+                        "schema": {"title": "Hero Id", "type": "integer"},
+                        "name": "hero_id",
+                        "in": "path",
+                    }
+                ],
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {"$ref": "#/components/schemas/HeroUpdate"}
+                        }
+                    },
+                    "required": True,
+                },
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {
+                            "application/json": {
+                                "schema": {"$ref": "#/components/schemas/HeroRead"}
+                            }
+                        },
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+            },
+        },
+    },
+    "components": {
+        "schemas": {
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+            "HeroCreate": {
+                "title": "HeroCreate",
+                "required": ["name", "secret_name"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "HeroRead": {
+                "title": "HeroRead",
+                "required": ["name", "secret_name", "id"],
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                    "id": {"title": "Id", "type": "integer"},
+                },
+            },
+            "HeroUpdate": {
+                "title": "HeroUpdate",
+                "type": "object",
+                "properties": {
+                    "name": {"title": "Name", "type": "string"},
+                    "secret_name": {"title": "Secret Name", "type": "string"},
+                    "age": {"title": "Age", "type": "integer"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+        }
+    },
+}
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.fastapi.update import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(
+        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
+    )
+
+    with TestClient(mod.app) as client:
+
+        hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
+        hero2_data = {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "id": 9000,
+        }
+        hero3_data = {
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+        }
+        response = client.post("/heroes/", json=hero1_data)
+        assert response.status_code == 200, response.text
+        response = client.post("/heroes/", json=hero2_data)
+        assert response.status_code == 200, response.text
+        hero2 = response.json()
+        hero2_id = hero2["id"]
+        response = client.post("/heroes/", json=hero3_data)
+        assert response.status_code == 200, response.text
+        hero3 = response.json()
+        hero3_id = hero3["id"]
+        response = client.get(f"/heroes/{hero2_id}")
+        assert response.status_code == 200, response.text
+        response = client.get("/heroes/9000")
+        assert response.status_code == 404, response.text
+        response = client.get("/openapi.json")
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data == openapi_schema
+        response = client.get("/heroes/")
+        assert response.status_code == 200, response.text
+        data = response.json()
+        assert len(data) == 3
+
+        response = client.patch(
+            f"/heroes/{hero2_id}", json={"secret_name": "Spider-Youngster"}
+        )
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data["name"] == hero2_data["name"], "The name should not be set to none"
+        assert (
+            data["secret_name"] == "Spider-Youngster"
+        ), "The secret name should be updated"
+
+        response = client.patch(f"/heroes/{hero3_id}", json={"age": None})
+        data = response.json()
+        assert response.status_code == 200, response.text
+        assert data["name"] == hero3_data["name"]
+        assert data["age"] is None, (
+            "A field should be updatable to None, even if " "that's the default"
+        )
+
+        response = client.patch("/heroes/9001", json={"name": "Dragon Cube X"})
+        assert response.status_code == 404, response.text
diff --git a/tests/test_tutorial/test_insert/__init__.py b/tests/test_tutorial/test_insert/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_insert/test_tutorial001.py b/tests/test_tutorial/test_insert/test_tutorial001.py
new file mode 100644 (file)
index 0000000..4e04754
--- /dev/null
@@ -0,0 +1,27 @@
+from sqlmodel import create_engine, Session, select
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.insert import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    mod.main()
+    with Session(mod.engine) as session:
+        heroes = session.exec(select(mod.Hero)).all()
+    heroes_by_name = {hero.name: hero for hero in heroes}
+    deadpond = heroes_by_name["Deadpond"]
+    spider_boy = heroes_by_name["Spider-Boy"]
+    rusty_man = heroes_by_name["Rusty-Man"]
+    assert deadpond.name == "Deadpond"
+    assert deadpond.age is None
+    assert deadpond.id is not None
+    assert deadpond.secret_name == "Dive Wilson"
+    assert spider_boy.name == "Spider-Boy"
+    assert spider_boy.age is None
+    assert spider_boy.id is not None
+    assert spider_boy.secret_name == "Pedro Parqueador"
+    assert rusty_man.name == "Rusty-Man"
+    assert rusty_man.age == 48
+    assert rusty_man.id is not None
+    assert rusty_man.secret_name == "Tommy Sharp"
diff --git a/tests/test_tutorial/test_insert/test_tutorial002.py b/tests/test_tutorial/test_insert/test_tutorial002.py
new file mode 100644 (file)
index 0000000..17834ba
--- /dev/null
@@ -0,0 +1,27 @@
+from sqlmodel import create_engine, Session, select
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.insert import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    mod.main()
+    with Session(mod.engine) as session:
+        heroes = session.exec(select(mod.Hero)).all()
+    heroes_by_name = {hero.name: hero for hero in heroes}
+    deadpond = heroes_by_name["Deadpond"]
+    spider_boy = heroes_by_name["Spider-Boy"]
+    rusty_man = heroes_by_name["Rusty-Man"]
+    assert deadpond.name == "Deadpond"
+    assert deadpond.age is None
+    assert deadpond.id is not None
+    assert deadpond.secret_name == "Dive Wilson"
+    assert spider_boy.name == "Spider-Boy"
+    assert spider_boy.age is None
+    assert spider_boy.id is not None
+    assert spider_boy.secret_name == "Pedro Parqueador"
+    assert rusty_man.name == "Rusty-Man"
+    assert rusty_man.age == 48
+    assert rusty_man.id is not None
+    assert rusty_man.secret_name == "Tommy Sharp"
diff --git a/tests/test_tutorial/test_insert/test_tutorial003.py b/tests/test_tutorial/test_insert/test_tutorial003.py
new file mode 100644 (file)
index 0000000..2b6fb0b
--- /dev/null
@@ -0,0 +1,27 @@
+from sqlmodel import create_engine, Session, select
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.insert import tutorial003 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    mod.main()
+    with Session(mod.engine) as session:
+        heroes = session.exec(select(mod.Hero)).all()
+    heroes_by_name = {hero.name: hero for hero in heroes}
+    deadpond = heroes_by_name["Deadpond"]
+    spider_boy = heroes_by_name["Spider-Boy"]
+    rusty_man = heroes_by_name["Rusty-Man"]
+    assert deadpond.name == "Deadpond"
+    assert deadpond.age is None
+    assert deadpond.id is not None
+    assert deadpond.secret_name == "Dive Wilson"
+    assert spider_boy.name == "Spider-Boy"
+    assert spider_boy.age is None
+    assert spider_boy.id is not None
+    assert spider_boy.secret_name == "Pedro Parqueador"
+    assert rusty_man.name == "Rusty-Man"
+    assert rusty_man.age == 48
+    assert rusty_man.id is not None
+    assert rusty_man.secret_name == "Tommy Sharp"
diff --git a/tests/test_tutorial/test_limit_and_offset/__init__.py b/tests/test_tutorial/test_limit_and_offset/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_limit_and_offset/test_tutorial001.py b/tests/test_tutorial/test_limit_and_offset/test_tutorial001.py
new file mode 100644 (file)
index 0000000..8aeb204
--- /dev/null
@@ -0,0 +1,35 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+expected_calls = [
+    [
+        [
+            {"id": 1, "name": "Deadpond", "secret_name": "Dive Wilson", "age": None},
+            {
+                "id": 2,
+                "name": "Spider-Boy",
+                "secret_name": "Pedro Parqueador",
+                "age": None,
+            },
+            {"id": 3, "name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48},
+        ]
+    ]
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.offset_and_limit import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_limit_and_offset/test_tutorial002.py b/tests/test_tutorial/test_limit_and_offset/test_tutorial002.py
new file mode 100644 (file)
index 0000000..82a615a
--- /dev/null
@@ -0,0 +1,35 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+expected_calls = [
+    [
+        [
+            {
+                "id": 4,
+                "name": "Tarantula",
+                "secret_name": "Natalia Roman-on",
+                "age": 32,
+            },
+            {"id": 5, "name": "Black Lion", "secret_name": "Trevor Challa", "age": 35},
+            {"id": 6, "name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36},
+        ]
+    ]
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.offset_and_limit import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_limit_and_offset/test_tutorial003.py b/tests/test_tutorial/test_limit_and_offset/test_tutorial003.py
new file mode 100644 (file)
index 0000000..ad37788
--- /dev/null
@@ -0,0 +1,33 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+expected_calls = [
+    [
+        [
+            {
+                "id": 7,
+                "name": "Captain North America",
+                "secret_name": "Esteban Rogelios",
+                "age": 93,
+            }
+        ]
+    ]
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.offset_and_limit import tutorial003 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py b/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py
new file mode 100644 (file)
index 0000000..9482f4b
--- /dev/null
@@ -0,0 +1,30 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+expected_calls = [
+    [
+        [
+            {"id": 5, "name": "Black Lion", "secret_name": "Trevor Challa", "age": 35},
+            {"id": 6, "name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36},
+            {"id": 3, "name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48},
+        ]
+    ]
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.offset_and_limit import tutorial004 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_many_to_many/__init__.py b/tests/test_tutorial/test_many_to_many/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_many_to_many/test_tutorial001.py b/tests/test_tutorial/test_many_to_many/test_tutorial001.py
new file mode 100644 (file)
index 0000000..6bfac7f
--- /dev/null
@@ -0,0 +1,53 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ...conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Deadpond:",
+        {"id": 1, "secret_name": "Dive Wilson", "age": None, "name": "Deadpond"},
+    ],
+    [
+        "Deadpond teams:",
+        [
+            {"id": 1, "name": "Z-Force", "headquarters": "Sister Margaret’s Bar"},
+            {"id": 2, "name": "Preventers", "headquarters": "Sharp Tower"},
+        ],
+    ],
+    [
+        "Rusty-Man:",
+        {"id": 2, "secret_name": "Tommy Sharp", "age": 48, "name": "Rusty-Man"},
+    ],
+    [
+        "Rusty-Man Teams:",
+        [{"id": 2, "name": "Preventers", "headquarters": "Sharp Tower"}],
+    ],
+    [
+        "Spider-Boy:",
+        {"id": 3, "secret_name": "Pedro Parqueador", "age": None, "name": "Spider-Boy"},
+    ],
+    [
+        "Spider-Boy Teams:",
+        [{"id": 2, "name": "Preventers", "headquarters": "Sharp Tower"}],
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.many_to_many import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_many_to_many/test_tutorial002.py b/tests/test_tutorial/test_many_to_many/test_tutorial002.py
new file mode 100644 (file)
index 0000000..960e515
--- /dev/null
@@ -0,0 +1,80 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ...conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Deadpond:",
+        {"id": 1, "secret_name": "Dive Wilson", "age": None, "name": "Deadpond"},
+    ],
+    [
+        "Deadpond teams:",
+        [
+            {"id": 1, "name": "Z-Force", "headquarters": "Sister Margaret’s Bar"},
+            {"id": 2, "name": "Preventers", "headquarters": "Sharp Tower"},
+        ],
+    ],
+    [
+        "Rusty-Man:",
+        {"id": 2, "secret_name": "Tommy Sharp", "age": 48, "name": "Rusty-Man"},
+    ],
+    [
+        "Rusty-Man Teams:",
+        [{"id": 2, "name": "Preventers", "headquarters": "Sharp Tower"}],
+    ],
+    [
+        "Spider-Boy:",
+        {"id": 3, "secret_name": "Pedro Parqueador", "age": None, "name": "Spider-Boy"},
+    ],
+    [
+        "Spider-Boy Teams:",
+        [{"id": 2, "name": "Preventers", "headquarters": "Sharp Tower"}],
+    ],
+    [
+        "Updated Spider-Boy's Teams:",
+        [
+            {"id": 2, "name": "Preventers", "headquarters": "Sharp Tower"},
+            {"id": 1, "name": "Z-Force", "headquarters": "Sister Margaret’s Bar"},
+        ],
+    ],
+    [
+        "Z-Force heroes:",
+        [
+            {"id": 1, "secret_name": "Dive Wilson", "age": None, "name": "Deadpond"},
+            {
+                "id": 3,
+                "secret_name": "Pedro Parqueador",
+                "age": None,
+                "name": "Spider-Boy",
+            },
+        ],
+    ],
+    [
+        "Reverted Z-Force's heroes:",
+        [{"id": 1, "secret_name": "Dive Wilson", "age": None, "name": "Deadpond"}],
+    ],
+    [
+        "Reverted Spider-Boy's teams:",
+        [{"id": 2, "name": "Preventers", "headquarters": "Sharp Tower"}],
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.many_to_many import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_many_to_many/test_tutorial003.py b/tests/test_tutorial/test_many_to_many/test_tutorial003.py
new file mode 100644 (file)
index 0000000..a6921d6
--- /dev/null
@@ -0,0 +1,76 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ...conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Z-Force hero:",
+        {"name": "Deadpond", "secret_name": "Dive Wilson", "id": 1, "age": None},
+        "is training:",
+        False,
+    ],
+    [
+        "Preventers hero:",
+        {"name": "Deadpond", "secret_name": "Dive Wilson", "id": 1, "age": None},
+        "is training:",
+        True,
+    ],
+    [
+        "Preventers hero:",
+        {"name": "Spider-Boy", "secret_name": "Pedro Parqueador", "id": 2, "age": None},
+        "is training:",
+        True,
+    ],
+    [
+        "Preventers hero:",
+        {"name": "Rusty-Man", "secret_name": "Tommy Sharp", "id": 3, "age": 48},
+        "is training:",
+        False,
+    ],
+    [
+        "Updated Spider-Boy's Teams:",
+        [
+            {"team_id": 2, "is_training": True, "hero_id": 2},
+            {"team_id": 1, "is_training": True, "hero_id": 2},
+        ],
+    ],
+    [
+        "Z-Force heroes:",
+        [
+            {"team_id": 1, "is_training": False, "hero_id": 1},
+            {"team_id": 1, "is_training": True, "hero_id": 2},
+        ],
+    ],
+    [
+        "Spider-Boy team:",
+        {"headquarters": "Sharp Tower", "id": 2, "name": "Preventers"},
+        "is training:",
+        False,
+    ],
+    [
+        "Spider-Boy team:",
+        {"headquarters": "Sister Margaret’s Bar", "id": 1, "name": "Z-Force"},
+        "is training:",
+        True,
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.many_to_many import tutorial003 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_one/__init__.py b/tests/test_tutorial/test_one/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_one/test_tutorial001.py b/tests/test_tutorial/test_one/test_tutorial001.py
new file mode 100644 (file)
index 0000000..d465f22
--- /dev/null
@@ -0,0 +1,29 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.one import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [
+            "Hero:",
+            {
+                "name": "Tarantula",
+                "secret_name": "Natalia Roman-on",
+                "age": 32,
+                "id": 4,
+            },
+        ]
+    ]
diff --git a/tests/test_tutorial/test_one/test_tutorial002.py b/tests/test_tutorial/test_one/test_tutorial002.py
new file mode 100644 (file)
index 0000000..0fb223e
--- /dev/null
@@ -0,0 +1,19 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.one import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [["Hero:", None]]
diff --git a/tests/test_tutorial/test_one/test_tutorial003.py b/tests/test_tutorial/test_one/test_tutorial003.py
new file mode 100644 (file)
index 0000000..c917f71
--- /dev/null
@@ -0,0 +1,24 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.one import tutorial003 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [
+            "Hero:",
+            {"name": "Deadpond", "secret_name": "Dive Wilson", "age": None, "id": 1},
+        ]
+    ]
diff --git a/tests/test_tutorial/test_one/test_tutorial004.py b/tests/test_tutorial/test_one/test_tutorial004.py
new file mode 100644 (file)
index 0000000..4c03458
--- /dev/null
@@ -0,0 +1,42 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+import pytest
+from sqlalchemy.sql.expression import delete
+
+from sqlmodel import create_engine, Session, delete, select
+from sqlalchemy.exc import MultipleResultsFound
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.one import tutorial004 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    with pytest.raises(MultipleResultsFound):
+        mod.main()
+    with Session(mod.engine) as session:
+        # TODO: create delete() function
+        # TODO: add overloads for .exec() with delete object
+        session.exec(delete(mod.Hero))
+        session.add(mod.Hero(name="Test Hero", secret_name="Secret Test Hero", age=24))
+        session.commit()
+
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.select_heroes()
+    assert calls == [
+        [
+            "Hero:",
+            {
+                "id": 1,
+                "name": "Test Hero",
+                "secret_name": "Secret Test Hero",
+                "age": 24,
+            },
+        ]
+    ]
diff --git a/tests/test_tutorial/test_one/test_tutorial005.py b/tests/test_tutorial/test_one/test_tutorial005.py
new file mode 100644 (file)
index 0000000..3a6de4d
--- /dev/null
@@ -0,0 +1,42 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+import pytest
+from sqlalchemy.sql.expression import delete
+
+from sqlmodel import create_engine, Session, delete, select
+from sqlalchemy.exc import NoResultFound
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.one import tutorial005 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    with pytest.raises(NoResultFound):
+        mod.main()
+    with Session(mod.engine) as session:
+        # TODO: create delete() function
+        # TODO: add overloads for .exec() with delete object
+        session.exec(delete(mod.Hero))
+        session.add(mod.Hero(name="Test Hero", secret_name="Secret Test Hero", age=24))
+        session.commit()
+
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.select_heroes()
+    assert calls == [
+        [
+            "Hero:",
+            {
+                "id": 1,
+                "name": "Test Hero",
+                "secret_name": "Secret Test Hero",
+                "age": 24,
+            },
+        ]
+    ]
diff --git a/tests/test_tutorial/test_one/test_tutorial006.py b/tests/test_tutorial/test_one/test_tutorial006.py
new file mode 100644 (file)
index 0000000..30f9b49
--- /dev/null
@@ -0,0 +1,24 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.one import tutorial006 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [
+            "Hero:",
+            {"name": "Deadpond", "secret_name": "Dive Wilson", "age": None, "id": 1},
+        ]
+    ]
diff --git a/tests/test_tutorial/test_one/test_tutorial007.py b/tests/test_tutorial/test_one/test_tutorial007.py
new file mode 100644 (file)
index 0000000..e6ccf4d
--- /dev/null
@@ -0,0 +1,24 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.one import tutorial007 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [
+            "Hero:",
+            {"name": "Deadpond", "secret_name": "Dive Wilson", "age": None, "id": 1},
+        ]
+    ]
diff --git a/tests/test_tutorial/test_one/test_tutorial008.py b/tests/test_tutorial/test_one/test_tutorial008.py
new file mode 100644 (file)
index 0000000..afadf9c
--- /dev/null
@@ -0,0 +1,24 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.one import tutorial008 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [
+            "Hero:",
+            {"name": "Deadpond", "secret_name": "Dive Wilson", "age": None, "id": 1},
+        ]
+    ]
diff --git a/tests/test_tutorial/test_one/test_tutorial009.py b/tests/test_tutorial/test_one/test_tutorial009.py
new file mode 100644 (file)
index 0000000..4011a09
--- /dev/null
@@ -0,0 +1,19 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.one import tutorial009 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [["Hero:", None]]
diff --git a/tests/test_tutorial/test_relationship_attributes/__init__.py b/tests/test_tutorial/test_relationship_attributes/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_relationship_attributes/test_back_populates/__init__.py b/tests/test_tutorial/test_relationship_attributes/test_back_populates/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial001.py b/tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial001.py
new file mode 100644 (file)
index 0000000..663e583
--- /dev/null
@@ -0,0 +1,293 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+import pytest
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+from sqlalchemy.exc import SAWarning
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 1,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 2,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Updated hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 2,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Team Wakaland:",
+        {"headquarters": "Wakaland Capital City", "id": 3, "name": "Wakaland"},
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 32,
+            "id": 6,
+            "secret_name": "Natalia Roman-on",
+            "team_id": 2,
+            "name": "Tarantula",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 36,
+            "id": 7,
+            "secret_name": "Steve Weird",
+            "team_id": 2,
+            "name": "Dr. Weird",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 93,
+            "id": 8,
+            "secret_name": "Esteban Rogelios",
+            "team_id": 2,
+            "name": "Captain North America",
+        },
+    ],
+    [
+        "Preventers heroes:",
+        [
+            {
+                "age": 48,
+                "id": 2,
+                "secret_name": "Tommy Sharp",
+                "team_id": 2,
+                "name": "Rusty-Man",
+            },
+            {
+                "age": None,
+                "id": 3,
+                "secret_name": "Pedro Parqueador",
+                "team_id": 2,
+                "name": "Spider-Boy",
+            },
+            {
+                "age": 32,
+                "id": 6,
+                "secret_name": "Natalia Roman-on",
+                "team_id": 2,
+                "name": "Tarantula",
+            },
+            {
+                "age": 36,
+                "id": 7,
+                "secret_name": "Steve Weird",
+                "team_id": 2,
+                "name": "Dr. Weird",
+            },
+            {
+                "age": 93,
+                "id": 8,
+                "secret_name": "Esteban Rogelios",
+                "team_id": 2,
+                "name": "Captain North America",
+            },
+        ],
+    ],
+    [
+        "Hero Spider-Boy:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 2,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Preventers Team:",
+        {"headquarters": "Sharp Tower", "id": 2, "name": "Preventers"},
+    ],
+    [
+        "Preventers Team Heroes:",
+        [
+            {
+                "age": 48,
+                "id": 2,
+                "secret_name": "Tommy Sharp",
+                "team_id": 2,
+                "name": "Rusty-Man",
+            },
+            {
+                "age": None,
+                "id": 3,
+                "secret_name": "Pedro Parqueador",
+                "team_id": 2,
+                "name": "Spider-Boy",
+            },
+            {
+                "age": 32,
+                "id": 6,
+                "secret_name": "Natalia Roman-on",
+                "team_id": 2,
+                "name": "Tarantula",
+            },
+            {
+                "age": 36,
+                "id": 7,
+                "secret_name": "Steve Weird",
+                "team_id": 2,
+                "name": "Dr. Weird",
+            },
+            {
+                "age": 93,
+                "id": 8,
+                "secret_name": "Esteban Rogelios",
+                "team_id": 2,
+                "name": "Captain North America",
+            },
+        ],
+    ],
+    [
+        "Spider-Boy without team:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 2,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Preventers Team Heroes again:",
+        [
+            {
+                "age": 48,
+                "id": 2,
+                "secret_name": "Tommy Sharp",
+                "team_id": 2,
+                "name": "Rusty-Man",
+            },
+            {
+                "age": None,
+                "id": 3,
+                "secret_name": "Pedro Parqueador",
+                "team_id": 2,
+                "name": "Spider-Boy",
+            },
+            {
+                "age": 32,
+                "id": 6,
+                "secret_name": "Natalia Roman-on",
+                "team_id": 2,
+                "name": "Tarantula",
+            },
+            {
+                "age": 36,
+                "id": 7,
+                "secret_name": "Steve Weird",
+                "team_id": 2,
+                "name": "Dr. Weird",
+            },
+            {
+                "age": 93,
+                "id": 8,
+                "secret_name": "Esteban Rogelios",
+                "team_id": 2,
+                "name": "Captain North America",
+            },
+        ],
+    ],
+    ["After committing"],
+    [
+        "Spider-Boy after commit:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Preventers Team Heroes after commit:",
+        [
+            {
+                "age": 48,
+                "id": 2,
+                "secret_name": "Tommy Sharp",
+                "team_id": 2,
+                "name": "Rusty-Man",
+            },
+            {
+                "age": 32,
+                "id": 6,
+                "secret_name": "Natalia Roman-on",
+                "team_id": 2,
+                "name": "Tarantula",
+            },
+            {
+                "age": 36,
+                "id": 7,
+                "secret_name": "Steve Weird",
+                "team_id": 2,
+                "name": "Dr. Weird",
+            },
+            {
+                "age": 93,
+                "id": 8,
+                "secret_name": "Esteban Rogelios",
+                "team_id": 2,
+                "name": "Captain North America",
+            },
+        ],
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.relationship_attributes.back_populates import (
+        tutorial001 as mod,
+    )
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        with pytest.warns(SAWarning):
+            mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial002.py b/tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial002.py
new file mode 100644 (file)
index 0000000..daa9c33
--- /dev/null
@@ -0,0 +1,283 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 1,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 2,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Updated hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 2,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Team Wakaland:",
+        {"id": 3, "name": "Wakaland", "headquarters": "Wakaland Capital City"},
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 32,
+            "id": 6,
+            "secret_name": "Natalia Roman-on",
+            "team_id": 2,
+            "name": "Tarantula",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 36,
+            "id": 7,
+            "secret_name": "Steve Weird",
+            "team_id": 2,
+            "name": "Dr. Weird",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 93,
+            "id": 8,
+            "secret_name": "Esteban Rogelios",
+            "team_id": 2,
+            "name": "Captain North America",
+        },
+    ],
+    [
+        "Preventers heroes:",
+        [
+            {
+                "age": 48,
+                "id": 2,
+                "secret_name": "Tommy Sharp",
+                "team_id": 2,
+                "name": "Rusty-Man",
+            },
+            {
+                "age": None,
+                "id": 3,
+                "secret_name": "Pedro Parqueador",
+                "team_id": 2,
+                "name": "Spider-Boy",
+            },
+            {
+                "age": 32,
+                "id": 6,
+                "secret_name": "Natalia Roman-on",
+                "team_id": 2,
+                "name": "Tarantula",
+            },
+            {
+                "age": 36,
+                "id": 7,
+                "secret_name": "Steve Weird",
+                "team_id": 2,
+                "name": "Dr. Weird",
+            },
+            {
+                "age": 93,
+                "id": 8,
+                "secret_name": "Esteban Rogelios",
+                "team_id": 2,
+                "name": "Captain North America",
+            },
+        ],
+    ],
+    [
+        "Hero Spider-Boy:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 2,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Preventers Team:",
+        {"id": 2, "name": "Preventers", "headquarters": "Sharp Tower"},
+    ],
+    [
+        "Preventers Team Heroes:",
+        [
+            {
+                "age": 48,
+                "id": 2,
+                "secret_name": "Tommy Sharp",
+                "team_id": 2,
+                "name": "Rusty-Man",
+            },
+            {
+                "age": None,
+                "id": 3,
+                "secret_name": "Pedro Parqueador",
+                "team_id": 2,
+                "name": "Spider-Boy",
+            },
+            {
+                "age": 32,
+                "id": 6,
+                "secret_name": "Natalia Roman-on",
+                "team_id": 2,
+                "name": "Tarantula",
+            },
+            {
+                "age": 36,
+                "id": 7,
+                "secret_name": "Steve Weird",
+                "team_id": 2,
+                "name": "Dr. Weird",
+            },
+            {
+                "age": 93,
+                "id": 8,
+                "secret_name": "Esteban Rogelios",
+                "team_id": 2,
+                "name": "Captain North America",
+            },
+        ],
+    ],
+    [
+        "Spider-Boy without team:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 2,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Preventers Team Heroes again:",
+        [
+            {
+                "age": 48,
+                "id": 2,
+                "secret_name": "Tommy Sharp",
+                "team_id": 2,
+                "name": "Rusty-Man",
+            },
+            {
+                "age": 32,
+                "id": 6,
+                "secret_name": "Natalia Roman-on",
+                "team_id": 2,
+                "name": "Tarantula",
+            },
+            {
+                "age": 36,
+                "id": 7,
+                "secret_name": "Steve Weird",
+                "team_id": 2,
+                "name": "Dr. Weird",
+            },
+            {
+                "age": 93,
+                "id": 8,
+                "secret_name": "Esteban Rogelios",
+                "team_id": 2,
+                "name": "Captain North America",
+            },
+        ],
+    ],
+    ["After committing"],
+    [
+        "Spider-Boy after commit:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Preventers Team Heroes after commit:",
+        [
+            {
+                "age": 48,
+                "id": 2,
+                "secret_name": "Tommy Sharp",
+                "team_id": 2,
+                "name": "Rusty-Man",
+            },
+            {
+                "age": 32,
+                "id": 6,
+                "secret_name": "Natalia Roman-on",
+                "team_id": 2,
+                "name": "Tarantula",
+            },
+            {
+                "age": 36,
+                "id": 7,
+                "secret_name": "Steve Weird",
+                "team_id": 2,
+                "name": "Dr. Weird",
+            },
+            {
+                "age": 93,
+                "id": 8,
+                "secret_name": "Esteban Rogelios",
+                "team_id": 2,
+                "name": "Captain North America",
+            },
+        ],
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.relationship_attributes.back_populates import (
+        tutorial002 as mod,
+    )
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial003.py b/tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial003.py
new file mode 100644 (file)
index 0000000..ae05d9a
--- /dev/null
@@ -0,0 +1,24 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.relationship_attributes.back_populates import (
+        tutorial003 as mod,
+    )
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    mod.main()
+    insp: Inspector = inspect(mod.engine)
+    assert insp.has_table(str(mod.Hero.__tablename__))
+    assert insp.has_table(str(mod.Weapon.__tablename__))
+    assert insp.has_table(str(mod.Power.__tablename__))
+    assert insp.has_table(str(mod.Team.__tablename__))
diff --git a/tests/test_tutorial/test_relationship_attributes/test_create_and_update_relationships/__init__.py b/tests/test_tutorial/test_relationship_attributes/test_create_and_update_relationships/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_relationship_attributes/test_create_and_update_relationships/test_tutorial001.py b/tests/test_tutorial/test_relationship_attributes/test_create_and_update_relationships/test_tutorial001.py
new file mode 100644 (file)
index 0000000..afb379e
--- /dev/null
@@ -0,0 +1,102 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 1,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 2,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Updated hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 2,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Team Wakaland:",
+        {"id": 3, "headquarters": "Wakaland Capital City", "name": "Wakaland"},
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 32,
+            "id": 6,
+            "secret_name": "Natalia Roman-on",
+            "team_id": 2,
+            "name": "Tarantula",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 36,
+            "id": 7,
+            "secret_name": "Steve Weird",
+            "team_id": 2,
+            "name": "Dr. Weird",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 93,
+            "id": 8,
+            "secret_name": "Esteban Rogelios",
+            "team_id": 2,
+            "name": "Captain North America",
+        },
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.relationship_attributes.create_and_update_relationships import (
+        tutorial001 as mod,
+    )
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_relationship_attributes/test_define_relationship_attributes/__init__.py b/tests/test_tutorial/test_relationship_attributes/test_define_relationship_attributes/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_relationship_attributes/test_define_relationship_attributes/test_tutorial001.py b/tests/test_tutorial/test_relationship_attributes/test_define_relationship_attributes/test_tutorial001.py
new file mode 100644 (file)
index 0000000..d3cd5ae
--- /dev/null
@@ -0,0 +1,58 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "name": "Deadpond",
+            "age": None,
+            "team_id": 1,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "name": "Rusty-Man",
+            "age": 48,
+            "team_id": 2,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "name": "Spider-Boy",
+            "age": None,
+            "team_id": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+        },
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.relationship_attributes.define_relationship_attributes import (
+        tutorial001 as mod,
+    )
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_relationship_attributes/test_read_relationships/__init__.py b/tests/test_tutorial/test_relationship_attributes/test_read_relationships/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_relationship_attributes/test_read_relationships/test_tutorial001.py b/tests/test_tutorial/test_relationship_attributes/test_read_relationships/test_tutorial001.py
new file mode 100644 (file)
index 0000000..96ca9ef
--- /dev/null
@@ -0,0 +1,110 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 1,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 2,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Updated hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 2,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Team Wakaland:",
+        {"headquarters": "Wakaland Capital City", "id": 3, "name": "Wakaland"},
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 32,
+            "id": 6,
+            "secret_name": "Natalia Roman-on",
+            "team_id": 2,
+            "name": "Tarantula",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 36,
+            "id": 7,
+            "secret_name": "Steve Weird",
+            "team_id": 2,
+            "name": "Dr. Weird",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 93,
+            "id": 8,
+            "secret_name": "Esteban Rogelios",
+            "team_id": 2,
+            "name": "Captain North America",
+        },
+    ],
+    [
+        "Spider-Boy's team:",
+        {"headquarters": "Wakaland Capital City", "id": 3, "name": "Wakaland"},
+    ],
+    [
+        "Spider-Boy's team again:",
+        {"headquarters": "Sharp Tower", "id": 2, "name": "Preventers"},
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.relationship_attributes.read_relationships import (
+        tutorial001 as mod,
+    )
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_relationship_attributes/test_read_relationships/test_tutorial002.py b/tests/test_tutorial/test_relationship_attributes/test_read_relationships/test_tutorial002.py
new file mode 100644 (file)
index 0000000..b6d2e44
--- /dev/null
@@ -0,0 +1,152 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlalchemy import inspect
+from sqlalchemy.engine.reflection import Inspector
+from sqlmodel import create_engine
+from sqlmodel.pool import StaticPool
+
+from ....conftest import get_testing_print_function
+
+expected_calls = [
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 1,
+            "secret_name": "Dive Wilson",
+            "team_id": 1,
+            "name": "Deadpond",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": 48,
+            "id": 2,
+            "secret_name": "Tommy Sharp",
+            "team_id": 2,
+            "name": "Rusty-Man",
+        },
+    ],
+    [
+        "Created hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Updated hero:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": 2,
+            "name": "Spider-Boy",
+        },
+    ],
+    [
+        "Team Wakaland:",
+        {"id": 3, "name": "Wakaland", "headquarters": "Wakaland Capital City"},
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 32,
+            "id": 6,
+            "secret_name": "Natalia Roman-on",
+            "team_id": 2,
+            "name": "Tarantula",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 36,
+            "id": 7,
+            "secret_name": "Steve Weird",
+            "team_id": 2,
+            "name": "Dr. Weird",
+        },
+    ],
+    [
+        "Preventers new hero:",
+        {
+            "age": 93,
+            "id": 8,
+            "secret_name": "Esteban Rogelios",
+            "team_id": 2,
+            "name": "Captain North America",
+        },
+    ],
+    [
+        "Preventers heroes:",
+        [
+            {
+                "age": 48,
+                "id": 2,
+                "secret_name": "Tommy Sharp",
+                "team_id": 2,
+                "name": "Rusty-Man",
+            },
+            {
+                "age": None,
+                "id": 3,
+                "secret_name": "Pedro Parqueador",
+                "team_id": 2,
+                "name": "Spider-Boy",
+            },
+            {
+                "age": 32,
+                "id": 6,
+                "secret_name": "Natalia Roman-on",
+                "team_id": 2,
+                "name": "Tarantula",
+            },
+            {
+                "age": 36,
+                "id": 7,
+                "secret_name": "Steve Weird",
+                "team_id": 2,
+                "name": "Dr. Weird",
+            },
+            {
+                "age": 93,
+                "id": 8,
+                "secret_name": "Esteban Rogelios",
+                "team_id": 2,
+                "name": "Captain North America",
+            },
+        ],
+    ],
+    [
+        "Spider-Boy without team:",
+        {
+            "age": None,
+            "id": 3,
+            "secret_name": "Pedro Parqueador",
+            "team_id": None,
+            "name": "Spider-Boy",
+        },
+    ],
+]
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.relationship_attributes.read_relationships import (
+        tutorial002 as mod,
+    )
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_select/__init__.py b/tests/test_tutorial/test_select/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_select/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_select/test_tutorial001_tutorial002.py
new file mode 100644 (file)
index 0000000..aac1e91
--- /dev/null
@@ -0,0 +1,54 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]):
+    assert calls[0][0] == {
+        "name": "Deadpond",
+        "secret_name": "Dive Wilson",
+        "age": None,
+        "id": 1,
+    }
+    assert calls[1][0] == {
+        "name": "Spider-Boy",
+        "secret_name": "Pedro Parqueador",
+        "age": None,
+        "id": 2,
+    }
+    assert calls[2][0] == {
+        "name": "Rusty-Man",
+        "secret_name": "Tommy Sharp",
+        "age": 48,
+        "id": 3,
+    }
+
+
+def test_tutorial_001(clear_sqlmodel):
+    from docs_src.tutorial.select import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    check_calls(calls)
+
+
+def test_tutorial_002(clear_sqlmodel):
+    from docs_src.tutorial.select import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    check_calls(calls)
diff --git a/tests/test_tutorial/test_select/test_tutorial003_tutorial004.py b/tests/test_tutorial/test_select/test_tutorial003_tutorial004.py
new file mode 100644 (file)
index 0000000..bfda0cb
--- /dev/null
@@ -0,0 +1,57 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+
+from ...conftest import get_testing_print_function
+
+
+def check_calls(calls: List[List[Union[str, Dict[str, Any]]]]):
+    assert calls[0][0] == [
+        {
+            "name": "Deadpond",
+            "secret_name": "Dive Wilson",
+            "age": None,
+            "id": 1,
+        },
+        {
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "age": None,
+            "id": 2,
+        },
+        {
+            "name": "Rusty-Man",
+            "secret_name": "Tommy Sharp",
+            "age": 48,
+            "id": 3,
+        },
+    ]
+
+
+def test_tutorial_003(clear_sqlmodel):
+    from docs_src.tutorial.select import tutorial003 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    check_calls(calls)
+
+
+def test_tutorial_002(clear_sqlmodel):
+    from docs_src.tutorial.select import tutorial004 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    check_calls(calls)
diff --git a/tests/test_tutorial/test_update/__init__.py b/tests/test_tutorial/test_update/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_update/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_update/test_tutorial001_tutorial002.py
new file mode 100644 (file)
index 0000000..25458b8
--- /dev/null
@@ -0,0 +1,55 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+expected_calls = [
+    [
+        "Hero:",
+        {
+            "id": 2,
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "age": None,
+        },
+    ],
+    [
+        "Updated hero:",
+        {
+            "id": 2,
+            "name": "Spider-Boy",
+            "secret_name": "Pedro Parqueador",
+            "age": 16,
+        },
+    ],
+]
+
+
+def test_tutorial001(clear_sqlmodel):
+    from docs_src.tutorial.update import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
+
+
+def test_tutorial002(clear_sqlmodel):
+    from docs_src.tutorial.update import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_update/test_tutorial003_tutorial004.py b/tests/test_tutorial/test_update/test_tutorial003_tutorial004.py
new file mode 100644 (file)
index 0000000..3ffaac7
--- /dev/null
@@ -0,0 +1,68 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+expected_calls = [
+    [
+        "Hero 1:",
+        {"id": 2, "name": "Spider-Boy", "secret_name": "Pedro Parqueador", "age": None},
+    ],
+    [
+        "Hero 2:",
+        {
+            "id": 7,
+            "name": "Captain North America",
+            "secret_name": "Esteban Rogelios",
+            "age": 93,
+        },
+    ],
+    [
+        "Updated hero 1:",
+        {
+            "id": 2,
+            "name": "Spider-Youngster",
+            "secret_name": "Pedro Parqueador",
+            "age": 16,
+        },
+    ],
+    [
+        "Updated hero 2:",
+        {
+            "id": 7,
+            "name": "Captain North America Except Canada",
+            "secret_name": "Esteban Rogelios",
+            "age": 110,
+        },
+    ],
+]
+
+
+def test_tutorial003(clear_sqlmodel):
+    from docs_src.tutorial.update import tutorial003 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
+
+
+def test_tutorial004(clear_sqlmodel):
+    from docs_src.tutorial.update import tutorial004 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == expected_calls
diff --git a/tests/test_tutorial/test_where/__init__.py b/tests/test_tutorial/test_where/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_where/test_tutorial001.py b/tests/test_tutorial/test_where/test_tutorial001.py
new file mode 100644 (file)
index 0000000..63b8829
--- /dev/null
@@ -0,0 +1,28 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial001 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [
+            {
+                "name": "Deadpond",
+                "secret_name": "Dive Wilson",
+                "age": None,
+                "id": 1,
+            }
+        ]
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial002.py b/tests/test_tutorial/test_where/test_tutorial002.py
new file mode 100644 (file)
index 0000000..6efb682
--- /dev/null
@@ -0,0 +1,29 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial002 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [
+            {
+                "name": "Spider-Boy",
+                "secret_name": "Pedro Parqueador",
+                "age": None,
+                "id": 2,
+            }
+        ],
+        [{"name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48, "id": 3}],
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial003.py b/tests/test_tutorial/test_where/test_tutorial003.py
new file mode 100644 (file)
index 0000000..cbba6c2
--- /dev/null
@@ -0,0 +1,31 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial003 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+
+    assert calls == [
+        [{"id": 6, "name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36}],
+        [{"id": 3, "name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48}],
+        [
+            {
+                "id": 7,
+                "name": "Captain North America",
+                "secret_name": "Esteban Rogelios",
+                "age": 93,
+            }
+        ],
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial004.py b/tests/test_tutorial/test_where/test_tutorial004.py
new file mode 100644 (file)
index 0000000..a7c2add
--- /dev/null
@@ -0,0 +1,31 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial004 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [{"id": 5, "name": "Black Lion", "secret_name": "Trevor Challa", "age": 35}],
+        [{"id": 6, "name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36}],
+        [{"id": 3, "name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48}],
+        [
+            {
+                "id": 7,
+                "name": "Captain North America",
+                "secret_name": "Esteban Rogelios",
+                "age": 93,
+            }
+        ],
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial005.py b/tests/test_tutorial/test_where/test_tutorial005.py
new file mode 100644 (file)
index 0000000..4727b87
--- /dev/null
@@ -0,0 +1,21 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial005 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [{"name": "Tarantula", "secret_name": "Natalia Roman-on", "age": 32, "id": 4}]
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial006.py b/tests/test_tutorial/test_where/test_tutorial006.py
new file mode 100644 (file)
index 0000000..0b6c1c2
--- /dev/null
@@ -0,0 +1,22 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial006 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [{"name": "Tarantula", "secret_name": "Natalia Roman-on", "age": 32, "id": 4}],
+        [{"name": "Black Lion", "secret_name": "Trevor Challa", "age": 35, "id": 5}],
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial007.py b/tests/test_tutorial/test_where/test_tutorial007.py
new file mode 100644 (file)
index 0000000..5c1cb2f
--- /dev/null
@@ -0,0 +1,22 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial007 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [{"id": 5, "name": "Black Lion", "secret_name": "Trevor Challa", "age": 35}],
+        [{"id": 6, "name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36}],
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial008.py b/tests/test_tutorial/test_where/test_tutorial008.py
new file mode 100644 (file)
index 0000000..8140e03
--- /dev/null
@@ -0,0 +1,22 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial008 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [{"id": 5, "name": "Black Lion", "secret_name": "Trevor Challa", "age": 35}],
+        [{"id": 6, "name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36}],
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial009.py b/tests/test_tutorial/test_where/test_tutorial009.py
new file mode 100644 (file)
index 0000000..a50c78a
--- /dev/null
@@ -0,0 +1,30 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial009 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [{"name": "Tarantula", "secret_name": "Natalia Roman-on", "age": 32, "id": 4}],
+        [{"name": "Black Lion", "secret_name": "Trevor Challa", "age": 35, "id": 5}],
+        [
+            {
+                "name": "Captain North America",
+                "secret_name": "Esteban Rogelios",
+                "age": 93,
+                "id": 7,
+            }
+        ],
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial010.py b/tests/test_tutorial/test_where/test_tutorial010.py
new file mode 100644 (file)
index 0000000..ccf474d
--- /dev/null
@@ -0,0 +1,30 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial010 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [{"name": "Tarantula", "secret_name": "Natalia Roman-on", "age": 32, "id": 4}],
+        [{"name": "Black Lion", "secret_name": "Trevor Challa", "age": 35, "id": 5}],
+        [
+            {
+                "name": "Captain North America",
+                "secret_name": "Esteban Rogelios",
+                "age": 93,
+                "id": 7,
+            }
+        ],
+    ]
diff --git a/tests/test_tutorial/test_where/test_tutorial011.py b/tests/test_tutorial/test_where/test_tutorial011.py
new file mode 100644 (file)
index 0000000..86ceaba
--- /dev/null
@@ -0,0 +1,31 @@
+from typing import Any, Dict, List, Union
+from unittest.mock import patch
+
+from sqlmodel import create_engine
+from ...conftest import get_testing_print_function
+
+
+def test_tutorial(clear_sqlmodel):
+    from docs_src.tutorial.where import tutorial011 as mod
+
+    mod.sqlite_url = "sqlite://"
+    mod.engine = create_engine(mod.sqlite_url)
+    calls = []
+
+    new_print = get_testing_print_function(calls)
+
+    with patch("builtins.print", new=new_print):
+        mod.main()
+    assert calls == [
+        [{"id": 5, "name": "Black Lion", "secret_name": "Trevor Challa", "age": 35}],
+        [{"id": 6, "name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36}],
+        [{"id": 3, "name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48}],
+        [
+            {
+                "id": 7,
+                "name": "Captain North America",
+                "secret_name": "Esteban Rogelios",
+                "age": 93,
+            }
+        ],
+    ]