initial commits

master
Charles Iliya Krempeaux 2023-09-27 09:12:51 +09:00
parent a9b529016b
commit cef52f3630
5 changed files with 414 additions and 0 deletions

14
errors.go 100644
View File

@ -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")
)

100
strings.go 100644
View File

@ -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
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

25
validate.go 100644
View File

@ -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
}