From 983eb7b54fe3502d3febcf4c4100717e946be98f Mon Sep 17 00:00:00 2001 From: Ben Vezzani Date: Fri, 27 Nov 2020 22:02:22 -0500 Subject: [PATCH] Tests for dialect and datatypes (#2) --- internal/datatype/datatypes_test.go | 270 ++++++++++++++++++++++++++++ internal/dbms/base/dialect.go | 2 +- internal/dbms/base/dialect_test.go | 57 ++++++ internal/dbms/base/errors.go | 27 --- internal/dbms/mysql/migrator.go | 3 +- 5 files changed, 330 insertions(+), 29 deletions(-) create mode 100644 internal/dbms/base/dialect_test.go delete mode 100644 internal/dbms/base/errors.go diff --git a/internal/datatype/datatypes_test.go b/internal/datatype/datatypes_test.go index ab273d1..2e0df20 100644 --- a/internal/datatype/datatypes_test.go +++ b/internal/datatype/datatypes_test.go @@ -2,6 +2,7 @@ package datatype import ( "gopkg.in/yaml.v2" + "reflect" "testing" ) @@ -120,3 +121,272 @@ func TestDatatype_UnmarshalYAML(t *testing.T) { }) } } + +func TestDatatype_String(t *testing.T) { + tests := []struct { + dt Datatype + want string + }{ + { + dt: Integer, + want: integer, + }, + { + dt: TinyInt, + want: tinyint, + }, + { + dt: SmallInt, + want: smallint, + }, + { + dt: MediumInt, + want: mediumint, + }, + { + dt: BigInt, + want: bigint, + }, + { + dt: Decimal, + want: decimal, + }, + { + dt: Varchar, + want: varchar, + }, + { + dt: Text, + want: text, + }, + { + dt: TinyText, + want: tinytext, + }, + { + dt: MediumText, + want: mediumtext, + }, + { + dt: LongText, + want: longtext, + }, + { + dt: Char, + want: char, + }, + { + dt: Blob, + want: blob, + }, + { + dt: Enum, + want: enum, + }, + { + dt: Boolean, + want: boolean, + }, + { + dt: 123123, + want: "NONE", + }, + } + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := tt.dt.String(); got != tt.want { + t.Errorf("String() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDatatype_IsInt(t *testing.T) { + tests := []struct { + dt Datatype + want bool + }{ + { + dt: Integer, + want: true, + }, + { + dt: Text, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.dt.String(), func(t *testing.T) { + if got := tt.dt.IsInt(); got != tt.want { + t.Errorf("IsInt() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDatatype_IsNumeric(t *testing.T) { + tests := []struct { + dt Datatype + want bool + }{ + { + dt: Integer, + want: true, + }, + { + dt: Decimal, + want: true, + }, + { + dt: Text, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.dt.String(), func(t *testing.T) { + if got := tt.dt.IsNumeric(); got != tt.want { + t.Errorf("IsNumeric() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDatatype_IsBinary(t *testing.T) { + tests := []struct { + dt Datatype + want bool + }{ + { + dt: Integer, + want: false, + }, + { + dt: Decimal, + want: false, + }, + { + dt: Text, + want: false, + }, + { + dt: Blob, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.dt.String(), func(t *testing.T) { + if got := tt.dt.IsBinary(); got != tt.want { + t.Errorf("IsNumeric() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDatatype_RequiresScale(t *testing.T) { + tests := []struct { + dt Datatype + want bool + }{ + { + dt: Integer, + want: false, + }, + { + dt: Decimal, + want: true, + }, + { + dt: Text, + want: false, + }, + { + dt: Enum, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.dt.String(), func(t *testing.T) { + if got := tt.dt.RequiresScale(); got != tt.want { + t.Errorf("IsNumeric() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDatatype_IsString(t *testing.T) { + tests := []struct { + dt Datatype + want bool + }{ + { + dt: Integer, + want: false, + }, + { + dt: Decimal, + want: false, + }, + { + dt: Text, + want: true, + }, + { + dt: Enum, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.dt.String(), func(t *testing.T) { + if got := tt.dt.IsString(); got != tt.want { + t.Errorf("IsNumeric() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDatatype_IsSignable(t *testing.T) { + tests := []struct { + dt Datatype + want bool + }{ + { + dt: Integer, + want: true, + }, + { + dt: Decimal, + want: true, + }, + { + dt: Text, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.dt.String(), func(t *testing.T) { + if got := tt.dt.IsSignable(); got != tt.want { + t.Errorf("IsNumeric() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDatatype_MarshalYAML(t *testing.T) { + tests := []struct { + dt Datatype + want string + }{ + { + dt: Integer, + want: "integer", + }, + } + for _, tt := range tests { + t.Run(tt.dt.String(), func(t *testing.T) { + got, _ := tt.dt.MarshalYAML() + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("MarshalYAML() got = %v, want %v", got, tt.want) + } + }) + } +} \ No newline at end of file diff --git a/internal/dbms/base/dialect.go b/internal/dbms/base/dialect.go index bd7a7f7..2afa44c 100644 --- a/internal/dbms/base/dialect.go +++ b/internal/dbms/base/dialect.go @@ -13,7 +13,7 @@ func (d *Base) TypeString(dt datatype.Datatype) (string, error) { s := dt.String() if s == "NONE" { - return "", d.InvalidDatatype(dt) + return "", datatype.UnknownDatatype } return s, nil diff --git a/internal/dbms/base/dialect_test.go b/internal/dbms/base/dialect_test.go new file mode 100644 index 0000000..ccc39bb --- /dev/null +++ b/internal/dbms/base/dialect_test.go @@ -0,0 +1,57 @@ +package base + +import ( + "github.com/dotvezz/yoyo/internal/datatype" + "testing" +) + +func TestBase_TypeString(t *testing.T) { + type fields struct { + Dialect string + } + type args struct { + dt datatype.Datatype + } + tests := []struct { + fields fields + args args + want string + wantErr bool + }{ + { + fields: fields{ + Dialect: "mysql", + }, + args: args{ + dt: datatype.Integer, + }, + want: "INTEGER", + wantErr: false, + }, + { + fields: fields{ + Dialect: "mysql", + }, + args: args{ + dt: 0, + }, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.args.dt.String(), func(t *testing.T) { + d := &Base{ + Dialect: tt.fields.Dialect, + } + got, err := d.TypeString(tt.args.dt) + if (err != nil) != tt.wantErr { + t.Errorf("TypeString() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("TypeString() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/dbms/base/errors.go b/internal/dbms/base/errors.go deleted file mode 100644 index f06de22..0000000 --- a/internal/dbms/base/errors.go +++ /dev/null @@ -1,27 +0,0 @@ -package base - -import ( - "errors" - "fmt" - "github.com/dotvezz/yoyo/internal/datatype" -) - -// Errors returned from functions or methods in the `dialect` package MUST: -// 1. Wrap exactly one error from this list of vars -// OR -// 2. Be an error from this list of vars -var ( - // InvalidDatatype is an error to use when a datatype referenced does not match anyything in the `datatype` package - InvalidDatatype = errors.New("invalid datatype") - // unsupportedDatatype is an error to use when a datatype is valid, but not supported in the current operation or - // by the current dialect - UnsupportedDatatype = errors.New("unsupported datatype") -) - -func (*Base) InvalidDatatype(dt datatype.Datatype) error { - return fmt.Errorf("%w: datatype `%s` is invalid", InvalidDatatype, dt) -} - -func (d *Base) UnsupportedDatatype(dt datatype.Datatype) error { - return fmt.Errorf("%w: %s does not support %s", UnsupportedDatatype, d.Dialect, dt) -} diff --git a/internal/dbms/mysql/migrator.go b/internal/dbms/mysql/migrator.go index 145a54c..e42a285 100644 --- a/internal/dbms/mysql/migrator.go +++ b/internal/dbms/mysql/migrator.go @@ -1,6 +1,7 @@ package mysql import ( + "errors" "fmt" "github.com/dotvezz/yoyo/internal/datatype" "github.com/dotvezz/yoyo/internal/dbms/base" @@ -23,7 +24,7 @@ type migrator struct { func (d *migrator) TypeString(dt datatype.Datatype) (s string, err error) { if dt&datatype.MySQL != datatype.MySQL { - return "", d.UnsupportedDatatype(dt) + return "", errors.New("unsupported datatype") } switch dt { case datatype.Integer: