1package authoring23import (4 "path/filepath"5 "strings"6 "testing"7)89func TestAcquisitionIdentityIsSharedAcrossBindingsAndVersionsInputs(t *testing.T) {10 first := Request{11 Kind: RequestFeatures, Source: "sample-places", Adapter: "geojson",12 IdentityLocator: "https://example.invalid/sample-region.geojson", MediaType: "application/geo+json",13 }14 second := first15 second.Source = "alternate-places"16 finalizeRequest(&first)17 finalizeRequest(&second)18 if first.AcquisitionID != second.AcquisitionID {19 t.Fatalf("same acquisition has different identities: %s != %s", first.AcquisitionID, second.AcquisitionID)20 }21 if first.ID == second.ID {22 t.Fatal("distinct source bindings share a request identity")23 }24 changed := first25 changed.MediaType = "application/json"26 finalizeRequest(&changed)27 if changed.AcquisitionID == first.AcquisitionID {28 t.Fatal("Accept/media type did not change acquisition identity")29 }30}3132func TestMappingAndPresentationChangesReuseAcquisitionEvidence(t *testing.T) {33 project, err := LoadProject(filepath.Join("..", "..", "examples", "sample-region"+ProjectExtension))34 if err != nil {35 t.Fatal(err)36 }37 first, err := PlanProject(project, nil, t.TempDir())38 if err != nil {39 t.Fatal(err)40 }41 project.Sources[0].Mapping.FeatureTitle = "properties.alternate_name"42 project.Presentation.Styles[0].Fill = "#123456"43 second, err := PlanProject(project, nil, first.Output)44 if err != nil {45 t.Fatal(err)46 }47 if first.ProjectDigest == second.ProjectDigest {48 t.Fatal("mapping/presentation policy did not change the project digest")49 }50 if len(first.Requests) != len(second.Requests) {51 t.Fatalf("request count changed: %d != %d", len(first.Requests), len(second.Requests))52 }53 for index := range first.Requests {54 if first.Requests[index].ID != second.Requests[index].ID || first.Requests[index].AcquisitionID != second.Requests[index].AcquisitionID {55 t.Fatalf("policy change invalidated evidence request %d", index)56 }57 }58}5960func TestWMTSPlansAnExplicitPortableWindow(t *testing.T) {61 project := Project{baseDir: t.TempDir()}62 raster := Raster{63 ID: "background", Name: "Sample Background", Adapter: "wmts",64 Locator: "https://example.invalid/tiles/{TileMatrix}/{TileRow}/{TileCol}.png",65 MediaType: "image/png", License: "Example data", Attribution: "Sample Region contributors", TileSize: 256,66 Levels: []RasterLevel{{Zoom: 0, MinX: 0, MinY: 0, MaxX: 0, MaxY: 0}, {Zoom: 1, MinX: 0, MinY: 0, MaxX: 1, MaxY: 1}},67 }68 if err := validateRaster(raster); err != nil {69 t.Fatal(err)70 }71 requests, _, _, err := rasterRequests(project, raster, defaultBuildBudgets)72 if err != nil {73 t.Fatal(err)74 }75 if len(requests) != 5 || requests[0].AdapterVersion != "wmts-rest/v1" {76 t.Fatalf("WMTS plan = %d requests, version %q", len(requests), requests[0].AdapterVersion)77 }78 for _, request := range requests {79 if strings.Contains(request.IdentityLocator, "{") || request.AcquisitionID == "" {80 t.Fatalf("unresolved WMTS request: %+v", request)81 }82 }83}8485func TestRasterPlanRefusesExplosiveWindowBeforeEnumeration(t *testing.T) {86 project := Project{baseDir: t.TempDir()}87 raster := Raster{88 ID: "background", Adapter: "xyz", Locator: "https://example.invalid/{z}/{x}/{y}.png", TileSize: 256,89 Levels: []RasterLevel{{Zoom: 30, MinX: 0, MinY: 0, MaxX: 1<<30 - 1, MaxY: 1<<30 - 1}},90 }91 budgets := defaultBuildBudgets92 budgets.RasterTiles = 1093 if _, _, _, err := rasterRequests(project, raster, budgets); err == nil || !strings.Contains(err.Error(), "tile budget") {94 t.Fatalf("explosive raster plan = %v", err)95 }96}9798func TestBuildBudgetsResolveStableDefaultsAndRejectInversion(t *testing.T) {99 resolved, err := (BuildBudgets{}).resolved()100 if err != nil || resolved != defaultBuildBudgets {101 t.Fatalf("resolved defaults = %+v, %v", resolved, err)102 }103 if _, err := (BuildBudgets{RequestBytes: 2, TotalBytes: 1}).resolved(); err == nil {104 t.Fatal("request budget larger than total was accepted")105 }106 if _, err := (BuildBudgets{Features: -1}).resolved(); err == nil {107 t.Fatal("negative feature budget was accepted")108 }109 if _, err := (BuildBudgets{GeometryPositions: -1}).resolved(); err == nil {110 t.Fatal("negative geometry-position budget was accepted")111 }112}