From 87be2d97907952e87203bd3a4b09cfbe49ce028d Mon Sep 17 00:00:00 2001
From: Alex Flint <alex.flint@gmail.com>
Date: Thu, 2 May 2019 09:28:17 -0700
Subject: [PATCH] add unittests for canParse

---
 parse.go        | 55 ------------------------------------------
 reflect.go      | 64 +++++++++++++++++++++++++++++++++++++++++++++++++
 reflect_test.go | 40 +++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+), 55 deletions(-)
 create mode 100644 reflect.go
 create mode 100644 reflect_test.go

diff --git a/parse.go b/parse.go
index 2a3442a..0633bb6 100644
--- a/parse.go
+++ b/parse.go
@@ -1,7 +1,6 @@
 package arg
 
 import (
-	"encoding"
 	"encoding/csv"
 	"errors"
 	"fmt"
@@ -659,60 +658,6 @@ func setSlice(dest reflect.Value, values []string, trunc bool) error {
 	return nil
 }
 
-// canParse returns true if the type can be parsed from a string
-func canParse(t reflect.Type) (parseable, boolean, multiple bool) {
-	parseable = scalar.CanParse(t)
-	boolean = isBoolean(t)
-	if parseable {
-		return
-	}
-
-	// Look inside pointer types
-	if t.Kind() == reflect.Ptr {
-		t = t.Elem()
-	}
-	// Look inside slice types
-	if t.Kind() == reflect.Slice {
-		multiple = true
-		t = t.Elem()
-	}
-
-	parseable = scalar.CanParse(t)
-	boolean = isBoolean(t)
-	if parseable {
-		return
-	}
-
-	// Look inside pointer types (again, in case of []*Type)
-	if t.Kind() == reflect.Ptr {
-		t = t.Elem()
-	}
-
-	parseable = scalar.CanParse(t)
-	boolean = isBoolean(t)
-	if parseable {
-		return
-	}
-
-	return false, false, false
-}
-
-var textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem()
-
-// isBoolean returns true if the type can be parsed from a single string
-func isBoolean(t reflect.Type) bool {
-	switch {
-	case t.Implements(textUnmarshalerType):
-		return false
-	case t.Kind() == reflect.Bool:
-		return true
-	case t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Bool:
-		return true
-	default:
-		return false
-	}
-}
-
 // findOption finds an option from its name, or returns null if no spec is found
 func findOption(specs []*spec, name string) *spec {
 	for _, spec := range specs {
diff --git a/reflect.go b/reflect.go
new file mode 100644
index 0000000..32efe04
--- /dev/null
+++ b/reflect.go
@@ -0,0 +1,64 @@
+package arg
+
+import (
+	"encoding"
+	"reflect"
+
+	scalar "github.com/alexflint/go-scalar"
+)
+
+var textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem()
+
+// This file contains miscellaneous reflection utilities
+
+// canParse returns true if the type can be parsed from a string
+func canParse(t reflect.Type) (parseable, boolean, multiple bool) {
+	parseable = scalar.CanParse(t)
+	boolean = isBoolean(t)
+	if parseable {
+		return
+	}
+
+	// Look inside pointer types
+	if t.Kind() == reflect.Ptr {
+		t = t.Elem()
+	}
+	// Look inside slice types
+	if t.Kind() == reflect.Slice {
+		multiple = true
+		t = t.Elem()
+	}
+
+	parseable = scalar.CanParse(t)
+	boolean = isBoolean(t)
+	if parseable {
+		return
+	}
+
+	// Look inside pointer types (again, in case of []*Type)
+	if t.Kind() == reflect.Ptr {
+		t = t.Elem()
+	}
+
+	parseable = scalar.CanParse(t)
+	boolean = isBoolean(t)
+	if parseable {
+		return
+	}
+
+	return false, false, false
+}
+
+// isBoolean returns true if the type can be parsed from a single string
+func isBoolean(t reflect.Type) bool {
+	switch {
+	case t.Implements(textUnmarshalerType):
+		return false
+	case t.Kind() == reflect.Bool:
+		return true
+	case t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Bool:
+		return true
+	default:
+		return false
+	}
+}
diff --git a/reflect_test.go b/reflect_test.go
new file mode 100644
index 0000000..0f285f7
--- /dev/null
+++ b/reflect_test.go
@@ -0,0 +1,40 @@
+package arg
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func assertCanParse(t *testing.T, typ reflect.Type, parseable, boolean, multiple bool) {
+	p, b, m := canParse(typ)
+	assert.Equal(t, parseable, p, "expected %v to have parseable=%v but was %v", typ, parseable, p)
+	assert.Equal(t, boolean, b, "expected %v to have boolean=%v but was %v", typ, boolean, b)
+	assert.Equal(t, multiple, m, "expected %v to have multiple=%v but was %v", typ, multiple, m)
+}
+
+func TestCanParse(t *testing.T) {
+	var b bool
+	var i int
+	var s string
+	var f float64
+	var bs []bool
+	var is []int
+
+	assertCanParse(t, reflect.TypeOf(b), true, true, false)
+	assertCanParse(t, reflect.TypeOf(i), true, false, false)
+	assertCanParse(t, reflect.TypeOf(s), true, false, false)
+	assertCanParse(t, reflect.TypeOf(f), true, false, false)
+
+	assertCanParse(t, reflect.TypeOf(&b), true, true, false)
+	assertCanParse(t, reflect.TypeOf(&s), true, false, false)
+	assertCanParse(t, reflect.TypeOf(&i), true, false, false)
+	assertCanParse(t, reflect.TypeOf(&f), true, false, false)
+
+	assertCanParse(t, reflect.TypeOf(bs), true, true, true)
+	assertCanParse(t, reflect.TypeOf(&bs), true, true, true)
+
+	assertCanParse(t, reflect.TypeOf(is), true, false, true)
+	assertCanParse(t, reflect.TypeOf(&is), true, false, true)
+}