Skip to content

Commit

Permalink
[*] fix: Issue #29
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew-M-C committed Mar 22, 2024
1 parent b2d9505 commit 68a49c4
Show file tree
Hide file tree
Showing 16 changed files with 247 additions and 56 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go_1.16_above.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
max-parallel: 6
matrix:
GO_VER: ['1.16', '1.17', '1.18', '1.19', '1.20', '1.21']
GO_VER: ['1.16', '1.17', '1.18', '1.19', '1.20', '1.21', '1.22']
HOST_OS: ['ubuntu-latest', 'macos-latest']

runs-on: ${{ matrix.HOST_OS }}
Expand Down
6 changes: 3 additions & 3 deletions equal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func testEqual(t *testing.T) {
cv("test array type", func() { testEqualArray(t) })
}

func testEqualSimpleTypes(t *testing.T) {
func testEqualSimpleTypes(*testing.T) {
cv("invalid type", func() {
var v1, v2 *V
so(v1.Equal(v2), isFalse)
Expand Down Expand Up @@ -89,7 +89,7 @@ func testEqualNumbers(t *testing.T) {
})
}

func testEqualObject(t *testing.T) {
func testEqualObject(*testing.T) {
cv("general", func() {
v1 := MustUnmarshalString(`{"obj":{},"arr":[]}`)
v2 := MustUnmarshalString(`{"arr":[],"obj":{}}`)
Expand All @@ -113,7 +113,7 @@ func testEqualObject(t *testing.T) {
})
}

func testEqualArray(t *testing.T) {
func testEqualArray(*testing.T) {
cv("general", func() {
v1 := MustUnmarshalString(`[1,2,3,4]`)
v2 := MustUnmarshalString(`[1,2,3,4.0]`)
Expand Down
6 changes: 3 additions & 3 deletions get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func testJsonvalue_Get(t *testing.T) {
})
}

func testMiscError(t *testing.T) {
func testMiscError(*testing.T) {
var err error
raw := `{"array":[0,1,2,3],"string":"hello, world","number":1234.12345}`
v, err := UnmarshalString(raw)
Expand Down Expand Up @@ -422,7 +422,7 @@ func testCaselessGet(t *testing.T) {
so(sub.ValueType(), eq, NotExist)
}

func testNotExistGet(t *testing.T) {
func testNotExistGet(*testing.T) {
cv("unmarshal a not exist V", func() {
v := MustUnmarshalString("blahblah")
so(v, notNil)
Expand All @@ -449,7 +449,7 @@ func testNotExistGet(t *testing.T) {
})
}

func testGetNumFromString(t *testing.T) {
func testGetNumFromString(*testing.T) {
cv("invalid number", func() {
v := MustUnmarshalString(`{"num":"abcde","bool":true}`)

Expand Down
12 changes: 12 additions & 0 deletions import_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func validateValAndReturnParser(v reflect.Value, ex ext) (out reflect.Value, fu

// json.Marshaler and encoding.TextMarshaler
if o, f := checkAndParseMarshaler(v); f != nil {
// jsonvalue itself
if _, ok := v.Interface().(deepCopier); ok {
return out, parseJSONValueDeepCopier, nil
}
return o, f, nil
}

Expand Down Expand Up @@ -186,6 +190,14 @@ func getPointerOfValue(v reflect.Value) reflect.Value {
return vp
}

func parseJSONValueDeepCopier(v reflect.Value, ex ext) (*V, error) {
if v.IsNil() {
return nil, nil // empty
}
j, _ := v.Interface().(deepCopier)
return j.deepCopy(), nil
}

func parseJSONMarshaler(v reflect.Value, ex ext) (*V, error) {
if v.Kind() == reflect.Ptr && v.IsNil() {
return nil, nil // empty
Expand Down
35 changes: 17 additions & 18 deletions import_export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func testImportExport(t *testing.T) {
cv("test miscellaneous anonymous situations", func() { testImportMiscAnonymous(t) })
}

func testExportString(t *testing.T) {
func testExportString(*testing.T) {
const S = "Hello, jsonvalue!"
v := NewString(S)

Expand All @@ -49,7 +49,7 @@ func testExportString(t *testing.T) {
so(err, isErr)
}

func testExportInt(t *testing.T) {
func testExportInt(*testing.T) {
const positive = 123454321
const negative = -987656789

Expand Down Expand Up @@ -95,7 +95,7 @@ func testExportInt(t *testing.T) {
so(err, isErr)
}

func testExportFloat(t *testing.T) {
func testExportFloat(*testing.T) {
const F = 12345.4321

n := NewFloat64(F)
Expand All @@ -118,7 +118,7 @@ func testExportFloat(t *testing.T) {
so(err, isErr)
}

func testExportBool(t *testing.T) {
func testExportBool(*testing.T) {
v := NewBool(true)
b := false

Expand All @@ -135,9 +135,8 @@ func testExportBool(t *testing.T) {
so(err, isErr)
}

func testImport(t *testing.T) {
func testImport(*testing.T) {
cv("integers", func() {

params := []any{
int(1),
uint(2),
Expand Down Expand Up @@ -927,7 +926,7 @@ func (m *customizedZeroJSONMarshaler) MarshalJSON() (b []byte, _ error) {
return
}

func testStructConv_Import_TextMarshaler(t *testing.T) {
func testStructConv_Import_TextMarshaler(*testing.T) {
cv("legal customized encoding.TextMarshaler", func() {
m := &customizedTextMarshaler{}
m.str = "Hello, text!"
Expand Down Expand Up @@ -995,7 +994,7 @@ func (m *customizedTextMarshaler) MarshalText() ([]byte, error) {
return []byte(m.str), nil
}

func testImportBugIssue19(t *testing.T) {
func testImportBugIssue19(*testing.T) {
type req struct {
IDs []uint64 `json:"ids,omitempty"`
}
Expand Down Expand Up @@ -1046,7 +1045,7 @@ func testImportMiscAnonymous(t *testing.T) {
cv("misc marshaler types", func() { testImportExportMiscMarshalerTypes(t) })
}

func testImportMiscAnonymousStructPtrInStruct(t *testing.T) {
func testImportMiscAnonymousStructPtrInStruct(*testing.T) {
type inner struct {
Name string
}
Expand All @@ -1069,7 +1068,7 @@ func testImportMiscAnonymousStructPtrInStruct(t *testing.T) {
so(s, eq, `{"Name":"Andrew","Age":20}`)
}

func testImportMiscEmptyAnonymousStructPtrInStruct(t *testing.T) {
func testImportMiscEmptyAnonymousStructPtrInStruct(*testing.T) {
type inner struct {
Name string
}
Expand All @@ -1090,7 +1089,7 @@ func testImportMiscEmptyAnonymousStructPtrInStruct(t *testing.T) {
so(s, eq, `{"Age":20}`)
}

func testImportMiscAnonymousExportableBasicTypeInStruct(t *testing.T) {
func testImportMiscAnonymousExportableBasicTypeInStruct(*testing.T) {
type Name string
type Age int
type Gender string
Expand All @@ -1117,7 +1116,7 @@ func testImportMiscAnonymousExportableBasicTypeInStruct(t *testing.T) {
so(s, eq, `{"Name":"Andrew","Age":20}`)
}

func testImportMiscAnonymousExportableBasicTypeInStructWithTags(t *testing.T) {
func testImportMiscAnonymousExportableBasicTypeInStructWithTags(*testing.T) {
type Name string
type Age int

Expand All @@ -1141,7 +1140,7 @@ func testImportMiscAnonymousExportableBasicTypeInStructWithTags(t *testing.T) {
so(s, eq, `{"n":"Andrew","a":20}`)
}

func testImportMiscAnonymousPrivateBasicTypeInStruct(t *testing.T) {
func testImportMiscAnonymousPrivateBasicTypeInStruct(*testing.T) {
type name string

type outer struct {
Expand All @@ -1162,7 +1161,7 @@ func testImportMiscAnonymousPrivateBasicTypeInStruct(t *testing.T) {
so(s, eq, `{"a":20}`)
}

func testImportMiscAnonymousSliceInStruct(t *testing.T) {
func testImportMiscAnonymousSliceInStruct(*testing.T) {
type Name []string
type nickname []string

Expand Down Expand Up @@ -1195,7 +1194,7 @@ func testImportMiscAnonymousSliceInStruct(t *testing.T) {
so(s, eq, `{"Name":["Andrew","M","C"],"Age":20}`)
}

func testImportMiscAnonymousArrayInStruct(t *testing.T) {
func testImportMiscAnonymousArrayInStruct(*testing.T) {
type Name [3]string

type outer struct {
Expand All @@ -1217,7 +1216,7 @@ func testImportMiscAnonymousArrayInStruct(t *testing.T) {
so(s, eq, `{"Name":["Andrew","C",""],"Age":20}`)
}

func testImportMiscAnonymousSlicePtrInStruct(t *testing.T) {
func testImportMiscAnonymousSlicePtrInStruct(*testing.T) {
type Name []string

type outer struct {
Expand Down Expand Up @@ -1249,7 +1248,7 @@ func testImportMiscAnonymousSlicePtrInStruct(t *testing.T) {
so(s, eq, `{"Name":["Andrew","M","C"],"Age":20}`)
}

func testImportMiscAnonymousInvalidTypes(t *testing.T) {
func testImportMiscAnonymousInvalidTypes(*testing.T) {
type Inner chan int
type outer struct {
Inner
Expand All @@ -1266,7 +1265,7 @@ func testImportMiscAnonymousInvalidTypes(t *testing.T) {
so(err, isErr)
}

func testImportExportMiscMarshalerTypes(t *testing.T) {
func testImportExportMiscMarshalerTypes(*testing.T) {
cv("json.Marshaler, ptr", func() {
r := &refJSONMarshaler{}
r.s = "json.Marshaler"
Expand Down
8 changes: 4 additions & 4 deletions insert_append_delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ func testMustDelete(t *testing.T) {
so(s, eq, `{"array":[1,3,4,5,6]}`)
}

func testMiscAppend(t *testing.T) {
func testMiscAppend(*testing.T) {
expected := `[true,-1,2,-3,4,-5,6,-7.7,8.8000,{},[[false],null]]`
a := NewArray()
_, _ = a.AppendBool(true).InTheBeginning()
Expand All @@ -454,7 +454,7 @@ func testMiscAppend(t *testing.T) {
so(s, eq, expected)
}

func testAppendAndAutoGeneratePath(t *testing.T) {
func testAppendAndAutoGeneratePath(*testing.T) {
expected := `{"arr":[1]}`

o := NewObject()
Expand Down Expand Up @@ -581,7 +581,7 @@ func testMiscInsert(t *testing.T) {
so(s, eq, expected)
}

func testMiscInsertError(t *testing.T) {
func testMiscInsertError(*testing.T) {
cv("not initialized", func() {
v := V{}
_, err := v.Insert(nil).After(0)
Expand Down Expand Up @@ -708,7 +708,7 @@ func testMiscAppendError(t *testing.T) {
})
}

func testMiscDeleteError(t *testing.T) {
func testMiscDeleteError(*testing.T) {
var err error
raw := `{"Hello":"world","object":{"hello":"world","object":{"int":123456}},"array":[123456]}`
v, _ := UnmarshalString(raw)
Expand Down
64 changes: 64 additions & 0 deletions jsonvalue.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,36 @@ type children struct {
lowerCaseKeys map[string]map[string]struct{}
}

func (c *children) deepCopy() children {
res := children{
incrID: c.incrID,
}

// if length or arr > 0, this must be an array type
if len(c.arr) > 0 {
for _, v := range c.arr {
res.arr = append(res.arr, v.deepCopy())
}
return res
}

// if this is an object?
if c.object != nil {
res.object = make(map[string]childWithProperty, len(c.object))
for key, item := range c.object {
res.object[key] = childWithProperty{
id: item.id,
v: item.v.deepCopy(),
}
}
}

// no need to copy lowerCaseKeys because it could be rebuild after calling
// Caseless() next time

return res
}

func (v *V) addCaselessKey(k string) {
if v.children.lowerCaseKeys == nil {
return
Expand Down Expand Up @@ -463,6 +493,40 @@ func (v *V) Bytes() []byte {
return b
}

func (v *V) deepCopy() *V {
if v == nil {
return &V{}
}

switch v.valueType {
default:
// fallthrough
// case NotExist, Unknown:
return &V{}
case String:
return NewString(v.String())
case Number:
res := new(globalPool{}, Number)
res.num = v.num
res.srcByte = v.srcByte
return res
case Object:
res := new(globalPool{}, Object)
res.children = v.children.deepCopy()
return res
case Array:
res := new(globalPool{}, Array)
res.children = v.children.deepCopy()
return res
case Null:
return NewNull()
}
}

type deepCopier interface {
deepCopy() *V
}

// String returns represented string value or the description for the jsonvalue.V
// instance if it is not a string.
//
Expand Down
Loading

0 comments on commit 68a49c4

Please sign in to comment.