Repository: bxcodec/faker
Pull request #102 (2020-06-03 16:45:47)

Allow AddProvider to still work with some custom types
Before, even if using `AddProvider()` some custom types would not work, as there was no check for `mapperTag[tag]` function before calling `userDefinedArray()`.   
^ it would fail with `Tag unsupported: ....` even if provided with a tag!

Since `AddProvider()` can provide the ability to instantiate/manipulate the type, it would be great if when using `AddProvider()` the user could provide a tag that would work even for some custom types.   

If you comment out the changes I made to `faker.go` and run the tests `go test ./...` you will see the failure, even though `AddProvider()` was called to add the desired tag.

Fixes issue https://github.com/bxcodec/faker/issues/101



codecov[bot]: # [Codecov](https://codecov.io/gh/bxcodec/faker/pull/102?src=pr&el=h1) Report
> Merging [#102](https://codecov.io/gh/bxcodec/faker/pull/102?src=pr&el=desc) into [master](https://codecov.io/gh/bxcodec/faker/commit/9169c33ae9926e5b8f8732909790ee20b10b736a&el=desc) will **decrease** coverage by `0.14%`.
> The diff coverage is `83.33%`.

[![Impacted file tree graph](https://codecov.io/gh/bxcodec/faker/pull/102/graphs/tree.svg?width=650&height=150&src=pr&token=cLPGB7MHVc)](https://codecov.io/gh/bxcodec/faker/pull/102?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #102      +/-   ##
==========================================
- Coverage   95.04%   94.90%   -0.15%     
==========================================
  Files          10       10              
  Lines         989     1001      +12     
==========================================
+ Hits          940      950      +10     
- Misses         27       28       +1     
- Partials       22       23       +1     
```


| [Impacted Files](https://codecov.io/gh/bxcodec/faker/pull/102?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [faker.go](https://codecov.io/gh/bxcodec/faker/pull/102/diff?src=pr&el=tree#diff-ZmFrZXIuZ28=) | `90.67% <83.33%> (-0.20%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/bxcodec/faker/pull/102?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/bxcodec/faker/pull/102?src=pr&el=footer). Last update [9169c33...8f5d6a5](https://codecov.io/gh/bxcodec/faker/pull/102?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.md b/README.md
index 93311f2..1fd9682 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,7 @@ Unfortunately this library has some limitation
 * It does not support the `interface{}` data type. How could we generate anything without knowing its data type?
 * It does not support the `map[interface{}]interface{}`, `map[any_type]interface{}` & `map[interface{}]any_type` data types. Once again, we cannot generate values for an unknown data type.
 * Custom types are not fully supported. However some custom types are already supported: we are still investigating how to do this the correct way. For now, if you use `faker`, it's safer not to use any custom types in order to avoid panics.
+* Some extra custom types can be supported IF AND ONLY IF extended with [AddProvider()](https://github.com/bxcodec/faker/blob/9169c33ae9926e5b8f8732909790ee20b10b736a/faker.go#L320) please see [example](example_custom_faker_test.go#L46)
 
 ## Contribution
 
diff --git a/faker.go b/faker.go
index 3ab6650..1da4bc9 100644
--- a/faker.go
+++ b/faker.go
@@ -622,6 +622,21 @@ func setDataWithTag(v reflect.Value, tag string) error {
 		reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
 		return userDefinedNumber(v, tag)
 	case reflect.Slice, reflect.Array:
+		/**
+		 * check for added Provider tag first before
+		 * defaulting to userDefinedArray()
+		 * this way the user at least has the
+		 * option of a custom tag working
+		 */
+		_, tagExists := mapperTag[tag]
+		if tagExists {
+			res, err := mapperTag[tag](v)
+			if err != nil {
+				return err
+			}
+			v.Set(reflect.ValueOf(res))
+			return nil
+		}
 		return userDefinedArray(v, tag)
 	case reflect.Map:
 		return userDefinedMap(v, tag)


Test patch:
diff --git a/example_custom_faker_test.go b/example_custom_faker_test.go
index ee56e72..160a1ca 100644
--- a/example_custom_faker_test.go
+++ b/example_custom_faker_test.go
@@ -13,11 +13,15 @@ type Gondoruwo struct {
 	Locatadata int
 }
 
+// custom type that aliases over slice of byte
+type CustomUUID []byte
+
 // Sample ...
 type Sample struct {
 	ID        int64     `faker:"customIdFaker"`
 	Gondoruwo Gondoruwo `faker:"gondoruwo"`
 	Danger    string    `faker:"danger"`
+	UUID      CustomUUID `faker:"customUUID"`
 }
 
 // CustomGenerator ...
@@ -36,6 +40,13 @@ func CustomGenerator() {
 		}
 		return obj, nil
 	})
+
+	_ = faker.AddProvider("customUUID", func(v reflect.Value) (interface{}, error) {
+		s := []byte {
+			0,8,7,2,3,
+		}
+		return s, nil
+	})
 }
 
 // You can also add your own generator function to your own defined tags.
@@ -45,5 +56,5 @@ func Example_customFaker() {
 	_ = faker.FakeData(&sample)
 	fmt.Printf("%+v", sample)
 	// Output:
-	// {ID:43 Gondoruwo:{Name:Power Locatadata:324} Danger:danger-ranger}
+	// {ID:43 Gondoruwo:{Name:Power Locatadata:324} Danger:danger-ranger UUID:[0 8 7 2 3]}
 }
diff --git a/faker_test.go b/faker_test.go
index fb5be3a..91ec250 100644
--- a/faker_test.go
+++ b/faker_test.go
@@ -908,6 +908,11 @@ type School struct {
 	Location string
 }
 
+type CustomTypeOverSlice []byte
+type CustomThatUsesSlice struct {
+	UUID CustomTypeOverSlice `faker:"custom-type-over-slice"`
+}
+
 func TestExtend(t *testing.T) {
 	// This test is to ensure that faker can be extended new providers
 
@@ -961,6 +966,30 @@ func TestExtend(t *testing.T) {
 		}
 	})
 
+	/**
+	 * Before updates, this test would fail
+	 */
+	t.Run("test-with-custom-slice-type", func(t *testing.T) {
+		a := CustomThatUsesSlice{}
+		err := AddProvider("custom-type-over-slice", func(v reflect.Value) (interface{}, error) {
+			return []byte{0,1,2,3,4}, nil
+		})
+
+		if err != nil {
+			t.Error("Expected Not Error, But Got: ", err)
+		}
+
+		err = FakeData(&a)
+
+		if err != nil {
+			t.Error("Expected Not Error, But Got: ", err)
+		}
+
+		if reflect.DeepEqual(a.UUID, []byte{0,1,2,3,4}) {
+			t.Error("UUID should equal test value")
+		}
+	})
+
 }
 
 func TestTagAlreadyExists(t *testing.T) {