Repository: bxcodec/faker
Pull request #123 (2020-10-28 00:12:12)

feat: Add ability to ignore interface{} population with SetIgnoreInterface()
This PR adds a flag that tells faker to ignore the population of interface{} types.

This is useful when populating complex structures for Marshal testing, where you don't have the control or ability to use a non-interface{}. This makes testing complex structure marshaling a LOT simpler, since otherwise you would have to faker every element in the structure above and beside an interface{}.

The default behavior is to not ignore interface{}, so no behavior changes should be seen.

A test has been added.

Thanks!

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

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

```diff
@@            Coverage Diff             @@
##           master     #123      +/-   ##
==========================================
- Coverage   93.87%   92.33%   -1.54%     
==========================================
  Files          11       11              
  Lines        1289     1083     -206     
==========================================
- Hits         1210     1000     -210     
- Misses         43       45       +2     
- Partials       36       38       +2     
```


| [Impacted Files](https://codecov.io/gh/bxcodec/faker/pull/123?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [faker.go](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree#diff-ZmFrZXIuZ28=) | `90.59% <100.00%> (-0.67%)` | :arrow_down: |
| [internet.go](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree#diff-aW50ZXJuZXQuZ28=) | `76.69% <0.00%> (-6.64%)` | :arrow_down: |
| [uuid.go](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree#diff-dXVpZC5nbw==) | `82.35% <0.00%> (-3.37%)` | :arrow_down: |
| [datetime.go](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree#diff-ZGF0ZXRpbWUuZ28=) | `97.46% <0.00%> (-0.80%)` | :arrow_down: |
| [lorem.go](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree#diff-bG9yZW0uZ28=) | `100.00% <0.00%> (ø)` | |
| [phone.go](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree#diff-cGhvbmUuZ28=) | `100.00% <0.00%> (ø)` | |
| [price.go](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree#diff-cHJpY2UuZ28=) | `100.00% <0.00%> (ø)` | |
| [person.go](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree#diff-cGVyc29uLmdv) | `100.00% <0.00%> (ø)` | |
| [address.go](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree#diff-YWRkcmVzcy5nbw==) | `100.00% <0.00%> (ø)` | |
| ... and [2 more](https://codecov.io/gh/bxcodec/faker/pull/123/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/bxcodec/faker/pull/123?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/123?src=pr&el=footer). Last update [02fc1b2...2b2d2a5](https://codecov.io/gh/bxcodec/faker/pull/123?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

bxcodec: Hi @nashikb 

Thanks for the PR, I was so busy lately, haven't seen this repo for a while. 
Is using ignore tag doesn't help?

```go
type Person struct {
  Metadata interface{} `faker:"-"`
}
```

Patch:
diff --git a/faker.go b/faker.go
index d10ccd5..d97bd3a 100644
--- a/faker.go
+++ b/faker.go
@@ -30,6 +30,8 @@ var (
 	randomSize = 100
 	// Sets the single fake data generator to generate unique values
 	generateUniqueValues = false
+	// Sets whether interface{}s should be ignored.
+	ignoreInterface = false
 	// Unique values are kept in memory so the generator retries if the value already exists
 	uniqueValues = map[string][]interface{}{}
 	// Lang is selected language for random string generator
@@ -278,6 +280,11 @@ func SetGenerateUniqueValues(unique bool) {
 	generateUniqueValues = unique
 }
 
+// SetIgnoreInterface allows to set a flag to ignore found interface{}s.
+func SetIgnoreInterface(ignore bool) {
+	ignoreInterface = ignore
+}
+
 // SetNilIfLenIsZero allows to set nil for the slice and maps, if size is 0.
 func SetNilIfLenIsZero(setNil bool) {
 	shouldSetNil = setNil
@@ -407,6 +414,9 @@ func RemoveProvider(tag string) error {
 func getValue(a interface{}) (reflect.Value, error) {
 	t := reflect.TypeOf(a)
 	if t == nil {
+		if ignoreInterface {
+			return reflect.New(reflect.TypeOf(reflect.Struct)), nil
+		}
 		return reflect.Value{}, fmt.Errorf("interface{} not allowed")
 	}
 	k := t.Kind()
@@ -1098,12 +1108,16 @@ func randomString(n int, lang *langRuneBoundary) (string, error) {
 
 // randomIntegerWithBoundary returns a random integer between input start and end boundary. [start, end)
 func randomIntegerWithBoundary(boundary numberBoundary) int {
-	return rand.Intn(boundary.end-boundary.start) + boundary.start
+	span := boundary.end - boundary.start
+	if span <= 0 {
+		return boundary.start
+	}
+	return rand.Intn(span) + boundary.start
 }
 
 // randomInteger returns a random integer between start and end boundary. [start, end)
 func randomInteger() int {
-	return rand.Intn(nBoundary.end-nBoundary.start) + nBoundary.start
+	return randomIntegerWithBoundary(nBoundary)
 }
 
 // randomSliceAndMapSize returns a random integer between [0,randomSliceAndMapSize). If the testRandZero is set, returns 0
diff --git a/person.go b/person.go
index 26cd0a9..dc9ccb9 100644
--- a/person.go
+++ b/person.go
@@ -26,7 +26,7 @@ var titlesFemale = []string{
 	"Mrs.", "Ms.", "Miss", "Dr.", "Prof.", "Lady", "Queen", "Princess",
 }
 var firstNamesMale = []string{
-	"Aaron", "Abdiel", "Abdul", "Abdullah", "Abe", "Abel", "Abelardo", "Abner", "Abraham", "Adalberto", "Adam", "Adan", "Adelbert", "Adolf", "Adolfo", "Adolph", "Adolphus", "Adonis", "Adrain", "Adrian", "Adriel", "Adrien", "Afton", "Agustin", "Ahmad", "Ahmed", "Aidan", "Aiden", "Akeem", "Al", "Alan", "Albert", "Alberto", "Albin", "Alden", "Alec", "Alejandrin", "Alek", "Alessandro", "Alex", "Alexander", "Alexandre", "Alexandro", "Alexie", "Alexis", "Alexys", "Alexzander", "Alf", "Alfonso", "Alfonzo", "Alford", "Alfred", "Alfredo", "Ali", "Allan", "Allen", "Alphonso", "Alvah", "Alvis", "Amani", "Amari", "Ambrose", "Americo", "Amir", "Amos", "Amparo", "Anastacio", "Anderson", "Andre", "Andres", "Andrew", "Andy", "Angel", "Angelo", "Angus", "Anibal", "Ansel", "Ansley", "Anthony", "Antone", "Antonio", "Antwan", "Antwon", "Arch", "Archibald", "Arden", "Arely", "Ari", "Aric", "Ariel", "Arjun", "Arlo", "Armand", "Armando", "Armani", "Arnaldo", "Arne", "Arno", "Arnold", "Arnoldo", "Arnulfo", "Aron", "Art", "Arthur", "Arturo", "Arvel", "Arvid", "Ashton", "August", "Augustus", "Aurelio", "Austen", "Austin", "Austyn", "Avery", "Axel", "Ayden",
+	"Aaron", "Abdiel", "Abdul", "Abdullah", "Abe", "Abel", "Abelardo", "Abner", "Abraham", "Adalberto", "Adam", "Adan", "Adelbert", "Adolfo", "Adolph", "Adolphus", "Adonis", "Adrain", "Adrian", "Adriel", "Adrien", "Afton", "Agustin", "Ahmad", "Ahmed", "Aidan", "Aiden", "Akeem", "Al", "Alan", "Albert", "Alberto", "Albin", "Alden", "Alec", "Alejandrin", "Alek", "Alessandro", "Alex", "Alexander", "Alexandre", "Alexandro", "Alexie", "Alexis", "Alexys", "Alexzander", "Alf", "Alfonso", "Alfonzo", "Alford", "Alfred", "Alfredo", "Ali", "Allan", "Allen", "Alphonso", "Alvah", "Alvis", "Amani", "Amari", "Ambrose", "Americo", "Amir", "Amos", "Amparo", "Anastacio", "Anderson", "Andre", "Andres", "Andrew", "Andy", "Angel", "Angelo", "Angus", "Anibal", "Ansel", "Ansley", "Anthony", "Antone", "Antonio", "Antwan", "Antwon", "Arch", "Archibald", "Arden", "Arely", "Ari", "Aric", "Ariel", "Arjun", "Arlo", "Armand", "Armando", "Armani", "Arnaldo", "Arne", "Arno", "Arnold", "Arnoldo", "Arnulfo", "Aron", "Art", "Arthur", "Arturo", "Arvel", "Arvid", "Ashton", "August", "Augustus", "Aurelio", "Austen", "Austin", "Austyn", "Avery", "Axel", "Ayden",
 	"Bailey", "Barney", "Baron", "Barrett", "Barry", "Bart", "Bartholome", "Barton", "Baylee", "Beau", "Bell", "Ben", "Benedict", "Benjamin", "Bennett", "Bennie", "Benny", "Benton", "Bernard", "Bernardo", "Bernhard", "Bernie", "Berry", "Berta", "Bertha", "Bertram", "Bertrand", "Bill", "Billy", "Blair", "Blaise", "Blake", "Blaze", "Bo", "Bobbie", "Bobby", "Boris", "Boyd", "Brad", "Braden", "Bradford", "Bradley", "Bradly", "Brady", "Braeden", "Brain", "Brando", "Brandon", "Brandt", "Brannon", "Branson", "Brant", "Braulio", "Braxton", "Brayan", "Brendan", "Brenden", "Brendon", "Brennan", "Brennon", "Brent", "Bret", "Brett", "Brian", "Brice", "Brock", "Broderick", "Brody", "Brook", "Brooks", "Brown", "Bruce", "Bryce", "Brycen", "Bryon", "Buck", "Bud", "Buddy", "Buford", "Burley", "Buster",
 	"Cade", "Caden", "Caesar", "Cale", "Caleb", "Camden", "Cameron", "Camren", "Camron", "Camryn", "Candelario", "Candido", "Carey", "Carleton", "Carlo", "Carlos", "Carmel", "Carmelo", "Carmine", "Carol", "Carroll", "Carson", "Carter", "Cary", "Casey", "Casimer", "Casimir", "Casper", "Ceasar", "Cecil", "Cedrick", "Celestino", "Cesar", "Chad", "Chadd", "Chadrick", "Chaim", "Chance", "Chandler", "Charles", "Charley", "Charlie", "Chase", "Chauncey", "Chaz", "Chelsey", "Chesley", "Chester", "Chet", "Chris", "Christ", "Christian", "Christop", "Christophe", "Christopher", "Cicero", "Cielo", "Clair", "Clark", "Claud", "Claude", "Clay", "Clemens", "Clement", "Cleo", "Cletus", "Cleve", "Cleveland", "Clifford", "Clifton", "Clint", "Clinton", "Clovis", "Cloyd", "Clyde", "Coby", "Cody", "Colby", "Cole", "Coleman", "Colin", "Collin", "Colt", "Colten", "Colton", "Columbus", "Conner", "Connor", "Conor", "Conrad", "Constantin", "Consuelo", "Cooper", "Corbin", "Cordelia", "Cordell", "Cornelius", "Cornell", "Cortez", "Cory", "Coty", "Coy", "Craig", "Crawford", "Cristian", "Cristina", "Cristobal", "Cristopher", "Cruz", "Cullen", "Curt", "Curtis", "Cyril", "Cyrus",
 	"Dagmar", "Dale", "Dallas", "Dallin", "Dalton", "Dameon", "Damian", "Damien", "Damion", "Damon", "Dan", "Dane", "D\"angelo", "Dangelo", "Danial", "Danny", "Dante", "Daren", "Darian", "Darien", "Dario", "Darion", "Darius", "Daron", "Darrel", "Darrell", "Darren", "Darrick", "Darrin", "Darrion", "Darron", "Darryl", "Darwin", "Daryl", "Dashawn", "Dave", "David", "Davin", "Davion", "Davon", "Davonte", "Dawson", "Dax", "Dayne", "Dayton", "Dean", "Deangelo", "Declan", "Dedric", "Dedrick", "Dee", "Deion", "Dejon", "Dejuan", "Delaney", "Delbert", "Dell", "Delmer", "Demarco", "Demarcus", "Demario", "Demetrius", "Demond", "Denis", "Dennis", "Deon", "Deondre", "Deontae", "Deonte", "Dereck", "Derek", "Derick", "Deron", "Derrick", "Deshaun", "Deshawn", "Desmond", "Destin", "Devan", "Devante", "Deven", "Devin", "Devon", "Devonte", "Devyn", "Dewayne", "Dewitt", "Dexter", "Diamond", "Diego", "Dillan", "Dillon", "Dimitri", "Dino", "Dion", "Dock", "Domenic", "Domenick", "Domenico", "Domingo", "Dominic", "Don", "Donald", "Donato", "Donavon", "Donnell", "Donnie", "Donny", "Dorcas", "Dorian", "Doris", "Dorthy", "Doug", "Douglas", "Doyle", "Drake", "Dudley", "Duncan", "Durward", "Dustin", "Dusty", "Dwight", "Dylan",


Test patch:
diff --git a/faker_test.go b/faker_test.go
index e8dce13..7fff340 100644
--- a/faker_test.go
+++ b/faker_test.go
@@ -482,6 +482,19 @@ func TestSetNilIfLenIsZero(t *testing.T) {
 	testRandZero = false
 }
 
+func TestSetIgnoreInterface(t *testing.T) {
+	SetIgnoreInterface(false)
+	var someInterface interface{}
+	if err := FakeData(&someInterface); err == nil {
+		t.Error("Fake data generation didn't fail on interface{}")
+	}
+	SetIgnoreInterface(true)
+	if err := FakeData(&someInterface); err != nil {
+		t.Error("Fake data generation fail on interface{} with SetIgnoreInterface(true)")
+	}
+	SetIgnoreInterface(false)
+}
+
 func TestBoundaryAndLen(t *testing.T) {
 	iterate := 10
 	someStruct := SomeStructWithLen{}