1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-04 21:02:27 +08:00

Compare commits

...

33 Commits

Author SHA1 Message Date
dudaodong
0a1386f5a7 release v1.0.9 2021-12-26 13:57:05 +08:00
Beyond
b5541ea177 Merge pull request #2 from donutloop/slice/Some
Some: allocate slice to keep track of unused indexes is not necessary
2021-12-26 11:44:46 +08:00
Marcel Edmund Franke
578b1bba65 Some: allocate slice to keep track unused indexes is not necessary
Waste of memory for those unused indexes. It got replaced by a simple
boolean to keep track of it.
2021-12-25 13:04:03 +01:00
dudaodong
3045d56503 release: update readme.file v1.0.8, ParseHttpResponse in netutil/request.go 2021-12-20 11:43:39 +08:00
dudaodong
f1dbd943aa refactor: rename ParseResponse to ParseHttpResponse func in netutil/request.go 2021-12-17 17:29:28 +08:00
dudaodong
e87f3b70f0 feat: add ParseResponse func in netutil/request.go 2021-12-17 17:23:18 +08:00
dudaodong
26b59dd56b update: update go test command in workflows/codecov.yml 2021-12-14 11:02:19 +08:00
dudaodong
143aba7112 release: update readme file, new feature for functional programming 2021-12-14 10:55:07 +08:00
dudaodong
60f3a72c88 refactor: update Compose func in function.go 2021-12-14 10:29:53 +08:00
dudaodong
d1b74cfcfb feat: add Compose in function.go 2021-12-13 20:15:34 +08:00
dudaodong
72a89be8c1 feat: add function package for funcational programming 2021-12-11 13:30:11 +08:00
dudaodong
0cf59323ff update: update comment for ReadFileByLine in file.go 2021-12-10 10:51:50 +08:00
dudaodong
afec27fb4e release: new feature for slice and fileutil 2021-12-10 10:50:46 +08:00
dudaodong
3021985df9 feat: add ClearFile, ReadFileToString, ReadFileByLine into file.go 2021-12-09 20:19:13 +08:00
dudaodong
188d52cd9d feat: add Some and Every function in slice.go 2021-12-09 19:27:20 +08:00
dudaodong
8c8f991390 feat: add Find function in slice.go 2021-12-09 17:54:16 +08:00
dudaodong
b7bb7c6ae0 fmt: gofmt random_test.go 2021-12-01 20:38:54 +08:00
dudaodong
2e04a41f34 update version 2021-12-01 11:34:53 +08:00
dudaodong
acb7873832 fix: setQueryParam failed in request_util.go 2021-12-01 11:34:18 +08:00
dudaodong
8b3cc3266d fix misspel in README_zh-CN.md 2021-11-30 09:51:21 +08:00
dudaodong
62c570d29b update version 2021-11-29 20:24:28 +08:00
dudaodong
4e5d3c2603 fix: fix IsExist function in fileutil/file.go 2021-11-29 20:23:26 +08:00
dudaodong
561b590e13 update: fix misspell in readme file 2021-11-29 20:02:55 +08:00
dudaodong
f2ed3c6270 test: add some unit test function for convertor, random, slice, and formatter 2021-11-29 17:27:02 +08:00
dudaodong
fee6cb17f3 update: update validator test function 2021-11-29 15:53:48 +08:00
dudaodong
7d39d1319b add github workflow 2021-11-29 15:19:52 +08:00
dudaodong
59d7281967 Merge branch 'main' of github.com:duke-git/lancet into main 2021-11-29 15:06:59 +08:00
dudaodong
bdf052819d delete .travis.yml 2021-11-29 15:06:52 +08:00
dudaodong
0148af4839 update: readme file 2021-11-29 14:41:14 +08:00
Beyond
99b74e6fc6 add codecov.yml 2021-11-29 14:37:35 +08:00
dudaodong
499c1df9bd update: add godoc, goreport, lincense badges in readme file, add .travis.yml 2021-11-29 14:19:41 +08:00
dudaodong
6af13a01de update: add godoc, goreport, lincense badges in readme file, add .travis.yml 2021-11-29 14:19:23 +08:00
dudaodong
0c4b512084 fmt: fix some gofmt issue 2021-11-29 13:01:46 +08:00
28 changed files with 731 additions and 138 deletions

