diff --git a/version.go b/version.go index 116a744..fd1a873 100644 --- a/version.go +++ b/version.go @@ -2,6 +2,7 @@ package version import ( "bytes" + "encoding/json" "fmt" "reflect" "regexp" @@ -388,3 +389,26 @@ func (v *Version) String() string { func (v *Version) Original() string { return v.original } + +// UnmarshalJSON implements JSON.Unmarshaler interface. +func (v *Version) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + temp, err := NewVersion(s) + if err != nil { + return err + } + v.metadata = temp.metadata + v.pre = temp.pre + v.segments = temp.segments + v.si = temp.si + v.original = temp.original + return nil +} + +// MarshalJSON implements JSON.Marshaler interface. +func (v Version) MarshalJSON() ([]byte, error) { + return json.Marshal(v.String()) +} diff --git a/version_test.go b/version_test.go index 9fa34f6..08cbf01 100644 --- a/version_test.go +++ b/version_test.go @@ -1,6 +1,8 @@ package version import ( + "encoding/json" + "fmt" "reflect" "testing" ) @@ -21,13 +23,13 @@ func TestNewVersion(t *testing.T) { {"1.2-beta.5", false}, {"\n1.2", true}, {"1.2.0-x.Y.0+metadata", false}, - {"1.2.0-x.Y.0+metadata-width-hypen", false}, - {"1.2.3-rc1-with-hypen", false}, + {"1.2.0-x.Y.0+metadata-width-hyphen", false}, + {"1.2.3-rc1-with-hyphen", false}, {"1.2.3.4", false}, {"1.2.0.4-x.Y.0+metadata", false}, - {"1.2.0.4-x.Y.0+metadata-width-hypen", false}, + {"1.2.0.4-x.Y.0+metadata-width-hyphen", false}, {"1.2.0-X-1.2.0+metadata~dist", false}, - {"1.2.3.4-rc1-with-hypen", false}, + {"1.2.3.4-rc1-with-hyphen", false}, {"1.2.3.4", false}, {"v1.2.3", false}, {"foo1.2.3", true}, @@ -62,13 +64,13 @@ func TestNewSemver(t *testing.T) { {"1.2-beta.5", false}, {"\n1.2", true}, {"1.2.0-x.Y.0+metadata", false}, - {"1.2.0-x.Y.0+metadata-width-hypen", false}, - {"1.2.3-rc1-with-hypen", false}, + {"1.2.0-x.Y.0+metadata-width-hyphen", false}, + {"1.2.3-rc1-with-hyphen", false}, {"1.2.3.4", false}, {"1.2.0.4-x.Y.0+metadata", false}, - {"1.2.0.4-x.Y.0+metadata-width-hypen", false}, + {"1.2.0.4-x.Y.0+metadata-width-hyphen", false}, {"1.2.0-X-1.2.0+metadata~dist", false}, - {"1.2.3.4-rc1-with-hypen", false}, + {"1.2.3.4-rc1-with-hyphen", false}, {"1.2.3.4", false}, {"v1.2.3", false}, {"foo1.2.3", true}, @@ -393,6 +395,75 @@ func TestVersionSegments64(t *testing.T) { } } +func TestJsonMarshal(t *testing.T) { + cases := []struct { + version string + err bool + }{ + {"1.2.3", false}, + {"1.2.0-x.Y.0+metadata", false}, + {"1.2.0-x.Y.0+metadata-width-hyphen", false}, + {"1.2.3-rc1-with-hyphen", false}, + {"1.2.3.4", false}, + {"1.2.0.4-x.Y.0+metadata", false}, + {"1.2.0.4-x.Y.0+metadata-width-hyphen", false}, + {"1.2.0-X-1.2.0+metadata~dist", false}, + {"1.2.3.4-rc1-with-hyphen", false}, + {"1.2.3.4", false}, + } + + for _, tc := range cases { + v, err1 := NewVersion(tc.version) + if err1 != nil { + t.Fatalf("error for version %q: %s", tc.version, err1) + } + + parsed, err2 := json.Marshal(v) + if err2 != nil { + t.Fatalf("error marshaling version %q: %s", tc.version, err2) + } + result := string(parsed) + expected := fmt.Sprintf("%q", tc.version) + if result != expected && !tc.err { + t.Fatalf("Error marshaling unexpected marshaled content: result=%q expected=%q", result, expected) + } + } +} + +func TestJsonUnmarshal(t *testing.T) { + cases := []struct { + version string + err bool + }{ + {"1.2.3", false}, + {"1.2.0-x.Y.0+metadata", false}, + {"1.2.0-x.Y.0+metadata-width-hyphen", false}, + {"1.2.3-rc1-with-hyphen", false}, + {"1.2.3.4", false}, + {"1.2.0.4-x.Y.0+metadata", false}, + {"1.2.0.4-x.Y.0+metadata-width-hyphen", false}, + {"1.2.0-X-1.2.0+metadata~dist", false}, + {"1.2.3.4-rc1-with-hyphen", false}, + {"1.2.3.4", false}, + } + + for _, tc := range cases { + expected, err1 := NewVersion(tc.version) + if err1 != nil { + t.Fatalf("err: %s", err1) + } + + actual := &Version{} + err2 := json.Unmarshal([]byte(fmt.Sprintf("%q", tc.version)), actual) + if err2 != nil { + t.Fatalf("error unmarshaling version: %s", err2) + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("error unmarshaling, unexpected object content: actual=%q expected=%q", actual, expected) + } + } +} + func TestVersionString(t *testing.T) { cases := [][]string{ {"1.2.3", "1.2.3"},