github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/json/json_test.go (about) 1 //go:build go1.8 2 // +build go1.8 3 4 /* 5 Copyright 2015 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package json 21 22 import ( 23 gojson "encoding/json" 24 25 "fmt" 26 "math" 27 "reflect" 28 "strconv" 29 "strings" 30 "testing" 31 ) 32 33 func TestEvaluateTypes(t *testing.T) { 34 testCases := []struct { 35 In string 36 Data interface{} 37 Out string 38 Err bool 39 }{ 40 // Invalid syntaxes 41 { 42 In: `x`, 43 Err: true, 44 }, 45 { 46 In: ``, 47 Err: true, 48 }, 49 50 // Null 51 { 52 In: `null`, 53 Data: nil, 54 Out: `null`, 55 }, 56 // Booleans 57 { 58 In: `true`, 59 Data: true, 60 Out: `true`, 61 }, 62 { 63 In: `false`, 64 Data: false, 65 Out: `false`, 66 }, 67 68 // Integers 69 { 70 In: `0`, 71 Data: int64(0), 72 Out: `0`, 73 }, 74 { 75 In: `-0`, 76 Data: int64(-0), 77 Out: `0`, 78 }, 79 { 80 In: `1`, 81 Data: int64(1), 82 Out: `1`, 83 }, 84 { 85 In: `2147483647`, 86 Data: int64(math.MaxInt32), 87 Out: `2147483647`, 88 }, 89 { 90 In: `-2147483648`, 91 Data: int64(math.MinInt32), 92 Out: `-2147483648`, 93 }, 94 { 95 In: `9223372036854775807`, 96 Data: int64(math.MaxInt64), 97 Out: `9223372036854775807`, 98 }, 99 { 100 In: `-9223372036854775808`, 101 Data: int64(math.MinInt64), 102 Out: `-9223372036854775808`, 103 }, 104 105 // Int overflow 106 { 107 In: `9223372036854775808`, // MaxInt64 + 1 108 Data: float64(9223372036854775808), 109 Out: `9223372036854776000`, 110 }, 111 { 112 In: `-9223372036854775809`, // MinInt64 - 1 113 Data: float64(math.MinInt64), 114 Out: `-9223372036854776000`, 115 }, 116 117 // Floats 118 { 119 In: `0.0`, 120 Data: float64(0), 121 Out: `0`, 122 }, 123 { 124 In: `-0.0`, 125 Data: float64(-0.0), //nolint:staticcheck // SA4026: in Go, the floating-point literal '-0.0' is the same as '0.0' 126 Out: `-0`, 127 }, 128 { 129 In: `0.5`, 130 Data: float64(0.5), 131 Out: `0.5`, 132 }, 133 { 134 In: `1e3`, 135 Data: float64(1e3), 136 Out: `1000`, 137 }, 138 { 139 In: `1.5`, 140 Data: float64(1.5), 141 Out: `1.5`, 142 }, 143 { 144 In: `-0.3`, 145 Data: float64(-.3), 146 Out: `-0.3`, 147 }, 148 { 149 // Largest representable float32 150 In: `3.40282346638528859811704183484516925440e+38`, 151 Data: float64(math.MaxFloat32), 152 Out: strconv.FormatFloat(math.MaxFloat32, 'g', -1, 64), 153 }, 154 { 155 // Smallest float32 without losing precision 156 In: `1.175494351e-38`, 157 Data: float64(1.175494351e-38), 158 Out: `1.175494351e-38`, 159 }, 160 { 161 // float32 closest to zero 162 In: `1.401298464324817070923729583289916131280e-45`, 163 Data: float64(math.SmallestNonzeroFloat32), 164 Out: strconv.FormatFloat(math.SmallestNonzeroFloat32, 'g', -1, 64), 165 }, 166 { 167 // Largest representable float64 168 In: `1.797693134862315708145274237317043567981e+308`, 169 Data: float64(math.MaxFloat64), 170 Out: strconv.FormatFloat(math.MaxFloat64, 'g', -1, 64), 171 }, 172 { 173 // Closest to zero without losing precision 174 In: `2.2250738585072014e-308`, 175 Data: float64(2.2250738585072014e-308), 176 Out: `2.2250738585072014e-308`, 177 }, 178 179 { 180 // float64 closest to zero 181 In: `4.940656458412465441765687928682213723651e-324`, 182 Data: float64(math.SmallestNonzeroFloat64), 183 Out: strconv.FormatFloat(math.SmallestNonzeroFloat64, 'g', -1, 64), 184 }, 185 186 { 187 // math.MaxFloat64 + 2 overflow 188 In: `1.7976931348623159e+308`, 189 Err: true, 190 }, 191 192 // Strings 193 { 194 In: `""`, 195 Data: string(""), 196 Out: `""`, 197 }, 198 { 199 In: `"0"`, 200 Data: string("0"), 201 Out: `"0"`, 202 }, 203 { 204 In: `"A"`, 205 Data: string("A"), 206 Out: `"A"`, 207 }, 208 { 209 In: `"Iñtërnâtiônàlizætiøn"`, 210 Data: string("Iñtërnâtiônàlizætiøn"), 211 Out: `"Iñtërnâtiônàlizætiøn"`, 212 }, 213 214 // Arrays 215 { 216 In: `[]`, 217 Data: []interface{}{}, 218 Out: `[]`, 219 }, 220 { 221 In: `[` + strings.Join([]string{ 222 `null`, 223 `true`, 224 `false`, 225 `0`, 226 `9223372036854775807`, 227 `0.0`, 228 `0.5`, 229 `1.0`, 230 `1.797693134862315708145274237317043567981e+308`, 231 `"0"`, 232 `"A"`, 233 `"Iñtërnâtiônàlizætiøn"`, 234 `[null,true,1,1.0,1.5]`, 235 `{"boolkey":true,"floatkey":1.0,"intkey":1,"nullkey":null}`, 236 }, ",") + `]`, 237 Data: []interface{}{ 238 nil, 239 true, 240 false, 241 int64(0), 242 int64(math.MaxInt64), 243 float64(0.0), 244 float64(0.5), 245 float64(1.0), 246 float64(math.MaxFloat64), 247 string("0"), 248 string("A"), 249 string("Iñtërnâtiônàlizætiøn"), 250 []interface{}{nil, true, int64(1), float64(1.0), float64(1.5)}, 251 map[string]interface{}{"nullkey": nil, "boolkey": true, "intkey": int64(1), "floatkey": float64(1.0)}, 252 }, 253 Out: `[` + strings.Join([]string{ 254 `null`, 255 `true`, 256 `false`, 257 `0`, 258 `9223372036854775807`, 259 `0`, 260 `0.5`, 261 `1`, 262 strconv.FormatFloat(math.MaxFloat64, 'g', -1, 64), 263 `"0"`, 264 `"A"`, 265 `"Iñtërnâtiônàlizætiøn"`, 266 `[null,true,1,1,1.5]`, 267 `{"boolkey":true,"floatkey":1,"intkey":1,"nullkey":null}`, // gets alphabetized by Marshal 268 }, ",") + `]`, 269 }, 270 271 // Maps 272 { 273 In: `{}`, 274 Data: map[string]interface{}{}, 275 Out: `{}`, 276 }, 277 { 278 In: `{"boolkey":true,"floatkey":1.0,"intkey":1,"nullkey":null}`, 279 Data: map[string]interface{}{"nullkey": nil, "boolkey": true, "intkey": int64(1), "floatkey": float64(1.0)}, 280 Out: `{"boolkey":true,"floatkey":1,"intkey":1,"nullkey":null}`, // gets alphabetized by Marshal 281 }, 282 } 283 284 for i, tc := range testCases { 285 t.Run(fmt.Sprintf("%d_map", i), func(t *testing.T) { 286 // decode the input as a map item 287 inputJSON := fmt.Sprintf(`{"data":%s}`, tc.In) 288 expectedJSON := fmt.Sprintf(`{"data":%s}`, tc.Out) 289 m := map[string]interface{}{} 290 err := Unmarshal([]byte(inputJSON), &m) 291 if tc.Err && err != nil { 292 // Expected error 293 return 294 } 295 if err != nil { 296 t.Fatalf("%s: error decoding: %v", tc.In, err) 297 } 298 if tc.Err { 299 t.Fatalf("%s: expected error, got none", tc.In) 300 } 301 data, ok := m["data"] 302 if !ok { 303 t.Fatalf("%s: decoded object missing data key: %#v", tc.In, m) 304 } 305 if !reflect.DeepEqual(tc.Data, data) { 306 t.Fatalf("%s: expected\n\t%#v (%v), got\n\t%#v (%v)", tc.In, tc.Data, reflect.TypeOf(tc.Data), data, reflect.TypeOf(data)) 307 } 308 309 outputJSON, err := Marshal(m) 310 if err != nil { 311 t.Fatalf("%s: error encoding: %v", tc.In, err) 312 } 313 314 if expectedJSON != string(outputJSON) { 315 t.Fatalf("%s: expected\n\t%s, got\n\t%s", tc.In, expectedJSON, string(outputJSON)) 316 } 317 }) 318 319 t.Run(fmt.Sprintf("%d_slice", i), func(t *testing.T) { 320 // decode the input as an array item 321 inputJSON := fmt.Sprintf(`[0,%s]`, tc.In) 322 expectedJSON := fmt.Sprintf(`[0,%s]`, tc.Out) 323 m := []interface{}{} 324 err := Unmarshal([]byte(inputJSON), &m) 325 if tc.Err && err != nil { 326 // Expected error 327 return 328 } 329 if err != nil { 330 t.Fatalf("%s: error decoding: %v", tc.In, err) 331 } 332 if tc.Err { 333 t.Fatalf("%s: expected error, got none", tc.In) 334 } 335 if len(m) != 2 { 336 t.Fatalf("%s: decoded object wasn't the right length: %#v", tc.In, m) 337 } 338 data := m[1] 339 if !reflect.DeepEqual(tc.Data, data) { 340 t.Fatalf("%s: expected\n\t%#v (%v), got\n\t%#v (%v)", tc.In, tc.Data, reflect.TypeOf(tc.Data), data, reflect.TypeOf(data)) 341 } 342 343 outputJSON, err := Marshal(m) 344 if err != nil { 345 t.Fatalf("%s: error encoding: %v", tc.In, err) 346 } 347 348 if expectedJSON != string(outputJSON) { 349 t.Fatalf("%s: expected\n\t%s, got\n\t%s", tc.In, expectedJSON, string(outputJSON)) 350 } 351 }) 352 353 t.Run(fmt.Sprintf("%d_raw", i), func(t *testing.T) { 354 // decode the input as a standalone object 355 inputJSON := tc.In 356 expectedJSON := tc.Out 357 var m interface{} 358 err := Unmarshal([]byte(inputJSON), &m) 359 if tc.Err && err != nil { 360 // Expected error 361 return 362 } 363 if err != nil { 364 t.Fatalf("%s: error decoding: %v", tc.In, err) 365 } 366 if tc.Err { 367 t.Fatalf("%s: expected error, got none", tc.In) 368 } 369 data := m 370 if !reflect.DeepEqual(tc.Data, data) { 371 t.Fatalf("%s: expected\n\t%#v (%v), got\n\t%#v (%v)", tc.In, tc.Data, reflect.TypeOf(tc.Data), data, reflect.TypeOf(data)) 372 } 373 374 outputJSON, err := Marshal(m) 375 if err != nil { 376 t.Fatalf("%s: error encoding: %v", tc.In, err) 377 } 378 379 if expectedJSON != string(outputJSON) { 380 t.Fatalf("%s: expected\n\t%s, got\n\t%s", tc.In, expectedJSON, string(outputJSON)) 381 } 382 }) 383 } 384 } 385 386 func TestUnmarshalNil(t *testing.T) { 387 { 388 var v *interface{} 389 err := Unmarshal([]byte(`0`), v) 390 goerr := gojson.Unmarshal([]byte(`0`), v) 391 if err == nil || goerr == nil || err.Error() != goerr.Error() { 392 t.Fatalf("expected error matching stdlib, got %v, %v", err, goerr) 393 } else { 394 t.Log(err) 395 } 396 } 397 398 { 399 var v *[]interface{} 400 err := Unmarshal([]byte(`[]`), v) 401 goerr := gojson.Unmarshal([]byte(`[]`), v) 402 if err == nil || goerr == nil || err.Error() != goerr.Error() { 403 t.Fatalf("expected error matching stdlib, got %v, %v", err, goerr) 404 } else { 405 t.Log(err) 406 } 407 } 408 409 { 410 var v *map[string]interface{} 411 err := Unmarshal([]byte(`{}`), v) 412 goerr := gojson.Unmarshal([]byte(`{}`), v) 413 if err == nil || goerr == nil || err.Error() != goerr.Error() { 414 t.Fatalf("expected error matching stdlib, got %v, %v", err, goerr) 415 } else { 416 t.Log(err) 417 } 418 } 419 }