typeutil_test.gno
21.99 Kb ยท 1070 lines
1package typeutil
2
3import (
4 "strings"
5 "testing"
6 "time"
7)
8
9type testStringer struct {
10 value string
11}
12
13func (t testStringer) String() string {
14 return "test:" + t.value
15}
16
17func TestToString(t *testing.T) {
18 // setup test data
19 str := "hello"
20 num := 42
21 b := true
22 now := time.Now()
23 addr := address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
24 stringer := testStringer{value: "hello"}
25
26 type testCase struct {
27 name string
28 input any
29 expected string
30 }
31
32 tests := []testCase{
33 // basic types
34 {"string", "hello", "hello"},
35 {"empty_string", "", ""},
36 {"nil", nil, ""},
37
38 // integer types
39 {"int", 42, "42"},
40 {"int8", int8(8), "8"},
41 {"int16", int16(16), "16"},
42 {"int32", int32(32), "32"},
43 {"int64", int64(64), "64"},
44 {"uint", uint(42), "42"},
45 {"uint8", uint8(8), "8"},
46 {"uint16", uint16(16), "16"},
47 {"uint32", uint32(32), "32"},
48 {"uint64", uint64(64), "64"},
49
50 // float types
51 {"float32", float32(3.14), "3.14"},
52 {"float64", 3.14159, "3.14159"},
53
54 // boolean
55 {"bool_true", true, "true"},
56 {"bool_false", false, "false"},
57
58 // special types
59 {"time", now, now.String()},
60 {"address", addr, string(addr)},
61 {"bytes", []byte("hello"), "hello"},
62 {"stringer", stringer, "test:hello"},
63
64 // slices
65 {"empty_slice", []string{}, "[]"},
66 {"string_slice", []string{"a", "b"}, "[a b]"},
67 {"int_slice", []int{1, 2}, "[1 2]"},
68 {"int32_slice", []int32{1, 2}, "[1 2]"},
69 {"int64_slice", []int64{1, 2}, "[1 2]"},
70 {"float32_slice", []float32{1.1, 2.2}, "[1.1 2.2]"},
71 {"float64_slice", []float64{1.1, 2.2}, "[1.1 2.2]"},
72 {"bytes_slice", [][]byte{[]byte("a"), []byte("b")}, "[a b]"},
73 {"time_slice", []time.Time{now, now}, "[" + now.String() + " " + now.String() + "]"},
74 {"address_slice", []address{addr, addr}, "[" + string(addr) + " " + string(addr) + "]"},
75 {"interface_slice", []any{1, "a", true}, "[1 a true]"},
76
77 // empty slices
78 {"empty_string_slice", []string{}, "[]"},
79 {"empty_int_slice", []int{}, "[]"},
80 {"empty_int32_slice", []int32{}, "[]"},
81 {"empty_int64_slice", []int64{}, "[]"},
82 {"empty_float32_slice", []float32{}, "[]"},
83 {"empty_float64_slice", []float64{}, "[]"},
84 {"empty_bytes_slice", [][]byte{}, "[]"},
85 {"empty_time_slice", []time.Time{}, "[]"},
86 {"empty_address_slice", []address{}, "[]"},
87 {"empty_interface_slice", []any{}, "[]"},
88
89 // maps
90 {"empty_string_map", map[string]string{}, "map[]"},
91 {"string_map", map[string]string{"a": "1", "b": "2"}, "map[a:1 b:2]"},
92 {"empty_interface_map", map[string]any{}, "map[]"},
93 {"interface_map", map[string]any{"a": 1, "b": "2"}, "map[a:1 b:2]"},
94
95 // edge cases
96 {"empty_bytes", []byte{}, ""},
97 {"nil_interface", any(nil), ""},
98 {"empty_struct", struct{}{}, "{}"},
99 {"unknown_type", struct{ foo string }{}, "<unknown>"},
100
101 // pointer types
102 {"nil_string_ptr", (*string)(nil), ""},
103 {"string_ptr", &str, "hello"},
104 {"nil_int_ptr", (*int)(nil), ""},
105 {"int_ptr", &num, "42"},
106 {"nil_bool_ptr", (*bool)(nil), ""},
107 {"bool_ptr", &b, "true"},
108 // {"nil_time_ptr", (*time.Time)(nil), ""}, // TODO: fix this
109 {"time_ptr", &now, now.String()},
110 // {"nil_address_ptr", (*address)(nil), ""}, // TODO: fix this
111 {"address_ptr", &addr, string(addr)},
112 }
113
114 for _, tt := range tests {
115 t.Run(tt.name, func(t *testing.T) {
116 got := ToString(tt.input)
117 if got != tt.expected {
118 t.Errorf("%s: ToString(%v) = %q, want %q", tt.name, tt.input, got, tt.expected)
119 }
120 })
121 }
122}
123
124func TestToBool(t *testing.T) {
125 str := "true"
126 num := 42
127 b := true
128 now := time.Now()
129 addr := address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
130 zero := 0
131 empty := ""
132 falseVal := false
133
134 type testCase struct {
135 name string
136 input any
137 expected bool
138 }
139
140 tests := []testCase{
141 // basic types
142 {"true", true, true},
143 {"false", false, false},
144 {"nil", nil, false},
145
146 // strings
147 {"empty_string", "", false},
148 {"zero_string", "0", false},
149 {"false_string", "false", false},
150 {"f_string", "f", false},
151 {"no_string", "no", false},
152 {"n_string", "n", false},
153 {"off_string", "off", false},
154 {"space_string", " ", false},
155 {"true_string", "true", true},
156 {"yes_string", "yes", true},
157 {"random_string", "hello", true},
158
159 // numbers
160 {"zero_int", 0, false},
161 {"positive_int", 1, true},
162 {"negative_int", -1, true},
163 {"zero_float", 0.0, false},
164 {"positive_float", 0.1, true},
165 {"negative_float", -0.1, true},
166
167 // special types
168 {"empty_bytes", []byte{}, false},
169 {"non_empty_bytes", []byte{1}, true},
170 /*{"zero_time", time.Time{}, false},*/ // TODO: fix this
171 {"empty_address", address(""), false},
172
173 // slices
174 {"empty_slice", []string{}, false},
175 {"non_empty_slice", []string{"a"}, true},
176
177 // maps
178 {"empty_map", map[string]string{}, false},
179 {"non_empty_map", map[string]string{"a": "b"}, true},
180
181 // pointer types
182 {"nil_bool_ptr", (*bool)(nil), false},
183 {"true_ptr", &b, true},
184 {"false_ptr", &falseVal, false},
185 {"nil_string_ptr", (*string)(nil), false},
186 {"string_ptr", &str, true},
187 {"empty_string_ptr", &empty, false},
188 {"nil_int_ptr", (*int)(nil), false},
189 {"int_ptr", &num, true},
190 {"zero_int_ptr", &zero, false},
191 // {"nil_time_ptr", (*time.Time)(nil), false}, // TODO: fix this
192 {"time_ptr", &now, true},
193 // {"nil_address_ptr", (*address)(nil), false}, // TODO: fix this
194 {"address_ptr", &addr, true},
195 }
196
197 for _, tt := range tests {
198 t.Run(tt.name, func(t *testing.T) {
199 got := ToBool(tt.input)
200 if got != tt.expected {
201 t.Errorf("%s: ToBool(%v) = %v, want %v", tt.name, tt.input, got, tt.expected)
202 }
203 })
204 }
205}
206
207func TestIsZero(t *testing.T) {
208 str := "hello"
209 num := 42
210 b := true
211 now := time.Now()
212 addr := address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
213 zero := 0
214 empty := ""
215 falseVal := false
216
217 type testCase struct {
218 name string
219 input any
220 expected bool
221 }
222
223 tests := []testCase{
224 // basic types
225 {"true", true, false},
226 {"false", false, true},
227 {"nil", nil, true},
228
229 // strings
230 {"empty_string", "", true},
231 {"non_empty_string", "hello", false},
232
233 // numbers
234 {"zero_int", 0, true},
235 {"non_zero_int", 1, false},
236 {"zero_float", 0.0, true},
237 {"non_zero_float", 0.1, false},
238
239 // special types
240 {"empty_bytes", []byte{}, true},
241 {"non_empty_bytes", []byte{1}, false},
242 /*{"zero_time", time.Time{}, true},*/ // TODO: fix this
243 {"empty_address", address(""), true},
244
245 // slices
246 {"empty_slice", []string{}, true},
247 {"non_empty_slice", []string{"a"}, false},
248
249 // maps
250 {"empty_map", map[string]string{}, true},
251 {"non_empty_map", map[string]string{"a": "b"}, false},
252
253 // pointer types
254 {"nil_bool_ptr", (*bool)(nil), true},
255 {"false_ptr", &falseVal, true},
256 {"true_ptr", &b, false},
257 {"nil_string_ptr", (*string)(nil), true},
258 {"empty_string_ptr", &empty, true},
259 {"string_ptr", &str, false},
260 {"nil_int_ptr", (*int)(nil), true},
261 {"zero_int_ptr", &zero, true},
262 {"int_ptr", &num, false},
263 // {"nil_time_ptr", (*time.Time)(nil), true}, // TODO: fix this
264 {"time_ptr", &now, false},
265 // {"nil_address_ptr", (*address)(nil), true}, // TODO: fix this
266 {"address_ptr", &addr, false},
267 }
268
269 for _, tt := range tests {
270 t.Run(tt.name, func(t *testing.T) {
271 got := IsZero(tt.input)
272 if got != tt.expected {
273 t.Errorf("%s: IsZero(%v) = %v, want %v", tt.name, tt.input, got, tt.expected)
274 }
275 })
276 }
277}
278
279func TestToInterfaceSlice(t *testing.T) {
280 tests := []struct {
281 name string
282 input any
283 expected []any
284 compare func([]any, []any) bool
285 }{
286 {
287 name: "nil",
288 input: nil,
289 expected: nil,
290 compare: compareNil,
291 },
292 {
293 name: "empty_interface_slice",
294 input: []any{},
295 expected: []any{},
296 compare: compareEmpty,
297 },
298 {
299 name: "interface_slice",
300 input: []any{1, "two", true},
301 expected: []any{1, "two", true},
302 compare: compareInterfaces,
303 },
304 {
305 name: "string_slice",
306 input: []string{"a", "b", "c"},
307 expected: []any{"a", "b", "c"},
308 compare: compareStrings,
309 },
310 {
311 name: "int_slice",
312 input: []int{1, 2, 3},
313 expected: []any{1, 2, 3},
314 compare: compareInts,
315 },
316 {
317 name: "int32_slice",
318 input: []int32{1, 2, 3},
319 expected: []any{int32(1), int32(2), int32(3)},
320 compare: compareInt32s,
321 },
322 {
323 name: "int64_slice",
324 input: []int64{1, 2, 3},
325 expected: []any{int64(1), int64(2), int64(3)},
326 compare: compareInt64s,
327 },
328 {
329 name: "float32_slice",
330 input: []float32{1.1, 2.2, 3.3},
331 expected: []any{float32(1.1), float32(2.2), float32(3.3)},
332 compare: compareFloat32s,
333 },
334 {
335 name: "float64_slice",
336 input: []float64{1.1, 2.2, 3.3},
337 expected: []any{1.1, 2.2, 3.3},
338 compare: compareFloat64s,
339 },
340 {
341 name: "bool_slice",
342 input: []bool{true, false, true},
343 expected: []any{true, false, true},
344 compare: compareBools,
345 },
346 /* {
347 name: "time_slice",
348 input: []time.Time{now},
349 expected: []any{now},
350 compare: compareTimes,
351 }, */ // TODO: fix this
352 /* {
353 name: "address_slice",
354 input: []address{addr},
355 expected: []any{addr},
356 compare: compareAddresses,
357 },*/ // TODO: fix this
358 /* {
359 name: "bytes_slice",
360 input: [][]byte{[]byte("hello"), []byte("world")},
361 expected: []any{[]byte("hello"), []byte("world")},
362 compare: compareBytes,
363 },*/ // TODO: fix this
364 }
365
366 for _, tt := range tests {
367 t.Run(tt.name, func(t *testing.T) {
368 got := ToInterfaceSlice(tt.input)
369 if !tt.compare(got, tt.expected) {
370 t.Errorf("ToInterfaceSlice() = %v, want %v", got, tt.expected)
371 }
372 })
373 }
374}
375
376func compareNil(a, b []any) bool {
377 return a == nil && b == nil
378}
379
380func compareEmpty(a, b []any) bool {
381 return len(a) == 0 && len(b) == 0
382}
383
384func compareInterfaces(a, b []any) bool {
385 if len(a) != len(b) {
386 return false
387 }
388 for i := range a {
389 if a[i] != b[i] {
390 return false
391 }
392 }
393 return true
394}
395
396func compareStrings(a, b []any) bool {
397 if len(a) != len(b) {
398 return false
399 }
400 for i := range a {
401 as, ok1 := a[i].(string)
402 bs, ok2 := b[i].(string)
403 if !ok1 || !ok2 || as != bs {
404 return false
405 }
406 }
407 return true
408}
409
410func compareInts(a, b []any) bool {
411 if len(a) != len(b) {
412 return false
413 }
414 for i := range a {
415 ai, ok1 := a[i].(int)
416 bi, ok2 := b[i].(int)
417 if !ok1 || !ok2 || ai != bi {
418 return false
419 }
420 }
421 return true
422}
423
424func compareInt32s(a, b []any) bool {
425 if len(a) != len(b) {
426 return false
427 }
428 for i := range a {
429 ai, ok1 := a[i].(int32)
430 bi, ok2 := b[i].(int32)
431 if !ok1 || !ok2 || ai != bi {
432 return false
433 }
434 }
435 return true
436}
437
438func compareInt64s(a, b []any) bool {
439 if len(a) != len(b) {
440 return false
441 }
442 for i := range a {
443 ai, ok1 := a[i].(int64)
444 bi, ok2 := b[i].(int64)
445 if !ok1 || !ok2 || ai != bi {
446 return false
447 }
448 }
449 return true
450}
451
452func compareFloat32s(a, b []any) bool {
453 if len(a) != len(b) {
454 return false
455 }
456 for i := range a {
457 ai, ok1 := a[i].(float32)
458 bi, ok2 := b[i].(float32)
459 if !ok1 || !ok2 || ai != bi {
460 return false
461 }
462 }
463 return true
464}
465
466func compareFloat64s(a, b []any) bool {
467 if len(a) != len(b) {
468 return false
469 }
470 for i := range a {
471 ai, ok1 := a[i].(float64)
472 bi, ok2 := b[i].(float64)
473 if !ok1 || !ok2 || ai != bi {
474 return false
475 }
476 }
477 return true
478}
479
480func compareBools(a, b []any) bool {
481 if len(a) != len(b) {
482 return false
483 }
484 for i := range a {
485 ab, ok1 := a[i].(bool)
486 bb, ok2 := b[i].(bool)
487 if !ok1 || !ok2 || ab != bb {
488 return false
489 }
490 }
491 return true
492}
493
494func compareTimes(a, b []any) bool {
495 if len(a) != len(b) {
496 return false
497 }
498 for i := range a {
499 at, ok1 := a[i].(time.Time)
500 bt, ok2 := b[i].(time.Time)
501 if !ok1 || !ok2 || !at.Equal(bt) {
502 return false
503 }
504 }
505 return true
506}
507
508func compareAddresses(a, b []any) bool {
509 if len(a) != len(b) {
510 return false
511 }
512 for i := range a {
513 aa, ok1 := a[i].(address)
514 ba, ok2 := b[i].(address)
515 if !ok1 || !ok2 || aa != ba {
516 return false
517 }
518 }
519 return true
520}
521
522func compareBytes(a, b []any) bool {
523 if len(a) != len(b) {
524 return false
525 }
526 for i := range a {
527 ab, ok1 := a[i].([]byte)
528 bb, ok2 := b[i].([]byte)
529 if !ok1 || !ok2 || string(ab) != string(bb) {
530 return false
531 }
532 }
533 return true
534}
535
536// compareStringInterfaceMaps compares two map[string]any for equality
537func compareStringInterfaceMaps(a, b map[string]any) bool {
538 if len(a) != len(b) {
539 return false
540 }
541 for k, v1 := range a {
542 v2, ok := b[k]
543 if !ok {
544 return false
545 }
546 // Compare values based on their type
547 switch val1 := v1.(type) {
548 case string:
549 val2, ok := v2.(string)
550 if !ok || val1 != val2 {
551 return false
552 }
553 case int:
554 val2, ok := v2.(int)
555 if !ok || val1 != val2 {
556 return false
557 }
558 case float64:
559 val2, ok := v2.(float64)
560 if !ok || val1 != val2 {
561 return false
562 }
563 case bool:
564 val2, ok := v2.(bool)
565 if !ok || val1 != val2 {
566 return false
567 }
568 case []any:
569 val2, ok := v2.([]any)
570 if !ok || len(val1) != len(val2) {
571 return false
572 }
573 for i := range val1 {
574 if val1[i] != val2[i] {
575 return false
576 }
577 }
578 case map[string]any:
579 val2, ok := v2.(map[string]any)
580 if !ok || !compareStringInterfaceMaps(val1, val2) {
581 return false
582 }
583 default:
584 return false
585 }
586 }
587 return true
588}
589
590func TestToMapStringInterface(t *testing.T) {
591 tests := []struct {
592 name string
593 input any
594 expected map[string]any
595 wantErr bool
596 }{
597 {
598 name: "map[string]any",
599 input: map[string]any{
600 "key1": "value1",
601 "key2": 42,
602 },
603 expected: map[string]any{
604 "key1": "value1",
605 "key2": 42,
606 },
607 wantErr: false,
608 },
609 {
610 name: "map[string]string",
611 input: map[string]string{
612 "key1": "value1",
613 "key2": "value2",
614 },
615 expected: map[string]any{
616 "key1": "value1",
617 "key2": "value2",
618 },
619 wantErr: false,
620 },
621 {
622 name: "map[string]int",
623 input: map[string]int{
624 "key1": 1,
625 "key2": 2,
626 },
627 expected: map[string]any{
628 "key1": 1,
629 "key2": 2,
630 },
631 wantErr: false,
632 },
633 {
634 name: "map[string]float64",
635 input: map[string]float64{
636 "key1": 1.1,
637 "key2": 2.2,
638 },
639 expected: map[string]any{
640 "key1": 1.1,
641 "key2": 2.2,
642 },
643 wantErr: false,
644 },
645 {
646 name: "map[string]bool",
647 input: map[string]bool{
648 "key1": true,
649 "key2": false,
650 },
651 expected: map[string]any{
652 "key1": true,
653 "key2": false,
654 },
655 wantErr: false,
656 },
657 {
658 name: "map[string][]string",
659 input: map[string][]string{
660 "key1": {"a", "b"},
661 "key2": {"c", "d"},
662 },
663 expected: map[string]any{
664 "key1": []any{"a", "b"},
665 "key2": []any{"c", "d"},
666 },
667 wantErr: false,
668 },
669 {
670 name: "nested map[string]map[string]string",
671 input: map[string]map[string]string{
672 "key1": {"nested1": "value1"},
673 "key2": {"nested2": "value2"},
674 },
675 expected: map[string]any{
676 "key1": map[string]any{"nested1": "value1"},
677 "key2": map[string]any{"nested2": "value2"},
678 },
679 wantErr: false,
680 },
681 {
682 name: "unsupported type",
683 input: 42, // not a map
684 expected: nil,
685 wantErr: true,
686 },
687 }
688
689 for _, tt := range tests {
690 t.Run(tt.name, func(t *testing.T) {
691 got, err := ToMapStringInterface(tt.input)
692 if (err != nil) != tt.wantErr {
693 t.Errorf("ToMapStringInterface() error = %v, wantErr %v", err, tt.wantErr)
694 return
695 }
696 if !tt.wantErr {
697 if !compareStringInterfaceMaps(got, tt.expected) {
698 t.Errorf("ToMapStringInterface() = %v, expected %v", got, tt.expected)
699 }
700 }
701 })
702 }
703}
704
705// Test error messages
706func TestToMapStringInterfaceErrors(t *testing.T) {
707 _, err := ToMapStringInterface(42)
708 if err == nil || !strings.Contains(err.Error(), "unsupported map type") {
709 t.Errorf("Expected error containing 'unsupported map type', got %v", err)
710 }
711}
712
713// compareIntInterfaceMaps compares two map[int]any for equality
714func compareIntInterfaceMaps(a, b map[int]any) bool {
715 if len(a) != len(b) {
716 return false
717 }
718 for k, v1 := range a {
719 v2, ok := b[k]
720 if !ok {
721 return false
722 }
723 // Compare values based on their type
724 switch val1 := v1.(type) {
725 case string:
726 val2, ok := v2.(string)
727 if !ok || val1 != val2 {
728 return false
729 }
730 case int:
731 val2, ok := v2.(int)
732 if !ok || val1 != val2 {
733 return false
734 }
735 case float64:
736 val2, ok := v2.(float64)
737 if !ok || val1 != val2 {
738 return false
739 }
740 case bool:
741 val2, ok := v2.(bool)
742 if !ok || val1 != val2 {
743 return false
744 }
745 case []any:
746 val2, ok := v2.([]any)
747 if !ok || len(val1) != len(val2) {
748 return false
749 }
750 for i := range val1 {
751 if val1[i] != val2[i] {
752 return false
753 }
754 }
755 case map[string]any:
756 val2, ok := v2.(map[string]any)
757 if !ok || !compareStringInterfaceMaps(val1, val2) {
758 return false
759 }
760 default:
761 return false
762 }
763 }
764 return true
765}
766
767func TestToMapIntInterface(t *testing.T) {
768 tests := []struct {
769 name string
770 input any
771 expected map[int]any
772 wantErr bool
773 }{
774 {
775 name: "map[int]any",
776 input: map[int]any{
777 1: "value1",
778 2: 42,
779 },
780 expected: map[int]any{
781 1: "value1",
782 2: 42,
783 },
784 wantErr: false,
785 },
786 {
787 name: "map[int]string",
788 input: map[int]string{
789 1: "value1",
790 2: "value2",
791 },
792 expected: map[int]any{
793 1: "value1",
794 2: "value2",
795 },
796 wantErr: false,
797 },
798 {
799 name: "map[int]int",
800 input: map[int]int{
801 1: 10,
802 2: 20,
803 },
804 expected: map[int]any{
805 1: 10,
806 2: 20,
807 },
808 wantErr: false,
809 },
810 {
811 name: "map[int]float64",
812 input: map[int]float64{
813 1: 1.1,
814 2: 2.2,
815 },
816 expected: map[int]any{
817 1: 1.1,
818 2: 2.2,
819 },
820 wantErr: false,
821 },
822 {
823 name: "map[int]bool",
824 input: map[int]bool{
825 1: true,
826 2: false,
827 },
828 expected: map[int]any{
829 1: true,
830 2: false,
831 },
832 wantErr: false,
833 },
834 {
835 name: "map[int][]string",
836 input: map[int][]string{
837 1: {"a", "b"},
838 2: {"c", "d"},
839 },
840 expected: map[int]any{
841 1: []any{"a", "b"},
842 2: []any{"c", "d"},
843 },
844 wantErr: false,
845 },
846 {
847 name: "map[int]map[string]any",
848 input: map[int]map[string]any{
849 1: {"nested1": "value1"},
850 2: {"nested2": "value2"},
851 },
852 expected: map[int]any{
853 1: map[string]any{"nested1": "value1"},
854 2: map[string]any{"nested2": "value2"},
855 },
856 wantErr: false,
857 },
858 {
859 name: "unsupported type",
860 input: 42, // not a map
861 expected: nil,
862 wantErr: true,
863 },
864 }
865
866 for _, tt := range tests {
867 t.Run(tt.name, func(t *testing.T) {
868 got, err := ToMapIntInterface(tt.input)
869 if (err != nil) != tt.wantErr {
870 t.Errorf("ToMapIntInterface() error = %v, wantErr %v", err, tt.wantErr)
871 return
872 }
873 if !tt.wantErr {
874 if !compareIntInterfaceMaps(got, tt.expected) {
875 t.Errorf("ToMapIntInterface() = %v, expected %v", got, tt.expected)
876 }
877 }
878 })
879 }
880}
881
882func TestToStringSlice(t *testing.T) {
883 tests := []struct {
884 name string
885 input any
886 expected []string
887 }{
888 {
889 name: "nil input",
890 input: nil,
891 expected: nil,
892 },
893 {
894 name: "empty slice",
895 input: []string{},
896 expected: []string{},
897 },
898 {
899 name: "string slice",
900 input: []string{"a", "b", "c"},
901 expected: []string{"a", "b", "c"},
902 },
903 {
904 name: "int slice",
905 input: []int{1, 2, 3},
906 expected: []string{"1", "2", "3"},
907 },
908 {
909 name: "int32 slice",
910 input: []int32{1, 2, 3},
911 expected: []string{"1", "2", "3"},
912 },
913 {
914 name: "int64 slice",
915 input: []int64{1, 2, 3},
916 expected: []string{"1", "2", "3"},
917 },
918 {
919 name: "uint slice",
920 input: []uint{1, 2, 3},
921 expected: []string{"1", "2", "3"},
922 },
923 {
924 name: "uint8 slice",
925 input: []uint8{1, 2, 3},
926 expected: []string{"1", "2", "3"},
927 },
928 {
929 name: "uint16 slice",
930 input: []uint16{1, 2, 3},
931 expected: []string{"1", "2", "3"},
932 },
933 {
934 name: "uint32 slice",
935 input: []uint32{1, 2, 3},
936 expected: []string{"1", "2", "3"},
937 },
938 {
939 name: "uint64 slice",
940 input: []uint64{1, 2, 3},
941 expected: []string{"1", "2", "3"},
942 },
943 {
944 name: "float32 slice",
945 input: []float32{1.1, 2.2, 3.3},
946 expected: []string{"1.1", "2.2", "3.3"},
947 },
948 {
949 name: "float64 slice",
950 input: []float64{1.1, 2.2, 3.3},
951 expected: []string{"1.1", "2.2", "3.3"},
952 },
953 {
954 name: "bool slice",
955 input: []bool{true, false, true},
956 expected: []string{"true", "false", "true"},
957 },
958 {
959 name: "[]byte slice",
960 input: [][]byte{[]byte("hello"), []byte("world")},
961 expected: []string{"hello", "world"},
962 },
963 {
964 name: "interface slice",
965 input: []any{1, "hello", true},
966 expected: []string{"1", "hello", "true"},
967 },
968 {
969 name: "time slice",
970 input: []time.Time{{}, {}},
971 expected: []string{"0001-01-01 00:00:00 +0000 UTC", "0001-01-01 00:00:00 +0000 UTC"},
972 },
973 {
974 name: "address slice",
975 input: []address{"addr1", "addr2"},
976 expected: []string{"addr1", "addr2"},
977 },
978 {
979 name: "non-slice input",
980 input: 42,
981 expected: nil,
982 },
983 }
984
985 for _, tt := range tests {
986 t.Run(tt.name, func(t *testing.T) {
987 result := ToStringSlice(tt.input)
988 if !slicesEqual(result, tt.expected) {
989 t.Errorf("ToStringSlice(%v) = %v, want %v", tt.input, result, tt.expected)
990 }
991 })
992 }
993}
994
995// Helper function to compare string slices
996func slicesEqual(a, b []string) bool {
997 if len(a) != len(b) {
998 return false
999 }
1000 for i := range a {
1001 if a[i] != b[i] {
1002 return false
1003 }
1004 }
1005 return true
1006}
1007
1008func TestToStringAdvanced(t *testing.T) {
1009 tests := []struct {
1010 name string
1011 input any
1012 expected string
1013 }{
1014 {
1015 name: "slice with mixed basic types",
1016 input: []any{
1017 42,
1018 "hello",
1019 true,
1020 3.14,
1021 },
1022 expected: "[42 hello true 3.14]",
1023 },
1024 {
1025 name: "map with basic types",
1026 input: map[string]any{
1027 "int": 42,
1028 "str": "hello",
1029 "bool": true,
1030 "float": 3.14,
1031 },
1032 expected: "map[bool:true float:3.14 int:42 str:hello]",
1033 },
1034 {
1035 name: "mixed types map",
1036 input: map[any]any{
1037 42: "number",
1038 "string": 123,
1039 true: []int{1, 2, 3},
1040 struct{}{}: "empty",
1041 },
1042 expected: "map[42:number string:123 true:[1 2 3] {}:empty]",
1043 },
1044 {
1045 name: "nested maps",
1046 input: map[string]any{
1047 "a": map[string]int{
1048 "x": 1,
1049 "y": 2,
1050 },
1051 "b": []any{1, "two", true},
1052 },
1053 expected: "map[a:map[x:1 y:2] b:[1 two true]]",
1054 },
1055 {
1056 name: "empty struct",
1057 input: struct{}{},
1058 expected: "{}",
1059 },
1060 }
1061
1062 for _, tt := range tests {
1063 t.Run(tt.name, func(t *testing.T) {
1064 result := ToString(tt.input)
1065 if result != tt.expected {
1066 t.Errorf("\nToString(%v) =\n%v\nwant:\n%v", tt.input, result, tt.expected)
1067 }
1068 })
1069 }
1070}