summaryrefslogtreecommitdiff
path: root/libgo/go/fmt/fmt_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/fmt/fmt_test.go')
-rw-r--r--libgo/go/fmt/fmt_test.go197
1 files changed, 180 insertions, 17 deletions
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
index 8e6923119de..ccd80904771 100644
--- a/libgo/go/fmt/fmt_test.go
+++ b/libgo/go/fmt/fmt_test.go
@@ -108,6 +108,20 @@ func (p *P) String() string {
var barray = [5]renamedUint8{1, 2, 3, 4, 5}
var bslice = barray[:]
+type byteStringer byte
+
+func (byteStringer) String() string { return "X" }
+
+var byteStringerSlice = []byteStringer{97, 98, 99, 100}
+
+type byteFormatter byte
+
+func (byteFormatter) Format(f State, _ rune) {
+ Fprint(f, "X")
+}
+
+var byteFormatterSlice = []byteFormatter{97, 98, 99, 100}
+
var b byte
var fmtTests = []struct {
@@ -125,13 +139,17 @@ var fmtTests = []struct {
{"%x", "xyz", "78797a"},
{"%X", "xyz", "78797A"},
{"%q", "abc", `"abc"`},
+ {"%#x", []byte("abc\xff"), "0x616263ff"},
+ {"%#X", []byte("abc\xff"), "0X616263FF"},
+ {"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"},
+ {"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"},
// basic bytes
{"%s", []byte("abc"), "abc"},
{"%x", []byte("abc"), "616263"},
{"% x", []byte("abc\xff"), "61 62 63 ff"},
- {"%#x", []byte("abc\xff"), "0x610x620x630xff"},
- {"%#X", []byte("abc\xff"), "0X610X620X630XFF"},
+ {"%#x", []byte("abc\xff"), "0x616263ff"},
+ {"%#X", []byte("abc\xff"), "0X616263FF"},
{"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"},
{"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"},
{"% X", []byte("abc\xff"), "61 62 63 FF"},
@@ -176,9 +194,18 @@ var fmtTests = []struct {
{"%.5s", "日本語日本語", "日本語日本"},
{"%.5s", []byte("日本語日本語"), "日本語日本"},
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
+ {"%.5x", "abcdefghijklmnopqrstuvwxyz", `6162636465`},
+ {"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`},
+ {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), `6162636465`},
{"%.3q", "日本語日本語", `"日本語"`},
{"%.3q", []byte("日本語日本語"), `"日本語"`},
+ {"%.1q", "日本語", `"日"`},
+ {"%.1q", []byte("日本語"), `"日"`},
+ {"%.1x", "日本語", `e6`},
+ {"%.1X", []byte("日本語"), `E6`},
{"%10.1q", "日本語日本語", ` "日"`},
+ {"%3c", '⌘', " ⌘"},
+ {"%5q", '\u2026', ` '…'`},
{"%10v", nil, " <nil>"},
{"%-10v", nil, "<nil> "},
@@ -379,7 +406,7 @@ var fmtTests = []struct {
{"%s", I(23), `<23>`},
{"%q", I(23), `"<23>"`},
{"%x", I(23), `3c32333e`},
- {"%#x", I(23), `0x3c0x320x330x3e`},
+ {"%#x", I(23), `0x3c32333e`},
{"%# x", I(23), `0x3c 0x32 0x33 0x3e`},
{"%d", I(23), `23`}, // Stringer applies only to string formats.
@@ -623,6 +650,21 @@ var fmtTests = []struct {
{"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"},
{"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"},
{"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
+
+ // []T where type T is a byte with a Stringer method.
+ {"%v", byteStringerSlice, "[X X X X]"},
+ {"%s", byteStringerSlice, "abcd"},
+ {"%q", byteStringerSlice, "\"abcd\""},
+ {"%x", byteStringerSlice, "61626364"},
+ {"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x61, 0x62, 0x63, 0x64}"},
+
+ // And the same for Formatter.
+ {"%v", byteFormatterSlice, "[X X X X]"},
+ {"%s", byteFormatterSlice, "abcd"},
+ {"%q", byteFormatterSlice, "\"abcd\""},
+ {"%x", byteFormatterSlice, "61626364"},
+ // This next case seems wrong, but the docs say the Formatter wins here.
+ {"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"},
}
// zeroFill generates zero-filled strings of the specified width. The length
@@ -672,7 +714,7 @@ func TestSprintf(t *testing.T) {
// thing as if done by hand with two singleton prints.
func TestComplexFormatting(t *testing.T) {
var yesNo = []bool{true, false}
- var signs = []float64{1, 0, -1}
+ var values = []float64{1, 0, -1, math.Inf(1), math.Inf(-1), math.NaN()}
for _, plus := range yesNo {
for _, zero := range yesNo {
for _, space := range yesNo {
@@ -697,10 +739,10 @@ func TestComplexFormatting(t *testing.T) {
imagFmt += "+"
imagFmt += "10.2"
imagFmt += string(char)
- for _, realSign := range signs {
- for _, imagSign := range signs {
- one := Sprintf(realFmt, complex(realSign, imagSign))
- two := Sprintf("("+realFmt+imagFmt+"i)", realSign, imagSign)
+ for _, realValue := range values {
+ for _, imagValue := range values {
+ one := Sprintf(realFmt, complex(realValue, imagValue))
+ two := Sprintf("("+realFmt+imagFmt+"i)", realValue, imagValue)
if one != two {
t.Error(f, one, two)
}
@@ -819,7 +861,25 @@ func BenchmarkManyArgs(b *testing.B) {
})
}
+func BenchmarkFprintInt(b *testing.B) {
+ var buf bytes.Buffer
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ Fprint(&buf, 123456)
+ }
+}
+
+func BenchmarkFprintIntNoAlloc(b *testing.B) {
+ var x interface{} = 123456
+ var buf bytes.Buffer
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ Fprint(&buf, x)
+ }
+}
+
var mallocBuf bytes.Buffer
+var mallocPointer *int // A pointer so we know the interface value won't allocate.
// gccgo numbers are different because gccgo does not have escape
// analysis yet.
@@ -833,11 +893,13 @@ var mallocTest = []struct {
{5, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
{5, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
{5, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }},
- // For %g we use a float32, not float64, to guarantee passing the argument
- // does not need to allocate memory to store the result in a pointer-sized word.
- {20, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }},
- {5, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }},
+ {20, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1?
{5, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
+ // If the interface value doesn't need to allocate, amortized allocation overhead should be zero.
+ {5, `Fprintf(buf, "%x %x %x")`, func() {
+ mallocBuf.Reset()
+ Fprintf(&mallocBuf, "%x %x %x", mallocPointer, mallocPointer, mallocPointer)
+ }},
}
var _ bytes.Buffer
@@ -859,7 +921,7 @@ func TestCountMallocs(t *testing.T) {
type flagPrinter struct{}
-func (*flagPrinter) Format(f State, c rune) {
+func (flagPrinter) Format(f State, c rune) {
s := "%"
for i := 0; i < 128; i++ {
if f.Flag(i) {
@@ -905,11 +967,12 @@ func TestFlagParser(t *testing.T) {
}
func TestStructPrinter(t *testing.T) {
- var s struct {
+ type T struct {
a string
b string
c int
}
+ var s T
s.a = "abc"
s.b = "def"
s.c = 123
@@ -919,15 +982,38 @@ func TestStructPrinter(t *testing.T) {
}{
{"%v", "{abc def 123}"},
{"%+v", "{a:abc b:def c:123}"},
+ {"%#v", `fmt_test.T{a:"abc", b:"def", c:123}`},
}
for _, tt := range tests {
out := Sprintf(tt.fmt, s)
if out != tt.out {
- t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out)
+ t.Errorf("Sprintf(%q, s) = %#q, want %#q", tt.fmt, out, tt.out)
+ }
+ // The same but with a pointer.
+ out = Sprintf(tt.fmt, &s)
+ if out != "&"+tt.out {
+ t.Errorf("Sprintf(%q, &s) = %#q, want %#q", tt.fmt, out, "&"+tt.out)
}
}
}
+func TestSlicePrinter(t *testing.T) {
+ slice := []int{}
+ s := Sprint(slice)
+ if s != "[]" {
+ t.Errorf("empty slice printed as %q not %q", s, "[]")
+ }
+ slice = []int{1, 2, 3}
+ s = Sprint(slice)
+ if s != "[1 2 3]" {
+ t.Errorf("slice: got %q expected %q", s, "[1 2 3]")
+ }
+ s = Sprint(&slice)
+ if s != "&[1 2 3]" {
+ t.Errorf("&slice: got %q expected %q", s, "&[1 2 3]")
+ }
+}
+
// presentInMap checks map printing using substrings so we don't depend on the
// print order.
func presentInMap(s string, a []string, t *testing.T) {
@@ -954,6 +1040,12 @@ func TestMapPrinter(t *testing.T) {
a := []string{"1:one", "2:two", "3:three"}
presentInMap(Sprintf("%v", m1), a, t)
presentInMap(Sprint(m1), a, t)
+ // Pointer to map prints the same but with initial &.
+ if !strings.HasPrefix(Sprint(&m1), "&") {
+ t.Errorf("no initial & for address of map")
+ }
+ presentInMap(Sprintf("%v", &m1), a, t)
+ presentInMap(Sprint(&m1), a, t)
}
func TestEmptyMap(t *testing.T) {
@@ -1084,10 +1176,10 @@ var panictests = []struct {
}
func TestPanics(t *testing.T) {
- for _, tt := range panictests {
+ for i, tt := range panictests {
s := Sprintf(tt.fmt, tt.in)
if s != tt.out {
- t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
+ t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out)
}
}
}
@@ -1147,3 +1239,74 @@ func TestNilDoesNotBecomeTyped(t *testing.T) {
t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
}
}
+
+var formatterFlagTests = []struct {
+ in string
+ val interface{}
+ out string
+}{
+ // scalar values with the (unused by fmt) 'a' verb.
+ {"%a", flagPrinter{}, "[%a]"},
+ {"%-a", flagPrinter{}, "[%-a]"},
+ {"%+a", flagPrinter{}, "[%+a]"},
+ {"%#a", flagPrinter{}, "[%#a]"},
+ {"% a", flagPrinter{}, "[% a]"},
+ {"%0a", flagPrinter{}, "[%0a]"},
+ {"%1.2a", flagPrinter{}, "[%1.2a]"},
+ {"%-1.2a", flagPrinter{}, "[%-1.2a]"},
+ {"%+1.2a", flagPrinter{}, "[%+1.2a]"},
+ {"%-+1.2a", flagPrinter{}, "[%+-1.2a]"},
+ {"%-+1.2abc", flagPrinter{}, "[%+-1.2a]bc"},
+ {"%-1.2abc", flagPrinter{}, "[%-1.2a]bc"},
+
+ // composite values with the 'a' verb
+ {"%a", [1]flagPrinter{}, "[[%a]]"},
+ {"%-a", [1]flagPrinter{}, "[[%-a]]"},
+ {"%+a", [1]flagPrinter{}, "[[%+a]]"},
+ {"%#a", [1]flagPrinter{}, "[[%#a]]"},
+ {"% a", [1]flagPrinter{}, "[[% a]]"},
+ {"%0a", [1]flagPrinter{}, "[[%0a]]"},
+ {"%1.2a", [1]flagPrinter{}, "[[%1.2a]]"},
+ {"%-1.2a", [1]flagPrinter{}, "[[%-1.2a]]"},
+ {"%+1.2a", [1]flagPrinter{}, "[[%+1.2a]]"},
+ {"%-+1.2a", [1]flagPrinter{}, "[[%+-1.2a]]"},
+ {"%-+1.2abc", [1]flagPrinter{}, "[[%+-1.2a]]bc"},
+ {"%-1.2abc", [1]flagPrinter{}, "[[%-1.2a]]bc"},
+
+ // simple values with the 'v' verb
+ {"%v", flagPrinter{}, "[%v]"},
+ {"%-v", flagPrinter{}, "[%-v]"},
+ {"%+v", flagPrinter{}, "[%+v]"},
+ {"%#v", flagPrinter{}, "[%#v]"},
+ {"% v", flagPrinter{}, "[% v]"},
+ {"%0v", flagPrinter{}, "[%0v]"},
+ {"%1.2v", flagPrinter{}, "[%1.2v]"},
+ {"%-1.2v", flagPrinter{}, "[%-1.2v]"},
+ {"%+1.2v", flagPrinter{}, "[%+1.2v]"},
+ {"%-+1.2v", flagPrinter{}, "[%+-1.2v]"},
+ {"%-+1.2vbc", flagPrinter{}, "[%+-1.2v]bc"},
+ {"%-1.2vbc", flagPrinter{}, "[%-1.2v]bc"},
+
+ // composite values with the 'v' verb.
+ {"%v", [1]flagPrinter{}, "[[%v]]"},
+ {"%-v", [1]flagPrinter{}, "[[%-v]]"},
+ {"%+v", [1]flagPrinter{}, "[[%+v]]"},
+ {"%#v", [1]flagPrinter{}, "[1]fmt_test.flagPrinter{[%#v]}"},
+ {"% v", [1]flagPrinter{}, "[[% v]]"},
+ {"%0v", [1]flagPrinter{}, "[[%0v]]"},
+ {"%1.2v", [1]flagPrinter{}, "[[%1.2v]]"},
+ {"%-1.2v", [1]flagPrinter{}, "[[%-1.2v]]"},
+ {"%+1.2v", [1]flagPrinter{}, "[[%+1.2v]]"},
+ {"%-+1.2v", [1]flagPrinter{}, "[[%+-1.2v]]"},
+ {"%-+1.2vbc", [1]flagPrinter{}, "[[%+-1.2v]]bc"},
+ {"%-1.2vbc", [1]flagPrinter{}, "[[%-1.2v]]bc"},
+}
+
+func TestFormatterFlags(t *testing.T) {
+ for _, tt := range formatterFlagTests {
+ s := Sprintf(tt.in, tt.val)
+ if s != tt.out {
+ t.Errorf("Sprintf(%q, %T) = %q, want %q", tt.in, tt.val, s, tt.out)
+ }
+ }
+}