Recognize NWS key points sections

This commit is contained in:
2026-08-03 00:15:52 +00:00
parent b8c6708439
commit 9a09454621
2 changed files with 107 additions and 4 deletions

View File

@@ -48,6 +48,7 @@ type forecastDiscussionSectionBlock struct {
var (
forecastDiscussionSectionRoles = map[string]forecastDiscussionSectionRole{
"KEY MESSAGES": forecastDiscussionSectionRoleKeyMessages,
"KEY POINTS": forecastDiscussionSectionRoleKeyMessages,
"SHORT TERM": forecastDiscussionSectionRoleShortTerm,
"LONG TERM": forecastDiscussionSectionRoleLongTerm,
}

View File

@@ -279,11 +279,29 @@ func TestParseForecastDiscussionSectionHeading(t *testing.T) {
}
func TestForecastDiscussionSectionRoleHeadingsParse(t *testing.T) {
if len(forecastDiscussionSectionRoles) != 3 {
t.Fatalf("role registry has %d entries, want 3", len(forecastDiscussionSectionRoles))
if len(forecastDiscussionSectionRoles) != 4 {
t.Fatalf("role registry has %d entries, want 4", len(forecastDiscussionSectionRoles))
}
if _, ok := forecastDiscussionSectionRoles["AVIATION"]; ok {
t.Fatalf("AVIATION must remain boundary-only")
for _, tt := range []struct {
section string
role forecastDiscussionSectionRole
}{
{section: "KEY MESSAGES", role: forecastDiscussionSectionRoleKeyMessages},
{section: "KEY POINTS", role: forecastDiscussionSectionRoleKeyMessages},
{section: "SHORT TERM", role: forecastDiscussionSectionRoleShortTerm},
{section: "LONG TERM", role: forecastDiscussionSectionRoleLongTerm},
} {
role, ok := forecastDiscussionSectionRoles[tt.section]
if !ok || role != tt.role {
t.Fatalf("role for %q = %d, present = %t; want %d", tt.section, role, ok, tt.role)
}
}
for _, section := range []string{"NEAR TERM", "DISCUSSION", "AVIATION"} {
if _, ok := forecastDiscussionSectionRoles[section]; ok {
t.Fatalf("%s must remain boundary-only", section)
}
}
for section := range forecastDiscussionSectionRoles {
@@ -464,6 +482,90 @@ func TestParseForecastDiscussionTextKeepsFirstMappedSections(t *testing.T) {
}
}
func TestParseForecastDiscussionTextKeepsFirstKeyMessageRole(t *testing.T) {
tests := []struct {
name string
lines []string
want []string
}{
{
name: "key points only",
lines: []string{
".KEY POINTS...",
"- First key point.",
},
want: []string{"First key point."},
},
{
name: "key points before key messages",
lines: []string{
".KEY POINTS...",
"- First key point.",
"&&",
".KEY MESSAGES...",
"- Later key message.",
},
want: []string{"First key point."},
},
{
name: "key messages before key points",
lines: []string{
".KEY MESSAGES...",
"- First key message.",
"&&",
".KEY POINTS...",
"- Later key point.",
},
want: []string{"First key message."},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
text := strings.Join(append([]string{
"AFDLSX",
"National Weather Service Saint Louis MO",
"224 PM CDT Sat Mar 28 2026",
"",
}, tt.lines...), "\n")
got, err := ParseForecastDiscussionText(text)
if err != nil {
t.Fatalf("ParseForecastDiscussionText() error = %v", err)
}
if !reflect.DeepEqual(got.KeyMessages, tt.want) {
t.Fatalf("KeyMessages = %#v, want %#v", got.KeyMessages, tt.want)
}
})
}
}
func TestParseForecastDiscussionTextKeepsUnmappedSectionsBoundaryOnly(t *testing.T) {
text := strings.Join([]string{
"AFDLSX",
"National Weather Service Saint Louis MO",
"224 PM CDT Sat Mar 28 2026",
"",
".SHORT TERM... (Tonight)",
"Short-term prose.",
".NEAR TERM... (This Evening)",
"Near-term prose.",
".LONG TERM... (Tomorrow)",
"Long-term prose.",
}, "\n")
got, err := ParseForecastDiscussionText(text)
if err != nil {
t.Fatalf("ParseForecastDiscussionText() error = %v", err)
}
if got.ShortTerm == nil || got.ShortTerm.Text != "Short-term prose." {
t.Fatalf("ShortTerm = %#v, want only short-term prose", got.ShortTerm)
}
if got.LongTerm == nil || got.LongTerm.Text != "Long-term prose." {
t.Fatalf("LongTerm = %#v, want only long-term prose", got.LongTerm)
}
}
func TestParseForecastDiscussionTextSectionKeepsHeadingQualifiers(t *testing.T) {
tests := []struct {
name string