Fixed releases with 1e9999 ("no limit") being skipped as unreadable

This commit is contained in:
bwilliams committed 2026-10-21 09:34:44 +01:00
1 parent 79efcb5e91
commit 4db268550b
2 files changed
+157 -49

No files matched your search

+77 -8
View File
@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"log/slog"
"math"
"net/http"
"net/http/httptest"
"strings"
@@ -763,7 +764,7 @@ func TestFetchAllRepeatedNextLink(t *testing.T) {
}
}
func TestUnmarshalLenientDates(t *testing.T) {
func TestUnmarshalLenient(t *testing.T) {
raw := json.RawMessage(`{
"date": "2006-10-02",
"publishedDate": "",
@@ -793,7 +794,7 @@ func TestUnmarshalLenientDates(t *testing.T) {
} `json:"awards"`
Value json.Number `json:"value"`
}
if err := unmarshalLenientDates(raw, &got); err != nil {
if err := unmarshalLenient(raw, &got); err != nil {
t.Fatal(err)
}
@@ -833,9 +834,77 @@ func TestUnmarshalLenientDates(t *testing.T) {
}
}
func TestRepairDatesLeavesValidJSONAlone(t *testing.T) {
func TestUnmarshalLenientNumbers(t *testing.T) {
tests := []struct {
raw string
wantInt int64
wantFloat float64
}{
{`1e9999`, math.MaxInt64, math.MaxInt64},
{`-1e9999`, math.MinInt64, math.MinInt64},
{`1E+400`, math.MaxInt64, math.MaxInt64},
{`3`, 3, 3},
}
for _, tc := range tests {
t.Run(tc.raw, func(t *testing.T) {
var got struct {
Int *int64 `json:"int"`
Float *float64 `json:"float"`
}
raw := json.RawMessage(
`{"int": ` + tc.raw + `, "float": ` + tc.raw + `}`,
)
if err := unmarshalLenient(raw, &got); err != nil {
t.Fatal(err)
}
if *got.Int != tc.wantInt {
t.Errorf("int = %d; want %d", *got.Int, tc.wantInt)
}
if *got.Float != tc.wantFloat {
t.Errorf("float = %v; want %v", *got.Float, tc.wantFloat)
}
})
}
}
// TestUnmarshalLenientNoLimit decodes OCDS's 1e9999 ("no limit") into the
// release fields Find a Tender sends it in, and checks the release can still
// be marshalled, as Convert does to store its JSON.
func TestUnmarshalLenientNoLimit(t *testing.T) {
raw := json.RawMessage(`{
"ocid": "ocds-1",
"id": "r1",
"date": "2026-10-16T15:52:30+01:00",
"tender": {
"lotDetails": {"maximumLotsBidPerSupplier": 1e9999},
"techniques": {
"frameworkAgreement": {"maximumParticipants": 1e9999}
}
}
}`)
var release ocds.Release
if err := unmarshalLenient(raw, &release); err != nil {
t.Fatal(err)
}
lots := release.Tender.LotDetails.MaximumLotsBidPerSupplier
if lots == nil || *lots != math.MaxInt64 {
t.Errorf("maximumLotsBidPerSupplier = %v", lots)
}
framework := release.Tender.Techniques.FrameworkAgreement
if participants := framework.MaximumParticipants; participants == nil ||
*participants != math.MaxInt64 {
t.Errorf("maximumParticipants = %v", participants)
}
if _, err := json.Marshal(release); err != nil {
t.Errorf("marshalling the repaired release: %v", err)
}
}
func TestRepairJSONLeavesValidJSONAlone(t *testing.T) {
raw := json.RawMessage(`{"date": "2006-10-02T15:33:02+07:00", "title": "x"}`)
out, err := repairDates(raw)
out, err := repairJSON(raw)
if err != nil {
t.Fatal(err)
}
@@ -844,15 +913,15 @@ func TestRepairDatesLeavesValidJSONAlone(t *testing.T) {
}
}
func TestRepairDatesRejectsBadJSON(t *testing.T) {
func TestRepairJSONRejectsBadJSON(t *testing.T) {
for _, raw := range []string{`{`, `{"date": "2006-10-02"} trailing`} {
if _, err := repairDates(json.RawMessage(raw)); err == nil {
if _, err := repairJSON(json.RawMessage(raw)); err == nil {
t.Errorf("expected an error for %q", raw)
}
}
}
func TestUnmarshalLenientDatesErrors(t *testing.T) {
func TestUnmarshalLenientErrors(t *testing.T) {
var v struct {
Date time.Time `json:"date"`
}
@@ -864,7 +933,7 @@ func TestUnmarshalLenientDatesErrors(t *testing.T) {
}
for name, raw := range tests {
t.Run(name, func(t *testing.T) {
if err := unmarshalLenientDates(json.RawMessage(raw), &v); err == nil {
if err := unmarshalLenient(json.RawMessage(raw), &v); err == nil {
t.Errorf("expected an error for %s", raw)
}
})