Created
February 19, 2020 23:01
-
-
Save packrat386/b1afed8aa6dc1f66ef0db43cb999aa41 to your computer and use it in GitHub Desktop.
A map that errors out if you attempt to marshal JSON with duplicate keys
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package wat | |
import ( | |
"bytes" | |
"encoding/json" | |
"fmt" | |
) | |
type noDupMap map[string]string | |
func (n *noDupMap) UnmarshalJSON(b []byte) error { | |
*n = map[string]string{} | |
fmt.Println(string(b)) | |
dec := json.NewDecoder(bytes.NewBuffer(b)) | |
tok, err := dec.Token() | |
if err != nil { | |
return err | |
} | |
d, ok := tok.(json.Delim) | |
if !ok { | |
return fmt.Errorf("didn't get a delimiter") | |
} | |
if d.String() != "{" { | |
return fmt.Errorf("expected '{', got: %s", d.String()) | |
} | |
for { | |
tok, err := dec.Token() | |
if err != nil { | |
return err | |
} | |
if d, ok := tok.(json.Delim); ok { | |
if d.String() != "}" { | |
return fmt.Errorf("expected '}', got: %s", d.String()) | |
} | |
break | |
} | |
k, ok := tok.(string) | |
if !ok { | |
fmt.Errorf("expected string, got: '%s'", tok) | |
} | |
if _, ok := (*n)[k]; ok { | |
return fmt.Errorf("duplicate key: %s", k) | |
} | |
var v string | |
err = dec.Decode(&v) | |
if err != nil { | |
return fmt.Errorf("error reading value: %w", err) | |
} | |
(*n)[k] = v | |
} | |
if dec.More() { | |
return fmt.Errorf("too much input") | |
} | |
return nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package wat | |
import ( | |
"encoding/json" | |
"fmt" | |
"testing" | |
) | |
func TestDedup(t *testing.T) { | |
input := `{"foo":"a", "bar":"b", "foo":"c"}` | |
var n noDupMap | |
err := json.Unmarshal([]byte(input), &n) | |
fmt.Println(n) | |
fmt.Println(err) | |
if err == nil { | |
t.Fatal("should have errored") | |
} | |
} | |
func TestWorks(t *testing.T) { | |
input := `{"foo":"a", "bar":"b"}` | |
var n noDupMap | |
err := json.Unmarshal([]byte(input), &n) | |
fmt.Println(n) | |
fmt.Println(err) | |
if err != nil { | |
t.Fatalf("done broke: %s", err.Error()) | |
} | |
} | |
func TestBad(t *testing.T) { | |
input := `{"foo":"a", "a":1}` | |
var n noDupMap | |
err := json.Unmarshal([]byte(input), &n) | |
fmt.Println(n) | |
fmt.Println(err) | |
if err == nil { | |
t.Fatal("should have errored") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment