ufmt_test.gno

7.09 Kb · 210 lines
  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}