Merge pull request #124324 from benluddy/cbor-decode-tests-grouped-by-cbor-type
KEP-4222: Group CBOR decode tests by the kind of their inputs.
This commit is contained in:
		@@ -37,14 +37,99 @@ func TestDecode(t *testing.T) {
 | 
				
			|||||||
		return b
 | 
							return b
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tc := range []struct {
 | 
						type test struct {
 | 
				
			||||||
		name          string
 | 
							name          string
 | 
				
			||||||
		modes         []cbor.DecMode
 | 
							modes         []cbor.DecMode // most tests should run for all modes
 | 
				
			||||||
		in            []byte
 | 
							in            []byte
 | 
				
			||||||
		into          interface{} // prototype for concrete destination type. if nil, decode into empty interface value.
 | 
							into          interface{} // prototype for concrete destination type. if nil, decode into empty interface value.
 | 
				
			||||||
		want          interface{}
 | 
							want          interface{}
 | 
				
			||||||
		assertOnError func(t *testing.T, e error)
 | 
							assertOnError func(t *testing.T, e error)
 | 
				
			||||||
	}{
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Test cases are grouped by the kind of the CBOR data item being decoded, as enumerated in
 | 
				
			||||||
 | 
						// https://www.rfc-editor.org/rfc/rfc8949.html#section-2.
 | 
				
			||||||
 | 
						group := func(t *testing.T, name string, tests []test) {
 | 
				
			||||||
 | 
							t.Run(name, func(t *testing.T) {
 | 
				
			||||||
 | 
								for _, test := range tests {
 | 
				
			||||||
 | 
									t.Run(test.name, func(t *testing.T) {
 | 
				
			||||||
 | 
										decModes := test.modes
 | 
				
			||||||
 | 
										if len(decModes) == 0 {
 | 
				
			||||||
 | 
											decModes = allDecModes
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										for _, decMode := range decModes {
 | 
				
			||||||
 | 
											modeName, ok := decModeNames[decMode]
 | 
				
			||||||
 | 
											if !ok {
 | 
				
			||||||
 | 
												t.Fatal("test case configured to run against unrecognized mode")
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											t.Run(fmt.Sprintf("%s/mode=%s", test.name, modeName), func(t *testing.T) {
 | 
				
			||||||
 | 
												var dst reflect.Value
 | 
				
			||||||
 | 
												if test.into == nil {
 | 
				
			||||||
 | 
													var i interface{}
 | 
				
			||||||
 | 
													dst = reflect.ValueOf(&i)
 | 
				
			||||||
 | 
												} else {
 | 
				
			||||||
 | 
													dst = reflect.New(reflect.TypeOf(test.into))
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												err := decMode.Unmarshal(test.in, dst.Interface())
 | 
				
			||||||
 | 
												test.assertOnError(t, err)
 | 
				
			||||||
 | 
												if test.want != nil {
 | 
				
			||||||
 | 
													if diff := cmp.Diff(test.want, dst.Elem().Interface()); diff != "" {
 | 
				
			||||||
 | 
														t.Errorf("unexpected output:\n%s", diff)
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											})
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						group(t, "unsigned integer", []test{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:          "unsigned integer decodes to interface{} as int64",
 | 
				
			||||||
 | 
								in:            hex("0a"), // 10
 | 
				
			||||||
 | 
								want:          int64(10),
 | 
				
			||||||
 | 
								assertOnError: assertNilError,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						group(t, "negative integer", []test{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						group(t, "byte string", []test{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						group(t, "text string", []test{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "reject text string containing invalid utf-8 sequence",
 | 
				
			||||||
 | 
								in:   hex("6180"), // text string beginning with continuation byte 0x80
 | 
				
			||||||
 | 
								assertOnError: assertOnConcreteError(func(t *testing.T, e *cbor.SemanticError) {
 | 
				
			||||||
 | 
									const expected = "cbor: invalid UTF-8 string"
 | 
				
			||||||
 | 
									if msg := e.Error(); msg != expected {
 | 
				
			||||||
 | 
										t.Errorf("expected %v, got %v", expected, msg)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:          "indefinite-length text string",
 | 
				
			||||||
 | 
								in:            hex("7f616161626163ff"), // (_ "a", "b", "c")
 | 
				
			||||||
 | 
								want:          "abc",
 | 
				
			||||||
 | 
								assertOnError: assertNilError,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						group(t, "array", []test{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "nested indefinite-length array",
 | 
				
			||||||
 | 
								in:   hex("9f9f8080ff9f8080ffff"), // [_ [_ [] []] [_ [][]]]
 | 
				
			||||||
 | 
								want: []interface{}{
 | 
				
			||||||
 | 
									[]interface{}{[]interface{}{}, []interface{}{}},
 | 
				
			||||||
 | 
									[]interface{}{[]interface{}{}, []interface{}{}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								assertOnError: assertNilError,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						group(t, "map", []test{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name:          "reject duplicate negative int keys into struct",
 | 
								name:          "reject duplicate negative int keys into struct",
 | 
				
			||||||
			modes:         []cbor.DecMode{modes.DecodeLax},
 | 
								modes:         []cbor.DecMode{modes.DecodeLax},
 | 
				
			||||||
@@ -216,22 +301,6 @@ func TestDecode(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			assertOnError: assertNilError,
 | 
								assertOnError: assertNilError,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name: "reject text string containing invalid utf-8 sequence",
 | 
					 | 
				
			||||||
			in:   hex("6180"), // text string beginning with continuation byte 0x80
 | 
					 | 
				
			||||||
			assertOnError: assertOnConcreteError(func(t *testing.T, e *cbor.SemanticError) {
 | 
					 | 
				
			||||||
				const expected = "cbor: invalid UTF-8 string"
 | 
					 | 
				
			||||||
				if msg := e.Error(); msg != expected {
 | 
					 | 
				
			||||||
					t.Errorf("expected %v, got %v", expected, msg)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:          "unsigned integer decodes to interface{} as int64",
 | 
					 | 
				
			||||||
			in:            hex("0a"), // 10
 | 
					 | 
				
			||||||
			want:          int64(10),
 | 
					 | 
				
			||||||
			assertOnError: assertNilError,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name:  "unknown field error",
 | 
								name:  "unknown field error",
 | 
				
			||||||
			modes: []cbor.DecMode{modes.Decode},
 | 
								modes: []cbor.DecMode{modes.Decode},
 | 
				
			||||||
@@ -251,21 +320,6 @@ func TestDecode(t *testing.T) {
 | 
				
			|||||||
			want:          struct{}{},
 | 
								want:          struct{}{},
 | 
				
			||||||
			assertOnError: assertNilError,
 | 
								assertOnError: assertNilError,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:          "indefinite-length text string",
 | 
					 | 
				
			||||||
			in:            hex("7f616161626163ff"), // (_ "a", "b", "c")
 | 
					 | 
				
			||||||
			want:          "abc",
 | 
					 | 
				
			||||||
			assertOnError: assertNilError,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name: "nested indefinite-length array",
 | 
					 | 
				
			||||||
			in:   hex("9f9f8080ff9f8080ffff"), // [_ [_ [] []] [_ [][]]]
 | 
					 | 
				
			||||||
			want: []interface{}{
 | 
					 | 
				
			||||||
				[]interface{}{[]interface{}{}, []interface{}{}},
 | 
					 | 
				
			||||||
				[]interface{}{[]interface{}{}, []interface{}{}},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			assertOnError: assertNilError,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "nested indefinite-length map",
 | 
								name: "nested indefinite-length map",
 | 
				
			||||||
			in:   hex("bf6141bf616101616202ff6142bf616901616a02ffff"), // {_ "A": {_ "a": 1, "b": 2}, "B": {_ "i": 1, "j": 2}}
 | 
								in:   hex("bf6141bf616101616202ff6142bf616901616a02ffff"), // {_ "A": {_ "a": 1, "b": 2}, "B": {_ "i": 1, "j": 2}}
 | 
				
			||||||
@@ -275,34 +329,21 @@ func TestDecode(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			assertOnError: assertNilError,
 | 
								assertOnError: assertNilError,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	} {
 | 
						})
 | 
				
			||||||
		decModes := tc.modes
 | 
					 | 
				
			||||||
		if len(decModes) == 0 {
 | 
					 | 
				
			||||||
			decModes = allDecModes
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for _, decMode := range decModes {
 | 
						group(t, "floating-point number", []test{})
 | 
				
			||||||
			modeName, ok := decModeNames[decMode]
 | 
					 | 
				
			||||||
			if !ok {
 | 
					 | 
				
			||||||
				t.Fatal("test case configured to run against unrecognized mode")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			t.Run(fmt.Sprintf("mode=%s/%s", modeName, tc.name), func(t *testing.T) {
 | 
						group(t, "simple value", []test{})
 | 
				
			||||||
				var dst reflect.Value
 | 
					
 | 
				
			||||||
				if tc.into == nil {
 | 
						t.Run("tag", func(t *testing.T) {
 | 
				
			||||||
					var i interface{}
 | 
							group(t, "rfc3339 time", []test{})
 | 
				
			||||||
					dst = reflect.ValueOf(&i)
 | 
					
 | 
				
			||||||
				} else {
 | 
							group(t, "epoch time", []test{})
 | 
				
			||||||
					dst = reflect.New(reflect.TypeOf(tc.into))
 | 
					
 | 
				
			||||||
				}
 | 
							group(t, "unsigned bignum", []test{})
 | 
				
			||||||
				err := decMode.Unmarshal(tc.in, dst.Interface())
 | 
					
 | 
				
			||||||
				tc.assertOnError(t, err)
 | 
							group(t, "negative bignum", []test{})
 | 
				
			||||||
				if tc.want != nil {
 | 
					
 | 
				
			||||||
					if diff := cmp.Diff(tc.want, dst.Elem().Interface()); diff != "" {
 | 
							group(t, "unrecognized", []test{})
 | 
				
			||||||
						t.Errorf("unexpected output:\n%s", diff)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user