285 lines
6.4 KiB
Go
285 lines
6.4 KiB
Go
// Copyright 2025 The Hugo Authors. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package hreflect
|
|
|
|
import (
|
|
"math"
|
|
"reflect"
|
|
"testing"
|
|
|
|
qt "github.com/frankban/quicktest"
|
|
"github.com/gohugoio/hugo/htesting/hqt"
|
|
)
|
|
|
|
func TestToFuncs(t *testing.T) {
|
|
c := qt.New(t)
|
|
|
|
c.Assert(ToInt64(reflect.ValueOf(int(42))), qt.Equals, int64(42))
|
|
c.Assert(ToFloat64(reflect.ValueOf(float32(3.14))), hqt.IsSameFloat64, float64(3.14))
|
|
c.Assert(ToString(reflect.ValueOf("hello")), qt.Equals, "hello")
|
|
}
|
|
|
|
func TestConvertIfPossible(t *testing.T) {
|
|
c := qt.New(t)
|
|
|
|
for _, test := range []struct {
|
|
name string
|
|
value any
|
|
typ any
|
|
expected any
|
|
ok bool
|
|
}{
|
|
// From uint to int.
|
|
{
|
|
name: "uint64(math.MaxUint64) to int16",
|
|
value: uint64(math.MaxUint64),
|
|
typ: int16(0),
|
|
ok: false, // overflow
|
|
},
|
|
|
|
{
|
|
name: "uint64(math.MaxUint64) to int64",
|
|
value: uint64(math.MaxUint64),
|
|
typ: int64(0),
|
|
ok: false, // overflow
|
|
},
|
|
{
|
|
name: "uint64(math.MaxInt16) to int16",
|
|
value: uint64(math.MaxInt16),
|
|
typ: int64(0),
|
|
ok: true,
|
|
expected: int64(math.MaxInt16),
|
|
},
|
|
// From int to int.
|
|
{
|
|
name: "int64(math.MaxInt64) to int16",
|
|
value: int64(math.MaxInt64),
|
|
typ: int16(0),
|
|
ok: false, // overflow
|
|
},
|
|
{
|
|
name: "int64(math.MaxInt16) to int",
|
|
value: int64(math.MaxInt16),
|
|
typ: int(0),
|
|
ok: true,
|
|
expected: int(math.MaxInt16),
|
|
},
|
|
|
|
{
|
|
name: "int64(math.MaxInt16) to int",
|
|
value: int64(math.MaxInt16),
|
|
typ: int(0),
|
|
ok: true,
|
|
expected: int(math.MaxInt16),
|
|
},
|
|
// From float64 to int.
|
|
{
|
|
name: "float64(1.5) to int",
|
|
value: float64(1.5),
|
|
typ: int(0),
|
|
ok: false, // loss of precision
|
|
},
|
|
{
|
|
name: "float64(1.0) to int",
|
|
value: float64(1.0),
|
|
typ: int(0),
|
|
ok: true,
|
|
expected: int(1),
|
|
},
|
|
{
|
|
name: "float64(math.MaxInt16+1) to int16",
|
|
value: float64(math.MaxInt16 + 1),
|
|
typ: int16(0),
|
|
ok: false, // overflow
|
|
},
|
|
{
|
|
name: "float64(math.MaxFloat64) to int64",
|
|
value: float64(math.MaxFloat64),
|
|
typ: int64(0),
|
|
ok: false, // overflow
|
|
},
|
|
{
|
|
name: "float64(32767) to int16",
|
|
value: float64(32767),
|
|
typ: int16(0),
|
|
ok: true,
|
|
expected: int16(32767),
|
|
},
|
|
// From float32 to int.
|
|
{
|
|
name: "float32(1.5) to int",
|
|
value: float32(1.5),
|
|
typ: int(0),
|
|
ok: false, // loss of precision
|
|
},
|
|
{
|
|
name: "float32(1.0) to int",
|
|
value: float32(1.0),
|
|
typ: int(0),
|
|
ok: true,
|
|
expected: int(1),
|
|
},
|
|
{
|
|
name: "float32(math.MaxFloat32) to int16",
|
|
value: float32(math.MaxFloat32),
|
|
typ: int16(0),
|
|
ok: false, // overflow
|
|
},
|
|
{
|
|
name: "float32(math.MaxFloat32) to int64",
|
|
value: float32(math.MaxFloat32),
|
|
typ: int64(0),
|
|
ok: false, // overflow
|
|
},
|
|
{
|
|
name: "float32(math.MaxInt16) to int16",
|
|
value: float32(math.MaxInt16),
|
|
typ: int16(0),
|
|
ok: true,
|
|
expected: int16(32767),
|
|
},
|
|
{
|
|
name: "float32(math.MaxInt16+1) to int16",
|
|
value: float32(math.MaxInt16 + 1),
|
|
typ: int16(0),
|
|
ok: false, // overflow
|
|
},
|
|
// Int to float.
|
|
{
|
|
name: "int16(32767) to float32",
|
|
value: int16(32767),
|
|
typ: float32(0),
|
|
ok: true,
|
|
expected: float32(32767),
|
|
},
|
|
{
|
|
name: "int64(32767) to float32",
|
|
value: int64(32767),
|
|
typ: float32(0),
|
|
ok: true,
|
|
expected: float32(32767),
|
|
},
|
|
{
|
|
name: "int64(math.MaxInt64) to float32",
|
|
value: int64(math.MaxInt64),
|
|
typ: float32(0),
|
|
ok: true,
|
|
expected: float32(math.MaxInt64),
|
|
},
|
|
{
|
|
name: "int64(math.MaxInt64) to float64",
|
|
value: int64(math.MaxInt64),
|
|
typ: float64(0),
|
|
ok: true,
|
|
expected: float64(math.MaxInt64),
|
|
},
|
|
// Int to uint.
|
|
{
|
|
name: "int16(32767) to uint16",
|
|
value: int16(32767),
|
|
typ: uint16(0),
|
|
ok: true,
|
|
expected: uint16(32767),
|
|
},
|
|
{
|
|
name: "int16(32767) to uint8",
|
|
value: int16(32767),
|
|
typ: uint8(0),
|
|
ok: false,
|
|
},
|
|
{
|
|
name: "float64(3.14) to uint64",
|
|
value: float64(3.14),
|
|
typ: uint64(0),
|
|
ok: false,
|
|
},
|
|
{
|
|
name: "float64(3.0) to uint64",
|
|
value: float64(3.0),
|
|
typ: uint64(0),
|
|
ok: true,
|
|
expected: uint64(3),
|
|
},
|
|
// From uint to float.
|
|
{
|
|
name: "uint64(math.MaxInt16) to float64",
|
|
value: uint64(math.MaxInt16),
|
|
typ: float64(0),
|
|
ok: true,
|
|
expected: float64(math.MaxInt16),
|
|
},
|
|
// Float to float.
|
|
{
|
|
name: "float64(3.14) to float32",
|
|
value: float64(3.14),
|
|
typ: float32(0),
|
|
ok: true,
|
|
expected: float32(3.14),
|
|
},
|
|
{
|
|
name: "float32(3.14) to float64",
|
|
value: float32(3.14),
|
|
typ: float64(0),
|
|
ok: true,
|
|
expected: float64(3.14),
|
|
},
|
|
{
|
|
name: "float64(3.14) to float64",
|
|
value: float64(3.14),
|
|
typ: float64(0),
|
|
ok: true,
|
|
expected: float64(3.14),
|
|
},
|
|
} {
|
|
|
|
v, ok := ConvertIfPossible(reflect.ValueOf(test.value), reflect.TypeOf(test.typ))
|
|
c.Assert(ok, qt.Equals, test.ok, qt.Commentf("test case: %s", test.name))
|
|
if test.ok {
|
|
c.Assert(v.Interface(), hqt.IsSameNumber, test.expected, qt.Commentf("test case: %s", test.name))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConvertIfPossibleMisc(t *testing.T) {
|
|
c := qt.New(t)
|
|
type s string
|
|
|
|
var (
|
|
i = int32(42)
|
|
i64 = int64(i)
|
|
iv any = i
|
|
ip = &i
|
|
inil any = (*int32)(nil)
|
|
shello = s("hello")
|
|
)
|
|
|
|
convertOK := func(v any, typ any) any {
|
|
rv, ok := ConvertIfPossible(reflect.ValueOf(v), reflect.TypeOf(typ))
|
|
c.Assert(ok, qt.IsTrue)
|
|
return rv.Interface()
|
|
}
|
|
|
|
c.Assert(convertOK(shello, ""), qt.Equals, "hello")
|
|
c.Assert(convertOK(ip, int64(0)), qt.Equals, i64)
|
|
c.Assert(convertOK(iv, int64(0)), qt.Equals, i64)
|
|
c.Assert(convertOK(inil, int64(0)), qt.Equals, int64(0))
|
|
}
|
|
|
|
func BenchmarkToInt64(b *testing.B) {
|
|
v := reflect.ValueOf(int(42))
|
|
for b.Loop() {
|
|
ToInt64(v)
|
|
}
|
|
}
|