Coverage for tests/test_places.py: 100%

78 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-07-28 10:16 -0400

1from copy import deepcopy 

2from typing import Any, Dict 

3import pytest 

4import pydantic 

5from src.overturetoosm.places import ( 

6 process_place, 

7) 

8from src.overturetoosm.utils import process_geojson 

9from src.overturetoosm.objects import ConfidenceError, UnmatchedError 

10 

11 

12@pytest.fixture(name="clean_dict") 

13def clean_fix() -> Dict[str, Any]: 

14 return { 

15 "name": "Primary Name", 

16 "brand": "Brand Name", 

17 "brand:wikidata": "Q123", 

18 "addr:street_address": "123 Main St", 

19 "addr:city": "City", 

20 "addr:postcode": "12345", 

21 "addr:state": "CA", 

22 "addr:country": "Country", 

23 "phone": "+1234567890", 

24 "website": "https://example.com", 

25 "source": "dataset1 via overturetoosm", 

26 "office": "lawyer", 

27 "lawyer": "notary", 

28 "contact:facebook": "www.facebook.com/example", 

29 } 

30 

31 

32@pytest.fixture(name="geojson_dict") 

33def geojson_fix() -> Dict[str, Any]: 

34 return { 

35 "type": "FeatureCollection", 

36 "features": [ 

37 { 

38 "type": "Feature", 

39 "geometry": {"type": "Point", "coordinates": [-1, 1]}, 

40 "properties": { 

41 "id": "123", 

42 "version": 1, 

43 "update_time": "2022-01-01T00:00:00Z", 

44 "sources": [ 

45 { 

46 "property": "property1", 

47 "dataset": "dataset1", 

48 "record_id": "record1", 

49 "confidence": 0.8, 

50 } 

51 ], 

52 "names": { 

53 "primary": "Primary Name", 

54 "common": "Common Name", 

55 "rules": "Rules Name", 

56 }, 

57 "brand": { 

58 "wikidata": "Q123", 

59 "names": { 

60 "primary": "Brand Name", 

61 "common": "Common Name", 

62 "rules": "Rules Name", 

63 }, 

64 }, 

65 "categories": { 

66 "main": "notary_public", 

67 "alternate": ["alternate_category1", "alternate_category2"], 

68 }, 

69 "confidence": 0.8, 

70 "websites": ["https://example.com"], 

71 "socials": ["www.facebook.com/example"], 

72 "phones": ["+1234567890"], 

73 "addresses": [ 

74 { 

75 "freeform": "123 Main St", 

76 "locality": "City", 

77 "postcode": "12345", 

78 "region": "CA", 

79 "country": "Country", 

80 } 

81 ], 

82 }, 

83 } 

84 ], 

85 } 

86 

87 

88@pytest.fixture(name="props_dict") 

89def props_fix() -> Dict[str, Any]: 

90 return { 

91 "id": "123", 

92 "version": 1, 

93 "update_time": "2022-01-01T00:00:00Z", 

94 "sources": [ 

95 { 

96 "property": "property1", 

97 "dataset": "dataset1", 

98 "record_id": "record1", 

99 "confidence": 0.8, 

100 } 

101 ], 

102 "names": { 

103 "primary": "Primary Name", 

104 "common": "Common Name", 

105 "rules": "Rules Name", 

106 }, 

107 "brand": { 

108 "wikidata": "Q123", 

109 "names": { 

110 "primary": "Brand Name", 

111 "common": "Common Name", 

112 "rules": "Rules Name", 

113 }, 

114 }, 

115 "categories": { 

116 "main": "notary_public", 

117 "alternate": ["alternate_category1", "alternate_category2"], 

118 }, 

119 "confidence": 0.8, 

120 "websites": ["https://example.com"], 

121 "socials": ["www.facebook.com/example"], 

122 "phones": ["+1234567890"], 

123 "addresses": [ 

124 { 

125 "freeform": "123 Main St", 

126 "locality": "City", 

127 "postcode": "12345", 

128 "region": "CA", 

129 "country": "Country", 

130 } 

131 ], 

132 } 

133 

134 

135def test_place_props(props_dict: dict, clean_dict: dict): 

136 """Test that all properties are processed correctly""" 

137 new_props = process_place(props_dict) 

138 assert new_props == clean_dict 

139 

140 

141def test_place_props_no_brand(props_dict: dict, clean_dict: dict): 

142 """Test that all properties are processed correctly""" 

143 props_dict.pop("brand", None) 

144 new_props = process_place(props_dict) 

145 for i in ["brand", "brand:wikidata"]: 

146 clean_dict.pop(i, None) 

147 assert new_props == clean_dict 

148 

149 

150def test_place_props_no_category(props_dict: dict, clean_dict: dict): 

