Coverage for src/csv_schema_validator/tests/test_validate_csv.py: 0%

66 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-20 12:34 +0200

1import pytest 

2import tempfile 

3import os 

4 

5from csv_schema_validator.validate_csv import validate_csv 

6 

7 

8class TestValidateCSV: 

9 """Test suite for the validate_csv function""" 

10 

11 @pytest.fixture 

12 def temp_dir(self): 

13 """Create a temporary directory for test files""" 

14 with tempfile.TemporaryDirectory() as tmpdir: 

15 yield tmpdir 

16 

17 @pytest.fixture 

18 def basic_schema(self): 

19 """Create a basic schema file for testing""" 

20 return { 

21 "name": "Test Schema", 

22 "description": "Basic test schema", 

23 "fields": [ 

24 { 

25 "name": "id", 

26 "type": "integer", 

27 "required": True, 

28 "description": "Unique identifier", 

29 }, 

30 { 

31 "name": "name", 

32 "type": "string", 

33 "required": True, 

34 "description": "Name field", 

35 }, 

36 { 

37 "name": "email", 

38 "type": "string", 

39 "required": True, 

40 "pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", 

41 "description": "Email address", 

42 }, 

43 { 

44 "name": "department", 

45 "type": "string", 

46 "required": True, 

47 "enum": ["Engineering", "Marketing", "Sales"], 

48 "description": "Department", 

49 }, 

50 { 

51 "name": "salary", 

52 "type": "number", 

53 "required": True, 

54 "min": 30000, 

55 "max": 200000, 

56 "description": "Salary", 

57 }, 

58 { 

59 "name": "is_active", 

60 "type": "boolean", 

61 "required": True, 

62 "description": "Active status", 

63 }, 

64 ], 

65 } 

66 

67 @pytest.fixture 

68 def invalid_schema(self): 

69 """Create an invalid schema file for testing""" 

70 return { 

71 "name": "Invalid Schema", 

72 "description": "Invalid schema", 

73 "fields": [ 

74 { 

75 "name": "id", 

76 "required": True, 

77 }, 

78 ], 

79 "invalid_field": "invalid_field", 

80 } 

81 

82 @pytest.fixture 

83 def non_json_non_text_schema(self): 

84 """Create a non JSON non text schema file for testing""" 

85 return 123 

86 

87 @pytest.fixture 

88 def non_json_text_schema(self): 

89 """Create a non JSON schema file for testing""" 

90 return "invalid schema" 

91 

92 @pytest.fixture 

93 def valid_csv(self, temp_dir): 

94 """Create a valid CSV file for testing""" 

95 csv_content = """id,name,email,department,salary,is_active 

961,John Doe,john.doe@company.com,Engineering,75000,true 

972,Jane Smith,jane.smith@company.com,Marketing,65000,false""" 

98 

99 csv_file = os.path.join(temp_dir, "valid.csv") 

100 with open(csv_file, "w") as f: 

101 f.write(csv_content) 

102 return csv_file 

103 

104 @pytest.fixture 

105 def invalid_csv(self, temp_dir): 

106 """Create an invalid CSV file for testing""" 

107 csv_content = """id,name,email,department,salary,is_active 

1081,John Doe,invalid-email,Engineering,75000,true 

1092,Jane Smith,jane.smith@company.com,InvalidDept,65000,false 

1103,invalid-id,Bob Johnson,bob@company.com,Sales,25000,maybe 

1114,Alice Williams,alice@company.com,Marketing,300000,true""" 

112 csv_file = os.path.join(temp_dir, "invalid.csv") 

113 with open(csv_file, "w") as f: 

114 f.write(csv_content) 

115 return csv_file 

116 

117 @pytest.fixture 

118 def non_matching_csv(self, temp_dir): 

119 """Create a non matching CSV file for testing""" 

120 csv_content = """id,namee,email,department,salary,is_active 

1211,John Doe,john.doe@company,Engineerin,75000,yes 

122two,Jane Smith,jane.smith@company.com,Marketing,65000,false""" 

123 csv_file = os.path.join(temp_dir, "non_matching.csv") 

124 with open(csv_file, "w") as f: 

