|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920 |
- // Copyright 2015 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- package bigquery
-
- import (
- "fmt"
- "math/big"
- "reflect"
- "testing"
- "time"
-
- "cloud.google.com/go/civil"
- "cloud.google.com/go/internal/pretty"
- "cloud.google.com/go/internal/testutil"
-
- bq "google.golang.org/api/bigquery/v2"
- )
-
- func (fs *FieldSchema) GoString() string {
- if fs == nil {
- return "<nil>"
- }
-
- return fmt.Sprintf("{Name:%s Description:%s Repeated:%t Required:%t Type:%s Schema:%s}",
- fs.Name,
- fs.Description,
- fs.Repeated,
- fs.Required,
- fs.Type,
- fmt.Sprintf("%#v", fs.Schema),
- )
- }
-
- func bqTableFieldSchema(desc, name, typ, mode string) *bq.TableFieldSchema {
- return &bq.TableFieldSchema{
- Description: desc,
- Name: name,
- Mode: mode,
- Type: typ,
- }
- }
-
- func fieldSchema(desc, name, typ string, repeated, required bool) *FieldSchema {
- return &FieldSchema{
- Description: desc,
- Name: name,
- Repeated: repeated,
- Required: required,
- Type: FieldType(typ),
- }
- }
-
- func TestSchemaConversion(t *testing.T) {
- testCases := []struct {
- schema Schema
- bqSchema *bq.TableSchema
- }{
- {
- // required
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("desc", "name", "STRING", "REQUIRED"),
- },
- },
- schema: Schema{
- fieldSchema("desc", "name", "STRING", false, true),
- },
- },
- {
- // repeated
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("desc", "name", "STRING", "REPEATED"),
- },
- },
- schema: Schema{
- fieldSchema("desc", "name", "STRING", true, false),
- },
- },
- {
- // nullable, string
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("desc", "name", "STRING", ""),
- },
- },
- schema: Schema{
- fieldSchema("desc", "name", "STRING", false, false),
- },
- },
- {
- // integer
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("desc", "name", "INTEGER", ""),
- },
- },
- schema: Schema{
- fieldSchema("desc", "name", "INTEGER", false, false),
- },
- },
- {
- // float
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("desc", "name", "FLOAT", ""),
- },
- },
- schema: Schema{
- fieldSchema("desc", "name", "FLOAT", false, false),
- },
- },
- {
- // boolean
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("desc", "name", "BOOLEAN", ""),
- },
- },
- schema: Schema{
- fieldSchema("desc", "name", "BOOLEAN", false, false),
- },
- },
- {
- // timestamp
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("desc", "name", "TIMESTAMP", ""),
- },
- },
- schema: Schema{
- fieldSchema("desc", "name", "TIMESTAMP", false, false),
- },
- },
- {
- // civil times
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("desc", "f1", "TIME", ""),
- bqTableFieldSchema("desc", "f2", "DATE", ""),
- bqTableFieldSchema("desc", "f3", "DATETIME", ""),
- },
- },
- schema: Schema{
- fieldSchema("desc", "f1", "TIME", false, false),
- fieldSchema("desc", "f2", "DATE", false, false),
- fieldSchema("desc", "f3", "DATETIME", false, false),
- },
- },
- {
- // numeric
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("desc", "n", "NUMERIC", ""),
- },
- },
- schema: Schema{
- fieldSchema("desc", "n", "NUMERIC", false, false),
- },
- },
- {
- // nested
- bqSchema: &bq.TableSchema{
- Fields: []*bq.TableFieldSchema{
- {
- Description: "An outer schema wrapping a nested schema",
- Name: "outer",
- Mode: "REQUIRED",
- Type: "RECORD",
- Fields: []*bq.TableFieldSchema{
- bqTableFieldSchema("inner field", "inner", "STRING", ""),
- },
- },
- },
- },
- schema: Schema{
- &FieldSchema{
- Description: "An outer schema wrapping a nested schema",
- Name: "outer",
- Required: true,
- Type: "RECORD",
- Schema: Schema{
- {
- Description: "inner field",
- Name: "inner",
- Type: "STRING",
- },
- },
- },
- },
- },
- }
- for _, tc := range testCases {
- bqSchema := tc.schema.toBQ()
- if !testutil.Equal(bqSchema, tc.bqSchema) {
- t.Errorf("converting to TableSchema: got:\n%v\nwant:\n%v",
- pretty.Value(bqSchema), pretty.Value(tc.bqSchema))
- }
- schema := bqToSchema(tc.bqSchema)
- if !testutil.Equal(schema, tc.schema) {
- t.Errorf("converting to Schema: got:\n%v\nwant:\n%v", schema, tc.schema)
- }
- }
- }
-
- type allStrings struct {
- String string
- ByteSlice []byte
- }
-
- type allSignedIntegers struct {
- Int64 int64
- Int32 int32
- Int16 int16
- Int8 int8
- Int int
- }
-
- type allUnsignedIntegers struct {
- Uint32 uint32
- Uint16 uint16
- Uint8 uint8
- }
-
- type allFloat struct {
- Float64 float64
- Float32 float32
- // NOTE: Complex32 and Complex64 are unsupported by BigQuery
- }
-
- type allBoolean struct {
- Bool bool
- }
-
- type allTime struct {
- Timestamp time.Time
- Time civil.Time
- Date civil.Date
- DateTime civil.DateTime
- }
-
- type allNumeric struct {
- Numeric *big.Rat
- }
-
- func reqField(name, typ string) *FieldSchema {
- return &FieldSchema{
- Name: name,
- Type: FieldType(typ),
- Required: true,
- }
- }
-
- func optField(name, typ string) *FieldSchema {
- return &FieldSchema{
- Name: name,
- Type: FieldType(typ),
- Required: false,
- }
- }
-
- func TestSimpleInference(t *testing.T) {
- testCases := []struct {
- in interface{}
- want Schema
- }{
- {
- in: allSignedIntegers{},
- want: Schema{
- reqField("Int64", "INTEGER"),
- reqField("Int32", "INTEGER"),
- reqField("Int16", "INTEGER"),
- reqField("Int8", "INTEGER"),
- reqField("Int", "INTEGER"),
- },
- },
- {
- in: allUnsignedIntegers{},
- want: Schema{
- reqField("Uint32", "INTEGER"),
- reqField("Uint16", "INTEGER"),
- reqField("Uint8", "INTEGER"),
- },
- },
- {
- in: allFloat{},
- want: Schema{
- reqField("Float64", "FLOAT"),
- reqField("Float32", "FLOAT"),
- },
- },
- {
- in: allBoolean{},
- want: Schema{
- reqField("Bool", "BOOLEAN"),
- },
- },
- {
- in: &allBoolean{},
- want: Schema{
- reqField("Bool", "BOOLEAN"),
- },
- },
- {
- in: allTime{},
- want: Schema{
- reqField("Timestamp", "TIMESTAMP"),
- reqField("Time", "TIME"),
- reqField("Date", "DATE"),
- reqField("DateTime", "DATETIME"),
- },
- },
- {
- in: &allNumeric{},
- want: Schema{
- reqField("Numeric", "NUMERIC"),
- },
- },
- {
- in: allStrings{},
- want: Schema{
- reqField("String", "STRING"),
- reqField("ByteSlice", "BYTES"),
- },
- },
- }
- for _, tc := range testCases {
- got, err := InferSchema(tc.in)
- if err != nil {
- t.Fatalf("%T: error inferring TableSchema: %v", tc.in, err)
- }
- if !testutil.Equal(got, tc.want) {
- t.Errorf("%T: inferring TableSchema: got:\n%#v\nwant:\n%#v", tc.in,
- pretty.Value(got), pretty.Value(tc.want))
- }
- }
- }
-
- type containsNested struct {
- hidden string
- NotNested int
- Nested struct {
- Inside int
- }
- }
-
- type containsDoubleNested struct {
- NotNested int
- Nested struct {
- InsideNested struct {
- Inside int
- }
- }
- }
-
- type ptrNested struct {
- Ptr *struct{ Inside int }
- }
-
- type dup struct { // more than one field of the same struct type
- A, B allBoolean
- }
-
- func TestNestedInference(t *testing.T) {
- testCases := []struct {
- in interface{}
- want Schema
- }{
- {
- in: containsNested{},
- want: Schema{
- reqField("NotNested", "INTEGER"),
- &FieldSchema{
- Name: "Nested",
- Required: true,
- Type: "RECORD",
- Schema: Schema{reqField("Inside", "INTEGER")},
- },
- },
- },
- {
- in: containsDoubleNested{},
- want: Schema{
- reqField("NotNested", "INTEGER"),
- &FieldSchema{
- Name: "Nested",
- Required: true,
- Type: "RECORD",
- Schema: Schema{
- {
- Name: "InsideNested",
- Required: true,
- Type: "RECORD",
- Schema: Schema{reqField("Inside", "INTEGER")},
- },
- },
- },
- },
- },
- {
- in: ptrNested{},
- want: Schema{
- &FieldSchema{
- Name: "Ptr",
- Required: true,
- Type: "RECORD",
- Schema: Schema{reqField("Inside", "INTEGER")},
- },
- },
- },
- {
- in: dup{},
- want: Schema{
- &FieldSchema{
- Name: "A",
- Required: true,
- Type: "RECORD",
- Schema: Schema{reqField("Bool", "BOOLEAN")},
- },
- &FieldSchema{
- Name: "B",
- Required: true,
- Type: "RECORD",
- Schema: Schema{reqField("Bool", "BOOLEAN")},
- },
- },
- },
- }
-
- for _, tc := range testCases {
- got, err := InferSchema(tc.in)
- if err != nil {
- t.Fatalf("%T: error inferring TableSchema: %v", tc.in, err)
- }
- if !testutil.Equal(got, tc.want) {
- t.Errorf("%T: inferring TableSchema: got:\n%#v\nwant:\n%#v", tc.in,
- pretty.Value(got), pretty.Value(tc.want))
- }
- }
- }
-
- type repeated struct {
- NotRepeated []byte
- RepeatedByteSlice [][]byte
- Slice []int
- Array [5]bool
- }
-
- type nestedRepeated struct {
- NotRepeated int
- Repeated []struct {
- Inside int
- }
- RepeatedPtr []*struct{ Inside int }
- }
-
- func repField(name, typ string) *FieldSchema {
- return &FieldSchema{
- Name: name,
- Type: FieldType(typ),
- Repeated: true,
- }
- }
-
- func TestRepeatedInference(t *testing.T) {
- testCases := []struct {
- in interface{}
- want Schema
- }{
- {
- in: repeated{},
- want: Schema{
- reqField("NotRepeated", "BYTES"),
- repField("RepeatedByteSlice", "BYTES"),
- repField("Slice", "INTEGER"),
- repField("Array", "BOOLEAN"),
- },
- },
- {
- in: nestedRepeated{},
- want: Schema{
- reqField("NotRepeated", "INTEGER"),
- {
- Name: "Repeated",
- Repeated: true,
- Type: "RECORD",
- Schema: Schema{reqField("Inside", "INTEGER")},
- },
- {
- Name: "RepeatedPtr",
- Repeated: true,
- Type: "RECORD",
- Schema: Schema{reqField("Inside", "INTEGER")},
- },
- },
- },
- }
-
- for i, tc := range testCases {
- got, err := InferSchema(tc.in)
- if err != nil {
- t.Fatalf("%d: error inferring TableSchema: %v", i, err)
- }
- if !testutil.Equal(got, tc.want) {
- t.Errorf("%d: inferring TableSchema: got:\n%#v\nwant:\n%#v", i,
- pretty.Value(got), pretty.Value(tc.want))
- }
- }
- }
-
- type allNulls struct {
- A NullInt64
- B NullFloat64
- C NullBool
- D NullString
- E NullTimestamp
- F NullTime
- G NullDate
- H NullDateTime
- }
-
- func TestNullInference(t *testing.T) {
- got, err := InferSchema(allNulls{})
- if err != nil {
- t.Fatal(err)
- }
- want := Schema{
- optField("A", "INTEGER"),
- optField("B", "FLOAT"),
- optField("C", "BOOLEAN"),
- optField("D", "STRING"),
- optField("E", "TIMESTAMP"),
- optField("F", "TIME"),
- optField("G", "DATE"),
- optField("H", "DATETIME"),
- }
- if diff := testutil.Diff(got, want); diff != "" {
- t.Error(diff)
- }
- }
-
- type Embedded struct {
- Embedded int
- }
-
- type embedded struct {
- Embedded2 int
- }
-
- type nestedEmbedded struct {
- Embedded
- embedded
- }
-
- func TestEmbeddedInference(t *testing.T) {
- got, err := InferSchema(nestedEmbedded{})
- if err != nil {
- t.Fatal(err)
- }
- want := Schema{
- reqField("Embedded", "INTEGER"),
- reqField("Embedded2", "INTEGER"),
- }
- if !testutil.Equal(got, want) {
- t.Errorf("got %v, want %v", pretty.Value(got), pretty.Value(want))
- }
- }
-
- func TestRecursiveInference(t *testing.T) {
- type List struct {
- Val int
- Next *List
- }
-
- _, err := InferSchema(List{})
- if err == nil {
- t.Fatal("got nil, want error")
- }
- }
-
- type withTags struct {
- NoTag int
- ExcludeTag int `bigquery:"-"`
- SimpleTag int `bigquery:"simple_tag"`
- UnderscoreTag int `bigquery:"_id"`
- MixedCase int `bigquery:"MIXEDcase"`
- Nullable []byte `bigquery:",nullable"`
- NullNumeric *big.Rat `bigquery:",nullable"`
- }
-
- type withTagsNested struct {
- Nested withTags `bigquery:"nested"`
- NestedAnonymous struct {
- ExcludeTag int `bigquery:"-"`
- Inside int `bigquery:"inside"`
- } `bigquery:"anon"`
- PNested *struct{ X int } // not nullable, for backwards compatibility
- PNestedNullable *struct{ X int } `bigquery:",nullable"`
- }
-
- type withTagsRepeated struct {
- Repeated []withTags `bigquery:"repeated"`
- RepeatedAnonymous []struct {
- ExcludeTag int `bigquery:"-"`
- Inside int `bigquery:"inside"`
- } `bigquery:"anon"`
- }
-
- type withTagsEmbedded struct {
- withTags
- }
-
- var withTagsSchema = Schema{
- reqField("NoTag", "INTEGER"),
- reqField("simple_tag", "INTEGER"),
- reqField("_id", "INTEGER"),
- reqField("MIXEDcase", "INTEGER"),
- optField("Nullable", "BYTES"),
- optField("NullNumeric", "NUMERIC"),
- }
-
- func TestTagInference(t *testing.T) {
- testCases := []struct {
- in interface{}
- want Schema
- }{
- {
- in: withTags{},
- want: withTagsSchema,
- },
- {
- in: withTagsNested{},
- want: Schema{
- &FieldSchema{
- Name: "nested",
- Required: true,
- Type: "RECORD",
- Schema: withTagsSchema,
- },
- &FieldSchema{
- Name: "anon",
- Required: true,
- Type: "RECORD",
- Schema: Schema{reqField("inside", "INTEGER")},
- },
- &FieldSchema{
- Name: "PNested",
- Required: true,
- Type: "RECORD",
- Schema: Schema{reqField("X", "INTEGER")},
- },
- &FieldSchema{
- Name: "PNestedNullable",
- Required: false,
- Type: "RECORD",
- Schema: Schema{reqField("X", "INTEGER")},
- },
- },
- },
- {
- in: withTagsRepeated{},
- want: Schema{
- &FieldSchema{
- Name: "repeated",
- Repeated: true,
- Type: "RECORD",
- Schema: withTagsSchema,
- },
- &FieldSchema{
- Name: "anon",
- Repeated: true,
- Type: "RECORD",
- Schema: Schema{reqField("inside", "INTEGER")},
- },
- },
- },
- {
- in: withTagsEmbedded{},
- want: withTagsSchema,
- },
- }
- for i, tc := range testCases {
- got, err := InferSchema(tc.in)
- if err != nil {
- t.Fatalf("%d: error inferring TableSchema: %v", i, err)
- }
- if !testutil.Equal(got, tc.want) {
- t.Errorf("%d: inferring TableSchema: got:\n%#v\nwant:\n%#v", i,
- pretty.Value(got), pretty.Value(tc.want))
- }
- }
- }
-
- func TestTagInferenceErrors(t *testing.T) {
- testCases := []struct {
- in interface{}
- err error
- }{
- {
- in: struct {
- LongTag int `bigquery:"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy"`
- }{},
- err: errInvalidFieldName,
- },
- {
- in: struct {
- UnsupporedStartChar int `bigquery:"øab"`
- }{},
- err: errInvalidFieldName,
- },
- {
- in: struct {
- UnsupportedEndChar int `bigquery:"abø"`
- }{},
- err: errInvalidFieldName,
- },
- {
- in: struct {
- UnsupportedMiddleChar int `bigquery:"aøb"`
- }{},
- err: errInvalidFieldName,
- },
- {
- in: struct {
- StartInt int `bigquery:"1abc"`
- }{},
- err: errInvalidFieldName,
- },
- {
- in: struct {
- Hyphens int `bigquery:"a-b"`
- }{},
- err: errInvalidFieldName,
- },
- }
- for i, tc := range testCases {
- want := tc.err
- _, got := InferSchema(tc.in)
- if got != want {
- t.Errorf("%d: inferring TableSchema: got:\n%#v\nwant:\n%#v", i, got, want)
- }
- }
-
- _, err := InferSchema(struct {
- X int `bigquery:",optional"`
- }{})
- if err == nil {
- t.Error("got nil, want error")
- }
- }
-
- func TestSchemaErrors(t *testing.T) {
- testCases := []struct {
- in interface{}
- err error
- }{
- {
- in: []byte{},
- err: errNoStruct,
- },
- {
- in: new(int),
- err: errNoStruct,
- },
- {
- in: struct{ Uint uint }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ Uint64 uint64 }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ Uintptr uintptr }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ Complex complex64 }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ Map map[string]int }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ Chan chan bool }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ Ptr *int }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ Interface interface{} }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ MultiDimensional [][]int }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ MultiDimensional [][][]byte }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ SliceOfPointer []*int }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ SliceOfNull []NullInt64 }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ ChanSlice []chan bool }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ NestedChan struct{ Chan []chan bool } }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct {
- X int `bigquery:",nullable"`
- }{},
- err: errBadNullable,
- },
- {
- in: struct {
- X bool `bigquery:",nullable"`
- }{},
- err: errBadNullable,
- },
- {
- in: struct {
- X struct{ N int } `bigquery:",nullable"`
- }{},
- err: errBadNullable,
- },
- {
- in: struct {
- X []int `bigquery:",nullable"`
- }{},
- err: errBadNullable,
- },
- {
- in: struct{ X *[]byte }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ X *[]int }{},
- err: errUnsupportedFieldType,
- },
- {
- in: struct{ X *int }{},
- err: errUnsupportedFieldType,
- },
- }
- for _, tc := range testCases {
- want := tc.err
- _, got := InferSchema(tc.in)
- if got != want {
- t.Errorf("%#v: got:\n%#v\nwant:\n%#v", tc.in, got, want)
- }
- }
- }
-
- func TestHasRecursiveType(t *testing.T) {
- type (
- nonStruct int
- nonRec struct{ A string }
- dup struct{ A, B nonRec }
- rec struct {
- A int
- B *rec
- }
- recUnexported struct {
- A int
- b *rec
- }
- hasRec struct {
- A int
- R *rec
- }
- recSlicePointer struct {
- A []*recSlicePointer
- }
- )
- for _, test := range []struct {
- in interface{}
- want bool
- }{
- {nonStruct(0), false},
- {nonRec{}, false},
- {dup{}, false},
- {rec{}, true},
- {recUnexported{}, false},
- {hasRec{}, true},
- {&recSlicePointer{}, true},
- } {
- got, err := hasRecursiveType(reflect.TypeOf(test.in), nil)
- if err != nil {
- t.Fatal(err)
- }
- if got != test.want {
- t.Errorf("%T: got %t, want %t", test.in, got, test.want)
- }
- }
- }
|