diff --git a/constraints.go b/constraints.go index 547613f..7bb62ac 100644 --- a/constraints.go +++ b/constraints.go @@ -2,6 +2,7 @@ package semver import ( "bytes" + "encoding/json" "errors" "fmt" "regexp" @@ -134,6 +135,33 @@ func (cs Constraints) String() string { return strings.Join(buf, " || ") } +// UnmarshalJSON implements JSON.Unmarshaler interface. +func (cs *Constraints) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + temp, err := NewConstraint(s) + if err != nil { + return err + } + *cs = *temp + return nil +} + +// MarshalJSON implements JSON.Marshaler interface. +func (cs Constraints) MarshalJSON() ([]byte, error) { + // we need our own encoder so we don't escape '<' and '>' which json.Marshal does + buf := new(bytes.Buffer) + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(false) + + if err := enc.Encode(cs.String()); err != nil { + return nil, err + } + return bytes.TrimRight(buf.Bytes(), "\n"), nil +} + var constraintOps map[string]cfunc var constraintRegex *regexp.Regexp var constraintRangeRegex *regexp.Regexp diff --git a/constraints_test.go b/constraints_test.go index 0504399..0820c09 100644 --- a/constraints_test.go +++ b/constraints_test.go @@ -1,6 +1,9 @@ package semver import ( + "bytes" + "encoding/json" + "fmt" "reflect" "testing" ) @@ -664,3 +667,56 @@ func TestConstraintString(t *testing.T) { } } } + +func TestJsonMarshalConstraints(t *testing.T) { + tests := []struct { + sCs string + want string + }{ + {"1.1.1", "1.1.1"}, + {">=1.1.1", ">=1.1.1"}, + {"<=1.1.1", "<=1.1.1"}, + } + + for _, tc := range tests { + cs, err := NewConstraint(tc.sCs) + if err != nil { + t.Errorf("Error creating constraints: %s", err) + } + buf := new(bytes.Buffer) + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(false) + err = enc.Encode(cs) + if err != nil { + t.Errorf("Error unmarshaling version: %s", err) + } + got := buf.String() + want := fmt.Sprintf("%q\n", tc.want) + if got != want { + t.Errorf("Error marshaling unexpected marshaled content: got=%q want=%q", got, want) + } + } +} + +func TestJsonUnmarshalConstraints(t *testing.T) { + tests := []struct { + sCs string + want string + }{ + {"1.1.1", "1.1.1"}, + {">=1.2.3", ">=1.2.3"}, + {"<=1.2.3", "<=1.2.3"}, + } + + for _, tc := range tests { + cs := Constraints{} + err := json.Unmarshal([]byte(fmt.Sprintf("%q", tc.sCs)), &cs) + if err != nil { + t.Errorf("Error unmarshaling constraints: %s", err) + } + got := cs.String() + if got != tc.want { + t.Errorf("Error unmarshaling unexpected object content: got=%q want=%q", got, tc.want) + } + } +}