mirror of
https://github.com/hanzo-fi/go-libs.git
synced 2026-10-30 20:53:44 +00:00
* test(currency): add fuzz tests for amount parsing and serialization Add three fuzz targets: GetAmountWithPrecisionFromString, AmountRoundTrip, and GetStringAmountFromBigIntWithPrecision. Includes regression corpus for a negative number serialization bug found during fuzzing. * fix(currency): handle negative numbers in GetStringAmountFromBigIntWithPrecision The sign was placed after the decimal point for negative amounts (e.g. -1 with precision 26 produced "0.-00...001"). Extract the sign before formatting and prepend it to the result. * test(query): add fuzz test for ParseJSON with round-trip verification Fuzzes the query DSL parser with random JSON inputs. Verifies no panics, successful Build calls, and marshal/re-parse round-trip consistency. Includes regression corpus for empty $and set serialization. * fix(query): marshal empty $and/$or sets as [] instead of null set.MarshalJSON serialized a nil items slice as null, which could not be re-parsed by ParseJSON. Initialize to an empty slice when nil so the round-trip produces valid JSON. * test(oidc): add fuzz tests for Audience, Time, SpaceDelimitedArray, and Locales Fuzz JSON unmarshaling for security-critical OIDC types. Includes round-trip verification for Audience and SpaceDelimitedArray, and panic-safety checks for Time and Locales. * test: add fuzz tests for JWT scopes, licence validation, and pagination - jwt: fuzz checkScopes and ClaimsFromRequest header parsing - licence: fuzz JWT token validation against embedded RSA key - paginate: fuzz UnmarshalCursor (base64->JSON) and BigInt.FromString in a separate subpackage to avoid Docker-dependent TestMain * test(time): add fuzz tests for ParseTime, UnmarshalJSON, and Scan Three fuzz targets covering time parsing, JSON unmarshaling, and database scanning with round-trip verification. Includes regression corpus for year 0000 with timezone offset producing negative years that cannot be re-parsed (Go stdlib limitation). * test(metadata): add fuzz tests for Scan, Merge, and UnmarshalValue Fuzz JSON scanning from database, metadata merging invariants, and the generic UnmarshalValue function with panic recovery. * test(currency): add fuzz tests for GetCurrencyAndPrecisionFromAsset and FormatAsset Fuzz asset string parsing (EUR/2 format) and currency formatting against the ISO4217 currency map. * test(oidc): add fuzz tests for JWTTokenRequest and mergeAndMarshalClaims Fuzz JWT token request round-trip and claims merging. Includes regression corpus for null Audience round-trip failure. * fix(oidc): handle null JSON value in Audience.UnmarshalJSON Audience marshals as null when empty, but UnmarshalJSON did not accept null back, breaking round-trip consistency. Add nil case to the type switch. * fix(time): skip round-trip check for negative years in FuzzParseTime Negative years produced by UTC conversion are not representable in RFC3339, causing the round-trip reparse to fail. * fix: address CodeRabbit review comments on fuzz tests - query/fuzz_test.go: fail on marshal error instead of silently returning - paginate/fuzz_test.go: add semantic validation with base64+JSON oracle - currency/amount.go: guard against nil *big.Int to prevent panic - time/fuzz_test.go: also skip year 0 and year > 9999 in round-trip check * fix(metadata): avoid masking unexpected panics in FuzzUnmarshalValue Skip invalid JSON inputs instead of catching all panics with defer/recover, so genuine unexpected panics surface properly.
72 lines
1.9 KiB
Go
72 lines
1.9 KiB
Go
package query
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func FuzzParseJSON(f *testing.F) {
|
|
// Valid expressions
|
|
f.Add(`{"$match": {"account": "users:001"}}`)
|
|
f.Add(`{"$and": [{"$match": {"account": "pending"}}, {"$gte": {"balance": 100}}]}`)
|
|
f.Add(`{"$or": [{"$match": {"a": "b"}}, {"$match": {"c": "d"}}]}`)
|
|
f.Add(`{"$not": {"$match": {"account": "blocked"}}}`)
|
|
f.Add(`{"$like": {"name": "john%"}}`)
|
|
f.Add(`{"$in": {"account": ["A", "B"]}}`)
|
|
f.Add(`{"$lt": {"balance": 0}}`)
|
|
f.Add(`{"$lte": {"balance": 50}}`)
|
|
f.Add(`{"$gt": {"balance": 100}}`)
|
|
f.Add(`{"$gte": {"balance": 288230376151711747}}`)
|
|
f.Add(`{"$exists": {"metadata": true}}`)
|
|
|
|
// Nested
|
|
f.Add(`{"$and": [{"$or": [{"$match": {"a": "1"}}, {"$match": {"b": "2"}}]}, {"$not": {"$match": {"c": "3"}}}]}`)
|
|
|
|
// Edge cases
|
|
f.Add(`{}`)
|
|
f.Add(``)
|
|
f.Add(`null`)
|
|
f.Add(`[]`)
|
|
f.Add(`"string"`)
|
|
f.Add(`42`)
|
|
f.Add(`{"$unknown": {"key": "val"}}`)
|
|
f.Add(`{"$match": "not_a_map"}`)
|
|
f.Add(`{"$and": "not_an_array"}`)
|
|
f.Add(`{"$and": []}`)
|
|
f.Add(`{`)
|
|
f.Add(`{"a": 1, "b": 2}`)
|
|
|
|
f.Fuzz(func(t *testing.T, data string) {
|
|
// Must not panic
|
|
builder, err := ParseJSON(data)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if builder == nil {
|
|
return
|
|
}
|
|
|
|
// If parsing succeeded, Build must not panic
|
|
_, _, _ = builder.Build(ContextFn(func(key, operator string, value any) (string, []any, error) {
|
|
return "1 = 1", nil, nil
|
|
}))
|
|
|
|
// If parsing succeeded, MarshalJSON must not panic
|
|
marshaled, err := json.Marshal(builder)
|
|
if err != nil {
|
|
t.Fatalf("marshal failed after successful parse for input %q: %v", data, err)
|
|
}
|
|
|
|
// Round-trip: re-parse the marshaled output
|
|
reparsed, err := ParseJSON(string(marshaled))
|
|
if err != nil {
|
|
t.Fatalf("round-trip parse failed: marshal produced %q, reparse error: %v", string(marshaled), err)
|
|
}
|
|
|
|
if reparsed == nil {
|
|
t.Fatal("round-trip produced nil builder from non-nil marshal output")
|
|
}
|
|
})
|
|
}
|