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

go-ap / activitypub / #2

02 Feb 2026 01:13PM UTC coverage: 43.033% (+1.0%) from 42.028%
#2

push

sourcehut

mariusor
Adding Stringer methods on the vocabulary types

0 of 12 new or added lines in 1 file covered. (0.0%)

1116 existing lines in 23 files now uncovered.

3255 of 7564 relevant lines covered (43.03%)

99.08 hits per line

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

53.33
/encoding_json.go
1
package activitypub
2

3
import (
4
        "encoding/json"
5
        "fmt"
6
        "time"
7

8
        "git.sr.ht/~mariusor/go-xsd-duration"
9
        "github.com/go-ap/jsonld"
10
)
11

12
func JSONWriteComma(b *[]byte) {
148✔
13
        if len(*b) > 1 && (*b)[len(*b)-1] != ',' {
178✔
14
                *b = append(*b, ',')
30✔
15
        }
30✔
16
}
17

18
func JSONWriteProp(b *[]byte, name string, val []byte) (notEmpty bool) {
146✔
19
        if len(val) == 0 {
146✔
20
                return false
×
21
        }
×
22
        JSONWriteComma(b)
146✔
23
        success := JSONWritePropName(b, name) && JSONWriteValue(b, val)
146✔
24
        if !success {
146✔
25
                *b = (*b)[:len(*b)-1]
×
26
        }
×
27
        return success
146✔
28
}
29

30
func JSONWrite(b *[]byte, c ...byte) {
1,040✔
31
        *b = append(*b, c...)
1,040✔
32
}
1,040✔
33

34
func JSONWriteS(b *[]byte, s string) {
256✔
35
        *b = append(*b, s...)
256✔
36
}
256✔
37

38
func JSONWritePropName(b *[]byte, s string) (notEmpty bool) {
146✔
39
        if len(s) == 0 {
146✔
40
                return false
×
41
        }
×
42
        JSONWrite(b, '"')
146✔
43
        JSONWriteS(b, s)
146✔
44
        JSONWrite(b, '"', ':')
146✔
45
        return true
146✔
46
}
47

48
func JSONWriteValue(b *[]byte, s []byte) (notEmpty bool) {
152✔
49
        if len(s) == 0 {
154✔
50
                return false
2✔
51
        }
2✔
52
        JSONWrite(b, s...)
150✔
53
        return true
150✔
54
}
55

56
func JSONWriteNaturalLanguageProp(b *[]byte, n string, nl NaturalLanguageValues) (notEmpty bool) {
40✔
57
        l := nl.Count()
40✔
58
        if l > 1 {
60✔
59
                n += "Map"
20✔
60
        }
20✔
61
        if v, err := nl.MarshalJSON(); err == nil && len(v) > 0 {
80✔
62
                return JSONWriteProp(b, n, v)
40✔
63
        }
40✔
64
        return false
×
65
}
66

67
func JSONWriteStringProp(b *[]byte, n string, s string) (notEmpty bool) {
×
68
        return JSONWriteProp(b, n, []byte(fmt.Sprintf(`"%s"`, s)))
×
69
}
×
70

71
func JSONWriteBoolProp(b *[]byte, n string, t bool) (notEmpty bool) {
×
72
        return JSONWriteProp(b, n, []byte(fmt.Sprintf(`"%t"`, t)))
×
73
}
×
74

75
func JSONWriteIntProp(b *[]byte, n string, d int64) (notEmpty bool) {
×
76
        return JSONWriteProp(b, n, []byte(fmt.Sprintf("%d", d)))
×
77
}
×
78

79
func JSONWriteFloatProp(b *[]byte, n string, f float64) (notEmpty bool) {
×
80
        return JSONWriteProp(b, n, []byte(fmt.Sprintf("%f", f)))
×
81
}
×
82

83
func JSONWriteTimeProp(b *[]byte, n string, t time.Time) (notEmpty bool) {
×
84
        var tb []byte
×
85
        JSONWrite(&tb, '"')
×
86
        JSONWriteS(&tb, t.UTC().Format(time.RFC3339))
×
87
        JSONWrite(&tb, '"')
×
88
        return JSONWriteProp(b, n, tb)
×
89
}
×
90

