forked from OurHike/OurHike
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcredits.test.ts
More file actions
121 lines (105 loc) · 5.32 KB
/
Copy pathcredits.test.ts
File metadata and controls
121 lines (105 loc) · 5.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { describe, it, expect } from 'vitest'
import { mapCredits, OPENFREEMAP_CREDIT, OSM_CREDIT, USGS_TOPO_CREDIT } from './credits'
import { ELEVATION_ATTRIBUTION } from './terrain'
import { buildMapStyle } from './style'
// The corner used to be two composed strings naming every source the app could
// possibly draw. What that put on a fresh install's screen was five clauses,
// "© OpenStreetMap contributors" printed twice, and a credit for a 314 MB
// archive that was not on the phone. So the two properties asserted here are
// the two that were broken: nothing is said twice, and nothing is credited
// that is not drawing.
const STYLE_OPTIONS = {
topoArchiveUrl: 'pmtiles://corridor',
trailsUrl: '/data/trails.geojson',
terrain: { demUrl: 'dem://tiles', contourTilesUrl: 'contours://tiles' },
}
/** Every distinct credit the built style's sources declare. */
function styleCredits(background: 'hiking_topo_live' | 'usgs_topo_offline'): Set<string> {
const sources = buildMapStyle({ ...STYLE_OPTIONS, background }).sources
const declared = new Set<string>()
for (const source of Object.values(sources) as { attribution?: string }[]) {
// Split, because a source declares everything IT brings on one line -
// the vector sheet brings OpenFreeMap's terms and ODbL together - while
// the corner says them one at a time.
for (const credit of (source.attribution ?? '').split(' · ')) {
if (credit !== '') declared.add(credit)
}
}
return declared
}
describe('mapCredits', () => {
it('never says the same thing twice', () => {
// The duplicate this replaces was not a typo. Two composed strings each
// correctly named OpenStreetMap - the sheet's licence and the app data's -
// and joining them printed it twice. Any later overlap does the same, so
// the property is asserted rather than the one pair that caused it.
for (const background of ['hiking_topo_live', 'usgs_topo_offline'] as const) {
for (const hasRasterArchive of [true, false]) {
const credits = mapCredits({ background, hasRasterArchive })
expect(new Set(credits).size).toBe(credits.length)
}
}
})
it('leads with OpenStreetMap in every state, because that is the line that survives collapsing', () => {
// MapAttribution shows credits[0] and hides the rest behind a tap on a
// phone. ODbL is the licence with the prominence requirement, so it has to
// be the one that stays - and it has to stay FIRST in every state, or the
// summary line would reshuffle as a download lands.
for (const background of ['hiking_topo_live', 'usgs_topo_offline'] as const) {
for (const hasRasterArchive of [true, false]) {
expect(mapCredits({ background, hasRasterArchive })[0]).toBe(OSM_CREDIT)
}
}
})
it('does not credit USGS on a phone with no corridor raster on it', () => {
// The reported bug, at its plainest: a fresh install draws no USGS tile
// anywhere, and said "USGS US Topo" in the corner regardless.
expect(
mapCredits({ background: 'hiking_topo_live', hasRasterArchive: false }),
).not.toContain(USGS_TOPO_CREDIT)
expect(
mapCredits({ background: 'usgs_topo_offline', hasRasterArchive: false }),
).not.toContain(USGS_TOPO_CREDIT)
})
it('credits USGS once the archive is on the phone, under either background', () => {
// Under the live sheet too: style.ts stacks the sheet OVER the raster
// rather than replacing it, and the sheet's fills do not cover the whole
// canvas - the archive shows through, so it is being drawn.
expect(
mapCredits({ background: 'hiking_topo_live', hasRasterArchive: true }),
).toContain(USGS_TOPO_CREDIT)
expect(
mapCredits({ background: 'usgs_topo_offline', hasRasterArchive: true }),
).toContain(USGS_TOPO_CREDIT)
})
it('credits the live sheet and its elevation only while the live sheet is drawn', () => {
const live = mapCredits({ background: 'hiking_topo_live' })
expect(live).toContain(OPENFREEMAP_CREDIT)
expect(live).toContain(ELEVATION_ATTRIBUTION)
// The offline background makes NO background request at all
// (MAP_OPTIONS.md §1), so there is nothing of either to credit.
const offline = mapCredits({ background: 'usgs_topo_offline' })
expect(offline).not.toContain(OPENFREEMAP_CREDIT)
expect(offline).not.toContain(ELEVATION_ATTRIBUTION)
})
it('says only what a source in the style declares - the corner cannot invent a credit', () => {
for (const background of ['hiking_topo_live', 'usgs_topo_offline'] as const) {
const declared = styleCredits(background)
for (const credit of mapCredits({ background, hasRasterArchive: true })) {
expect(declared).toContain(credit)
}
}
})
it('says everything the style declares, once a phone is holding all of it', () => {
// The other direction, and the one that stops a source being added in
// style.ts and going uncredited in the corner. Asserted with the archive
// present, since that is the only state in which every source in the style
// is actually drawing.
for (const background of ['hiking_topo_live', 'usgs_topo_offline'] as const) {
const credits = new Set(mapCredits({ background, hasRasterArchive: true }))
for (const declared of styleCredits(background)) {
expect(credits).toContain(declared)
}
}
})
})