You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
6.0 KiB
191 lines
6.0 KiB
4 weeks ago
|
package bytesize_test
|
||
|
|
||
|
import (
|
||
|
"math"
|
||
|
"math/rand"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
|
||
|
"gitoa.ru/go-4devs/bytesize"
|
||
|
)
|
||
|
|
||
|
var parseTests = []struct {
|
||
|
in string
|
||
|
want bytesize.Size
|
||
|
}{
|
||
|
// simple
|
||
|
{"0", 0},
|
||
|
{"5KiB", 5 * bytesize.Kibibyte},
|
||
|
{"30KiB", 30 * bytesize.Kibibyte},
|
||
|
{"1478KiB", 1478 * bytesize.Kibibyte},
|
||
|
// sign
|
||
|
{"-5KiB", -5 * bytesize.Kibibyte},
|
||
|
{"+5KiB", 5 * bytesize.Kibibyte},
|
||
|
{"-0", 0},
|
||
|
{"+0", 0},
|
||
|
// decimal
|
||
|
{"5.0KiB", 5 * bytesize.Kibibyte},
|
||
|
{"5.6KiB", 5*bytesize.Kibibyte + bytesize.Kibibyte*6/10},
|
||
|
{"5.KiB", 5 * bytesize.Kibibyte},
|
||
|
{".5KiB", bytesize.Kibibyte / 2},
|
||
|
{"1.0KiB", 1 * bytesize.Kibibyte},
|
||
|
{"1.00KiB", 1 * bytesize.Kibibyte},
|
||
|
{"1.004KiB", 1*bytesize.Kibibyte + 4*bytesize.Byte},
|
||
|
{"1.0040KiB", 1*bytesize.Kibibyte + 4*bytesize.Byte},
|
||
|
{"100.00100KiB", 100*bytesize.Kibibyte + 1*bytesize.Byte},
|
||
|
// different units
|
||
|
{"10B", 10 * bytesize.Byte},
|
||
|
{"11KiB", 11 * bytesize.Kibibyte},
|
||
|
{"12MiB", 12 * bytesize.Mebibyte},
|
||
|
{"12GiB", 12 * bytesize.Gibibyte},
|
||
|
{"13TiB", 13 * bytesize.Tebibyte},
|
||
|
{"14PiB", 14 * bytesize.Pebibyte},
|
||
|
// composite durations
|
||
|
{"3PiB30TiB", 3*bytesize.Pebibyte + 30*bytesize.Tebibyte},
|
||
|
{"10.5MiB4TiB", 4*bytesize.Tebibyte + 10*bytesize.Mebibyte + bytesize.Mebibyte/2},
|
||
|
{"-2TiB3.4MiB", -(2*bytesize.Tebibyte + 3*bytesize.Mebibyte + bytesize.Mebibyte*4/10)},
|
||
|
{
|
||
|
"1PiB2TiB3GiB4MiB5KiB6B",
|
||
|
1*bytesize.Pebibyte + 2*bytesize.Tebibyte + 3*bytesize.Gibibyte + 4*bytesize.Mebibyte + 5*bytesize.Kibibyte + 6*bytesize.Byte,
|
||
|
},
|
||
|
{
|
||
|
"39PiB9TiB14.425GiB",
|
||
|
39*bytesize.Pebibyte + 9*bytesize.Tebibyte + 14*bytesize.Gibibyte + bytesize.Gibibyte*425/1000,
|
||
|
},
|
||
|
// large value
|
||
|
{"52763797000B", 52763797000 * bytesize.Byte},
|
||
|
// more than 9 digits after decimal point
|
||
|
{"0.3333333333333333333GiB", bytesize.Gibibyte * 3333333333 / 1e10},
|
||
|
// 9007199254740993 = 1<<53+1 cannot be stored precisely in a float64
|
||
|
{"9007199254740993B", (1<<53 + 1) * bytesize.Byte},
|
||
|
// largest duration that can be represented by int64 in nanoseconds
|
||
|
{"9223372036854775807B", (1<<63 - 1) * bytesize.Byte},
|
||
|
{"-9223372036854775808B", -1 << 63 * bytesize.Byte},
|
||
|
// largest negative value
|
||
|
{"-9223372036854775808B", -1 << 63 * bytesize.Byte},
|
||
|
{"0.100000000000000000000MiB", bytesize.Mebibyte * 1 / 10},
|
||
|
|
||
|
// simple
|
||
|
{"5GB", 5 * bytesize.Gigabyte},
|
||
|
{"30GB", 30 * bytesize.Gigabyte},
|
||
|
{"1478GB", 1478 * bytesize.Gigabyte},
|
||
|
// sign
|
||
|
{"-5GB", -5 * bytesize.Gigabyte},
|
||
|
{"+5GB", 5 * bytesize.Gigabyte},
|
||
|
// decimal
|
||
|
{"5.0GB", 5 * bytesize.Gigabyte},
|
||
|
{"5.6GB", 5*bytesize.Gigabyte + 600*bytesize.Megabyte},
|
||
|
{"5.GB", 5 * bytesize.Gigabyte},
|
||
|
{".5GB", 500 * bytesize.Megabyte},
|
||
|
{"1.0GB", 1 * bytesize.Gigabyte},
|
||
|
{"1.00GB", 1 * bytesize.Gigabyte},
|
||
|
{"1.004GB", 1*bytesize.Gigabyte + 4*bytesize.Megabyte},
|
||
|
{"1.0040GB", 1*bytesize.Gigabyte + 4*bytesize.Megabyte},
|
||
|
{"100.00100GB", 100*bytesize.Gigabyte + 1*bytesize.Megabyte},
|
||
|
// different units
|
||
|
{"10B", 10 * bytesize.Byte},
|
||
|
{"11kB", 11 * bytesize.Kilobyte},
|
||
|
{"12MB", 12 * bytesize.Megabyte},
|
||
|
{"12GB", 12 * bytesize.Gigabyte},
|
||
|
{"13TB", 13 * bytesize.Terabyte},
|
||
|
{"14PB", 14 * bytesize.Petabyte},
|
||
|
// composite durations
|
||
|
{"3GB30MB", 3*bytesize.Gigabyte + 30*bytesize.Megabyte},
|
||
|
{"10.5MB4GB", 4*bytesize.Gigabyte + 10*bytesize.Megabyte + 500*bytesize.Kilobyte},
|
||
|
{"-2TB3.4GB", -(2*bytesize.Terabyte + 3*bytesize.Gigabyte + 400*bytesize.Megabyte)},
|
||
|
{
|
||
|
"1PB2TB3GB4MB5kB6B",
|
||
|
1*bytesize.Petabyte + 2*bytesize.Terabyte + 3*bytesize.Gigabyte + 4*bytesize.Megabyte + 5*bytesize.Kilobyte + 6*bytesize.Byte,
|
||
|
},
|
||
|
{"39PB9TB14.425GB", 39*bytesize.Petabyte + 9*bytesize.Terabyte + 14*bytesize.Gigabyte + 425*bytesize.Megabyte},
|
||
|
{"9223372036854775.807kB", (1<<63 - 1) * bytesize.Byte},
|
||
|
{"9223372036GB854MB775kB807B", (1<<63 - 1) * bytesize.Byte},
|
||
|
{"-9223372036854775.808kB", -1 << 63 * bytesize.Byte},
|
||
|
{"-9223372036GB854MB775kB808B", -1 << 63 * bytesize.Byte},
|
||
|
// largest negative round trip value
|
||
|
{"-9223372036GB854MB775.808kB", -1 << 63 * bytesize.Byte},
|
||
|
}
|
||
|
|
||
|
func TestParse(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
for _, tc := range parseTests {
|
||
|
d, err := bytesize.Parse(tc.in)
|
||
|
if err != nil || d != tc.want {
|
||
|
t.Errorf("Parse(%q) = %v, %v, want %v, nil", tc.in, d, err, tc.want)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var parseErrorTests = []struct {
|
||
|
in string
|
||
|
expect string
|
||
|
}{
|
||
|
// invalid
|
||
|
{"", `""`},
|
||
|
{"3", `"3"`},
|
||
|
{"-", `"-"`},
|
||
|
{"kB", `"kB"`},
|
||
|
{".", `"."`},
|
||
|
{"-.", `"-."`},
|
||
|
{".MB", `".MB"`},
|
||
|
{"+.MB", `"+.MB"`},
|
||
|
{"1ExB", `"1ExB"`},
|
||
|
{"\x85\x85", `"\x85\x85"`},
|
||
|
{"\xffff", `"\xffff"`},
|
||
|
{"hello \xffff world", `"hello \xffff world"`},
|
||
|
{"\uFFFD", `"�"`}, // utf8.RuneError
|
||
|
{"\uFFFD hello \uFFFD world", `"� hello � world"`}, // utf8.RuneError
|
||
|
// overflow
|
||
|
{"9223372036854775810B", `"9223372036854775810B"`},
|
||
|
{"9223372036854775808B", `"9223372036854775808B"`},
|
||
|
{"-9223372036854775809B", `"-9223372036854775809B"`},
|
||
|
{"9223372036854776kB", `"9223372036854776kB"`},
|
||
|
{"3000000PB", `"3000000PB"`},
|
||
|
{"9223372036854775.808KiB", `"9223372036854775.808KiB"`},
|
||
|
{"9223372036854MB775kB808B", `"9223372036854MB775kB808B"`},
|
||
|
}
|
||
|
|
||
|
func TestParseErrors(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
for _, tc := range parseErrorTests {
|
||
|
_, err := bytesize.Parse(tc.in)
|
||
|
if err == nil {
|
||
|
t.Errorf("Parse(%q) = _, nil, want _, non-nil", tc.in)
|
||
|
} else if !strings.Contains(err.Error(), tc.expect) {
|
||
|
t.Errorf("Parse(%q) = _, %q, error does not contain %q", tc.in, err, tc.expect)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestParseRoundTrip(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
max0 := bytesize.Size(math.MaxInt64)
|
||
|
max1, err := bytesize.Parse(max0.String())
|
||
|
|
||
|
if err != nil || max0 != max1 {
|
||
|
t.Errorf("round-trip failed: %d => %q => %d, %v", max0, max0.String(), max1, err)
|
||
|
}
|
||
|
|
||
|
min0 := bytesize.Size(math.MinInt64)
|
||
|
min1, err := bytesize.Parse(min0.String())
|
||
|
|
||
|
if err != nil || min0 != min1 {
|
||
|
t.Errorf("round-trip failed: %d => %q => %d, %v", min0, min0.String(), min1, err)
|
||
|
}
|
||
|
|
||
|
for range 100 {
|
||
|
// Resolutions finer than milliseconds will result in
|
||
|
// imprecise round-trips.
|
||
|
d0 := bytesize.Size(rand.Int31()) * bytesize.Megabyte
|
||
|
s := d0.String()
|
||
|
d1, err := bytesize.Parse(s)
|
||
|
|
||
|
if err != nil || d0 != d1 {
|
||
|
t.Errorf("round-trip failed: %d => %q => %d, %v", d0, s, d1, err)
|
||
|
}
|
||
|
}
|
||
|
}
|