1package authoring23import (4 "net/url"5 "path/filepath"6 "strings"7 "testing"8)910func TestAdapterRegistryIsTheSingleVersionAuthority(t *testing.T) {11 registry := defaultAdapterRegistry()12 tests := map[string]string{13 "geojson": "geojson/v1", "arcgis-feature-service": "arcgis-feature-service/v2",14 "ogc-api-features": "ogc-api-features/v2", "raster-file": "raster-file/v1",15 "xyz": "xyz/v1", "wmts": "wmts-rest/v1", "asset-file": "asset-file/v1",16 }17 for name, version := range tests {18 adapter, err := registry.Lookup(name)19 if err != nil || adapter.Version() != version {20 t.Fatalf("adapter %s = %v, %v", name, adapter, err)21 }22 }23 if _, err := registry.Lookup("unknown"); err == nil || !strings.Contains(err.Error(), "unknown adapter") {24 t.Fatalf("unknown adapter = %v", err)25 }26}2728func TestArcGISContinuationUsesStableOffsets(t *testing.T) {29 request := featureSetRequest("sample-roads", "arcgis-feature-service", "https://example.invalid/FeatureServer/0/query?f=geojson&resultRecordCount=2")30 adapter, err := defaultAdapterRegistry().Lookup(request.Adapter)31 if err != nil {32 t.Fatal(err)33 }34 decision, err := adapter.Next(request, []byte(`{"type":"FeatureCollection","exceededTransferLimit":true,"features":[{"id":"a"},{"id":"b"}]}`), &PageProgress{})35 if err != nil {36 t.Fatal(err)37 }38 if decision.Done || !strings.Contains(decision.Next.IdentityLocator, "resultOffset=2") || decision.Returned != 2 {39 t.Fatalf("ArcGIS decision = %+v", decision)40 }41}4243func TestArcGISPaginationRefusesOverlapAndMissingContinuations(t *testing.T) {44 request := featureSetRequest("sample-roads", "arcgis-feature-service", "https://example.invalid/FeatureServer/0/query?f=geojson&resultRecordCount=2")45 adapter, err := defaultAdapterRegistry().Lookup(request.Adapter)46 if err != nil {47 t.Fatal(err)48 }49 progress := PageProgress{SeenIDs: make(map[string]bool)}50 first, err := adapter.Next(request, []byte(`{"type":"FeatureCollection","exceededTransferLimit":true,"features":[{"id":1},{"id":2}]}`), &progress)51 if err != nil {52 t.Fatal(err)53 }54 progress.Returned = first.Returned55 if _, err := adapter.Next(first.Next, []byte(`{"type":"FeatureCollection","features":[{"id":2},{"id":3}]}`), &progress); err == nil || !strings.Contains(err.Error(), "repeats object ID") {56 t.Fatalf("overlapping page = %v", err)57 }5859 progress = PageProgress{Returned: first.Returned, SeenIDs: map[string]bool{"1": true, "2": true}, LastID: "2"}60 if _, err := adapter.Next(first.Next, []byte(`{"type":"FeatureCollection","features":[]}`), &progress); err == nil || !strings.Contains(err.Error(), "missing") {61 t.Fatalf("missing continuation = %v", err)62 }63}6465func TestOGCPaginationRefusesDuplicateFeatureIDsAcrossPages(t *testing.T) {66 request := featureSetRequest("sample-roads", "ogc-api-features", "https://example.invalid/collections/sample/items")67 adapter, err := defaultAdapterRegistry().Lookup(request.Adapter)68 if err != nil {69 t.Fatal(err)70 }71 progress := PageProgress{RootLocator: request.IdentityLocator, SeenIDs: make(map[string]bool)}72 first, err := adapter.Next(request, []byte(`{"type":"FeatureCollection","numberReturned":1,"features":[{"id":"same"}],"links":[{"rel":"next","href":"?page=2"}]}`), &progress)73 if err != nil {74 t.Fatal(err)75 }76 progress.Returned = first.Returned77 if _, err := adapter.Next(first.Next, []byte(`{"type":"FeatureCollection","numberReturned":1,"features":[{"id":"same"}]}`), &progress); err == nil || !strings.Contains(err.Error(), "repeats object ID") {78 t.Fatalf("duplicate OGC page = %v", err)79 }80}8182func TestArcGISPlanAlwaysCarriesTheConfiguredSpatialEnvelope(t *testing.T) {83 project, err := LoadProject(filepath.Join("..", "..", "examples", "sample-region"+ProjectExtension))84 if err != nil {85 t.Fatal(err)86 }87 source := project.Sources[0]88 source.Adapter = "arcgis-feature-service"89 source.Locator = "https://example.invalid/FeatureServer"90 source.Query.Layer = 291 source.Query.Limit = 50092 source.Query.ObjectID = "sample_id"93 source.Query.SpatialReference = 432694 request, err := featureRequest(project, source)95 if err != nil {96 t.Fatal(err)97 }98 parsed, err := url.Parse(request.IdentityLocator)99 if err != nil {100 t.Fatal(err)101 }102 query := parsed.Query()103 extent, err := sourceExtent(source.Mapping.Geometry, project.Target.CoordinateSpace)104 if err != nil {105 t.Fatal(err)106 }107 if parsed.Path != "/FeatureServer/2/query" || query.Get("geometry") != extentString(extent) || query.Get("geometryType") != "esriGeometryEnvelope" || query.Get("spatialRel") != "esriSpatialRelIntersects" || query.Get("resultRecordCount") != "500" || query.Get("resultOffset") != "0" || query.Get("orderByFields") != "sample_id ASC" || query.Get("inSR") != "4326" || query.Get("outSR") != "4326" {108 t.Fatalf("ArcGIS request = %s", request.IdentityLocator)109 }110}111112func TestArcGISPlanRefusesAnImplicitUnknownSpatialReference(t *testing.T) {113 project, err := LoadProject(filepath.Join("..", "..", "examples", "sample-region"+ProjectExtension))114 if err != nil {115 t.Fatal(err)116 }117 source := project.Sources[0]118 source.Adapter = "arcgis-feature-service"119 source.Locator = "https://example.invalid/FeatureServer/0"120 if _, err := featureRequest(project, source); err == nil || !strings.Contains(err.Error(), "spatial-reference") {121 t.Fatalf("implicit unknown ArcGIS spatial reference = %v", err)122 }123124 source.Mapping.Geometry.SourceSpace = "EPSG:4326"125 request, err := featureRequest(project, source)126 if err != nil {127 t.Fatal(err)128 }129 if !strings.Contains(request.IdentityLocator, "inSR=4326") || !strings.Contains(request.IdentityLocator, "outSR=4326") {130 t.Fatalf("recognized spatial reference request = %s", request.IdentityLocator)131 }132}