Repository: bxcodec/faker
Pull request #141 (2021-06-03 08:29:52)

fix slice tag bug AND add chinese name
# fix bug
```
AdCode[]string `json:"ad_code" xorm:"ad_code" faker:"len=slice_len=5,len=10"` 
```
return：
```
{AdCode:[rMZLe XgkhW IZHBZ qEaWa nwrKJ]}
```

but
```
AdCode[]string `json:"ad_code" xorm:"ad_code" faker:"len=10,slice_len=5"`
```
return:
```
{AdCode:[RotjXUZmnq MTbKBCQhJC PedUsSqIwv xTnlUgWajY PBENmHwGfc]}
```
# features
- add chinese_first_name
- add chinese_last_name
- add chinese_name 

qiangmzsx: I don't see the previously committed code being merged into master, is there anything I need to do?
bxcodec: Sorry, there's a linter issue. Not sure why, it's passed before merged to master, but it failed now. 
bxcodec: Can you help to fix the linter?
qiangmzsx: I will deal with it as soon as possible and submit the code
qiangmzsx: Through testing I found some problems with the code I wrote before and fixed them. Now it should be ready for merging, thanks!
qiangmzsx: Thanks for the review. I have made the changes and would appreciate your review again.
bxcodec: Hey @qiangmzsx  I think it's conflict, can you rebase your code from the master, and apply your changes?
qiangmzsx: I'm very sorry! This was my problem, caused by not doing a pull of the latest code for a long time, and I have fixed it. Request another review.
bxcodec: Hey @qiangmzsx 
reviewed, a minor change, also I have a question. Please address when you're free thank you 🙇🏻 
qiangmzsx: > 

I'm online today, so feel free to communicate with me if you need anything.
qiangmzsx: My email address is qiangmzsx@hotmail.com 。

