github.com/RevenueMonster/sqlike@v1.0.6/jsonb/marshal_test.go (about) 1 package jsonb 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "testing" 8 "time" 9 10 "github.com/RevenueMonster/sqlike/types" 11 "github.com/google/uuid" 12 "github.com/stretchr/testify/require" 13 "github.com/tidwall/sjson" 14 "golang.org/x/text/language" 15 ) 16 17 type longStr string 18 19 type Decimal float64 20 21 func (f Decimal) MarshalJSONB() ([]byte, error) { 22 return []byte(fmt.Sprintf(`"%.2f"`, f)), nil 23 } 24 25 type Boolean bool 26 27 func (b Boolean) MarshalJSON() ([]byte, error) { 28 if b { 29 return []byte(`"Yes"`), nil 30 } 31 return []byte(`"No"`), nil 32 } 33 34 type Text string 35 36 func (txt Text) MarshalText() ([]byte, error) { 37 return []byte(txt), nil 38 } 39 40 type normalStruct struct { 41 Str string 42 UUID uuid.UUID 43 Text Text 44 DecimalStr Decimal 45 NullDecimalStr *Decimal `sqlike:"NullableDecimal"` 46 Boolean Boolean 47 LongStr string 48 CustomStrType longStr 49 EmptyByte []byte 50 Byte []byte 51 Bool bool 52 priv int 53 Skip interface{} 54 Int int 55 TinyInt int8 56 SmallInt int16 57 MediumInt int32 58 BigInt int64 59 Uint uint 60 TinyUint uint8 61 SmallUint uint16 62 MediumUint uint32 63 BigUint uint64 64 Float32 float32 65 Float64 float64 66 UFloat32 float32 67 EmptyArray []string 68 EmptyMap map[string]interface{} 69 EmptyStruct struct{} 70 JSONRaw json.RawMessage 71 Timestamp time.Time 72 NullStr *string 73 NullCustomStrType *longStr 74 NullInt *int 75 NullTinyInt *int8 76 NullSmallInt *int16 77 NullMediumInt *int32 78 NullBigInt *int64 79 NullFloat32 *float32 80 NullFloat64 *float64 81 MultiPtr *****int 82 NullKey *types.Key 83 } 84 85 var ( 86 nsPtr *normalStruct 87 ns normalStruct 88 nsInit = new(normalStruct) 89 ) 90 91 func TestMarshal(t *testing.T) { 92 var ( 93 b []byte 94 err error 95 i normalStruct 96 i32 = int(888) 97 k = types.NameKey("Name", "@#$%^&*()ashdkjashd", types.NewIDKey("ID", nil)) 98 ) 99 100 data := `{"Str":"","UUID":"00000000-0000-0000-0000-000000000000","Text":"","DecimalStr":"0.00","NullableDecimal":null,` 101 data += `"Boolean":"No","LongStr":"","CustomStrType":"",` 102 data += `"EmptyByte":null,"Byte":null,"Bool":false,"Skip":null,` 103 data += `"Int":0,"TinyInt":0,"SmallInt":0,"MediumInt":0,"BigInt":0,` 104 data += `"Uint":0,"TinyUint":0,"SmallUint":0,"MediumUint":0,"BigUint":0,` 105 data += `"Float32":0,"Float64":0,"UFloat32":0,` 106 data += `"EmptyArray":null,"EmptyMap":null,"EmptyStruct":{},"JSONRaw":null,"Timestamp":"0001-01-01T00:00:00Z",` 107 data += `"NullStr":null,"NullCustomStrType":null,` 108 data += `"NullInt":null,"NullTinyInt":null,"NullSmallInt":null,"NullMediumInt":null,"NullBigInt":null,` 109 data += `"NullFloat32":null,"NullFloat64":null,` 110 data += `"MultiPtr":null,"NullKey":null}` 111 dataByte := []byte(data) 112 113 // Marshal nil 114 { 115 b, err = Marshal(nsPtr) 116 require.NoError(t, err) 117 require.Equal(t, []byte(`null`), b) 118 119 b, err = Marshal(nil) 120 require.NoError(t, err) 121 require.Equal(t, []byte(`null`), b) 122 } 123 124 // Marshal initialized struct 125 { 126 b, err = Marshal(nsInit) 127 require.NoError(t, err) 128 require.Equal(t, dataByte, b) 129 } 130 131 var ( 132 symbolStr = `'ajhdjasd12380912$%^&*()_\\"asdasd123910293"""\\\\123210312930-\\` 133 jsonEscapeStr = `"'ajhdjasd12380912$%^&*()_\\\\\"asdasd123910293\"\"\"\\\\\\\\123210312930-\\\\"` 134 bytes = []byte(`abcd1234`) 135 // result = []byte(`{"Str":"hello world","DecimalStr":"10.69","NullableDecimal":null,"Boolean":"Yes","LongStr":"` + jsonEscapeStr + `","CustomStrType":"","EmptyByte":"YWJjZDEyMzQ=","Byte":null,"Bool":false,"Skip":null,"Int":0,"TinyInt":0,"SmallInt":0,"MediumInt":0,"BigInt":0,"Uint":0,"TinyUint":0,"SmallUint":0,"MediumUint":0,"BigUint":0,"Float32":0,"Float64":0,"UFloat32":0,"EmptyStruct":{},"JSONRaw":null,"Timestamp":"0001-01-01T00:00:00Z","NullStr":"` + jsonEscapeStr + `","NullCustomStrType":null,"NullInt":888,"NullTinyInt":null,"NullSmallInt":null,"NullMediumInt":null,"NullBigInt":null,"NullFloat32":null,"NullFloat64":null,"MultiPtr":null,"NullKey":"` + k.String() + `"}`) 136 ) 137 138 // Marshal struct with pointer value 139 { 140 i.Text = `"My long text.......""` 141 i.Str = "hello world" 142 i.priv = 100 143 i.LongStr = symbolStr 144 i.Boolean = true 145 i.DecimalStr = 10.688 146 i.EmptyByte = bytes 147 i.EmptyArray = make([]string, 0) 148 i.EmptyMap = make(map[string]interface{}) 149 i.NullStr = &symbolStr 150 i.NullInt = &i32 151 i.NullKey = k 152 153 dataByte, _ = sjson.SetBytes(dataByte, "Str", "hello world") 154 dataByte, _ = sjson.SetBytes(dataByte, "Text", `"My long text.......""`) 155 dataByte, _ = sjson.SetRawBytes(dataByte, "LongStr", []byte(jsonEscapeStr)) 156 dataByte, _ = sjson.SetBytes(dataByte, "Boolean", "Yes") 157 dataByte, _ = sjson.SetBytes(dataByte, "DecimalStr", "10.69") 158 dataByte, _ = sjson.SetBytes(dataByte, "EmptyByte", base64.StdEncoding.EncodeToString(bytes)) 159 dataByte, _ = sjson.SetBytes(dataByte, "EmptyArray", make([]string, 0)) 160 dataByte, _ = sjson.SetBytes(dataByte, "EmptyMap", make(map[string]interface{})) 161 dataByte, _ = sjson.SetRawBytes(dataByte, "NullStr", []byte(jsonEscapeStr)) 162 dataByte, _ = sjson.SetBytes(dataByte, "NullInt", i32) 163 dataByte, _ = sjson.SetBytes(dataByte, "NullKey", k.String()) 164 165 b, err = Marshal(i) 166 require.NoError(t, err) 167 require.Equal(t, dataByte, b) 168 } 169 170 t.Run("Test Map's Key with Int, Uint data type", func(it *testing.T) { 171 var ( 172 intMap map[int]string 173 b []byte 174 err error 175 ) 176 177 b, err = Marshal(intMap) 178 require.NoError(t, err) 179 require.Equal(t, []byte(`null`), b) 180 181 intMap = make(map[int]string) 182 intMap[0] = "hello" 183 intMap[100] = "🤖🤖" 184 intMap[-1] = "negative" 185 186 b, err = Marshal(intMap) 187 require.NoError(t, err) 188 require.Equal(t, []byte(`{"-1":"negative","0":"hello","100":"🤖🤖"}`), b) 189 190 var outMap map[int]string 191 err = Unmarshal(b, &outMap) 192 require.NoError(t, err) 193 require.Equal(t, "hello", outMap[0]) 194 require.Equal(t, "🤖🤖", outMap[100]) 195 require.Equal(t, "negative", outMap[-1]) 196 197 var ( 198 uint8Map map[uint8]string 199 ) 200 201 b, err = Marshal(uint8Map) 202 require.NoError(t, err) 203 require.Equal(t, []byte(`null`), b) 204 205 uint8Map = make(map[uint8]string) 206 uint8Map[0] = "zero (\"initial value\")" 207 uint8Map[100] = "🤖🤖" 208 uint8Map[88] = "Long sentences here .............." 209 b, err = Marshal(uint8Map) 210 require.NoError(t, err) 211 require.Equal(t, []byte(`{"0":"zero (\"initial value\")","88":"Long sentences here ..............","100":"🤖🤖"}`), b) 212 213 var uoutMap map[uint8]string 214 err = Unmarshal(b, &uoutMap) 215 require.NoError(t, err) 216 require.Equal(t, `zero ("initial value")`, uoutMap[0]) 217 require.Equal(t, "🤖🤖", uoutMap[100]) 218 require.Equal(t, "Long sentences here ..............", uoutMap[88]) 219 }) 220 221 t.Run("Test Map's Key with data type implements `MarshalText`", func(it *testing.T) { 222 langMap := make(map[language.Tag]string) 223 langMap[language.English] = "english" 224 langMap[language.Japanese] = "japanese" 225 langMap[language.Korean] = "korean" 226 langMap[language.Arabic] = "arabic" 227 langMap[language.Chinese] = "chinese" 228 229 b, err := Marshal(langMap) 230 require.NoError(t, err) 231 232 outMap := make(map[language.Tag]string) 233 err = Unmarshal(b, &outMap) 234 require.NoError(t, err) 235 require.Equal(t, langMap[language.English], outMap[language.English]) 236 require.Equal(t, langMap[language.Japanese], outMap[language.Japanese]) 237 require.Equal(t, langMap[language.Korean], outMap[language.Korean]) 238 require.Equal(t, langMap[language.Arabic], outMap[language.Arabic]) 239 require.Equal(t, langMap[language.Chinese], outMap[language.Chinese]) 240 }) 241 } 242 243 func BenchmarkJSONMarshal(b *testing.B) { 244 var err error 245 b.Run("Pointer Struct w/o initialize", func(t *testing.B) { 246 for n := 0; n < t.N; n++ { 247 _, err = json.Marshal(nsPtr) 248 require.NoError(t, err) 249 } 250 }) 251 252 b.Run("Pointer Struct w initialize", func(t *testing.B) { 253 for n := 0; n < t.N; n++ { 254 _, err = json.Marshal(nsInit) 255 require.NoError(t, err) 256 } 257 }) 258 259 b.Run("Struct w initialize", func(t *testing.B) { 260 for n := 0; n < t.N; n++ { 261 _, err = json.Marshal(nsPtr) 262 require.NoError(t, err) 263 } 264 }) 265 } 266 267 func BenchmarkJSONBMarshal(b *testing.B) { 268 var err error 269 b.Run("Pointer Struct w/o initialize", func(t *testing.B) { 270 for n := 0; n < t.N; n++ { 271 _, err = Marshal(nsPtr) 272 require.NoError(t, err) 273 } 274 }) 275 276 b.Run("Pointer Struct w initialize", func(t *testing.B) { 277 for n := 0; n < t.N; n++ { 278 _, err = Marshal(nsInit) 279 require.NoError(t, err) 280 } 281 }) 282 283 b.Run("Struct w initialize", func(t *testing.B) { 284 for n := 0; n < t.N; n++ { 285 _, err = Marshal(nsPtr) 286 require.NoError(t, err) 287 } 288 }) 289 }