@agoric/cosmos 0.34.2-dev-5dc325b.0 → 0.35.0-getting-started-dev-26244e8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,298 +0,0 @@
1
- package capdata
2
-
3
- import (
4
- "bytes"
5
- "encoding/json"
6
- "fmt"
7
- "regexp"
8
- "strconv"
9
- "strings"
10
- )
11
-
12
- // JsonMarshal returns JSON text representing its input,
13
- // without special replacement of "<", ">", "&", U+2028, or U+2029.
14
- func JsonMarshal(val any) ([]byte, error) {
15
- buf := &bytes.Buffer{}
16
- encoder := json.NewEncoder(buf)
17
- encoder.SetEscapeHTML(false)
18
- if err := encoder.Encode(val); err != nil {
19
- return nil, err
20
- }
21
- // Return without a trailing line feed.
22
- lineTerminatedJson := buf.Bytes()
23
- return bytes.TrimSuffix(lineTerminatedJson, []byte("\n")), nil
24
- }
25
-
26
- // cf. https://github.com/endojs/endo/tree/master/packages/marshal
27
-
28
- type Capdata struct {
29
- Body string `json:"body"`
30
- Slots []interface{} `json:"slots"`
31
- }
32
-
33
- var validBigint = regexp.MustCompile(`^-?(?:0|[1-9][0-9]*)$`)
34
-
35
- type CapdataBigint struct {
36
- Normalized string
37
- }
38
-
39
- type CapdataRemotable struct {
40
- Id interface{}
41
- Iface *string
42
- Representation interface{}
43
- }
44
-
45
- func NewCapdataBigint(str string) *CapdataBigint {
46
- if !validBigint.MatchString(str) {
47
- return nil
48
- }
49
- bigint := CapdataBigint{str}
50
- return &bigint
51
- }
52
-
53
- func (r *CapdataRemotable) MarshalJSON() ([]byte, error) {
54
- return JsonMarshal(r.Representation)
55
- }
56
-
57
- type CapdataValueTransformations struct {
58
- Bigint func(*CapdataBigint) interface{}
59
- Remotable func(*CapdataRemotable) interface{}
60
- }
61
-
62
- // upsertCapdataRemotable either adds a new CapdataRemotable to `remotables` at the specified
63
- // slot index or updates the iface of the value that is already there, ensuring lack of iface name
64
- // inconsistency (iteration order is not guaranteed to correspond with JSON text like it does in
65
- // JavaScript, so we must accept encountering the "first" reference to a slot late
66
- // and must therefore also defer transformations).
67
- func upsertCapdataRemotable(remotables map[uint64]*CapdataRemotable, slotIndex uint64, id interface{}, iface *string) (*CapdataRemotable, error) {
68
- r := remotables[slotIndex]
69
- if r == nil {
70
- r = new(CapdataRemotable)
71
- r.Id = id
72
- r.Iface = iface
73
- remotables[slotIndex] = r
74
- } else if iface != nil {
75
- if r.Iface != nil && *iface != *r.Iface {
76
- return nil, fmt.Errorf("slot iface mismatch: %q", *iface)
77
- }
78
- r.Iface = iface
79
- }
80
- return r, nil
81
- }
82
-
83
- // decodeCapdataLegacyValue decodes the non-smallcaps encoding of
84
- // https://github.com/endojs/endo/blob/master/packages/marshal/src/encodeToCapData.js
85
- func decodeCapdataLegacyValue(
86
- encoded interface{},
87
- slots []interface{},
88
- remotables map[uint64]*CapdataRemotable,
89
- transformations CapdataValueTransformations,
90
- ) (interface{}, error) {
91
- if arr, ok := encoded.([]interface{}); ok {
92
- for i, v := range arr {
93
- decoded, err := decodeCapdataLegacyValue(v, slots, remotables, transformations)
94
- if err != nil {
95
- return nil, err
96
- }
97
- arr[i] = decoded
98
- }
99
- return arr, nil
100
- } else if obj, ok := encoded.(map[string]interface{}); ok {
101
- if qclassVal, ok := obj["@qclass"]; ok {
102
- qclass, ok := qclassVal.(string)
103
- if !ok {
104
- return nil, fmt.Errorf("invalid @qclass: %q", qclassVal)
105
- }
106
- switch qclass {
107
- case "bigint":
108
- var bigint *CapdataBigint
109
- digitsVal := obj["digits"]
110
- if digitsStr, ok := digitsVal.(string); ok {
111
- bigint = NewCapdataBigint(digitsStr)
112
- }
113
- if bigint == nil {
114
- return nil, fmt.Errorf("invalid bigint: %q", digitsVal)
115
- }
116
- if transformations.Bigint == nil {
117
- return nil, fmt.Errorf("untransformed bigint")
118
- }
119
- return transformations.Bigint(bigint), nil
120
- case "slot":
121
- var iface *string
122
- slotIndexVal, ifaceVal := obj["index"], obj["iface"]
123
- slotIndexNum, ok := slotIndexVal.(float64)
124
- slotIndex := uint64(slotIndexNum)
125
- if !ok || float64(slotIndex) != slotIndexNum || slotIndex >= uint64(len(slots)) {
126
- return nil, fmt.Errorf("invalid slot index: %q", slotIndexVal)
127
- }
128
- if ifaceStr, ok := ifaceVal.(string); ok {
129
- iface = &ifaceStr
130
- } else if ifaceVal != nil {
131
- return nil, fmt.Errorf("invalid slot iface: %q", ifaceVal)
132
- }
133
- return upsertCapdataRemotable(remotables, slotIndex, slots[slotIndex], iface)
134
- case "hilbert":
135
- fallthrough
136
- case "undefined":
137
- fallthrough
138
- case "NaN":
139
- fallthrough
140
- case "Infinity":
141
- fallthrough
142
- case "symbol":
143
- fallthrough
144
- case "tagged":
145
- fallthrough
146
- case "error":
147
- fallthrough
148
- case "-Infinity":
149
- return nil, fmt.Errorf("not implemented: @qclass %q", qclass)
150
- default:
151
- return nil, fmt.Errorf("unrecognized @qclass: %q", qclass)
152
- }
153
- }
154
- for k, v := range obj {
155
- decoded, err := decodeCapdataLegacyValue(v, slots, remotables, transformations)
156
- if err != nil {
157
- return nil, err
158
- }
159
- obj[k] = decoded
160
- }
161
- return obj, nil
162
- } else {
163
- return encoded, nil
164
- }
165
- }
166
-
167
- // decodeCapdataSmallcapsValue decodes the "smallcaps" encoding from
168
- // https://github.com/endojs/endo/blob/master/packages/marshal/src/encodeToSmallcaps.js
169
- func decodeCapdataSmallcapsValue(
170
- encoded interface{},
171
- slots []interface{},
172
- remotables map[uint64]*CapdataRemotable,
173
- transformations CapdataValueTransformations,
174
- ) (interface{}, error) {
175
- if arr, ok := encoded.([]interface{}); ok {
176
- for i, v := range arr {
177
- decoded, err := decodeCapdataSmallcapsValue(v, slots, remotables, transformations)
178
- if err != nil {
179
- return nil, err
180
- }
181
- arr[i] = decoded
182
- }
183
- return arr, nil
184
- } else if encodedObj, ok := encoded.(map[string]interface{}); ok {
185
- if _, ok := encodedObj["#tag"]; ok {
186
- return nil, fmt.Errorf("not implemented: #tag")
187
- }
188
- if _, ok := encodedObj["#error"]; ok {
189
- return nil, fmt.Errorf("not implemented: #error")
190
- }
191
- // We need a distinct output map to avoid reprocessing already-decoded keys.
192
- decodedObj := make(map[string]interface{}, len(encodedObj))
193
- for encodedK, v := range encodedObj {
194
- if strings.HasPrefix(encodedK, "#") {
195
- return nil, fmt.Errorf("unrecognized record type: %q", encodedK)
196
- }
197
- decodedK, err := decodeCapdataSmallcapsValue(encodedK, slots, remotables, CapdataValueTransformations{})
198
- k, ok := decodedK.(string)
199
- if err != nil || !ok {
200
- return nil, fmt.Errorf("invalid copyRecord key: %q", encodedK)
201
- }
202
- decoded, err := decodeCapdataSmallcapsValue(v, slots, remotables, transformations)
203
- if err != nil {
204
- return nil, err
205
- }
206
- decodedObj[k] = decoded
207
- }
208
- return decodedObj, nil
209
- } else if str, ok := encoded.(string); ok {
210
- if len(str) == 0 {
211
- return str, nil
212
- }
213
- switch str[0] {
214
- case '!':
215
- return str[1:], nil
216
- case '+':
217
- // Normalize to no leading "+".
218
- str = str[1:]
219
- fallthrough
220
- case '-':
221
- bigint := NewCapdataBigint(str)
222
- if bigint == nil {
223
- return nil, fmt.Errorf("invalid bigint: %q", encoded.(string))
224
- }
225
- if transformations.Bigint == nil {
226
- return nil, fmt.Errorf("untransformed bigint")
227
- }
228
- return transformations.Bigint(bigint), nil
229
- case '$':
230
- var slotIndexStr string
231
- var iface *string
232
- if dotIndex := strings.IndexByte(str, '.'); dotIndex >= 0 {
233
- slotIndexStr = str[1:dotIndex]
234
- ifaceStr := str[dotIndex+1:]
235
- iface = &ifaceStr
236
- } else {
237
- slotIndexStr = str[1:]
238
- }
239
- slotIndex, err := strconv.ParseUint(slotIndexStr, 10, 0)
240
- if err != nil || slotIndex >= uint64(len(slots)) {
241
- return nil, fmt.Errorf("invalid slot index: %q", str)
242
- }
243
- r, err := upsertCapdataRemotable(remotables, slotIndex, slots[slotIndex], iface)
244
- if err != nil {
245
- return nil, fmt.Errorf("slot iface mismatch: %q", str)
246
- }
247
- return r, nil
248
- case '#':
249
- fallthrough
250
- case '%':
251
- fallthrough
252
- case '&':
253
- return nil, fmt.Errorf("not implemented: %q", str)
254
- default:
255
- if str[0] >= '!' && str[0] <= '-' {
256
- return nil, fmt.Errorf("invalid smallcaps encoding prefix: %q", str[:1])
257
- }
258
- }
259
- return str, nil
260
- } else {
261
- return encoded, nil
262
- }
263
- }
264
-
265
- // DecodeSerializedCapdata accepts JSON text representing encoded CapData and
266
- // decodes it, applying specified transformations for values that otherwise
267
- // hinder interchange.
268
- func DecodeSerializedCapdata(
269
- serializedCapdata string,
270
- transformations CapdataValueTransformations,
271
- ) (interface{}, error) {
272
- var capdata Capdata
273
- if err := json.Unmarshal([]byte(serializedCapdata), &capdata); err != nil {
274
- return nil, err
275
- }
276
- if capdata.Body == "" || capdata.Slots == nil {
277
- return nil, fmt.Errorf("invalid CapData")
278
- }
279
- serializedBody, decodeValue := capdata.Body, decodeCapdataLegacyValue
280
- if strings.HasPrefix(serializedBody, "#") {
281
- serializedBody, decodeValue = serializedBody[1:], decodeCapdataSmallcapsValue
282
- }
283
- var encoded interface{}
284
- if err := json.Unmarshal([]byte(serializedBody), &encoded); err != nil {
285
- return nil, err
286
- }
287
- remotables := map[uint64]*CapdataRemotable{}
288
- decoded, err := decodeValue(encoded, capdata.Slots, remotables, transformations)
289
- if err == nil && len(remotables) > 0 {
290
- if transformations.Remotable == nil {
291
- return nil, fmt.Errorf("untransformed remotable")
292
- }
293
- for _, r := range remotables {
294
- r.Representation = transformations.Remotable(r)
295
- }
296
- }
297
- return decoded, err
298
- }
@@ -1,352 +0,0 @@
1
- package capdata
2
-
3
- import (
4
- "encoding/json"
5
- "fmt"
6
- "reflect"
7
- "strings"
8
- "testing"
9
- )
10
-
11
- func ptr[T any](v T) *T {
12
- return &v
13
- }
14
-
15
- func mustJsonMarshal(val any) string {
16
- jsonText, err := JsonMarshal(val)
17
- if err != nil {
18
- panic(err)
19
- }
20
- return string(jsonText)
21
- }
22
-
23
- func mustJsonUnmarshal(jsonText string, ptr any) {
24
- if err := json.Unmarshal([]byte(jsonText), ptr); err != nil {
25
- panic(err)
26
- }
27
- }
28
-
29
- func prefixBigint(bigint *CapdataBigint) interface{} {
30
- return fmt.Sprintf("bigint:%s", bigint.Normalized)
31
- }
32
-
33
- func remotableToString(r *CapdataRemotable) interface{} {
34
- iface := ""
35
- if r.Iface != nil {
36
- iface = *r.Iface
37
- }
38
- return fmt.Sprintf("remotable:%s{%s}", iface, r.Id)
39
- }
40
-
41
- func Test_JsonMarshal(t *testing.T) {
42
- type testCase struct {
43
- input string
44
- expected string
45
- errContains *string
46
- }
47
- testCases := []testCase{
48
- {
49
- input: "<>&\u2028\u2029",
50
- expected: `"<>&\u2028\u2029"`,
51
- },
52
- }
53
- for _, desc := range testCases {
54
- label := fmt.Sprintf("%q", desc.input)
55
- result, err := JsonMarshal(desc.input)
56
- if desc.errContains == nil {
57
- if err != nil {
58
- t.Errorf("%s: got unexpected error %v", label, err)
59
- } else if string(result) != desc.expected {
60
- t.Errorf("%s: wrong result: %#q", label, result)
61
- }
62
- } else if err == nil {
63
- t.Errorf("%s: got no error, want error %q", label, *desc.errContains)
64
- } else if !strings.Contains(err.Error(), *desc.errContains) {
65
- t.Errorf("%s: got error %v, want error %q", label, err, *desc.errContains)
66
- }
67
- }
68
- }
69
-
70
- func Test_DecodeSerializedCapdata(t *testing.T) {
71
- type testCase struct {
72
- format string
73
- label string
74
- body string
75
- slots []interface{}
76
- expected string
77
- errContains *string
78
- transformations CapdataValueTransformations
79
- }
80
- testCases := []testCase{
81
- // JSON
82
- // cf. https://github.com/endojs/endo/blob/209b612e0a267239f33cd607e94ccd179d3ba248/packages/marshal/test/test-marshal-capdata.js#L11
83
- {body: `[1, 2]`},
84
- {body: `{ "foo": 1 }`},
85
- {body: `{}`},
86
- {body: `{ "a": 1, "b": 2 }`},
87
- {body: `{ "a": 1, "b": { "c": 3 } }`},
88
- {body: `true`},
89
- {body: `1`},
90
- {body: `"abc"`},
91
- {body: `null`},
92
-
93
- // transformation of non-JSON values
94
- {format: "smallcaps", label: "bigint",
95
- body: `"+98765432101234567890"`,
96
- expected: `"bigint:98765432101234567890"`,
97
- transformations: CapdataValueTransformations{Bigint: prefixBigint},
98
- },
99
- {format: "legacy", label: "bigint",
100
- body: `{ "@qclass": "bigint", "digits": "98765432101234567890" }`,
101
- expected: `"bigint:98765432101234567890"`,
102
- transformations: CapdataValueTransformations{Bigint: prefixBigint},
103
- },
104
- {format: "smallcaps", label: "remotables",
105
- body: `["$0.Foo", "$0"]`,
106
- slots: []interface{}{"a"},
107
- expected: `["remotable:Foo{a}","remotable:Foo{a}"]`,
108
- transformations: CapdataValueTransformations{Remotable: remotableToString},
109
- },
110
- {format: "legacy", label: "remotables",
111
- body: `[{"@qclass":"slot","index":0,"iface":"Foo"}, {"@qclass":"slot","index":0}]`,
112
- slots: []interface{}{"a"},
113
- expected: `["remotable:Foo{a}","remotable:Foo{a}"]`,
114
- transformations: CapdataValueTransformations{Remotable: remotableToString},
115
- },
116
- {format: "smallcaps", label: "escaped string",
117
- body: `"!#escaped"`,
118
- expected: `"#escaped"`,
119
- },
120
-
121
- // unimplemented
122
- {format: "smallcaps",
123
- body: `"#undefined"`,
124
- errContains: ptr("not implemented"),
125
- },
126
- {format: "legacy", label: "undefined",
127
- body: `{"@qclass":"undefined"}`,
128
- errContains: ptr("not implemented"),
129
- },
130
- {format: "smallcaps",
131
- body: `"#NaN"`,
132
- errContains: ptr("not implemented"),
133
- },
134
- {format: "legacy", label: "NaN",
135
- body: `{"@qclass":"NaN"}`,
136
- errContains: ptr("not implemented"),
137
- },
138
- {format: "smallcaps",
139
- body: `"#Infinity"`,
140
- errContains: ptr("not implemented"),
141
- },
142
- {format: "legacy", label: "Infinity",
143
- body: `{"@qclass":"Infinity"}`,
144
- errContains: ptr("not implemented"),
145
- },
146
- {format: "smallcaps",
147
- body: `"#-Infinity"`,
148
- errContains: ptr("not implemented"),
149
- },
150
- {format: "legacy", label: "-Infinity",
151
- body: `{"@qclass":"-Infinity"}`,
152
- errContains: ptr("not implemented"),
153
- },
154
- {format: "smallcaps", label: "symbol",
155
- body: `"%foo"`,
156
- errContains: ptr("not implemented"),
157
- },
158
- {format: "legacy", label: "symbol",
159
- body: `{"@qclass":"symbol"}`,
160
- errContains: ptr("not implemented"),
161
- },
162
- {format: "smallcaps", label: "tagged",
163
- body: `{"#tag":"foo","payload":"bar"}`,
164
- errContains: ptr("not implemented: #tag"),
165
- },
166
- {format: "legacy", label: "tagged",
167
- body: `{"@qclass":"tagged","tag":"foo","payload":"bar"}`,
168
- errContains: ptr("not implemented"),
169
- },
170
- {format: "smallcaps", label: "error",
171
- body: `{"#error":"","name":"Error"}`,
172
- errContains: ptr("not implemented: #error"),
173
- },
174
- {format: "legacy", label: "error",
175
- body: `{"@qclass":"error","message":"foo","name":"bar"}`,
176
- errContains: ptr("not implemented"),
177
- },
178
- {format: "smallcaps", label: "promise",
179
- body: `"&0"`,
180
- slots: []interface{}{"a"},
181
- errContains: ptr("not implemented"),
182
- },
183
- {format: "legacy", label: "error",
184
- body: `{"@qclass":"hilbert","original":"foo"}`,
185
- errContains: ptr("not implemented"),
186
- },
187
-
188
- // missing transformations
189
- {format: "smallcaps", label: "untransformed bigint",
190
- body: `"+98765432101234567890"`,
191
- errContains: ptr("untransformed bigint"),
192
- },
193
- {format: "legacy", label: "untransformed bigint",
194
- body: `{ "@qclass": "bigint", "digits": "98765432101234567890" }`,
195
- errContains: ptr("untransformed bigint"),
196
- },
197
- {format: "smallcaps", label: "untransformed remotable",
198
- body: `["$0.Foo", "$0"]`,
199
- slots: []interface{}{"a"},
200
- errContains: ptr("untransformed remotable"),
201
- },
202
- {format: "legacy", label: "untransformed remotable",
203
- body: `[{"@qclass":"slot","index":0,"iface":"Foo"}, {"@qclass":"slot","index":0}]`,
204
- slots: []interface{}{"a"},
205
- errContains: ptr("untransformed remotable"),
206
- },
207
-
208
- // invalid data
209
- {format: "smallcaps", label: "iface mismatch",
210
- body: `["$0.Foo", "$0."]`,
211
- slots: []interface{}{"a"},
212
- errContains: ptr("iface mismatch"),
213
- },
214
- {format: "legacy", label: "iface mismatch",
215
- body: `[{"@qclass":"slot","index":0,"iface":"Foo"}, {"@qclass":"slot","index":0,"iface":""}]`,
216
- slots: []interface{}{"a"},
217
- errContains: ptr("iface mismatch"),
218
- },
219
- {format: "smallcaps", label: "invalid slot index (out of bounds)",
220
- body: `"$0.Foo"`,
221
- errContains: ptr("invalid slot index"),
222
- },
223
- {format: "legacy", label: "invalid slot index (out of bounds)",
224
- body: `{"@qclass":"slot","index":0}`,
225
- errContains: ptr("invalid slot index"),
226
- },
227
- {format: "smallcaps", label: "invalid slot index (bad format)",
228
- body: `"$x.Foo"`,
229
- slots: []interface{}{"a"},
230
- errContains: ptr("invalid slot index"),
231
- },
232
- {format: "legacy", label: "invalid slot index (missing)",
233
- body: `{"@qclass":"slot"}`,
234
- slots: []interface{}{"a"},
235
- errContains: ptr("invalid slot index"),
236
- },
237
- {format: "legacy", label: "invalid slot index (null)",
238
- body: `{"@qclass":"slot","index":null}`,
239
- slots: []interface{}{"a"},
240
- errContains: ptr("invalid slot index"),
241
- },
242
- {format: "legacy", label: "invalid slot index (string)",
243
- body: `{"@qclass":"slot","index":"0"}`,
244
- slots: []interface{}{"a"},
245
- errContains: ptr("invalid slot index"),
246
- },
247
- {format: "legacy", label: "invalid slot index (non-integer)",
248
- body: `{"@qclass":"slot","index":0.1}`,
249
- slots: []interface{}{"a"},
250
- errContains: ptr("invalid slot index"),
251
- },
252
- {format: "legacy", label: "invalid slot index (negative)",
253
- body: `{"@qclass":"slot","index":-1}`,
254
- slots: []interface{}{"a"},
255
- errContains: ptr("invalid slot index"),
256
- },
257
- {format: "legacy", label: "invalid slot iface (number)",
258
- body: `{"@qclass":"slot","index":0,"iface":0}`,
259
- slots: []interface{}{"a"},
260
- errContains: ptr("invalid slot iface"),
261
- },
262
- {format: "smallcaps", label: "unrecognized record type",
263
- body: `{"#foo":0}`,
264
- errContains: ptr("unrecognized record type"),
265
- },
266
- {format: "legacy", label: "invalid @qclass (null)",
267
- body: `{"@qclass":null}`,
268
- errContains: ptr("invalid @qclass"),
269
- },
270
- {format: "legacy", label: "invalid @qclass (number)",
271
- body: `{"@qclass":1}`,
272
- errContains: ptr("invalid @qclass"),
273
- },
274
- {format: "legacy", label: "invalid @qclass (number)",
275
- body: `{"@qclass":1}`,
276
- errContains: ptr("invalid @qclass"),
277
- },
278
- {format: "legacy", label: "unrecognized @qclass",
279
- body: `{"@qclass":"foo"}`,
280
- errContains: ptr("unrecognized @qclass"),
281
- },
282
- {format: "smallcaps", label: "invalid copyRecord key",
283
- body: `{"+0":0}`,
284
- errContains: ptr("invalid copyRecord key"),
285
- },
286
- {format: "smallcaps", label: "invalid bigint (`--`)",
287
- body: `"--"`,
288
- errContains: ptr("invalid bigint"),
289
- },
290
- {format: "smallcaps", label: "invalid bigint (`+0x`)",
291
- body: `"+0x"`,
292
- errContains: ptr("invalid bigint"),
293
- },
294
- {format: "legacy", label: "invalid bigint (no digits)",
295
- body: `{"@qclass":"bigint"}`,
296
- errContains: ptr("invalid bigint"),
297
- },
298
- {format: "legacy", label: "invalid bigint (null digits)",
299
- body: `{"@qclass":"bigint","digits":null}`,
300
- errContains: ptr("invalid bigint"),
301
- },
302
- {format: "legacy", label: "invalid bigint (`7up`)",
303
- body: `{"@qclass":"bigint","digits":"7up"}`,
304
- errContains: ptr("invalid bigint"),
305
- },
306
- }
307
-
308
- for _, desc := range testCases {
309
- slots := desc.slots
310
- if slots == nil {
311
- slots = []interface{}{}
312
- }
313
- var expected interface{}
314
- if desc.expected != "" {
315
- mustJsonUnmarshal(desc.expected, &expected)
316
- } else {
317
- mustJsonUnmarshal(desc.body, &expected)
318
- }
319
- for _, format := range []string{"smallcaps", "legacy"} {
320
- if desc.format != "" && desc.format != format {
321
- continue
322
- }
323
- label := fmt.Sprintf("%s %s", format, desc.label)
324
- if desc.label == "" {
325
- label = fmt.Sprintf("%s %s", format, desc.body)
326
- }
327
- capdata := Capdata{desc.body, slots}
328
- if format == "smallcaps" {
329
- capdata.Body = "#" + capdata.Body
330
- }
331
- intermediate, err := DecodeSerializedCapdata(mustJsonMarshal(capdata), desc.transformations)
332
- // Replace each Remotable with its representation before comparing.
333
- var got interface{}
334
- mustJsonUnmarshal(mustJsonMarshal(intermediate), &got)
335
- if desc.errContains == nil {
336
- if err != nil {
337
- t.Errorf("%s: got unexpected error %v", label, err)
338
- } else if !reflect.DeepEqual(got, expected) {
339
- result, err := JsonMarshal(got)
340
- if err != nil {
341
- panic(fmt.Errorf("%s: %v", label, err))
342
- }
343
- t.Errorf("%s: wrong result: %s", label, result)
344
- }
345
- } else if err == nil {
346
- t.Errorf("%s: got no error, want error %q", label, *desc.errContains)
347
- } else if !strings.Contains(err.Error(), *desc.errContains) {
348
- t.Errorf("%s: got error %v, want error %q", label, err, *desc.errContains)
349
- }
350
- }
351
- }
352
- }