91
func JSONWriteDurationProp(b *[]byte, n string, d time.Duration) (notEmpty bool) {
×
92
        var tb []byte
×
93
        if v, err := xsd.Marshal(d); err == nil {
×
94
                JSONWrite(&tb, '"')
×
95
                JSONWrite(&tb, v...)
×
96
                JSONWrite(&tb, '"')
×
97
        }
×
98
        return JSONWriteProp(b, n, tb)
×
99
}
100

101
func JSONWriteIRIProp(b *[]byte, n string, i LinkOrIRI) (notEmpty bool) {
×
102
        url := i.GetLink().String()
×
103
        if len(url) == 0 {
×
104
                return false
×
105
        }
×
106
        JSONWriteStringProp(b, n, url)
×
107
        return true
×
108
}
109

110
func JSONWriteItemProp(b *[]byte, n string, i Item) (notEmpty bool) {
18✔
111
        if i == nil {
18✔
112
                return notEmpty
×
113
        }
×
114
        if im, ok := i.(json.Marshaler); ok {
36✔
115
                v, err := im.MarshalJSON()
18✔
116
                if err != nil {
18✔
117
                        return false
×
118
                }
×
119
                return JSONWriteProp(b, n, v)
18✔
120
        }
121
        return notEmpty
×
122
}
123

124
func byteInsertAt(raw []byte, b byte, p int) []byte {
8✔
125
        return append(raw[:p], append([]byte{b}, raw[p:]...)...)
8✔
126
}
8✔
127

128
func escapeQuote(s string) string {
62✔
129
        raw := []byte(s)
62✔
130
        end := len(s)
62✔
131
        for i := 0; i < end; i++ {
496✔
132
                c := raw[i]
434✔
133
                if c == '"' && (i > 0 && s[i-1] != '\\') {
442✔
134
                        raw = byteInsertAt(raw, '\\', i)
8✔
135
                        i++
8✔
136
                        end++
8✔
137
                }
8✔
138
        }
139
        return string(raw)
62✔
140
}
141

142
func JSONWriteStringValue(b *[]byte, s string) (notEmpty bool) {
64✔
143
        if len(s) == 0 {
66✔
144
                return false
2✔
145
        }
2✔
146
        JSONWrite(b, '"')
62✔
147
        JSONWriteS(b, escapeQuote(s))
62✔
148
        JSONWrite(b, '"')
62✔
149
        return true
62✔
150
}
151

152
func JSONWriteItemCollectionValue(b *[]byte, col ItemCollection, compact bool) (notEmpty bool) {
6✔
153
        if len(col) == 0 {
6✔
154
                return notEmpty
×
155
        }
×
156
        if len(col) == 1 && compact {
6✔
157
                it := col[0]
×
158
                im, ok := it.(json.Marshaler)
×
159
                if !ok {
×
160
                        return false
×
161
                }
×
162
                v, err := im.MarshalJSON()
×
163
                if err != nil {
×
164
                        return false
×
165
                }
×
166
                if len(v) == 0 {
×
167
                        return false
×
168
                }
×
169
                JSONWrite(b, v...)
×
170
                return true
×
171
        }
172
        writeCommaIfNotEmpty := func(notEmpty bool) {
18✔
173
                if notEmpty {
18✔
174
                        JSONWrite(b, ',')
6✔
175
                }
6✔
176
        }
177
        JSONWrite(b, '[')
6✔
178
        skipComma := true
6✔
179
        for _, it := range col {
18✔
180
                im, ok := it.(json.Marshaler)
12✔
181
                if !ok {
12✔
182
                        continue
×
183
                }
184
                v, err := im.MarshalJSON()
12✔
185
                if err != nil {
12✔
186
                        return false
×
187
                }
×
188
                if len(v) == 0 {
12✔
189
                        continue
×
190
                }
191
                writeCommaIfNotEmpty(!skipComma)
12✔
192
                JSONWrite(b, v...)
12✔
193
                skipComma = false
12✔
194
        }
195
        JSONWrite(b, ']')
6✔
196
        return true
6✔
197
}
198

199
func JSONWriteItemCollectionProp(b *[]byte, n string, col ItemCollection, compact bool) (notEmpty bool) {
×
200
        if len(col) == 0 {
×
201
                return notEmpty
×
202
        }
×
203
        JSONWriteComma(b)
×
204
        success := JSONWritePropName(b, n) && JSONWriteItemCollectionValue(b, col, compact)
×
205
        if !success {
×
206
                *b = (*b)[:len(*b)-1]
×
207
        }
×
208
        return success
×
209
}
210

