Files
astro/internal/ephem/stack_test.go
T

128 lines
3.7 KiB
Go
Raw Normal View History

package ephem
import (
"errors"
"testing"
)
type stackTestEngine struct {
bodies []Body
pairs map[[2]Body][3]float64
start float64
end float64
}
func (engine stackTestEngine) State(target, center Body, jdTDB float64) (pos, vel [3]float64, err error) {
if value, ok := engine.pairs[[2]Body{target, center}]; ok && jdTDB >= engine.start && jdTDB <= engine.end {
pos = value
return pos, vel, nil
}
for _, body := range engine.bodies {
if body == target || body == center {
return pos, vel, ErrOutOfRange
}
}
return pos, vel, ErrUnsupportedBody
}
func (engine stackTestEngine) Coverage(target Body) (start, end float64, ok bool) {
for _, body := range engine.bodies {
if body == target {
return engine.start, engine.end, true
}
}
return 0, 0, false
}
func (engine stackTestEngine) Bodies() []Body { return append([]Body(nil), engine.bodies...) }
func TestStackComposesAcrossSources(t *testing.T) {
first := stackTestEngine{
bodies: []Body{Sun, SSB},
pairs: map[[2]Body][3]float64{
{Sun, SSB}: {10, 20, 30},
},
start: 0,
end: 3000000,
}
second := stackTestEngine{
bodies: []Body{Body(2000001), Sun},
pairs: map[[2]Body][3]float64{
{Body(2000001), Sun}: {1, 2, 3},
},
start: 0,
end: 3000000,
}
stack := NewStack(first, second)
pos, _, err := stack.State(Body(2000001), SSB, 2451545)
if err != nil {
t.Fatal(err)
}
if pos != [3]float64{11, 22, 33} {
t.Fatalf("position = %v", pos)
}
}
func TestStackFirstSourceWinsDirectState(t *testing.T) {
first := stackTestEngine{bodies: []Body{Mars, Earth}, pairs: map[[2]Body][3]float64{{Mars, Earth}: {1, 2, 3}}, start: 0, end: 10}
second := stackTestEngine{bodies: []Body{Mars, Earth}, pairs: map[[2]Body][3]float64{{Mars, Earth}: {4, 5, 6}}, start: 0, end: 10}
pos, _, err := NewStack(first, second).State(Mars, Earth, 5)
if err != nil || pos != [3]float64{1, 2, 3} {
t.Fatalf("state = %v, %v", pos, err)
}
}
func TestStackErrorPriority(t *testing.T) {
engine := stackTestEngine{bodies: []Body{Mars}, start: 0, end: 1}
_, _, err := NewStack(engine).State(Mars, Earth, 2)
if !errors.Is(err, ErrOutOfRange) {
t.Fatalf("error = %v", err)
}
}
func TestStackGenericApparentAcceptsArbitraryBody(t *testing.T) {
engine := stackTestEngine{
bodies: []Body{Earth, Sun, Body(2000001), SSB},
pairs: map[[2]Body][3]float64{
{Earth, SSB}: {0, 0, 0},
{Sun, SSB}: {1000000, 0, 0},
{Body(2000001), SSB}: {1001000, 0, 0},
},
start: 0,
end: 3000000,
}
instance := NewInstance(NewStack(engine))
if _, distance, _, err := instance.Apparent(Body(2000001), 2451545); err != nil || distance != 1001000 {
t.Fatalf("apparent distance = %.3f, err = %v", distance, err)
}
}
func BenchmarkStackStateChain(b *testing.B) {
first := stackTestEngine{bodies: []Body{Sun, SSB}, pairs: map[[2]Body][3]float64{{Sun, SSB}: {10, 20, 30}}, start: 0, end: 3000000}
second := stackTestEngine{bodies: []Body{Body(2000001), Sun}, pairs: map[[2]Body][3]float64{{Body(2000001), Sun}: {1, 2, 3}}, start: 0, end: 3000000}
stack := NewStack(first, second)
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, _, err := stack.State(Body(2000001), SSB, 2451545); err != nil {
b.Fatal(err)
}
}
}
func TestStackChainBeyondInlineCapacity(t *testing.T) {
bodies := []Body{SSB}
pairs := map[[2]Body][3]float64{}
previous := SSB
for index := 0; index < 2*stackInlineBodies; index++ {
body := Body(3000000 + index)
bodies = append(bodies, body)
pairs[[2]Body{body, previous}] = [3]float64{1, 0, 0}
previous = body
}
engine := stackTestEngine{bodies: bodies, pairs: pairs, start: 0, end: 10}
pos, _, err := NewStack(engine).State(previous, SSB, 5)
if err != nil || pos != [3]float64{2 * stackInlineBodies, 0, 0} {
t.Fatalf("state = %v, %v", pos, err)
}
}