1package ufmt
2
3import (
4 "errors"
5 "fmt"
6 "testing"
7)
8
9type stringer struct{}
10
11func (stringer) String() string {
12 return "I'm a stringer"
13}
14
15func TestSprintf(t *testing.T) {
16 tru := true
17 cases := []struct {
18 format string
19 values []interface{}
20 expectedOutput string
21 }{
22 {"hello %s!", []interface{}{"planet"}, "hello planet!"},
23 {"hello %v!", []interface{}{"planet"}, "hello planet!"},
24 {"hi %%%s!", []interface{}{"worl%d"}, "hi %worl%d!"},
25 {"%s %c %d %t", []interface{}{"foo", 'α', 421, true}, "foo α 421 true"},
26 {"string [%s]", []interface{}{"foo"}, "string [foo]"},
27 {"int [%d]", []interface{}{int(42)}, "int [42]"},
28 {"int [%v]", []interface{}{int(42)}, "int [42]"},
29 {"int8 [%d]", []interface{}{int8(8)}, "int8 [8]"},
30 {"int8 [%v]", []interface{}{int8(8)}, "int8 [8]"},
31 {"int16 [%d]", []interface{}{int16(16)}, "int16 [16]"},
32 {"int16 [%v]", []interface{}{int16(16)}, "int16 [16]"},
33 {"int32 [%d]", []interface{}{int32(32)}, "int32 [32]"},
34 {"int32 [%v]", []interface{}{int32(32)}, "int32 [32]"},
35 {"int64 [%d]", []interface{}{int64(64)}, "int64 [64]"},
36 {"int64 [%v]", []interface{}{int64(64)}, "int64 [64]"},
37 {"uint [%d]", []interface{}{uint(42)}, "uint [42]"},
38 {"uint [%v]", []interface{}{uint(42)}, "uint [42]"},
39 {"uint8 [%d]", []interface{}{uint8(8)}, "uint8 [8]"},
40 {"uint8 [%v]", []interface{}{uint8(8)}, "uint8 [8]"},
41 {"uint16 [%d]", []interface{}{uint16(16)}, "uint16 [16]"},
42 {"uint16 [%v]", []interface{}{uint16(16)}, "uint16 [16]"},
43 {"uint32 [%d]", []interface{}{uint32(32)}, "uint32 [32]"},
44 {"uint32 [%v]", []interface{}{uint32(32)}, "uint32 [32]"},
45 {"uint64 [%d]", []interface{}{uint64(64)}, "uint64 [64]"},
46 {"uint64 [%v]", []interface{}{uint64(64)}, "uint64 [64]"},
47 {"float64 [%e]", []interface{}{float64(64.1)}, "float64 [6.41e+01]"},
48 {"float64 [%E]", []interface{}{float64(64.1)}, "float64 [6.41E+01]"},
49 {"float64 [%f]", []interface{}{float64(64.1)}, "float64 [64.100000]"},
50 {"float64 [%F]", []interface{}{float64(64.1)}, "float64 [64.100000]"},
51 {"float64 [%g]", []interface{}{float64(64.1)}, "float64 [64.1]"},
52 {"float64 [%G]", []interface{}{float64(64.1)}, "float64 [64.1]"},
53 {"bool [%t]", []interface{}{true}, "bool [true]"},
54 {"bool [%v]", []interface{}{true}, "bool [true]"},
55 {"bool [%t]", []interface{}{false}, "bool [false]"},
56 {"bool [%v]", []interface{}{false}, "bool [false]"},
57 {"no args", nil, "no args"},
58 {"finish with %", nil, "finish with %"},
59 {"stringer [%s]", []interface{}{stringer{}}, "stringer [I'm a stringer]"},
60 {"â", nil, "â"},
61 {"Hello, World! 😊", nil, "Hello, World! 😊"},
62 {"unicode formatting: %s", []interface{}{"😊"}, "unicode formatting: 😊"},
63 {"invalid hex [%x]", []interface{}{"invalid"}, "invalid hex [(unhandled)]"},
64 {"rune as character [%c]", []interface{}{rune('A')}, "rune as character [A]"},
65 {"int as character [%c]", []interface{}{int('B')}, "int as character [B]"},
66 {"quoted string [%q]", []interface{}{"hello"}, "quoted string [\"hello\"]"},
67 {"quoted string with escape [%q]", []interface{}{"\thello\nworld\\"}, "quoted string with escape [\"\\thello\\nworld\\\\\"]"},
68 {"invalid quoted string [%q]", []interface{}{123}, "invalid quoted string [(unhandled)]"},
69 {"type of bool [%T]", []interface{}{true}, "type of bool [bool]"},
70 {"type of int [%T]", []interface{}{123}, "type of int [int]"},
71 {"type of string [%T]", []interface{}{"hello"}, "type of string [string]"},
72 {"type of []byte [%T]", []interface{}{[]byte{1, 2, 3}}, "type of []byte [[]byte]"},
73 {"type of []rune [%T]", []interface{}{[]rune{'a', 'b', 'c'}}, "type of []rune [[]rune]"},
74 {"type of unknown [%T]", []interface{}{struct{}{}}, "type of unknown [unknown]"},
75 // mismatch printing
76 {"%s", []interface{}{nil}, "%!s(<nil>)"},
77 {"%s", []interface{}{421}, "%!s(int=421)"},
78 {"%s", []interface{}{"z"}, "z"},
79 {"%s", []interface{}{tru}, "%!s(bool=true)"},
80 {"%s", []interface{}{'z'}, "%!s(int32=122)"},
81
82 {"%c", []interface{}{nil}, "%!c(<nil>)"},
83 {"%c", []interface{}{421}, "ƥ"},
84 {"%c", []interface{}{"z"}, "%!c(string=z)"},
85 {"%c", []interface{}{tru}, "%!c(bool=true)"},
86 {"%c", []interface{}{'z'}, "z"},
87
88 {"%d", []interface{}{nil}, "%!d(<nil>)"},
89 {"%d", []interface{}{421}, "421"},
90 {"%d", []interface{}{"z"}, "%!d(string=z)"},
91 {"%d", []interface{}{tru}, "%!d(bool=true)"},
92 {"%d", []interface{}{'z'}, "122"},
93
94 {"%t", []interface{}{nil}, "%!t(<nil>)"},
95 {"%t", []interface{}{421}, "%!t(int=421)"},
96 {"%t", []interface{}{"z"}, "%!t(string=z)"},
97 {"%t", []interface{}{tru}, "true"},
98 {"%t", []interface{}{'z'}, "%!t(int32=122)"},
99 }
100
101 for _, tc := range cases {
102 name := fmt.Sprintf(tc.format, tc.values...)
103 t.Run(name, func(t *testing.T) {
104 got := Sprintf(tc.format, tc.values...)
105 if got != tc.expectedOutput {
106 t.Errorf("got %q, want %q.", got, tc.expectedOutput)
107 }
108 })
109 }
110}
111
112func TestErrorf(t *testing.T) {
113 tests := []struct {
114 name string
115 format string
116 args []interface{}
117 expected string
118 }{
119 {
120 name: "simple string",
121 format: "error: %s",
122 args: []interface{}{"something went wrong"},
123 expected: "error: something went wrong",
124 },
125 {
126 name: "integer value",
127 format: "value: %d",
128 args: []interface{}{42},
129 expected: "value: 42",
130 },
131 {
132 name: "boolean value",
133 format: "success: %t",
134 args: []interface{}{true},
135 expected: "success: true",
136 },
137 {
138 name: "multiple values",
139 format: "error %d: %s (success=%t)",
140 args: []interface{}{123, "failure occurred", false},
141 expected: "error 123: failure occurred (success=false)",
142 },
143 {
144 name: "literal percent",
145 format: "literal %%",
146 args: []interface{}{},
147 expected: "literal %",
148 },
149 }
150
151 for _, tt := range tests {
152 t.Run(tt.name, func(t *testing.T) {
153 err := Errorf(tt.format, tt.args...)
154 if err.Error() != tt.expected {
155 t.Errorf("Errorf(%q, %v) = %q, expected %q", tt.format, tt.args, err.Error(), tt.expected)
156 }
157 })
158 }
159}
160
161func TestPrintErrors(t *testing.T) {
162 got := Sprintf("error: %s", errors.New("can I be printed?"))
163 expectedOutput := "error: can I be printed?"
164 if got != expectedOutput {
165 t.Errorf("got %q, want %q.", got, expectedOutput)
166 }
167}
168
169// NOTE: Currently, there is no way to get the output of Println without using os.Stdout,
170// so we can only test that it doesn't panic and print arguments well.
171func TestPrintln(t *testing.T) {
172 tests := []struct {
173 name string
174 args []interface{}
175 expected string
176 }{
177 {
178 name: "Empty args",
179 args: []interface{}{},
180 expected: "",
181 },
182 {
183 name: "String args",
184 args: []interface{}{"Hello", "World"},
185 expected: "Hello World",
186 },
187 {
188 name: "Integer args",
189 args: []interface{}{1, 2, 3},
190 expected: "1 2 3",
191 },
192 {
193 name: "Mixed args",
194 args: []interface{}{"Hello", 42, true, false, "World"},
195 expected: "Hello 42 true false World",
196 },
197 {
198 name: "Unhandled type",
199 args: []interface{}{"Hello", 3.14, []int{1, 2, 3}},
200 expected: "Hello (unhandled) (unhandled)",
201 },
202 }
203
204 // TODO: replace os.Stdout with a buffer to capture the output and test it.
205 for _, tt := range tests {
206 t.Run(tt.name, func(t *testing.T) {
207 Println(tt.args...)
208 })
209 }
210}
ufmt_test.gno
7.09 Kb · 210 lines