Repository: bxcodec/faker (go)

Issue:
Faking a UUID panics
I had a complex struct generating a panic from faker and I isolated it to the uuid field causing the issue.
Here's the minimal code to show the error:

```
package main

import (
	"github.com/bxcodec/faker"
	"github.com/gofrs/uuid"
	"fmt"
)

func main() {
	var u uuid.UUID
	faker.FakeData(&u)
	fmt.Println(u)
}
```

And the error trace is:
```
panic: reflect.MakeSlice of non-slice type

goroutine 1 [running]:
reflect.MakeSlice(0x11367c0, 0x1104fe0, 0x58, 0x58, 0xc420065cc8, 0xc420065cd8, 0x1010068)
	/usr/local/Cellar/go/1.10.3/libexec/src/reflect/value.go:2092 +0x1ce
github.com/bxcodec/faker.getValue(0x11367c0, 0x1104fe0, 0x1104fe0, 0xc4200aa250, 0x16, 0x0, 0x10)
	/Users/msorens/code/go/src/github.com/bxcodec/faker/faker.go:218 +0x7a9
github.com/bxcodec/faker.FakeData(0x110c840, 0xc4200aa250, 0xc42008a058, 0x0)
	/Users/msorens/code/go/src/github.com/bxcodec/faker/faker.go:145 +0x1bc
main.main()
	/Users/msorens/code/go/src/github.com/me/fake/tryfake.go:11 +0x4b
exit status 2
```

Pull request:
feat: UUID Generator
Added Identifier for faker.

Usage:
`faker:"uuid_digit"` xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
`faker:"uuid_hyphenated"` xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

close #39 

Patch:
diff --git a/.gitignore b/.gitignore
index d45334d..54ad996 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,8 @@
 # Output of the go coverage tool, specifically when used with LiteIDE
 *.out
 cover.html
+.vscode/
+
 
 # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
 .glide/
diff --git a/README.md b/README.md
index 1a7980c..9eba3f3 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,10 @@ Supported tag:
 * Amount
 * Amount with Currency
 
+**UUID :**
+* UUID Digit (32 bytes)
+* UUID Hyphenated (36 bytes)
+
 **Skip :**
 * \-
 
@@ -146,6 +150,8 @@ type SomeStruct struct {
 	Currency           string  `faker:"currency"`
 	Amount             float64 `faker:"amount"`
 	AmountWithCurrency string  `faker:"amount_with_currency"`
+	UUIDHypenated	   string  `faker:"uuid_hyphenated"`
+	UUID	           string  `faker:"uuid_digit"`
 	Skip		   string  `faker:"-"`
 }
 
@@ -198,6 +204,8 @@ func main() {
 			Currency: IRR,
 			Amount: 88.990000,
 			AmountWithCurrency: XBB 49257.100000,
+			UUIDHypenated: 8f8e4463-9560-4a38-9b0c-ef24481e4e27,
+			UUID: 90ea6479fd0e4940af741f0a87596b73,
 			Skip:
 		}
 	*/
