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"
|
2013-03-06 16:52:32 -07:00
|
|
|
"runtime"
|
2009-12-15 16:27:16 -07:00
|
|
|
"strings"
|
|
|
|
"testing"
|
2011-12-05 17:45:51 -07:00
|
|
|
"time"
|
2012-03-06 21:27:11 -07:00
|
|
|
"unicode"
|
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{}
|
|
|
|
}
|
|
|
|
|
2013-01-22 15:12:45 -07:00
|
|
|
// P is a type with a String method with pointer receiver for testing %p.
|
2010-08-13 15:37:03 -06:00
|
|
|
type P int
|
|
|
|
|
|
|
|
var pValue P
|
|
|
|
|
|
|
|
func (p *P) String() string {
|
|
|
|
return "String(p)"
|
|
|
|
}
|
|
|
|
|
2013-01-30 18:53:53 -07:00
|
|
|
var barray = [5]renamedUint8{1, 2, 3, 4, 5}
|
|
|
|
var bslice = barray[:]
|
|
|
|
|
fmt: print byte stringers correctly
type T byte
func (T) String() string { return "X" }
fmt.Sprintf("%s", []T{97, 98, 99, 100}) == "abcd"
fmt.Sprintf("%x", []T{97, 98, 99, 100}) == "61626364"
fmt.Sprintf("%v", []T{97, 98, 99, 100}) == "[X X X X]"
This change makes the last case print correctly.
Before, it would have been "[97 98 99 100]".
Fixes #8360.
LGTM=r
R=r, dan.kortschak
CC=golang-codereviews
https://golang.org/cl/129330043
2014-08-18 16:52:52 -06:00
|
|
|
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}
|
|
|
|
|
2009-10-06 16:38:57 -06:00
|
|
|
var b byte
|
2009-08-31 17:38:30 -06:00
|
|
|
|
fmt.Printf: introduce notation for random access to arguments.
This text is added to doc.go:
Explicit argument indexes:
In Printf, Sprintf, and Fprintf, the default behavior is for each
formatting verb to format successive arguments passed in the call.
However, the notation [n] immediately before the verb indicates that the
nth one-indexed argument is to be formatted instead. The same notation
before a '*' for a width or precision selects the argument index holding
the value. After processing a bracketed expression [n], arguments n+1,
n+2, etc. will be processed unless otherwise directed.
For example,
fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
will yield "22, 11", while
fmt.Sprintf("%[3]*[2].*[1]f", 12.0, 2, 6),
equivalent to
fmt.Sprintf("%6.2f", 12.0),
will yield " 12.00". Because an explicit index affects subsequent verbs,
this notation can be used to print the same values multiple times
by resetting the index for the first argument to be repeated:
fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
will yield "16 17 0x10 0x11".
The notation chosen differs from that in C, but I believe it's easier to read
and to remember (we're indexing the arguments), and compatibility with
C's printf was never a strong goal anyway.
While we're here, change the word "field" to "arg" or "argument" in the
code; it was being misused and was confusing.
R=rsc, bradfitz, rogpeppe, minux.ma, peter.armitage
CC=golang-dev
https://golang.org/cl/9680043
2013-05-24 16:49:26 -06:00
|
|
|
var fmtTests = []struct {
|
2011-01-05 12:42:35 -07:00
|
|
|
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"`},
|
2014-06-16 11:45:05 -06:00
|
|
|
{"%#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"},
|
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"},
|
2014-06-16 11:45:05 -06:00
|
|
|
{"%#x", []byte("abc\xff"), "0x616263ff"},
|
|
|
|
{"%#X", []byte("abc\xff"), "0X616263FF"},
|
2012-09-26 14:21:38 -06:00
|
|
|
{"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"},
|
|
|
|
{"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"},
|
2010-11-29 08:30:36 -07:00
|
|
|
{"% 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"`},
|
2014-09-24 15:33:30 -06:00
|
|
|
{"%.5x", "abcdefghijklmnopqrstuvwxyz", `6162636465`},
|
|
|
|
{"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`},
|
|
|
|
{"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), `6162636465`},
|
2011-06-07 06:23:08 -06:00
|
|
|
{"%.3q", "日本語日本語", `"日本語"`},
|
|
|
|
{"%.3q", []byte("日本語日本語"), `"日本語"`},
|
2014-09-24 15:33:30 -06:00
|
|
|
{"%.1q", "日本語", `"日"`},
|
|
|
|
{"%.1q", []byte("日本語"), `"日"`},
|
|
|
|
{"%.1x", "日本語", `e6`},
|
|
|
|
{"%.1X", []byte("日本語"), `E6`},
|
2011-06-07 06:23:08 -06:00
|
|
|
{"%10.1q", "日本語日本語", ` "日"`},
|
2014-07-29 17:46:53 -06:00
|
|
|
{"%3c", '⌘', " ⌘"},
|
|
|
|
{"%5q", '\u2026', ` '…'`},
|
2013-02-20 15:30:15 -07:00
|
|
|
{"%10v", nil, " <nil>"},
|
|
|
|
{"%-10v", nil, "<nil> "},
|
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"},
|
2014-03-19 15:51:06 -06:00
|
|
|
{"%+.3F", -1.0, "-1.000"},
|
|
|
|
{"%+.3F", float32(-1.0), "-1.000"},
|
2013-12-12 07:40:16 -07:00
|
|
|
{"%+07.2f", 1.0, "+001.00"},
|
|
|
|
{"%+07.2f", -1.0, "-001.00"},
|
2014-05-21 13:30:43 -06:00
|
|
|
{"%+10.2f", +1.0, " +1.00"},
|
|
|
|
{"%+10.2f", -1.0, " -1.00"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"% .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"},
|
2013-09-14 18:45:36 -06:00
|
|
|
{"%b", float32(1.0), "8388608p-23"},
|
|
|
|
{"%b", 1.0, "4503599627370496p-52"},
|
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)"},
|
2014-03-19 15:51:06 -06:00
|
|
|
{"%.3F", 0i, "(0.000+0.000i)"},
|
|
|
|
{"%.3F", complex64(0i), "(0.000+0.000i)"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%.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)"},
|
2013-09-14 18:45:36 -06:00
|
|
|
{"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
|
|
|
|
{"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
|
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>]"},
|
2013-01-30 18:53:53 -07:00
|
|
|
{"%v", barray, "[1 2 3 4 5]"},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%v", &array, "&[1 2 3 4 5]"},
|
|
|
|
{"%v", &iarray, "&[1 hello 2.5 <nil>]"},
|
2013-01-30 18:53:53 -07:00
|
|
|
{"%v", &barray, "&[1 2 3 4 5]"},
|
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>]"},
|
2013-01-30 18:53:53 -07:00
|
|
|
{"%v", bslice, "[1 2 3 4 5]"},
|
2011-11-23 10:04:02 -07:00
|
|
|
{"%v", &slice, "&[1 2 3 4 5]"},
|
|
|
|
{"%v", &islice, "&[1 hello 2.5 <nil>]"},
|
2013-01-30 18:53:53 -07:00
|
|
|
{"%v", &bslice, "&[1 2 3 4 5]"},
|
2011-11-23 10:04:02 -07:00
|
|
|
|
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
|
|
|
|
2012-09-26 14:21:38 -06:00
|
|
|
// other formats on Stringable items
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%s", I(23), `<23>`},
|
|
|
|
{"%q", I(23), `"<23>"`},
|
|
|
|
{"%x", I(23), `3c32333e`},
|
2014-06-16 11:45:05 -06:00
|
|
|
{"%#x", I(23), `0x3c32333e`},
|
2012-09-26 14:21:38 -06:00
|
|
|
{"%# x", I(23), `0x3c 0x32 0x33 0x3e`},
|
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{}`},
|
2012-06-06 13:08:00 -06:00
|
|
|
{"%#v", "foo", `"foo"`},
|
2013-01-30 18:53:53 -07:00
|
|
|
{"%#v", barray, `[5]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
|
|
|
|
{"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
|
2014-04-03 14:11:03 -06:00
|
|
|
{"%#v", []byte(nil), "[]byte(nil)"},
|
|
|
|
{"%#v", []int32(nil), "[]int32(nil)"},
|
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"`},
|
2013-01-30 18:53:53 -07:00
|
|
|
{"%x", []renamedUint8{'a', 'b', 'c'}, "616263"},
|
|
|
|
{"%s", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "hello"},
|
|
|
|
{"%q", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, `"hello"`},
|
2010-10-22 11:06:33 -06:00
|
|
|
{"%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"},
|
2013-02-20 15:30:15 -07:00
|
|
|
{"%10T", nil, " <nil>"},
|
|
|
|
{"%-10T", nil, "<nil> "},
|
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
|
2012-02-07 21:37:05 -07:00
|
|
|
{"p3=%p", (*int)(nil), "p3=0x0"},
|
2011-03-01 14:25:52 -07:00
|
|
|
{"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
|
|
|
|
2012-02-07 21:37:05 -07:00
|
|
|
// %q on pointers
|
|
|
|
{"%q", (*int)(nil), "%!q(*int=<nil>)"},
|
|
|
|
{"%q", new(int), "%!q(*int=0xPTR)"},
|
|
|
|
|
|
|
|
// %v on pointers formats 0 as <nil>
|
|
|
|
{"%v", (*int)(nil), "<nil>"},
|
|
|
|
{"%v", new(int), "0xPTR"},
|
|
|
|
|
2012-08-17 17:12:25 -06:00
|
|
|
// %d etc. pointers use specified base.
|
|
|
|
{"%d", new(int), "PTR_d"},
|
|
|
|
{"%o", new(int), "PTR_o"},
|
|
|
|
{"%x", new(int), "PTR_x"},
|
|
|
|
|
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)"},
|
2012-01-30 11:20:38 -07:00
|
|
|
|
|
|
|
// The "<nil>" show up because maps are printed by
|
|
|
|
// first obtaining a list of keys and then looking up
|
|
|
|
// each key. Since NaNs can be map keys but cannot
|
|
|
|
// be fetched directly, the lookup fails and returns a
|
|
|
|
// zero reflect.Value, which formats as <nil>.
|
|
|
|
// This test is just to check that it shows the two NaNs at all.
|
|
|
|
{"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
|
2012-04-12 17:28:37 -06:00
|
|
|
|
|
|
|
// Used to crash because nByte didn't allow for a sign.
|
2014-01-16 10:48:23 -07:00
|
|
|
{"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
|
2012-12-11 09:49:41 -07:00
|
|
|
|
2013-08-06 16:38:46 -06:00
|
|
|
// Used to panic.
|
2014-01-16 10:48:23 -07:00
|
|
|
{"%0100d", 1, zeroFill("", 100, "1")},
|
|
|
|
{"%0100d", -1, zeroFill("-", 99, "1")},
|
|
|
|
{"%0.100f", 1.0, zeroFill("1.", 100, "")},
|
|
|
|
{"%0.100f", -1.0, zeroFill("-1.", 100, "")},
|
2013-08-06 16:38:46 -06:00
|
|
|
|
2014-06-17 15:56:54 -06:00
|
|
|
// Comparison of padding rules with C printf.
|
|
|
|
/*
|
|
|
|
C program:
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
char *format[] = {
|
|
|
|
"[%.2f]",
|
|
|
|
"[% .2f]",
|
|
|
|
"[%+.2f]",
|
|
|
|
"[%7.2f]",
|
|
|
|
"[% 7.2f]",
|
|
|
|
"[%+7.2f]",
|
|
|
|
"[%07.2f]",
|
|
|
|
"[% 07.2f]",
|
|
|
|
"[%+07.2f]",
|
|
|
|
};
|
|
|
|
|
|
|
|
int main(void) {
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 9; i++) {
|
|
|
|
printf("%s: ", format[i]);
|
|
|
|
printf(format[i], 1.0);
|
|
|
|
printf(" ");
|
|
|
|
printf(format[i], -1.0);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Output:
|
|
|
|
[%.2f]: [1.00] [-1.00]
|
|
|
|
[% .2f]: [ 1.00] [-1.00]
|
|
|
|
[%+.2f]: [+1.00] [-1.00]
|
|
|
|
[%7.2f]: [ 1.00] [ -1.00]
|
|
|
|
[% 7.2f]: [ 1.00] [ -1.00]
|
|
|
|
[%+7.2f]: [ +1.00] [ -1.00]
|
|
|
|
[%07.2f]: [0001.00] [-001.00]
|
|
|
|
[% 07.2f]: [ 001.00] [-001.00]
|
|
|
|
[%+07.2f]: [+001.00] [-001.00]
|
|
|
|
*/
|
|
|
|
{"%.2f", 1.0, "1.00"},
|
|
|
|
{"%.2f", -1.0, "-1.00"},
|
|
|
|
{"% .2f", 1.0, " 1.00"},
|
|
|
|
{"% .2f", -1.0, "-1.00"},
|
|
|
|
{"%+.2f", 1.0, "+1.00"},
|
|
|
|
{"%+.2f", -1.0, "-1.00"},
|
|
|
|
{"%7.2f", 1.0, " 1.00"},
|
|
|
|
{"%7.2f", -1.0, " -1.00"},
|
|
|
|
{"% 7.2f", 1.0, " 1.00"},
|
|
|
|
{"% 7.2f", -1.0, " -1.00"},
|
|
|
|
{"%+7.2f", 1.0, " +1.00"},
|
|
|
|
{"%+7.2f", -1.0, " -1.00"},
|
|
|
|
{"%07.2f", 1.0, "0001.00"},
|
|
|
|
{"%07.2f", -1.0, "-001.00"},
|
|
|
|
{"% 07.2f", 1.0, " 001.00"},
|
|
|
|
{"% 07.2f", -1.0, "-001.00"},
|
|
|
|
{"%+07.2f", 1.0, "+001.00"},
|
|
|
|
{"%+07.2f", -1.0, "-001.00"},
|
|
|
|
|
|
|
|
// Complex numbers: exhaustively tested in TestComplexFormatting.
|
|
|
|
{"%7.2f", 1 + 2i, "( 1.00 +2.00i)"},
|
|
|
|
{"%+07.2f", -1 - 2i, "(-001.00-002.00i)"},
|
|
|
|
// Zero padding does not apply to infinities.
|
|
|
|
{"%020f", math.Inf(-1), " -Inf"},
|
|
|
|
{"%020f", math.Inf(+1), " +Inf"},
|
|
|
|
{"% 020f", math.Inf(-1), " -Inf"},
|
|
|
|
{"% 020f", math.Inf(+1), " Inf"},
|
|
|
|
{"%+020f", math.Inf(-1), " -Inf"},
|
|
|
|
{"%+020f", math.Inf(+1), " +Inf"},
|
2013-08-06 16:38:46 -06:00
|
|
|
{"%20f", -1.0, " -1.000000"},
|
2014-06-17 15:56:54 -06:00
|
|
|
// Make sure we can handle very large widths.
|
2014-01-16 10:48:23 -07:00
|
|
|
{"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
|
2013-08-06 16:38:46 -06:00
|
|
|
|
2012-12-11 09:49:41 -07:00
|
|
|
// Complex fmt used to leave the plus flag set for future entries in the array
|
|
|
|
// causing +2+0i and +3+0i instead of 2+0i and 3+0i.
|
|
|
|
{"%v", []complex64{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"},
|
|
|
|
{"%v", []complex128{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"},
|
2013-04-29 14:52:07 -06:00
|
|
|
|
|
|
|
// Incomplete format specification caused crash.
|
|
|
|
{"%.", 3, "%!.(int=3)"},
|
2014-01-16 10:48:23 -07:00
|
|
|
|
|
|
|
// Used to panic with out-of-bounds for very large numeric representations.
|
|
|
|
// nByte is set to handle one bit per uint64 in %b format, with a negative number.
|
|
|
|
// See issue 6777.
|
|
|
|
{"%#064x", 1, zeroFill("0x", 64, "1")},
|
|
|
|
{"%#064x", -1, zeroFill("-0x", 63, "1")},
|
|
|
|
{"%#064b", 1, zeroFill("", 64, "1")},
|
|
|
|
{"%#064b", -1, zeroFill("-", 63, "1")},
|
|
|
|
{"%#064o", 1, zeroFill("", 64, "1")},
|
|
|
|
{"%#064o", -1, zeroFill("-", 63, "1")},
|
|
|
|
{"%#064d", 1, zeroFill("", 64, "1")},
|
|
|
|
{"%#064d", -1, zeroFill("-", 63, "1")},
|
|
|
|
// Test that we handle the crossover above the size of uint64
|
|
|
|
{"%#072x", 1, zeroFill("0x", 72, "1")},
|
|
|
|
{"%#072x", -1, zeroFill("-0x", 71, "1")},
|
|
|
|
{"%#072b", 1, zeroFill("", 72, "1")},
|
|
|
|
{"%#072b", -1, zeroFill("-", 71, "1")},
|
|
|
|
{"%#072o", 1, zeroFill("", 72, "1")},
|
|
|
|
{"%#072o", -1, zeroFill("-", 71, "1")},
|
|
|
|
{"%#072d", 1, zeroFill("", 72, "1")},
|
|
|
|
{"%#072d", -1, zeroFill("-", 71, "1")},
|
2014-05-21 13:30:43 -06:00
|
|
|
|
|
|
|
// Padding for complex numbers. Has been bad, then fixed, then bad again.
|
|
|
|
{"%+10.2f", +104.66 + 440.51i, "( +104.66 +440.51i)"},
|
|
|
|
{"%+10.2f", -104.66 + 440.51i, "( -104.66 +440.51i)"},
|
|
|
|
{"%+10.2f", +104.66 - 440.51i, "( +104.66 -440.51i)"},
|
|
|
|
{"%+10.2f", -104.66 - 440.51i, "( -104.66 -440.51i)"},
|
|
|
|
{"%+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)"},
|
|
|
|
{"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
|
fmt: print byte stringers correctly
type T byte
func (T) String() string { return "X" }
fmt.Sprintf("%s", []T{97, 98, 99, 100}) == "abcd"
fmt.Sprintf("%x", []T{97, 98, 99, 100}) == "61626364"
fmt.Sprintf("%v", []T{97, 98, 99, 100}) == "[X X X X]"
This change makes the last case print correctly.
Before, it would have been "[97 98 99 100]".
Fixes #8360.
LGTM=r
R=r, dan.kortschak
CC=golang-codereviews
https://golang.org/cl/129330043
2014-08-18 16:52:52 -06:00
|
|
|
|
|
|
|
// []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}"},
|
2014-01-16 10:48:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// zeroFill generates zero-filled strings of the specified width. The length
|
|
|
|
// of the suffix (but not the prefix) is compensated for in the width calculation.
|
|
|
|
func zeroFill(prefix string, width int, suffix string) string {
|
|
|
|
return prefix + strings.Repeat("0", width-len(suffix)) + suffix
|
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) {
|
fmt.Printf: introduce notation for random access to arguments.
This text is added to doc.go:
Explicit argument indexes:
In Printf, Sprintf, and Fprintf, the default behavior is for each
formatting verb to format successive arguments passed in the call.
However, the notation [n] immediately before the verb indicates that the
nth one-indexed argument is to be formatted instead. The same notation
before a '*' for a width or precision selects the argument index holding
the value. After processing a bracketed expression [n], arguments n+1,
n+2, etc. will be processed unless otherwise directed.
For example,
fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
will yield "22, 11", while
fmt.Sprintf("%[3]*[2].*[1]f", 12.0, 2, 6),
equivalent to
fmt.Sprintf("%6.2f", 12.0),
will yield " 12.00". Because an explicit index affects subsequent verbs,
this notation can be used to print the same values multiple times
by resetting the index for the first argument to be repeated:
fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
will yield "16 17 0x10 0x11".
The notation chosen differs from that in C, but I believe it's easier to read
and to remember (we're indexing the arguments), and compatibility with
C's printf was never a strong goal anyway.
While we're here, change the word "field" to "arg" or "argument" in the
code; it was being misused and was confusing.
R=rsc, bradfitz, rogpeppe, minux.ma, peter.armitage
CC=golang-dev
https://golang.org/cl/9680043
2013-05-24 16:49:26 -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 {
|
2012-08-17 17:12:25 -06:00
|
|
|
pattern := "PTR"
|
|
|
|
chars := "0123456789abcdefABCDEF"
|
|
|
|
switch {
|
|
|
|
case strings.HasPrefix(tt.out[i:], "PTR_d"):
|
|
|
|
pattern = "PTR_d"
|
|
|
|
chars = chars[:10]
|
|
|
|
case strings.HasPrefix(tt.out[i:], "PTR_o"):
|
|
|
|
pattern = "PTR_o"
|
|
|
|
chars = chars[:8]
|
|
|
|
case strings.HasPrefix(tt.out[i:], "PTR_x"):
|
|
|
|
pattern = "PTR_x"
|
|
|
|
}
|
2011-03-01 14:25:52 -07:00
|
|
|
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]
|
2012-08-17 17:12:25 -06:00
|
|
|
if !strings.ContainsRune(chars, rune(c)) {
|
2009-11-09 13:07:39 -07:00
|
|
|
break
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
|
|
|
}
|
2012-08-17 17:12:25 -06:00
|
|
|
s = s[0:i] + pattern + 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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-17 15:56:54 -06:00
|
|
|
// TestComplexFormatting checks that a complex always formats to the same
|
|
|
|
// thing as if done by hand with two singleton prints.
|
|
|
|
func TestComplexFormatting(t *testing.T) {
|
|
|
|
var yesNo = []bool{true, false}
|
2014-06-18 11:57:18 -06:00
|
|
|
var values = []float64{1, 0, -1, math.Inf(1), math.Inf(-1), math.NaN()}
|
2014-06-17 15:56:54 -06:00
|
|
|
for _, plus := range yesNo {
|
|
|
|
for _, zero := range yesNo {
|
|
|
|
for _, space := range yesNo {
|
|
|
|
for _, char := range "fFeEgG" {
|
|
|
|
realFmt := "%"
|
|
|
|
if zero {
|
|
|
|
realFmt += "0"
|
|
|
|
}
|
|
|
|
if space {
|
|
|
|
realFmt += " "
|
|
|
|
}
|
|
|
|
if plus {
|
|
|
|
realFmt += "+"
|
|
|
|
}
|
|
|
|
realFmt += "10.2"
|
|
|
|
realFmt += string(char)
|
|
|
|
// Imaginary part always has a sign, so force + and ignore space.
|
|
|
|
imagFmt := "%"
|
|
|
|
if zero {
|
|
|
|
imagFmt += "0"
|
|
|
|
}
|
|
|
|
imagFmt += "+"
|
|
|
|
imagFmt += "10.2"
|
|
|
|
imagFmt += string(char)
|
2014-06-18 11:57:18 -06:00
|
|
|
for _, realValue := range values {
|
|
|
|
for _, imagValue := range values {
|
|
|
|
one := Sprintf(realFmt, complex(realValue, imagValue))
|
|
|
|
two := Sprintf("("+realFmt+imagFmt+"i)", realValue, imagValue)
|
2014-06-17 15:56:54 -06:00
|
|
|
if one != two {
|
|
|
|
t.Error(f, one, two)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
fmt.Printf: introduce notation for random access to arguments.
This text is added to doc.go:
Explicit argument indexes:
In Printf, Sprintf, and Fprintf, the default behavior is for each
formatting verb to format successive arguments passed in the call.
However, the notation [n] immediately before the verb indicates that the
nth one-indexed argument is to be formatted instead. The same notation
before a '*' for a width or precision selects the argument index holding
the value. After processing a bracketed expression [n], arguments n+1,
n+2, etc. will be processed unless otherwise directed.
For example,
fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
will yield "22, 11", while
fmt.Sprintf("%[3]*[2].*[1]f", 12.0, 2, 6),
equivalent to
fmt.Sprintf("%6.2f", 12.0),
will yield " 12.00". Because an explicit index affects subsequent verbs,
this notation can be used to print the same values multiple times
by resetting the index for the first argument to be repeated:
fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
will yield "16 17 0x10 0x11".
The notation chosen differs from that in C, but I believe it's easier to read
and to remember (we're indexing the arguments), and compatibility with
C's printf was never a strong goal anyway.
While we're here, change the word "field" to "arg" or "argument" in the
code; it was being misused and was confusing.
R=rsc, bradfitz, rogpeppe, minux.ma, peter.armitage
CC=golang-dev
https://golang.org/cl/9680043
2013-05-24 16:49:26 -06:00
|
|
|
type SE []interface{} // slice of empty; notational compactness.
|
|
|
|
|
|
|
|
var reorderTests = []struct {
|
|
|
|
fmt string
|
|
|
|
val SE
|
|
|
|
out string
|
|
|
|
}{
|
|
|
|
{"%[1]d", SE{1}, "1"},
|
|
|
|
{"%[2]d", SE{2, 1}, "1"},
|
|
|
|
{"%[2]d %[1]d", SE{1, 2}, "2 1"},
|
|
|
|
{"%[2]*[1]d", SE{2, 5}, " 2"},
|
2013-05-29 09:29:29 -06:00
|
|
|
{"%6.2f", SE{12.0}, " 12.00"}, // Explicit version of next line.
|
|
|
|
{"%[3]*.[2]*[1]f", SE{12.0, 2, 6}, " 12.00"},
|
|
|
|
{"%[1]*.[2]*[3]f", SE{6, 2, 12.0}, " 12.00"},
|
|
|
|
{"%10f", SE{12.0}, " 12.000000"},
|
|
|
|
{"%[1]*[3]f", SE{10, 99, 12.0}, " 12.000000"},
|
|
|
|
{"%.6f", SE{12.0}, "12.000000"}, // Explicit version of next line.
|
|
|
|
{"%.[1]*[3]f", SE{6, 99, 12.0}, "12.000000"},
|
|
|
|
{"%6.f", SE{12.0}, " 12"}, // // Explicit version of next line; empty precision means zero.
|
|
|
|
{"%[1]*.[3]f", SE{6, 3, 12.0}, " 12"},
|
fmt.Printf: introduce notation for random access to arguments.
This text is added to doc.go:
Explicit argument indexes:
In Printf, Sprintf, and Fprintf, the default behavior is for each
formatting verb to format successive arguments passed in the call.
However, the notation [n] immediately before the verb indicates that the
nth one-indexed argument is to be formatted instead. The same notation
before a '*' for a width or precision selects the argument index holding
the value. After processing a bracketed expression [n], arguments n+1,
n+2, etc. will be processed unless otherwise directed.
For example,
fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
will yield "22, 11", while
fmt.Sprintf("%[3]*[2].*[1]f", 12.0, 2, 6),
equivalent to
fmt.Sprintf("%6.2f", 12.0),
will yield " 12.00". Because an explicit index affects subsequent verbs,
this notation can be used to print the same values multiple times
by resetting the index for the first argument to be repeated:
fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
will yield "16 17 0x10 0x11".
The notation chosen differs from that in C, but I believe it's easier to read
and to remember (we're indexing the arguments), and compatibility with
C's printf was never a strong goal anyway.
While we're here, change the word "field" to "arg" or "argument" in the
code; it was being misused and was confusing.
R=rsc, bradfitz, rogpeppe, minux.ma, peter.armitage
CC=golang-dev
https://golang.org/cl/9680043
2013-05-24 16:49:26 -06:00
|
|
|
// An actual use! Print the same arguments twice.
|
|
|
|
{"%d %d %d %#[1]o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015"},
|
|
|
|
|
|
|
|
// Erroneous cases.
|
2013-07-31 00:11:12 -06:00
|
|
|
{"%[d", SE{2, 1}, "%!d(BADINDEX)"},
|
2013-05-29 09:29:29 -06:00
|
|
|
{"%]d", SE{2, 1}, "%!](int=2)d%!(EXTRA int=1)"},
|
2013-07-31 00:11:12 -06:00
|
|
|
{"%[]d", SE{2, 1}, "%!d(BADINDEX)"},
|
|
|
|
{"%[-3]d", SE{2, 1}, "%!d(BADINDEX)"},
|
|
|
|
{"%[99]d", SE{2, 1}, "%!d(BADINDEX)"},
|
fmt.Printf: introduce notation for random access to arguments.
This text is added to doc.go:
Explicit argument indexes:
In Printf, Sprintf, and Fprintf, the default behavior is for each
formatting verb to format successive arguments passed in the call.
However, the notation [n] immediately before the verb indicates that the
nth one-indexed argument is to be formatted instead. The same notation
before a '*' for a width or precision selects the argument index holding
the value. After processing a bracketed expression [n], arguments n+1,
n+2, etc. will be processed unless otherwise directed.
For example,
fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
will yield "22, 11", while
fmt.Sprintf("%[3]*[2].*[1]f", 12.0, 2, 6),
equivalent to
fmt.Sprintf("%6.2f", 12.0),
will yield " 12.00". Because an explicit index affects subsequent verbs,
this notation can be used to print the same values multiple times
by resetting the index for the first argument to be repeated:
fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
will yield "16 17 0x10 0x11".
The notation chosen differs from that in C, but I believe it's easier to read
and to remember (we're indexing the arguments), and compatibility with
C's printf was never a strong goal anyway.
While we're here, change the word "field" to "arg" or "argument" in the
code; it was being misused and was confusing.
R=rsc, bradfitz, rogpeppe, minux.ma, peter.armitage
CC=golang-dev
https://golang.org/cl/9680043
2013-05-24 16:49:26 -06:00
|
|
|
{"%[3]", SE{2, 1}, "%!(NOVERB)"},
|
2013-07-31 00:11:12 -06:00
|
|
|
{"%[1].2d", SE{5, 6}, "%!d(BADINDEX)"},
|
|
|
|
{"%[1]2d", SE{2, 1}, "%!d(BADINDEX)"},
|
|
|
|
{"%3.[2]d", SE{7}, "%!d(BADINDEX)"},
|
|
|
|
{"%.[2]d", SE{7}, "%!d(BADINDEX)"},
|
|
|
|
{"%d %d %d %#[1]o %#o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015 %!o(MISSING)"},
|
2013-09-23 00:03:57 -06:00
|
|
|
{"%[5]d %[2]d %d", SE{1, 2, 3}, "%!d(BADINDEX) 2 3"},
|
|
|
|
{"%d %[3]d %d", SE{1, 2}, "1 %!d(BADINDEX) 2"}, // Erroneous index does not affect sequence.
|
fmt.Printf: introduce notation for random access to arguments.
This text is added to doc.go:
Explicit argument indexes:
In Printf, Sprintf, and Fprintf, the default behavior is for each
formatting verb to format successive arguments passed in the call.
However, the notation [n] immediately before the verb indicates that the
nth one-indexed argument is to be formatted instead. The same notation
before a '*' for a width or precision selects the argument index holding
the value. After processing a bracketed expression [n], arguments n+1,
n+2, etc. will be processed unless otherwise directed.
For example,
fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
will yield "22, 11", while
fmt.Sprintf("%[3]*[2].*[1]f", 12.0, 2, 6),
equivalent to
fmt.Sprintf("%6.2f", 12.0),
will yield " 12.00". Because an explicit index affects subsequent verbs,
this notation can be used to print the same values multiple times
by resetting the index for the first argument to be repeated:
fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
will yield "16 17 0x10 0x11".
The notation chosen differs from that in C, but I believe it's easier to read
and to remember (we're indexing the arguments), and compatibility with
C's printf was never a strong goal anyway.
While we're here, change the word "field" to "arg" or "argument" in the
code; it was being misused and was confusing.
R=rsc, bradfitz, rogpeppe, minux.ma, peter.armitage
CC=golang-dev
https://golang.org/cl/9680043
2013-05-24 16:49:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestReorder(t *testing.T) {
|
|
|
|
for _, tt := range reorderTests {
|
|
|
|
s := Sprintf(tt.fmt, tt.val...)
|
|
|
|
if s != tt.out {
|
|
|
|
t.Errorf("Sprintf(%q, %v) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out)
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-24 01:21:50 -07:00
|
|
|
func BenchmarkSprintfEmpty(b *testing.B) {
|
2014-02-24 09:46:25 -07:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
Sprintf("")
|
|
|
|
}
|
2014-01-10 02:51:11 -07:00
|
|
|
})
|
2009-11-24 01:21:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSprintfString(b *testing.B) {
|
2014-02-24 09:46:25 -07:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
Sprintf("%s", "hello")
|
|
|
|
}
|
2014-01-10 02:51:11 -07:00
|
|
|
})
|
2009-11-24 01:21:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSprintfInt(b *testing.B) {
|
2014-02-24 09:46:25 -07:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
Sprintf("%d", 5)
|
|
|
|
}
|
2014-01-10 02:51:11 -07:00
|
|
|
})
|
2009-11-24 01:21:50 -07:00
|
|
|
}
|
|
|
|
|
2009-12-06 13:03:52 -07:00
|
|
|
func BenchmarkSprintfIntInt(b *testing.B) {
|
2014-02-24 09:46:25 -07:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
Sprintf("%d %d", 5, 6)
|
|
|
|
}
|
2014-01-10 02:51:11 -07:00
|
|
|
})
|
2009-12-06 13:03:52 -07:00
|
|
|
}
|
|
|
|
|
2011-01-05 12:42:35 -07:00
|
|
|
func BenchmarkSprintfPrefixedInt(b *testing.B) {
|
2014-02-24 09:46:25 -07:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
|
|
|
|
}
|
2014-01-10 02:51:11 -07:00
|
|
|
})
|
2011-01-05 12:42:35 -07:00
|
|
|
}
|
|
|
|
|
2011-12-06 09:40:16 -07:00
|
|
|
func BenchmarkSprintfFloat(b *testing.B) {
|
2014-02-24 09:46:25 -07:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
Sprintf("%g", 5.23184)
|
|
|
|
}
|
2014-01-10 02:51:11 -07:00
|
|
|
})
|
2011-12-06 09:40:16 -07:00
|
|
|
}
|
|
|
|
|
2012-05-29 16:08:08 -06:00
|
|
|
func BenchmarkManyArgs(b *testing.B) {
|
2014-02-24 09:46:25 -07:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
for pb.Next() {
|
|
|
|
buf.Reset()
|
|
|
|
Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
|
|
|
|
}
|
2014-01-10 02:51:11 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-09-22 12:58:15 -06:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-22 16:16:06 -07:00
|
|
|
var mallocBuf bytes.Buffer
|
2014-09-09 12:45:46 -06:00
|
|
|
var mallocPointer *int // A pointer so we know the interface value won't allocate.
|
2011-12-22 16:16:06 -07:00
|
|
|
|
|
|
|
var mallocTest = []struct {
|
2012-01-17 16:42:02 -07:00
|
|
|
count int
|
|
|
|
desc string
|
|
|
|
fn func()
|
2011-12-22 16:16:06 -07:00
|
|
|
}{
|
|
|
|
{0, `Sprintf("")`, func() { Sprintf("") }},
|
|
|
|
{1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
|
2014-09-18 10:45:58 -06:00
|
|
|
{2, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
|
2011-12-22 16:16:06 -07:00
|
|
|
{2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
|
2014-09-18 10:45:58 -06:00
|
|
|
{3, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }},
|
2014-09-09 12:45:46 -06:00
|
|
|
{2, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1?
|
2011-12-22 16:16:06 -07:00
|
|
|
{1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
|
2014-09-09 12:45:46 -06:00
|
|
|
// If the interface value doesn't need to allocate, amortized allocation overhead should be zero.
|
|
|
|
{0, `Fprintf(buf, "%x %x %x")`, func() {
|
|
|
|
mallocBuf.Reset()
|
|
|
|
Fprintf(&mallocBuf, "%x %x %x", mallocPointer, mallocPointer, mallocPointer)
|
|
|
|
}},
|
2011-12-22 16:16:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ bytes.Buffer
|
|
|
|
|
2009-12-06 13:03:52 -07:00
|
|
|
func TestCountMallocs(t *testing.T) {
|
2013-08-20 22:00:45 -06:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("skipping malloc count in short mode")
|
|
|
|
}
|
2013-03-06 16:52:32 -07:00
|
|
|
if runtime.GOMAXPROCS(0) > 1 {
|
|
|
|
t.Skip("skipping; GOMAXPROCS>1")
|
|
|
|
}
|
2011-12-22 16:16:06 -07:00
|
|
|
for _, mt := range mallocTest {
|
2013-02-02 20:52:29 -07:00
|
|
|
mallocs := testing.AllocsPerRun(100, mt.fn)
|
|
|
|
if got, max := mallocs, float64(mt.count); got > max {
|
|
|
|
t.Errorf("%s: got %v allocs, want <=%v", mt.desc, got, max)
|
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
|
|
|
|
2013-01-22 15:12:45 -07:00
|
|
|
// presentInMap checks map printing using substrings so we don't depend on the
|
|
|
|
// print order.
|
2009-07-09 18:30:07 -06:00
|
|
|
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
|
|
|
|
2013-01-22 15:12:45 -07:00
|
|
|
// TestBlank checks that Sprint (and hence Print, Fprint) puts spaces in the
|
|
|
|
// right places, that is, between arg pairs in which neither is a string.
|
2010-07-29 11:50:09 -06:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-22 15:12:45 -07:00
|
|
|
// TestBlankln checks that Sprintln (and hence Println, Fprintln) puts spaces in
|
|
|
|
// the right places, that is, between all arg pairs.
|
2010-07-29 11:50:09 -06:00
|
|
|
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
|
|
|
|
2013-01-22 15:12:45 -07:00
|
|
|
// TestFormatterPrintln checks Formatter with Sprint, Sprintln, Sprintf.
|
2010-08-13 01:26:32 -06:00
|
|
|
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
|
|
|
|
2013-01-22 15:12:45 -07:00
|
|
|
// Panic is a type that panics in String.
|
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
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2013-01-22 15:12:45 -07:00
|
|
|
// PanicF is a type that panics in Format.
|
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
|
|
|
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
|
2013-07-31 00:11:12 -06:00
|
|
|
{"%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
|
2013-07-31 00:11:12 -06:00
|
|
|
{"%#v", Panic{io.ErrUnexpectedEOF}, "%!v(PANIC=unexpected EOF)"},
|
|
|
|
{"%#v", Panic{3}, "%!v(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
|
|
|
// Format
|
|
|
|
{"%s", (*PanicF)(nil), "<nil>"}, // nil pointer special case
|
2013-07-31 00:11:12 -06:00
|
|
|
{"%s", PanicF{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
|
|
|
|
{"%s", PanicF{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
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2013-01-22 15:12:45 -07:00
|
|
|
// recurCount tests that erroneous String routine doesn't cause fatal recursion.
|
2011-12-14 17:37:54 -07:00
|
|
|
var recurCount = 0
|
|
|
|
|
|
|
|
type Recur struct {
|
|
|
|
i int
|
|
|
|
failed *bool
|
|
|
|
}
|
|
|
|
|
2013-08-01 19:38:19 -06:00
|
|
|
func (r *Recur) String() string {
|
2011-12-14 17:37:54 -07:00
|
|
|
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
|
2013-08-01 19:38:19 -06:00
|
|
|
r := &Recur{3, &failed}
|
2011-12-14 17:37:54 -07:00
|
|
|
Sprintf("recur@%p value: %d\n", &r, r.i)
|
|
|
|
if failed {
|
|
|
|
t.Error("fail with pointer")
|
|
|
|
}
|
|
|
|
failed = false
|
2013-08-01 19:38:19 -06:00
|
|
|
r = &Recur{4, &failed}
|
2011-12-14 17:37:54 -07:00
|
|
|
Sprintf("recur@%p, value: %d\n", r, r.i)
|
|
|
|
if failed {
|
|
|
|
t.Error("fail with value")
|
|
|
|
}
|
|
|
|
}
|
2012-03-06 21:27:11 -07:00
|
|
|
|
|
|
|
func TestIsSpace(t *testing.T) {
|
|
|
|
// This tests the internal isSpace function.
|
|
|
|
// IsSpace = isSpace is defined in export_test.go.
|
|
|
|
for i := rune(0); i <= unicode.MaxRune; i++ {
|
|
|
|
if IsSpace(i) != unicode.IsSpace(i) {
|
2012-03-11 21:04:45 -06:00
|
|
|
t.Errorf("isSpace(%U) = %v, want %v", i, IsSpace(i), unicode.IsSpace(i))
|
2012-03-06 21:27:11 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-06-25 17:48:20 -06:00
|
|
|
|
|
|
|
func TestNilDoesNotBecomeTyped(t *testing.T) {
|
|
|
|
type A struct{}
|
|
|
|
type B struct{}
|
|
|
|
var a *A = nil
|
|
|
|
var b B = B{}
|
|
|
|
got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil)
|
|
|
|
const expect = "%!s(<nil>) %!s(*fmt_test.A=<nil>) %!s(<nil>) {} %!s(<nil>)"
|
|
|
|
if got != expect {
|
|
|
|
t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
|
|
|
|
}
|
|
|
|
}
|