1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
|
package tests
import (
"reflect"
"testing"
"unsafe"
"github.com/mailru/easyjson"
)
// verifies if string pointer belongs to the given buffer or outside of it
func strBelongsTo(s string, buf []byte) bool {
sPtr := (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
bufPtr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)).Data
if bufPtr <= sPtr && sPtr < bufPtr+uintptr(len(buf)) {
return true
}
return false
}
func TestNocopy(t *testing.T) {
data := []byte(`{"a": "valueA", "b": "valueB"}`)
exp := NocopyStruct{
A: "valueA",
B: "valueB",
}
res := NocopyStruct{}
err := easyjson.Unmarshal(data, &res)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(exp, res) {
t.Errorf("TestNocopy(): got=%+v, exp=%+v", res, exp)
}
if strBelongsTo(res.A, data) {
t.Error("TestNocopy(): field A was not copied and refers to buffer")
}
if !strBelongsTo(res.B, data) {
t.Error("TestNocopy(): field B was copied rather than refer to bufferr")
}
data = []byte(`{"b": "valueNoCopy"}`)
res = NocopyStruct{}
allocsPerRun := testing.AllocsPerRun(1000, func() {
err := easyjson.Unmarshal(data, &res)
if err != nil {
t.Error(err)
}
if res.B != "valueNoCopy" {
t.Fatalf("wrong value: %q", res.B)
}
})
if allocsPerRun > 1 {
t.Fatalf("noCopy field unmarshal: expected <= 1 allocs, got %f", allocsPerRun)
}
data = []byte(`{"a": "valueNoCopy"}`)
allocsPerRun = testing.AllocsPerRun(1000, func() {
err := easyjson.Unmarshal(data, &res)
if err != nil {
t.Error(err)
}
if res.A != "valueNoCopy" {
t.Fatalf("wrong value: %q", res.A)
}
})
if allocsPerRun > 2 {
t.Fatalf("copy field unmarshal: expected <= 2 allocs, got %f", allocsPerRun)
}
}
|