using System.Text.Json.Nodes; using Microsoft.Extensions.Options; using TileServer.Application.Configuration; using TileServer.Application.Extracts; using TileServer.Application.Styles; using TileServer.Application.Tiles; using TileServer.Domain.Extracts; using TileServer.Domain.Tiles; namespace TileServer.UnitTests; public sealed class StyleServiceTests { [Fact] public void Get_BindsAbsoluteTilesAndSourceMaxZoom() { var extract = new Extract { Id = "central-fed-district", Name = "ЦФО", Url = new Uri("https://download.geofabrik.de/russia/central-fed-district-latest.osm.pbf"), CenterLon = 37.6, CenterLat = 55.7, MinZoom = 0, MaxZoom = 14 }; var metadata = new TilesetMetadata( extract.Id, extract.Name, "pbf", 29.2, 48.7, 47.6, 59.6, 38.4, 54.2, 5, 0, 14, []); var template = new JsonObject { ["version"] = 8, ["name"] = "OSM Bright", ["sources"] = new JsonObject { ["openmaptiles"] = new JsonObject { ["type"] = "vector", ["url"] = "/api/v1/tiles/central-fed-district.json" } } }; var service = new StyleService( new MemoryStyleCatalog(template), new MemoryExtractCatalog(extract), new MemoryTileStore(metadata), Options.Create(new TileServerOptions { GlyphsUrl = "https://fonts.example/{fontstack}/{range}.pbf" })); var style = service.Get("osm-bright", extract.Id, "https://tile-server.ru"); var source = style["sources"]!["openmaptiles"]!.AsObject(); Assert.Null(source["url"]); Assert.Equal(0, source["minzoom"]!.GetValue()); Assert.Equal(14, source["maxzoom"]!.GetValue()); Assert.Equal("xyz", source["scheme"]!.GetValue()); Assert.Equal( "https://tile-server.ru/api/v1/tiles/central-fed-district/{z}/{x}/{y}.pbf?v=3", source["tiles"]!.AsArray()[0]!.GetValue()); Assert.Null(source["bounds"]); } [Fact] public void Bind_UsesPersonalTileUrlAndToken() { var extract = new Extract { Id = "central-fed-district", Name = "ЦФО", Url = new Uri("https://download.geofabrik.de/russia/central-fed-district-latest.osm.pbf"), CenterLon = 37.6, CenterLat = 55.7, MinZoom = 0, MaxZoom = 14 }; var metadata = new TilesetMetadata( extract.Id, extract.Name, "pbf", 29.2, 48.7, 47.6, 59.6, 38.4, 54.2, 5, 0, 14, []); var template = new JsonObject { ["version"] = 8, ["sources"] = new JsonObject { ["openmaptiles"] = new JsonObject { ["type"] = "vector" } } }; var service = new StyleService( new MemoryStyleCatalog(template), new MemoryExtractCatalog(extract), new MemoryTileStore(metadata), Options.Create(new TileServerOptions())); var tilesUrl = "https://tile-server.ru/u/alice/tiles/central-fed-district/{z}/{x}/{y}.pbf?v=3&token=ts_abc"; var style = service.Bind(template, extract.Id, tilesUrl); var tile = style["sources"]!["openmaptiles"]!["tiles"]!.AsArray()[0]!.GetValue(); Assert.Contains("/u/alice/", tile, StringComparison.Ordinal); Assert.Contains("token=ts_abc", tile, StringComparison.Ordinal); } private sealed class MemoryStyleCatalog(JsonObject style) : IStyleCatalog { public IReadOnlyList List() => [new("osm-bright", DateTimeOffset.UnixEpoch)]; public JsonObject GetRequired(string name) => JsonNode.Parse(style.ToJsonString())!.AsObject(); public Task SaveAsync(string name, JsonObject incoming, CancellationToken ct) => Task.CompletedTask; public Task SeedDefaultsAsync(CancellationToken ct) => Task.CompletedTask; } private sealed class MemoryExtractCatalog(Extract extract) : IExtractCatalog { public IReadOnlyList GetAll() => [extract]; public Extract? Find(string id) => id == extract.Id ? extract : null; public Extract GetRequired(string id) => Find(id) ?? throw new InvalidOperationException(id); public Task AddOrUpdateAsync(Extract incoming, CancellationToken ct) => Task.CompletedTask; public Task RemoveAsync(string id, CancellationToken ct) => Task.CompletedTask; } private sealed class MemoryTileStore(TilesetMetadata metadata) : ITileStore { public bool Exists(string extractId) => true; public Task GetTileAsync(string extractId, TileCoordinate tile, CancellationToken ct) => Task.FromResult(null); public TilesetMetadata? GetMetadata(string extractId) => metadata; public string GetActivePath(string extractId) => extractId; public string GetStagingPath(string extractId) => extractId + ".building.mbtiles"; public void Activate(string extractId, string stagingPath) { } } }