22
.github/workflows/codecov.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Test and coverage
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- uses: actions/setup-go@v2
with:
go-version: "1.16"
- name: Run coverage
run: go test -v ./... -coverprofile=coverage.txt -covermode=atomic
- name: Upload coverage to Codecov
run: bash <(curl -s https://codecov.io/bash)

5
.gitignore vendored
View File

@@ -1,3 +1,6 @@
.idea/*
.vscode/*
.DS_Store
.DS_Store
cryptor/*.txt
fileutil/*.txt
cryptor/*.pem

View File

@@ -5,6 +5,13 @@
</p>
<div align="center" style="text-align: center;">
![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf)
[![Release](https://img.shields.io/badge/release-1.0.9-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com//duke-git/lancet?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet)](https://goreportcard.com/report/github.com/duke-git/lancet)
[![codecov](https://codecov.io/gh/duke-git/lancet/branch/main/graph/badge.svg?token=FC48T1F078)](https://codecov.io/gh/duke-git/lancet)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/duke-git/lancet/blob/main/LICENSE)
</div>
English | [简体中文](./README_zh-CN.md)
@@ -200,15 +207,18 @@ func main() {
}
```
- 函数列表
- Function list
```go
func ClearFile(path string) error //write empty string to path file
func CreateFile(path string) bool // create a file in path
func CopyFile(srcFilePath string, dstFilePath string) error //copy src file to dst file
func IsExist(path string) bool //checks if a file or directory exists
func IsDir(path string) bool //checks if the path is directy or not
func ListFileNames(path string) ([]string, error) //return all file names in the path
func RemoveFile(path string) error //remove the path file
func ReadFileToString(path string) (string, error) //return string of file content
func ReadFileByLine(path string)([]string, error) //read file content by line
```
#### 5. formatter is for data format
@@ -236,7 +246,39 @@ func main() {
func Comma(v interface{}, symbol string) string //add comma to number by every 3 numbers from right. ahead by symbol char
```
#### 6. netutil is for net process
#### 6. function can control the function execution and support functional programming
- Control function execution and support functional programming.
- Usage: import "github.com/duke-git/lancet/function"
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/function"
)
func main() {
var print = func(s string) {
fmt.Println(s)
}
function.Delay(2*time.Second, print, "hello world")
}
```
- Function list:
```go
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value //creates a function that invokes func once it's called n or more times
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value //creates a function that invokes func once it's called less than n times
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} //make a curryed function
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} //compose the functions from right to left
func Delay(delay time.Duration, fn interface{}, args ...interface{}) //invoke function after delayed time
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool //invoke function every duration time, util close the returned bool chan
```
#### 7. netutil is for net process
- Ip and http request method.
- Usage: import "github.com/duke-git/lancet/netutil".
@@ -281,9 +323,10 @@ func HttpPut(url string, params ...interface{}) (*http.Response, error) //http p
func HttpDelete(url string, params ...interface{}) (*http.Response, error) //http delete request
func HttpPatch(url string, params ...interface{}) (*http.Response, error) //http patch request
func ConvertMapToQueryString(param map[string]interface{}) string //convert map to url query string
func ParseHttpResponse(resp *http.Response, obj interface{}) error //decode http response to specified interface
```
#### 7. random is for rand string and int generation
#### 8. random is for rand string and int generation
- Generate random string and int.
- Usage: import "github.com/duke-git/lancet/random".
@@ -312,7 +355,7 @@ func RandInt(min, max int) int //generate random int
func RandString(length int) string //generate random string
```
#### 8. slice is for process slice
#### 9. slice is for process slice
- Contain function for process slice.
- Usage: import "github.com/duke-git/lancet/slice"
@@ -343,7 +386,9 @@ func Chunk(slice []interface{}, size int) [][]interface{} //creates an slice of
func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //convert originalSlice to newSliceType
func Difference(slice1, slice2 interface{}) interface{} //creates an slice of whose element not included in the other given slice
func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error) //delete the element of slice from start index to end index - 1
func Every(slice, function interface{}) bool //return true if all of the values in the slice pass the predicate function, function signature should be func(index int, value interface{}) bool
func Filter(slice, function interface{}) interface{} //filter slice, function signature should be func(index int, value interface{}) bool
func Find(slice, function interface{}) interface{} //iterates over elements of slice, returning the first one that passes a truth test on function.function signature should be func(index int, value interface{}) bool .
func IntSlice(slice interface{}) ([]int, error) //convert value to int slice
func InterfaceSlice(slice interface{}) []interface{} //convert value to interface{} slice
func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //insert the element into slice at index.
@@ -351,12 +396,13 @@ func Map(slice, function interface{}) interface{} //map lisce, function signatur
func ReverseSlice(slice interface{}) //revere slice
func Reduce(slice, function, zero interface{}) interface{} //reduce slice, function signature should be func(index int, value1, value2 interface{}) interface{}
func SortByField(slice interface{}, field string, sortType ...string) error //sort struct slice by field
func Some(slice, function interface{}) bool //return true if any of the values in the list pass the predicate function, function signature should be func(index int, value interface{}) bool
func StringSlice(slice interface{}) []string //convert value to string slice
func Unique(slice interface{}) interface{} //remove duplicate elements in slice
func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //update the slice element at index.
```
#### 9. strutil is for processing string
#### 10. strutil is for processing string
- Contain functions to precess string
- Usage: import "github.com/duke-git/lancet/strutil"
@@ -396,7 +442,7 @@ func ReverseStr(s string) string //return string whose char order is reversed to
func SnakeCase(s string) string //covert string to snake_case "fooBar" -> "foo_bar"
```
#### 10. validator is for data validation
#### 11. validator is for data validation
- Contain function for data validation.
- Usage: import "github.com/duke-git/lancet/validator".

View File

@@ -5,6 +5,12 @@
</p>
<div align="center" style="text-align: center;">
![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf)
[![Release](https://img.shields.io/badge/release-1.0.9-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com//duke-git/lancet?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet)](https://goreportcard.com/report/github.com/duke-git/lancet)
[![codecov](https://codecov.io/gh/duke-git/lancet/branch/main/graph/badge.svg?token=FC48T1F078)](https://codecov.io/gh/duke-git/lancet)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/duke-git/lancet/blob/main/LICENSE)
</div>
@@ -17,7 +23,7 @@
- 👏 全面、高效、可复用
- 💪 100+常用go工具函数支持string、slice、datetime、net、crypt...
- 💅 只依赖go标准库
- 🌍 所有导出函数单测试覆盖率100%
- 🌍 所有导出函数单测试覆盖率100%
### 安装
@@ -57,7 +63,7 @@ func main() {
#### 1. convertor数据转换包
- 转换函数支持常用数据类型之间的转换
- 导入包import "github.com/duke-git/lancet/cryptor"
- 导入包import "github.com/duke-git/lancet/convertor"
```go
package main
@@ -94,7 +100,7 @@ func StructToMap(value interface{}) (map[string]interface{}, error) //struct串
#### 2. cryptor加解密包
- 加密函数支持md5, hmac, aes, des, ras
- 加密函数支持md5, hmac, aes, des, ras
- 导入包import "github.com/duke-git/lancet/cryptor"
```go
@@ -205,12 +211,15 @@ func main() {
- 函数列表:
```go
func ClearFile(path string) error //清空文件内容
func IsExist(path string) bool //判断文件/目录是否存在
func CreateFile(path string) bool //创建文件
func IsDir(path string) bool //判断是否为目录
func RemoveFile(path string) error //删除文件
func CopyFile(srcFilePath string, dstFilePath string) error //复制文件
func ListFileNames(path string) ([]string, error) //列出目录下所有文件名称
func ReadFileToString(path string) (string, error) //读取文件内容为字符串
func ReadFileByLine(path string)([]string, error) //按行读取文件内容
```
#### 5. formatter格式化处理包
@@ -238,7 +247,39 @@ func main() {
func Comma(v interface{}, symbol string) string //用逗号每隔3位分割数字/字符串
```
#### 6. netutil网络处理包
#### 6. function包可以控制函数执行支持部分函数式编程
- 控制函数执行,支持部分函数式编程
- 导入包import "github.com/duke-git/lancet/function"
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/function"
)
func main() {
var print = func(s string) {
fmt.Println(s)
}
function.Delay(2*time.Second, print, "hello world")
}
```
- Function list:
```go
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value //创建一个函数, 只有在运行了n次之后才有效果
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value //创建一个函数,调用不超过n次。 当n已经达到时最后一个函数调用的结果将被记住并返回
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} //函数柯里化
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} //从右至左组合函数
func Delay(delay time.Duration, fn interface{}, args ...interface{}) //延迟调用函数
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool //每隔duration时间调用函数, 关闭返回通道可以停止调用
```
#### 7. netutil网络处理包
- 处理ip, http请求相关函数
- 导入包import "github.com/duke-git/lancet/netutil"
@@ -283,9 +324,10 @@ func HttpPut(url string, params ...interface{}) (*http.Response, error) //http p
func HttpDelete(url string, params ...interface{}) (*http.Response, error) //http delete请求
func HttpPatch(url string, params ...interface{}) (*http.Response, error) //http patch请求
func ConvertMapToQueryString(param map[string]interface{}) string //将map转换成url query string
func ParseHttpResponse(resp *http.Response, obj interface{}) error //将http响应解码成特定interface
```
#### 7. random随机数处理包
#### 8. random随机数处理包
- 生成和处理随机数
- 导入包import "github.com/duke-git/lancet/random"
@@ -314,7 +356,7 @@ func RandInt(min, max int) int //生成随机int
func RandString(length int) string //生成随机string
```
#### 8. slice切片操作包
#### 9. slice切片操作包
- 切片操作相关函数
- 导入包import "github.com/duke-git/lancet/slice"
@@ -345,6 +387,8 @@ func Chunk(slice []interface{}, size int) [][]interface{} //均分slice
func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //将originalSlice转换为 newSliceType
func Difference(slice1, slice2 interface{}) interface{} //返回
func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error) //删除切片中start到end位置的值
func Every(slice, function interface{}) bool //slice中所有元素都符合函数条件时返回true, 否则返回false. 函数签名func(index int, value interface{}) bool
func Find(slice, function interface{}) interface{} //查找slice中第一个符合条件的元素函数签名func(index int, value interface{}) bool
func Filter(slice, function interface{}) interface{} //过滤slice, 函数签名func(index int, value interface{}) bool
func IntSlice(slice interface{}) ([]int, error) //转成int切片
func InterfaceSlice(slice interface{}) []interface{} //转成interface{}切片
@@ -352,13 +396,14 @@ func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}
func Map(slice, function interface{}) interface{} //遍历切片, 函数签名func(index int, value interface{}) interface{}
func ReverseSlice(slice interface{}) //反转切片
func Reduce(slice, function, zero interface{}) interface{} //切片reduce操作 函数签名func(index int, value1, value2 interface{}) interface{}
func Some(slice, function interface{}) bool //slice中任意一个元素都符合函数条件时返回true, 否则返回false. 函数签名func(index int, value interface{}) bool
func SortByField(slice interface{}, field string, sortType ...string) error //对struct切片进行排序
func StringSlice(slice interface{}) []string //转为string切片
func Unique(slice interface{}) interface{} //去重切片
func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //在切片中index位置更新value
```
#### 9. strutil字符串处理包
#### 10. strutil字符串处理包
- 字符串操作相关函数
- 导入包import "github.com/duke-git/lancet/strutil"
@@ -398,7 +443,7 @@ func ReverseStr(s string) string //字符串逆袭
func SnakeCase(s string) string //字符串转为SnakeCase, "fooBar" -> "foo_bar"
```
#### 10. validator验证器包
#### 11. validator验证器包
- 数据校验相关函数
- 导入包import "github.com/duke-git/lancet/validator"

View File

@@ -20,7 +20,7 @@ func ToBool(s string) (bool, error) {
return strconv.ParseBool(s)
}
// ToBool convert interface to bytes
// ToBytes convert interface to bytes
func ToBytes(data interface{}) ([]byte, error) {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)

View File

@@ -2,9 +2,10 @@ package convertor
import (
"fmt"
"github.com/duke-git/lancet/utils"
"reflect"
"testing"
"github.com/duke-git/lancet/utils"
)
func TestToChar(t *testing.T) {
@@ -58,8 +59,12 @@ func TestToBytes(t *testing.T) {
}
func TestToInt(t *testing.T) {
cases := []interface{}{"123", "-123", 123, "abc", false, "111111111111111111111111111111111111111"}
expected := []int64{123, -123, 123, 0, 0, 0}
cases := []interface{}{"123", "-123", 123,
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float32(12.3), float64(12.3),
"abc", false, "111111111111111111111111111111111111111"}
expected := []int64{123, -123, 123, 123, 123, 123, 123, 123, 12, 12, 0, 0, 0}
for i := 0; i < len(cases); i++ {
res, _ := ToInt(cases[i])
@@ -71,8 +76,14 @@ func TestToInt(t *testing.T) {
}
func TestToFloat(t *testing.T) {
cases := []interface{}{"", "-1", "-.11", "1.23e3", ".123e10", "abc"}
expected := []float64{0, -1, -0.11, 1230, 0.123e10, 0}
cases := []interface{}{
"", "-1", "-.11", "1.23e3", ".123e10", "abc",
int(0), int8(1), int16(-1), int32(123), int64(123),
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float64(12.3), float32(12.3),
}
expected := []float64{0, -1, -0.11, 1230, 0.123e10, 0,
0, 1, -1, 123, 123, 123, 123, 123, 123, 123, 12.3, 12.300000190734863}
for i := 0; i < len(cases); i++ {
res, _ := ToFloat(cases[i])
@@ -84,41 +95,37 @@ func TestToFloat(t *testing.T) {
}
func TestToString(t *testing.T) {
// basic type
toString(t, "a1", "a1")
toString(t, 111, "111")
toString(t, 111.01, "111.01")
toString(t, true, "true")
//toString(t, 1.5+10i, "(1.5+10i)")
// slice
aSlice := []int{1, 2, 3}
toString(t, aSlice, "[1,2,3]")
// map
aMap := make(map[string]int)
aMap["a"] = 1
aMap["b"] = 2
aMap["c"] = 3
toString(t, aMap, "{\"a\":1,\"b\":2,\"c\":3}")
// struct
type TestStruct struct {
Name string
}
aStruct := TestStruct{Name: "TestStruct"}
toString(t, aStruct, "{\"Name\":\"TestStruct\"}")
}
func toString(t *testing.T, test interface{}, expected string) {
res := ToString(test)
if res != expected {
utils.LogFailedTestInfo(t, "ToString", test, expected, res)
t.FailNow()
cases := []interface{}{
int(0), int8(1), int16(-1), int32(123), int64(123),
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float64(12.3), float32(12.3),
true, false,
[]int{1, 2, 3}, aMap, aStruct, []byte{104, 101, 108, 108, 111}}
expected := []string{"0", "1", "-1", "123", "123", "123", "123", "123",
"123", "123", "12.3", "12.300000190734863", "true", "false",
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
for i := 0; i < len(cases); i++ {
res := ToString(cases[i])
if res != expected[i] {
utils.LogFailedTestInfo(t, "ToString", cases[i], expected[i], res)
t.FailNow()
}
}
}
func TestToJson(t *testing.T) {
// map
aMap := make(map[string]int)

View File

@@ -65,7 +65,7 @@ func AesCbcEncrypt(data, key []byte) []byte {
return encrypted
}
// AesEcbDecrypt decrypt data with key use AES CBC algorithm
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32
func AesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := aes.NewCipher(key)

View File

@@ -21,13 +21,13 @@ func Base64StdEncode(s string) string {
return base64.StdEncoding.EncodeToString([]byte(s))
}
// Base64StdEncode decode a base64 encoded string
// Base64StdDecode decode a base64 encoded string
func Base64StdDecode(s string) string {
b, _ := base64.StdEncoding.DecodeString(s)
return string(b)
}
// Md5Str return the md5 value of string
// Md5String return the md5 value of string
func Md5String(s string) string {
h := md5.New()
h.Write([]byte(s))

View File

@@ -2,7 +2,6 @@
// Use of this source code is governed by MIT license.
// Package datetime implements some functions to format date and time.
// Note:
// 1. `format` param in FormatTimeToStr function should be as flow:
//"yyyy-mm-dd hh:mm:ss"
@@ -23,7 +22,6 @@
//"mm"
//"hh:mm:ss"
//"mm:ss"
package datetime
import (

View File

@@ -2,23 +2,23 @@
// Use of this source code is governed by MIT license.
// Package fileutil implements some basic functions for file operations
package fileutil
import (
"bufio"
"errors"
"io"
"io/ioutil"
"os"
)
// IsFileExists checks if a file or directory exists
// IsExist checks if a file or directory exists
func IsExist(path string) bool {
_, err := os.Stat(path)
if err == nil {
return true
}
if errors.Is(err, os.ErrExist) {
if errors.Is(err, os.ErrNotExist) {
return false
}
return false
@@ -35,7 +35,7 @@ func CreateFile(path string) bool {
return true
}
// IsFileExists checks if the path is directy or not
// IsDir checks if the path is directory or not
func IsDir(path string) bool {
file, err := os.Stat(path)
if err != nil {
@@ -70,13 +70,59 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
if err != nil {
if err == io.EOF {
return nil
} else {
return err
}
return err
}
}
}
//ClearFile write empty string to path file
func ClearFile(path string) error {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString("")
return err
}
//ReadFileToString return string of file content
func ReadFileToString(path string) (string, error) {
bytes, err := ioutil.ReadFile(path)
if err != nil {
return "", err
}
return string(bytes), nil
}
// ReadFileByLine read file line by line
func ReadFileByLine(path string) ([]string, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
res := make([]string, 0)
buf := bufio.NewReader(f)
for {
line, _, err := buf.ReadLine()
l := string(line)
if err == io.EOF {
break
}
if err != nil {
continue
}
res = append(res, l)
}
return res, nil
}
// ListFileNames return all file names in the path
func ListFileNames(path string) ([]string, error) {
if !IsExist(path) {

View File

@@ -1,15 +1,16 @@
package fileutil
import (
"github.com/duke-git/lancet/utils"
"os"
"reflect"
"testing"
"github.com/duke-git/lancet/utils"
)
func TestIsExist(t *testing.T) {
cases := []string{"./", "./a.txt"}
expected := []bool{true, false}
cases := []string{"./", "./file.go", "./a.txt"}
expected := []bool{true, true, false}
for i := 0; i < len(cases); i++ {
res := IsExist(cases[i])
@@ -86,14 +87,52 @@ func TestCopyFile(t *testing.T) {
}
func TestListFileNames(t *testing.T) {
filesInCurrentPath, err := ListFileNames("./")
filesInCurrentPath, err := ListFileNames("../datetime/")
if err != nil {
t.FailNow()
}
expected := []string{"file.go", "file_test.go"}
expected := []string{"datetime.go", "datetime_test.go"}
if !reflect.DeepEqual(filesInCurrentPath, expected) {
utils.LogFailedTestInfo(t, "ToChar", "./", expected, filesInCurrentPath)
t.FailNow()
}
}
func TestReadFileToString(t *testing.T) {
path := "./text.txt"
CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
res, _ := ReadFileToString(path)
if res != "hello world" {
utils.LogFailedTestInfo(t, "ReadFileToString", path, "hello world", res)
}
}
func TestClearFile(t *testing.T) {
path := "./text.txt"
CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
CreateFile(path)
res, _ := ReadFileToString(path)
if res != "" {
utils.LogFailedTestInfo(t, "CreateFile", path, "", res)
}
}
func TestReadFileByLine(t *testing.T) {
path := "./text.txt"
CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello\nworld")
expected := []string{"hello", "world"}
res, _ := ReadFileByLine(path)
if !reflect.DeepEqual(res, expected) {
utils.LogFailedTestInfo(t, "ReadFileByLine", path, expected, res)
}
}

View File

@@ -14,4 +14,4 @@ func Comma(v interface{}, symbol string) string {
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
}
return symbol + commaString(s)
}
}

View File

@@ -1,25 +1,28 @@
package formatter
import (
"github.com/duke-git/lancet/utils"
"testing"
"github.com/duke-git/lancet/utils"
)
func TestComma(t *testing.T) {
comma(t, "", "","")
comma(t, "aa", "","")
comma(t, "123", "","123")
comma(t, "12345", "","12,345")
comma(t, 12345, "","12,345")
comma(t, 12345, "$","$12,345")
comma(t, 12345, "¥","¥12,345")
comma(t, 12345.6789, "","12,345.6789")
comma(t, "", "", "")
comma(t, "aa", "", "")
comma(t, "aa.a", "", "")
comma(t, []int{1}, "", "")
comma(t, "123", "", "123")
comma(t, "12345", "", "12,345")
comma(t, 12345, "", "12,345")
comma(t, 12345, "$", "$12,345")
comma(t, 12345, "¥", "¥12,345")
comma(t, 12345.6789, "", "12,345.6789")
}
func comma(t *testing.T, test interface{}, symbol string, expected interface{}) {
res:= Comma(test, symbol)
func comma(t *testing.T, test interface{}, symbol string, expected interface{}) {
res := Comma(test, symbol)
if res != expected {
utils.LogFailedTestInfo(t, "Comma", test, expected, res)
t.FailNow()
}
}
}

View File

@@ -18,22 +18,23 @@ func numString(value interface{}) string {
switch reflect.TypeOf(value).Kind() {
case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64:
return fmt.Sprintf("%v", value)
case reflect.String: {
sv := fmt.Sprintf("%v", value)
if strings.Contains(sv, ".") {
_, err := strconv.ParseFloat(sv, 64)
if err == nil {
return sv
}
}else {
_, err := strconv.ParseInt(sv, 10, 64)
if err == nil {
return sv
case reflect.String:
{
sv := fmt.Sprintf("%v", value)
if strings.Contains(sv, ".") {
_, err := strconv.ParseFloat(sv, 64)
if err == nil {
return sv
}
} else {
_, err := strconv.ParseInt(sv, 10, 64)
if err == nil {
return sv
}
}
}
}
default:
return ""
}
return ""
}
}

87
function/function.go Normal file
View File

@@ -0,0 +1,87 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package function implements some functions for control the function execution and some is for functional programming.
package function
import (
"reflect"
"time"
)
// After creates a function that invokes func once it's called n or more times
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
return func(args ...interface{}) []reflect.Value {
n--
if n < 1 {
return invokeFunc(fn, args...)
}
return nil
}
}
// Before creates a function that invokes func once it's called less than n times
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
var res []reflect.Value
return func(args ...interface{}) []reflect.Value {
if n > 0 {
res = invokeFunc(fn, args...)
}
if n <= 0 {
fn = nil
}
n--
return res
}
}
type Fn func(...interface{}) interface{}
// Curry make a curryed function
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} {
return func(values ...interface{}) interface{} {
v := append([]interface{}{i}, values...)
return f(v...)
}
}
// Compose compose the functions from right to left
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} {
return func(s... interface{}) interface{} {
f := fnList[0]
restFn := fnList[1:]
if len(fnList) == 1 {
return f(s...)
}
return f(Compose(restFn...)(s...))
}
}
// Delay make the function execution after delayed time
func Delay(delay time.Duration, fn interface{}, args ...interface{}) {
time.Sleep(delay)
invokeFunc(fn, args...)
}
// Schedule invoke function every duration time, util close the returned bool chan
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
quit := make(chan bool)
go func() {
for {
invokeFunc(fn, args...)
select {
case <-time.After(d):
case <-quit:
return
}
}
}()
return quit
}

114
function/function_test.go Normal file
View File

@@ -0,0 +1,114 @@
package function
import (
"fmt"
"reflect"
"strings"
"testing"
"time"
)
func TestAfter(t *testing.T) {
arr := []string{"a", "b"}
f := After(len(arr), func(i int) int {
fmt.Println("print done")
return i
})
type cb func(args ...interface{}) []reflect.Value
print := func(i int, s string, fn cb) {
fmt.Printf("print: arr[%d] is %s \n", i, s)
v := fn(i)
if v != nil {
vv := v[0].Int()
if vv != 1 {
t.FailNow()
}
}
}
fmt.Println("print: arr is", arr)
for i := 0; i < len(arr); i++ {
print(i, arr[i], f)
}
}
func TestBefore(t *testing.T) {
arr := []string{"a", "b", "c", "d", "e"}
f := Before(3, func(i int) int {
return i
})
var res []int64
type cb func(args ...interface{}) []reflect.Value
appendStr := func(i int, s string, fn cb) {
fmt.Printf("appendStr: arr[%d] is %s \n", i, s)
v := fn(i)
res = append(res, v[0].Int())
}
for i := 0; i < len(arr); i++ {
appendStr(i, arr[i], f)
}
expect := []int64{0, 1, 2, 2, 2}
if !reflect.DeepEqual(expect, res) {
t.FailNow()
}
}
func TestCurry(t *testing.T) {
add := func(a, b int) int {
return a + b
}
var addCurry Fn = func(values ...interface{}) interface{} {
return add(values[0].(int), values[1].(int))
}
add1 := addCurry.Curry(1)
v := add1(2)
if v != 3 {
t.FailNow()
}
}
func TestCompose(t *testing.T) {
toUpper := func(a ...interface{}) interface{} {
return strings.ToUpper(a[0].(string))
}
toLower := func(a ...interface{}) interface{} {
return strings.ToLower(a[0].(string))
}
expect := toUpper(toLower("aBCde"))
cf := Compose(toUpper, toLower)
res := cf("aBCde")
if res != expect {
t.FailNow()
}
}
func TestDelay(t *testing.T) {
var print = func(s string) {
fmt.Println(s)
}
Delay(2*time.Second, print, "test delay")
}
func TestSchedule(t *testing.T) {
var res []string
appendStr := func(s string) {
fmt.Println(s)
res = append(res, s)
}
stop := Schedule(1*time.Second, appendStr, "*")
time.Sleep(5 * time.Second)
close(stop)
expect := []string{"*", "*", "*", "*", "*"}
if !reflect.DeepEqual(expect, res) {
t.FailNow()
}
fmt.Println("done")
}

23
function/function_util.go Normal file
View File

@@ -0,0 +1,23 @@
package function
import (
"fmt"
"reflect"
)
func invokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
fv := functionValue(fn)
params := make([]reflect.Value, len(args))
for i, item := range args {
params[i] = reflect.ValueOf(item)
}
return fv.Call(params)
}
func functionValue(function interface{}) reflect.Value {
v := reflect.ValueOf(function)
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
}
return v
}

View File

@@ -47,6 +47,7 @@ func GetPublicIpInfo() (*PublicIpInfo, error) {
return &ip, nil
}
// PublicIpInfo public ip info: country, region, isp, city, lat, lon, ip
type PublicIpInfo struct {
Status string `json:"status"`
Country string `json:"country"`

View File

@@ -2,9 +2,10 @@ package netutil
import (
"fmt"
"github.com/duke-git/lancet/utils"
"net"
"testing"
"github.com/duke-git/lancet/utils"
)
func TestGetInternalIp(t *testing.T) {

View File

@@ -12,6 +12,8 @@
package netutil
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"sort"
@@ -43,6 +45,15 @@ func HttpPatch(url string, params ...interface{}) (*http.Response, error) {
return request(http.MethodPatch, url, params...)
}
// ParseHttpResponse decode http response to specified interface
func ParseHttpResponse(resp *http.Response, obj interface{}) error {
if resp == nil {
return errors.New("InvalidResp")
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(obj)
}
// ConvertMapToQueryString convert map to sorted url query string
func ConvertMapToQueryString(param map[string]interface{}) string {
if param == nil {

View File

@@ -4,12 +4,18 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"github.com/duke-git/lancet/utils"
"log"
"testing"
"github.com/duke-git/lancet/utils"
)
func TestHttpGet(t *testing.T) {
_, e := HttpGet("", nil)
if e == nil {
t.FailNow()
}
url := "https://gutendex.com/books?"
queryParams := make(map[string]interface{})
queryParams["ids"] = "1"
@@ -96,3 +102,27 @@ func TestConvertMapToQueryString(t *testing.T) {
t.FailNow()
}
}
func TestParseResponse(t *testing.T) {
url := "http://public-api-v1.aspirantzhang.com/users"
type User struct {
Id int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
type UserResp struct {
Data []User `json:"data"`
}
resp, err := HttpGet(url)
if err != nil {
log.Fatal(err)
t.FailNow()
}
userResp := &UserResp{}
err = ParseHttpResponse(resp, userResp)
if err != nil {
log.Fatal(err)
t.FailNow()
}
fmt.Println(userResp.Data)
}

View File

@@ -124,7 +124,7 @@ func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) err
case map[string]interface{}:
values = url.Values{}
for k := range v {
values.Set(k, fmt.Sprintf("%s", v[k]))
values.Set(k, fmt.Sprintf("%v", v[k]))
}
case url.Values:
values = v

View File

@@ -1,11 +1,20 @@
/*
* @Descripttion:
* @version: v1.0.0
* @Author: dudaodong@kingsoft.com
* @Date: 2021-11-29 11:43:28
* @LastEditors: dudaodong@kingsoft.com
* @LastEditTime: 2021-12-01 18:05:29
*/
package random
import (
"fmt"
"github.com/duke-git/lancet/utils"
"reflect"
"regexp"
"testing"
"github.com/duke-git/lancet/utils"
)
func TestRandString(t *testing.T) {
@@ -21,26 +30,42 @@ func TestRandString(t *testing.T) {
}
func TestRandInt(t *testing.T) {
randInt := RandInt(1, 10)
res1 := RandInt(1, 10)
if res1 < 1 || res1 >= 10 {
utils.LogFailedTestInfo(t, "RandInt", "RandInt(1, 10)", "RandInt(1, 10) should between [1, 10) ", res1)
t.FailNow()
}
if randInt < 1 || randInt >= 10 {
utils.LogFailedTestInfo(t, "RandInt", "RandInt(1, 10)", "RandInt(1, 10) should between [1, 10) ", randInt)
res2 := RandInt(1, 1)
if res2 != 1 {
utils.LogFailedTestInfo(t, "RandInt", "RandInt(1, 1)", "RandInt(1, 1) should be 1 ", res2)
t.FailNow()
}
res3 := RandInt(10, 1)
if res3 < 1 || res3 >= 10 {
utils.LogFailedTestInfo(t, "RandInt", "RandInt(10, 1)", "RandInt(10, 1) should between [1, 10) ", res3)
t.FailNow()
}
}
func TestRandBytes(t *testing.T) {
randBytes := RandBytes(4)
if len(randBytes) != 4 {
utils.LogFailedTestInfo(t, "RandBytes", "RandBytes(4)", "RandBytes(4) should return 4 element of []bytes", randBytes)
t.FailNow()
}
v := reflect.ValueOf(randBytes)
et := v.Type().Elem()
if v.Kind() != reflect.Slice || et.Kind() != reflect.Uint8 {
utils.LogFailedTestInfo(t, "RandBytes", "RandBytes(4)", "RandBytes(4) should return 4 element of []bytes", randBytes)
t.FailNow()
}
randErr := RandBytes(0)
if randErr != nil {
utils.LogFailedTestInfo(t, "RandBytes", "RandBytes(0)", "RandBytes(0) should return nil", randErr)
t.FailNow()
}
}

View File

@@ -89,6 +89,50 @@ func Difference(slice1, slice2 interface{}) interface{} {
return res.Interface()
}
// Every return true if all of the values in the slice pass the predicate function.
// The function signature should be func(index int, value interface{}) bool .
func Every(slice, function interface{}) bool {
sv := sliceValue(slice)
fn := functionValue(function)
elemType := sv.Type().Elem()
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
panic("Filter function must be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
}
var indexes []int
for i := 0; i < sv.Len(); i++ {
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
if flag.Bool() {
indexes = append(indexes, i)
}
}
return len(indexes) == sv.Len()
}
// Some return true if any of the values in the list pass the predicate function.
// The function signature should be func(index int, value interface{}) bool .
func Some(slice, function interface{}) bool {
sv := sliceValue(slice)
fn := functionValue(function)
elemType := sv.Type().Elem()
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
panic("Filter function must be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
}
has := false
for i := 0; i < sv.Len(); i++ {
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
if flag.Bool() {
has = true
}
}
return has
}
// Filter iterates over elements of slice, returning an slice of all elements `signature` returns truthy for.
// The function signature should be func(index int, value interface{}) bool .
func Filter(slice, function interface{}) interface{} {
@@ -115,6 +159,28 @@ func Filter(slice, function interface{}) interface{} {
return res.Interface()
}
// Find iterates over elements of slice, returning the first one that passes a truth test on function.
// The function signature should be func(index int, value interface{}) bool .
func Find(slice, function interface{}) interface{} {
sv := sliceValue(slice)
fn := functionValue(function)
elemType := sv.Type().Elem()
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
panic("Filter function must be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
}
var index int
for i := 0; i < sv.Len(); i++ {
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
if flag.Bool() {
index = i
break
}
}
return sv.Index(index).Interface()
}
// Map creates an slice of values by running each element of `slice` thru `function`.
// The function signature should be func(index int, value interface{}) interface{}.
func Map(slice, function interface{}) interface{} {
@@ -137,17 +203,16 @@ func Map(slice, function interface{}) interface{} {
// The function signature should be func(index int, value1, value2 interface{}) interface{} .
func Reduce(slice, function, zero interface{}) interface{} {
sv := sliceValue(slice)
elementType := sv.Type().Elem()
len := sv.Len()
if len == 0 {
return zero
} else if len == 1 {
return sv.Index(0)
return sv.Index(0).Interface()
}
elementType := sv.Type().Elem()
fn := functionValue(function)
if checkSliceCallbackFuncSignature(fn, elementType, elementType, elementType) {
t := elementType.String()
panic("Reduce function must be of type func(int, " + t + ", " + t + ")" + t)

View File

@@ -14,6 +14,15 @@ func TestContain(t *testing.T) {
var t2 []string
contain(t, t2, "1", false)
m := make(map[string]int)
m["a"] = 1
contain(t, m, "a", true)
contain(t, m, "b", false)
s := "hello"
contain(t, s, "h", true)
contain(t, s, "s", false)
}
func contain(t *testing.T, test interface{}, value interface{}, expected bool) {
@@ -87,15 +96,39 @@ func TestConvertSlice(t *testing.T) {
//}
}
func TestEvery(t *testing.T) {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res := Every(nums, isEven)
if res != false {
utils.LogFailedTestInfo(t, "Every", nums, false, res)
t.FailNow()
}
}
func TestSome(t *testing.T) {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res := Some(nums, isEven)
if res != true {
utils.LogFailedTestInfo(t, "Some", nums, true, res)
t.FailNow()
}
}
func TestFilter(t *testing.T) {
s1 := []int{1, 2, 3, 4, 5}
nums := []int{1, 2, 3, 4, 5}
even := func(i, num int) bool {
return num%2 == 0
}
e1 := []int{2, 4}
r1 := Filter(s1, even)
r1 := Filter(nums, even)
if !reflect.DeepEqual(r1, e1) {
utils.LogFailedTestInfo(t, "Filter", s1, e1, r1)
utils.LogFailedTestInfo(t, "Filter", nums, e1, r1)
t.FailNow()
}
@@ -128,6 +161,18 @@ func TestFilter(t *testing.T) {
}
func TestFind(t *testing.T) {
nums := []int{1, 2, 3, 4, 5}
even := func(i, num int) bool {
return num%2 == 0
}
res := Find(nums, even)
if res != 2 {
utils.LogFailedTestInfo(t, "Find", nums, 2, res)
t.FailNow()
}
}
func TestMap(t *testing.T) {
s1 := []int{1, 2, 3, 4}
multiplyTwo := func(i, num int) int {
@@ -167,28 +212,21 @@ func TestMap(t *testing.T) {
}
func TestReduce(t *testing.T) {
s1 := []int{1, 2, 3, 4}
f1 := func(i, v1, v2 int) int {
cases := [][]int{
{},
{1},
{1, 2, 3, 4}}
expected := []int{0, 1, 10}
f := func(i, v1, v2 int) int {
return v1 + v2
}
e1 := 10
r1 := Reduce(s1, f1, 0)
if e1 != r1 {
utils.LogFailedTestInfo(t, "Reduce", s1, e1, r1)
t.FailNow()
for i := 0; i < len(cases); i++ {
res := Reduce(cases[i], f, 0)
if res != expected[i] {
utils.LogFailedTestInfo(t, "Reduce", cases[i], expected[i], res)
t.FailNow()
}
}
// failed Reduce function should be func(i int, v1, v2 int) int
//s1 := []int{1, 2, 3, 4}
//f1 := func(i string, v1, v2 int) int { //i should be int
// return v1+v2
//}
//e1 := 10
//r1 := Reduce(s1, f1, 0)
//if e1 != r1 {
// utils.LogFailedTestInfo(t, "Reduce", s1, e1, r1)
// t.FailNow()
//}
}
func TestIntSlice(t *testing.T) {
@@ -340,11 +378,6 @@ func TestUpdateByIndex(t *testing.T) {
r3 := []string{"a", "b", "1"}
updateByIndex(t, t1, 2, "1", r3)
//failed
//t1 = []string{"a","b","c"}
//r4 := []string{"a", "b", "1"}
//updateByIndex(t, t1, 3, "1", r4)
}
func updateByIndex(t *testing.T, test interface{}, index int, value, expected interface{}) {

View File

@@ -9,6 +9,7 @@ import (
"testing"
)
// LogFailedTestInfo log test failed info for internal use
func LogFailedTestInfo(t *testing.T, testCase, input, expected, result interface{}) {
errInfo := fmt.Sprintf("Test case %v: input is %+v, expected %v, but result is %v", testCase, input, expected, result)
t.Error(errInfo)

View File

@@ -26,11 +26,7 @@ func IsNumberStr(s string) bool {
// IsFloatStr check if the string can convert to a float.
func IsFloatStr(s string) bool {
_, e := strconv.ParseFloat(s, 64)
if e != nil {
return false
}
return true
return e == nil
}
// IsIntStr check if the string can convert to a integer.
@@ -42,10 +38,7 @@ func IsIntStr(s string) bool {
// IsIp check if the string is a ip address.
func IsIp(ipstr string) bool {
ip := net.ParseIP(ipstr)
if ip == nil {
return false
}
return true
return ip != nil
}
// IsIpV4 check if the string is a ipv4 address.
@@ -123,9 +116,9 @@ func IsChinesePhone(phone string) bool {
// IsCreditCard check if the string is credit card.
func IsCreditCard(creditCart string) bool {
pattern := `^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`
reg := regexp.MustCompile(pattern)
return reg.MatchString(creditCart)
pattern := `^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`
reg := regexp.MustCompile(pattern)
return reg.MatchString(creditCart)
}
// IsBase64 check if the string is base64 string.
@@ -191,4 +184,3 @@ func IsWeakPassword(password string) bool {
return (num || letter) && !special
}

View File

@@ -190,7 +190,7 @@ func isCreditCard(t *testing.T, source string, expected bool) {
}
func TestIsBase64(t *testing.T) {
isBase64(t, "aGVsbG8", true)
isBase64(t, "aGVsbG8=", true)
isBase64(t, "123456", false)
}