Files
weatherreporter/internal/module/module_test.go

141 lines
4.7 KiB
Go

package module
import (
"encoding/json"
"strings"
"testing"
)
type testStanza struct {
Message string `json:"message"`
Count int `json:"count"`
}
func TestSnapshotPreservesOutputOrderAndJSON(t *testing.T) {
snapshot, err := NewSnapshot([]Output{
{
ID: Metadata,
StanzaName: "metadata",
Value: testStanza{Message: "first", Count: 1},
PromptValue: testStanza{Message: "prompt-only", Count: 10},
},
{ID: AlertDigest, StanzaName: "alert_digest", Value: testStanza{Message: "second", Count: 2}},
})
if err != nil {
t.Fatalf("NewSnapshot() error = %v", err)
}
if snapshot.SchemaVersion != SnapshotSchemaVersion {
t.Fatalf("SchemaVersion = %q, want %q", snapshot.SchemaVersion, SnapshotSchemaVersion)
}
if snapshot.Outputs[0].ID != Metadata || snapshot.Outputs[1].ID != AlertDigest {
t.Fatalf("Outputs order = %#v, want input order", snapshot.Outputs)
}
data, err := json.Marshal(snapshot)
if err != nil {
t.Fatalf("Marshal() error = %v", err)
}
got := string(data)
want := `{"schemaVersion":"weatherreporter.modules.v1","outputs":[{"id":"metadata","stanzaName":"metadata","value":{"message":"first","count":1}},{"id":"alert_digest","stanzaName":"alert_digest","value":{"message":"second","count":2}}]}`
if got != want {
t.Fatalf("json = %s, want %s", got, want)
}
if strings.Contains(got, "PromptValue") || strings.Contains(got, "promptValue") || strings.Contains(got, "prompt-only") {
t.Fatalf("json includes runtime-only prompt value: %s", got)
}
}
func TestOutputDataPackageValue(t *testing.T) {
output := Output{
ID: Metadata,
StanzaName: "metadata",
Value: testStanza{Message: "rich", Count: 1},
PromptValue: testStanza{Message: "prompt", Count: 2},
}
if got := output.DataPackageValue(); got != output.PromptValue {
t.Fatalf("DataPackageValue() = %#v, want prompt value", got)
}
output.PromptValue = nil
if got := output.DataPackageValue(); got != output.Value {
t.Fatalf("DataPackageValue() = %#v, want rich value fallback", got)
}
}
func TestSnapshotRejectsDuplicateOutputs(t *testing.T) {
_, err := NewSnapshot([]Output{
{ID: Metadata, StanzaName: "metadata", Value: struct{}{}},
{ID: Metadata, StanzaName: "other_metadata", Value: struct{}{}},
})
if err == nil || !strings.Contains(err.Error(), `duplicate module output "metadata"`) {
t.Fatalf("duplicate module error = %v, want duplicate module output", err)
}
_, err = NewSnapshot([]Output{
{ID: Metadata, StanzaName: "metadata", Value: struct{}{}},
{ID: CurrentConditions, StanzaName: "metadata", Value: struct{}{}},
})
if err == nil || !strings.Contains(err.Error(), `duplicate stanza name "metadata"`) {
t.Fatalf("duplicate stanza error = %v, want duplicate stanza name", err)
}
}
func TestStanzaValueDecodesTypedOutput(t *testing.T) {
snapshot, err := NewSnapshot([]Output{
{
ID: Metadata,
StanzaName: "metadata",
Value: testStanza{Message: "available", Count: 3},
PromptValue: testStanza{Message: "prompt-only", Count: 99},
},
})
if err != nil {
t.Fatalf("NewSnapshot() error = %v", err)
}
value, found, err := StanzaValue[testStanza](snapshot, "metadata")
if err != nil {
t.Fatalf("StanzaValue() error = %v", err)
}
if !found {
t.Fatal("StanzaValue() found = false, want true")
}
if value.Message != "available" || value.Count != 3 {
t.Fatalf("StanzaValue() = %#v, want decoded stanza", value)
}
_, found, err = StanzaValue[testStanza](snapshot, "missing")
if err != nil {
t.Fatalf("StanzaValue(missing) error = %v", err)
}
if found {
t.Fatal("StanzaValue(missing) found = true, want false")
}
}
func TestSPCConvectiveModuleContractsAreStable(t *testing.T) {
if SPCConvectiveOutlooks != ID("spc_convective_outlooks") {
t.Fatalf("SPCConvectiveOutlooks = %q, want stable source/module ID", SPCConvectiveOutlooks)
}
if SPCConvectiveDiscussion != ID("spc_convective_discussion") {
t.Fatalf("SPCConvectiveDiscussion = %q, want stable discussion module ID", SPCConvectiveDiscussion)
}
if CollectedSPCConvectiveOutlooks != FactRequirement("collected.spc_convective_outlooks") {
t.Fatalf("CollectedSPCConvectiveOutlooks = %q, want collected requirement", CollectedSPCConvectiveOutlooks)
}
if RequiresDerivedSPCConvectiveOutlooks != FactRequirement("derived.spc_convective_outlooks") {
t.Fatalf("RequiresDerivedSPCConvectiveOutlooks = %q, want derived requirement", RequiresDerivedSPCConvectiveOutlooks)
}
_ = SPCConvectiveOutlooksOptions{}
_ = SPCConvectiveDiscussionOptions{}
}
func TestDailyPlanningModuleContractIsStable(t *testing.T) {
if DailyPlanning != ID("daily_planning") {
t.Fatalf("DailyPlanning = %q, want stable module ID", DailyPlanning)
}
_ = DailyPlanningOptions{}
}