diff --git a/faker.go b/faker.go
index 3b4c47e..7efb40c 100644
--- a/faker.go
+++ b/faker.go
@@ -20,6 +20,8 @@ const (
 	letterIdxMax       = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
 	letterBytes        = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
 	tagName            = "faker"
+	ID                 = "uuid_digit"
+	HyphenatedID       = "uuid_hyphenated"
 	Email              = "email"
 	MacAddress         = "mac_address"
 	DomainName         = "domain_name"
@@ -102,6 +104,8 @@ var mapperTag = map[string]interface{}{
 	Currency:           GetPrice().Currency,
 	Amount:             GetPrice().Amount,
 	AmountWithCurrency: GetPrice().AmountWithCurrency,
+	ID:                 GetIdentifier().Digit,
+	HyphenatedID:       GetIdentifier().Hyphenated,
 }
 
 // Generic Error Messages for tags
diff --git a/uuid.go b/uuid.go
new file mode 100644
index 0000000..e260da8
--- /dev/null
+++ b/uuid.go
@@ -0,0 +1,54 @@
+package faker
+
+import (
+	"crypto/rand"
+	"fmt"
+	"io"
+)
+
+var identifier Identifier
+
+// GetIdentifier returns a new Identifier
+func GetIdentifier() Identifier {
+	mu.Lock()
+	defer mu.Unlock()
+
+	if identifier == nil {
+		identifier = &UUID{}
+	}
+	return identifier
+}
+
+// Identifier ...
+type Identifier interface {
+	Digit() string
+	Hyphenated() string
+}
+
+// UUID struct
+type UUID struct{}
+
+// createUUID returns a 16 byte slice with random values
+func createUUID() []byte {
+	b := make([]byte, 16)
+	io.ReadFull(rand.Reader, b)
+	// variant bits; see section 4.1.1
+	b[8] = b[8]&^0xc0 | 0x80
+	// version 4 (pseudo-random); see section 4.1.3
+	b[6] = b[6]&^0xf0 | 0x40
+	return b
+}
+
+// Hyphenated returns a 36 byte hyphenated UUID
+func (i UUID) Hyphenated() string {
+	b := createUUID()
+	uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
+	return uuid
+}
+
+// Digit returns a 32 bytes UUID
+func (i UUID) Digit() string {
+	b := createUUID()
+	uuid := fmt.Sprintf("%x", b)
+	return uuid
+}


Test patch:
diff --git a/faker_test.go b/faker_test.go
index bd58d5f..e7db415 100644
--- a/faker_test.go
+++ b/faker_test.go
@@ -49,6 +49,8 @@ type SomeStruct struct {
 	Currency           string  `faker:"currency"`
 	Amount             float64 `faker:"amount"`
 	AmountWithCurrency string  `faker:"amount_with_currency"`
+	ID                 string  `faker:"uuid_digit"`
+	HyphenatedID       string  `faker:"uuid_hyphenated"`
 
 	MapStringString        map[string]string
 	MapStringStruct        map[string]AStruct
@@ -107,6 +109,8 @@ type TaggedStruct struct {
 	Currency           string  `faker:"currency"`
 	Amount             float32 `faker:"amount"`
 	AmountWithCurrency string  `faker:"amount_with_currency"`
+	ID                 string  `faker:"uuid_digit"`
+	HyphenatedID       string  `faker:"uuid_hyphenated"`
 }
 
 func (t TaggedStruct) String() string {
@@ -149,6 +153,8 @@ func (t TaggedStruct) String() string {
 	Currency: %s,
 	Amount: %f,
 	AmountWithCurrency: %s,
+	HyphenatedID: %s,
+	ID: %s,
 }`, t.Latitude, t.Longitude, t.CreditCardNumber,
 		t.CreditCardType, t.Email, t.IPV4,
 		t.IPV6, t.Password, t.PhoneNumber, t.MacAddress,
@@ -160,6 +166,7 @@ func (t TaggedStruct) String() string {
 		t.DayOfMonth, t.Timestamp, t.Century, t.TimeZone,
 		t.TimePeriod, t.Word, t.Sentence, t.Paragraph,
 		t.Currency, t.Amount, t.AmountWithCurrency,
+		t.HyphenatedID, t.ID,
 	)
 }
 
diff --git a/uuid_test.go b/uuid_test.go
new file mode 100644
index 0000000..e3ea26c
--- /dev/null
+++ b/uuid_test.go
@@ -0,0 +1,33 @@
+package faker
+
+import (
+	"fmt"
+	"regexp"
+	"testing"
+)
+
+func TestDigit(t *testing.T) {
+	p := GetIdentifier()
+	uuid := p.Digit()
+	if match, err := regexp.Match("^[a-zA-Z0-9]{32}$", []byte(uuid)); !match || err != nil {
+		t.Errorf("Could not match the UUID format, err: %+v, match: %+v", err, match)
+	}
+}
+
+func TestHyphenated(t *testing.T) {
+	p := GetIdentifier()
+	uuid := p.Hyphenated()
+	exp := "[a-zA-Z 0-9]"
+	pattern := fmt.Sprintf("^%s{8}-%s{4}-%s{4}-%s{4}-%s{12}$", exp, exp, exp, exp, exp)
+	if match, err := regexp.Match(pattern, []byte(uuid)); !match || err != nil {
+		t.Errorf("Could not match the UUID hyphenated format, err: %+v, match: %+v", err, match)
+	}
+
+}
+
+func TestGetIdentifier(t *testing.T) {
+	identifier := GetIdentifier()
+	if identifier == nil {
+		t.Fatalf("TestGetIdentifier failed because identifier was nil")
+	}
+}