diff --git a/constraint.go b/constraint.go index d055759..2f31787 100644 --- a/constraint.go +++ b/constraint.go @@ -1,6 +1,7 @@ package version import ( + "encoding/json" "fmt" "reflect" "regexp" @@ -202,3 +203,24 @@ func constraintPessimistic(v, c *Version) bool { // If nothing has rejected the version by now, it's valid return true } + +// MarshalJSON implements the json.Marshaler interface +func (c *Constraints) MarshalJSON() ([]byte, error) { + return json.Marshal(c.String()) +} + +// UnmarshalJSON implements the json.Unmarshaler interface +func (c *Constraints) UnmarshalJSON(data []byte) error { + var csStr string + if err := json.Unmarshal(data, &csStr); err != nil { + return err + } + + nc, err := NewConstraint(csStr) + if err != nil { + return err + } + *c = nc + + return nil +} diff --git a/constraint_test.go b/constraint_test.go index 9c5bee3..34286d0 100644 --- a/constraint_test.go +++ b/constraint_test.go @@ -1,6 +1,7 @@ package version import ( + "encoding/json" "testing" ) @@ -124,3 +125,58 @@ func TestConstraintsString(t *testing.T) { } } } + +func TestConstraintsMarshalJSON(t *testing.T) { + cases := []struct { + constraint string + result string + }{ + {">= 1.0, < 1.2", `"\u003e= 1.0, \u003c 1.2"`}, + {"~> 1.0.7", `"~\u003e 1.0.7"`}, + } + + for _, tc := range cases { + c, err := NewConstraint(tc.constraint) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual, err := json.Marshal(&c) + if err != nil { + t.Fatalf("err: %s", err) + } + + expected := tc.result + if string(actual) != expected { + t.Fatalf("Constraint: %s\nExpected: %s\nActual: %s", + tc.constraint, expected, actual) + } + } +} + +func TestConstraintsUnmarshalJSON(t *testing.T) { + cases := []struct { + constraint string + result string + }{ + {`">= 1.0, < 1.2"`, ">= 1.0, < 1.2"}, + {`"~> 1.0.7"`, "~> 1.0.7"}, + } + + for _, tc := range cases { + var actual Constraints + if err := json.Unmarshal([]byte(tc.constraint), &actual); err != nil { + t.Fatalf("err: %s", err) + } + + expected, err := NewConstraint(tc.result) + if err != nil { + t.Fatalf("err: %s", err) + } + + if actual.String() != expected.String() { + t.Fatalf("Constraint: %s\nExpected: %s\nActual: %s", + tc.result, expected, actual) + } + } +} diff --git a/version.go b/version.go index 8068834..a222cc7 100644 --- a/version.go +++ b/version.go @@ -2,6 +2,7 @@ package version import ( "bytes" + "encoding/json" "fmt" "reflect" "regexp" @@ -390,3 +391,24 @@ func (v *Version) String() string { func (v *Version) Original() string { return v.original } + +// MarshalJSON implements the json.Marshaler interface +func (v *Version) MarshalJSON() ([]byte, error) { + return json.Marshal(v.original) +} + +// UnmarshalJSON implements the json.Unmarshaler interface +func (v *Version) UnmarshalJSON(data []byte) error { + var vStr string + if err := json.Unmarshal(data, &vStr); err != nil { + return err + } + + nv, err := NewVersion(vStr) + if err != nil { + return err + } + *v = *nv + + return nil +} diff --git a/version_test.go b/version_test.go index 9fa34f6..e59ea35 100644 --- a/version_test.go +++ b/version_test.go @@ -1,6 +1,7 @@ package version import ( + "encoding/json" "reflect" "testing" ) @@ -654,3 +655,58 @@ func TestLessThanOrEqual(t *testing.T) { } } } + +func TestVersionMarshalJSON(t *testing.T) { + cases := []struct { + version string + result string + }{ + {"1.7rc2", `"1.7rc2"`}, + {"1.2.0", `"1.2.0"`}, + } + + for _, tc := range cases { + v, err := NewVersion(tc.version) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual, err := json.Marshal(&v) + if err != nil { + t.Fatalf("err: %s", err) + } + + expected := tc.result + if string(actual) != expected { + t.Fatalf("Version: %s\nExpected: %s\nActual: %s", + tc.version, expected, actual) + } + } +} + +func TestVersionUnmarshalJSON(t *testing.T) { + cases := []struct { + version string + result string + }{ + {`"1.7rc2"`, "1.7rc2"}, + {`"1.2.0"`, "1.2.0"}, + } + + for _, tc := range cases { + var actual Version + if err := json.Unmarshal([]byte(tc.version), &actual); err != nil { + t.Fatalf("err: %s", err) + } + + expected, err := NewVersion(tc.result) + if err != nil { + t.Fatalf("err: %s", err) + } + + if !reflect.DeepEqual(&actual, expected) { + t.Fatalf("Constraint: %s\nExpected: %#v\nActual: %#v", + tc.result, expected, actual) + } + } +}