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

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 

15 

16import pytest 

17import pydantic 

18from _pytest.monkeypatch import MonkeyPatch 

19 

20from prisma.utils import temp_env_update 

21from prisma.generator.models import InterfaceChoices 

22 

23from ..utils import Runner, Testdir 

24 

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 

28 

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 

32 

33 

34@pytest.fixture(autouse=True) 

35def setup_env() -> Iterator[None]: 

36 with temp_env_update({'PRISMA_PY_DEBUG_GENERATOR': '1'}): 

37 yield 

38 

39 

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 = '' 

49 

50 schema = testdir.make_schema(options=options) 

51 

52 args = ['py', 'generate', f'--schema={schema}'] 

53 if argument is not None: 

54 args.append(argument) 

55 

56 result = runner.invoke(args) 

57 print(result.output) 

58 assert result.exit_code == 0 

59 

60 path = testdir.path / 'prisma' / 'generator' / 'debug-data.json' 

61 data = json.loads(path.read_text()) 

62 do_assert(data) 

63 

64 

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()) 

67 

68 

69def test_unsupported_pydantic_version(runner: Runner, monkeypatch: MonkeyPatch) -> None: 

70 """Using an older version of pydantic outputs warning 

71 

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 ) 

81 

82 

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 

91 

92 

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 

99 

100 

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 

106 

107 

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""" 

127 

128 def do_assert(data: Dict[str, Any]) -> None: 

129 assert data['generator']['config']['interface'] == target 

130 

131 run_test(runner, testdir, argument, options, do_assert) 

132 

133 

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""" 

155 

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() 

163 

164 def partials() -> None: # mark: filedef 

165 pass 

166 

167 testdir.make_from_function(partials, name='partials.py') 

168 run_test(runner, testdir, argument, options, do_assert) 

169 

170 

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""" 

187 

188 def do_assert(data: Dict[str, Any]) -> None: 

189 assert data['generator']['config']['recursive_type_depth'] == target 

190 

191 run_test(runner, testdir, argument, options, do_assert)