88import java .io .StringReader ;
99import java .net .URI ;
1010import java .util .List ;
11+ import java .util .Map ;
1112
1213import org .junit .jupiter .api .Test ;
1314import org .openstreetmap .josm .plugins .mapwithai .data .mapwithai .MapWithAICategory ;
1617import org .openstreetmap .josm .testutils .annotations .BasicPreferences ;
1718
1819import jakarta .json .Json ;
20+ import jakarta .json .JsonObject ;
1921
2022/**
2123 * Test class for {@link OvertureSourceReader}
2224 */
2325@ BasicPreferences
2426class OvertureSourceReaderTest {
27+ private static final String STAC = "https://stac.overturemaps.org/" ;
28+ private static final String ROOT = """
29+ {"type":"Catalog","id":"Overture Releases","stac_version":"1.1.0","latest":"2026-09-23.1",
30+ "links":[{"rel":"child","href":"https://stac.overturemaps.org/2026-08-19.0/catalog.json","title":"2026-08-19.0 Overture Release"},
31+ {"rel":"child","href":"https://stac.overturemaps.org/2026-09-23.1/catalog.json","title":"2026-09-23.1 Overture Release","latest":true},
32+ {"rel":"self","href":"https://stac.overturemaps.org/catalog.json"}]}""" ;
33+ private static final String RELEASE = """
34+ {"type":"Catalog","id":"2026-09-23.1","stac_version":"1.1.0",
35+ "links":[{"rel":"root","href":"https://stac.overturemaps.org/catalog.json"},
36+ {"rel":"child","href":"https://stac.overturemaps.org/2026-09-23.1/addresses/catalog.json","title":"addresses"},
37+ {"rel":"child","href":"https://stac.overturemaps.org/2026-09-23.1/buildings/catalog.json","title":"buildings"},
38+ {"rel":"child","href":"https://stac.overturemaps.org/2026-09-23.1/divisions/catalog.json","title":"divisions"},
39+ {"rel":"child","href":"https://stac.overturemaps.org/2026-09-23.1/transportation/catalog.json","title":"transportation"}]}""" ;
40+
41+ private static String theme (String theme , boolean tiles ) {
42+ return "{\" type\" :\" Catalog\" ,\" id\" :\" " + theme + "\" ,\" links\" :[{\" rel\" :\" root\" ,\" href\" :\" " + STAC
43+ + "catalog.json\" }" + (tiles ? ",{\" rel\" :\" pmtiles\" ,\" href\" :\" https://tiles.overturemaps.org/2026-09-23.1/"
44+ + theme + ".pmtiles\" ,\" type\" :\" application/vnd.pmtiles\" }" : "" )
45+ + "]}" ;
46+ }
47+
48+ private static final Map <String , String > CATALOGS = Map .of (STAC + "2026-09-23.1/catalog.json" , RELEASE ,
49+ STAC + "2026-09-23.1/addresses/catalog.json" , theme ("addresses" , true ),
50+ STAC + "2026-09-23.1/buildings/catalog.json" , theme ("buildings" , true ),
51+ STAC + "2026-09-23.1/divisions/catalog.json" , theme ("divisions" , false ),
52+ STAC + "2026-09-23.1/transportation/catalog.json" , theme ("transportation" , true ));
53+
2554 private static List <MapWithAIInfo > parse (String json ) throws IOException {
26- final var source = new MapWithAIInfo ("Overture" , "https://stac.overturemaps.org/ catalog.json" );
55+ final var source = new MapWithAIInfo ("Overture" , STAC + " catalog.json" );
2756 source .setSourceType (MapWithAIType .OVERTURE );
2857 try (var reader = new OvertureSourceReader (source ) {
58+ @ Override
59+ protected JsonObject readObject (String url ) throws IOException {
60+ // Serve the canned catalogs instead of going to the network
61+ if (!CATALOGS .containsKey (url )) {
62+ throw new IOException ("Unexpected url: " + url );
63+ }
64+ try (var parser = Json .createParser (new StringReader (CATALOGS .get (url )))) {
65+ parser .next ();
66+ return parser .getObject ();
67+ }
68+ }
69+
2970 @ Override
3071 void readTileInformation (MapWithAIInfo info , URI uri , String releaseId ) {
3172 // Don't read the (remote) pmtiles headers in tests
3273 }
33- };
34- var sr = new StringReader (json );
35- var parser = Json .createParser (sr )) {
74+ }; var sr = new StringReader (json ); var parser = Json .createParser (sr )) {
3675 parser .next ();
3776 return reader .parseJson (parser );
3877 }
@@ -44,29 +83,39 @@ void readTileInformation(MapWithAIInfo info, URI uri, String releaseId) {
4483 */
4584 @ Test
4685 void testStacCatalog () throws IOException {
47- final var infos = parse ("""
48- {"type":"Catalog","id":"Overture Releases","stac_version":"1.1.0",
49- "links":[{"rel":"child","href":"https://stac.overturemaps.org/2026-09-23.1/catalog.json","latest":true}],
50- "latest":"2026-09-23.1"}""" );
51- assertEquals (5 , infos .size ());
86+ final var infos = parse (ROOT );
87+ // divisions has no tiles, transportation is skipped
88+ assertEquals (2 , infos .size (), infos .toString ());
5289 for (var info : infos ) {
5390 assertEquals (MapWithAIType .PMTILES , info .getSourceType ());
54- assertTrue (info .getUrl ().startsWith (
55- "https://overturemaps-extras-us-west-2.s3.us-west-2.amazonaws.com/tiles/2026-09-23.1/" ),
56- info .getUrl ());
57- assertTrue (info .getUrl ().endsWith (".pmtiles" ), info .getUrl ());
5891 assertTrue (info .hasValidUrl ());
92+ assertTrue (info .getName ().contains ("2026-09-23.1" ), info .getName ());
5993 }
6094 final var buildings = infos .stream ().filter (i -> i .getUrl ().endsWith ("/buildings.pmtiles" )).findFirst ()
6195 .orElseThrow ();
96+ assertEquals ("https://tiles.overturemaps.org/2026-09-23.1/buildings.pmtiles" , buildings .getUrl ());
6297 assertEquals (MapWithAICategory .BUILDING , buildings .getCategory ());
6398 // The id must not change between releases
6499 assertEquals ("Overture: buildings" , buildings .getId ());
100+ final var addresses = infos .stream ().filter (i -> i .getUrl ().endsWith ("/addresses.pmtiles" )).findFirst ()
101+ .orElseThrow ();
102+ assertEquals (MapWithAICategory .ADDRESS , addresses .getCategory ());
103+ }
104+
105+ /**
106+ * The {@code latest} field is optional in STAC; fall back to the link marked as
107+ * latest.
108+ */
109+ @ Test
110+ void testStacCatalogWithoutLatest () throws IOException {
111+ assertEquals (2 , parse (ROOT .replace ("\" latest\" :\" 2026-09-23.1\" ," , "" )).size ());
65112 }
66113
67114 @ Test
68115 void testBadCatalog () throws IOException {
69116 assertTrue (parse ("{\" type\" :\" Catalog\" }" ).isEmpty ());
70- assertTrue (parse ("{\" latest\" :\" ../../something else\" }" ).isEmpty ());
117+ assertTrue (parse ("{\" type\" :\" Catalog\" ,\" links\" :[]}" ).isEmpty ());
118+ assertTrue (parse ("{\" type\" :\" Catalog\" ,\" latest\" :\" 2000-01-01.0\" ,\" links\" :[{\" rel\" :\" child\" ,"
119+ + "\" href\" :\" https://stac.overturemaps.org/2000-01-01.0/catalog.json\" }]}" ).isEmpty ());
71120 }
72121}
0 commit comments