mirror of
https://github.com/tailscale/tailscale.git
synced 2026-10-29 06:28:57 -04:00
Package unitconv implements string conversion functionality for unit prefixes such as those from the SI and IEC standards. It is catered towards printing of values for human consumption. This exists to support open-sourcing JSON migration tooling. Updates #20220 Updates tailscale/corp#791 Signed-off-by: Joe Tsai <joetsai@digital-static.net>
242 lines
7.7 KiB
Go
242 lines
7.7 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package unitconv
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestFormatSI(t *testing.T) {
|
|
tests := []struct {
|
|
in float64
|
|
unit string
|
|
want string
|
|
}{
|
|
{-123456789123456789, "W", "-123PW"},
|
|
{-12345678912345678, "W", "-12.3PW"},
|
|
{-1234567891234567, "W", "-1.23PW"},
|
|
{-123456789123456, "W", "-123TW"},
|
|
{-12345678912345, "W", "-12.3TW"},
|
|
{-1234567891234, "W", "-1.23TW"},
|
|
{-123456789123, "W", "-123GW"},
|
|
{-12345678912, "W", "-12.3GW"},
|
|
{-1234567891, "W", "-1.23GW"},
|
|
{-123456789, "W", "-123MW"},
|
|
{-12345678, "W", "-12.3MW"},
|
|
{-1234567, "W", "-1.23MW"},
|
|
{-123456, "W", "-123kW"},
|
|
{-12345, "W", "-12.3kW"},
|
|
{-1234, "W", "-1.23kW"},
|
|
{-123, "W", "-123W"},
|
|
{-12, "W", "-12W"},
|
|
{-1, "W", "-1W"},
|
|
{0, "W", "0W"},
|
|
{+123, "W", "123W"},
|
|
{+123456, "W", "123kW"},
|
|
{+123456789, "W", "123MW"},
|
|
{+123456789123, "W", "123GW"},
|
|
{+123456789123456, "W", "123TW"},
|
|
{+123456789123456789, "W", "123PW"},
|
|
{-1000000000000000000, " B", "-1 EB"},
|
|
{-1000000000000000, " B", "-1 PB"},
|
|
{-1000000000000, " B", "-1 TB"},
|
|
{-1000000000, " B", "-1 GB"},
|
|
{-1000000, " B", "-1 MB"},
|
|
{-1000, " B", "-1 kB"},
|
|
{0, " B", "0 B"},
|
|
{+1000, " B", "1 kB"},
|
|
{+1000000, " B", "1 MB"},
|
|
{+1000000000, " B", "1 GB"},
|
|
{+1000000000000, " B", "1 TB"},
|
|
{+1000000000000000, " B", "1 PB"},
|
|
{+1000000000000000000, " B", "1 EB"},
|
|
{0.123456, "m", "123mm"},
|
|
{0.0123456, "m", "12.3mm"},
|
|
{0.00123456, "m", "1.23mm"},
|
|
{0.000123456, "m", "123µm"},
|
|
{0.0000123456, "m", "12.3µm"},
|
|
{0.00000123456, "m", "1.23µm"},
|
|
{0.000000123456, "m", "123nm"},
|
|
{0.0000000123456, "m", "12.3nm"},
|
|
{0.00000000123456, "m", "1.23nm"},
|
|
{0.000000000123456, "m", "123pm"},
|
|
{0.0000000000123456, "m", "12.3pm"},
|
|
{0.00000000000123456, "m", "1.23pm"},
|
|
{0.000000000000123456, "m", "123fm"},
|
|
{0.0000000000000123456, "m", "12.3fm"},
|
|
{0.00000000000000123456, "m", "1.23fm"},
|
|
{0.000000000000000123456, "m", "123am"},
|
|
{0.0000000000000000123456, "m", "12.3am"},
|
|
{math.Nextafter(0, 1), "W", "0.00yW"},
|
|
{math.Copysign(0, -1), "W", "-0W"},
|
|
{math.Nextafter(1e0, math.Inf(-1)), "W", "1000mW"},
|
|
{1e0, "W", "1W"},
|
|
{math.Nextafter(1e0, math.Inf(+1)), "W", "1.00W"},
|
|
{math.Nextafter(50e0, math.Inf(-1)), "W", "50.0W"},
|
|
{50e0, "W", "50W"},
|
|
{math.Nextafter(50e0, math.Inf(+1)), "W", "50.0W"},
|
|
{math.Nextafter(1e3, math.Inf(-1)), "W", "1000W"},
|
|
{1e3, "W", "1kW"},
|
|
{math.Nextafter(1e3, math.Inf(+1)), "W", "1.00kW"},
|
|
{math.Nextafter(1e6, math.Inf(-1)), "W", "1000kW"},
|
|
{1e6, "W", "1MW"},
|
|
{math.Nextafter(1e6, math.Inf(+1)), "W", "1.00MW"},
|
|
{math.Nextafter(1e9, math.Inf(-1)), "W", "1000MW"},
|
|
{1e9, "W", "1GW"},
|
|
{math.Nextafter(1e9, math.Inf(+1)), "W", "1.00GW"},
|
|
{math.Nextafter(500e9, math.Inf(-1)), "W", "500GW"},
|
|
{500e9, "W", "500GW"},
|
|
{math.Nextafter(500e9, math.Inf(+1)), "W", "500GW"},
|
|
{math.Nextafter(1e12, math.Inf(-1)), "W", "1000GW"},
|
|
{1e12, "W", "1TW"},
|
|
{math.Nextafter(1e12, math.Inf(+1)), "W", "1.00TW"},
|
|
{math.Nextafter(1e15, math.Inf(-1)), "W", "1000TW"},
|
|
{1e15, "W", "1PW"},
|
|
{math.Nextafter(1e15, math.Inf(+1)), "W", "1.00PW"},
|
|
{math.Nextafter(1e18, math.Inf(-1)), "W", "1000PW"},
|
|
{1e18, "W", "1EW"},
|
|
{math.Nextafter(1e18, math.Inf(+1)), "W", "1.00EW"},
|
|
{math.Nextafter(1e21, math.Inf(-1)), "W", "1000EW"},
|
|
{1e21, "W", "1ZW"},
|
|
{math.Nextafter(1e21, math.Inf(+1)), "W", "1.00ZW"},
|
|
{math.Nextafter(1e24, math.Inf(-1)), "W", "1000ZW"},
|
|
{1e24, "W", "1YW"},
|
|
{math.Nextafter(1e24, math.Inf(+1)), "W", "1.00YW"},
|
|
{math.Inf(-1), "W", "-Inf"},
|
|
{math.Inf(+1), "W", "+Inf"},
|
|
{math.NaN(), "W", "NaN"},
|
|
}
|
|
for _, tt := range tests {
|
|
got := FormatSI(tt.in, tt.unit)
|
|
if got != tt.want {
|
|
t.Errorf("FormatSI(%v, %q) = %q, want %q", tt.in, tt.unit, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFormatIEC(t *testing.T) {
|
|
tests := []struct {
|
|
in float64
|
|
unit string
|
|
want string
|
|
}{
|
|
{-123456789123456789, "B/s", "-109.6PiB/s"},
|
|
{-12345678912345678, "B/s", "-10.96PiB/s"},
|
|
{-1234567891234567, "B/s", "-1.096PiB/s"},
|
|
{-123456789123456, "B/s", "-112.2TiB/s"},
|
|
{-12345678912345, "B/s", "-11.22TiB/s"},
|
|
{-1234567891234, "B/s", "-1.122TiB/s"},
|
|
{-123456789123, "B/s", "-114.9GiB/s"},
|
|
{-12345678912, "B/s", "-11.49GiB/s"},
|
|
{-1234567891, "B/s", "-1.149GiB/s"},
|
|
{-123456789, "B/s", "-117.7MiB/s"},
|
|
{-12345678, "B/s", "-11.77MiB/s"},
|
|
{-1234567, "B/s", "-1.177MiB/s"},
|
|
{-123456, "B/s", "-120.5KiB/s"},
|
|
{-12345, "B/s", "-12.05KiB/s"},
|
|
{-1234, "B/s", "-1.205KiB/s"},
|
|
{-123, "B/s", "-123B/s"},
|
|
{-12, "B/s", "-12B/s"},
|
|
{-1, "B/s", "-1B/s"},
|
|
{0, "B/s", "0B/s"},
|
|
{+123, "B/s", "123B/s"},
|
|
{+123456, "B/s", "120.5KiB/s"},
|
|
{+123456789, "B/s", "117.7MiB/s"},
|
|
{+123456789123, "B/s", "114.9GiB/s"},
|
|
{+123456789123456, "B/s", "112.2TiB/s"},
|
|
{+123456789123456789, "B/s", "109.6PiB/s"},
|
|
{-1000000000000000000, " B", "-888.1 PiB"},
|
|
{-1000000000000000, " B", "-909.4 TiB"},
|
|
{-1000000000000, " B", "-931.3 GiB"},
|
|
{-1000000000, " B", "-953.6 MiB"},
|
|
{-1000000, " B", "-976.5 KiB"},
|
|
{-1000, " B", "-1000 B"},
|
|
{0, " B", "0 B"},
|
|
{+1000, " B", "1000 B"},
|
|
{+1000000, " B", "976.5 KiB"},
|
|
{+1000000000, " B", "953.6 MiB"},
|
|
{+1000000000000, " B", "931.3 GiB"},
|
|
{+1000000000000000, " B", "909.4 TiB"},
|
|
{+1000000000000000000, " B", "888.1 PiB"},
|
|
{math.Nextafter(0, 1), "B", "0.000B"},
|
|
{math.Copysign(0, -1), "B", "-0B"},
|
|
{math.Nextafter(1<<0, math.Inf(-1)), "B", "1.000B"},
|
|
{1 << 0, "B", "1B"},
|
|
{math.Nextafter(1<<0, math.Inf(+1)), "B", "1.000B"},
|
|
{math.Nextafter(1<<10, math.Inf(-1)), "B", "1024B"},
|
|
{1 << 10, "B", "1KiB"},
|
|
{math.Nextafter(1<<10, math.Inf(+1)), "B", "1.000KiB"},
|
|
{math.Nextafter(1<<20, math.Inf(-1)), "B", "1024KiB"},
|
|
{1 << 20, "B", "1MiB"},
|
|
{math.Nextafter(1<<20, math.Inf(+1)), "B", "1.000MiB"},
|
|
{math.Nextafter(1<<30, math.Inf(-1)), "B", "1024MiB"},
|
|
{1 << 30, "B", "1GiB"},
|
|
{math.Nextafter(1<<30, math.Inf(+1)), "B", "1.000GiB"},
|
|
{math.Nextafter(1<<40, math.Inf(-1)), "B", "1024GiB"},
|
|
{1 << 40, "B", "1TiB"},
|
|
{math.Nextafter(1<<40, math.Inf(+1)), "B", "1.000TiB"},
|
|
{math.Nextafter(1<<50, math.Inf(-1)), "B", "1024TiB"},
|
|
{1 << 50, "B", "1PiB"},
|
|
{math.Nextafter(1<<50, math.Inf(+1)), "B", "1.000PiB"},
|
|
{math.Nextafter(1<<60, math.Inf(-1)), "B", "1024PiB"},
|
|
{1 << 60, "B", "1EiB"},
|
|
{math.Nextafter(1<<60, math.Inf(+1)), "B", "1.000EiB"},
|
|
{math.Nextafter(1<<70, math.Inf(-1)), "B", "1024EiB"},
|
|
{1 << 70, "B", "1ZiB"},
|
|
{math.Nextafter(1<<70, math.Inf(+1)), "B", "1.000ZiB"},
|
|
{math.Nextafter(1<<80, math.Inf(-1)), "B", "1024ZiB"},
|
|
{1 << 80, "B", "1YiB"},
|
|
{math.Nextafter(1<<80, math.Inf(+1)), "B", "1.000YiB"},
|
|
{math.Inf(-1), "B", "-Inf"},
|
|
{math.Inf(+1), "B", "+Inf"},
|
|
{math.NaN(), "B", "NaN"},
|
|
}
|
|
for _, tt := range tests {
|
|
got := FormatIEC(tt.in, tt.unit)
|
|
if got != tt.want {
|
|
t.Errorf("FormatIEC(%v, %q) = %q, want %q", tt.in, tt.unit, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFormatDuration(t *testing.T) {
|
|
tests := []struct {
|
|
in time.Duration
|
|
want string
|
|
}{
|
|
{-123456789123456789, "-3y333d"},
|
|
{-123456789123456, "-1d10h"},
|
|
{-123456789123, "-2m3s"},
|
|
{-123456789, "-123ms"},
|
|
{-123456, "-123µs"},
|
|
{-123, "-123ns"},
|
|
{0, "0s"},
|
|
{123, "123ns"},
|
|
{123456, "123µs"},
|
|
{123456789, "123ms"},
|
|
{123456789123, "2m3s"},
|
|
{123456789123456, "1d10h"},
|
|
{123456789123456789, "3y333d"},
|
|
{math.MinInt64, "-292y98d"},
|
|
{math.MaxInt64, "292y98d"},
|
|
{time.Minute - 1, "1m0s"},
|
|
{time.Minute, "1m0s"},
|
|
{time.Hour - 1, "60m0s"},
|
|
{time.Hour, "1h0m"},
|
|
{24*time.Hour - 1, "24h0m"},
|
|
{24 * time.Hour, "1d0h"},
|
|
{365 * 24 * time.Hour, "365d0h"},
|
|
{365*24*time.Hour + 6*time.Hour - 1, "365d6h"},
|
|
{365*24*time.Hour + 6*time.Hour, "1y0d"},
|
|
}
|
|
for _, tt := range tests {
|
|
got := FormatDuration(tt.in)
|
|
if got != tt.want {
|
|
t.Errorf("FormatDuration(%d) = %q, want %q", tt.in, got, tt.want)
|
|
}
|
|
}
|
|
}
|