151 """Test that all properties are processed correctly""" 

152 props_dict.pop("categories", None) 

153 new_props = process_place(props_dict) 

154 for i in ["office", "lawyer"]: 

155 clean_dict.pop(i, None) 

156 assert new_props == clean_dict 

157 

158 

159def test_place_props_twitter(props_dict: dict, clean_dict: dict) -> None: 

160 """Test that all properties are processed correctly""" 

161 props_dict["socials"].append("https://twitter.com/example") 

162 new_props = process_place(props_dict) 

163 clean_dict["contact:twitter"] = "https://twitter.com/example" 

164 assert new_props == clean_dict 

165 

166 

167def test_low_confidence(props_dict): 

168 """Test that properties with low confidence are not processed""" 

169 with pytest.raises(ConfidenceError): 

170 process_place(props_dict, confidence=0.9) 

171 

172 

173def test_confidence(props_dict): 

174 """Test that invalid properties are not processed""" 

175 props_dict["confidence"] = -0.1 

176 with pytest.raises(pydantic.ValidationError): 

177 process_place(props_dict) 

178 

179 

180def test_unmatched_error(props_dict): 

181 """Test that invalid properties are not processed""" 

182 props_dict["categories"]["main"] = "invalid_category" 

183 with pytest.raises(UnmatchedError): 

184 process_place(props_dict, unmatched="error") 

185 

186 

187def test_unmatched_ignore(props_dict, clean_dict: dict): 

188 """Test that invalid properties are not processed""" 

189 props_dict["categories"]["main"] = "invalid_category" 

190 for i in ["office", "lawyer"]: 

191 clean_dict.pop(i, None) 

192 assert process_place(props_dict, unmatched="ignore") == clean_dict 

193 

194 

195def test_unmatched_force(props_dict, clean_dict: dict): 

196 """Test that invalid properties are not processed""" 

197 cat = "invalid_category" 

198 props_dict["categories"]["main"] = cat 

199 for i in ["office", "lawyer"]: 

200 clean_dict.pop(i, None) 

201 clean_dict["type"] = cat 

202 assert process_place(props_dict, unmatched="force") == clean_dict 

203 

204 

205def test_place_geojson(geojson_dict, clean_dict: dict): 

206 """Test that all properties are processed correctly""" 

207 assert process_geojson(geojson=geojson_dict, fx=process_place) == { 

208 "type": "FeatureCollection", 

209 "features": [ 

210 { 

211 "type": "Feature", 

212 "geometry": {"type": "Point", "coordinates": [-1, 1]}, 

213 "properties": clean_dict, 

214 } 

215 ], 

216 } 

217 

218 

219def test_place_geojson_error(geojson_dict): 

220 """Test that all properties are processed correctly when error flag is set""" 

221 copy = deepcopy(geojson_dict) 

222 copy["features"][0]["properties"]["categories"]["main"] = "invalid_category" 

223 assert process_geojson( 

224 geojson=copy, fx=process_place, options={"unmatched": "error"} 

225 ) == { 

226 "type": "FeatureCollection", 

227 "features": [], 

228 } 

229 

230 

231def test_place_geojson_force(geojson_dict, clean_dict: dict) -> None: 

232 """Test that all properties are processed correctly when force flag is set""" 

233 copy = deepcopy(geojson_dict) 

234 copy["features"][0]["properties"]["categories"]["main"] = "invalid_category" 

235 clean_dict["type"] = "invalid_category" 

236 for i in ["office", "lawyer"]: 

237 clean_dict.pop(i, None) 

238 assert process_geojson( 

239 geojson=copy, fx=process_place, options={"unmatched": "force"} 

240 ) == { 

241 "type": "FeatureCollection", 

242 "features": [ 

243 { 

244 "type": "Feature", 

245 "geometry": {"type": "Point", "coordinates": [-1, 1]}, 

246 "properties": clean_dict, 

247 } 

248 ], 

249 } 

250 

251 

252def test_place_geojson_ignore(geojson_dict, clean_dict: dict) -> None: 

253 """Test that all properties are processed correctly when ignore flag is set""" 

254 copy = deepcopy(geojson_dict) 

255 copy["features"][0]["properties"]["categories"]["main"] = "invalid_category" 

256 for i in ["office", "lawyer"]: 

257 clean_dict.pop(i, None) 

258 assert process_geojson( 

259 geojson=copy, fx=process_place, options={"unmatched": "ignore"} 

260 ) == { 

261 "type": "FeatureCollection", 

262 "features": [ 

263 { 

264 "type": "Feature", 

265 "geometry": {"type": "Point", "coordinates": [-1, 1]}, 

266 "properties": clean_dict, 

267 } 

268 ], 

269 }