Skip to content

Commit

Permalink
randx:新增生成随机code方法 (#207)
Browse files Browse the repository at this point in the history
* 优化slice的delete方法的性能

* 添加到ChangeLog中

* 新增生成随机code方法

* 修改changelog

* randx:修改代码提升可读性提升

* randx:增加测试覆盖

* randx:测试修改为table driven方式

* randx:测试修改

---------

Signed-off-by: Zhang Cancan <[email protected]>
  • Loading branch information
cancan927 authored Sep 8, 2023
1 parent e76aae0 commit abbebbd
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
- [slice: 添加Add函数,在指定位置插入元素](https://github.com/ecodeclub/ekit/pull/201)
- [slice: 优化delete方法,无需从头开始遍历](https://github.com/ecodeclub/ekit/pull/203)
- [slice: 重构 slice 中使用 equalFunc 的方法](https://github.com/ecodeclub/ekit/pull/205)
- [randx: 新增生成随机code方法](https://github.com/ecodeclub/ekit/pull/207)
- [slice: intersect方法优化, symmetricDiffSet重构](https://github.com/ecodeclub/ekit/pull/208)


# v0.0.7
- [slice: FilterDelete](https://github.com/ecodeclub/ekit/pull/152)
- [reflectx: IsNil 方法](https://github.com/ecodeclub/ekit/pull/150)
Expand Down
88 changes: 88 additions & 0 deletions randx/rand_code.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2021 ecodeclub
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package randx

import (
"errors"
"math/rand"
)

var ERRTYPENOTSUPPORTTED = errors.New("ekit:不支持的类型")

type TYPE int

const (
TYPE_DEFAULT TYPE = 0 //默认类型
TYPE_DIGIT TYPE = 1 //数字//
TYPE_LETTER TYPE = 2 //小写字母
TYPE_CAPITAL TYPE = 3 //大写字母
TYPE_MIXED TYPE = 4 //数字+字母混合
)

// RandCode 根据传入的长度和类型生成随机字符串,这个方法目前可以生成数字、字母、数字+字母的随机字符串
func RandCode(length int, typ TYPE) (string, error) {
switch typ {
case TYPE_DEFAULT:
fallthrough
case TYPE_DIGIT:
return generate("0123456789", length, 4), nil
case TYPE_LETTER:
return generate("abcdefghijklmnopqrstuvwxyz", length, 5), nil
case TYPE_CAPITAL:
return generate("ABCDEFGHIJKLMNOPQRSTUVWXYZ", length, 5), nil
case TYPE_MIXED:
return generate("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", length, 7), nil
default:
return "", ERRTYPENOTSUPPORTTED
}
}

// generate 根据传入的随机源和长度生成随机字符串,一次随机,多次使用
func generate(source string, length, idxBits int) string {

//掩码
//例如: 使用低6位:0000 0000 --> 0011 1111
idxMask := 1<<idxBits - 1

// 63位最多可以使用多少次
remain := 63 / idxBits

//cache 随机位缓存
cache := rand.Int63()

result := make([]byte, length)

for i := 0; i < length; {
//如果使用次数剩余0,重新获取随机
if remain == 0 {
cache, remain = rand.Int63(), 63/idxBits
}

//利用掩码获取有效的随机数位
if randIndex := int(cache & int64(idxMask)); randIndex < len(source) {
result[i] = source[randIndex]
i++
}

//使用下一组随机位
cache >>= idxBits

//扣减remain
remain--

}
return string(result)

}
92 changes: 92 additions & 0 deletions randx/rand_code_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2021 ecodeclub
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package randx

import (
"errors"
"regexp"
"testing"
)

func TestRandCode(t *testing.T) {
testCases := []struct {
name string
length int
typ TYPE
wantMatch string
wantErr error
}{
{
name: "默认类型",
length: 8,
typ: TYPE_DEFAULT,
wantMatch: "^[0-9]+$",
wantErr: nil,
},
{
name: "数字验证码",
length: 8,
typ: TYPE_DIGIT,
wantMatch: "^[0-9]+$",
wantErr: nil,
}, {
name: "小写字母验证码",
length: 8,
typ: TYPE_LETTER,
wantMatch: "^[a-z]+$",
wantErr: nil,
}, {
name: "大写字母验证码",
length: 8,
typ: TYPE_CAPITAL,
wantMatch: "^[A-Z]+$",
wantErr: nil,
}, {
name: "混合验证码",
length: 8,
typ: TYPE_MIXED,
wantMatch: "^[0-9a-zA-Z]+$",
wantErr: nil,
}, {
name: "未定义类型",
length: 8,
typ: 9,
wantMatch: "",
wantErr: ERRTYPENOTSUPPORTTED,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
code, err := RandCode(tc.length, tc.typ)
if err != nil {
if !errors.Is(err, tc.wantErr) {
t.Errorf("unexpected error: %v", err)
}
} else {
//长度检验
if len(code) != tc.length {
t.Errorf("expected length: %d but got length:%d ", tc.length, len(code))
}
//模式检验
matched, _ := regexp.MatchString(tc.wantMatch, code)
if !matched {
t.Errorf("expected %s but got %s", tc.wantMatch, code)
}
}
})
}

}

0 comments on commit abbebbd

Please sign in to comment.