• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

maxatome / go-testdeep / 21543714832

31 Jan 2026 11:20AM UTC coverage: 26.962% (-73.0%) from 99.921%
21543714832

Pull #287

github

maxatome
chore: gocovmerge not needed anymore

Signed-off-by: Maxime Soulé <btik-git@scoubidou.com>
Pull Request #287: Some features before the release

25 of 57 new or added lines in 6 files covered. (43.86%)

7342 existing lines in 95 files now uncovered.

2796 of 10370 relevant lines covered (26.96%)

22.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

7.1
/internal/util/string.go
1
// Copyright (c) 2018-2022, Maxime Soulé
2
// All rights reserved.
3
//
4
// This source code is licensed under the BSD-style license found in the
5
// LICENSE file in the root directory of this source tree.
6

7
package util
8

9
import (
10
        "bytes"
11
        "fmt"
12
        "io"
13
        "reflect"
14
        "strconv"
15
        "strings"
16

17
        "github.com/maxatome/go-testdeep/helpers/tdutil"
18
        "github.com/maxatome/go-testdeep/internal/dark"
19
        "github.com/maxatome/go-testdeep/internal/types"
20
)
21

22
// ToString does its best to stringify val. inReflectValue is used
23
// internally to avoid treating specifically reflect.Value type.
24
func ToString(val any, inReflectValue ...bool) string {
160✔
25
        if val == nil {
160✔
UNCOV
26
                return "nil"
×
UNCOV
27
        }
×
28

29
        switch tval := val.(type) {
160✔
30
        case reflect.Value:
80✔
31
                if len(inReflectValue) > 0 && inReflectValue[0] {
80✔
UNCOV
32
                        break
×
33
                }
34
                newVal, ok := dark.GetInterface(tval, true)
80✔
35
                if ok {
160✔
36
                        return ToString(newVal, true)
80✔
37
                }
80✔
38

UNCOV
39
        case []reflect.Value:
×
UNCOV
40
                if len(inReflectValue) > 0 && inReflectValue[0] {
×
UNCOV
41
                        break
×
42
                }
UNCOV
43
                var buf strings.Builder
×
UNCOV
44
                SliceToString(&buf, tval)
×
UNCOV
45
                return buf.String()
×
46

47
                // no "(string) " prefix for printable strings
48
        case string:
80✔
49
                return tdutil.FormatString(tval)
80✔
50

51
                // no "(int) " prefix for ints
UNCOV
52
        case int:
×
UNCOV
53
                return strconv.Itoa(tval)
×
54

55
                // no "(float64) " prefix for float64s
UNCOV
56
        case float64:
×
UNCOV
57
                s := strconv.FormatFloat(tval, 'g', -1, 64)
×
UNCOV
58
                if strings.ContainsAny(s, "e.IN") { // I for Inf, N for NaN
×
UNCOV
59
                        return s
×
UNCOV
60
                }
×
UNCOV
61
                return s + ".0" // to distinguish from ints
×
62

63
                // no "(bool) " prefix for booleans
UNCOV
64
        case bool:
×
UNCOV
65
                if tval {
×
UNCOV
66
                        return "true"
×
UNCOV
67
                }
×
UNCOV
68
                return "false"
×
69

UNCOV
70
        case types.TestDeepStringer:
×
UNCOV
71
                return tval.String()
×
72
        }
73

UNCOV
74
        return tdutil.SpewString(val)
×
75
}
76

77
// IndentString indents str lines (from 2nd one = 1st line is not
78
// indented) by indent.
UNCOV
79
func IndentString(str, indent string) string {
×
UNCOV
80
        return strings.ReplaceAll(str, "\n", "\n"+indent)
×
UNCOV
81
}
×
82

83
// IndentStringIn indents str lines (from 2nd one = 1st line is not
84
// indented) by indent and write it to w.
UNCOV
85
func IndentStringIn(w io.Writer, str, indent string) {
×
UNCOV
86
        repl := strings.NewReplacer("\n", "\n"+indent)
×
UNCOV
87
        repl.WriteString(w, str) //nolint: errcheck
×
UNCOV
88
}
×
89

90
// IndentColorizeStringIn indents str lines (from 2nd one = 1st line
91
// is not indented) by indent and write it to w. Before each end of
92
// line, colOff is inserted, and after each indent on new line, colOn
93
// is inserted.
UNCOV
94
func IndentColorizeStringIn(w io.Writer, str, indent, colOn, colOff string) {
×
UNCOV
95
        if str != "" {
×
UNCOV
96
                if colOn == "" && colOff == "" {
×
UNCOV
97
                        IndentStringIn(w, str, indent)
×
UNCOV
98
                        return
×
UNCOV
99
                }
×
UNCOV
100
                repl := strings.NewReplacer("\n", colOff+"\n"+indent+colOn)
×
UNCOV
101
                io.WriteString(w, colOn)  //nolint: errcheck
×
UNCOV
102
                repl.WriteString(w, str)  //nolint: errcheck
×
UNCOV
103
                io.WriteString(w, colOff) //nolint: errcheck
×
104
        }
105
}
106