211
func JSONWriteObjectValue(b *[]byte, o Object) (notEmpty bool) {
110✔
212
        if v, err := o.ID.MarshalJSON(); err == nil && len(v) > 0 {
142✔
213
                notEmpty = JSONWriteProp(b, "id", v)
32✔
214
        }
32✔
215
        if HasTypes(o) {
142✔
216
                notEmpty = JSONWriteTypes(b, "type", o.Type) || notEmpty
32✔
217
        }
32✔
218
        if v, err := o.MediaType.MarshalJSON(); err == nil && len(v) > 0 {
116✔
219
                notEmpty = JSONWriteProp(b, "mediaType", v) || notEmpty
6✔
220
        }
6✔
221
        if len(o.Name) > 0 {
122✔
222
                notEmpty = JSONWriteNaturalLanguageProp(b, "name", o.Name) || notEmpty
12✔
223
        }
12✔
224
        if len(o.Summary) > 0 {
122✔
225
                notEmpty = JSONWriteNaturalLanguageProp(b, "summary", o.Summary) || notEmpty
12✔
226
        }
12✔
227
        if len(o.Content) > 0 {
122✔
228
                notEmpty = JSONWriteNaturalLanguageProp(b, "content", o.Content) || notEmpty
12✔
229
        }
12✔
230
        if o.Attachment != nil {
116✔
231
                notEmpty = JSONWriteItemProp(b, "attachment", o.Attachment) || notEmpty
6✔
232
        }
6✔
233
        if o.AttributedTo != nil {
122✔
234
                notEmpty = JSONWriteItemProp(b, "attributedTo", o.AttributedTo) || notEmpty
12✔
235
        }
12✔
236
        if o.Audience != nil {
110✔
237
                notEmpty = JSONWriteItemProp(b, "audience", o.Audience) || notEmpty
×
238
        }
×
239
        if o.Context != nil {
110✔
240
                notEmpty = JSONWriteItemProp(b, "context", o.Context) || notEmpty
×
241
        }
×
242
        if o.Generator != nil {
110✔
243
                notEmpty = JSONWriteItemProp(b, "generator", o.Generator) || notEmpty
×
244
        }
×
245
        if o.Icon != nil {
110✔
246
                notEmpty = JSONWriteItemProp(b, "icon", o.Icon) || notEmpty
×
247
        }
×
248
        if o.Image != nil {
110✔
249
                notEmpty = JSONWriteItemProp(b, "image", o.Image) || notEmpty
×
250
        }
×
251
        if o.InReplyTo != nil {
110✔
252
                notEmpty = JSONWriteItemProp(b, "inReplyTo", o.InReplyTo) || notEmpty
×
253
        }
×
254
        if o.Location != nil {
110✔
255
                notEmpty = JSONWriteItemProp(b, "location", o.Location) || notEmpty
×
256
        }
×
257
        if o.Preview != nil {
110✔
258
                notEmpty = JSONWriteItemProp(b, "preview", o.Preview) || notEmpty
×
259
        }
×
260
        if o.Replies != nil {
110✔
261
                notEmpty = JSONWriteItemProp(b, "replies", o.Replies) || notEmpty
×
262
        }
×
263
        if o.Tag != nil {
110✔
264
                notEmpty = JSONWriteItemCollectionProp(b, "tag", o.Tag, false) || notEmpty
×
265
        }
×
266
        if o.URL != nil {
110✔
267
                notEmpty = JSONWriteItemProp(b, "url", o.URL) || notEmpty
×
268
        }
×
269
        if o.To != nil {
110✔
270
                notEmpty = JSONWriteItemCollectionProp(b, "to", o.To, false) || notEmpty
×
271
        }
×
272
        if o.Bto != nil {
110✔
273
                notEmpty = JSONWriteItemCollectionProp(b, "bto", o.Bto, false) || notEmpty
×
274
        }
×
275
        if o.CC != nil {
110✔
276
                notEmpty = JSONWriteItemCollectionProp(b, "cc", o.CC, false) || notEmpty
×
277
        }
×
278
        if o.BCC != nil {
110✔
279
                notEmpty = JSONWriteItemCollectionProp(b, "bcc", o.BCC, false) || notEmpty
×
280
        }
×
281
        if !o.Published.IsZero() {
110✔
282
                notEmpty = JSONWriteTimeProp(b, "published", o.Published) || notEmpty
×
283
        }
×
284
        if !o.Updated.IsZero() {
110✔
285
                notEmpty = JSONWriteTimeProp(b, "updated", o.Updated) || notEmpty
×
286
        }
×
287
        if !o.StartTime.IsZero() {
110✔
288
                notEmpty = JSONWriteTimeProp(b, "startTime", o.StartTime) || notEmpty
×
289
        }
×
290
        if !o.EndTime.IsZero() {
110✔
291
                notEmpty = JSONWriteTimeProp(b, "endTime", o.EndTime) || notEmpty
×
292
        }
×
293
        if o.Duration != 0 {
110✔
294
                // TODO(marius): maybe don't use 0 as a nil value for Object types
×
295
                //  which can have a valid duration of 0 - (Video, Audio, etc)
×
296
                notEmpty = JSONWriteDurationProp(b, "duration", o.Duration) || notEmpty
×
297
        }
×
298
        if o.Likes != nil {
110✔
299
                notEmpty = JSONWriteItemProp(b, "likes", o.Likes) || notEmpty
×
300
        }
×
301
        if o.Shares != nil {
110✔
302
                notEmpty = JSONWriteItemProp(b, "shares", o.Shares) || notEmpty
×
303
        }
×
304
        if v, err := o.Source.MarshalJSON(); err == nil && len(v) > 0 {
116✔
305
                notEmpty = JSONWriteProp(b, "source", v) || notEmpty
6✔
306
        }
6✔
307
        return notEmpty
110✔
308
}
309

