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