Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding text marshaling and unmarshaling #190

Merged
merged 1 commit into from Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 8 additions & 19 deletions constraints.go
Expand Up @@ -2,7 +2,6 @@ package semver

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"regexp"
Expand Down Expand Up @@ -135,31 +134,21 @@ 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)
// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (cs *Constraints) UnmarshalText(text []byte) error {
temp, err := NewConstraint(string(text))
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
// MarshalText implements the encoding.TextMarshaler interface.
func (cs Constraints) MarshalText() ([]byte, error) {
return []byte(cs.String()), nil
}

var constraintOps map[string]cfunc
Expand Down
68 changes: 52 additions & 16 deletions constraints_test.go
Expand Up @@ -680,55 +680,91 @@ func TestConstraintString(t *testing.T) {
}
}

func TestJsonMarshalConstraints(t *testing.T) {
func TestTextMarshalConstraints(t *testing.T) {
tests := []struct {
sCs string
want string
constraint string
want string
}{
{"1.1.1", "1.1.1"},
{">=1.1.1", ">=1.1.1"},
{"<=1.1.1", "<=1.1.1"},
{"1.2.3", "1.2.3"},
{">=1.2.3", ">=1.2.3"},
{"<=1.2.3", "<=1.2.3"},
{"1 <=1.2.3", "1 <=1.2.3"},
{"1, <=1.2.3", "1 <=1.2.3"},
{">1, <=1.2.3", ">1 <=1.2.3"},
{"> 1 , <=1.2.3", ">1 <=1.2.3"},
}

for _, tc := range tests {
cs, err := NewConstraint(tc.sCs)
cs, err := NewConstraint(tc.constraint)
if err != nil {
t.Errorf("Error creating constraints: %s", err)
}

out, err2 := cs.MarshalText()
if err2 != nil {
t.Errorf("Error constraint version: %s", err2)
}

got := string(out)
if got != tc.want {
t.Errorf("Error marshaling constraint, unexpected marshaled content: got=%q want=%q", got, tc.want)
}

// Test that this works for JSON as well as text. When JSON marshaling
// functions are missing it falls through to TextMarshal.
// NOTE: To not escape the < and > (which json.Marshal does) you need
// a custom encoder where html escaping is disabled. This must be done
// in the top level encoder being used to marshal the constraints.
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)
t.Errorf("Error unmarshaling constraint: %s", err)
}
got := buf.String()
got = buf.String()
// The encoder used here adds a newline so we add that to what we want
// so they align. The newline is an artifact of the testing.
want := fmt.Sprintf("%q\n", tc.want)
if got != want {
t.Errorf("Error marshaling unexpected marshaled content: got=%q want=%q", got, want)
t.Errorf("Error marshaling constraint, unexpected marshaled content: got=%q want=%q", got, want)
}
}
}

func TestJsonUnmarshalConstraints(t *testing.T) {
func TestTextUnmarshalConstraints(t *testing.T) {
tests := []struct {
sCs string
want string
constraint string
want string
}{
{"1.1.1", "1.1.1"},
{"1.2.3", "1.2.3"},
{">=1.2.3", ">=1.2.3"},
{"<=1.2.3", "<=1.2.3"},
{">1 <=1.2.3", ">1 <=1.2.3"},
{"> 1 <=1.2.3", ">1 <=1.2.3"},
{">1, <=1.2.3", ">1 <=1.2.3"},
}

for _, tc := range tests {
cs := Constraints{}
err := json.Unmarshal([]byte(fmt.Sprintf("%q", tc.sCs)), &cs)
err := cs.UnmarshalText([]byte(tc.constraint))
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)
t.Errorf("Error unmarshaling constraint, unexpected object content: got=%q want=%q", got, tc.want)
}

// Test that this works for JSON as well as text. When JSON unmarshaling
// functions are missing it falls through to TextUnmarshal.
err = json.Unmarshal([]byte(fmt.Sprintf("%q", tc.constraint)), &cs)
if err != nil {
t.Errorf("Error unmarshaling constraints: %s", err)
}
got = cs.String()
if got != tc.want {
t.Errorf("Error unmarshaling constraint, unexpected object content: got=%q want=%q", got, tc.want)
}
}
}