go-ipfs-config: feat: OptionalString type and UnixFSShardingSizeThreshold (#149)
* feat: add OptionalString type * test: fix OptionalInteger test * add Internal.UnixFSShardingSizeThreshold as optional string * test: OptionalString null unmarshal with default * fix: omitempty UnixFSShardingSizeThreshold Co-authored-by: Marcin Rataj <lidel@lidel.org>
Adin Schmahmann committed
Oct 28, 2021 at 13:55 UTC
cdaa222b22424a615e16fe349bc47c1e1f47c752
3 files changed
+151
-2
config/internal.go
+2
-1
@@ -1,7 +1,8 @@
1
package config
2
3
type Internal struct {
4
- Bitswap *InternalBitswap `json:",omitempty"` // This is omitempty since we are expecting to make changes to all subcomponents of Internal
4
+ Bitswap *InternalBitswap `json:",omitempty"` // This is omitempty since we are expecting to make changes to all subcomponents of Internal
5
+ UnixFSShardingSizeThreshold *OptionalString `json:",omitempty"`
6
}
7
8
type InternalBitswap struct {
config/types.go
+52
@@ -313,3 +313,55 @@ func (p OptionalInteger) String() string {
313
314
var _ json.Unmarshaler = (*OptionalInteger)(nil)
315
var _ json.Marshaler = (*OptionalInteger)(nil)
316
+
317
+// OptionalString represents a string that has a default value
318
+//
319
+// When encoded in json, Default is encoded as "null"
320
+type OptionalString struct {
321
+ value *string
322
+}
323
+
324
+// WithDefault resolves the integer with the given default.
325
+func (p *OptionalString) WithDefault(defaultValue string) (value string) {
326
+ if p == nil || p.value == nil {
327
+ return defaultValue
328
+ }
329
+ return *p.value
330
+}
331
+
332
+// IsDefault returns if this is a default optional integer
333
+func (p *OptionalString) IsDefault() bool {
334
+ return p == nil || p.value == nil
335
+}
336
+
337
+func (p OptionalString) MarshalJSON() ([]byte, error) {
338
+ if p.value != nil {
339
+ return json.Marshal(p.value)
340
+ }
341
+ return json.Marshal(nil)
342
+}
343
+
344
+func (p *OptionalString) UnmarshalJSON(input []byte) error {
345
+ switch string(input) {
346
+ case "null", "undefined":
347
+ *p = OptionalString{}
348
+ default:
349
+ var value string
350
+ err := json.Unmarshal(input, &value)
351
+ if err != nil {
352
+ return err
353
+ }
354
+ *p = OptionalString{value: &value}
355
+ }
356
+ return nil
357
+}
358
+
359
+func (p OptionalString) String() string {
360
+ if p.value == nil {
361
+ return "default"
362
+ }
363
+ return fmt.Sprintf("%d", p.value)
364
+}
365
+
366
+var _ json.Unmarshaler = (*OptionalInteger)(nil)
367
+var _ json.Marshaler = (*OptionalInteger)(nil)
config/types_test.go
+97
-1
@@ -389,10 +389,106 @@ func TestOptionalInteger(t *testing.T) {
389
for _, invalid := range []string{
390
"foo", "-1.1", "1.1", "0.0", "[]",
391
} {
392
- var p Priority
392
+ var p OptionalInteger
393
err := json.Unmarshal([]byte(invalid), &p)
394
if err == nil {
395
t.Errorf("expected to fail to decode %s as a priority", invalid)
396
}
397
}
398
}
399
+
400
+func TestOptionalString(t *testing.T) {
401
+ makeStringPointer := func(v string) *string {
402
+ return &v
403
+ }
404
+
405
+ var defaultOptionalString OptionalString
406
+ if !defaultOptionalString.IsDefault() {
407
+ t.Fatal("should be the default")
408
+ }
409
+ if val := defaultOptionalString.WithDefault(""); val != "" {
410
+ t.Errorf("optional integer should have been empty, got %s", val)
411
+ }
412
+
413
+ if val := defaultOptionalString.WithDefault("foo"); val != "foo" {
414
+ t.Errorf("optional integer should have been foo, got %s", val)
415
+ }
416
+
417
+ var filledStr OptionalString
418
+ filledStr = OptionalString{value: makeStringPointer("foo")}
419
+ if filledStr.IsDefault() {
420
+ t.Fatal("should not be the default")
421
+ }
422
+ if val := filledStr.WithDefault("bar"); val != "foo" {
423
+ t.Errorf("optional integer should have been foo, got %s", val)
424
+ }
425
+
426
+ filledStr = OptionalString{value: makeStringPointer("")}
427
+ if val := filledStr.WithDefault("foo"); val != "" {
428
+ t.Errorf("optional integer should have been 0, got %s", val)
429
+ }
430
+
431
+ for jsonStr, goValue := range map[string]OptionalString{
432
+ "null": {},
433
+ "\"0\"": {value: makeStringPointer("0")},
434
+ `"1"`: {value: makeStringPointer("1")},
435
+ `"-1"`: {value: makeStringPointer("-1")},
436
+ `"qwerty"`: {value: makeStringPointer("qwerty")},
437
+ } {
438
+ var d OptionalString
439
+ err := json.Unmarshal([]byte(jsonStr), &d)
440
+ if err != nil {
441
+ t.Fatal(err)
442
+ }
443
+
444
+ if goValue.value == nil && d.value == nil {
445
+ } else if goValue.value == nil && d.value != nil {
446
+ t.Errorf("expected default, got %s", d)
447
+ } else if *d.value != *goValue.value {
448
+ t.Fatalf("expected %s, got %s", goValue, d)
449
+ }
450
+
451
+ // Reverse
452
+ out, err := json.Marshal(goValue)
453
+ if err != nil {
454
+ t.Fatal(err)
455
+ }
456
+ if string(out) != jsonStr {
457
+ t.Fatalf("expected %s, got %s", jsonStr, string(out))
458
+ }
459
+ }
460
+
461
+ // marshal with omitempty
462
+ type Foo struct {
463
+ S *OptionalString `json:",omitempty"`
464
+ }
465
+ out, err := json.Marshal(new(Foo))
466
+ if err != nil {
467
+ t.Fatal(err)
468
+ }
469
+ expected := "{}"
470
+ if string(out) != expected {
471
+ t.Fatal("expected omitempty to omit the optional integer")
472
+ }
473
+ // unmarshal from omitempty output and get default value
474
+ var foo2 Foo
475
+ if err := json.Unmarshal(out, &foo2); err != nil {
476
+ t.Fatalf("%s failed to unmarshall with %s", string(out), err)
477
+ }
478
+ if s := foo2.S.WithDefault("foo"); s != "foo" {
479
+ t.Fatalf("expected default value to be used, got %s", s)
480
+ }
481
+ if !foo2.S.IsDefault() {
482
+ t.Fatal("expected value to be the default")
483
+ }
484
+
485
+ for _, invalid := range []string{
486
+ "[]", "{}", "0", "a", "'b'",
487
+ } {
488
+ var p OptionalString
489
+ err := json.Unmarshal([]byte(invalid), &p)
490
+ if err == nil {
491
+ t.Errorf("expected to fail to decode %s as an optional string", invalid)
492
+ }
493
+ }
494
+}