mirror of
https://github.com/restic/restic.git
synced 2024-09-08 12:29:39 +02:00
523 lines
11 KiB
Go
523 lines
11 KiB
Go
|
// Copyright 2017 The Go Authors. All rights reserved.
|
|||
|
// Use of this source code is governed by a BSD-style
|
|||
|
// license that can be found in the LICENSE file.
|
|||
|
|
|||
|
package number
|
|||
|
|
|||
|
import (
|
|||
|
"fmt"
|
|||
|
"log"
|
|||
|
"testing"
|
|||
|
|
|||
|
"golang.org/x/text/language"
|
|||
|
)
|
|||
|
|
|||
|
func TestAppendDecimal(t *testing.T) {
|
|||
|
type pairs map[string]string // alternates with decimal input and result
|
|||
|
|
|||
|
testCases := []struct {
|
|||
|
pattern string
|
|||
|
// We want to be able to test some forms of patterns that cannot be
|
|||
|
// represented as a string.
|
|||
|
pat *Pattern
|
|||
|
|
|||
|
test pairs
|
|||
|
}{{
|
|||
|
pattern: "0",
|
|||
|
test: pairs{
|
|||
|
"0": "0",
|
|||
|
"1": "1",
|
|||
|
"-1": "-1",
|
|||
|
".00": "0",
|
|||
|
"10.": "10",
|
|||
|
"12": "12",
|
|||
|
"1.2": "1",
|
|||
|
"NaN": "NaN",
|
|||
|
"-Inf": "-∞",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "+0;+0",
|
|||
|
test: pairs{
|
|||
|
"0": "+0",
|
|||
|
"1": "+1",
|
|||
|
"-1": "-1",
|
|||
|
".00": "+0",
|
|||
|
"10.": "+10",
|
|||
|
"12": "+12",
|
|||
|
"1.2": "+1",
|
|||
|
"NaN": "NaN",
|
|||
|
"-Inf": "-∞",
|
|||
|
"Inf": "+∞",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "0 +;0 +",
|
|||
|
test: pairs{
|
|||
|
"0": "0 +",
|
|||
|
"1": "1 +",
|
|||
|
"-1": "1 -",
|
|||
|
".00": "0 +",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "0;0-",
|
|||
|
test: pairs{
|
|||
|
"-1": "1-",
|
|||
|
"NaN": "NaN",
|
|||
|
"-Inf": "∞-",
|
|||
|
"Inf": "∞",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "0000",
|
|||
|
test: pairs{
|
|||
|
"0": "0000",
|
|||
|
"1": "0001",
|
|||
|
"12": "0012",
|
|||
|
"12345": "12345",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: ".0",
|
|||
|
test: pairs{
|
|||
|
"0": ".0",
|
|||
|
"1": "1.0",
|
|||
|
"1.2": "1.2",
|
|||
|
"1.2345": "1.2",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#.0",
|
|||
|
test: pairs{
|
|||
|
"0": ".0",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#.0#",
|
|||
|
test: pairs{
|
|||
|
"0": ".0",
|
|||
|
"1": "1.0",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "0.0#",
|
|||
|
test: pairs{
|
|||
|
"0": "0.0",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#0.###",
|
|||
|
test: pairs{
|
|||
|
"0": "0",
|
|||
|
"1": "1",
|
|||
|
"1.2": "1.2",
|
|||
|
"1.2345": "1.234", // rounding should have been done earlier
|
|||
|
"1234.5": "1234.5",
|
|||
|
"1234.567": "1234.567",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#0.######",
|
|||
|
test: pairs{
|
|||
|
"0": "0",
|
|||
|
"1234.5678": "1234.5678",
|
|||
|
"0.123456789": "0.123457",
|
|||
|
"NaN": "NaN",
|
|||
|
"Inf": "∞",
|
|||
|
},
|
|||
|
|
|||
|
// Test separators.
|
|||
|
}, {
|
|||
|
pattern: "#,#.00",
|
|||
|
test: pairs{
|
|||
|
"100": "1,0,0.00",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#,0.##",
|
|||
|
test: pairs{
|
|||
|
"10": "1,0",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#,0",
|
|||
|
test: pairs{
|
|||
|
"10": "1,0",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#,##,#.00",
|
|||
|
test: pairs{
|
|||
|
"1000": "1,00,0.00",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#,##0.###",
|
|||
|
test: pairs{
|
|||
|
"0": "0",
|
|||
|
"1234.5678": "1,234.568",
|
|||
|
"0.123456789": "0.123",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#,##,##0.###",
|
|||
|
test: pairs{
|
|||
|
"0": "0",
|
|||
|
"123456789012": "1,23,45,67,89,012",
|
|||
|
"0.123456789": "0.123",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "0,00,000.###",
|
|||
|
test: pairs{
|
|||
|
"0": "0,00,000",
|
|||
|
"123456789012": "1,23,45,67,89,012",
|
|||
|
"12.3456789": "0,00,012.346",
|
|||
|
"0.123456789": "0,00,000.123",
|
|||
|
},
|
|||
|
|
|||
|
// Support for ill-formed patterns.
|
|||
|
}, {
|
|||
|
pattern: "#",
|
|||
|
test: pairs{
|
|||
|
".00": "", // This is the behavior of fmt.
|
|||
|
"0": "", // This is the behavior of fmt.
|
|||
|
"1": "1",
|
|||
|
"10.": "10",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: ".#",
|
|||
|
test: pairs{
|
|||
|
"0": "", // This is the behavior of fmt.
|
|||
|
"1": "1",
|
|||
|
"1.2": "1.2",
|
|||
|
"1.2345": "1.2",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#,#.##",
|
|||
|
test: pairs{
|
|||
|
"10": "1,0",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#,#",
|
|||
|
test: pairs{
|
|||
|
"10": "1,0",
|
|||
|
},
|
|||
|
|
|||
|
// Special patterns
|
|||
|
}, {
|
|||
|
pattern: "#,max_int=2",
|
|||
|
pat: &Pattern{
|
|||
|
RoundingContext: RoundingContext{
|
|||
|
MaxIntegerDigits: 2,
|
|||
|
},
|
|||
|
},
|
|||
|
test: pairs{
|
|||
|
"2017": "17",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "0,max_int=2",
|
|||
|
pat: &Pattern{
|
|||
|
RoundingContext: RoundingContext{
|
|||
|
MaxIntegerDigits: 2,
|
|||
|
MinIntegerDigits: 1,
|
|||
|
},
|
|||
|
},
|
|||
|
test: pairs{
|
|||
|
"2000": "0",
|
|||
|
"2001": "1",
|
|||
|
"2017": "17",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "00,max_int=2",
|
|||
|
pat: &Pattern{
|
|||
|
RoundingContext: RoundingContext{
|
|||
|
MaxIntegerDigits: 2,
|
|||
|
MinIntegerDigits: 2,
|
|||
|
},
|
|||
|
},
|
|||
|
test: pairs{
|
|||
|
"2000": "00",
|
|||
|
"2001": "01",
|
|||
|
"2017": "17",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "@@@@,max_int=2",
|
|||
|
pat: &Pattern{
|
|||
|
RoundingContext: RoundingContext{
|
|||
|
MaxIntegerDigits: 2,
|
|||
|
MinSignificantDigits: 4,
|
|||
|
},
|
|||
|
},
|
|||
|
test: pairs{
|
|||
|
"2017": "17.00",
|
|||
|
"2000": "0.000",
|
|||
|
"2001": "1.000",
|
|||
|
},
|
|||
|
|
|||
|
// Significant digits
|
|||
|
}, {
|
|||
|
pattern: "@@##",
|
|||
|
test: pairs{
|
|||
|
"1": "1.0",
|
|||
|
"0.1": "0.10", // leading zero does not count as significant digit
|
|||
|
"123": "123",
|
|||
|
"1234": "1234",
|
|||
|
"12345": "12340",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "@@@@",
|
|||
|
test: pairs{
|
|||
|
"1": "1.000",
|
|||
|
".1": "0.1000",
|
|||
|
".001": "0.001000",
|
|||
|
"123": "123.0",
|
|||
|
"1234": "1234",
|
|||
|
"12345": "12340", // rounding down
|
|||
|
"NaN": "NaN",
|
|||
|
"-Inf": "-∞",
|
|||
|
},
|
|||
|
|
|||
|
// TODO: rounding
|
|||
|
// {"@@@@": "23456": "23460"}, // rounding up
|
|||
|
// TODO: padding
|
|||
|
|
|||
|
// Scientific and Engineering notation
|
|||
|
}, {
|
|||
|
pattern: "#E0",
|
|||
|
test: pairs{
|
|||
|
"0": "0\u202f×\u202f10⁰",
|
|||
|
"1": "1\u202f×\u202f10⁰",
|
|||
|
"123.456": "1\u202f×\u202f10²",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "#E+0",
|
|||
|
test: pairs{
|
|||
|
"0": "0\u202f×\u202f10⁺⁰",
|
|||
|
"1000": "1\u202f×\u202f10⁺³",
|
|||
|
"1E100": "1\u202f×\u202f10⁺¹⁰⁰",
|
|||
|
"1E-100": "1\u202f×\u202f10⁻¹⁰⁰",
|
|||
|
"NaN": "NaN",
|
|||
|
"-Inf": "-∞",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "##0E00",
|
|||
|
test: pairs{
|
|||
|
"100": "100\u202f×\u202f10⁰⁰",
|
|||
|
"12345": "12\u202f×\u202f10⁰³",
|
|||
|
"123.456": "123\u202f×\u202f10⁰⁰",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "##0.###E00",
|
|||
|
test: pairs{
|
|||
|
"100": "100\u202f×\u202f10⁰⁰",
|
|||
|
"12345": "12.345\u202f×\u202f10⁰³",
|
|||
|
"123456": "123.456\u202f×\u202f10⁰³",
|
|||
|
"123.456": "123.456\u202f×\u202f10⁰⁰",
|
|||
|
"123.4567": "123.457\u202f×\u202f10⁰⁰",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "##0.000E00",
|
|||
|
test: pairs{
|
|||
|
"100": "100.000\u202f×\u202f10⁰⁰",
|
|||
|
"12345": "12.345\u202f×\u202f10⁰³",
|
|||
|
"123.456": "123.456\u202f×\u202f10⁰⁰",
|
|||
|
"12.3456": "12.346\u202f×\u202f10⁰⁰",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "@@E0",
|
|||
|
test: pairs{
|
|||
|
"0": "0.0\u202f×\u202f10⁰",
|
|||
|
"99": "9.9\u202f×\u202f10¹",
|
|||
|
"0.99": "9.9\u202f×\u202f10⁻¹",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "@###E00",
|
|||
|
test: pairs{
|
|||
|
"0": "0\u202f×\u202f10⁰⁰",
|
|||
|
"1": "1\u202f×\u202f10⁰⁰",
|
|||
|
"11": "1.1\u202f×\u202f10⁰¹",
|
|||
|
"111": "1.11\u202f×\u202f10⁰²",
|
|||
|
"1111": "1.111\u202f×\u202f10⁰³",
|
|||
|
"11111": "1.111\u202f×\u202f10⁰⁴",
|
|||
|
"0.1": "1\u202f×\u202f10⁻⁰¹",
|
|||
|
"0.11": "1.1\u202f×\u202f10⁻⁰¹",
|
|||
|
"0.001": "1\u202f×\u202f10⁻⁰³",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "*x##0",
|
|||
|
test: pairs{
|
|||
|
"0": "xx0",
|
|||
|
"10": "x10",
|
|||
|
"100": "100",
|
|||
|
"1000": "1000",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "##0*x",
|
|||
|
test: pairs{
|
|||
|
"0": "0xx",
|
|||
|
"10": "10x",
|
|||
|
"100": "100",
|
|||
|
"1000": "1000",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "* ###0.000",
|
|||
|
test: pairs{
|
|||
|
"0": " 0.000",
|
|||
|
"123": " 123.000",
|
|||
|
"123.456": " 123.456",
|
|||
|
"1234.567": "1234.567",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "**0.0#######E00",
|
|||
|
test: pairs{
|
|||
|
"0": "***0.0\u202f×\u202f10⁰⁰",
|
|||
|
"10": "***1.0\u202f×\u202f10⁰¹",
|
|||
|
"11": "***1.1\u202f×\u202f10⁰¹",
|
|||
|
"111": "**1.11\u202f×\u202f10⁰²",
|
|||
|
"1111": "*1.111\u202f×\u202f10⁰³",
|
|||
|
"11111": "1.1111\u202f×\u202f10⁰⁴",
|
|||
|
"11110": "*1.111\u202f×\u202f10⁰⁴",
|
|||
|
"11100": "**1.11\u202f×\u202f10⁰⁴",
|
|||
|
"11000": "***1.1\u202f×\u202f10⁰⁴",
|
|||
|
"10000": "***1.0\u202f×\u202f10⁰⁴",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "*xpre0suf",
|
|||
|
test: pairs{
|
|||
|
"0": "pre0suf",
|
|||
|
"10": "pre10suf",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "*∞ pre ###0 suf",
|
|||
|
test: pairs{
|
|||
|
"0": "∞∞∞ pre 0 suf",
|
|||
|
"10": "∞∞ pre 10 suf",
|
|||
|
"100": "∞ pre 100 suf",
|
|||
|
"1000": " pre 1000 suf",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "pre *∞###0 suf",
|
|||
|
test: pairs{
|
|||
|
"0": "pre ∞∞∞0 suf",
|
|||
|
"10": "pre ∞∞10 suf",
|
|||
|
"100": "pre ∞100 suf",
|
|||
|
"1000": "pre 1000 suf",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "pre ###0*∞ suf",
|
|||
|
test: pairs{
|
|||
|
"0": "pre 0∞∞∞ suf",
|
|||
|
"10": "pre 10∞∞ suf",
|
|||
|
"100": "pre 100∞ suf",
|
|||
|
"1000": "pre 1000 suf",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "pre ###0 suf *∞",
|
|||
|
test: pairs{
|
|||
|
"0": "pre 0 suf ∞∞∞",
|
|||
|
"10": "pre 10 suf ∞∞",
|
|||
|
"100": "pre 100 suf ∞",
|
|||
|
"1000": "pre 1000 suf ",
|
|||
|
},
|
|||
|
}, {
|
|||
|
// Take width of positive pattern.
|
|||
|
pattern: "**###0;**-#####0x",
|
|||
|
test: pairs{
|
|||
|
"0": "***0",
|
|||
|
"-1": "*-1x",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "0.00%",
|
|||
|
test: pairs{
|
|||
|
"0.1": "10.00%",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "0.##%",
|
|||
|
test: pairs{
|
|||
|
"0.1": "10%",
|
|||
|
"0.11": "11%",
|
|||
|
"0.111": "11.1%",
|
|||
|
"0.1111": "11.11%",
|
|||
|
"0.11111": "11.11%",
|
|||
|
},
|
|||
|
}, {
|
|||
|
pattern: "‰ 0.0#",
|
|||
|
test: pairs{
|
|||
|
"0.1": "‰ 100.0",
|
|||
|
"0.11": "‰ 110.0",
|
|||
|
"0.111": "‰ 111.0",
|
|||
|
"0.1111": "‰ 111.1",
|
|||
|
"0.11111": "‰ 111.11",
|
|||
|
"0.111111": "‰ 111.11",
|
|||
|
},
|
|||
|
}}
|
|||
|
|
|||
|
// TODO:
|
|||
|
// "#,##0.00¤",
|
|||
|
// "#,##0.00 ¤;(#,##0.00 ¤)",
|
|||
|
|
|||
|
for _, tc := range testCases {
|
|||
|
pat := tc.pat
|
|||
|
if pat == nil {
|
|||
|
var err error
|
|||
|
if pat, err = ParsePattern(tc.pattern); err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
}
|
|||
|
var f Formatter
|
|||
|
f.InitPattern(language.English, pat)
|
|||
|
for num, want := range tc.test {
|
|||
|
buf := make([]byte, 100)
|
|||
|
t.Run(tc.pattern+"/"+num, func(t *testing.T) {
|
|||
|
var d Decimal
|
|||
|
d.Convert(f.RoundingContext, dec(num))
|
|||
|
buf = f.Format(buf[:0], &d)
|
|||
|
if got := string(buf); got != want {
|
|||
|
t.Errorf("\n got %[1]q (%[1]s)\nwant %[2]q (%[2]s)", got, want)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func TestLocales(t *testing.T) {
|
|||
|
testCases := []struct {
|
|||
|
tag language.Tag
|
|||
|
num string
|
|||
|
want string
|
|||
|
}{
|
|||
|
{language.Make("en"), "123456.78", "123,456.78"},
|
|||
|
{language.Make("de"), "123456.78", "123.456,78"},
|
|||
|
{language.Make("de-CH"), "123456.78", "123’456.78"},
|
|||
|
{language.Make("fr"), "123456.78", "123 456,78"},
|
|||
|
{language.Make("bn"), "123456.78", "১,২৩,৪৫৬.৭৮"},
|
|||
|
}
|
|||
|
for _, tc := range testCases {
|
|||
|
t.Run(fmt.Sprint(tc.tag, "/", tc.num), func(t *testing.T) {
|
|||
|
var f Formatter
|
|||
|
f.InitDecimal(tc.tag)
|
|||
|
var d Decimal
|
|||
|
d.Convert(f.RoundingContext, dec(tc.num))
|
|||
|
b := f.Format(nil, &d)
|
|||
|
if got := string(b); got != tc.want {
|
|||
|
t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func TestFormatters(t *testing.T) {
|
|||
|
var f Formatter
|
|||
|
testCases := []struct {
|
|||
|
init func(t language.Tag)
|
|||
|
num string
|
|||
|
want string
|
|||
|
}{
|
|||
|
{f.InitDecimal, "123456.78", "123,456.78"},
|
|||
|
{f.InitScientific, "123456.78", "1.23\u202f×\u202f10⁵"},
|
|||
|
{f.InitEngineering, "123456.78", "123.46\u202f×\u202f10³"},
|
|||
|
{f.InitEngineering, "1234", "1.23\u202f×\u202f10³"},
|
|||
|
|
|||
|
{f.InitPercent, "0.1234", "12.34%"},
|
|||
|
{f.InitPerMille, "0.1234", "123.40‰"},
|
|||
|
}
|
|||
|
for i, tc := range testCases {
|
|||
|
t.Run(fmt.Sprint(i, "/", tc.num), func(t *testing.T) {
|
|||
|
tc.init(language.English)
|
|||
|
f.SetScale(2)
|
|||
|
var d Decimal
|
|||
|
d.Convert(f.RoundingContext, dec(tc.num))
|
|||
|
b := f.Format(nil, &d)
|
|||
|
if got := string(b); got != tc.want {
|
|||
|
t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
}
|