2008-11-24 15:51:33 -07:00
|
|
|
// Copyright 2009 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.
|
|
|
|
|
2009-08-12 14:18:37 -06:00
|
|
|
package fmt_test
|
2008-11-24 15:51:33 -07:00
|
|
|
|
|
|
|
import (
|
2011-09-01 19:47:15 -06:00
|
|
|
"bytes"
|
2009-12-15 16:27:16 -07:00
|
|
|
. "fmt"
|
|
|
|
"io"
|
|
|
|
"math"
|
2010-02-03 17:31:34 -07:00
|
|
|
"runtime" // for the malloc count test only
|
2009-12-15 16:27:16 -07:00
|
|
|
"strings"
|
|
|
|
"testing"
|
2011-12-05 17:45:51 -07:00
|
|
|
"time"
|
2008-11-24 15:51:33 -07:00
|
|
|
)
|
|
|
|
|
2010-06-14 18:16:35 -06:00
|
|
|
type (
|
|
|
|
renamedBool bool
|
|
|
|
renamedInt int
|
|
|
|
renamedInt8 int8
|
|
|
|
renamedInt16 int16
|
|
|
|
renamedInt32 int32
|
|
|
|
renamedInt64 int64
|
|
|
|
renamedUint uint
|
|
|
|
renamedUint8 uint8
|
|
|
|
renamedUint16 uint16
|
|
|
|
renamedUint32 uint32
|
|
|
|
renamedUint64 uint64
|
|
|
|
renamedUintptr uintptr
|
|
|
|
renamedString string
|
|
|
|
renamedBytes []byte
|
|
|
|
renamedFloat32 float32
|
|
|
|
renamedFloat64 float64
|
|
|
|
renamedComplex64 complex64
|
|
|
|
renamedComplex128 complex128
|
|
|
|
)
|
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
func TestFmtInterface(t *testing.T) {
|
2009-10-06 16:38:57 -06:00
|
|
|
var i1 interface{}
|
2009-12-15 16:27:16 -07:00
|
|
|
i1 = "abc"
|
|
|
|
s := Sprintf("%s", i1)
|
2008-11-24 15:51:33 -07:00
|
|
|
if s != "abc" {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf(`Sprintf("%%s", empty("abc")) = %q want %q`, s, "abc")
|
2008-11-24 15:51:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-15 17:03:27 -07:00
|
|
|
const b32 uint32 = 1<<32 - 1
|
|
|
|
const b64 uint64 = 1<<64 - 1
|
2009-10-06 16:38:57 -06:00
|
|
|
|
2011-11-23 10:04:02 -07:00
|
|
|
var array = [5]int{1, 2, 3, 4, 5}
|
|
|
|
var iarray = [4]interface{}{1, "hello", 2.5, nil}
|
|
|
|
var slice = array[:]
|
|
|
|
var islice = iarray[:]
|
2008-11-24 15:51:33 -07:00
|
|
|
|
2009-08-31 17:38:30 -06:00
|
|
|
type A struct {
|
2009-12-15 16:27:16 -07:00
|
|
|
i int
|
|
|
|
j uint
|
|
|
|
s string
|
|
|
|
x []int
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
|
|
|
|
2009-11-17 23:14:34 -07:00
|
|
|
type I int
|
|
|
|
|
2010-06-14 18:16:35 -06:00
|
|
|
func (i I) String() string { return Sprintf("<%d>", int(i)) }
|
2009-11-17 23:14:34 -07:00
|
|
|
|
|
|
|
type B struct {
|
2011-10-17 16:48:45 -06:00
|
|
|
I I
|
2009-12-15 16:27:16 -07:00
|
|
|
j int
|
2009-11-17 23:14:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
type C struct {
|
2009-12-15 16:27:16 -07:00
|
|
|
i int
|
|
|
|
B
|
2009-11-17 23:14:34 -07:00
|
|
|
}
|
|
|
|
|
2010-08-13 01:26:32 -06:00
|
|
|
type F int
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (f F) Format(s State, c rune) {
|
2010-08-13 01:26:32 -06:00
|
|
|
Fprintf(s, "<%c=F(%d)>", c, int(f))
|
|
|
|
}
|
|
|
|
|
|
|
|
type G int
|
|
|
|
|
|
|
|
func (g G) GoString() string {
|
|
|
|
return Sprintf("GoString(%d)", int(g))
|
|
|
|
}
|
|
|
|
|
|
|
|
type S struct {
|
2011-10-17 16:48:45 -06:00
|
|
|
F F // a struct field that Formats
|
|
|
|
G G // a struct field that GoStrings
|
2010-08-13 01:26:32 -06:00
|
|
|
}
|
|
|
|
|
2011-10-19 14:26:08 -06:00
|
|
|
type SI struct {
|
|
|
|
I interface{}
|
|
|
|
}
|
|
|
|
|
2010-08-13 15:37:03 -06:00
|
|
|
// A type with a String method with pointer receiver for testing %p
|
|
|
|
type P int
|
|
|
|
|
|
|
|
var pValue P
|
|
|
|
|
|
|
|
func (p *P) String() string {
|
|
|
|
return "String(p)"
|
|
|
|
}
|
|
|
|
|
2009-10-06 16:38:57 -06:00
|
|
|
var b byte
|
2009-08-31 17:38:30 -06:00
|
|
|
|
2011-01-05 12:42:35 -07:00
|
|
|
var fmttests = []struct {
|
|
|
|
fmt string
|
|
|
|
val interface{}
|
|
|
|
out string
|
|
|
|
}{
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%d", 12345, "12345"},
|
|
|
|
{"%v", 12345, "12345"},
|
|
|
|
{"%t", true, "true"},
|
2010-06-14 18:16:35 -06:00
|
|
|
|
2008-11-24 15:51:33 -07:00
|
|
|
// basic string
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%s", "abc", "abc"},
|
|
|
|
{"%x", "abc", "616263"},
|
|
|
|
{"%x", "xyz", "78797a"},
|
|
|
|
{"%X", "xyz", "78797A"},
|
|
|
|
{"%q", "abc", `"abc"`},
|
2008-11-24 15:51:33 -07:00
|
|
|
|
|
|
|
// basic bytes
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%s", []byte("abc"), "abc"},
|
|
|
|
{"%x", []byte("abc"), "616263"},
|
2010-11-29 08:30:36 -07:00
|
|
|
{"% x", []byte("abc\xff"), "61 62 63 ff"},
|
|
|
|
{"% X", []byte("abc\xff"), "61 62 63 FF"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%x", []byte("xyz"), "78797a"},
|
|
|
|
{"%X", []byte("xyz"), "78797A"},
|
|
|
|
{"%q", []byte("abc"), `"abc"`},
|
2008-11-24 15:51:33 -07:00
|
|
|
|
|
|
|
// escaped strings
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%#q", `abc`, "`abc`"},
|
|
|
|
{"%#q", `"`, "`\"`"},
|
|
|
|
{"1 %#q", `\n`, "1 `\\n`"},
|
|
|
|
{"2 %#q", "\n", `2 "\n"`},
|
|
|
|
{"%q", `"`, `"\""`},
|
|
|
|
{"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
|
|
|
|
{"%q", "abc\xffdef", `"abc\xffdef"`},
|
2011-06-07 06:23:08 -06:00
|
|
|
{"%q", "\u263a", `"☺"`},
|
2011-06-10 18:03:02 -06:00
|
|
|
{"%+q", "\u263a", `"\u263a"`},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%q", "\U0010ffff", `"\U0010ffff"`},
|
2008-11-24 15:51:33 -07:00
|
|
|
|
2011-05-25 05:25:15 -06:00
|
|
|
// escaped characters
|
|
|
|
{"%q", 'x', `'x'`},
|
|
|
|
{"%q", 0, `'\x00'`},
|
|
|
|
{"%q", '\n', `'\n'`},
|
2011-06-07 06:23:08 -06:00
|
|
|
{"%q", '\u0e00', `'\u0e00'`}, // not a printable rune.
|
|
|
|
{"%q", '\U000c2345', `'\U000c2345'`}, // not a printable rune.
|
2011-05-25 05:25:15 -06:00
|
|
|
{"%q", int64(0x7FFFFFFF), `%!q(int64=2147483647)`},
|
|
|
|
{"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
|
|
|
|
{"%q", '"', `'"'`},
|
|
|
|
{"%q", '\'', `'\''`},
|
2011-06-10 18:03:02 -06:00
|
|
|
{"%q", "\u263a", `"☺"`},
|
|
|
|
{"%+q", "\u263a", `"\u263a"`},
|
2011-05-25 05:25:15 -06:00
|
|
|
|
2008-11-24 15:51:33 -07:00
|
|
|
// width
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%5s", "abc", " abc"},
|
2011-06-07 06:23:08 -06:00
|
|
|
{"%2s", "\u263a", " ☺"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%-5s", "abc", "abc "},
|
2011-03-31 15:56:01 -06:00
|
|
|
{"%-8q", "abc", `"abc" `},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%05s", "abc", "00abc"},
|
2011-03-31 15:56:01 -06:00
|
|
|
{"%08q", "abc", `000"abc"`},
|
|
|
|
{"%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"},
|
|
|
|
{"%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"},
|
|
|
|
{"%.5s", "日本語日本語", "日本語日本"},
|
|
|
|
{"%.5s", []byte("日本語日本語"), "日本語日本"},
|
|
|
|
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
|
2011-06-07 06:23:08 -06:00
|
|
|
{"%.3q", "日本語日本語", `"日本語"`},
|
|
|
|
{"%.3q", []byte("日本語日本語"), `"日本語"`},
|
|
|
|
{"%10.1q", "日本語日本語", ` "日"`},
|
2008-11-24 15:51:33 -07:00
|
|
|
|
|
|
|
// integers
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%d", 12345, "12345"},
|
|
|
|
{"%d", -12345, "-12345"},
|
|
|
|
{"%10d", 12345, " 12345"},
|
|
|
|
{"%10d", -12345, " -12345"},
|
|
|
|
{"%+10d", 12345, " +12345"},
|
|
|
|
{"%010d", 12345, "0000012345"},
|
|
|
|
{"%010d", -12345, "-000012345"},
|
|
|
|
{"%-10d", 12345, "12345 "},
|
|
|
|
{"%010.3d", 1, " 001"},
|
|
|
|
{"%010.3d", -1, " -001"},
|
|
|
|
{"%+d", 12345, "+12345"},
|
|
|
|
{"%+d", -12345, "-12345"},
|
|
|
|
{"%+d", 0, "+0"},
|
|
|
|
{"% d", 0, " 0"},
|
|
|
|
{"% d", 12345, " 12345"},
|
2011-07-21 00:46:51 -06:00
|
|
|
{"%.0d", 0, ""},
|
|
|
|
{"%.d", 0, ""},
|
2008-11-24 15:51:33 -07:00
|
|
|
|
2010-12-06 12:23:37 -07:00
|
|
|
// unicode format
|
|
|
|
{"%U", 0x1, "U+0001"},
|
2011-04-12 12:03:05 -06:00
|
|
|
{"%U", uint(0x1), "U+0001"},
|
2010-12-06 12:23:37 -07:00
|
|
|
{"%.8U", 0x2, "U+00000002"},
|
|
|
|
{"%U", 0x1234, "U+1234"},
|
|
|
|
{"%U", 0x12345, "U+12345"},
|
|
|
|
{"%10.6U", 0xABC, " U+000ABC"},
|
|
|
|
{"%-10.6U", 0xABC, "U+000ABC "},
|
2011-06-10 18:03:02 -06:00
|
|
|
{"%U", '\n', `U+000A`},
|
|
|
|
{"%#U", '\n', `U+000A`},
|
|
|
|
{"%U", 'x', `U+0078`},
|
|
|
|
{"%#U", 'x', `U+0078 'x'`},
|
|
|
|
{"%U", '\u263a', `U+263A`},
|
|
|
|
{"%#U", '\u263a', `U+263A '☺'`},
|
2010-12-06 12:23:37 -07:00
|
|
|
|
2009-11-20 12:04:51 -07:00
|
|
|
// floats
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%+.3e", 0.0, "+0.000e+00"},
|
|
|
|
{"%+.3e", 1.0, "+1.000e+00"},
|
|
|
|
{"%+.3f", -1.0, "-1.000"},
|
|
|
|
{"% .3E", -1.0, "-1.000E+00"},
|
|
|
|
{"% .3e", 1.0, " 1.000e+00"},
|
|
|
|
{"%+.3g", 0.0, "+0"},
|
|
|
|
{"%+.3g", 1.0, "+1"},
|
|
|
|
{"%+.3g", -1.0, "-1"},
|
|
|
|
{"% .3g", -1.0, "-1"},
|
|
|
|
{"% .3g", 1.0, " 1"},
|
2009-11-20 12:04:51 -07:00
|
|
|
|
2010-03-06 14:38:14 -07:00
|
|
|
// complex values
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
|
|
|
|
{"%+.3f", 0i, "(+0.000+0.000i)"},
|
|
|
|
{"%+.3g", 0i, "(+0+0i)"},
|
|
|
|
{"%+.3e", 1 + 2i, "(+1.000e+00+2.000e+00i)"},
|
|
|
|
{"%+.3f", 1 + 2i, "(+1.000+2.000i)"},
|
|
|
|
{"%+.3g", 1 + 2i, "(+1+2i)"},
|
|
|
|
{"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
|
|
|
|
{"%.3f", 0i, "(0.000+0.000i)"},
|
|
|
|
{"%.3g", 0i, "(0+0i)"},
|
|
|
|
{"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
|
|
|
|
{"%.3f", 1 + 2i, "(1.000+2.000i)"},
|
|
|
|
{"%.3g", 1 + 2i, "(1+2i)"},
|
|
|
|
{"%.3e", -1 - 2i, "(-1.000e+00-2.000e+00i)"},
|
|
|
|
{"%.3f", -1 - 2i, "(-1.000-2.000i)"},
|
|
|
|
{"%.3g", -1 - 2i, "(-1-2i)"},
|
|
|
|
{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
|
|
|
|
{"%+.3g", complex64(1 + 2i), "(+1+2i)"},
|
|
|
|
{"%+.3g", complex128(1 + 2i), "(+1+2i)"},
|
2010-03-06 14:38:14 -07:00
|
|
|
|
2009-08-28 14:02:34 -06:00
|
|
|
// erroneous formats
|
2010-10-22 11:06:33 -06:00
|
|
|
{"", 2, "%!(EXTRA int=2)"},
|
|
|
|
{"%d", "hello", "%!d(string=hello)"},
|
2009-08-28 14:02:34 -06:00
|
|
|
|
2008-11-24 15:51:33 -07:00
|
|
|
// old test/fmt_test.go
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%d", 1234, "1234"},
|
|
|
|
{"%d", -1234, "-1234"},
|
|
|
|
{"%d", uint(1234), "1234"},
|
|
|
|
{"%d", uint32(b32), "4294967295"},
|
|
|
|
{"%d", uint64(b64), "18446744073709551615"},
|
|
|
|
{"%o", 01234, "1234"},
|
|
|
|
{"%#o", 01234, "01234"},
|
|
|
|
{"%o", uint32(b32), "37777777777"},
|
|
|
|
{"%o", uint64(b64), "1777777777777777777777"},
|
|
|
|
{"%x", 0x1234abcd, "1234abcd"},
|
|
|
|
{"%#x", 0x1234abcd, "0x1234abcd"},
|
|
|
|
{"%x", b32 - 0x1234567, "fedcba98"},
|
|
|
|
{"%X", 0x1234abcd, "1234ABCD"},
|
|
|
|
{"%X", b32 - 0x1234567, "FEDCBA98"},
|
|
|
|
{"%#X", 0, "0X0"},
|
|
|
|
{"%x", b64, "ffffffffffffffff"},
|
|
|
|
{"%b", 7, "111"},
|
|
|
|
{"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"},
|
|
|
|
{"%b", -6, "-110"},
|
2011-01-19 21:09:00 -07:00
|
|
|
{"%e", 1.0, "1.000000e+00"},
|
|
|
|
{"%e", 1234.5678e3, "1.234568e+06"},
|
|
|
|
{"%e", 1234.5678e-8, "1.234568e-05"},
|
|
|
|
{"%e", -7.0, "-7.000000e+00"},
|
|
|
|
{"%e", -1e-9, "-1.000000e-09"},
|
|
|
|
{"%f", 1234.5678e3, "1234567.800000"},
|
|
|
|
{"%f", 1234.5678e-8, "0.000012"},
|
|
|
|
{"%f", -7.0, "-7.000000"},
|
|
|
|
{"%f", -1e-9, "-0.000000"},
|
|
|
|
{"%g", 1234.5678e3, "1.2345678e+06"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%g", float32(1234.5678e3), "1.2345678e+06"},
|
2011-01-19 21:09:00 -07:00
|
|
|
{"%g", 1234.5678e-8, "1.2345678e-05"},
|
|
|
|
{"%g", -7.0, "-7"},
|
|
|
|
{"%g", -1e-9, "-1e-09"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%g", float32(-1e-9), "-1e-09"},
|
2011-01-19 21:09:00 -07:00
|
|
|
{"%E", 1.0, "1.000000E+00"},
|
|
|
|
{"%E", 1234.5678e3, "1.234568E+06"},
|
|
|
|
{"%E", 1234.5678e-8, "1.234568E-05"},
|
|
|
|
{"%E", -7.0, "-7.000000E+00"},
|
|
|
|
{"%E", -1e-9, "-1.000000E-09"},
|
|
|
|
{"%G", 1234.5678e3, "1.2345678E+06"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%G", float32(1234.5678e3), "1.2345678E+06"},
|
2011-01-19 21:09:00 -07:00
|
|
|
{"%G", 1234.5678e-8, "1.2345678E-05"},
|
|
|
|
{"%G", -7.0, "-7"},
|
|
|
|
{"%G", -1e-9, "-1E-09"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%G", float32(-1e-9), "-1E-09"},
|
|
|
|
{"%c", 'x', "x"},
|
|
|
|
{"%c", 0xe4, "ä"},
|
|
|
|
{"%c", 0x672c, "本"},
|
|
|
|
{"%c", '日', "日"},
|
|
|
|
{"%20.8d", 1234, " 00001234"},
|
|
|
|
{"%20.8d", -1234, " -00001234"},
|
|
|
|
{"%20d", 1234, " 1234"},
|
|
|
|
{"%-20.8d", 1234, "00001234 "},
|
|
|
|
{"%-20.8d", -1234, "-00001234 "},
|
|
|
|
{"%-#20.8x", 0x1234abc, "0x01234abc "},
|
|
|
|
{"%-#20.8X", 0x1234abc, "0X01234ABC "},
|
|
|
|
{"%-#20.8o", 01234, "00001234 "},
|
|
|
|
{"%.20b", 7, "00000000000000000111"},
|
|
|
|
{"%20.5s", "qwertyuiop", " qwert"},
|
|
|
|
{"%.5s", "qwertyuiop", "qwert"},
|
|
|
|
{"%-20.5s", "qwertyuiop", "qwert "},
|
|
|
|
{"%20c", 'x', " x"},
|
|
|
|
{"%-20c", 'x', "x "},
|
|
|
|
{"%20.6e", 1.2345e3, " 1.234500e+03"},
|
|
|
|
{"%20.6e", 1.2345e-3, " 1.234500e-03"},
|
|
|
|
{"%20e", 1.2345e3, " 1.234500e+03"},
|
|
|
|
{"%20e", 1.2345e-3, " 1.234500e-03"},
|
|
|
|
{"%20.8e", 1.2345e3, " 1.23450000e+03"},
|
2011-01-19 21:09:00 -07:00
|
|
|
{"%20f", 1.23456789e3, " 1234.567890"},
|
|
|
|
{"%20f", 1.23456789e-3, " 0.001235"},
|
|
|
|
{"%20f", 12345678901.23456789, " 12345678901.234568"},
|
|
|
|
{"%-20f", 1.23456789e3, "1234.567890 "},
|
|
|
|
{"%20.8f", 1.23456789e3, " 1234.56789000"},
|
|
|
|
{"%20.8f", 1.23456789e-3, " 0.00123457"},
|
|
|
|
{"%g", 1.23456789e3, "1234.56789"},
|
|
|
|
{"%g", 1.23456789e-3, "0.00123456789"},
|
|
|
|
{"%g", 1.23456789e20, "1.23456789e+20"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%20e", math.Inf(1), " +Inf"},
|
|
|
|
{"%-20f", math.Inf(-1), "-Inf "},
|
|
|
|
{"%20g", math.NaN(), " NaN"},
|
2009-08-31 17:38:30 -06:00
|
|
|
|
|
|
|
// arrays
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%v", array, "[1 2 3 4 5]"},
|
|
|
|
{"%v", iarray, "[1 hello 2.5 <nil>]"},
|
|
|
|
{"%v", &array, "&[1 2 3 4 5]"},
|
|
|
|
{"%v", &iarray, "&[1 hello 2.5 <nil>]"},
|
2009-08-31 17:38:30 -06:00
|
|
|
|
2011-11-23 10:04:02 -07:00
|
|
|
// slices
|
|
|
|
{"%v", slice, "[1 2 3 4 5]"},
|
|
|
|
{"%v", islice, "[1 hello 2.5 <nil>]"},
|
|
|
|
{"%v", &slice, "&[1 2 3 4 5]"},
|
|
|
|
{"%v", &islice, "&[1 hello 2.5 <nil>]"},
|
|
|
|
|
2010-03-06 14:38:14 -07:00
|
|
|
// complexes with %v
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%v", 1 + 2i, "(1+2i)"},
|
|
|
|
{"%v", complex64(1 + 2i), "(1+2i)"},
|
|
|
|
{"%v", complex128(1 + 2i), "(1+2i)"},
|
2010-03-06 14:38:14 -07:00
|
|
|
|
2009-08-31 17:38:30 -06:00
|
|
|
// structs
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
|
|
|
|
{"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`},
|
2009-08-31 17:38:30 -06:00
|
|
|
|
2009-11-17 23:14:34 -07:00
|
|
|
// +v on structs with Stringable items
|
2011-10-17 16:48:45 -06:00
|
|
|
{"%+v", B{1, 2}, `{I:<1> j:2}`},
|
|
|
|
{"%+v", C{1, B{2, 3}}, `{i:1 B:{I:<2> j:3}}`},
|
2009-11-17 23:14:34 -07:00
|
|
|
|
2010-02-24 23:29:37 -07:00
|
|
|
// q on Stringable items
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%s", I(23), `<23>`},
|
|
|
|
{"%q", I(23), `"<23>"`},
|
|
|
|
{"%x", I(23), `3c32333e`},
|
2011-12-05 17:45:51 -07:00
|
|
|
{"%d", I(23), `23`}, // Stringer applies only to string formats.
|
2010-02-24 23:29:37 -07:00
|
|
|
|
2009-08-31 17:38:30 -06:00
|
|
|
// go syntax
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
|
2011-03-01 14:25:52 -07:00
|
|
|
{"%#v", &b, "(*uint8)(0xPTR)"},
|
|
|
|
{"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"},
|
|
|
|
{"%#v", make(chan int), "(chan int)(0xPTR)"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
|
|
|
|
{"%#v", 1000000000, "1000000000"},
|
2011-12-02 12:45:07 -07:00
|
|
|
{"%#v", map[string]int{"a": 1}, `map[string]int{"a":1}`},
|
|
|
|
{"%#v", map[string]B{"a": {1, 2}}, `map[string]fmt_test.B{"a":fmt_test.B{I:1, j:2}}`},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
|
2011-10-31 11:09:40 -06:00
|
|
|
{"%#v", SI{}, `fmt_test.SI{I:interface {}(nil)}`},
|
2011-11-14 14:10:58 -07:00
|
|
|
{"%#v", []int(nil), `[]int(nil)`},
|
|
|
|
{"%#v", []int{}, `[]int{}`},
|
2011-11-23 10:04:02 -07:00
|
|
|
{"%#v", array, `[5]int{1, 2, 3, 4, 5}`},
|
|
|
|
{"%#v", &array, `&[5]int{1, 2, 3, 4, 5}`},
|
|
|
|
{"%#v", iarray, `[4]interface {}{1, "hello", 2.5, interface {}(nil)}`},
|
|
|
|
{"%#v", &iarray, `&[4]interface {}{1, "hello", 2.5, interface {}(nil)}`},
|
2011-12-02 12:45:07 -07:00
|
|
|
{"%#v", map[int]byte(nil), `map[int]uint8(nil)`},
|
|
|
|
{"%#v", map[int]byte{}, `map[int]uint8{}`},
|
2010-06-28 15:11:38 -06:00
|
|
|
|
|
|
|
// slices with other formats
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
|
|
|
|
{"%x", []int{1, 2, 15}, `[1 2 f]`},
|
|
|
|
{"%d", []int{1, 2, 15}, `[1 2 15]`},
|
|
|
|
{"%d", []byte{1, 2, 15}, `[1 2 15]`},
|
|
|
|
{"%q", []string{"a", "b"}, `["a" "b"]`},
|
2010-02-04 17:23:25 -07:00
|
|
|
|
2010-06-14 18:16:35 -06:00
|
|
|
// renamings
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%v", renamedBool(true), "true"},
|
|
|
|
{"%d", renamedBool(true), "%!d(fmt_test.renamedBool=true)"},
|
|
|
|
{"%o", renamedInt(8), "10"},
|
|
|
|
{"%d", renamedInt8(-9), "-9"},
|
|
|
|
{"%v", renamedInt16(10), "10"},
|
|
|
|
{"%v", renamedInt32(-11), "-11"},
|
|
|
|
{"%X", renamedInt64(255), "FF"},
|
|
|
|
{"%v", renamedUint(13), "13"},
|
|
|
|
{"%o", renamedUint8(14), "16"},
|
|
|
|
{"%X", renamedUint16(15), "F"},
|
|
|
|
{"%d", renamedUint32(16), "16"},
|
|
|
|
{"%X", renamedUint64(17), "11"},
|
|
|
|
{"%o", renamedUintptr(18), "22"},
|
|
|
|
{"%x", renamedString("thing"), "7468696e67"},
|
|
|
|
{"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`},
|
|
|
|
{"%q", renamedBytes([]byte("hello")), `"hello"`},
|
|
|
|
{"%v", renamedFloat32(22), "22"},
|
|
|
|
{"%v", renamedFloat64(33), "33"},
|
|
|
|
{"%v", renamedComplex64(3 + 4i), "(3+4i)"},
|
|
|
|
{"%v", renamedComplex128(4 - 3i), "(4-3i)"},
|
2010-06-14 18:16:35 -06:00
|
|
|
|
2010-08-13 01:26:32 -06:00
|
|
|
// Formatter
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%x", F(1), "<x=F(1)>"},
|
|
|
|
{"%x", G(2), "2"},
|
2011-10-17 16:48:45 -06:00
|
|
|
{"%+v", S{F(4), G(5)}, "{F:<v=F(4)> G:5}"},
|
2010-08-13 01:26:32 -06:00
|
|
|
|
|
|
|
// GoStringer
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%#v", G(6), "GoString(6)"},
|
2011-10-17 16:48:45 -06:00
|
|
|
{"%#v", S{F(7), G(8)}, "fmt_test.S{F:<v=F(7)>, G:GoString(8)}"},
|
2010-08-13 01:26:32 -06:00
|
|
|
|
2010-06-14 18:42:31 -06:00
|
|
|
// %T
|
2011-01-19 21:09:00 -07:00
|
|
|
{"%T", (4 - 3i), "complex128"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
|
|
|
|
{"%T", intVal, "int"},
|
|
|
|
{"%6T", &intVal, " *int"},
|
2010-06-14 18:42:31 -06:00
|
|
|
|
2010-08-13 15:37:03 -06:00
|
|
|
// %p
|
2011-03-01 14:25:52 -07:00
|
|
|
{"p0=%p", new(int), "p0=0xPTR"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"p1=%s", &pValue, "p1=String(p)"}, // String method...
|
2011-03-01 14:25:52 -07:00
|
|
|
{"p2=%p", &pValue, "p2=0xPTR"}, // ... not called with %p
|
|
|
|
{"p4=%#p", new(int), "p4=PTR"},
|
2010-08-13 15:37:03 -06:00
|
|
|
|
|
|
|
// %p on non-pointers
|
2011-03-01 14:25:52 -07:00
|
|
|
{"%p", make(chan int), "0xPTR"},
|
|
|
|
{"%p", make(map[int]int), "0xPTR"},
|
|
|
|
{"%p", make([]int, 1), "0xPTR"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%p", 27, "%!p(int=27)"}, // not a pointer at all
|
2010-08-13 15:37:03 -06:00
|
|
|
|
2011-12-05 17:45:51 -07:00
|
|
|
// %d on Stringer should give integer if possible
|
|
|
|
{"%s", time.Time{}.Month(), "January"},
|
|
|
|
{"%d", time.Time{}.Month(), "1"},
|
|
|
|
|
2010-02-04 17:23:25 -07:00
|
|
|
// erroneous things
|
2011-01-05 11:11:34 -07:00
|
|
|
{"%s %", "hello", "hello %!(NOVERB)"},
|
|
|
|
{"%s %.2", "hello", "hello %!(NOVERB)"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%d", "hello", "%!d(string=hello)"},
|
|
|
|
{"no args", "hello", "no args%!(EXTRA string=hello)"},
|
|
|
|
{"%s", nil, "%!s(<nil>)"},
|
|
|
|
{"%T", nil, "<nil>"},
|
2011-01-05 11:11:34 -07:00
|
|
|
{"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
|
2009-03-03 09:39:12 -07:00
|
|
|
}
|
2008-11-24 15:51:33 -07:00
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
func TestSprintf(t *testing.T) {
|
2009-09-15 10:41:59 -06:00
|
|
|
for _, tt := range fmttests {
|
2009-12-15 16:27:16 -07:00
|
|
|
s := Sprintf(tt.fmt, tt.val)
|
2011-03-01 14:25:52 -07:00
|
|
|
if i := strings.Index(tt.out, "PTR"); i >= 0 {
|
|
|
|
j := i
|
2009-08-31 17:38:30 -06:00
|
|
|
for ; j < len(s); j++ {
|
2009-12-15 16:27:16 -07:00
|
|
|
c := s[j]
|
2009-12-21 23:02:00 -07:00
|
|
|
if (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F') {
|
2009-11-09 13:07:39 -07:00
|
|
|
break
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
s = s[0:i] + "PTR" + s[j:]
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2008-11-24 15:51:33 -07:00
|
|
|
if s != tt.out {
|
2009-09-15 10:41:59 -06:00
|
|
|
if _, ok := tt.val.(string); ok {
|
2008-11-24 15:51:33 -07:00
|
|
|
// Don't requote the already-quoted strings.
|
|
|
|
// It's too confusing to read the errors.
|
2009-12-06 13:03:52 -07:00
|
|
|
t.Errorf("Sprintf(%q, %q) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out)
|
2008-11-24 15:51:33 -07:00
|
|
|
} else {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out)
|
2008-11-24 15:51:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-24 01:21:50 -07:00
|
|
|
func BenchmarkSprintfEmpty(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Sprintf("")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSprintfString(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Sprintf("%s", "hello")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSprintfInt(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Sprintf("%d", 5)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-06 13:03:52 -07:00
|
|
|
func BenchmarkSprintfIntInt(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Sprintf("%d %d", 5, 6)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-05 12:42:35 -07:00
|
|
|
func BenchmarkSprintfPrefixedInt(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-06 09:40:16 -07:00
|
|
|
func BenchmarkSprintfFloat(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Sprintf("%g", 5.23184)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-22 16:16:06 -07:00
|
|
|
var mallocBuf bytes.Buffer
|
|
|
|
|
|
|
|
var mallocTest = []struct {
|
2012-01-17 11:45:36 -07:00
|
|
|
max int
|
|
|
|
desc string
|
|
|
|
fn func()
|
2011-12-22 16:16:06 -07:00
|
|
|
}{
|
|
|
|
{0, `Sprintf("")`, func() { Sprintf("") }},
|
|
|
|
{1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
|
|
|
|
{1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
|
|
|
|
{2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
|
2012-01-05 19:38:01 -07:00
|
|
|
{1, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }},
|
2012-01-17 11:45:36 -07:00
|
|
|
{2, `Sprintf("%g")`, func() { Sprintf("%g", 3.14159) }}, // TODO: should be 1. See Issue 2722.
|
2011-12-22 16:16:06 -07:00
|
|
|
{0, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }},
|
|
|
|
{1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ bytes.Buffer
|
|
|
|
|
2009-12-06 13:03:52 -07:00
|
|
|
func TestCountMallocs(t *testing.T) {
|
2011-12-22 16:16:06 -07:00
|
|
|
for _, mt := range mallocTest {
|
|
|
|
const N = 100
|
|
|
|
runtime.UpdateMemStats()
|
|
|
|
mallocs := 0 - runtime.MemStats.Mallocs
|
|
|
|
for i := 0; i < N; i++ {
|
|
|
|
mt.fn()
|
|
|
|
}
|
|
|
|
runtime.UpdateMemStats()
|
|
|
|
mallocs += runtime.MemStats.Mallocs
|
2012-01-17 11:45:36 -07:00
|
|
|
if mallocs/N > uint64(mt.max) {
|
|
|
|
t.Errorf("%s: expected at most %d mallocs, got %d", mt.desc, mt.max, mallocs/N)
|
2011-12-22 16:16:06 -07:00
|
|
|
}
|
2011-09-01 19:47:15 -06:00
|
|
|
}
|
2009-12-06 13:03:52 -07:00
|
|
|
}
|
|
|
|
|
2009-10-06 16:38:57 -06:00
|
|
|
type flagPrinter struct{}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (*flagPrinter) Format(f State, c rune) {
|
2009-12-15 16:27:16 -07:00
|
|
|
s := "%"
|
2008-12-11 17:53:33 -07:00
|
|
|
for i := 0; i < 128; i++ {
|
|
|
|
if f.Flag(i) {
|
2009-11-09 13:07:39 -07:00
|
|
|
s += string(i)
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if w, ok := f.Width(); ok {
|
2009-11-09 13:07:39 -07:00
|
|
|
s += Sprintf("%d", w)
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
|
|
|
if p, ok := f.Precision(); ok {
|
2009-11-09 13:07:39 -07:00
|
|
|
s += Sprintf(".%d", p)
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
s += string(c)
|
|
|
|
io.WriteString(f, "["+s+"]")
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
|
|
|
|
2011-01-05 12:42:35 -07:00
|
|
|
var flagtests = []struct {
|
2009-12-15 16:27:16 -07:00
|
|
|
in string
|
|
|
|
out string
|
2011-01-05 12:42:35 -07:00
|
|
|
}{
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%a", "[%a]"},
|
|
|
|
{"%-a", "[%-a]"},
|
|
|
|
{"%+a", "[%+a]"},
|
|
|
|
{"%#a", "[%#a]"},
|
|
|
|
{"% a", "[% a]"},
|
|
|
|
{"%0a", "[%0a]"},
|
|
|
|
{"%1.2a", "[%1.2a]"},
|
|
|
|
{"%-1.2a", "[%-1.2a]"},
|
|
|
|
{"%+1.2a", "[%+1.2a]"},
|
|
|
|
{"%-+1.2a", "[%+-1.2a]"},
|
|
|
|
{"%-+1.2abc", "[%+-1.2a]bc"},
|
|
|
|
{"%-1.2abc", "[%-1.2a]bc"},
|
2009-03-03 09:39:12 -07:00
|
|
|
}
|
2008-12-11 17:53:33 -07:00
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
func TestFlagParser(t *testing.T) {
|
2009-12-15 16:27:16 -07:00
|
|
|
var flagprinter flagPrinter
|
2009-09-15 10:41:59 -06:00
|
|
|
for _, tt := range flagtests {
|
2009-12-15 16:27:16 -07:00
|
|
|
s := Sprintf(tt.in, &flagprinter)
|
2008-12-11 17:53:33 -07:00
|
|
|
if s != tt.out {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("Sprintf(%q, &flagprinter) => %q, want %q", tt.in, s, tt.out)
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
func TestStructPrinter(t *testing.T) {
|
2008-12-11 17:53:33 -07:00
|
|
|
var s struct {
|
2009-12-15 16:27:16 -07:00
|
|
|
a string
|
|
|
|
b string
|
|
|
|
c int
|
2009-10-06 16:38:57 -06:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
s.a = "abc"
|
|
|
|
s.b = "def"
|
|
|
|
s.c = 123
|
2011-01-05 12:42:35 -07:00
|
|
|
var tests = []struct {
|
2009-12-15 16:27:16 -07:00
|
|
|
fmt string
|
|
|
|
out string
|
2011-01-05 12:42:35 -07:00
|
|
|
}{
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%v", "{abc def 123}"},
|
|
|
|
{"%+v", "{a:abc b:def c:123}"},
|
2009-12-15 16:27:16 -07:00
|
|
|
}
|
2009-09-15 10:41:59 -06:00
|
|
|
for _, tt := range tests {
|
2009-12-15 16:27:16 -07:00
|
|
|
out := Sprintf(tt.fmt, s)
|
2008-12-11 17:53:33 -07:00
|
|
|
if out != tt.out {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out)
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-07-09 18:30:07 -06:00
|
|
|
|
|
|
|
// Check map printing using substrings so we don't depend on the print order.
|
|
|
|
func presentInMap(s string, a []string, t *testing.T) {
|
|
|
|
for i := 0; i < len(a); i++ {
|
2009-12-15 16:27:16 -07:00
|
|
|
loc := strings.Index(s, a[i])
|
2009-07-09 18:30:07 -06:00
|
|
|
if loc < 0 {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("map print: expected to find %q in %q", a[i], s)
|
2009-07-09 18:30:07 -06:00
|
|
|
}
|
|
|
|
// make sure the match ends here
|
2009-12-15 16:27:16 -07:00
|
|
|
loc += len(a[i])
|
2009-07-09 18:30:07 -06:00
|
|
|
if loc >= len(s) || (s[loc] != ' ' && s[loc] != ']') {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("map print: %q not properly terminated in %q", a[i], s)
|
2009-07-09 18:30:07 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMapPrinter(t *testing.T) {
|
2009-12-15 16:27:16 -07:00
|
|
|
m0 := make(map[int]string)
|
|
|
|
s := Sprint(m0)
|
2009-07-09 18:30:07 -06:00
|
|
|
if s != "map[]" {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("empty map printed as %q not %q", s, "map[]")
|
2009-07-09 18:30:07 -06:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
m1 := map[int]string{1: "one", 2: "two", 3: "three"}
|
|
|
|
a := []string{"1:one", "2:two", "3:three"}
|
|
|
|
presentInMap(Sprintf("%v", m1), a, t)
|
|
|
|
presentInMap(Sprint(m1), a, t)
|
2009-07-09 18:30:07 -06:00
|
|
|
}
|
2009-08-03 14:34:20 -06:00
|
|
|
|
|
|
|
func TestEmptyMap(t *testing.T) {
|
2009-12-15 16:27:16 -07:00
|
|
|
const emptyMapStr = "map[]"
|
|
|
|
var m map[string]int
|
|
|
|
s := Sprint(m)
|
2009-08-03 14:34:20 -06:00
|
|
|
if s != emptyMapStr {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("nil map printed as %q not %q", s, emptyMapStr)
|
2009-08-03 14:34:20 -06:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
m = make(map[string]int)
|
|
|
|
s = Sprint(m)
|
2009-08-03 14:34:20 -06:00
|
|
|
if s != emptyMapStr {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("empty map printed as %q not %q", s, emptyMapStr)
|
2009-08-03 14:34:20 -06:00
|
|
|
}
|
|
|
|
}
|
2010-07-29 11:50:09 -06:00
|
|
|
|
|
|
|
// Check that Sprint (and hence Print, Fprint) puts spaces in the right places,
|
|
|
|
// that is, between arg pairs in which neither is a string.
|
|
|
|
func TestBlank(t *testing.T) {
|
|
|
|
got := Sprint("<", 1, ">:", 1, 2, 3, "!")
|
|
|
|
expect := "<1>:1 2 3!"
|
|
|
|
if got != expect {
|
|
|
|
t.Errorf("got %q expected %q", got, expect)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that Sprintln (and hence Println, Fprintln) puts spaces in the right places,
|
|
|
|
// that is, between all arg pairs.
|
|
|
|
func TestBlankln(t *testing.T) {
|
|
|
|
got := Sprintln("<", 1, ">:", 1, 2, 3, "!")
|
|
|
|
expect := "< 1 >: 1 2 3 !\n"
|
|
|
|
if got != expect {
|
|
|
|
t.Errorf("got %q expected %q", got, expect)
|
|
|
|
}
|
|
|
|
}
|
2010-08-13 01:26:32 -06:00
|
|
|
|
|
|
|
// Check Formatter with Sprint, Sprintln, Sprintf
|
|
|
|
func TestFormatterPrintln(t *testing.T) {
|
|
|
|
f := F(1)
|
|
|
|
expect := "<v=F(1)>\n"
|
|
|
|
s := Sprint(f, "\n")
|
|
|
|
if s != expect {
|
2010-09-22 21:48:56 -06:00
|
|
|
t.Errorf("Sprint wrong with Formatter: expected %q got %q", expect, s)
|
2010-08-13 01:26:32 -06:00
|
|
|
}
|
|
|
|
s = Sprintln(f)
|
|
|
|
if s != expect {
|
2010-09-22 21:48:56 -06:00
|
|
|
t.Errorf("Sprintln wrong with Formatter: expected %q got %q", expect, s)
|
2010-08-13 01:26:32 -06:00
|
|
|
}
|
|
|
|
s = Sprintf("%v\n", f)
|
|
|
|
if s != expect {
|
2010-09-22 21:48:56 -06:00
|
|
|
t.Errorf("Sprintf wrong with Formatter: expected %q got %q", expect, s)
|
2010-08-13 01:26:32 -06:00
|
|
|
}
|
|
|
|
}
|
2010-09-22 00:10:38 -06:00
|
|
|
|
|
|
|
func args(a ...interface{}) []interface{} { return a }
|
|
|
|
|
2011-01-05 12:42:35 -07:00
|
|
|
var startests = []struct {
|
2010-09-22 00:10:38 -06:00
|
|
|
fmt string
|
|
|
|
in []interface{}
|
|
|
|
out string
|
2011-01-05 12:42:35 -07:00
|
|
|
}{
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%*d", args(4, 42), " 42"},
|
|
|
|
{"%.*d", args(4, 42), "0042"},
|
|
|
|
{"%*.*d", args(8, 4, 42), " 0042"},
|
|
|
|
{"%0*d", args(4, 42), "0042"},
|
|
|
|
{"%-*d", args(4, 42), "42 "},
|
2010-09-22 00:10:38 -06:00
|
|
|
|
|
|
|
// erroneous
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%*d", args(nil, 42), "%!(BADWIDTH)42"},
|
|
|
|
{"%.*d", args(nil, 42), "%!(BADPREC)42"},
|
|
|
|
{"%*d", args(5, "foo"), "%!d(string= foo)"},
|
|
|
|
{"%*% %d", args(20, 5), "% 5"},
|
2011-01-05 11:11:34 -07:00
|
|
|
{"%*", args(4), "%!(NOVERB)"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%*d", args(int32(4), 42), "%!(BADWIDTH)42"},
|
2010-09-22 00:10:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestWidthAndPrecision(t *testing.T) {
|
|
|
|
for _, tt := range startests {
|
2011-01-05 12:42:35 -07:00
|
|
|
s := Sprintf(tt.fmt, tt.in...)
|
2010-09-22 00:10:38 -06:00
|
|
|
if s != tt.out {
|
2011-01-05 11:11:34 -07:00
|
|
|
t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
|
2010-09-22 00:10:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
fmt: catch panics from calls to String etc.
This change causes Print et al. to catch panics generated by
calls to String, GoString, and Format. The panic is formatted
into the output stream as an error, but the program continues.
As a special case, if the argument was a nil pointer, the
result is just "<nil>", because that's almost certainly enough
information and handles the very common case of String
methods that don't guard against nil.
Scan does not want this change. Input must work; output can
be for debugging and it's nice to get output even when you
make a mistake.
R=dsymonds, r, adg, gri, rsc, gri
CC=golang-dev
https://golang.org/cl/4640043
2011-06-20 16:31:02 -06:00
|
|
|
|
|
|
|
// A type that panics in String.
|
|
|
|
type Panic struct {
|
|
|
|
message interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Value receiver.
|
|
|
|
func (p Panic) GoString() string {
|
|
|
|
panic(p.message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Value receiver.
|
|
|
|
func (p Panic) String() string {
|
|
|
|
panic(p.message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// A type that panics in Format.
|
|
|
|
type PanicF struct {
|
|
|
|
message interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Value receiver.
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p PanicF) Format(f State, c rune) {
|
fmt: catch panics from calls to String etc.
This change causes Print et al. to catch panics generated by
calls to String, GoString, and Format. The panic is formatted
into the output stream as an error, but the program continues.
As a special case, if the argument was a nil pointer, the
result is just "<nil>", because that's almost certainly enough
information and handles the very common case of String
methods that don't guard against nil.
Scan does not want this change. Input must work; output can
be for debugging and it's nice to get output even when you
make a mistake.
R=dsymonds, r, adg, gri, rsc, gri
CC=golang-dev
https://golang.org/cl/4640043
2011-06-20 16:31:02 -06:00
|
|
|
panic(p.message)
|
|
|
|
}
|
|
|
|
|
|
|
|
var panictests = []struct {
|
|
|
|
fmt string
|
|
|
|
in interface{}
|
|
|
|
out string
|
|
|
|
}{
|
|
|
|
// String
|
2011-12-05 17:45:51 -07:00
|
|
|
{"%s", (*Panic)(nil), "<nil>"}, // nil pointer special case
|
|
|
|
{"%s", Panic{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"},
|
|
|
|
{"%s", Panic{3}, "%s(PANIC=3)"},
|
fmt: catch panics from calls to String etc.
This change causes Print et al. to catch panics generated by
calls to String, GoString, and Format. The panic is formatted
into the output stream as an error, but the program continues.
As a special case, if the argument was a nil pointer, the
result is just "<nil>", because that's almost certainly enough
information and handles the very common case of String
methods that don't guard against nil.
Scan does not want this change. Input must work; output can
be for debugging and it's nice to get output even when you
make a mistake.
R=dsymonds, r, adg, gri, rsc, gri
CC=golang-dev
https://golang.org/cl/4640043
2011-06-20 16:31:02 -06:00
|
|
|
// GoString
|
|
|
|
{"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case
|
|
|
|
{"%#v", Panic{io.ErrUnexpectedEOF}, "%v(PANIC=unexpected EOF)"},
|
|
|
|
{"%#v", Panic{3}, "%v(PANIC=3)"},
|
|
|
|
// Format
|
|
|
|
{"%s", (*PanicF)(nil), "<nil>"}, // nil pointer special case
|
|
|
|
{"%s", PanicF{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"},
|
|
|
|
{"%s", PanicF{3}, "%s(PANIC=3)"},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPanics(t *testing.T) {
|
|
|
|
for _, 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-14 17:37:54 -07:00
|
|
|
|
|
|
|
// Test that erroneous String routine doesn't cause fatal recursion.
|
|
|
|
var recurCount = 0
|
|
|
|
|
|
|
|
type Recur struct {
|
|
|
|
i int
|
|
|
|
failed *bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r Recur) String() string {
|
|
|
|
if recurCount++; recurCount > 10 {
|
|
|
|
*r.failed = true
|
|
|
|
return "FAIL"
|
|
|
|
}
|
|
|
|
// This will call badVerb. Before the fix, that would cause us to recur into
|
|
|
|
// this routine to print %!p(value). Now we don't call the user's method
|
|
|
|
// during an error.
|
|
|
|
return Sprintf("recur@%p value: %d", r, r.i)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBadVerbRecursion(t *testing.T) {
|
|
|
|
failed := false
|
|
|
|
r := Recur{3, &failed}
|
|
|
|
Sprintf("recur@%p value: %d\n", &r, r.i)
|
|
|
|
if failed {
|
|
|
|
t.Error("fail with pointer")
|
|
|
|
}
|
|
|
|
failed = false
|
|
|
|
r = Recur{4, &failed}
|
|
|
|
Sprintf("recur@%p, value: %d\n", r, r.i)
|
|
|
|
if failed {
|
|
|
|
t.Error("fail with value")
|
|
|
|
}
|
|
|
|
}
|