125 f.write(csv_content) 

126 return csv_file 

127 

128 def test_validate_csv_empty_file(self, temp_dir, basic_schema): 

129 """Test validation of empty CSV file""" 

130 empty_csv = os.path.join(temp_dir, "empty.csv") 

131 with open(empty_csv, "w") as f: 

132 f.write("") 

133 

134 result = validate_csv(empty_csv, basic_schema) 

135 assert result == { 

136 "is_valid": False, 

137 "errors": [ 

138 { 

139 "error_type": "empty_csv_file", 

140 "value": empty_csv, 

141 "row": -1, 

142 "column": -1, 

143 "details": {}, 

144 } 

145 ], 

146 } 

147 

148 def test_validate_invalid_schema(self, valid_csv, invalid_schema): 

149 result = validate_csv(valid_csv, invalid_schema) 

150 assert result == { 

151 "is_valid": False, 

152 "errors": [ 

153 { 

154 "field": "fields.0.type", 

155 "message": "Field required", 

156 "type": "missing", 

157 "input": {"name": "id", "required": True}, 

158 } 

159 ], 

160 "validated_schema": None, 

161 } 

162 

163 def test_non_json_text_schema(self, valid_csv, non_json_text_schema): 

164 result = validate_csv(valid_csv, non_json_text_schema) 

165 assert result == { 

166 "is_valid": False, 

167 "errors": [ 

168 { 

169 "error_type": "invalid_schema", 

170 "error_message": "csv_schema_validator.schema_models.CSVSchema() argument after ** must be a mapping, not str", 

171 } 

172 ], 

173 "schema_value": "invalid schema", 

174 } 

175 

176 def test_non_json_non_text_schema(self, valid_csv, non_json_non_text_schema): 

177 result = validate_csv(valid_csv, non_json_non_text_schema) 

178 assert result == { 

179 "is_valid": False, 

180 "errors": [ 

181 { 

182 "error_type": "invalid_schema", 

183 "error_message": "csv_schema_validator.schema_models.CSVSchema() argument after ** must be a mapping, not int", 

184 } 

185 ], 

186 "schema_value": 123, 

187 } 

188 

189 def test_validate_valid_csv(self, valid_csv, basic_schema): 

190 result = validate_csv(valid_csv, basic_schema) 

191 assert result == { 

192 "is_valid": True, 

193 "errors": [], 

194 } 

195 

196 def test_validate_non_matching_csv(self, non_matching_csv, basic_schema): 

197 result = validate_csv(non_matching_csv, basic_schema) 

198 print("Actual result") 

199 print(result) 

200 assert result == { 

201 "is_valid": False, 

202 "errors": [ 

203 { 

204 "error_type": "missing_fields", 

205 "value": [ 

206 "id", 

207 "namee", 

208 "email", 

209 "department", 

210 "salary", 

211 "is_active", 

212 ], 

213 "row": -1, 

214 "column": -1, 

215 "details": { 

216 "required_fields": [ 

217 "id", 

218 "name", 

219 "email", 

220 "department", 

221 "salary", 

222 "is_active", 

223 ], 

224 "missing_fields": ["name"], 

225 }, 

226 }, 

227 { 

228 "error_type": "pattern_not_matched", 

229 "value": "john.doe@company", 

230 "column": "email", 

231 "row": 0, 

232 "details": { 

233 "expected_pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" 

234 }, 

235 }, 

236 { 

237 "error_type": "not_in_enum", 

238 "value": "Engineerin", 

239 "column": "department", 

240 "row": 0, 

241 "details": {"expected_enum": ["Engineering", "Marketing", "Sales"]}, 

242 }, 

243 { 

244 "error_type": "invalid_boolean", 

245 "value": "yes", 

246 "column": "is_active", 

247 "row": 0, 

248 "details": {"supported_values": ["true", "false"]}, 

249 }, 

250 { 

251 "error_type": "invalid_integer", 

252 "value": "two", 

253 "column": "id", 

254 "row": 1, 

255 "details": {}, 

256 }, 

257 ], 

258 } 

259 

260 """ 

261 Test case to handle, both cli and library: 

262 - Invalid CSV file - not matching schema 

263 """