Coverage for tests/test_cli/test_generate.py: 100%
70 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-27 18:25 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-27 18:25 +0000
1import json
2from enum import Enum
3from typing import (
4 Any,
5 Dict,
6 Type,
7 Tuple,
8 Callable,
9 Iterator,
10 Optional,
11 Generator,
12)
13from pathlib import Path
14from itertools import chain
16import pytest
17import pydantic
18from _pytest.monkeypatch import MonkeyPatch
20from prisma.utils import temp_env_update
21from prisma.generator.models import InterfaceChoices
23from ..utils import Runner, Testdir
25# all these tests simply ensure the correct config is being parsed by generator.run,
26# as each config option is individually tested elsewwere we can be sure that each
27# config option results in the intended output
29# TODO: test watch option
30# TODO: nearly all of these tests could be optimised by exiting the generator early
31# and not actually generating the client as we don't make use of it in any of these tests
34@pytest.fixture(autouse=True)
35def setup_env() -> Iterator[None]:
36 with temp_env_update({'PRISMA_PY_DEBUG_GENERATOR': '1'}):
37 yield
40def run_test(
41 runner: Runner,
42 testdir: Testdir,
43 argument: Optional[str],
44 options: Optional[str],
45 do_assert: Callable[[Dict[str, Any]], None],
46) -> None:
47 if options is None:
48 options = ''
50 schema = testdir.make_schema(options=options)
52 args = ['py', 'generate', f'--schema={schema}']
53 if argument is not None:
54 args.append(argument)
56 result = runner.invoke(args)
57 print(result.output)
58 assert result.exit_code == 0
60 path = testdir.path / 'prisma' / 'generator' / 'debug-data.json'
61 data = json.loads(path.read_text())
62 do_assert(data)
65def from_enum(enum: Type[Enum], arg: str) -> Generator[Tuple[str, str, None], None, None]:
66 return ((item.value, arg + item.value, None) for item in enum.__members__.values())
69def test_unsupported_pydantic_version(runner: Runner, monkeypatch: MonkeyPatch) -> None:
70 """Using an older version of pydantic outputs warning
72 We need to use pydantic>=1.8.2 as that added the customise_sources config option to
73 prioritise env variables over init kwargs.
74 """
75 monkeypatch.setattr(pydantic, 'VERSION', '1.6.2', raising=True)
76 result = runner.invoke(['py', 'generate'])
77 assert result.output.startswith(
78 'WARNING: Unsupported version of pydantic installed, this command may not work as intended\n'
79 'Please update pydantic to 1.8 or greater'
80 )
83def test_bad_interface_option(runner: Runner) -> None:
84 """Passing an unknown interface option raises an error"""
85 result = runner.invoke(['py', 'generate', '--interface=foo'])
86 assert result.exit_code != 0
87 assert "Error: Invalid value for '--interface'" in result.output
88 assert 'foo' in result.output
89 assert 'sync' in result.output
90 assert 'asyncio' in result.output
93def test_prisma_error_non_zero_exit_code(testdir: Testdir, runner: Runner) -> None:
94 """Exits non-zero when the prisma process exits non-zero"""
95 path = testdir.make_schema(schema=testdir.default_schema + 'foo')
96 result = runner.invoke(['py', 'generate', f'--schema={path}'])
97 assert result.exit_code != 0
98 assert 'Error code: P1012' in result.output
101def test_schema_not_found(runner: Runner) -> None:
102 """Passing non-existent schema raises an error"""
103 result = runner.invoke(['py', 'generate', '--schema=foo'])
104 assert result.exit_code != 0
105 assert "Error: Invalid value for '--schema': File 'foo' does not exist." in result.output
108@pytest.mark.parametrize(
109 'target,argument,options',
110 chain(
111 from_enum(InterfaceChoices, '--interface='),
112 [
113 ('sync', None, 'interface = sync'), # ensure uses schema property
114 # ensure overrides
115 ('asyncio', '--interface=asyncio', 'interface = sync'),
116 ],
117 ),
118)
119def test_interface_option(
120 testdir: Testdir,
121 runner: Runner,
122 target: str,
123 argument: Optional[str],
124 options: Optional[str],
125) -> None:
126 """interface option is overrided correctly"""
128 def do_assert(data: Dict[str, Any]) -> None:
129 assert data['generator']['config']['interface'] == target
131 run_test(runner, testdir, argument, options, do_assert)
134@pytest.mark.parametrize(
135 'target,argument,options',
136 [
137 (None, None, None), # default
138 ('partials.py', '--partials=partials.py', None),
139 ('partials.py', None, 'partial_type_generator = "partials.py"'),
140 (
141 'partials.py',
142 '--partials=partials.py',
143 'partial_type_generator = "invalid.py"',
144 ),
145 ],
146)
147def test_partials_option(
148 testdir: Testdir,
149 runner: Runner,
150 target: Optional[str],
151 argument: Optional[str],
152 options: Optional[str],
153) -> None:
154 """partial type generator option is overrided correctly"""
156 def do_assert(data: Dict[str, Any]) -> None:
157 partial_type_generator = data['generator']['config']['partial_type_generator']
158 if target is None:
159 assert partial_type_generator is None
160 else:
161 actual = Path(partial_type_generator['spec']).absolute()
162 assert actual == Path(target).absolute()
164 def partials() -> None: # mark: filedef
165 pass
167 testdir.make_from_function(partials, name='partials.py')
168 run_test(runner, testdir, argument, options, do_assert)
171@pytest.mark.parametrize(
172 'target,argument,options',
173 [
174 (5, None, None), # default
175 (3, None, 'recursive_type_depth = 3'), # ensure uses schema property
176 (-1, '-t -1', 'recursive_type_depth = 3'), # ensure overrides
177 ],
178)
179def test_type_depth_option(
180 testdir: Testdir,
181 runner: Runner,
182 target: str,
183 argument: Optional[str],
184 options: Optional[str],
185) -> None:
186 """recursive_type_depth option is overrided correctly"""
188 def do_assert(data: Dict[str, Any]) -> None:
189 assert data['generator']['config']['recursive_type_depth'] == target
191 run_test(runner, testdir, argument, options, do_assert)