// TDD: solar position math — RFC-accurate NOAA algorithm, pure functions. const assert = require('node:assert/strict'); const fs = require('node:fs'); const src = fs.readFileSync('src/common/solar.js', 'utf8'); const mod = {}; new Function('module', 'exports', src)(mod, mod.exports || (mod.exports = {})); const { solarPosition, dayProgress, formatCountdown } = mod.exports; // Reference: NOAA solar calculator, 2026-09-09, Paris (48.8566, 2.3522), 12:00 UTC ≈ solar noon-ish const p = solarPosition(new Date('2026-09-09T12:00:00Z'), 48.8566, 2.3522); assert.ok(Number.isFinite(p.altitude) && Number.isFinite(p.azimuth), 'finite angles'); assert.ok(p.altitude > 35 && p.altitude < 60, `Paris noon September altitude ~45°, got ${p.altitude}`); // Night: same place, 00:30 UTC → sun below horizon const n = solarPosition(new Date('2026-09-09T00:30:00Z'), 48.8566, 2.3522); assert.ok(n.altitude < -20, `midnight Paris altitude strongly negative, got ${n.altitude}`); // Southern hemisphere summer: Sydney January noon → high sun const syd = solarPosition(new Date('2026-01-15T03:00:00Z'), -33.8688, 151.2093); assert.ok(syd.altitude > 55, `Sydney Jan noon altitude high, got ${syd.altitude}`); // dayProgress: 0 at sunrise, 1 at sunset, 0.5 ≈ solar noon const dp = dayProgress(new Date('2026-09-09T12:00:00Z'), 48.8566, 2.3522); assert.ok(dp > 0.4 && dp < 0.6, `midday progress ≈ 0.5, got ${dp}`); assert.equal(dayProgress(new Date('2026-09-09T00:30:00Z'), 48.8566, 2.3522), 0, 'before sunrise → 0'); assert.equal(dayProgress(new Date('2026-09-09T22:00:00Z'), 48.8566, 2.3522), 1, 'after sunset → 1'); // Polar night / midnight sun don't crash solarPosition(new Date('2026-06-21T12:00:00Z'), 78.22, 15.63); // Svalbard solarPosition(new Date('2026-12-21T12:00:00Z'), 78.22, 15.63); const polar = dayProgress(new Date('2026-12-21T12:00:00Z'), 78.22, 15.63); assert.ok(polar === 0 || polar === 1, 'polar night returns boundary'); // countdown formatting assert.equal(formatCountdown(3725), '1h 2m'); assert.equal(formatCountdown(600), '10m'); assert.equal(formatCountdown(45), '<1m'); assert.equal(formatCountdown(0), '0m'); console.log('ALL SOLAR MATH PASS');