310
func JSONWriteActivityValue(b *[]byte, a Activity) (notEmpty bool) {
28✔
311
        _ = OnIntransitiveActivity(a, func(i *IntransitiveActivity) error {
56✔
312
                if i == nil {
28✔
313
                        return nil
×
314
                }
×
315
                notEmpty = JSONWriteIntransitiveActivityValue(b, *i) || notEmpty
28✔
316
                return nil
28✔
317
        })
318
        if a.Object != nil {
28✔
319
                notEmpty = JSONWriteItemProp(b, "object", a.Object) || notEmpty
×
320
        }
×
321
        return notEmpty
28✔
322
}
323

324
func JSONWriteIntransitiveActivityValue(b *[]byte, i IntransitiveActivity) (notEmpty bool) {
56✔
325
        _ = OnObject(i, func(o *Object) error {
112✔
326
                if o == nil {
56✔
327
                        return nil
×
328
                }
×
329
                notEmpty = JSONWriteObjectValue(b, *o) || notEmpty
56✔
330
                return nil
56✔
331
        })
332
        if i.Actor != nil {
56✔
333
                notEmpty = JSONWriteItemProp(b, "actor", i.Actor) || notEmpty
×
334
        }
×
335
        if i.Target != nil {
56✔
336
                notEmpty = JSONWriteItemProp(b, "target", i.Target) || notEmpty
×
337
        }
×
338
        if i.Result != nil {
56✔
339
                notEmpty = JSONWriteItemProp(b, "result", i.Result) || notEmpty
×
340
        }
×
341
        if i.Origin != nil {
56✔
342
                notEmpty = JSONWriteItemProp(b, "origin", i.Origin) || notEmpty
×
343
        }
×
344
        if i.Instrument != nil {
56✔
345
                notEmpty = JSONWriteItemProp(b, "instrument", i.Instrument) || notEmpty
×
346
        }
×
347
        return notEmpty
56✔
348
}
349

350
func JSONWriteQuestionValue(b *[]byte, q Question) (notEmpty bool) {
×
351
        _ = OnIntransitiveActivity(q, func(i *IntransitiveActivity) error {
×
352
                if i == nil {
×
353
                        return nil
×
354
                }
×
355
                notEmpty = JSONWriteIntransitiveActivityValue(b, *i) || notEmpty
×
356
                return nil
×
357
        })
358
        if q.OneOf != nil {
×
359
                notEmpty = JSONWriteItemProp(b, "oneOf", q.OneOf) || notEmpty
×
360
        }
×
361
        if q.AnyOf != nil {
×
362
                notEmpty = JSONWriteItemProp(b, "anyOf", q.AnyOf) || notEmpty
×
363
        }
×
364
        notEmpty = JSONWriteBoolProp(b, "closed", q.Closed) || notEmpty
×
365
        return notEmpty
×
366
}
367

