go-ipfs-config: feat: add an OptionalInteger type
Adin Schmahmann committed
Aug 16, 2021 at 00:01 UTC
ac81804c8c4b76aa1de7358abdd45c69ed53978a
2 files changed
+142
config/types.go
+52
@@ -232,3 +232,55 @@ func (d Duration) String() string {
232
233
var _ encoding.TextUnmarshaler = (*Duration)(nil)
234
var _ encoding.TextMarshaler = (*Duration)(nil)
235
+
236
+// OptionalInteger represents an integer that has a default value
237
+//
238
+// When encoded in json, Default is encoded as "null"
239
+type OptionalInteger struct {
240
+ value *int64
241
+}
242
+
243
+// WithDefault resolves the integer with the given default.
244
+func (p OptionalInteger) WithDefault(defaultValue int64) (value int64) {
245
+ if p.value == nil {
246
+ return defaultValue
247
+ }
248
+ return *p.value
249
+}
250
+
251
+// IsDefault returns if this is a default optional integer
252
+func (p OptionalInteger) IsDefault() bool {
253
+ return p.value == nil
254
+}
255
+
256
+func (p OptionalInteger) MarshalJSON() ([]byte, error) {
257
+ if p.value != nil {
258
+ return json.Marshal(p.value)
259
+ }
260
+ return json.Marshal(nil)
261
+}
262
+
263
+func (p *OptionalInteger) UnmarshalJSON(input []byte) error {
264
+ switch string(input) {
265
+ case "null", "undefined":
266
+ *p = OptionalInteger{}
267
+ default:
268
+ var value int64
269
+ err := json.Unmarshal(input, &value)
270
+ if err != nil {
271
+ return err
272
+ }
273
+ *p = OptionalInteger{value: &value}
274
+ }
275
+ return nil
276
+}
277
+
278
+func (p OptionalInteger) String() string {
279
+ if p.value == nil {
280
+ return "default"
281
+ }
282
+ return fmt.Sprintf("%d", p.value)
283
+}
284
+
285
+var _ json.Unmarshaler = (*OptionalInteger)(nil)
286
+var _ json.Marshaler = (*OptionalInteger)(nil)
config/types_test.go
+90
@@ -218,3 +218,93 @@ func TestPriority(t *testing.T) {
218
}
219
}
220
}
221
+
222
+func TestOptionalInteger(t *testing.T) {
223
+ makeInt64Pointer := func(v int64) *int64 {
224
+ return &v
225
+ }
226
+
227
+ var defaultOptionalInt OptionalInteger
228
+ if !defaultOptionalInt.IsDefault() {
229
+ t.Fatal("should be the default")
230
+ }
231
+ if val := defaultOptionalInt.WithDefault(0); val != 0 {
232
+ t.Errorf("optional integer should have been 0, got %d", val)
233
+ }
234
+
235
+ if val := defaultOptionalInt.WithDefault(1); val != 1 {
236
+ t.Errorf("optional integer should have been 1, got %d", val)
237
+ }
238
+
239
+ if val := defaultOptionalInt.WithDefault(-1); val != -1 {
240
+ t.Errorf("optional integer should have been -1, got %d", val)
241
+ }
242
+
243
+ var filledInt OptionalInteger
244
+ filledInt = OptionalInteger{value: makeInt64Pointer(1)}
245
+ if filledInt.IsDefault() {
246
+ t.Fatal("should not be the default")
247
+ }
248
+ if val := filledInt.WithDefault(0); val != 1 {
249
+ t.Errorf("optional integer should have been 1, got %d", val)
250
+ }
251
+
252
+ if val := filledInt.WithDefault(-1); val != 1 {
253
+ t.Errorf("optional integer should have been 1, got %d", val)
254
+ }
255
+
256
+ filledInt = OptionalInteger{value: makeInt64Pointer(0)}
257
+ if val := filledInt.WithDefault(1); val != 0 {
258
+ t.Errorf("optional integer should have been 0, got %d", val)
259
+ }
260
+
261
+ for jsonStr, goValue := range map[string]OptionalInteger{
262
+ "null": {},
263
+ "0": {value: makeInt64Pointer(0)},
264
+ "1": {value: makeInt64Pointer(1)},
265
+ "-1": {value: makeInt64Pointer(-1)},
266
+ } {
267
+ var d OptionalInteger
268
+ err := json.Unmarshal([]byte(jsonStr), &d)
269
+ if err != nil {
270
+ t.Fatal(err)
271
+ }
272
+
273
+ if goValue.value == nil && d.value == nil {
274
+ } else if goValue.value == nil && d.value != nil {
275
+ t.Errorf("expected default, got %s", d)
276
+ } else if *d.value != *goValue.value {
277
+ t.Fatalf("expected %s, got %s", goValue, d)
278
+ }
279
+
280
+ // Reverse
281
+ out, err := json.Marshal(goValue)
282
+ if err != nil {
283
+ t.Fatal(err)
284
+ }
285
+ if string(out) != jsonStr {
286
+ t.Fatalf("expected %s, got %s", jsonStr, string(out))
287
+ }
288
+ }
289
+
290
+ type Foo struct {
291
+ I *OptionalInteger `json:",omitempty"`
292
+ }
293
+ out, err := json.Marshal(new(Foo))
294
+ if err != nil {
295
+ t.Fatal(err)
296
+ }
297
+ expected := "{}"
298
+ if string(out) != expected {
299
+ t.Fatal("expected omitempty to omit the optional integer")
300
+ }
301
+ for _, invalid := range []string{
302
+ "foo", "-1.1", "1.1", "0.0", "[]",
303
+ } {
304
+ var p Priority
305
+ err := json.Unmarshal([]byte(invalid), &p)
306
+ if err == nil {
307
+ t.Errorf("expected to fail to decode %s as a priority", invalid)
308
+ }
309
+ }
310
+}