krz/moonrise

Night-sky companion for iPhone, Apple Watch and Vision Pro: what's up tonight, the Moon, planets, launches and missions, and a Library of the solar system. SwiftUI app with a Cloudflare Workers backend. astronomy cloudflare-workers ios night-sky space swiftui visionos watchos

Packages/MoonriseKit/Tests/LibraryTests/LibraryTests.swift

04b2b1d914788057bcd20945b876847386eb8f65
moonrise/Packages/MoonriseKit/Tests/LibraryTests/LibraryTests.swift history · blame · raw

115 lines · 5365 bytes

10 symbols in this file
  1import Foundation
  2import SkyEngine
  3import Testing
  4@testable import Library
  5@testable import SkyRenderer
  6
  7// Checks every bundled page against the rules in docs/library-content.org.
  8
  9let allowedLicences: Set<String> = ["Public domain", "CC BY 4.0", "CC BY-SA 3.0 IGO"]
 10
 11@Test func idsAreUnique() {
 12    let ids = Library.pages.map(\.id)
 13    #expect(Set(ids).count == ids.count, "duplicates: \(Dictionary(grouping: ids, by: { $0 }).filter { $1.count > 1 }.keys.sorted())")
 14}
 15
 16@Test(arguments: Library.pages)
 17func pageFollowsTheBrief(_ p: LibraryPage) {
 18    #expect(!p.title.isEmpty && !p.subtitle.isEmpty, "\(p.id): title/subtitle")
 19    #expect((1...5).contains(p.sources.count), "\(p.id): \(p.sources.count) sources")
 20    #expect((3...9).contains(p.facts.count), "\(p.id): \(p.facts.count) facts")
 21    for f in p.facts {
 22        #expect(p.sources.indices.contains(f.source), "\(p.id): fact '\(f.label)' cites missing source \(f.source)")
 23    }
 24    #expect(!p.sources.contains { $0.url.host()?.contains("wikipedia.org") == true }, "\(p.id): Wikipedia as a source")
 25    #expect((120...300).contains(p.wordCount), "\(p.id): essay \(p.wordCount) words")
 26    if let image = p.image {
 27        #expect(allowedLicences.contains(image.licence), "\(p.id): licence \(image.licence)")
 28        #expect(image.url.scheme == "https", "\(p.id): image URL")
 29        #expect(!image.credit.isEmpty, "\(p.id): image credit")
 30    } else {
 31        #expect([.constellations, .stars, .missions, .rockets].contains(p.section), "\(p.id): missing image")
 32    }
 33}
 34
 35@Test(arguments: Library.pages)
 36func linksPointAtThingsTheAppKnows(_ p: LibraryPage) {
 37    let l = p.link
 38    if let body = l.body { #expect(Body(rawValue: body) != nil, "\(p.id): body \(body)") }
 39    if let c = l.constellation { #expect(constellationNames[c] != nil, "\(p.id): constellation \(c)") }
 40    if let hr = l.hr { #expect(Catalog.stars.contains { $0.hr == hr }, "\(p.id): HR \(hr)") }
 41    if let m = l.messier { #expect((1...110).contains(m), "\(p.id): M\(m)") }
 42    if let s = l.spacecraft { #expect(Spacecraft.all.contains { $0.name == s }, "\(p.id): spacecraft \(s)") }
 43}
 44
 45@Test func searchFindsByTitleBeforeEssay() {
 46    guard let first = Library.pages.first else { return }
 47    #expect(Library.search(first.title).first?.id == first.id)
 48    #expect(Library.search("   ").isEmpty)
 49}
 50
 51@Test func scaleObjectsComeFromPages() {
 52    let objects = Library.scaleObjects
 53    #expect(objects.first?.name == "ISS")
 54    #expect(objects.last?.name == "Observable universe")
 55    #expect(objects.contains { $0.name == "Earth" && abs($0.meters - 12_742_000) < 1 })
 56    #expect(objects.contains { $0.page == "arcturus" })
 57    #expect(objects.contains { $0.page == "m31" })
 58    #expect(Set(objects.map(\.name)).count == objects.count)
 59    for o in objects where o.page != nil { #expect(Library.page(id: o.page!) != nil, "\(o.name)") }
 60}
 61
 62@Test func scaleSizeFormats() {
 63    #expect(Library.formatSize(109) == "109 m")
 64    #expect(Library.formatSize(12_742_000) == "12,742 km")
 65    #expect(Library.formatSize(2 * 30.07 * 1.495978707e11) == "60.1 AU")
 66    #expect(Library.formatSize(100_000 * 9.4607e15) == "100,000 light-years")
 67    #expect(Library.formatSize(93e9 * 9.4607e15) == "93 billion light-years")
 68}
 69
 70@Test func toursPointAtKnownThings() {
 71    #expect(Tour.all.count == 4)
 72    let constellations = Set(Catalog.constellations.map(\.id))
 73    let stars = Set(Catalog.stars.map(\.hr))
 74    for tour in Tour.all {
 75        #expect(!tour.steps.isEmpty)
 76        for step in tour.steps {
 77            let t = step.target
 78            #expect([t.constellation != nil, t.hr != nil, t.body != nil].filter { $0 }.count == 1, "\(tour.id) \(step.title)")
 79            if let c = t.constellation { #expect(constellations.contains(c), "\(c)") }
 80            if let hr = t.hr { #expect(stars.contains(hr), "\(hr)") }
 81            if let p = step.page { #expect(Library.page(id: p) != nil, "\(p)") }
 82        }
 83    }
 84    #expect(Set(Tour.all.flatMap(\.months)) == Set(1...12))
 85}
 86
 87@Test func toursStartWithTheSeason() {
 88    #expect(Tour.ordered(month: 1).first?.id == "winter")
 89    #expect(Tour.ordered(month: 7).first?.id == "summer")
 90    #expect(Tour.ordered(month: 11).map(\.id) == ["autumn", "winter", "spring", "summer"])
 91}
 92
 93@Test func storiesMatchSpacecraftAndPages() {
 94    #expect(MissionStory.all.count == 5)
 95    let craft = Set(Spacecraft.all.map(\.name))
 96    for s in MissionStory.all {
 97        #expect(craft.contains(s.spacecraft), "\(s.spacecraft)")
 98        #expect(Library.page(id: s.page)?.link.spacecraft == s.spacecraft, "\(s.page)")
 99        let days = s.chapters.map(\.day)
100        #expect(days == days.sorted(), "\(s.page) chapters out of order")
101        // After launch, every chapter falls within the trajectory data (which starts up to 30 days after launch).
102        let craftData = Spacecraft.all.first { $0.name == s.spacecraft }!
103        for c in s.chapters.dropFirst() { #expect(craftData.position(at: c.day) != nil, "\(s.page) \(c.date)") }
104    }
105}
106
107@Test func relatedPages() throws {
108    let saturn = try #require(Library.page(id: "saturn"))
109    let related = saturn.related().map(\.id)
110    #expect(related.contains("titan"))
111    #expect(related.contains("cassini-huygens"))
112    #expect(!related.contains("saturn"))
113    #expect(related.count <= 10)
114    #expect(Library.page(id: "europa")!.related().first?.id == "jupiter")
115}