@cryptotaxi247 / kubo / commits / cdaa222b2

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 +}