368
func JSONWriteTypes(b *[]byte, n string, ty Typer) (notEmpty bool) {
34✔
369
        var typ ActivityVocabularyTypes
34✔
370
        if tt, ok := ty.(ActivityVocabularyType); ok {
68✔
371
                typ = ActivityVocabularyTypes{tt}
34✔
372
        }
34✔
373
        if tt, ok := ty.(ActivityVocabularyTypes); ok {
34✔
UNCOV
374
                typ = tt
×
UNCOV
375
        }
×
376
        if v, err := typ.MarshalJSON(); err == nil && len(v) > 0 {
68✔
377
                notEmpty = JSONWriteProp(b, n, v)
34✔
378
        }
34✔
379
        return true
34✔
380
}
381

382
func JSONWriteLinkValue(b *[]byte, l Link) (notEmpty bool) {
2✔
383
        if v, err := l.ID.MarshalJSON(); err == nil && len(v) > 0 {
4✔
384
                notEmpty = JSONWriteProp(b, "id", v)
2✔
385
        }
2✔
386
        if HasTypes(l) {
4✔
387
                notEmpty = JSONWriteTypes(b, "type", l.Type) || notEmpty
2✔
388
        }
2✔
389
        if v, err := l.MediaType.MarshalJSON(); err == nil && len(v) > 0 {
2✔
UNCOV
390
                notEmpty = JSONWriteProp(b, "mediaType", v) || notEmpty
×
391
        }
×
392
        if len(l.Name) > 0 {
2✔
UNCOV
393
                notEmpty = JSONWriteNaturalLanguageProp(b, "name", l.Name) || notEmpty
×
394
        }
×
395
        if v, err := l.Rel.MarshalJSON(); err == nil && len(v) > 0 {
2✔
UNCOV
396
                notEmpty = JSONWriteProp(b, "rel", v) || notEmpty
×
397
        }
×
398
        if l.Height > 0 {
2✔
UNCOV
399
                notEmpty = JSONWriteIntProp(b, "height", int64(l.Height))
×
UNCOV
400
        }
×
401
        if l.Width > 0 {
2✔
UNCOV
402
                notEmpty = JSONWriteIntProp(b, "width", int64(l.Width))
×
UNCOV
403
        }
×
404
        if l.Preview != nil {
2✔
UNCOV
405
                notEmpty = JSONWriteItemProp(b, "rel", l.Preview) || notEmpty
×
UNCOV
406
        }
×
407
        if v, err := l.Href.MarshalJSON(); err == nil && len(v) > 0 {
2✔
408
                notEmpty = JSONWriteProp(b, "href", v) || notEmpty
×
409
        }
×
410
        if l.HrefLang.Valid() {
2✔
UNCOV
411
                notEmpty = JSONWriteStringProp(b, "hrefLang", l.HrefLang.String()) || notEmpty
×
UNCOV
412
        }
×
413
        return notEmpty
2✔
414
}
415

416
func JSONWriteActivityVocabularyTypes(b *[]byte, t ActivityVocabularyTypes) (notEmpty bool) {
40✔
417
        if b == nil {
42✔
418
                return notEmpty
2✔
419
        }
2✔
420
        tLen := len(t)
38✔
421
        switch tLen {
38✔
UNCOV
422
        case 0:
×
UNCOV
423
                return notEmpty
×
424
        case 1:
36✔
425
                return JSONWriteStringValue(b, string(t[0]))
36✔
426
        default:
2✔
427
                JSONWrite(b, '[')
2✔
428
                for i, ty := range t {
6✔
429
                        if !JSONWriteStringValue(b, string(ty)) {
4✔
UNCOV
430
                                return false
×
UNCOV
431
                        }
×
432
                        if i < tLen-1 {
6✔
433
                                JSONWriteComma(b)
2✔
434
                        }
2✔
435
                        notEmpty = true
4✔
436
                }
437
                JSONWrite(b, ']')
2✔
438
                return notEmpty
2✔
439
        }
440
}
441

442
// MarshalJSON represents just a wrapper for the jsonld.Marshal function
443
func MarshalJSON(it LinkOrIRI) ([]byte, error) {
6✔
444
        return jsonld.Marshal(it)
6✔
445
}
6✔
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