Patch:
diff --git a/faker.go b/faker.go
index 2248af6..d237a61 100644
--- a/faker.go
+++ b/faker.go
@@ -102,6 +102,9 @@ const (
 	FirstNameFemaleTag    = "first_name_female"
 	LastNameTag           = "last_name"
 	NAME                  = "name"
+	ChineseFirstNameTag   = "chinese_first_name"
+	ChineseLastNameTag    = "chinese_last_name"
+	ChineseNameTag        = "chinese_name"
 	GENDER                = "gender"
 	UnixTimeTag           = "unix_time"
 	DATE                  = "date"
@@ -134,6 +137,15 @@ const (
 	//hyphen = "-"
 )
 
+// PriorityTags define the priority order of the tag
+var PriorityTags = []string{ID, HyphenatedID, EmailTag, MacAddressTag, DomainNameTag, UserNameTag, URLTag, IPV4Tag,
+	IPV6Tag, PASSWORD, JWT, LATITUDE, LONGITUDE, CreditCardNumber, CreditCardType, PhoneNumber, TollFreeNumber,
+	E164PhoneNumberTag, TitleMaleTag, TitleFemaleTag, FirstNameTag, FirstNameMaleTag, FirstNameFemaleTag, LastNameTag,
+	NAME, ChineseFirstNameTag, ChineseLastNameTag, ChineseNameTag, GENDER, UnixTimeTag, DATE, TIME, MonthNameTag,
+	YEAR, DayOfWeekTag, DayOfMonthTag, TIMESTAMP, CENTURY, TIMEZONE, TimePeriodTag, WORD, SENTENCE, PARAGRAPH,
+	CurrencyTag, AmountTag, AmountWithCurrencyTag, SKIP, Length, SliceLength, Language, BoundaryStart, BoundaryEnd, ONEOF,
+}
+
 var defaultTag = map[string]string{
 	EmailTag:              EmailTag,
 	MacAddressTag:         MacAddressTag,
@@ -158,6 +170,9 @@ var defaultTag = map[string]string{
 	FirstNameFemaleTag:    FirstNameFemaleTag,
 	LastNameTag:           LastNameTag,
 	NAME:                  NAME,
+	ChineseFirstNameTag:   ChineseFirstNameTag,
+	ChineseLastNameTag:    ChineseLastNameTag,
+	ChineseNameTag:        ChineseNameTag,
 	GENDER:                GENDER,
 	UnixTimeTag:           UnixTimeTag,
 	DATE:                  DATE,
@@ -208,6 +223,9 @@ var mapperTag = map[string]TaggedFunction{
 	FirstNameFemaleTag:    GetPerson().FirstNameFemale,
 	LastNameTag:           GetPerson().LastName,
 	NAME:                  GetPerson().Name,
+	ChineseFirstNameTag:   GetPerson().ChineseFirstName,
+	ChineseLastNameTag:    GetPerson().ChineseLastName,
+	ChineseNameTag:        GetPerson().ChineseName,
 	GENDER:                GetPerson().Gender,
 	UnixTimeTag:           GetDateTimer().UnixTime,
 	DATE:                  GetDateTimer().Date,
@@ -422,7 +440,7 @@ func AddProvider(tag string, provider TaggedFunction) error {
 	if _, ok := mapperTag[tag]; ok {
 		return errors.New(ErrTagAlreadyExists)
 	}
-
+	PriorityTags = append(PriorityTags, tag)
 	mapperTag[tag] = provider
 
 	return nil
@@ -640,11 +658,13 @@ func isZero(field reflect.Value) (bool, error) {
 }
 
 func decodeTags(typ reflect.Type, i int) structTag {
-	tags := strings.Split(typ.Field(i).Tag.Get(tagName), ",")
+	tagField := typ.Field(i).Tag.Get(tagName)
+	tags := strings.Split(tagField, ",")
 
 	keepOriginal := false
 	uni := false
 	res := make([]string, 0)
+	pMap := make(map[string]string)
 	for _, tag := range tags {
 		if tag == keep {
 			keepOriginal = true
@@ -653,7 +673,28 @@ func decodeTags(typ reflect.Type, i int) structTag {
 			uni = true
 			continue
 		}
-		res = append(res, tag)
+		// res = append(res, tag)
+		ptag := strings.ToLower(strings.Trim(strings.Split(tag, "=")[0], " "))
+		pMap[ptag] = tag
+		ptag = strings.ToLower(strings.Trim(strings.Split(tag, ":")[0], " "))
+		pMap[ptag] = tag
+	}
+	// Priority
+	for _, ptag := range PriorityTags {
+		if tag, ok := pMap[ptag]; ok {
+			if ptag == ONEOF {
+				res = append(res, tags...)
+			} else {
+				res = append(res, tag)
+			}
+			delete(pMap, ptag)
+		}
+	}
+	// custom,keep,unique
+	if len(res) < 1 {
+		if !keepOriginal && !uni {
+			res = append(res, tags...)
+		}
 	}
 
 	return structTag{
diff --git a/person.go b/person.go
index 8123fa1..569bade 100644
--- a/person.go
+++ b/person.go
@@ -15,6 +15,9 @@ type Dowser interface {
 	LastName(v reflect.Value) (interface{}, error)
 	Name(v reflect.Value) (interface{}, error)
 	Gender(v reflect.Value) (interface{}, error)
+	ChineseFirstName(v reflect.Value) (interface{}, error)
+	ChineseLastName(v reflect.Value) (interface{}, error)
+	ChineseName(v reflect.Value) (interface{}, error)
 }
 
 var person Dowser
@@ -111,6 +114,60 @@ var randNameFlag int
 
 var genders = []string{"Male", "Female", "Prefer to skip"}
 
+var chineseFirstNames = []string{
+	"赵", "钱", "孙", "李", "周", "吴", "郑", "王", "冯", "陈", "褚", "卫", "蒋", "沈", "韩", "杨", "朱", "秦", "尤", "许",
+	"何", "吕", "施", "张", "孔", "曹", "严", "华", "金", "魏", "陶", "姜", "戚", "谢", "邹", "喻", "柏", "水", "窦", "章",
+	"云", "苏", "潘", "葛", "奚", "范", "彭", "郎", "鲁", "韦", "昌", "马", "苗", "凤", "花", "方", "俞", "任", "袁", "柳",
+	"酆", "鲍", "史", "唐", "费", "廉", "岑", "薛", "雷", "贺", "倪", "汤", "滕", "殷", "罗", "毕", "郝", "邬", "安", "常",
+	"乐", "于", "时", "傅", "皮", "卞", "齐", "康", "伍", "余", "元", "卜", "顾", "孟", "平", "黄", "和", "穆", "萧", "尹",
+	"姚", "邵", "湛", "汪", "祁", "毛", "禹", "狄", "米", "贝", "明", "臧", "计", "伏", "成", "戴", "谈", "宋", "茅", "庞",
+	"熊", "纪", "舒", "屈", "项", "祝", "董", "梁", "杜", "阮", "蓝", "闵", "席", "季", "麻", "强", "贾", "路", "娄", "危",
+	"江", "童", "颜", "郭", "梅", "盛", "林", "刁", "钟", "徐", "邱", "骆", "高", "夏", "蔡", "田", "樊", "胡", "凌", "霍",
+	"虞", "万", "支", "柯", "昝", "管", "卢", "莫", "经", "房", "裘", "缪", "干", "解", "应", "宗", "丁", "宣", "贲", "邓",
+	"郁", "单", "杭", "洪", "包", "诸", "左", "石", "崔", "吉", "钮", "龚", "程", "嵇", "邢", "滑", "裴", "陆", "荣", "翁",
+	"荀", "羊", "於", "惠", "甄", "麴", "家", "封", "芮", "羿", "储", "靳", "汲", "邴", "糜", "松", "井", "段", "富", "巫",
+	"乌", "焦", "巴", "弓", "牧", "隗", "山", "谷", "车", "侯", "宓", "蓬", "全", "郗", "班", "仰", "秋", "仲", "伊", "宫",
+	"宁", "仇", "栾", "暴", "甘", "钭", "厉", "戎", "祖", "武", "符", "刘", "景", "詹", "束", "龙", "叶", "幸", "司", "韶",
+	"郜", "黎", "蓟", "薄", "印", "宿", "白", "怀", "蒲", "邰", "从", "鄂", "索", "咸", "籍", "赖", "卓", "蔺", "屠", "蒙",
+	"池", "乔", "阴", "郁", "胥", "能", "苍", "双", "闻", "莘", "党", "翟", "谭", "贡", "劳", "逄", "姬", "申", "扶", "堵",
+	"冉", "宰", "郦", "雍", "舄", "璩", "桑", "桂", "濮", "牛", "寿", "通", "边", "扈", "燕", "冀", "郏", "浦", "尚", "农",
+	"温", "别", "庄", "晏", "柴", "瞿", "阎", "充", "慕", "连", "茹", "习", "宦", "艾", "鱼", "容", "向", "古", "易", "慎",
+	"戈", "廖", "庾", "终", "暨", "居", "衡", "步", "都", "耿", "满", "弘", "匡", "国", "文", "寇", "广", "禄", "阙", "东",
+	"殴", "殳", "沃", "利", "蔚", "越", "夔", "隆", "师", "巩", "厍", "聂", "晁", "勾", "敖", "融", "冷", "訾", "辛", "阚",
+	"那", "简", "饶", "空", "曾", "毋", "沙", "乜", "养", "鞠", "须", "丰", "巢", "关", "蒯", "相", "查", "後", "荆", "红",
+	"游", "竺", "权", "逯", "盖", "益", "桓", "公", "司马", "上官", "欧阳", "夏侯", "诸葛",
+}
+
+var chineseLastNames = []string{
+	"澄邈", "德泽", "海超", "海阳", "海荣", "海逸", "海昌", "瀚钰", "瀚文", "涵亮", "涵煦", "明宇",
+	"涵衍", "浩皛", "浩波", "浩博", "浩初", "浩宕", "浩歌", "浩广", "浩邈", "浩气", "浩思", "浩言",
+	"鸿宝", "鸿波", "鸿博", "鸿才", "鸿畅", "鸿畴", "鸿达", "鸿德", "鸿飞", "鸿风", "鸿福", "鸿光",
+	"鸿晖", "鸿朗", "鸿文", "鸿轩", "鸿煊", "鸿骞", "鸿远", "鸿云", "鸿哲", "鸿祯", "鸿志", "鸿卓",
+	"嘉澍", "光济", "澎湃", "彭泽", "鹏池", "鹏海", "浦和", "浦泽", "瑞渊", "越泽", "博耘", "德运",
+	"辰宇", "辰皓", "辰钊", "辰铭", "辰锟", "辰阳", "辰韦", "辰良", "辰沛", "晨轩", "晨涛", "晨濡",
+	"晨潍", "鸿振", "吉星", "铭晨", "起运", "运凡", "运凯", "运鹏", "运浩", "运诚", "运良", "运鸿",
+	"运锋", "运盛", "运升", "运杰", "运珧", "运骏", "运凯", "运乾", "维运", "运晟", "运莱", "运华",
+	"耘豪", "星爵", "星腾", "星睿", "星泽", "星鹏", "星然", "震轩", "震博", "康震", "震博", "振强",
+	"振博", "振华", "振锐", "振凯", "振海", "振国", "振平", "昂然", "昂雄", "昂杰", "昂熙", "昌勋",
+	"昌盛", "昌淼", "昌茂", "昌黎", "昌燎", "昌翰", "晨朗", "德明", "德昌", "德曜", "范明", "飞昂",
+	"高旻", "晗日", "昊然", "昊天", "昊苍", "昊英", "昊宇", "昊嘉", "昊明", "昊伟", "昊硕", "昊磊",
+	"昊东", "鸿晖", "鸿朗", "华晖", "金鹏", "晋鹏", "敬曦", "景明", "景天", "景浩", "俊晖", "君昊",
+	"昆锐", "昆卉", "昆峰", "昆颉", "昆谊", "昆皓", "昆鹏", "昆明", "昆杰", "昆雄", "昆纶", "鹏涛",
+	"依秋", "依波", "香巧", "紫萱", "涵易", "忆之", "幻巧", "美倩", "安寒", "白亦", "惜玉", "碧春",
+	"怜雪", "听南", "念蕾", "紫夏", "凌旋", "芷梦", "凌寒", "梦竹", "千凡", "丹蓉", "慧贞", "思菱",
+	"平卉", "笑柳", "雪卉", "南蓉", "谷梦", "巧兰", "绿蝶", "飞荷", "佳蕊", "芷荷", "怀瑶", "慕易",
+	"若芹", "紫安", "曼冬", "寻巧", "雅昕", "尔槐", "以旋", "初夏", "依丝", "怜南", "傲菡", "谷蕊",
+	"笑槐", "飞兰", "笑卉", "迎荷", "佳音", "梦君", "妙绿", "觅雪", "寒安", "沛凝", "白容", "乐蓉",
+	"映安", "依云", "映冬", "凡雁", "梦秋", "梦凡", "秋巧", "若云", "元容", "怀蕾", "灵寒", "天薇",
+	"翠安", "乐琴", "宛南", "怀蕊", "白风", "访波", "亦凝", "易绿", "夜南", "曼凡", "亦巧", "青易",
+	"冰真", "白萱", "友安", "海之", "小蕊", "又琴", "天风", "若松", "盼菡", "秋荷", "香彤", "语梦",
+	"惜蕊", "迎彤", "沛白", "雁彬", "易蓉", "雪晴", "诗珊", "春冬", "晴钰", "冰绿", "半梅", "笑容",
+	"沛凝", "映秋", "盼烟", "晓凡", "涵雁", "问凝", "冬萱", "晓山", "雁蓉", "梦蕊", "山菡", "南莲",
+	"飞双", "凝丝", "思萱", "怀梦", "雨梅", "冷霜", "向松", "迎丝", "迎梅", "雅彤", "香薇", "以山",
+	"碧萱", "寒云", "向南", "书雁", "怀薇", "思菱", "忆文", "翠巧", "书文", "若山", "向秋", "凡白",
+	"绮烟", "从蕾", "天曼", "又亦", "从语", "绮彤", "之玉", "凡梅", "依琴", "沛槐", "又槐", "元绿",
+}
+
 // GetPerson returns a new Dowser interface of Person struct
 func GetPerson() Dowser {
 	mu.Lock()
@@ -269,3 +326,54 @@ func Gender() string {
 		return p.gender()
 	}).(string)
 }
+
+// ChineseFirstName returns a random chinese first name
+func (p Person) ChineseFirstName(v reflect.Value) (interface{}, error) {
+	return p.chineseFirstName(), nil
+}
+
+func (p Person) chineseFirstName() string {
+	return randomElementFromSliceString(chineseFirstNames)
+}
+
+// ChineseFirstName get chinese first name
+func ChineseFirstName() string {
+	return singleFakeData(ChineseFirstNameTag, func() interface{} {
+		p := Person{}
+		return p.chineseFirstName()
+	}).(string)
+}
+
+// ChineseLastName returns a random chinese last name
+func (p Person) ChineseLastName(v reflect.Value) (interface{}, error) {
+	return p.chineseLastName(), nil
+}
+
+func (p Person) chineseLastName() string {
+	return randomElementFromSliceString(chineseLastNames)
+}
+
+// ChineseLastName get chinese lsst name
+func ChineseLastName() string {
+	return singleFakeData(ChineseLastNameTag, func() interface{} {
+		p := Person{}
+		return p.chineseLastName()
+	}).(string)
+}
+
+// ChineseName returns a random nhinese name
+func (p Person) ChineseName(v reflect.Value) (interface{}, error) {
+	return p.chineseName(), nil
+}
+
+func (p Person) chineseName() string {
+	return fmt.Sprintf("%s%s", randomElementFromSliceString(chineseFirstNames), randomElementFromSliceString(chineseLastNames))
+}
+
+// ChineseName get chinese lsst name
+func ChineseName() string {
+	return singleFakeData(ChineseNameTag, func() interface{} {
+		p := Person{}
+		return p.chineseName()
+	}).(string)
+}


Test patch:
diff --git a/faker_test.go b/faker_test.go
index c1b39bc..eef3064 100644
--- a/faker_test.go
+++ b/faker_test.go
@@ -33,6 +33,34 @@ var (
 	sliceLenIncorrectTags = [3]string{"slice_len=b", "slice_len=-1", "slice_len=-10"}
 )
 
+type Coupon struct {
+	ID         int      `json:"id" xorm:"id"`
+	BrokerCode string   `json:"broker_code" xorm:"broker_code"`
+	IgetUID    int      `json:"iget_uid" xorm:"iget_uid"`
+	CreateTime string   `json:"create_time" xorm:"create_time"`
+	CFirstName string   `json:"chinese_first_name" faker:"chinese_first_name"`
+	CLsstName  string   `json:"chinese_last_name" faker:"chinese_last_name"`
+	CName      string   `json:"name" faker:"chinese_name"`
+	AdNames    []string `json:"ad_name" xorm:"ad_name" faker:"slice_len=5,len=10"` // faker:"len=10,slice_len=5"
+	CdNames    []string `json:"cd_name" xorm:"cd_name" faker:"len=10,slice_len=5"` //
+}
+
+func TestPLen(t *testing.T) {
+	coupon := Coupon{}
+	err := FakeData(&coupon)
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+	if len(coupon.AdNames[0]) != 10 || len(coupon.AdNames) != 5 {
+		t.Fatal("slice len is error")
+	}
+	if len(coupon.CdNames[0]) != 10 || len(coupon.CdNames) != 5 {
+		t.Fatal("slice len is error")
+	}
+	t.Logf("%+v\n", coupon)
+}
+
 type SomeInt32 int32
 
 type TArray [16]byte
@@ -224,6 +252,9 @@ type TaggedStruct struct {
 	FirstNameFemale    string  `faker:"first_name_female"`
 	LastName           string  `faker:"last_name"`
 	Name               string  `faker:"name"`
+	ChineseFirstName   string  `faker:"chinese_first_name"`
+	ChineseLastName    string  `faker:"chinese_last_name"`
+	ChineseName        string  `faker:"chinese_name"`
 	UnixTime           int64   `faker:"unix_time"`
 	Date               string  `faker:"date"`
 	Time               string  `faker:"time"`
@@ -394,19 +425,28 @@ func TestSetDataIfArgumentNotHaveReflect(t *testing.T) {
 
 func TestSetDataErrorDataParseTagStringType(t *testing.T) {
 	temp := &struct {
-		Test string `faker:"test"`
+		Test string `faker:"test_no_exist"`
 	}{}
-	fmt.Printf("%+v ", temp)
+	for idx, tag := range PriorityTags {
+		if tag == "test_no_exist" {
+			PriorityTags[idx] = ""
+		}
+	}
 	if err := FakeData(temp); err == nil {
-		t.Error("Exptected error Unsupported tag, but got nil")
+		t.Error("Exptected error Unsupported tag, but got nil", temp, err)
 	}
+
 }
 
 func TestSetDataErrorDataParseTagIntType(t *testing.T) {
 	temp := &struct {
-		Test int `faker:"test"`
+		Test int `faker:"test_no_exist"`
 	}{}
-
+	for idx, tag := range PriorityTags {
+		if tag == "test_no_exist" {
+			PriorityTags[idx] = ""
+		}
+	}
 	if err := FakeData(temp); err == nil {
 		t.Error("Expected error Unsupported tag, but got nil")
 	}
@@ -1672,6 +1712,7 @@ func TestOneOfTag__BadInputsForFloats(t *testing.T) {
 		err := FakeData(&a)
 		if err == nil {
 			t.Errorf("expected error, but got no error")
+			return
 		}
 		actual := err.Error()
 		expected := ErrNotEnoughTagArguments
@@ -1705,7 +1746,7 @@ func TestOneOfTag__BadInputsForFloats(t *testing.T) {
 		a := CustomWrongFloat9{}
 		err := FakeData(&a)
 		if err == nil {
-			t.Fatal("expected error, but got no error")
+			t.Fatal("expected error, but got no error", err)
 		}
 		actual := err.Error()
 		expected := ErrUnsupportedTagArguments
@@ -1809,11 +1850,13 @@ func TestOneOfTag__BadInputsForInts(t *testing.T) {
 
 	type CustomTypeInt64Wrong struct {
 		Age int64 `faker:"oneof: 1_000_000, oops"`
+		Avg int64 `faker:"boundary_start=31, boundary_end=88"`
 	}
 
 	t.Run("should error for int64 with bad tag arguments", func(t *testing.T) {
 		a := CustomTypeInt64Wrong{}
 		err := FakeData(&a)
+		t.Log(a.Age, a.Avg)
 		if err == nil {
 			t.Errorf("expected error but got nil")
 		}
diff --git a/person_test.go b/person_test.go
index ce98a47..421ad37 100644
--- a/person_test.go
+++ b/person_test.go
@@ -147,6 +147,7 @@ func TestFakeNameFemale(t *testing.T) {
 	if name == "" {
 		t.Error("Expected from function name string get empty string")
 	}
+	t.Log(name)
 }
 
 func TestFakeGender(t *testing.T) {
@@ -165,3 +166,33 @@ func TestFakeGenderPublicFunction(t *testing.T) {
 		t.Error("Expected value from variable genders in function Gender")
 	}
 }
+
+func TestChineseFirstName(t *testing.T) {
+	firstname, err := GetPerson().ChineseFirstName(reflect.Value{})
+	if err != nil {
+		t.Error("Expected  not error, got err", err)
+	}
+	t.Log(firstname)
+	if !slice.Contains(chineseFirstNames, firstname.(string)) {
+		t.Error("Expected value from either chineseFirstNames in function ChineseFirstName")
+	}
+}
+
+func TestChineseLastName(t *testing.T) {
+	firstname, err := GetPerson().ChineseLastName(reflect.Value{})
+	if err != nil {
+		t.Error("Expected  not error, got err", err)
+	}
+	t.Log(firstname)
+	if !slice.Contains(chineseLastNames, firstname.(string)) {
+		t.Error("Expected value from either chineseLastNames in function ChineseLastName")
+	}
+}
+
+func TestChineseName(t *testing.T) {
+	firstname, err := GetPerson().ChineseName(reflect.Value{})
+	if err != nil {
+		t.Error("Expected  not error, got err", err)
+	}
+	t.Log(firstname)
+}