Skip to content
This repository has been archived by the owner on Mar 11, 2021. It is now read-only.

Commit

Permalink
Table driven tests for SimpleType, EnumType and ListType. (#115)
Browse files Browse the repository at this point in the history
* table drive tests for SimpleType. WIP

* conflict fix
added pkg govalidator to glide

* added KindList and updated related tests.

* Basic Enum tests added.

* variable declaration factored into blocks.

* Test cases added for available Types. #115

These test cases are testing ConvertToModel function of the Type. Also added fixes in existing ConvertToModel as needed.
Few validations are added in Conversion logic. govalidator lib is added for the validations like IsURL.

Fixes: #77
  • Loading branch information
pranavgore09 authored and kwk committed Aug 18, 2016
1 parent 829fdae commit 72a5560
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 11 deletions.
8 changes: 6 additions & 2 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ import:
subpackages:
- gocov
- package: github.com/wadey/gocovmerge
- package: gopkg.in/asaskevich/govalidator.v4
134 changes: 134 additions & 0 deletions models/fieldtype_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package models

import "testing"

var (
stString = SimpleType{KindString}
stInt = SimpleType{KindInteger}
stFloat = SimpleType{KindFloat}
stDuration = SimpleType{KindDuration}
stURL = SimpleType{KindURL}
stList = SimpleType{KindList}
)

type input struct {
t FieldType
value interface{}
expectedValue interface{}
errorExpected bool
}

func TestSimpleTypeConversion(t *testing.T) {
test_data := []input{
{stString, "hello world", "hello world", false},
{stString, "", "", false},
{stString, 100, nil, true},
{stString, 1.90, nil, true},

{stInt, 100.0, nil, true},
{stInt, 100, 100, false},
{stInt, "100", nil, true},
{stInt, true, nil, true},

{stFloat, 1.1, 1.1, false},
{stFloat, 1, nil, true},
{stFloat, "a", nil, true},

{stDuration, 0, 0, false},
{stDuration, 1.1, nil, true},
{stDuration, "duration", nil, true},

{stURL, "http://www.google.com", "http://www.google.com", false},
{stURL, "", nil, true},
{stURL, "google", nil, true},
{stURL, "http://google.com", "http://google.com", false},

{stList, [4]int{1, 2, 3, 4}, [4]int{1, 2, 3, 4}, false},
{stList, [2]string{"1", "2"}, [2]string{"1", "2"}, false},
{stList, "", nil, true},
// {stList, []int{}, []int{}, false}, need to find out the way for empty array.
// because slices do not have equality operator.
}
for _, inp := range test_data {
retVal, err := inp.t.ConvertToModel(inp.value)
if retVal == inp.expectedValue && (err != nil) == inp.errorExpected {
t.Log("test pass for input: ", inp)
} else {
t.Error(retVal, err)
t.Fail()
}
}
}

var (
stEnum = SimpleType{KindEnum}
enum = EnumType{
BaseType: stEnum,
// ENUM with same type values
Values: []interface{}{"new", "triaged", "WIP", "QA", "done"},
}

multipleTypeEnum = EnumType{
BaseType: stEnum,
// ENUM with different type values.
Values: []interface{}{100, 1.1, "hello"},
}
)

func TestEnumTypeConversion(t *testing.T) {
data := []input{
{enum, "string", nil, true},
{enum, "triaged", "triaged", false},
{enum, "done", "done", false},
{enum, "", nil, true},
{enum, 100, nil, true},

{multipleTypeEnum, "abcd", nil, true},
{multipleTypeEnum, 100, 100, false},
{multipleTypeEnum, "hello", "hello", false},
}
for _, inp := range data {
retVal, err := inp.t.ConvertToModel(inp.value)
if retVal == inp.expectedValue && (err != nil) == inp.errorExpected {
t.Log("test pass for input: ", inp)
} else {
t.Error(retVal, err)
t.Fail()
}
}
}

var (
intList = ListType{
SimpleType: SimpleType{KindList},
ComponentType: SimpleType{KindInteger},
}
strList = ListType{
SimpleType: SimpleType{KindList},
ComponentType: SimpleType{KindString},
}
)

func TestListTypeConversion(t *testing.T) {
data := []input{
{intList, [2]int{11, 2}, "array/slice", false},
{intList, [2]string{"11", "2"}, nil, true},

{strList, [2]string{"11", "2"}, "array/slice", false},
{strList, [2]int{11, 2}, nil, true},
}

for _, inp := range data {
// Ignore expectedValue for now.
// slices can be compared only with nil.
// Because we will need to iterate and match the output.
retVal, err := inp.t.ConvertToModel(inp.value)
if (err != nil) == inp.errorExpected {
t.Log("test pass for input: ", inp)
} else {
t.Error("failed for input=", inp)
t.Error(retVal, err)
t.Fail()
}
}
}
11 changes: 6 additions & 5 deletions models/list_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ func convertList(converter converter, fieldType ListType, value interface{}) (in
// the assumption is that work item types do not change over time...only new ones can be created
valueType := reflect.TypeOf(value)

if valueType.Kind() != reflect.Array {
return nil, fmt.Errorf("value %v should be %s, but is %s", value, "array", valueType.Name())
if (valueType.Kind() != reflect.Array) && (valueType.Kind() != reflect.Slice) {
return nil, fmt.Errorf("value %v should be %s, but is %s", value, "array/slice", valueType.Name())
}
valueArray := value.([]interface{})
converted := make([]interface{}, len(valueArray))
valueArray := reflect.ValueOf(value)
converted := make([]interface{}, valueArray.Len())
for i := range converted {
var err error
converted[i], err = converter(fieldType, valueArray[i])
// valueArray index value must be converted to Interface else it has TYPE=Value
converted[i], err = converter(fieldType.ComponentType, valueArray.Index(i).Interface())
if err != nil {
return nil, fmt.Errorf("error converting list value: %s", err.Error())
}
Expand Down
27 changes: 23 additions & 4 deletions models/simple_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"reflect"
"strconv"
"time"

"github.com/asaskevich/govalidator"
)

// SimpleType is an unstructured FieldType
Expand All @@ -23,18 +25,28 @@ var timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
func (fieldType SimpleType) ConvertToModel(value interface{}) (interface{}, error) {
valueType := reflect.TypeOf(value)
switch fieldType.GetKind() {
case KindString, KindURL, KindUser:
case KindString, KindUser:
if valueType.Kind() != reflect.String {
return nil, fmt.Errorf("value %v should be %s, but is %s", value, "string", valueType.Name())
}
return value, nil
case KindInteger, KindFloat, KindDuration:
// instant == milliseconds
case KindURL:
if valueType.Kind() == reflect.String && govalidator.IsURL(value.(string)) {
return value, nil
}
return nil, fmt.Errorf("value %v should be %s, but is %s", value, "URL", valueType.Name())
case KindFloat:
if valueType.Kind() != reflect.Float64 {
return nil, fmt.Errorf("value %v should be %s, but is %s", value, "float64", valueType.Name())
}
return value, nil
case KindInteger, KindDuration:
if valueType.Kind() != reflect.Int {
return nil, fmt.Errorf("value %v should be %s, but is %s", value, "int", valueType.Name())
}
return value, nil
case KindInstant:
// instant == milliseconds
if !valueType.Implements(timeType) {
return nil, fmt.Errorf("value %v should be %s, but is %s", value, "time.Time", valueType.Name())
}
Expand All @@ -45,7 +57,14 @@ func (fieldType SimpleType) ConvertToModel(value interface{}) (interface{}, erro
}
idValue, err := strconv.Atoi(value.(string))
return idValue, err

case KindList:
if (valueType.Kind() != reflect.Array) && (valueType.Kind() != reflect.Slice) {
return nil, fmt.Errorf("value %v should be %s, but is %s,", value, "array/slice", valueType.Kind())
}
return value, nil
case KindEnum:
// to be done yet | not sure what to write here as of now.
return value, nil
default:
return nil, fmt.Errorf("unexpected type constant: %d", fieldType.GetKind())
}
Expand Down

0 comments on commit 72a5560

Please sign in to comment.