initial commits
parent
a9b529016b
commit
cef52f3630
|
@ -0,0 +1,14 @@
|
|||
package jsonstr
|
||||
|
||||
import (
|
||||
"sourcecode.social/reiver/go-erorr"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrNotJSONArrayOfString = erorr.Error("jsonstr: not JSON array of strings")
|
||||
)
|
||||
|
||||
const (
|
||||
errNilReceiver = erorr.Error("jsonstr: nil receiver")
|
||||
errNilData = erorr.Error("jsonstr: nil data")
|
||||
)
|
|
@ -0,0 +1,100 @@
|
|||
package jsonstr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var _ json.Marshaler = Strings{}
|
||||
var _ json.Unmarshaler = new(Strings)
|
||||
|
||||
// Strings represents a JSON array of strings.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// var strings jsonstr.Strings
|
||||
//
|
||||
// // ...
|
||||
//
|
||||
// jason := []byte(`["once", "twice", "thrice", "fource"]`)
|
||||
//
|
||||
// err := json.Unmarshal(jason, &strings)
|
||||
type Strings struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func Compile(a ...string) Strings {
|
||||
if len(a) <= 0 {
|
||||
return Strings{
|
||||
value:"[]",
|
||||
}
|
||||
}
|
||||
|
||||
// This should not return an error, since this is a []string.
|
||||
p, _ := json.Marshal(a)
|
||||
|
||||
return Strings{
|
||||
value: string(p),
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver Strings) Decompile() []string {
|
||||
if "" == receiver.value {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
var ss []string
|
||||
json.Unmarshal([]byte(receiver.value), &ss)
|
||||
if nil == ss {
|
||||
ss = []string{}
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
var emptyJSONArray []byte = []byte{'[',']'}
|
||||
|
||||
func (receiver Strings) MarshalJSON() ([]byte, error) {
|
||||
if "" == receiver.value {
|
||||
return emptyJSONArray, nil
|
||||
}
|
||||
|
||||
return []byte(receiver.value), nil
|
||||
}
|
||||
|
||||
func (receiver *Strings) UnmarshalJSON(data []byte) error {
|
||||
if nil == receiver {
|
||||
return errNilReceiver
|
||||
}
|
||||
if nil == data {
|
||||
return errNilData
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
{
|
||||
|
||||
if err := json.Compact(&buffer, data); nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s := buffer.String()
|
||||
|
||||
if "[]" == s {
|
||||
receiver.value = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
{
|
||||
validated, err := validate(buffer.Bytes())
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
if !validated {
|
||||
return ErrNotJSONArrayOfString
|
||||
}
|
||||
}
|
||||
|
||||
receiver.value = s
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package jsonstr_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"sourcecode.social/reiver/go-jsonstr"
|
||||
)
|
||||
|
||||
func TestString_MarshalJSON(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Strings jsonstr.Strings
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
Strings: jsonstr.Strings{},
|
||||
Expected: `[]`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Strings: jsonstr.Compile("apple"),
|
||||
Expected: `["apple"]`,
|
||||
},
|
||||
{
|
||||
Strings: jsonstr.Compile("apple", "banana"),
|
||||
Expected: `["apple","banana"]`,
|
||||
},
|
||||
{
|
||||
Strings: jsonstr.Compile("apple", "banana", "cherry"),
|
||||
Expected: `["apple","banana","cherry"]`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Strings: jsonstr.Compile("😈"),
|
||||
Expected: `["😈"]`,
|
||||
},
|
||||
{
|
||||
Strings: jsonstr.Compile("😈", "🙂🙁"),
|
||||
Expected: `["😈","🙂🙁"]`,
|
||||
},
|
||||
{
|
||||
Strings: jsonstr.Compile("😈", "🙂🙁", ""),
|
||||
Expected: `["😈","🙂🙁",""]`,
|
||||
},
|
||||
{
|
||||
Strings: jsonstr.Compile("😈", "🙂🙁", "", "٠١٢٣۴۵۶٧٨٩"),
|
||||
Expected: `["😈","🙂🙁","","٠١٢٣۴۵۶٧٨٩"]`,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
actualBytes, err := json.Marshal(test.Strings)
|
||||
if nil != err {
|
||||
t.Errorf("For test #%d, did not expect an error but actually got one.", testNumber)
|
||||
t.Logf("ERROR: (%T) %s", err, err)
|
||||
t.Logf("STRINGS: %#v", test.Strings)
|
||||
t.Logf("EXPECTED: %#v", test.Expected)
|
||||
continue
|
||||
}
|
||||
|
||||
{
|
||||
actual := string(actualBytes)
|
||||
expected := test.Expected
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual marshaled value is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED: %s", expected)
|
||||
t.Logf("ACTUAL: %s", actual)
|
||||
t.Logf("STRINGS: %#v", test.Strings)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
package jsonstr_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"sourcecode.social/reiver/go-jsonstr"
|
||||
)
|
||||
|
||||
func TestString_UnmarshalJSON(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
JSON string
|
||||
Expected jsonstr.Strings
|
||||
}{
|
||||
{
|
||||
JSON: `[]`,
|
||||
Expected: jsonstr.Strings{},
|
||||
},
|
||||
{
|
||||
JSON: `[ ]`,
|
||||
Expected: jsonstr.Strings{},
|
||||
},
|
||||
{
|
||||
JSON: `[ ]`,
|
||||
Expected: jsonstr.Strings{},
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
JSON: `["apple"]`,
|
||||
Expected: jsonstr.Compile("apple"),
|
||||
},
|
||||
{
|
||||
JSON: `["apple","banana"]`,
|
||||
Expected: jsonstr.Compile("apple","banana"),
|
||||
},
|
||||
{
|
||||
JSON: `["apple","banana","cherry"]`,
|
||||
Expected: jsonstr.Compile("apple","banana","cherry"),
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
JSON: `["😈"]`,
|
||||
Expected: jsonstr.Compile("😈"),
|
||||
},
|
||||
{
|
||||
JSON: `["😈","🙂🙁"]`,
|
||||
Expected: jsonstr.Compile("😈","🙂🙁"),
|
||||
},
|
||||
{
|
||||
JSON: `["😈","🙂🙁",""]`,
|
||||
Expected: jsonstr.Compile("😈","🙂🙁",""),
|
||||
},
|
||||
{
|
||||
JSON: `["😈","🙂🙁","","٠١٢٣۴۵۶٧٨٩"]`,
|
||||
Expected: jsonstr.Compile("😈","🙂🙁","","٠١٢٣۴۵۶٧٨٩"),
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
JSON: `["1","two", "THREE", "iv", "۵"]`,
|
||||
Expected: jsonstr.Compile("1","two", "THREE", "iv", "۵"),
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
var actual jsonstr.Strings
|
||||
|
||||
err := json.Unmarshal([]byte(test.JSON), &actual)
|
||||
if nil != err {
|
||||
t.Errorf("For test #%d, did not expect an error but actually got one.", testNumber)
|
||||
t.Logf("ERROR: (%T) %s", err, err)
|
||||
t.Logf("JSON: %#v", test.JSON)
|
||||
t.Logf("EXPECTED: %#v", test.Expected)
|
||||
continue
|
||||
}
|
||||
|
||||
{
|
||||
expected := test.Expected
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual marshaled value is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED: %#v", expected)
|
||||
t.Logf("ACTUAL: %#v", actual)
|
||||
t.Logf("JSON: %#v", test.JSON)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestString_UnmarshalJSON_fail(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
JSON string
|
||||
}{
|
||||
{
|
||||
JSON: `{}`,
|
||||
},
|
||||
{
|
||||
JSON: `{"name":"value"}`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
JSON: `false`,
|
||||
},
|
||||
{
|
||||
JSON: `true`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
JSON: `-2.223`,
|
||||
},
|
||||
{
|
||||
JSON: `-1`,
|
||||
},
|
||||
{
|
||||
JSON: `0`,
|
||||
},
|
||||
{
|
||||
JSON: `11`,
|
||||
},
|
||||
{
|
||||
JSON: `222.22`,
|
||||
},
|
||||
{
|
||||
JSON: `3333`,
|
||||
},
|
||||
{
|
||||
JSON: `44444`,
|
||||
},
|
||||
{
|
||||
JSON: `5.0`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
JSON: `[false]`,
|
||||
},
|
||||
{
|
||||
JSON: `[false, true]`,
|
||||
},
|
||||
{
|
||||
JSON: `[false, false, false, false, true, true, true, false]`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
JSON: `["hello", 1, "wow", true, -3.2, "world"]`,
|
||||
},
|
||||
|
||||
{
|
||||
JSON: `["once","twice","thrice","fource",5]`,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
var actual jsonstr.Strings
|
||||
|
||||
err := json.Unmarshal([]byte(test.JSON), &actual)
|
||||
if nil == err {
|
||||
t.Errorf("For test #%d, expected an error but did not actually get one.", testNumber)
|
||||
t.Logf("JSON: %#v", test.JSON)
|
||||
continue
|
||||
}
|
||||
|
||||
{
|
||||
expected := jsonstr.ErrNotJSONArrayOfString
|
||||
actual := err
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual error is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED ERROR: (%T) %s", expected, expected)
|
||||
t.Logf("ACTUAL ERROR: (%T) %s", actual, actual)
|
||||
t.Logf("JSON: %#v", test.JSON)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package jsonstr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func validate(data []byte) (bool, error) {
|
||||
if nil == data {
|
||||
return false, errNilData
|
||||
}
|
||||
|
||||
var ss []string
|
||||
|
||||
err := json.Unmarshal(data, &ss)
|
||||
if nil != err {
|
||||
switch err.(type) {
|
||||
case *json.UnmarshalTypeError:
|
||||
return false, nil
|
||||
default:
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
Loading…
Reference in New Issue