Implemented the weather forecast discussion product from weatherfeeder v0.8.3
All checks were successful
ci/woodpecker/push/build-image Pipeline was successful
All checks were successful
ci/woodpecker/push/build-image Pipeline was successful
This commit is contained in:
38
internal/adapters/inbound/httpapi/presenter/discussion.go
Normal file
38
internal/adapters/inbound/httpapi/presenter/discussion.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// discussion.go presents forecast discussion payloads.
|
||||
// Layer: adapters/inbound/httpapi/presenter discussion payload mapping.
|
||||
package presenter
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/ejr/weatherfeeder/model"
|
||||
)
|
||||
|
||||
func DiscussionPayload(run *model.WeatherForecastDiscussion, _ Units, tz *time.Location) any {
|
||||
if run == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := model.WeatherForecastDiscussion{
|
||||
OfficeID: run.OfficeID,
|
||||
OfficeName: run.OfficeName,
|
||||
Product: run.Product,
|
||||
IssuedAt: inLocationTime(run.IssuedAt, tz),
|
||||
UpdatedAt: inLocationTimePtr(run.UpdatedAt, tz),
|
||||
KeyMessages: append([]string(nil), run.KeyMessages...),
|
||||
ShortTerm: copyDiscussionSection(run.ShortTerm, tz),
|
||||
LongTerm: copyDiscussionSection(run.LongTerm, tz),
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func copyDiscussionSection(in *model.WeatherForecastDiscussionSection, tz *time.Location) *model.WeatherForecastDiscussionSection {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
return &model.WeatherForecastDiscussionSection{
|
||||
Qualifier: in.Qualifier,
|
||||
IssuedAt: inLocationTimePtr(in.IssuedAt, tz),
|
||||
Text: in.Text,
|
||||
}
|
||||
}
|
||||
@@ -175,6 +175,40 @@ func TestForecastPayloadNoTimezonePreservesUTCAndCopySemantics(t *testing.T) {
|
||||
assertOffsetSeconds(t, metric.Periods[0].StartTime, 0)
|
||||
}
|
||||
|
||||
func TestDiscussionPayloadTimezoneConversionAndCopySemantics(t *testing.T) {
|
||||
loc := time.FixedZone("UTC-05:00", -5*60*60)
|
||||
issuedAt := time.Date(2026, 7, 10, 12, 0, 0, 0, time.UTC)
|
||||
updatedAt := issuedAt.Add(30 * time.Minute)
|
||||
shortIssuedAt := issuedAt.Add(-15 * time.Minute)
|
||||
run := &model.WeatherForecastDiscussion{
|
||||
OfficeID: "LSX",
|
||||
Product: model.ForecastDiscussionProductAFD,
|
||||
IssuedAt: issuedAt,
|
||||
UpdatedAt: &updatedAt,
|
||||
KeyMessages: []string{"msg one"},
|
||||
ShortTerm: &model.WeatherForecastDiscussionSection{Qualifier: "(Tonight)", IssuedAt: &shortIssuedAt, Text: "Short term text"},
|
||||
}
|
||||
|
||||
payload := DiscussionPayload(run, UnitsMetric, loc)
|
||||
discussion, ok := payload.(*model.WeatherForecastDiscussion)
|
||||
if !ok {
|
||||
t.Fatalf("expected *model.WeatherForecastDiscussion payload, got %T", payload)
|
||||
}
|
||||
if discussion == run {
|
||||
t.Fatalf("expected discussion payload to be copied")
|
||||
}
|
||||
if discussion.ShortTerm == run.ShortTerm {
|
||||
t.Fatalf("expected shortTerm pointer to be copied")
|
||||
}
|
||||
assertOffsetSeconds(t, discussion.IssuedAt, -5*60*60)
|
||||
assertOffsetSeconds(t, *discussion.UpdatedAt, -5*60*60)
|
||||
assertOffsetSeconds(t, *discussion.ShortTerm.IssuedAt, -5*60*60)
|
||||
if discussion.KeyMessages[0] != "msg one" {
|
||||
t.Fatalf("expected key message preserved, got %#v", discussion.KeyMessages)
|
||||
}
|
||||
assertOffsetSeconds(t, run.IssuedAt, 0)
|
||||
}
|
||||
|
||||
func TestMetricCopyAndNilHandling(t *testing.T) {
|
||||
obs := &model.WeatherObservation{
|
||||
TemperatureC: float64Ptr(20.6),
|
||||
@@ -202,6 +236,9 @@ func TestMetricCopyAndNilHandling(t *testing.T) {
|
||||
if AlertsPayload(nil, UnitsUS) != nil {
|
||||
t.Fatalf("expected nil alerts input to return nil payload")
|
||||
}
|
||||
if DiscussionPayload(nil, UnitsUS, nil) != nil {
|
||||
t.Fatalf("expected nil discussion input to return nil payload")
|
||||
}
|
||||
if CurrentConditionsPayload(nil, UnitsUS, 0) != nil {
|
||||
t.Fatalf("expected nil current conditions input to return nil payload")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user