diff --git a/.github/workflows/go.yaml b/.github/workflows/go.yaml index 687270ea..8ce4352e 100644 --- a/.github/workflows/go.yaml +++ b/.github/workflows/go.yaml @@ -15,17 +15,60 @@ jobs: continue-on-error: true # make sure to run all versions, even if one fails strategy: + fail-fast: false matrix: go-version: ${{ fromJSON(needs.go-versions.outputs.versions) }} steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - with: - persist-credentials: false + with: {persist-credentials: false} - name: Run all unit tests w/ -cover, all YTS tests and go lint run: make test lint v=1 GO-VERSION=${{ matrix.go-version }} + test-cross-platform: + name: Test on ${{ matrix.GOOS }}/${{ matrix.GOARCH }} + runs-on: ${{ matrix.os }} + continue-on-error: true # make sure to run all platforms, even if one fails + + strategy: + fail-fast: false + matrix: + include: + - os: macos-latest + GOOS: darwin + GOARCH: amd64 + test-args: -race + - os: macos-latest + GOOS: darwin + GOARCH: arm64 + test-args: -race + - os: windows-latest + GOOS: windows + GOARCH: amd64 + test-args: -race + - os: ubuntu-latest + GOOS: linux + GOARCH: 386 + test-args: '' # race is not available on 32 bits architecture + - os: windows-latest + GOOS: windows + GOARCH: 386 + test-args: '' # race is not available on 32 bits architecture + + env: + GOARCH: ${{ matrix.GOARCH }} + GOOS: ${{ matrix.GOOS }} + + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: {persist-credentials: false} + + - name: Run unit tests + run: | + bash -c 'echo + $OSTYPE + $MACHTYPE +' + make test-unit test-internal v=1 o=${{ matrix.test-args }} + go-versions: name: Lookup Go versions runs-on: ubuntu-latest diff --git a/GNUmakefile b/GNUmakefile index d857d189..a498eeaf 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,7 +1,7 @@ # Auto-install https://github.com/makeplus/makes at specific commit: MAKES := .cache/makes MAKES-LOCAL := .cache/local -MAKES-COMMIT ?= 4962658786cf52734b3e416e49cba2abf08402a6 +MAKES-COMMIT ?= 4e48a743c3652b88adc4a257398d895a801e6d11 $(shell [ -d $(MAKES) ] || ( \ git clone -q https://github.com/makeplus/makes $(MAKES) && \ git -C $(MAKES) reset -q --hard $(MAKES-COMMIT))) diff --git a/decode_test.go b/decode_test.go index bc1c4da6..b659f5f6 100644 --- a/decode_test.go +++ b/decode_test.go @@ -23,6 +23,7 @@ import ( "io" "math" "reflect" + "strconv" "strings" "testing" "time" @@ -40,6 +41,17 @@ var negativeZero = math.Copysign(0.0, -1.0) var unmarshalIntTest = 123 +// archSafeInt returns v as int if it fits in the architecture's int type, +// otherwise returns int64. +func archSafeInt(v int64) any { + if strconv.IntSize == 64 || math.MinInt32 <= v && v <= math.MaxInt32 { + return int(v) // int is safe + } + + // on 32-bit systems, and v overflows int, we need to return an int64 + return int64(v) +} + // Named struct types for data-driven tests type ( testStructHello struct{ Hello string } @@ -197,11 +209,11 @@ func init() { decodeValues.Register("-0", negativeZero) // Register math limit constants - decodeValues.Register("MaxInt32", math.MaxInt32) - decodeValues.Register("MinInt32", math.MinInt32) - decodeValues.Register("MaxInt64", math.MaxInt64) - decodeValues.Register("MinInt64", math.MinInt64) - decodeValues.Register("MaxUint32", math.MaxUint32) + decodeValues.Register("MaxInt32", int(math.MaxInt32)) + decodeValues.Register("MinInt32", int(math.MinInt32)) + decodeValues.Register("MaxInt64", int64(math.MaxInt64)) + decodeValues.Register("MinInt64", int64(math.MinInt64)) + decodeValues.Register("MaxUint32", uint(math.MaxUint32)) decodeValues.Register("MaxUint64", uint64(math.MaxUint64)) decodeValues.Register("MaxFloat32", math.MaxFloat32) decodeValues.Register("MaxFloat64", math.MaxFloat64) @@ -235,6 +247,18 @@ var unmarshalTests = []struct { "\t\n", }, + // Cross-architecture numeric tests + { + "bin: -0b1000000000000000000000000000000000000000000000000000000000000000", + map[string]any{"bin": archSafeInt(math.MinInt64)}, + }, + { + // When unmarshaling into map[string]int64, values that overflow int64 + // cannot be decoded and result in an empty map. + "int_overflow: 9223372036854775808", // math.MaxInt64 + 1 + map[string]int64{}, + }, + // Structs and type conversions. { "a: 'null'", diff --git a/internal/libyaml/yamldatatest_loader.go b/internal/libyaml/yamldatatest_loader.go index 182bfaaa..3abc6d58 100644 --- a/internal/libyaml/yamldatatest_loader.go +++ b/internal/libyaml/yamldatatest_loader.go @@ -33,9 +33,14 @@ func coerceScalar(value string) interface{} { } } - // Try decimal int - if _, err := fmt.Sscanf(value, "%d", &intVal); err == nil { - return intVal + // Try decimal int - use int64 to handle large values on 32-bit systems + var int64Val int64 + if _, err := fmt.Sscanf(value, "%d", &int64Val); err == nil { + // Return as int if it fits, otherwise int64 + if int64Val == int64(int(int64Val)) { + return int(int64Val) + } + return int64Val } // Default to string