harshith99 Claude Sonnet 4.6 commited on
Commit
1fec3cb
Β·
1 Parent(s): 291da19

Test: export.build_kml coordinate invariants (regression for coord-less KML)

Browse files

Five new checks in test_pipeline.py guard against places_map.kml being
generated without <Point><coordinates> elements when geocoded rows exist:
build_kml writes coords, omits Point for ungeocoded rows, correct pinned
count in mixed batches, full export→import round-trip, and export.run()
end-to-end via a temp CSV.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. tests/test_pipeline.py +99 -0
tests/test_pipeline.py CHANGED
@@ -334,6 +334,100 @@ https://www.instagram.com/p/ABC123/]]></description>
334
  check("KML import: flat Placemark name", flat_rows[0]["name"] == "Mystery Place")
335
 
336
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  # ── FOOD_CATEGORIES sync invariant ────────────────────────────────────────────
338
 
339
  def test_food_categories_sync():
@@ -674,6 +768,11 @@ test_parse_response()
674
  test_parse_responses_dedup()
675
  test_parse_import_csv()
676
  test_parse_import_kml()
 
 
 
 
 
677
  test_food_categories_sync()
678
  test_parse_batch_response_none_guard()
679
  test_parse_batch_response_empty_string()
 
334
  check("KML import: flat Placemark name", flat_rows[0]["name"] == "Mystery Place")
335
 
336
 
337
+ # ── export.build_kml ─────────────────────────────────────────────────────────
338
+
339
+ def _row(**overrides) -> dict:
340
+ """Minimal valid row dict for export tests."""
341
+ base = {
342
+ "name": "Ichiran", "city": "Tokyo", "state": "Tokyo", "country": "Japan",
343
+ "address": "UNKNOWN", "category": "Restaurant", "cuisine": "Ramen",
344
+ "price_range": "$$", "highlight": "Best ramen", "occasion": "UNKNOWN",
345
+ "lat": "35.6595000", "lng": "139.7005000", "creator": "ramenking",
346
+ "saved_at": "2024-03-15", "instagram_url": "https://instagram.com/p/abc",
347
+ "status": "unvisited",
348
+ }
349
+ base.update(overrides)
350
+ return base
351
+
352
+
353
+ def test_build_kml_writes_coordinates():
354
+ from pipeline import export as export_mod
355
+ kml = export_mod.build_kml([_row()])
356
+ check("build_kml: <Point> present for geocoded row", "<Point>" in kml)
357
+ check("build_kml: <coordinates> tag present", "<coordinates>" in kml)
358
+ check("build_kml: lng,lat,alt order correct", "139.7005000,35.6595000,0" in kml)
359
+
360
+
361
+ def test_build_kml_omits_point_for_no_coords():
362
+ from pipeline import export as export_mod
363
+ kml = export_mod.build_kml([_row(lat="", lng="")])
364
+ check("build_kml: no <Point> for ungeocoded row", "<Point>" not in kml)
365
+ check("build_kml: no <coordinates> for ungeocoded row", "<coordinates>" not in kml)
366
+
367
+
368
+ def test_build_kml_mixed_pinned_count():
369
+ """Only geocoded rows emit <Point>; ungeocoded rows are included but pin-free."""
370
+ from pipeline import export as export_mod
371
+ rows = [
372
+ _row(name="Geocoded"),
373
+ _row(name="Not Geocoded", lat="", lng=""),
374
+ _row(name="Also Geocoded", lat="34.6937", lng="135.5023"),
375
+ ]
376
+ kml = export_mod.build_kml(rows)
377
+ import xml.etree.ElementTree as ET
378
+ root = ET.fromstring(kml)
379
+ ns = "http://www.opengis.net/kml/2.2"
380
+ coords = root.findall(f".//{{{ns}}}coordinates")
381
+ placemarks = root.findall(f".//{{{ns}}}Placemark")
382
+ check("build_kml: 3 placemarks total", len(placemarks) == 3)
383
+ check("build_kml: exactly 2 <coordinates> for 2 geocoded rows", len(coords) == 2)
384
+
385
+
386
+ def test_build_kml_coordinates_roundtrip():
387
+ """export.build_kml β†’ _parse_import_kml preserves lat/lng exactly."""
388
+ from pipeline import export as export_mod
389
+ from web.app import _parse_import_kml
390
+ rows_in = [
391
+ _row(name="Ichiran"),
392
+ _row(name="No Coord Cafe", lat="", lng=""),
393
+ ]
394
+ kml_bytes = export_mod.build_kml(rows_in).encode("utf-8")
395
+ rows_out = _parse_import_kml(kml_bytes)
396
+ geocoded = [r for r in rows_out if r.get("lat") and r.get("lng")]
397
+ check("roundtrip: 1 geocoded row survives", len(geocoded) == 1)
398
+ check("roundtrip: lat preserved", geocoded[0]["lat"] == "35.6595000")
399
+ check("roundtrip: lng preserved", geocoded[0]["lng"] == "139.7005000")
400
+ check("roundtrip: name preserved", geocoded[0]["name"] == "Ichiran")
401
+ check("roundtrip: total row count unchanged", len(rows_out) == 2)
402
+
403
+
404
+ def test_export_run_writes_coordinates():
405
+ """export.run() reads a CSV with geocoded rows and writes <Point> elements."""
406
+ import csv as _csv, tempfile, xml.etree.ElementTree as ET
407
+ from pipeline import export as export_mod
408
+ from pipeline.extract import FIELDNAMES
409
+
410
+ rows = [_row(name="Ichiran"), _row(name="No Coord", lat="", lng="")]
411
+
412
+ with tempfile.TemporaryDirectory() as d:
413
+ csv_path = f"{d}/places_full.csv"
414
+ kml_path = f"{d}/places_map.kml"
415
+ with open(csv_path, "w", newline="", encoding="utf-8") as f:
416
+ w = _csv.DictWriter(f, fieldnames=FIELDNAMES)
417
+ w.writeheader()
418
+ w.writerows(rows)
419
+
420
+ export_mod.run(csv_path, kml_path)
421
+
422
+ kml_content = open(kml_path, encoding="utf-8").read()
423
+ root = ET.fromstring(kml_content)
424
+ ns = "http://www.opengis.net/kml/2.2"
425
+ coords = root.findall(f".//{{{ns}}}coordinates")
426
+ check("export.run: KML file written", len(kml_content) > 0)
427
+ check("export.run: exactly 1 <coordinates> for 1 geocoded row", len(coords) == 1)
428
+ check("export.run: coordinate value correct", "139.7005" in (coords[0].text or ""))
429
+
430
+
431
  # ── FOOD_CATEGORIES sync invariant ────────────────────────────────────────────
432
 
433
  def test_food_categories_sync():
 
768
  test_parse_responses_dedup()
769
  test_parse_import_csv()
770
  test_parse_import_kml()
771
+ test_build_kml_writes_coordinates()
772
+ test_build_kml_omits_point_for_no_coords()
773
+ test_build_kml_mixed_pinned_count()
774
+ test_build_kml_coordinates_roundtrip()
775
+ test_export_run_writes_coordinates()
776
  test_food_categories_sync()
777
  test_parse_batch_response_none_guard()
778
  test_parse_batch_response_empty_string()