Skip to content

Commit 3efb84c

Browse files
authored
Merge pull request #190 from mattfarina/constraints-text-marshal
Adding text marshaling and unmarshaling
2 parents 00300c4 + 3c1d0f2 commit 3efb84c

File tree

2 files changed

+60
-35
lines changed

2 files changed

+60
-35
lines changed

constraints.go

+8-19
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package semver
22

33
import (
44
"bytes"
5-
"encoding/json"
65
"errors"
76
"fmt"
87
"regexp"
@@ -135,31 +134,21 @@ func (cs Constraints) String() string {
135134
return strings.Join(buf, " || ")
136135
}
137136

138-
// UnmarshalJSON implements JSON.Unmarshaler interface.
139-
func (cs *Constraints) UnmarshalJSON(b []byte) error {
140-
var s string
141-
if err := json.Unmarshal(b, &s); err != nil {
142-
return err
143-
}
144-
temp, err := NewConstraint(s)
137+
// UnmarshalText implements the encoding.TextUnmarshaler interface.
138+
func (cs *Constraints) UnmarshalText(text []byte) error {
139+
temp, err := NewConstraint(string(text))
145140
if err != nil {
146141
return err
147142
}
143+
148144
*cs = *temp
145+
149146
return nil
150147
}
151148

152-
// MarshalJSON implements JSON.Marshaler interface.
153-
func (cs Constraints) MarshalJSON() ([]byte, error) {
154-
// we need our own encoder so we don't escape '<' and '>' which json.Marshal does
155-
buf := new(bytes.Buffer)
156-
enc := json.NewEncoder(buf)
157-
enc.SetEscapeHTML(false)
158-
159-
if err := enc.Encode(cs.String()); err != nil {
160-
return nil, err
161-
}
162-
return bytes.TrimRight(buf.Bytes(), "\n"), nil
149+
// MarshalText implements the encoding.TextMarshaler interface.
150+
func (cs Constraints) MarshalText() ([]byte, error) {
151+
return []byte(cs.String()), nil
163152
}
164153

165154
var constraintOps map[string]cfunc

constraints_test.go

+52-16
Original file line numberDiff line numberDiff line change
@@ -680,55 +680,91 @@ func TestConstraintString(t *testing.T) {
680680
}
681681
}
682682

683-
func TestJsonMarshalConstraints(t *testing.T) {
683+
func TestTextMarshalConstraints(t *testing.T) {
684684
tests := []struct {
685-
sCs string
686-
want string
685+
constraint string
686+
want string
687687
}{
688-
{"1.1.1", "1.1.1"},
689-
{">=1.1.1", ">=1.1.1"},
690-
{"<=1.1.1", "<=1.1.1"},
688+
{"1.2.3", "1.2.3"},
689+
{">=1.2.3", ">=1.2.3"},
690+
{"<=1.2.3", "<=1.2.3"},
691+
{"1 <=1.2.3", "1 <=1.2.3"},
692+
{"1, <=1.2.3", "1 <=1.2.3"},
693+
{">1, <=1.2.3", ">1 <=1.2.3"},
694+
{"> 1 , <=1.2.3", ">1 <=1.2.3"},
691695
}
692696

693697
for _, tc := range tests {
694-
cs, err := NewConstraint(tc.sCs)
698+
cs, err := NewConstraint(tc.constraint)
695699
if err != nil {
696700
t.Errorf("Error creating constraints: %s", err)
697701
}
702+
703+
out, err2 := cs.MarshalText()
704+
if err2 != nil {
705+
t.Errorf("Error constraint version: %s", err2)
706+
}
707+
708+
got := string(out)
709+
if got != tc.want {
710+
t.Errorf("Error marshaling constraint, unexpected marshaled content: got=%q want=%q", got, tc.want)
711+
}
712+
713+
// Test that this works for JSON as well as text. When JSON marshaling
714+
// functions are missing it falls through to TextMarshal.
715+
// NOTE: To not escape the < and > (which json.Marshal does) you need
716+
// a custom encoder where html escaping is disabled. This must be done
717+
// in the top level encoder being used to marshal the constraints.
698718
buf := new(bytes.Buffer)
699719
enc := json.NewEncoder(buf)
700720
enc.SetEscapeHTML(false)
701721
err = enc.Encode(cs)
702722
if err != nil {
703-
t.Errorf("Error unmarshaling version: %s", err)
723+
t.Errorf("Error unmarshaling constraint: %s", err)
704724
}
705-
got := buf.String()
725+
got = buf.String()
726+
// The encoder used here adds a newline so we add that to what we want
727+
// so they align. The newline is an artifact of the testing.
706728
want := fmt.Sprintf("%q\n", tc.want)
707729
if got != want {
708-
t.Errorf("Error marshaling unexpected marshaled content: got=%q want=%q", got, want)
730+
t.Errorf("Error marshaling constraint, unexpected marshaled content: got=%q want=%q", got, want)
709731
}
710732
}
711733
}
712734

713-
func TestJsonUnmarshalConstraints(t *testing.T) {
735+
func TestTextUnmarshalConstraints(t *testing.T) {
714736
tests := []struct {
715-
sCs string
716-
want string
737+
constraint string
738+
want string
717739
}{
718-
{"1.1.1", "1.1.1"},
740+
{"1.2.3", "1.2.3"},
719741
{">=1.2.3", ">=1.2.3"},
720742
{"<=1.2.3", "<=1.2.3"},
743+
{">1 <=1.2.3", ">1 <=1.2.3"},
744+
{"> 1 <=1.2.3", ">1 <=1.2.3"},
745+
{">1, <=1.2.3", ">1 <=1.2.3"},
721746
}
722747

723748
for _, tc := range tests {
724749
cs := Constraints{}
725-
err := json.Unmarshal([]byte(fmt.Sprintf("%q", tc.sCs)), &cs)
750+
err := cs.UnmarshalText([]byte(tc.constraint))
726751
if err != nil {
727752
t.Errorf("Error unmarshaling constraints: %s", err)
728753
}
729754
got := cs.String()
730755
if got != tc.want {
731-
t.Errorf("Error unmarshaling unexpected object content: got=%q want=%q", got, tc.want)
756+
t.Errorf("Error unmarshaling constraint, unexpected object content: got=%q want=%q", got, tc.want)
757+
}
758+
759+
// Test that this works for JSON as well as text. When JSON unmarshaling
760+
// functions are missing it falls through to TextUnmarshal.
761+
err = json.Unmarshal([]byte(fmt.Sprintf("%q", tc.constraint)), &cs)
762+
if err != nil {
763+
t.Errorf("Error unmarshaling constraints: %s", err)
764+
}
765+
got = cs.String()
766+
if got != tc.want {
767+
t.Errorf("Error unmarshaling constraint, unexpected object content: got=%q want=%q", got, tc.want)
732768
}
733769
}
734770
}

0 commit comments

Comments
 (0)