107
// SliceToString stringifies items slice into buf then returns buf.
UNCOV
108
func SliceToString(buf *strings.Builder, items []reflect.Value) *strings.Builder {
×
UNCOV
109
        buf.WriteByte('(')
×
UNCOV
110

×
UNCOV
111
        begLine := strings.LastIndexByte(buf.String(), '\n') + 1
×
UNCOV
112
        prefix := strings.Repeat(" ", buf.Len()-begLine)
×
UNCOV
113

×
UNCOV
114
        if len(items) < 2 {
×
UNCOV
115
                if len(items) > 0 {
×
UNCOV
116
                        buf.WriteString(IndentString(ToString(items[0]), prefix))
×
UNCOV
117
                }
×
UNCOV
118
        } else {
×
UNCOV
119
                buf.WriteString(IndentString(ToString(items[0]), prefix))
×
UNCOV
120
                for _, item := range items[1:] {
×
UNCOV
121
                        buf.WriteString(",\n")
×
UNCOV
122
                        buf.WriteString(prefix)
×
UNCOV
123
                        buf.WriteString(IndentString(ToString(item), prefix))
×
UNCOV
124
                }
×
125
        }
UNCOV
126
        buf.WriteByte(')')
×
UNCOV
127

×
UNCOV
128
        return buf
×
129
}
130

131
// TypeFullName returns the t type name with packages fully visible
132
// instead of the last package part in t.String().
UNCOV
133
func TypeFullName(t reflect.Type) string {
×
UNCOV
134
        var b bytes.Buffer
×
UNCOV
135
        typeFullName(&b, t)
×
UNCOV
136
        return b.String()
×
UNCOV
137
}
×
138

UNCOV
139
func typeFullName(b *bytes.Buffer, t reflect.Type) {
×
UNCOV
140
        if t.Name() != "" {
×
UNCOV
141
                if pkg := t.PkgPath(); pkg != "" {
×
UNCOV
142
                        fmt.Fprintf(b, "%s.", pkg)
×
UNCOV
143
                }
×
UNCOV
144
                b.WriteString(t.Name())
×
UNCOV
145
                return
×
146
        }
147

UNCOV
148
        switch t.Kind() {
×
UNCOV
149
        case reflect.Ptr:
×
UNCOV
150
                b.WriteByte('*')
×
UNCOV
151
                typeFullName(b, t.Elem())
×
152

UNCOV
153
        case reflect.Slice:
×
UNCOV
154
                b.WriteString("[]")
×
UNCOV
155
                typeFullName(b, t.Elem())
×
156

UNCOV
157
        case reflect.Array:
×
UNCOV
158
                fmt.Fprintf(b, "[%d]", t.Len())
×
UNCOV
159
                typeFullName(b, t.Elem())
×
160

UNCOV
161
        case reflect.Map:
×
UNCOV
162
                b.WriteString("map[")
×
UNCOV
163
                typeFullName(b, t.Key())
×
UNCOV
164
                b.WriteByte(']')
×
UNCOV
165
                typeFullName(b, t.Elem())
×
166

UNCOV
167
        case reflect.Struct:
×
UNCOV
168
                b.WriteString("struct {")
×
UNCOV
169
                if num := t.NumField(); num > 0 {
×
UNCOV
170
                        for i := 0; i < num; i++ {
×
UNCOV
171
                                sf := t.Field(i)
×
UNCOV
172
                                if !sf.Anonymous {
×
UNCOV
173
                                        b.WriteByte(' ')
×
UNCOV
174
                                        b.WriteString(sf.Name)
×
UNCOV
175
                                }
×
UNCOV
176
                                b.WriteByte(' ')
×
UNCOV
177
                                typeFullName(b, sf.Type)
×
UNCOV
178
                                b.WriteByte(';')
×
179
                        }
UNCOV
180
                        b.Truncate(b.Len() - 1)
×
UNCOV
181
                        b.WriteByte(' ')
×
182
                }
UNCOV
183
                b.WriteByte('}')
×
184

UNCOV
185
        case reflect.Func:
×
UNCOV
186
                b.WriteString("func(")
×
UNCOV
187
                if num := t.NumIn(); num > 0 {
×
UNCOV
188
                        for i := 0; i < num; i++ {
×
UNCOV
189
                                if i == num-1 && t.IsVariadic() {
×
UNCOV
190
                                        b.WriteString("...")
×
UNCOV
191
                                        typeFullName(b, t.In(i).Elem())
×
UNCOV
192
                                } else {
×
UNCOV
193
                                        typeFullName(b, t.In(i))
×
UNCOV
194
                                }
×
UNCOV
195
                                b.WriteString(", ")
×
196
                        }
UNCOV
197
                        b.Truncate(b.Len() - 2)
×
198
                }
UNCOV
199
                b.WriteByte(')')
×
UNCOV
200

×
UNCOV
201
                if num := t.NumOut(); num > 0 {
×
UNCOV
202
                        if num == 1 {
×
UNCOV
203
                                b.WriteByte(' ')
×
UNCOV
204
                        } else {
×
UNCOV
205
                                b.WriteString(" (")
×
UNCOV
206
                        }
×
UNCOV
207
                        for i := 0; i < num; i++ {
×
UNCOV
208
                                typeFullName(b, t.Out(i))
×
UNCOV
209
                                b.WriteString(", ")
×
UNCOV
210
                        }
×
UNCOV
211
                        b.Truncate(b.Len() - 2)
×
UNCOV
212
                        if num > 1 {
×
UNCOV
213
                                b.WriteByte(')')
×
UNCOV
214
                        }
×
215
                }
216

UNCOV
217
        case reflect.Chan:
×
UNCOV
218
                switch t.ChanDir() {
×
UNCOV
219
                case reflect.RecvDir:
×
UNCOV
220
                        b.WriteString("<-chan ")
×
UNCOV
221
                case reflect.SendDir:
×
UNCOV
222
                        b.WriteString("chan<- ")
×
UNCOV
223
                case reflect.BothDir:
×
UNCOV
224
                        b.WriteString("chan ")
×
225
                }
UNCOV
226
                typeFullName(b, t.Elem())
×
227

UNCOV
228
        default:
×
UNCOV
229
                // Fallback to default implementation
×
UNCOV
230
                b.WriteString(t.String())
×
231
        }
232
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc