Packages/MoonriseKit/Tests/SkyRendererTests/SkyRenderTests.swift
79 lines · 3410 bytes
1import Foundation
2import SkyEngine
3import SwiftUI
4import Testing
5@testable import SkyRenderer
6
7let chicago = Observer(latitude: 41.8781, longitude: -87.6298)
8let evening = Date(timeIntervalSince1970: 1_792_202_400) // 2026-10-17T02:00:00Z, 21:00 CDT
9
10@Test func catalogLoads() {
11 #expect(Catalog.stars.count > 9_000)
12 #expect(Catalog.stars.contains { $0.hr == 2491 && $0.magnitude < -1 }) // Sirius
13}
14
15@Test func sceneHasSaturnUpAndMarsDown() throws {
16 let scene = try SkyScene(date: evening, observer: chicago)
17 let saturn = try #require(scene.bodies.first { $0.body == .saturn })
18 let mars = try #require(scene.bodies.first { $0.body == .mars })
19 #expect(saturn.position.altitude > 30)
20 #expect(mars.position.altitude < 0)
21}
22
23/// Renders the sky to a PNG and reports timings. Set SKY_RENDER_OUT to keep the image.
24@MainActor
25@Test func renderStaticSky() throws {
26 let clock = ContinuousClock()
27 var scene: SkyScene!
28 let build = try clock.measure { scene = try SkyScene(date: evening, observer: chicago) }
29
30 let renderer = ImageRenderer(content: SkyView(scene: scene).frame(width: 393, height: 852))
31 renderer.scale = 3
32 var image: CGImage?
33 let render = clock.measure { image = renderer.cgImage }
34 let cg = try #require(image)
35
36 print("scene: \(scene.stars.count) stars, build \(build); render \(cg.width)x\(cg.height) in \(render)")
37
38 if let out = ProcessInfo.processInfo.environment["SKY_RENDER_OUT"] {
39 let url = URL(fileURLWithPath: out)
40 let dest = try #require(CGImageDestinationCreateWithURL(url as CFURL, "public.png" as CFString, 1, nil))
41 CGImageDestinationAddImage(dest, cg, nil)
42 #expect(CGImageDestinationFinalize(dest))
43 }
44}
45
46@Test func tapOnSaturnFindsSaturnAndNearbyStarsFindTheirConstellation() throws {
47 let scene = try SkyScene(date: evening, observer: chicago)
48 let p = Projection(centerAzimuth: 180, centerAltitude: 45, fieldOfView: 100, size: CGSize(width: 393, height: 852))
49 let saturn = try #require(scene.bodies.first { $0.body == .saturn })
50 let pt = try #require(p.point(saturn.position))
51 #expect(scene.object(at: CGPoint(x: pt.x + 5, y: pt.y), projection: p) == .body(.saturn))
52
53 // Altair (HR 7557) is in Aquila's figure.
54 let altair = try #require(scene.starsByHR[7557])
55 let a = try #require(p.point(altair))
56 #expect(scene.object(at: a, projection: p) == .constellation("Aql"))
57}
58
59@MainActor
60@Test func nightStyleRenders() throws {
61 let scene = try SkyScene(date: evening, observer: chicago)
62 let renderer = ImageRenderer(content: SkyView(scene: scene, style: .night).frame(width: 393, height: 852))
63 #expect(renderer.cgImage != nil)
64}
65
66@Test func skyCulturesUseCatalogueStars() {
67 let cultures = Catalog.skyCultures
68 #expect(cultures.count == 10)
69 let known = Set(Catalog.stars.map(\.hr))
70 for c in cultures {
71 #expect(!c.constellations.isEmpty, "\(c.id)")
72 #expect(c.licence.contains("BY-SA") || c.licence.contains("BY SA"), "\(c.id)")
73 for f in c.constellations {
74 #expect(f.lines.allSatisfy { $0.count > 1 && $0.allSatisfy(known.contains) }, "\(c.id) \(f.name)")
75 }
76 }
77 // The Norse Wolf's Mouth is the Hyades and includes Aldebaran (HR 1457).
78 #expect(cultures.first { $0.id == "norse" }?.constellations.contains { $0.name == "Wolf's Mouth" && $0.lines.joined().contains(1457) } == true)
79}