Added support for rounding of values by default in API responses
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:
@@ -119,6 +119,70 @@ func TestObservationsPopulatedJSONEnvelope(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestObservationsDefaultPrecisionRoundsToInteger(t *testing.T) {
|
||||
h := newHandler(t, &fakeService{
|
||||
observation: &model.WeatherObservation{
|
||||
Timestamp: time.Now().UTC(),
|
||||
ConditionCode: model.WMOUnknown,
|
||||
TemperatureC: float64Ptr(20.6),
|
||||
},
|
||||
}, "/observations")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/observations", nil)
|
||||
h.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", w.Code)
|
||||
}
|
||||
|
||||
var payload struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &payload); err != nil {
|
||||
t.Fatalf("decode envelope: %v", err)
|
||||
}
|
||||
got, ok := payload.Data["temperatureC"].(float64)
|
||||
if !ok {
|
||||
t.Fatalf("expected temperatureC float, got %#v", payload.Data["temperatureC"])
|
||||
}
|
||||
if got != 21 {
|
||||
t.Fatalf("expected rounded temperatureC 21, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestObservationsPrecisionTwo(t *testing.T) {
|
||||
h := newHandler(t, &fakeService{
|
||||
observation: &model.WeatherObservation{
|
||||
Timestamp: time.Now().UTC(),
|
||||
ConditionCode: model.WMOUnknown,
|
||||
TemperatureC: float64Ptr(20.678),
|
||||
},
|
||||
}, "/observations")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/observations?precision=2", nil)
|
||||
h.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", w.Code)
|
||||
}
|
||||
|
||||
var payload struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &payload); err != nil {
|
||||
t.Fatalf("decode envelope: %v", err)
|
||||
}
|
||||
got, ok := payload.Data["temperatureC"].(float64)
|
||||
if !ok {
|
||||
t.Fatalf("expected temperatureC float, got %#v", payload.Data["temperatureC"])
|
||||
}
|
||||
if math.Abs(got-20.68) > 0.00001 {
|
||||
t.Fatalf("expected rounded temperatureC 20.68, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatNegotiationCaseInsensitive(t *testing.T) {
|
||||
hXML := newHandler(t, &fakeService{alerts: &model.WeatherAlertRun{AsOf: time.Now().UTC()}}, "/alerts/active")
|
||||
|
||||
@@ -285,6 +349,51 @@ func TestForecastUSUnitsWithXMLFormatUppercaseQuery(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestForecastPrecisionTwo(t *testing.T) {
|
||||
h := newHandler(t, &fakeService{
|
||||
forecast: &model.WeatherForecastRun{
|
||||
Product: model.ForecastProductHourly,
|
||||
IssuedAt: time.Now().UTC(),
|
||||
Periods: []model.WeatherForecastPeriod{{
|
||||
StartTime: time.Now().UTC(),
|
||||
EndTime: time.Now().UTC().Add(time.Hour),
|
||||
ConditionCode: model.WMOUnknown,
|
||||
TemperatureC: float64Ptr(12.345),
|
||||
}},
|
||||
},
|
||||
}, "/forecast/hourly")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/forecast/hourly?precision=2", nil)
|
||||
h.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", w.Code)
|
||||
}
|
||||
|
||||
var payload struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &payload); err != nil {
|
||||
t.Fatalf("decode envelope: %v", err)
|
||||
}
|
||||
periods, ok := payload.Data["periods"].([]any)
|
||||
if !ok || len(periods) == 0 {
|
||||
t.Fatalf("expected non-empty periods, got %#v", payload.Data["periods"])
|
||||
}
|
||||
first, ok := periods[0].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("expected first period object, got %#v", periods[0])
|
||||
}
|
||||
got, ok := first["temperatureC"].(float64)
|
||||
if !ok {
|
||||
t.Fatalf("expected temperatureC float, got %#v", first["temperatureC"])
|
||||
}
|
||||
if math.Abs(got-12.35) > 0.00001 {
|
||||
t.Fatalf("expected rounded temperatureC 12.35, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrentConditionsNoDataReturnsNullEnvelopeData(t *testing.T) {
|
||||
h := newHandler(t, &fakeService{}, "/conditions/current")
|
||||
|
||||
@@ -436,6 +545,33 @@ func TestCurrentConditionsRejectUnknownQueryParameter(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrecisionValidationRange(t *testing.T) {
|
||||
h := newHandler(t, &fakeService{}, "/conditions/current")
|
||||
|
||||
for _, raw := range []string{"-1", "3", "abc"} {
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/conditions/current?precision="+raw, nil)
|
||||
h.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400 for precision=%s, got %d", raw, w.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertsRejectPrecisionQueryParameter(t *testing.T) {
|
||||
h := newHandler(t, &fakeService{
|
||||
alerts: &model.WeatherAlertRun{AsOf: time.Now().UTC()},
|
||||
}, "/alerts/active")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/alerts/active?precision=1", nil)
|
||||
h.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func newHandler(t *testing.T, svc Service, path string) http.Handler {
|
||||
t.Helper()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user