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  }