1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-08 06:32:28 +08:00

Compare commits

...

46 Commits

Author SHA1 Message Date
dudaodong
764a6fe107 release v1.2.0 2022-01-17 14:49:20 +08:00
dudaodong
f3749c52b9 feat: add system package 2022-01-17 11:54:03 +08:00
dudaodong
f368854b2d update text style of readme file 2022-01-17 10:40:41 +08:00
dudaodong
c424b88d40 update style of readme file 2022-01-16 22:17:51 +08:00
Dan Anstis
aeebd63eda docs(readme): fix convertor import example (#23) 2022-01-14 12:33:53 +08:00
dudaodong
22b3c4dd42 feat: add validator functions, IsAllUpper, IsAllLower, ContainUpper, ContainLower, ContainLetter, IsJSON and IsPort 2022-01-13 20:19:41 +08:00
dudaodong
bd976642f6 feat: add try package for executing a function repeatedly 2022-01-13 16:18:49 +08:00
dudaodong
e31fb28003 feat: add func ContainSubSlice 2022-01-13 11:00:27 +08:00
dudaodong
fd271fe176 add test passing badge 2022-01-12 11:27:09 +08:00
dudaodong
6890bbfe05 update: rename workflow 2022-01-12 11:23:51 +08:00
dudaodong
24ae47a12f remove v2 branch 2022-01-12 10:13:13 +08:00
dudaodong
d8d85efedf update: add v2 branch 2022-01-12 10:05:21 +08:00
dudaodong
ba73847b80 fix: fix some go report issue 2022-01-12 09:57:10 +08:00
dudaodong
69453eba19 release v1.1.9 2022-01-11 20:42:04 +08:00
donutloop
f147f78a41 Slice: sort from v2 branch (#22)
ref: f1d7154179
2022-01-11 20:13:25 +08:00
dudaodong
bbfc5b7060 delete file utils.go and fix some misspel 2022-01-09 16:12:26 +08:00
dudaodong
1f45937190 refactor: rewrite all unit test functions with assert 2022-01-09 16:04:33 +08:00
dudaodong
52c5a91606 refactor: rewrite all unit test functions with assert 2022-01-09 15:57:21 +08:00
dudaodong
49f62c3550 refactor: rewrite all unit test functions with assert 2022-01-09 15:53:30 +08:00
dudaodong
23701e6998 refactor: rewrite all unit test functions with assert 2022-01-09 15:49:52 +08:00
dudaodong
1199c30ef3 refactor: rewrite all unit test functions with assert 2022-01-09 15:48:29 +08:00
dudaodong
b0e17c7bc4 refactor: rewrite all unit test functions with assert 2022-01-09 15:39:50 +08:00
dudaodong
d3525dfe8f refactor: rewrite all unit test functions with assert 2022-01-09 15:34:17 +08:00
dudaodong
9da7115169 refactor: rewrite all unit test functions with assert 2022-01-09 15:10:56 +08:00
dudaodong
9cb9aa2f2f refactor: rewrite all unit test functions with assert 2022-01-09 14:46:17 +08:00
dudaodong
e4cd7dad35 refactor: rewrite all unit test functions with assert 2022-01-09 14:31:31 +08:00
dudaodong
31e08197d4 remove file comment 2022-01-09 14:03:46 +08:00
dudaodong
642d0b8077 refactor: rewrite all unit test functions with assert 2022-01-09 14:01:51 +08:00
dudaodong
25b2ae6b98 fix: return empty byte slice when rand bytes lenght less 1 2022-01-09 14:00:23 +08:00
dudaodong
65719515bd feat: add LessOrEqual and GreaterOrEqual 2022-01-09 13:58:27 +08:00
dudaodong
3ffd81a98a refactor: rewrite all unit test functions with assert 2022-01-09 13:51:07 +08:00
dudaodong
f490ef2404 refactor: rewrite all unit test functions with assert 2022-01-09 13:30:08 +08:00
dudaodong
3438f3b18a refactor: rewrite all unit test functions with assert 2022-01-09 13:07:49 +08:00
dudaodong
73f4ae7b35 refactor: add internal/assert.go and rewrite all unit funcs string_test.go with assert 2022-01-08 21:58:35 +08:00
rumikk
a8996933bf ToJson fix error handling (#16) 2022-01-07 15:00:05 +08:00
donutloop
3905c0bde1 Slice: Add count func (#15)
Returns the count of matched elements
2022-01-06 20:32:14 +08:00
dudaodong
c7e961704d Merge branch 'main' of github.com:duke-git/lancet into main 2022-01-06 17:09:43 +08:00
dudaodong
cb7df1b57d update: add some new feature comments for file and slice 2022-01-06 17:09:01 +08:00
dudaodong
eeff28606e feat: add IsLink, FileMode, MiMeType funcs for file 2022-01-06 16:53:32 +08:00
dudaodong
86d4b25a2b feat: and Zip and UnZip func for file operation 2022-01-06 15:15:59 +08:00
Ahmad Alfy
ad287ed99a doc: minor spelling mistak (#14) 2022-01-05 21:25:21 +08:00
dudaodong
df9de3065b feat: add ForEach func 2022-01-05 20:17:16 +08:00
dudaodong
71a2ea3f20 update: change case name for TestNone func 2022-01-05 19:46:51 +08:00
dudaodong
955f2e6de6 update func GetElapsedTime and None comment 2022-01-05 19:44:22 +08:00
donutloop
4aef9d6d22 Slice: Add none func (#13)
Returns true whether no elements of this slice match the provided predicate
func. Negated form of Every func
2022-01-05 19:38:14 +08:00
dudaodong
4752725dd6 add Wrap and Unwrap func comment 2022-01-04 11:22:54 +08:00
32 changed files with 1901 additions and 1226 deletions

View File

@@ -1,11 +1,13 @@
name: Test and coverage name: test
on: on:
push: push:
branches: branches:
- main - main
# - v2
pull_request: pull_request:
branches: branches:
- main - main
# - v2
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest

3
.gitignore vendored
View File

@@ -3,4 +3,7 @@
.DS_Store .DS_Store
cryptor/*.txt cryptor/*.txt
fileutil/*.txt fileutil/*.txt
fileutil/*.zip
fileutil/*.link
fileutil/unzip/*
cryptor/*.pem cryptor/*.pem

155
README.md
View File

@@ -1,44 +1,42 @@
<div align="center"> # Lancet
<h1 style="width: 100%; text-align: center;">Lancet</h1> <p style="font-size: 18px">
<p style="font-size: 18px"> Lancet is a comprehensive, efficient, and reusable util function library of go. Inspired by the java apache common package and lodash.js.
Lancet is a comprehensive, efficient, and reusable util function library of go. Inspired by the java apache common package and lodash.js. </p>
</p>
<div align="center" style="text-align: center;">
![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf)
[![Release](https://img.shields.io/badge/release-1.1.7-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-1.2.0-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) [![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) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet)](https://goreportcard.com/report/github.com/duke-git/lancet)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
[![codecov](https://codecov.io/gh/duke-git/lancet/branch/main/graph/badge.svg?token=FC48T1F078)](https://codecov.io/gh/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) [![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) English | [简体中文](./README_zh-CN.md)
</div>
### Feature ## Feature
- 👏 Comprehensive, efficient and reusable. - 👏 Comprehensive, efficient and reusable.
- 💪 140+ common go util functions, support string, slice, datetime, net, crypt... - 💪 160+ common go util functions, support string, slice, datetime, net, crypt...
- 💅 Only depend on the go standard library. - 💅 Only depend on the go standard library.
- 🌍 Unit test for exery exported function. - 🌍 Unit test for every exported function.
### Installation ## Installation
```go ```go
go get github.com/duke-git/lancet go get github.com/duke-git/lancet
``` ```
### Usage ## Usage
Lancet organizes the code into package structure, and you need to import the corresponding package name when use it. For example, if you use string-related functions,import the strutil package like below: Lancet organizes the code into package structure, and you need to import the corresponding package name when use it. For example, if you use string-related functions,import the strutil package like below:
```go ```go
import "github.com/duke-git/lancet/strutil" import "github.com/duke-git/lancet/strutil"
``` ```
### Example ## Example
Here takes the string function ReverseStr (reverse order string) as an example, and the strutil package needs to be imported. Here takes the string function ReverseStr (reverse order string) as an example, and the strutil package needs to be imported.
@@ -57,12 +55,11 @@ func main() {
} }
``` ```
### API Documentation ## API Documentation
### 1. convertor contains some functions for data convertion
#### 1. convertor contains some functions for data convertion
- Support conversion between commonly used data types. - Support conversion between commonly used data types.
- Usage: import "github.com/duke-git/lancet/cryptor" - Usage: import "github.com/duke-git/lancet/convertor"
```go ```go
package main package main
@@ -97,7 +94,7 @@ func ToString(value interface{}) string //convert value to string
func StructToMap(value interface{}) (map[string]interface{}, error) //convert struct to map, only convert exported field, tag `json` should be set func StructToMap(value interface{}) (map[string]interface{}, error) //convert struct to map, only convert exported field, tag `json` should be set
``` ```
#### 2. cryptor is for data encryption and decryption ### 2. cryptor is for data encryption and decryption
- Support md5, hmac, aes, des, ras. - Support md5, hmac, aes, des, ras.
- Usage: import "github.com/duke-git/lancet/cryptor" - Usage: import "github.com/duke-git/lancet/cryptor"
@@ -156,7 +153,7 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte //RSA decrypt
``` ```
#### 3. datetime parse and format datetime ### 3. datetime parse and format datetime
- Parse and format datetime - Parse and format datetime
- Usage: import "github.com/duke-git/lancet/datetime" - Usage: import "github.com/duke-git/lancet/datetime"
@@ -191,7 +188,7 @@ func FormatTimeToStr(t time.Time, format string) string //convert time to string
func FormatStrToTime(str, format string) time.Time //convert string to time func FormatStrToTime(str, format string) time.Time //convert string to time
``` ```
#### 4. fileutil basic functions for file operations ### 4. fileutil basic functions for file operations
- Basic functions for file operations. - Basic functions for file operations.
- Usage: import "github.com/duke-git/lancet/fileutil" - Usage: import "github.com/duke-git/lancet/fileutil"
@@ -215,15 +212,20 @@ func main() {
func ClearFile(path string) error //write empty string to path file func ClearFile(path string) error //write empty string to path file
func CreateFile(path string) bool // create a file in path func CreateFile(path string) bool // create a file in path
func CopyFile(srcFilePath string, dstFilePath string) error //copy src file to dst file func CopyFile(srcFilePath string, dstFilePath string) error //copy src file to dst file
func FileMode(path string) (fs.FileMode, error) //return file's mode and permission
func MiMeType(file interface{}) string //return file mime type, file should be string or *os.File
func IsExist(path string) bool //checks if a file or directory exists func IsExist(path string) bool //checks if a file or directory exists
func IsLink(path string) bool //checks if a file is symbol link or not
func IsDir(path string) bool //checks if the path is directy or not 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 ListFileNames(path string) ([]string, error) //return all file names in the path
func RemoveFile(path string) error //remove the path file func RemoveFile(path string) error //remove the path file
func ReadFileToString(path string) (string, error) //return string of file content func ReadFileToString(path string) (string, error) //return string of file content
func ReadFileByLine(path string)([]string, error) //read file content by line func ReadFileByLine(path string)([]string, error) //read file content by line
func Zip(fpath string, destPath string) error //create zip file, fpath could be a single file or a directory
func UnZip(zipFile string, destPath string) error //unzip the file and save it to destPath
``` ```
#### 5. formatter is for data format ### 5. formatter is for data format
- Contain some formatting function - Contain some formatting function
- Usage: import "github.com/duke-git/lancet/formatter" - Usage: import "github.com/duke-git/lancet/formatter"
@@ -248,7 +250,7 @@ func main() {
func Comma(v interface{}, symbol string) string //add comma to number by every 3 numbers from right. ahead by symbol char func Comma(v interface{}, symbol string) string //add comma to number by every 3 numbers from right. ahead by symbol char
``` ```
#### 6. function can control the function execution and support functional programming ### 6. function can control the function execution and support functional programming
- Control function execution and support functional programming. - Control function execution and support functional programming.
- Usage: import "github.com/duke-git/lancet/function" - Usage: import "github.com/duke-git/lancet/function"
@@ -281,10 +283,10 @@ func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool //
func (w *Watcher) Start() //start the watch timer. func (w *Watcher) Start() //start the watch timer.
func (w *Watcher) Stop() //stop the watch timer func (w *Watcher) Stop() //stop the watch timer
func (w *Watcher) Reset() {} //reset the watch timer. func (w *Watcher) Reset() {} //reset the watch timer.
func (w *Watcher) GetElapsedTime() time.Duration //获取代码段运行时间 func (w *Watcher) GetElapsedTime() time.Duration //return time duration from watcher start to end.
``` ```
#### 7. netutil is for net process ### 7. netutil is for net process
- Ip and http request method. - Ip and http request method.
- Usage: import "github.com/duke-git/lancet/netutil". - Usage: import "github.com/duke-git/lancet/netutil".
@@ -332,7 +334,7 @@ func ConvertMapToQueryString(param map[string]interface{}) string //convert map
func ParseHttpResponse(resp *http.Response, obj interface{}) error //decode http response to specified interface func ParseHttpResponse(resp *http.Response, obj interface{}) error //decode http response to specified interface
``` ```
#### 8. random is for rand string and int generation ### 8. random is for rand string and int generation
- Generate random string and int. - Generate random string and int.
- Usage: import "github.com/duke-git/lancet/random". - Usage: import "github.com/duke-git/lancet/random".
@@ -361,7 +363,49 @@ func RandInt(min, max int) int //generate random int
func RandString(length int) string //generate random string func RandString(length int) string //generate random string
``` ```
#### 9. slice is for process slice ### 9. retry is for executing a function repeatedly until it was successful or canceled by the context.
- Executes a function repeatedly until it was successful or canceled by the context.
- Default retry times is 5, default retry duration is 3 second.
- Usage: import "github.com/duke-git/lancet/retry".
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/retry"
)
func main() {
var number int
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
fmt.Println(number) //3
}
```
- Function list:
```go
type RetryFunc func() error //function that retry executes
func RetryTimes(n uint) //set times of retry
func RetryDuration(d time.Duration) //generate random string
func Context(ctx context.Context) //set retry context config
func Retry(retryFunc RetryFunc, opts ...Option) error //executes the retryFunc repeatedly until it was successful or canceled by the context
```
### 10. slice is for process slice
- Contain function for process slice. - Contain function for process slice.
- Usage: import "github.com/duke-git/lancet/slice" - Usage: import "github.com/duke-git/lancet/slice"
@@ -388,15 +432,18 @@ func main() {
```go ```go
func Contain(slice interface{}, value interface{}) bool //check if the value is in the slice or not func Contain(slice interface{}, value interface{}) bool //check if the value is in the slice or not
func Chunk(slice []interface{}, size int) [][]interface{} //creates an slice of elements split into groups the length of `size`. func ContainSubSlice(slice interface{}, subslice interface{}) bool //check if the slice contain subslice or not
func Chunk(slice []interface{}, size int) [][]interface{} //creates an slice of elements split into groups the length of `size`
func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //convert originalSlice to newSliceType 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 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 DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error) //delete the element of slice from start index to end index - 1
func Drop(slice interface{}, n int) interface{} //creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0 func Drop(slice interface{}, n int) interface{} //creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0
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 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 None(slice, function interface{}) bool // return true if all the values in the slice mismatch the criteria
func Filter(slice, function interface{}) interface{} //filter slice, 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{}, bool) //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 Find(slice, function interface{}) (interface{}, bool) //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 FlattenDeep(slice interface{}) interface{} //flattens slice recursive func FlattenDeep(slice interface{}) interface{} //flattens slice recursive
func ForEach(slice, function interface{}) //iterates over elements of slice and invokes function for each element, function signature should be func(index int, value interface{})
func IntSlice(slice interface{}) ([]int, error) //convert value to int slice func IntSlice(slice interface{}) ([]int, error) //convert value to int slice
func InterfaceSlice(slice interface{}) []interface{} //convert value to interface{} slice func InterfaceSlice(slice interface{}) []interface{} //convert value to interface{} slice
func Intersection(slices ...interface{}) interface{} //creates a slice of unique values that included by all slices. func Intersection(slices ...interface{}) interface{} //creates a slice of unique values that included by all slices.
@@ -409,13 +456,14 @@ func SortByField(slice interface{}, field string, sortType ...string) error //so
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 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 StringSlice(slice interface{}) []string //convert value to string slice
func Unique(slice interface{}) interface{} //remove duplicate elements in slice func Unique(slice interface{}) interface{} //remove duplicate elements in slice
func Union(slices ...interface{}) interface{} //Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons. func Union(slices ...interface{}) interface{} //Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons
func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //update the slice element at index. func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //update the slice element at index.
func Without(slice interface{}, values ...interface{}) interface{} //creates a slice excluding all given values func Without(slice interface{}, values ...interface{}) interface{} //creates a slice excluding all given values
func GroupBy(slice, function interface{}) (interface{}, interface{}) // groups slice into two categories func GroupBy(slice, function interface{}) (interface{}, interface{}) // groups slice into two categories
func Count(slice, function interface{}) int // Count iterates over elements of slice, returns a count of all matched elements
``` ```
#### 10. strutil is for processing string ### 11. strutil is for processing string
- Contain functions to precess string - Contain functions to precess string
- Usage: import "github.com/duke-git/lancet/strutil" - Usage: import "github.com/duke-git/lancet/strutil"
@@ -453,9 +501,44 @@ func PadEnd(source string, size int, padStr string) string //pads string on the
func PadStart(source string, size int, padStr string) string//pads string on the left side if it's shorter than size func PadStart(source string, size int, padStr string) string//pads string on the left side if it's shorter than size
func ReverseStr(s string) string //return string whose char order is reversed to the given string func ReverseStr(s string) string //return string whose char order is reversed to the given string
func SnakeCase(s string) string //covert string to snake_case "fooBar" -> "foo_bar" func SnakeCase(s string) string //covert string to snake_case "fooBar" -> "foo_bar"
func Wrap(str string, wrapWith string) string //wrap a string with another string.
func Unwrap(str string, wrapToken string) string //unwrap a given string from anther string. will change str value
```
### 12. system contain some functions about os, runtime, shell command.
- Generate random string and int.
- Usage: import "github.com/duke-git/lancet/system".
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/system"
)
func main() {
envFoo := system.GetOsEnv("foo")
fmt.Println(envFoo)
}
``` ```
#### 11. validator is for data validation - Function list:
```go
func IsWindows() bool //check if current os is windows
func IsLinux() bool //check if current os is linux
func IsMac() bool //check if current os is macos
func GetOsEnv(key string) string //gets the value of the environment variable named by the key.
func SetOsEnv(key, value string) error //sets the value of the environment variable named by the key.
func RemoveOsEnv(key string) error //remove a single environment variable.
func CompareOsEnv(key, comparedEnv string) bool //gets env named by the key and compare it with comparedEnv
func ExecCommand(command string) (err error, stdout, stderr string) //use shell /bin/bash -c to execute command
```
### 13. validator is for data validation
- Contain function for data validation. - Contain function for data validation.
- Usage: import "github.com/duke-git/lancet/validator". - Usage: import "github.com/duke-git/lancet/validator".
@@ -483,6 +566,12 @@ func main() {
func ContainChinese(s string) bool //check if the string contain mandarin chinese func ContainChinese(s string) bool //check if the string contain mandarin chinese
func IsAlpha(s string) bool //checks if the string contains only letters (a-zA-Z) func IsAlpha(s string) bool //checks if the string contains only letters (a-zA-Z)
func IsBase64(base64 string) bool //check if the string is base64 string func IsBase64(base64 string) bool //check if the string is base64 string
func IsAllUpper(str string) bool //check if the string is all upper case letters A-Z
func IsAllLower(str string) bool //check if the string is all lower case letters a-z
func ContainUpper(str string) bool //check if the string contain at least one upper case letter A-Z
func ContainLower(str string) bool //check if the string contain at least one lower case letter a-z
func ContainLetter(str string) bool //check if the string contain at least one letter
func IsJSON(str string) bool //checks if the string is valid JSON
func IsChineseMobile(mobileNum string) bool //check if the string is chinese mobile number func IsChineseMobile(mobileNum string) bool //check if the string is chinese mobile number
func IsChineseIdNum(id string) bool //check if the string is chinese id number func IsChineseIdNum(id string) bool //check if the string is chinese id number
func IsChinesePhone(phone string) bool //check if the string is chinese phone number func IsChinesePhone(phone string) bool //check if the string is chinese phone number

View File

@@ -1,37 +1,34 @@
<div align="center"> # Lancet
<h1 style="width: 100%; text-align: center;">Lancet</h1> <p style="font-size: 18px">
<p style="font-size: 18px"> lancet柳叶刀是一个全面、高效、可复用的go语言工具函数库。 lancet受到了java apache common包和lodash.js的启发。
lancet柳叶刀是一个全面、高效、可复用的go语言工具函数库。 lancet受到了java apache common包和lodash.js的启发。 </p>
</p>
<div align="center" style="text-align: center;">
![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf)
[![Release](https://img.shields.io/badge/release-1.1.7-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-1.2.0-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) [![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) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet)](https://goreportcard.com/report/github.com/duke-git/lancet)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
[![codecov](https://codecov.io/gh/duke-git/lancet/branch/main/graph/badge.svg?token=FC48T1F078)](https://codecov.io/gh/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) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/duke-git/lancet/blob/main/LICENSE)
</div>
简体中文 | [English](./README.md) 简体中文 | [English](./README.md)
</div>
### 特性 ## 特性
- 👏 全面、高效、可复用 - 👏 全面、高效、可复用
- 💪 140+常用go工具函数支持string、slice、datetime、net、crypt... - 💪 160+常用go工具函数支持string、slice、datetime、net、crypt...
- 💅 只依赖go标准库 - 💅 只依赖go标准库
- 🌍 所有导出函数单元测试覆盖率100% - 🌍 所有导出函数单元测试覆盖率100%
### 安装 ## 安装
```go ```go
go get github.com/duke-git/lancet go get github.com/duke-git/lancet
``` ```
### 用法 ## 用法
lancet是以包的结构组织代码的使用时需要导入相应的包名。例如如果使用字符串相关函数需要导入strutil包: lancet是以包的结构组织代码的使用时需要导入相应的包名。例如如果使用字符串相关函数需要导入strutil包:
@@ -39,7 +36,7 @@ lancet是以包的结构组织代码的使用时需要导入相应的包名
import "github.com/duke-git/lancet/strutil" import "github.com/duke-git/lancet/strutil"
``` ```
### 例子 ## 例子
此处以字符串工具函数ReverseStr逆序字符串为例需要导入strutil包: 此处以字符串工具函数ReverseStr逆序字符串为例需要导入strutil包:
@@ -58,9 +55,8 @@ func main() {
} }
``` ```
### API文档 ## API文档
### 1. convertor数据转换包
#### 1. convertor数据转换包
- 转换函数支持常用数据类型之间的转换 - 转换函数支持常用数据类型之间的转换
- 导入包import "github.com/duke-git/lancet/convertor" - 导入包import "github.com/duke-git/lancet/convertor"
@@ -98,7 +94,7 @@ func ToString(value interface{}) string //interface转成string
func StructToMap(value interface{}) (map[string]interface{}, error) //struct串转成map, 需要设置struct tag `json` func StructToMap(value interface{}) (map[string]interface{}, error) //struct串转成map, 需要设置struct tag `json`
``` ```
#### 2. cryptor加解密包 ### 2. cryptor加解密包
- 加密函数支持md5, hmac, aes, des, ras - 加密函数支持md5, hmac, aes, des, ras
- 导入包import "github.com/duke-git/lancet/cryptor" - 导入包import "github.com/duke-git/lancet/cryptor"
@@ -157,7 +153,7 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte //RSA解密
``` ```
#### 3. datetime日期时间处理包 ### 3. datetime日期时间处理包
- 处理日期时间 - 处理日期时间
- 导入包import "github.com/duke-git/lancet/datetime" - 导入包import "github.com/duke-git/lancet/datetime"
@@ -192,7 +188,7 @@ func FormatTimeToStr(t time.Time, format string) string //时间格式化字符
func FormatStrToTime(str, format string) time.Time //字符串转换成时间 func FormatStrToTime(str, format string) time.Time //字符串转换成时间
``` ```
#### 4. fileutil文件处理包 ### 4. fileutil文件处理包
- 文件处理常用函数 - 文件处理常用函数
- 导入包import "github.com/duke-git/lancet/fileutil" - 导入包import "github.com/duke-git/lancet/fileutil"
@@ -214,17 +210,22 @@ func main() {
```go ```go
func ClearFile(path string) error //清空文件内容 func ClearFile(path string) error //清空文件内容
func IsExist(path string) bool //判断文件/目录是否存在
func CreateFile(path string) bool //创建文件 func CreateFile(path string) bool //创建文件
func FileMode(path string) (fs.FileMode, error) //返回文件mode信息
func MiMeType(file interface{}) string //返回文件mime类型
func IsExist(path string) bool //判断文件/目录是否存在
func IsDir(path string) bool //判断是否为目录 func IsDir(path string) bool //判断是否为目录
func IsLink(path string) bool //检查文件是否为符号链接文件
func RemoveFile(path string) error //删除文件 func RemoveFile(path string) error //删除文件
func CopyFile(srcFilePath string, dstFilePath string) error //复制文件 func CopyFile(srcFilePath string, dstFilePath string) error //复制文件
func ListFileNames(path string) ([]string, error) //列出目录下所有文件名称 func ListFileNames(path string) ([]string, error) //列出目录下所有文件名称
func ReadFileToString(path string) (string, error) //读取文件内容为字符串 func ReadFileToString(path string) (string, error) //读取文件内容为字符串
func ReadFileByLine(path string)([]string, error) //按行读取文件内容 func ReadFileByLine(path string)([]string, error) //按行读取文件内容
func Zip(fpath string, destPath string) error //压缩文件fpath参数可以是文件或目录destPath是压缩后目标文件
func UnZip(zipFile string, destPath string) error //解压文件并将文件存储在destPath目录中
``` ```
#### 5. formatter格式化处理包 ### 5. formatter格式化处理包
- 格式化相关处理函数 - 格式化相关处理函数
- 导入包import "github.com/duke-git/lancet/formatter" - 导入包import "github.com/duke-git/lancet/formatter"
@@ -249,7 +250,7 @@ func main() {
func Comma(v interface{}, symbol string) string //用逗号每隔3位分割数字/字符串 func Comma(v interface{}, symbol string) string //用逗号每隔3位分割数字/字符串
``` ```
#### 6. function包可以控制函数执行支持部分函数式编程 ### 6. function包可以控制函数执行支持部分函数式编程
- 控制函数执行,支持部分函数式编程 - 控制函数执行,支持部分函数式编程
- 导入包import "github.com/duke-git/lancet/function" - 导入包import "github.com/duke-git/lancet/function"
@@ -285,7 +286,7 @@ func (w *Watcher) Reset() {} //重置代码watcher
func (w *Watcher) GetElapsedTime() time.Duration //get code excution elapsed time. func (w *Watcher) GetElapsedTime() time.Duration //get code excution elapsed time.
``` ```
#### 7. netutil网络处理包 ### 7. netutil网络处理包
- 处理ip, http请求相关函数 - 处理ip, http请求相关函数
- 导入包import "github.com/duke-git/lancet/netutil" - 导入包import "github.com/duke-git/lancet/netutil"
@@ -333,7 +334,7 @@ func ConvertMapToQueryString(param map[string]interface{}) string //将map转换
func ParseHttpResponse(resp *http.Response, obj interface{}) error //将http响应解码成特定interface func ParseHttpResponse(resp *http.Response, obj interface{}) error //将http响应解码成特定interface
``` ```
#### 8. random随机数处理包 ### 8. random随机数处理包
- 生成和处理随机数 - 生成和处理随机数
- 导入包import "github.com/duke-git/lancet/random" - 导入包import "github.com/duke-git/lancet/random"
@@ -362,7 +363,49 @@ func RandInt(min, max int) int //生成随机int
func RandString(length int) string //生成随机string func RandString(length int) string //生成随机string
``` ```
#### 9. slice切片操作包 ### 9. retry重试执行函数
- 重试执行函数直到函数成功或被context停止
- 默认重试次数5, 默认执行间隔3秒.
- Usage: import "github.com/duke-git/lancet/retry".
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/retry"
)
func main() {
var number int
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
fmt.Println(number) //3
}
```
- Function list:
```go
type RetryFunc func() error //要重试执行的函数
func RetryTimes(n uint) //设置重试次数默认5次
func RetryDuration(d time.Duration) //设置重试间隔时间默认3秒
func Context(ctx context.Context) //context config
func Retry(retryFunc RetryFunc, opts ...Option) error //重试函数
```
### 10. slice切片操作包
- 切片操作相关函数 - 切片操作相关函数
- 导入包import "github.com/duke-git/lancet/slice" - 导入包import "github.com/duke-git/lancet/slice"
@@ -389,15 +432,18 @@ func main() {
```go ```go
func Contain(slice interface{}, value interface{}) bool //判断slice是否包含value func Contain(slice interface{}, value interface{}) bool //判断slice是否包含value
func ContainSubSlice(slice interface{}, subslice interface{}) bool //判断slice是否包含subslice
func Chunk(slice []interface{}, size int) [][]interface{} //均分slice func Chunk(slice []interface{}, size int) [][]interface{} //均分slice
func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //将originalSlice转换为 newSliceType func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //将originalSlice转换为 newSliceType
func Difference(slice1, slice2 interface{}) interface{} //返回 func Difference(slice1, slice2 interface{}) interface{} //返回切片其元素在slice1中不在slice2中
func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error) //删除切片中start到end位置的值 func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error) //删除切片中start到end位置的值
func Drop(slice interface{}, n int) interface{} //创建一个新切片当n大于0时删除原切片前n个元素当n小于0时删除原切片后n个元素 func Drop(slice interface{}, n int) interface{} //创建一个新切片当n大于0时删除原切片前n个元素当n小于0时删除原切片后n个元素
func Every(slice, function interface{}) bool //slice中所有元素都符合函数条件时返回true, 否则返回false. 函数签名func(index int, value interface{}) bool func Every(slice, function interface{}) bool //slice中所有元素都符合函数条件时返回true, 否则返回false. 函数签名func(index int, value interface{}) bool
func None(slice, function interface{}) bool //slice中所有元素都不符合函数条件时返回true, 否则返回false. 函数签名func(index int, value interface{}) bool
func Find(slice, function interface{}) (interface{}, bool)//查找slice中第一个符合条件的元素函数签名func(index int, value interface{}) bool func Find(slice, function interface{}) (interface{}, bool)//查找slice中第一个符合条件的元素函数签名func(index int, value interface{}) bool
func Filter(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 FlattenDeep(slice interface{}) interface{} //将slice递归为一维切片。 func FlattenDeep(slice interface{}) interface{} //将slice递归为一维切片。
func ForEach(slice, function interface{}) //遍历切片在每个元素上执行函数函数签名func(index int, value interface{})
func IntSlice(slice interface{}) ([]int, error) //转成int切片 func IntSlice(slice interface{}) ([]int, error) //转成int切片
func InterfaceSlice(slice interface{}) []interface{} //转成interface{}切片 func InterfaceSlice(slice interface{}) []interface{} //转成interface{}切片
func Intersection(slices ...interface{}) interface{} //slice交集去重 func Intersection(slices ...interface{}) interface{} //slice交集去重
@@ -414,9 +460,10 @@ func Union(slices ...interface{}) interface{} //slice并集, 去重
func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //在切片中index位置更新value func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //在切片中index位置更新value
func Without(slice interface{}, values ...interface{}) interface{} //slice去除values func Without(slice interface{}, values ...interface{}) interface{} //slice去除values
func GroupBy(slice, function interface{}) (interface{}, interface{}) //根据函数function的逻辑分slice为两组slice func GroupBy(slice, function interface{}) (interface{}, interface{}) //根据函数function的逻辑分slice为两组slice
func Count(slice, function interface{}) int
``` ```
#### 10. strutil字符串处理包 ### 11. strutil字符串处理包
- 字符串操作相关函数 - 字符串操作相关函数
- 导入包import "github.com/duke-git/lancet/strutil" - 导入包import "github.com/duke-git/lancet/strutil"
@@ -452,11 +499,47 @@ func KebabCase(s string) string //字符串转为KebabCase, "foo_Bar" -> "foo-ba
func LowerFirst(s string) string //字符串的第一个字母转为小写字母 func LowerFirst(s string) string //字符串的第一个字母转为小写字母
func PadEnd(source string, size int, padStr string) string //字符串末尾填充size个字符 func PadEnd(source string, size int, padStr string) string //字符串末尾填充size个字符
func PadStart(source string, size int, padStr string) string//字符串开头填充size个字符 func PadStart(source string, size int, padStr string) string//字符串开头填充size个字符
func ReverseStr(s string) string //字符串逆 func ReverseStr(s string) string //字符串逆
func Wrap(str string, wrapWith string) string //包裹字符串 Wrap("abc", "*") -> *abc*.
func Unwrap(str string, wrapToken string) string //解包裹字符串 Wrap("*abc*", "*") -> abc.
func SnakeCase(s string) string //字符串转为SnakeCase, "fooBar" -> "foo_bar" func SnakeCase(s string) string //字符串转为SnakeCase, "fooBar" -> "foo_bar"
``` ```
#### 11. validator验证器 ### 12. system系统
- 包含一些操作系统运行时shell命令执行的函数.
- Usage: import "github.com/duke-git/lancet/system".
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/system"
)
func main() {
envFoo := system.GetOsEnv("foo")
fmt.Println(envFoo)
}
```
- Function list:
```go
func IsWindows() bool //判断操作系统是windows
func IsLinux() bool //判断操作系统是linux
func IsMac() bool //判断操作系统是macos
func GetOsEnv(key string) string //获取名称为key的环境变量
func SetOsEnv(key, value string) error //设置环境变量
func RemoveOsEnv(key string) error //删除指定key的环境变量
func CompareOsEnv(key, comparedEnv string) bool //获取名称为key的环境变量并和comparedEnv比较
func ExecCommand(command string) (err error, stdout, stderr string) //执行shell命令/bin/bash)
```
### 13. validator验证器包
- 数据校验相关函数 - 数据校验相关函数
- 导入包import "github.com/duke-git/lancet/validator" - 导入包import "github.com/duke-git/lancet/validator"
@@ -484,6 +567,12 @@ func main() {
func ContainChinese(s string) bool //判断字符串中是否含有中文字符 func ContainChinese(s string) bool //判断字符串中是否含有中文字符
func IsAlpha(s string) bool //判断字符串是否只含有字母 func IsAlpha(s string) bool //判断字符串是否只含有字母
func IsBase64(base64 string) bool //判断字符串是base64 func IsBase64(base64 string) bool //判断字符串是base64
func IsAllUpper(str string) bool //断字符串是否全是大写字母
func IsAllLower(str string) bool //断字符串是否全是小写字母
func ContainUpper(str string) bool //判断字符串是否包含大写字母
func ContainLower(str string) bool //判断字符串是否包含小写字母
func ContainLetter(str string) bool //判断字符串是否包含字母
func IsJSON(str string) bool //判断字符串是否是JSON
func IsChineseMobile(mobileNum string) bool //判断字符串是否是手机号 func IsChineseMobile(mobileNum string) bool //判断字符串是否是手机号
func IsChineseIdNum(id string) bool //判断字符串是否是身份证号 func IsChineseIdNum(id string) bool //判断字符串是否是身份证号
func IsChinesePhone(phone string) bool //判断字符串是否是座机电话号码 func IsChinesePhone(phone string) bool //判断字符串是否是座机电话号码

View File

@@ -79,10 +79,10 @@ func ToString(value interface{}) string {
func ToJson(value interface{}) (string, error) { func ToJson(value interface{}) (string, error) {
res, err := json.Marshal(value) res, err := json.Marshal(value)
if err != nil { if err != nil {
res = []byte("") return "", err
} }
return string(res), err return string(res), nil
} }
// ToFloat convert value to a float64, if input is not a float return 0.0 and error // ToFloat convert value to a float64, if input is not a float return 0.0 and error

View File

@@ -2,13 +2,14 @@ package convertor
import ( import (
"fmt" "fmt"
"reflect"
"testing" "testing"
"github.com/duke-git/lancet/internal" "github.com/duke-git/lancet/internal"
) )
func TestToChar(t *testing.T) { func TestToChar(t *testing.T) {
assert := internal.NewAssert(t, "TestToChar")
cases := []string{"", "abc", "1 2#3"} cases := []string{"", "abc", "1 2#3"}
expected := [][]string{ expected := [][]string{
{""}, {""},
@@ -16,28 +17,25 @@ func TestToChar(t *testing.T) {
{"1", " ", "2", "#", "3"}, {"1", " ", "2", "#", "3"},
} }
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res := ToChar(cases[i]) assert.Equal(expected[i], ToChar(cases[i]))
if !reflect.DeepEqual(res, expected[i]) {
internal.LogFailedTestInfo(t, "ToChar", cases[i], expected[i], res)
t.FailNow()
}
} }
} }
func TestToBool(t *testing.T) { func TestToBool(t *testing.T) {
assert := internal.NewAssert(t, "TestToBool")
cases := []string{"true", "True", "false", "False", "0", "1", "123"} cases := []string{"true", "True", "false", "False", "0", "1", "123"}
expected := []bool{true, true, false, false, false, true, false} expected := []bool{true, true, false, false, false, true, false}
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res, _ := ToBool(cases[i]) actual, _ := ToBool(cases[i])
if res != expected[i] { assert.Equal(expected[i], actual)
internal.LogFailedTestInfo(t, "ToBool", cases[i], expected[i], res)
t.FailNow()
}
} }
} }
func TestToBytes(t *testing.T) { func TestToBytes(t *testing.T) {
assert := internal.NewAssert(t, "TestToBytes")
cases := []interface{}{ cases := []interface{}{
0, 0,
false, false,
@@ -49,16 +47,14 @@ func TestToBytes(t *testing.T) {
{4, 12, 0, 1, 49}, {4, 12, 0, 1, 49},
} }
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res, _ := ToBytes(cases[i]) actual, _ := ToBytes(cases[i])
fmt.Println(res) assert.Equal(expected[i], actual)
if !reflect.DeepEqual(res, expected[i]) {
internal.LogFailedTestInfo(t, "ToBytes", cases[i], expected[i], res)
t.FailNow()
}
} }
} }
func TestToInt(t *testing.T) { func TestToInt(t *testing.T) {
assert := internal.NewAssert(t, "TestToInt")
cases := []interface{}{"123", "-123", 123, cases := []interface{}{"123", "-123", 123,
uint(123), uint8(123), uint16(123), uint32(123), uint64(123), uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float32(12.3), float64(12.3), float32(12.3), float64(12.3),
@@ -67,15 +63,14 @@ func TestToInt(t *testing.T) {
expected := []int64{123, -123, 123, 123, 123, 123, 123, 123, 12, 12, 0, 0, 0} expected := []int64{123, -123, 123, 123, 123, 123, 123, 123, 12, 12, 0, 0, 0}
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res, _ := ToInt(cases[i]) actual, _ := ToInt(cases[i])
if res != expected[i] { assert.Equal(expected[i], actual)
internal.LogFailedTestInfo(t, "ToInt", cases[i], expected[i], res)
t.FailNow()
}
} }
} }
func TestToFloat(t *testing.T) { func TestToFloat(t *testing.T) {
assert := internal.NewAssert(t, "TestToFloat")
cases := []interface{}{ cases := []interface{}{
"", "-1", "-.11", "1.23e3", ".123e10", "abc", "", "-1", "-.11", "1.23e3", ".123e10", "abc",
int(0), int8(1), int16(-1), int32(123), int64(123), int(0), int8(1), int16(-1), int32(123), int64(123),
@@ -86,22 +81,19 @@ func TestToFloat(t *testing.T) {
0, 1, -1, 123, 123, 123, 123, 123, 123, 123, 12.3, 12.300000190734863} 0, 1, -1, 123, 123, 123, 123, 123, 123, 123, 12.3, 12.300000190734863}
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res, _ := ToFloat(cases[i]) actual, _ := ToFloat(cases[i])
if res != expected[i] { assert.Equal(expected[i], actual)
internal.LogFailedTestInfo(t, "ToFloat", cases[i], expected[i], res)
t.FailNow()
}
} }
} }
func TestToString(t *testing.T) { func TestToString(t *testing.T) {
// map assert := internal.NewAssert(t, "TestToString")
aMap := make(map[string]int) aMap := make(map[string]int)
aMap["a"] = 1 aMap["a"] = 1
aMap["b"] = 2 aMap["b"] = 2
aMap["c"] = 3 aMap["c"] = 3
// struct
type TestStruct struct { type TestStruct struct {
Name string Name string
} }
@@ -124,75 +116,39 @@ func TestToString(t *testing.T) {
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"} "[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res := ToString(cases[i]) actual := ToString(cases[i])
if res != expected[i] { assert.Equal(expected[i], actual)
internal.LogFailedTestInfo(t, "ToString", cases[i], expected[i], res)
t.FailNow()
}
} }
} }
func TestToJson(t *testing.T) { func TestToJson(t *testing.T) {
// map assert := internal.NewAssert(t, "TestToJson")
aMap := make(map[string]int)
aMap["a"] = 1
aMap["b"] = 2
aMap["c"] = 3
mapJson := "{\"a\":1,\"b\":2,\"c\":3}" var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
r1, _ := ToJson(aMap) mapJsonStr, _ := ToJson(aMap)
if r1 != mapJson { assert.Equal("{\"a\":1,\"b\":2,\"c\":3}", mapJsonStr)
internal.LogFailedTestInfo(t, "ToJson", aMap, mapJson, r1)
t.FailNow()
}
// struct
type TestStruct struct { type TestStruct struct {
Name string Name string
} }
aStruct := TestStruct{Name: "TestStruct"} aStruct := TestStruct{Name: "TestStruct"}
structJson := "{\"Name\":\"TestStruct\"}" structJsonStr, _ := ToJson(aStruct)
r2, _ := ToJson(aStruct) assert.Equal("{\"Name\":\"TestStruct\"}", structJsonStr)
if r2 != structJson {
internal.LogFailedTestInfo(t, "ToJson", aMap, mapJson, r1)
t.FailNow()
}
} }
func TestStructToMap(t *testing.T) { func TestStructToMap(t *testing.T) {
assert := internal.NewAssert(t, "TestStructToMap")
type People struct { type People struct {
Name string `json:"name"` Name string `json:"name"`
age int age int
} }
p := People{
p1 := People{
"test", "test",
100, 100,
} }
pm, _ := StructToMap(p)
pm1, _ := StructToMap(p1) var expected = map[string]interface{}{"name": "test"}
m1 := make(map[string]interface{}) assert.Equal(expected, pm)
m1["name"] = "test"
//exp1["100"] = 100
if !reflect.DeepEqual(pm1, m1) {
internal.LogFailedTestInfo(t, "StructToMap", p1, m1, pm1)
t.FailNow()
}
p2 := People{
"test",
100,
}
pm2, _ := StructToMap(p1)
m2 := make(map[string]interface{})
m2["name"] = "test"
m2["100"] = 100
if reflect.DeepEqual(pm2, m2) {
internal.LogFailedTestInfo(t, "StructToMap", p2, m2, pm2)
t.FailNow()
}
} }
func TestColorHexToRGB(t *testing.T) { func TestColorHexToRGB(t *testing.T) {
@@ -201,22 +157,17 @@ func TestColorHexToRGB(t *testing.T) {
colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b) colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b)
expected := "0,51,102" expected := "0,51,102"
if colorRGB != expected { assert := internal.NewAssert(t, "TestColorHexToRGB")
internal.LogFailedTestInfo(t, "ColorHexToRGB", colorHex, expected, colorRGB) assert.Equal(expected, colorRGB)
t.FailNow()
}
} }
func TestColorRGBToHex(t *testing.T) { func TestColorRGBToHex(t *testing.T) {
r := 0 r := 0
g := 51 g := 51
b := 102 b := 102
colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b)
colorHex := ColorRGBToHex(r, g, b) colorHex := ColorRGBToHex(r, g, b)
expected := "#003366" expected := "#003366"
if colorHex != expected { assert := internal.NewAssert(t, "TestColorRGBToHex")
internal.LogFailedTestInfo(t, "ColorHexToRGB", colorRGB, expected, colorHex) assert.Equal(expected, colorHex)
t.FailNow()
}
} }

View File

@@ -13,10 +13,8 @@ func TestAesEcbEncrypt(t *testing.T) {
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key)) aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key)) aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
if string(aesEcbDecrypt) != data { assert := internal.NewAssert(t, "TestAesEcbEncrypt")
internal.LogFailedTestInfo(t, "AesEcbEncrypt/AesEcbDecrypt", data, data, string(aesEcbDecrypt)) assert.Equal(data, string(aesEcbDecrypt))
t.FailNow()
}
} }
func TestAesCbcEncrypt(t *testing.T) { func TestAesCbcEncrypt(t *testing.T) {
@@ -26,10 +24,8 @@ func TestAesCbcEncrypt(t *testing.T) {
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key)) aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key)) aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
if string(aesCbcDecrypt) != data { assert := internal.NewAssert(t, "TestAesCbcEncrypt")
internal.LogFailedTestInfo(t, "AesCbcEncrypt/AesCbcDecrypt", data, data, string(aesCbcDecrypt)) assert.Equal(data, string(aesCbcDecrypt))
t.FailNow()
}
} }
func TestAesCtrCrypt(t *testing.T) { func TestAesCtrCrypt(t *testing.T) {
@@ -39,10 +35,8 @@ func TestAesCtrCrypt(t *testing.T) {
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key)) aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key)) aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
if string(aesCtrDeCrypt) != data { assert := internal.NewAssert(t, "TestAesCtrCrypt")
internal.LogFailedTestInfo(t, "AesCtrCrypt", data, data, string(aesCtrDeCrypt)) assert.Equal(data, string(aesCtrDeCrypt))
t.FailNow()
}
} }
func TestAesCfbEncrypt(t *testing.T) { func TestAesCfbEncrypt(t *testing.T) {
@@ -52,10 +46,8 @@ func TestAesCfbEncrypt(t *testing.T) {
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key)) aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key)) aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
if string(aesCfbDecrypt) != data { assert := internal.NewAssert(t, "TestAesCfbEncrypt")
internal.LogFailedTestInfo(t, "AesCfbEncrypt/AesCfbDecrypt", data, data, string(aesCfbDecrypt)) assert.Equal(data, string(aesCfbDecrypt))
t.FailNow()
}
} }
func TestAesOfbEncrypt(t *testing.T) { func TestAesOfbEncrypt(t *testing.T) {
@@ -65,8 +57,6 @@ func TestAesOfbEncrypt(t *testing.T) {
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key)) aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key)) aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
if string(aesOfbDecrypt) != data { assert := internal.NewAssert(t, "TestAesOfbEncrypt")
internal.LogFailedTestInfo(t, "AesOfbEncrypt/AesOfbDecrypt", data, data, string(aesOfbDecrypt)) assert.Equal(data, string(aesOfbDecrypt))
t.FailNow()
}
} }

View File

@@ -1,66 +1,36 @@
package cryptor package cryptor
import ( import (
"fmt"
"os"
"testing" "testing"
"github.com/duke-git/lancet/internal" "github.com/duke-git/lancet/internal"
) )
func TestBase64StdEncode(t *testing.T) { func TestBase64StdEncode(t *testing.T) {
s := "hello world" assert := internal.NewAssert(t, "TestBase64StdEncode")
bs := Base64StdEncode(s) assert.Equal("aGVsbG8gd29ybGQ=", Base64StdEncode("hello world"))
if bs != "aGVsbG8gd29ybGQ=" {
internal.LogFailedTestInfo(t, "Base64StdEncode", s, "aGVsbG8gd29ybGQ=", bs)
t.FailNow()
}
} }
func TestBase64StdDecode(t *testing.T) { func TestBase64StdDecode(t *testing.T) {
bs := "aGVsbG8gd29ybGQ=" assert := internal.NewAssert(t, "TestBase64StdDecode")
s := Base64StdDecode(bs) assert.Equal("hello world", Base64StdDecode("aGVsbG8gd29ybGQ="))
if s != "hello world" {
internal.LogFailedTestInfo(t, "Base64StdDecode", bs, "hello world=", s)
t.FailNow()
}
} }
func TestMd5String(t *testing.T) { func TestMd5String(t *testing.T) {
s := "hello" assert := internal.NewAssert(t, "TestMd5String")
smd5 := Md5String(s) assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
expected := "5d41402abc4b2a76b9719d911017c592"
if smd5 != expected {
internal.LogFailedTestInfo(t, "Md5String", s, expected, smd5)
t.FailNow()
}
} }
func TestMd5File(t *testing.T) { func TestMd5File(t *testing.T) {
file, _ := os.Create("./hello.txt") fileMd5, err := Md5File("./basic.go")
defer file.Close() assert := internal.NewAssert(t, "TestMd5File")
file.WriteString("hello\n") assert.IsNotNil(fileMd5)
assert.IsNil(err)
fileMd5, err := Md5File("./hello.txt")
if err != nil {
t.FailNow()
}
fmt.Println(fileMd5)
} }
func TestHmacMd5(t *testing.T) { func TestHmacMd5(t *testing.T) {
s := "hello world" assert := internal.NewAssert(t, "TestHmacMd5")
key := "12345" assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345"))
hmacMd5 := HmacMd5(s, key)
expected := "5f4c9faaff0a1ad3007d9ddc06abe36d"
if hmacMd5 != expected {
internal.LogFailedTestInfo(t, "HmacMd5", s, expected, hmacMd5)
t.FailNow()
}
} }
func TestHmacSha1(t *testing.T) { func TestHmacSha1(t *testing.T) {
@@ -69,10 +39,8 @@ func TestHmacSha1(t *testing.T) {
hmacSha1 := HmacSha1(s, key) hmacSha1 := HmacSha1(s, key)
expected := "3826f812255d8683f051ee97346d1359234d5dbd" expected := "3826f812255d8683f051ee97346d1359234d5dbd"
if hmacSha1 != expected { assert := internal.NewAssert(t, "TestHmacSha1")
internal.LogFailedTestInfo(t, "HmacSha1", s, expected, hmacSha1) assert.Equal(expected, hmacSha1)
t.FailNow()
}
} }
func TestHmacSha256(t *testing.T) { func TestHmacSha256(t *testing.T) {
@@ -81,10 +49,8 @@ func TestHmacSha256(t *testing.T) {
hmacSha256 := HmacSha256(s, key) hmacSha256 := HmacSha256(s, key)
expected := "9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8" expected := "9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8"
if hmacSha256 != expected { assert := internal.NewAssert(t, "TestHmacSha256")
internal.LogFailedTestInfo(t, "HmacSha256", s, expected, hmacSha256) assert.Equal(expected, hmacSha256)
t.FailNow()
}
} }
func TestHmacSha512(t *testing.T) { func TestHmacSha512(t *testing.T) {
@@ -93,10 +59,8 @@ func TestHmacSha512(t *testing.T) {
hmacSha512 := HmacSha512(s, key) hmacSha512 := HmacSha512(s, key)
expected := "5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175" expected := "5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175"
if hmacSha512 != expected { assert := internal.NewAssert(t, "TestHmacSha512")
internal.LogFailedTestInfo(t, "HmacSha512", s, expected, hmacSha512) assert.Equal(expected, hmacSha512)
t.FailNow()
}
} }
func TestSha1(t *testing.T) { func TestSha1(t *testing.T) {
@@ -104,10 +68,8 @@ func TestSha1(t *testing.T) {
sha1 := Sha1(s) sha1 := Sha1(s)
expected := "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed" expected := "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"
if sha1 != expected { assert := internal.NewAssert(t, "TestSha1")
internal.LogFailedTestInfo(t, "Sha1", s, expected, sha1) assert.Equal(expected, sha1)
t.FailNow()
}
} }
func TestSha256(t *testing.T) { func TestSha256(t *testing.T) {
@@ -115,10 +77,8 @@ func TestSha256(t *testing.T) {
sha256 := Sha256(s) sha256 := Sha256(s)
expected := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" expected := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
if sha256 != expected { assert := internal.NewAssert(t, "TestSha256")
internal.LogFailedTestInfo(t, "Sha256", s, expected, sha256) assert.Equal(expected, sha256)
t.FailNow()
}
} }
func TestSha512(t *testing.T) { func TestSha512(t *testing.T) {
@@ -126,8 +86,6 @@ func TestSha512(t *testing.T) {
sha512 := Sha512(s) sha512 := Sha512(s)
expected := "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f" expected := "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"
if sha512 != expected { assert := internal.NewAssert(t, "TestSha512")
internal.LogFailedTestInfo(t, "Sha512", s, expected, sha512) assert.Equal(expected, sha512)
t.FailNow()
}
} }

View File

@@ -13,10 +13,8 @@ func TestDesEcbEncrypt(t *testing.T) {
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key)) desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key)) desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
if string(desEcbDecrypt) != data { assert := internal.NewAssert(t, "TestDesEcbEncrypt")
internal.LogFailedTestInfo(t, "DesEcbEncrypt/DesEcbDecrypt", data, data, string(desEcbDecrypt)) assert.Equal(data, string(desEcbDecrypt))
t.FailNow()
}
} }
func TestDesCbcEncrypt(t *testing.T) { func TestDesCbcEncrypt(t *testing.T) {
@@ -26,10 +24,8 @@ func TestDesCbcEncrypt(t *testing.T) {
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key)) desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key)) desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
if string(desCbcDecrypt) != data { assert := internal.NewAssert(t, "TestDesCbcEncrypt")
internal.LogFailedTestInfo(t, "DesCbcEncrypt/DesCbcDecrypt", data, data, string(desCbcDecrypt)) assert.Equal(data, string(desCbcDecrypt))
t.FailNow()
}
} }
func TestDesCtrCrypt(t *testing.T) { func TestDesCtrCrypt(t *testing.T) {
@@ -39,10 +35,8 @@ func TestDesCtrCrypt(t *testing.T) {
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key)) desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key)) desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
if string(desCtrDeCrypt) != data { assert := internal.NewAssert(t, "TestDesCtrCrypt")
internal.LogFailedTestInfo(t, "DesCtrCrypt", data, data, string(desCtrDeCrypt)) assert.Equal(data, string(desCtrDeCrypt))
t.FailNow()
}
} }
func TestDesCfbEncrypt(t *testing.T) { func TestDesCfbEncrypt(t *testing.T) {
@@ -52,10 +46,8 @@ func TestDesCfbEncrypt(t *testing.T) {
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key)) desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key)) desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
if string(desCfbDecrypt) != data { assert := internal.NewAssert(t, "TestDesCfbEncrypt")
internal.LogFailedTestInfo(t, "DesCfbEncrypt/DesCfbDecrypt", data, data, string(desCfbDecrypt)) assert.Equal(data, string(desCfbDecrypt))
t.FailNow()
}
} }
func TestDesOfbEncrypt(t *testing.T) { func TestDesOfbEncrypt(t *testing.T) {
@@ -65,8 +57,6 @@ func TestDesOfbEncrypt(t *testing.T) {
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key)) desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key)) desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
if string(desOfbDecrypt) != data { assert := internal.NewAssert(t, "TestDesOfbEncrypt")
internal.LogFailedTestInfo(t, "DesOfbEncrypt/DesOfbDecrypt", data, data, string(desOfbDecrypt)) assert.Equal(data, string(desOfbDecrypt))
t.FailNow()
}
} }

View File

@@ -12,8 +12,6 @@ func TestRsaEncrypt(t *testing.T) {
encrypted := RsaEncrypt(data, "rsa_public.pem") encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem") decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
if string(data) != string(decrypted) { assert := internal.NewAssert(t, "TestRsaEncrypt")
internal.LogFailedTestInfo(t, "RsaEncrypt/RsaDecrypt", string(data), string(data), string(decrypted)) assert.Equal(string(data), string(decrypted))
t.FailNow()
}
} }

View File

@@ -1,90 +1,67 @@
package datetime package datetime
import ( import (
"github.com/duke-git/lancet/internal"
"testing" "testing"
"time" "time"
"github.com/duke-git/lancet/internal"
) )
func TestAddDay(t *testing.T) { func TestAddDay(t *testing.T) {
now := time.Now() assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
after2Days := AddDay(now, 2) after2Days := AddDay(now, 2)
diff1 := after2Days.Sub(now) diff1 := after2Days.Sub(now)
if diff1.Hours() != 48 { assert.Equal(float64(48), diff1.Hours())
internal.LogFailedTestInfo(t, "AddDay", now, 48, diff1.Hours())
t.FailNow()
}
before2Days := AddDay(now, -2) before2Days := AddDay(now, -2)
diff2 := before2Days.Sub(now) diff2 := before2Days.Sub(now)
if diff2.Hours() != -48 { assert.Equal(float64(-48), diff2.Hours())
internal.LogFailedTestInfo(t, "AddDay", now, -48, diff2.Hours())
t.FailNow()
}
} }
func TestAddHour(t *testing.T) {
now := time.Now()
func TestAddHour(t *testing.T) {
assert := internal.NewAssert(t, "TestAddHour")
now := time.Now()
after2Hours := AddHour(now, 2) after2Hours := AddHour(now, 2)
diff1 := after2Hours.Sub(now) diff1 := after2Hours.Sub(now)
if diff1.Hours() != 2 { assert.Equal(float64(2), diff1.Hours())
internal.LogFailedTestInfo(t, "AddHour", now, 2, diff1.Hours())
t.FailNow()
}
before2Hours := AddHour(now, -2) before2Hours := AddHour(now, -2)
diff2 := before2Hours.Sub(now) diff2 := before2Hours.Sub(now)
if diff2.Hours() != -2 { assert.Equal(float64(-2), diff2.Hours())
internal.LogFailedTestInfo(t, "AddHour", now, -2, diff2.Hours())
t.FailNow()
}
} }
func TestAddMinute(t *testing.T) { func TestAddMinute(t *testing.T) {
now := time.Now() assert := internal.NewAssert(t, "TestAddMinute")
now := time.Now()
after2Minutes := AddMinute(now, 2) after2Minutes := AddMinute(now, 2)
diff1 := after2Minutes.Sub(now) diff1 := after2Minutes.Sub(now)
if diff1.Minutes() != 2 { assert.Equal(float64(2), diff1.Minutes())
internal.LogFailedTestInfo(t, "AddMinute", now, 2, diff1.Minutes())
t.FailNow()
}
before2Minutes := AddMinute(now, -2) before2Minutes := AddMinute(now, -2)
diff2 := before2Minutes.Sub(now) diff2 := before2Minutes.Sub(now)
if diff2.Minutes() != -2 { assert.Equal(float64(-2), diff2.Minutes())
internal.LogFailedTestInfo(t, "AddMinute", now, -2, diff2.Minutes())
t.FailNow()
}
} }
func TestGetNowDate(t *testing.T) { func TestGetNowDate(t *testing.T) {
date := GetNowDate() assert := internal.NewAssert(t, "TestGetNowDate")
expected := time.Now().Format("2006-01-02") expected := time.Now().Format("2006-01-02")
if date != expected { assert.Equal(expected, GetNowDate())
internal.LogFailedTestInfo(t, "GetNowDate", "", expected, date)
t.FailNow()
}
} }
func TestGetNotTime(t *testing.T) { func TestGetNotTime(t *testing.T) {
ts := GetNowTime() assert := internal.NewAssert(t, "TestGetNotTime")
expected := time.Now().Format("15:04:05") expected := time.Now().Format("15:04:05")
if ts != expected { assert.Equal(expected, GetNowTime())
internal.LogFailedTestInfo(t, "GetNowTime", "", expected, ts)
t.FailNow()
}
} }
func TestGetNowDateTime(t *testing.T) { func TestGetNowDateTime(t *testing.T) {
ts := GetNowDateTime() assert := internal.NewAssert(t, "TestGetNowDateTime")
expected := time.Now().Format("2006-01-02 15:04:05") expected := time.Now().Format("2006-01-02 15:04:05")
if ts != expected { assert.Equal(expected, GetNowDateTime())
internal.LogFailedTestInfo(t, "GetNowDateTime", "", expected, ts)
t.FailNow()
}
} }
//todo //todo
@@ -98,6 +75,8 @@ func TestGetNowDateTime(t *testing.T) {
//} //}
func TestFormatTimeToStr(t *testing.T) { func TestFormatTimeToStr(t *testing.T) {
assert := internal.NewAssert(t, "TestFormatTimeToStr")
datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08") datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
cases := []string{ cases := []string{
"yyyy-mm-dd hh:mm:ss", "yyyy-mm-dd", "yyyy-mm-dd hh:mm:ss", "yyyy-mm-dd",
@@ -110,16 +89,15 @@ func TestFormatTimeToStr(t *testing.T) {
"16:04:08", "2021/01"} "16:04:08", "2021/01"}
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res := FormatTimeToStr(datetime, cases[i]) actual := FormatTimeToStr(datetime, cases[i])
if res != expected[i] { assert.Equal(expected[i], actual)
internal.LogFailedTestInfo(t, "FormatTimeToStr", cases[i], expected[i], res)
t.FailNow()
}
}
}
} }
func TestFormatStrToTime(t *testing.T) { func TestFormatStrToTime(t *testing.T) {
assert := internal.NewAssert(t, "TestFormatStrToTime")
formats := []string{ formats := []string{
"2006-01-02 15:04:05", "2006-01-02", "2006-01-02 15:04:05", "2006-01-02",
"02-01-06 15:04:05", "2006/01/02 15:04:05", "02-01-06 15:04:05", "2006/01/02 15:04:05",
@@ -135,14 +113,11 @@ func TestFormatStrToTime(t *testing.T) {
"2021/01"} "2021/01"}
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res, err := FormatStrToTime(datetimeStr[i], cases[i]) actual, err := FormatStrToTime(datetimeStr[i], cases[i])
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
expected, _ := time.Parse(formats[i], datetimeStr[i]) expected, _ := time.Parse(formats[i], datetimeStr[i])
if res != expected { assert.Equal(expected, actual)
internal.LogFailedTestInfo(t, "FormatTimeToStr", cases[i], expected, res)
t.FailNow()
}
} }
} }

View File

@@ -5,11 +5,16 @@
package fileutil package fileutil
import ( import (
"archive/zip"
"bufio" "bufio"
"errors" "errors"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"path/filepath"
"strings"
) )
// IsExist checks if a file or directory exists // IsExist checks if a file or directory exists
@@ -148,3 +153,146 @@ func ListFileNames(path string) ([]string, error) {
return res, nil return res, nil
} }
// Zip create zip file, fpath could be a single file or a directory
func Zip(fpath string, destPath string) error {
zipFile, err := os.Create(destPath)
if err != nil {
return err
}
defer zipFile.Close()
archive := zip.NewWriter(zipFile)
defer archive.Close()
filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = strings.TrimPrefix(path, filepath.Dir(fpath)+"/")
if info.IsDir() {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if !info.IsDir() {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
if err != nil {
return err
}
}
return nil
})
return nil
}
// UnZip unzip the file and save it to destPath
func UnZip(zipFile string, destPath string) error {
zipReader, err := zip.OpenReader(zipFile)
if err != nil {
return err
}
defer zipReader.Close()
for _, f := range zipReader.File {
path := filepath.Join(destPath, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(path, os.ModePerm)
} else {
if err = os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
return err
}
inFile, err := f.Open()
if err != nil {
return err
}
defer inFile.Close()
outFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer outFile.Close()
_, err = io.Copy(outFile, inFile)
if err != nil {
return err
}
}
}
return nil
}
// IsLink checks if a file is symbol link or not
func IsLink(path string) bool {
fi, err := os.Lstat(path)
if err != nil {
return false
}
return fi.Mode()&os.ModeSymlink != 0
}
// FileMode return file's mode and permission
func FileMode(path string) (fs.FileMode, error) {
fi, err := os.Lstat(path)
if err != nil {
return 0, err
}
return fi.Mode(), nil
}
// MiMeType return file mime type
// file should be string or *os.File
func MiMeType(file interface{}) string {
var mediatype string
readBuffer := func(f *os.File) ([]byte, error) {
buffer := make([]byte, 512)
_, err := f.Read(buffer)
if err != nil {
return nil, err
}
return buffer, nil
}
if filePath, ok := file.(string); ok {
f, err := os.Open(filePath)
if err != nil {
return mediatype
}
buffer, err := readBuffer(f)
if err != nil {
return mediatype
}
return http.DetectContentType(buffer)
}
if f, ok := file.(*os.File); ok {
buffer, err := readBuffer(f)
if err != nil {
return mediatype
}
return http.DetectContentType(buffer)
}
return mediatype
}

View File

@@ -2,137 +2,201 @@ package fileutil
import ( import (
"os" "os"
"reflect"
"testing" "testing"
"github.com/duke-git/lancet/internal" "github.com/duke-git/lancet/internal"
) )
func TestIsExist(t *testing.T) { func TestIsExist(t *testing.T) {
assert := internal.NewAssert(t, "TestIsExist")
cases := []string{"./", "./file.go", "./a.txt"} cases := []string{"./", "./file.go", "./a.txt"}
expected := []bool{true, true, false} expected := []bool{true, true, false}
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res := IsExist(cases[i]) actual := IsExist(cases[i])
if res != expected[i] { assert.Equal(expected[i], actual)
internal.LogFailedTestInfo(t, "IsExist", cases[i], expected[i], res)
t.FailNow()
}
} }
} }
func TestCreateFile(t *testing.T) { func TestCreateFile(t *testing.T) {
assert := internal.NewAssert(t, "TestCreateFile")
f := "./text.txt" f := "./text.txt"
if CreateFile(f) { if CreateFile(f) {
file, err := os.Open(f) file, err := os.Open(f)
if err != nil { assert.IsNil(err)
internal.LogFailedTestInfo(t, "CreateFile", f, f, "create file error: "+err.Error()) assert.Equal(f, file.Name())
t.FailNow()
}
if file.Name() != f {
internal.LogFailedTestInfo(t, "CreateFile", f, f, file.Name())
t.FailNow()
}
} else { } else {
internal.LogFailedTestInfo(t, "CreateFile", f, f, "create file error")
t.FailNow() t.FailNow()
} }
os.Remove(f)
} }
func TestIsDir(t *testing.T) { func TestIsDir(t *testing.T) {
assert := internal.NewAssert(t, "TestIsDir")
cases := []string{"./", "./a.txt"} cases := []string{"./", "./a.txt"}
expected := []bool{true, false} expected := []bool{true, false}
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res := IsDir(cases[i]) actual := IsDir(cases[i])
if res != expected[i] { assert.Equal(expected[i], actual)
internal.LogFailedTestInfo(t, "IsDir", cases[i], expected[i], res)
t.FailNow()
}
} }
} }
func TestRemoveFile(t *testing.T) { func TestRemoveFile(t *testing.T) {
assert := internal.NewAssert(t, "TestRemoveFile")
f := "./text.txt" f := "./text.txt"
if CreateFile(f) { if !IsExist(f) {
CreateFile(f)
err := RemoveFile(f) err := RemoveFile(f)
if err != nil { assert.IsNil(err)
internal.LogFailedTestInfo(t, "RemoveFile", f, f, err.Error())
t.FailNow()
}
} else {
internal.LogFailedTestInfo(t, "RemoveFile", f, f, "create file error")
t.FailNow()
} }
} }
func TestCopyFile(t *testing.T) { func TestCopyFile(t *testing.T) {
assert := internal.NewAssert(t, "TestCopyFile")
srcFile := "./text.txt" srcFile := "./text.txt"
CreateFile(srcFile) CreateFile(srcFile)
dstFile := "./text_copy.txt" destFile := "./text_copy.txt"
err := CopyFile(srcFile, dstFile) err := CopyFile(srcFile, destFile)
if err != nil { if err != nil {
file, err := os.Open(dstFile) file, err := os.Open(destFile)
if err != nil { assert.IsNil(err)
internal.LogFailedTestInfo(t, "CopyFile", srcFile, dstFile, "create file error: "+err.Error()) assert.Equal(destFile, file.Name())
t.FailNow()
}
if file.Name() != dstFile {
internal.LogFailedTestInfo(t, "CopyFile", srcFile, dstFile, file.Name())
t.FailNow()
}
} }
os.Remove(srcFile)
os.Remove(destFile)
} }
func TestListFileNames(t *testing.T) { func TestListFileNames(t *testing.T) {
filesInCurrentPath, err := ListFileNames("../datetime/") assert := internal.NewAssert(t, "TestListFileNames")
if err != nil {
t.FailNow() filesInPath, err := ListFileNames("../datetime/")
} assert.IsNil(err)
expected := []string{"datetime.go", "datetime_test.go"} expected := []string{"datetime.go", "datetime_test.go"}
if !reflect.DeepEqual(filesInCurrentPath, expected) { assert.Equal(expected, filesInPath)
internal.LogFailedTestInfo(t, "ToChar", "./", expected, filesInCurrentPath)
t.FailNow()
}
} }
func TestReadFileToString(t *testing.T) { func TestReadFileToString(t *testing.T) {
assert := internal.NewAssert(t, "TestReadFileToString")
path := "./text.txt" path := "./text.txt"
CreateFile(path) CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777) f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world") f.WriteString("hello world")
res, _ := ReadFileToString(path) content, _ := ReadFileToString(path)
if res != "hello world" { assert.Equal("hello world", content)
internal.LogFailedTestInfo(t, "ReadFileToString", path, "hello world", res)
} os.Remove(path)
} }
func TestClearFile(t *testing.T) { func TestClearFile(t *testing.T) {
assert := internal.NewAssert(t, "TestClearFile")
path := "./text.txt" path := "./text.txt"
CreateFile(path) CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777) f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello world") f.WriteString("hello world")
CreateFile(path) err := ClearFile(path)
assert.IsNil(err)
res, _ := ReadFileToString(path) content, _ := ReadFileToString(path)
if res != "" { assert.Equal("", content)
internal.LogFailedTestInfo(t, "CreateFile", path, "", res)
} os.Remove(path)
} }
func TestReadFileByLine(t *testing.T) { func TestReadFileByLine(t *testing.T) {
assert := internal.NewAssert(t, "TestReadFileByLine")
path := "./text.txt" path := "./text.txt"
CreateFile(path) CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777) f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld") f.WriteString("hello\nworld")
expected := []string{"hello", "world"} expected := []string{"hello", "world"}
res, _ := ReadFileByLine(path) actual, _ := ReadFileByLine(path)
if !reflect.DeepEqual(res, expected) { assert.Equal(expected, actual)
internal.LogFailedTestInfo(t, "ReadFileByLine", path, expected, res)
} os.Remove(path)
}
func TestZipAndUnZip(t *testing.T) {
assert := internal.NewAssert(t, "TestZipAndUnZip")
srcFile := "./text.txt"
CreateFile(srcFile)
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
defer file.Close()
file.WriteString("hello\nworld")
zipFile := "./text.zip"
err := Zip(srcFile, zipFile)
assert.IsNil(err)
unZipPath := "./unzip"
err = UnZip(zipFile, unZipPath)
assert.IsNil(err)
unZipFile := "./unzip/text.txt"
assert.Equal(true, IsExist(unZipFile))
os.Remove(srcFile)
os.Remove(zipFile)
os.RemoveAll(unZipPath)
}
func TestFileMode(t *testing.T) {
assert := internal.NewAssert(t, "TestFileMode")
srcFile := "./text.txt"
CreateFile(srcFile)
mode, err := FileMode(srcFile)
assert.IsNil(err)
t.Log(mode)
os.Remove(srcFile)
}
func TestIsLink(t *testing.T) {
assert := internal.NewAssert(t, "TestIsLink")
srcFile := "./text.txt"
CreateFile(srcFile)
linkFile := "./text.link"
if !IsExist(linkFile) {
_ = os.Symlink(srcFile, linkFile)
}
assert.Equal(true, IsLink(linkFile))
assert.Equal(false, IsLink("./file.go"))
os.Remove(srcFile)
os.Remove(linkFile)
}
func TestMiMeType(t *testing.T) {
assert := internal.NewAssert(t, "TestMiMeType")
f, _ := os.Open("./file.go")
assert.Equal("text/plain; charset=utf-8", MiMeType(f))
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
} }

View File

@@ -7,22 +7,17 @@ import (
) )
func TestComma(t *testing.T) { func TestComma(t *testing.T) {
comma(t, "", "", "") assert := internal.NewAssert(t, "TestComma")
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{}) { assert.Equal("", Comma("", ""))
res := Comma(test, symbol) assert.Equal("", Comma("aa", ""))
if res != expected { assert.Equal("", Comma("aa.a", ""))
internal.LogFailedTestInfo(t, "Comma", test, expected, res) assert.Equal("", Comma([]int{1}, ""))
t.FailNow() assert.Equal("123", Comma("123", ""))
} assert.Equal("12,345", Comma("12345", ""))
assert.Equal("12,345", Comma(12345, ""))
assert.Equal("$12,345", Comma(12345, "$"))
assert.Equal("¥12,345", Comma(12345, "¥"))
assert.Equal("12,345.6789", Comma(12345.6789, ""))
} }

View File

@@ -6,6 +6,8 @@ import (
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/duke-git/lancet/internal"
) )
func TestAfter(t *testing.T) { func TestAfter(t *testing.T) {
@@ -32,6 +34,8 @@ func TestAfter(t *testing.T) {
} }
func TestBefore(t *testing.T) { func TestBefore(t *testing.T) {
assert := internal.NewAssert(t, "TestBefore")
arr := []string{"a", "b", "c", "d", "e"} arr := []string{"a", "b", "c", "d", "e"}
f := Before(3, func(i int) int { f := Before(3, func(i int) int {
return i return i
@@ -40,7 +44,6 @@ func TestBefore(t *testing.T) {
var res []int64 var res []int64
type cb func(args ...interface{}) []reflect.Value type cb func(args ...interface{}) []reflect.Value
appendStr := func(i int, s string, fn cb) { appendStr := func(i int, s string, fn cb) {
fmt.Printf("appendStr: arr[%d] is %s \n", i, s)
v := fn(i) v := fn(i)
res = append(res, v[0].Int()) res = append(res, v[0].Int())
} }
@@ -49,28 +52,26 @@ func TestBefore(t *testing.T) {
appendStr(i, arr[i], f) appendStr(i, arr[i], f)
} }
expect := []int64{0, 1, 2, 2, 2} expected := []int64{0, 1, 2, 2, 2}
if !reflect.DeepEqual(expect, res) { assert.Equal(expected, res)
t.FailNow()
}
} }
func TestCurry(t *testing.T) { func TestCurry(t *testing.T) {
assert := internal.NewAssert(t, "TestCurry")
add := func(a, b int) int { add := func(a, b int) int {
return a + b return a + b
} }
var addCurry Fn = func(values ...interface{}) interface{} { var addCurry Fn = func(values ...interface{}) interface{} {
return add(values[0].(int), values[1].(int)) return add(values[0].(int), values[1].(int))
} }
add1 := addCurry.Curry(1) add1 := addCurry.Curry(1)
v := add1(2) assert.Equal(3, add1(2))
if v != 3 {
t.FailNow()
}
} }
func TestCompose(t *testing.T) { func TestCompose(t *testing.T) {
assert := internal.NewAssert(t, "TestCompose")
toUpper := func(a ...interface{}) interface{} { toUpper := func(a ...interface{}) interface{} {
return strings.ToUpper(a[0].(string)) return strings.ToUpper(a[0].(string))
} }
@@ -78,27 +79,25 @@ func TestCompose(t *testing.T) {
return strings.ToLower(a[0].(string)) return strings.ToLower(a[0].(string))
} }
expect := toUpper(toLower("aBCde")) expected := toUpper(toLower("aBCde"))
cf := Compose(toUpper, toLower) cf := Compose(toUpper, toLower)
res := cf("aBCde") res := cf("aBCde")
if res != expect { assert.Equal(expected, res)
t.FailNow()
}
} }
func TestDelay(t *testing.T) { func TestDelay(t *testing.T) {
var print = func(s string) { var print = func(s string) {
fmt.Println(s) t.Log(s)
} }
Delay(2*time.Second, print, "test delay") Delay(2*time.Second, print, "test delay")
} }
func TestSchedule(t *testing.T) { func TestSchedule(t *testing.T) {
assert := internal.NewAssert(t, "TestSchedule")
var res []string var res []string
appendStr := func(s string) { appendStr := func(s string) {
fmt.Println(s)
res = append(res, s) res = append(res, s)
} }
@@ -106,9 +105,6 @@ func TestSchedule(t *testing.T) {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
close(stop) close(stop)
expect := []string{"*", "*", "*", "*", "*"} expected := []string{"*", "*", "*", "*", "*"}
if !reflect.DeepEqual(expect, res) { assert.Equal(expected, res)
t.FailNow()
}
fmt.Println("done")
} }

View File

@@ -2,26 +2,31 @@ package function
import ( import (
"testing" "testing"
"github.com/duke-git/lancet/internal"
) )
func TestWatcher(t *testing.T) { func TestWatcher(t *testing.T) {
assert := internal.NewAssert(t, "TestWatcher")
w := &Watcher{} w := &Watcher{}
w.Start() w.Start()
longRunningTask() longRunningTask()
if !w.excuting { assert.Equal(true, w.excuting)
t.FailNow()
}
w.Stop() w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds() eapsedTime := w.GetElapsedTime().Milliseconds()
t.Log("Elapsed Time (milsecond)", eapsedTime) t.Log("Elapsed Time (milsecond)", eapsedTime)
if w.excuting { assert.Equal(false, w.excuting)
t.FailNow()
} w.Reset()
assert.Equal(int64(0), w.startTime)
assert.Equal(int64(0), w.stopTime)
} }
func longRunningTask() { func longRunningTask() {

171
internal/assert.go Normal file
View File

@@ -0,0 +1,171 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package internal is for internal use.
package internal
import (
"fmt"
"reflect"
"runtime"
"testing"
)
const (
compareNotEqual int = iota - 2
compareLess
compareEqual
compareGreater
)
// Assert is a simple implementation of assertion, only for internal usage
type Assert struct {
T *testing.T
CaseName string
}
// NewAssert return instance of Assert
func NewAssert(t *testing.T, caseName string) *Assert {
return &Assert{T: t, CaseName: caseName}
}
// Equal check if expected is equal with actual
func (a *Assert) Equal(expected, actual interface{}) {
if compare(expected, actual) != compareEqual {
makeTestFailed(a.T, a.CaseName, expected, actual)
}
}
// NotEqual check if expected is not equal with actual
func (a *Assert) NotEqual(expected, actual interface{}) {
if compare(expected, actual) == compareEqual {
expectedInfo := fmt.Sprintf("not %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// Greater check if expected is greate than actual
func (a *Assert) Greater(expected, actual interface{}) {
if compare(expected, actual) != compareGreater {
expectedInfo := fmt.Sprintf("> %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// GreaterOrEqual check if expected is greate than or equal with actual
func (a *Assert) GreaterOrEqual(expected, actual interface{}) {
isGreatOrEqual := compare(expected, actual) == compareGreater || compare(expected, actual) == compareEqual
if !isGreatOrEqual {
expectedInfo := fmt.Sprintf(">= %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// Less check if expected is less than actual
func (a *Assert) Less(expected, actual interface{}) {
if compare(expected, actual) != compareLess {
expectedInfo := fmt.Sprintf("< %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// LessOrEqual check if expected is less than or equal with actual
func (a *Assert) LessOrEqual(expected, actual interface{}) {
isLessOrEqual := compare(expected, actual) == compareLess || compare(expected, actual) == compareEqual
if !isLessOrEqual {
expectedInfo := fmt.Sprintf("<= %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// IsNil check if value is nil
func (a *Assert) IsNil(value interface{}) {
if value != nil {
makeTestFailed(a.T, a.CaseName, nil, value)
}
}
// IsNotNil check if value is not nil
func (a *Assert) IsNotNil(value interface{}) {
if value == nil {
makeTestFailed(a.T, a.CaseName, "not nil", value)
}
}
// compare x and y return :
// x > y -> 1, x < y -> -1, x == y -> 0, x != y -> -2
func compare(x, y interface{}) int {
vx := reflect.ValueOf(x)
vy := reflect.ValueOf(y)
if vx.Type() != vy.Type() {
return compareNotEqual
}
switch vx.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
xInt := vx.Int()
yInt := vy.Int()
if xInt > yInt {
return compareGreater
}
if xInt == yInt {
return compareEqual
}
if xInt < yInt {
return compareLess
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
xUint := vx.Uint()
yUint := vy.Uint()
if xUint > yUint {
return compareGreater
}
if xUint == yUint {
return compareEqual
}
if xUint < yUint {
return compareLess
}
case reflect.Float32, reflect.Float64:
xFloat := vx.Float()
yFloat := vy.Float()
if xFloat > yFloat {
return compareGreater
}
if xFloat == yFloat {
return compareEqual
}
if xFloat < yFloat {
return compareLess
}
case reflect.String:
xString := vx.String()
yString := vy.String()
if xString > yString {
return compareGreater
}
if xString == yString {
return compareEqual
}
if xString < yString {
return compareLess
}
default:
if reflect.DeepEqual(x, y) {
return compareEqual
}
return compareNotEqual
}
return compareNotEqual
}
// logFailedInfo make test failed and log error info
func makeTestFailed(t *testing.T, caseName string, expected, actual interface{}) {
_, file, line, _ := runtime.Caller(2)
errInfo := fmt.Sprintf("Case %v failed. file: %v, line: %v, expected: %v, actual: %v.", caseName, file, line, expected, actual)
t.Error(errInfo)
t.FailNow()
}

30
internal/assert_test.go Normal file
View File

@@ -0,0 +1,30 @@
package internal
import (
"testing"
)
func TestAssert(t *testing.T) {
assert := NewAssert(t, "TestAssert")
assert.Equal(0, 0)
assert.NotEqual(1, 0)
assert.Greater(1, 0)
assert.GreaterOrEqual(1, 1)
assert.Less(0, 1)
assert.LessOrEqual(0, 0)
assert.Greater(1.1, 0.1)
assert.Less(0.1, 1.1)
assert.Equal("abc", "abc")
assert.NotEqual("abc", "abd")
assert.Less("abc", "abd")
assert.Greater("abd", "abc")
assert.Equal([]int{1, 2, 3}, []int{1, 2, 3})
assert.NotEqual([]int{1, 2, 3}, []int{1, 2})
assert.IsNil(nil)
assert.IsNotNil("abc")
}

View File

@@ -1,16 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package internal is for internal use.
package internal
import (
"fmt"
"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

@@ -1,7 +1,6 @@
package netutil package netutil
import ( import (
"fmt"
"net" "net"
"testing" "testing"
@@ -9,23 +8,25 @@ import (
) )
func TestGetInternalIp(t *testing.T) { func TestGetInternalIp(t *testing.T) {
assert := internal.NewAssert(t, "TestGetInternalIp")
internalIp := GetInternalIp() internalIp := GetInternalIp()
ip := net.ParseIP(internalIp) ip := net.ParseIP(internalIp)
if ip == nil { assert.IsNotNil(ip)
internal.LogFailedTestInfo(t, "GetInternalIp", "GetInternalIp", "", ip)
t.FailNow()
}
} }
func TestGetPublicIpInfo(t *testing.T) { func TestGetPublicIpInfo(t *testing.T) {
assert := internal.NewAssert(t, "TestGetPublicIpInfo")
publicIpInfo, err := GetPublicIpInfo() publicIpInfo, err := GetPublicIpInfo()
if err != nil { assert.IsNil(err)
t.FailNow()
} t.Logf("public ip info is: %+v \n", *publicIpInfo)
fmt.Printf("public ip info is: %+v \n", *publicIpInfo)
} }
func TestIsPublicIP(t *testing.T) { func TestIsPublicIP(t *testing.T) {
assert := internal.NewAssert(t, "TestIsPublicIP")
ips := []net.IP{ ips := []net.IP{
net.ParseIP("127.0.0.1"), net.ParseIP("127.0.0.1"),
net.ParseIP("192.168.0.1"), net.ParseIP("192.168.0.1"),
@@ -37,11 +38,7 @@ func TestIsPublicIP(t *testing.T) {
expected := []bool{false, false, false, false, true} expected := []bool{false, false, false, false, true}
for i := 0; i < len(ips); i++ { for i := 0; i < len(ips); i++ {
res := IsPublicIP(ips[i]) actual := IsPublicIP(ips[i])
assert.Equal(expected[i], actual)
if res != expected[i] {
internal.LogFailedTestInfo(t, "IsPublicIP", ips[i], expected[i], res)
t.FailNow()
}
} }
} }

View File

@@ -2,7 +2,6 @@ package netutil
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"testing" "testing"
@@ -23,7 +22,7 @@ func TestHttpGet(t *testing.T) {
} }
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body)) t.Log("response: ", resp.StatusCode, string(body))
} }
func TestHttpPost(t *testing.T) { func TestHttpPost(t *testing.T) {
@@ -44,7 +43,7 @@ func TestHttpPost(t *testing.T) {
t.FailNow() t.FailNow()
} }
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body)) t.Log("response: ", resp.StatusCode, string(body))
} }
func TestHttpPut(t *testing.T) { func TestHttpPut(t *testing.T) {
@@ -66,7 +65,7 @@ func TestHttpPut(t *testing.T) {
t.FailNow() t.FailNow()
} }
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body)) t.Log("response: ", resp.StatusCode, string(body))
} }
func TestHttpPatch(t *testing.T) { func TestHttpPatch(t *testing.T) {
@@ -88,7 +87,7 @@ func TestHttpPatch(t *testing.T) {
t.FailNow() t.FailNow()
} }
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body)) t.Log("response: ", resp.StatusCode, string(body))
} }
func TestHttpDelete(t *testing.T) { func TestHttpDelete(t *testing.T) {
@@ -99,22 +98,18 @@ func TestHttpDelete(t *testing.T) {
t.FailNow() t.FailNow()
} }
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body)) t.Log("response: ", resp.StatusCode, string(body))
} }
func TestConvertMapToQueryString(t *testing.T) { func TestConvertMapToQueryString(t *testing.T) {
assert := internal.NewAssert(t, "TestConvertMapToQueryString")
var m = map[string]interface{}{ var m = map[string]interface{}{
"c": 3, "c": 3,
"a": 1, "a": 1,
"b": 2, "b": 2,
} }
assert.Equal("a=1&b=2&c=3", ConvertMapToQueryString(m))
expected := "a=1&b=2&c=3"
r := ConvertMapToQueryString(m)
if r != expected {
internal.LogFailedTestInfo(t, "ConvertMapToQueryString", m, expected, r)
t.FailNow()
}
} }
func TestParseResponse(t *testing.T) { func TestParseResponse(t *testing.T) {
@@ -142,5 +137,5 @@ func TestParseResponse(t *testing.T) {
log.Fatal(err) log.Fatal(err)
t.FailNow() t.FailNow()
} }
fmt.Println("response: ", toDoResp) t.Log("response: ", toDoResp)
} }

View File

@@ -39,7 +39,7 @@ func RandInt(min, max int) int {
// RandBytes generate random byte slice // RandBytes generate random byte slice
func RandBytes(length int) []byte { func RandBytes(length int) []byte {
if length < 1 { if length < 1 {
return nil return []byte{}
} }
b := make([]byte, length) b := make([]byte, length)

View File

@@ -1,15 +1,6 @@
/*
* @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 package random
import ( import (
"fmt"
"reflect" "reflect"
"regexp" "regexp"
"testing" "testing"
@@ -18,54 +9,41 @@ import (
) )
func TestRandString(t *testing.T) { func TestRandString(t *testing.T) {
randStr := RandString(6)
fmt.Println(randStr)
pattern := `^[a-zA-Z]+$` pattern := `^[a-zA-Z]+$`
reg := regexp.MustCompile(pattern) reg := regexp.MustCompile(pattern)
if len(randStr) != 6 || !reg.MatchString(randStr) { randStr := RandString(6)
internal.LogFailedTestInfo(t, "RandString", "RandString(6)", "RandString(6) should be 6 letters ", randStr)
t.FailNow() assert := internal.NewAssert(t, "TestRandString")
} assert.Equal(6, len(randStr))
assert.Equal(true, reg.MatchString(randStr))
} }
func TestRandInt(t *testing.T) { func TestRandInt(t *testing.T) {
res1 := RandInt(1, 10) assert := internal.NewAssert(t, "TestRandInt")
if res1 < 1 || res1 >= 10 {
internal.LogFailedTestInfo(t, "RandInt", "RandInt(1, 10)", "RandInt(1, 10) should between [1, 10) ", res1)
t.FailNow()
}
res2 := RandInt(1, 1) r1 := RandInt(1, 10)
if res2 != 1 { assert.GreaterOrEqual(r1, 1)
internal.LogFailedTestInfo(t, "RandInt", "RandInt(1, 1)", "RandInt(1, 1) should be 1 ", res2) assert.Less(r1, 10)
t.FailNow()
}
res3 := RandInt(10, 1) r2 := RandInt(1, 1)
if res3 < 1 || res3 >= 10 { assert.Equal(1, r2)
internal.LogFailedTestInfo(t, "RandInt", "RandInt(10, 1)", "RandInt(10, 1) should between [1, 10) ", res3)
t.FailNow() r3 := RandInt(10, 1)
} assert.GreaterOrEqual(r1, 1)
assert.Less(r3, 10)
} }
func TestRandBytes(t *testing.T) { func TestRandBytes(t *testing.T) {
assert := internal.NewAssert(t, "TestRandBytes")
randBytes := RandBytes(4) randBytes := RandBytes(4)
if len(randBytes) != 4 { assert.Equal(4, len(randBytes))
internal.LogFailedTestInfo(t, "RandBytes", "RandBytes(4)", "RandBytes(4) should return 4 element of []bytes", randBytes)
t.FailNow()
}
v := reflect.ValueOf(randBytes) v := reflect.ValueOf(randBytes)
et := v.Type().Elem() elemType := v.Type().Elem()
if v.Kind() != reflect.Slice || et.Kind() != reflect.Uint8 { assert.Equal(reflect.Slice, v.Kind())
internal.LogFailedTestInfo(t, "RandBytes", "RandBytes(4)", "RandBytes(4) should return 4 element of []bytes", randBytes) assert.Equal(reflect.Uint8, elemType.Kind())
t.FailNow()
}
randErr := RandBytes(0)
if randErr != nil {
internal.LogFailedTestInfo(t, "RandBytes", "RandBytes(0)", "RandBytes(0) should return nil", randErr)
t.FailNow()
}
assert.Equal([]byte{}, RandBytes(0))
} }

89
retry/retry.go Normal file
View File

@@ -0,0 +1,89 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package retry is for executing a function repeatedly until it was successful or canceled by the context.
package retry
import (
"context"
"errors"
"fmt"
"reflect"
"runtime"
"strings"
"time"
)
const (
DefaultRetryTimes = 5
DefaultRetryDuration = time.Second * 3
)
// RetryConfig is config for retry
type RetryConfig struct {
context context.Context
retryTimes uint
retryDuration time.Duration
}
// RetryFn is function that retry executes
type RetryFunc func() error
// Option is for adding retry config
type Option func(*RetryConfig)
// RetryTimes set times of retry
func RetryTimes(n uint) Option {
return func(rc *RetryConfig) {
rc.retryTimes = n
}
}
// RetryDuration set duration of retries
func RetryDuration(d time.Duration) Option {
return func(rc *RetryConfig) {
rc.retryDuration = d
}
}
// Context set retry context config
func Context(ctx context.Context) Option {
return func(rc *RetryConfig) {
rc.context = ctx
}
}
// Retry executes the retryFunc repeatedly until it was successful or canceled by the context
// The default times of retries is 5 and the default duration between retries is 3 seconds
func Retry(retryFunc RetryFunc, opts ...Option) error {
config := &RetryConfig{
retryTimes: DefaultRetryTimes,
retryDuration: DefaultRetryDuration,
context: context.TODO(),
}
for _, opt := range opts {
opt(config)
}
var i uint
for i < config.retryTimes {
err := retryFunc()
if err != nil {
select {
case <-time.After(config.retryDuration):
case <-config.context.Done():
return errors.New("retry is cancelled")
}
} else {
return nil
}
i++
}
funcPath := runtime.FuncForPC(reflect.ValueOf(retryFunc).Pointer()).Name()
lastSlash := strings.LastIndex(funcPath, "/")
funcName := funcPath[lastSlash+1:]
return fmt.Errorf("function %s run failed after %d times retry", funcName, i)
}

80
retry/retry_test.go Normal file
View File

@@ -0,0 +1,80 @@
package retry
import (
"context"
"errors"
"testing"
"time"
"github.com/duke-git/lancet/internal"
)
func TestRetryFailed(t *testing.T) {
assert := internal.NewAssert(t, "TestRetryFailed")
var number int
increaseNumber := func() error {
number++
return errors.New("error occurs")
}
err := Retry(increaseNumber, RetryDuration(time.Microsecond*50))
assert.IsNotNil(err)
assert.Equal(DefaultRetryTimes, number)
}
func TestRetrySucceeded(t *testing.T) {
assert := internal.NewAssert(t, "TestRetrySucceeded")
var number int
increaseNumber := func() error {
number++
if number == DefaultRetryTimes {
return nil
}
return errors.New("error occurs")
}
err := Retry(increaseNumber, RetryDuration(time.Microsecond*50))
assert.IsNil(err)
assert.Equal(DefaultRetryTimes, number)
}
func TestSetRetryTimes(t *testing.T) {
assert := internal.NewAssert(t, "TestSetRetryTimes")
var number int
increaseNumber := func() error {
number++
return errors.New("error occurs")
}
err := Retry(increaseNumber, RetryDuration(time.Microsecond*50), RetryTimes(3))
assert.IsNotNil(err)
assert.Equal(3, number)
}
func TestCancelRetry(t *testing.T) {
assert := internal.NewAssert(t, "TestCancelRetry")
ctx, cancel := context.WithCancel(context.TODO())
var number int
increaseNumber := func() error {
number++
if number > 3 {
cancel()
}
return errors.New("error occurs")
}
err := Retry(increaseNumber,
RetryDuration(time.Microsecond*50),
Context(ctx),
)
assert.IsNotNil(err)
assert.Equal(4, number)
}

View File

@@ -17,7 +17,6 @@ import (
// Contain check if the value is in the iterable type or not // Contain check if the value is in the iterable type or not
func Contain(iterableType interface{}, value interface{}) bool { func Contain(iterableType interface{}, value interface{}) bool {
v := reflect.ValueOf(iterableType) v := reflect.ValueOf(iterableType)
switch kind := reflect.TypeOf(iterableType).Kind(); kind { switch kind := reflect.TypeOf(iterableType).Kind(); kind {
@@ -47,6 +46,30 @@ func Contain(iterableType interface{}, value interface{}) bool {
return false return false
} }
// ContainSubSlice check if the slice contain subslice or not
func ContainSubSlice(slice interface{}, subslice interface{}) bool {
super := sliceValue(slice)
sub := sliceValue(subslice)
if super.Type().Elem().Kind() != sub.Type().Elem().Kind() {
return false
}
unique := make(map[interface{}]bool)
for i := 0; i < super.Len(); i++ {
v := super.Index(i).Interface()
unique[v] = true
}
for i := 0; i < sub.Len(); i++ {
v := sub.Index(i).Interface()
if !unique[v] {
return false
}
}
return true
}
// Chunk creates an slice of elements split into groups the length of `size`. // Chunk creates an slice of elements split into groups the length of `size`.
func Chunk(slice []interface{}, size int) [][]interface{} { func Chunk(slice []interface{}, size int) [][]interface{} {
var res [][]interface{} var res [][]interface{}
@@ -121,6 +144,28 @@ func Every(slice, function interface{}) bool {
return currentLength == sv.Len() return currentLength == sv.Len()
} }
// None return true if all the values in the slice mismatch the criteria
// The function signature should be func(index int, value interface{}) bool .
func None(slice, function interface{}) bool {
sv := sliceValue(slice)
fn := functionValue(function)
elemType := sv.Type().Elem()
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
}
var currentLength int
for i := 0; i < sv.Len(); i++ {
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
if !flag.Bool() {
currentLength++
}
}
return currentLength == sv.Len()
}
// Some return true if any of the values in the list pass the predicate function. // 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 . // The function signature should be func(index int, value interface{}) bool .
func Some(slice, function interface{}) bool { func Some(slice, function interface{}) bool {
@@ -165,6 +210,28 @@ func Filter(slice, function interface{}) interface{} {
return res.Interface() return res.Interface()
} }
// Count iterates over elements of slice, returns a count of all matched elements
// The function signature should be func(index int, value interface{}) bool .
func Count(slice, function interface{}) int {
sv := sliceValue(slice)
fn := functionValue(function)
elemType := sv.Type().Elem()
if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) {
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
}
var counter int
for i := 0; i < sv.Len(); i++ {
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
if flag.Bool() {
counter++
}
}
return counter
}
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices // GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices
// The function signature should be func(index int, value interface{}) bool . // The function signature should be func(index int, value interface{}) bool .
func GroupBy(slice, function interface{}) (interface{}, interface{}) { func GroupBy(slice, function interface{}) (interface{}, interface{}) {
@@ -243,6 +310,22 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
return result return result
} }
// ForEach iterates over elements of slice and invokes function for each element
// The function signature should be func(index int, value interface{}).
func ForEach(slice, function interface{}) {
sv := sliceValue(slice)
fn := functionValue(function)
elemType := sv.Type().Elem()
if checkSliceCallbackFuncSignature(fn, elemType, nil) {
panic("function param should be of type func(int, " + elemType.String() + ")" + elemType.String())
}
for i := 0; i < sv.Len(); i++ {
fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})
}
}
// Map creates an slice of values by running each element of `slice` thru `function`. // 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{}. // The function signature should be func(index int, value interface{}) interface{}.
func Map(slice, function interface{}) interface{} { func Map(slice, function interface{}) interface{} {
@@ -615,18 +698,38 @@ func SortByField(slice interface{}, field string, sortType ...string) error {
} }
// Create a less function based on the field's kind. // Create a less function based on the field's kind.
var less func(a, b reflect.Value) bool var compare func(a, b reflect.Value) bool
switch sf.Type.Kind() { switch sf.Type.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } if len(sortType) > 0 && sortType[0] == "desc" {
compare = func(a, b reflect.Value) bool { return a.Int() > b.Int() }
} else {
compare = func(a, b reflect.Value) bool { return a.Int() < b.Int() }
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } if len(sortType) > 0 && sortType[0] == "desc" {
compare = func(a, b reflect.Value) bool { return a.Uint() > b.Uint() }
} else {
compare = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() }
}
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
less = func(a, b reflect.Value) bool { return a.Float() < b.Float() } if len(sortType) > 0 && sortType[0] == "desc" {
compare = func(a, b reflect.Value) bool { return a.Float() > b.Float() }
} else {
compare = func(a, b reflect.Value) bool { return a.Float() < b.Float() }
}
case reflect.String: case reflect.String:
less = func(a, b reflect.Value) bool { return a.String() < b.String() } if len(sortType) > 0 && sortType[0] == "desc" {
compare = func(a, b reflect.Value) bool { return a.String() > b.String() }
} else {
compare = func(a, b reflect.Value) bool { return a.String() < b.String() }
}
case reflect.Bool: case reflect.Bool:
less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } if len(sortType) > 0 && sortType[0] == "desc" {
compare = func(a, b reflect.Value) bool { return a.Bool() && !b.Bool() }
} else {
compare = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() }
}
default: default:
return fmt.Errorf("field type %s not supported", sf.Type) return fmt.Errorf("field type %s not supported", sf.Type)
} }
@@ -640,12 +743,9 @@ func SortByField(slice interface{}, field string, sortType ...string) error {
} }
a = a.FieldByIndex(sf.Index) a = a.FieldByIndex(sf.Index)
b = b.FieldByIndex(sf.Index) b = b.FieldByIndex(sf.Index)
return less(a, b) return compare(a, b)
}) })
if sortType[0] == "desc" {
ReverseSlice(slice)
}
return nil return nil
} }

View File

@@ -8,34 +8,34 @@ import (
) )
func TestContain(t *testing.T) { func TestContain(t *testing.T) {
t1 := []string{"a", "b", "c", "d"} assert := internal.NewAssert(t, "TestContain")
contain(t, t1, "a", true)
contain(t, t1, "e", false)
var t2 []string assert.Equal(true, Contain([]string{"a", "b", "c"}, "a"))
contain(t, t2, "1", false) assert.Equal(false, Contain([]string{"a", "b", "c"}, "d"))
assert.Equal(true, Contain([]string{""}, ""))
assert.Equal(false, Contain([]string{}, ""))
m := make(map[string]int) var m = map[string]int{"a": 1}
m["a"] = 1 assert.Equal(true, Contain(m, "a"))
contain(t, m, "a", true) assert.Equal(false, Contain(m, "b"))
contain(t, m, "b", false)
s := "hello" assert.Equal(true, Contain("abc", "a"))
contain(t, s, "h", true) assert.Equal(false, Contain("abc", "d"))
contain(t, s, "s", false)
} }
func contain(t *testing.T, test interface{}, value interface{}, expected bool) { func TestContainSubSlice(t *testing.T) {
res := Contain(test, value) assert := internal.NewAssert(t, "TestContainSubSlice")
if res != expected { assert.Equal(true, ContainSubSlice([]string{"a", "a", "b", "c"}, []string{"a", "a"}))
internal.LogFailedTestInfo(t, "Contain", test, expected, res) assert.Equal(false, ContainSubSlice([]string{"a", "a", "b", "c"}, []string{"a", "d"}))
t.FailNow()
} assert.Equal(true, ContainSubSlice([]int{1, 2, 3}, []int{1}))
assert.Equal(false, ContainSubSlice([]int{1, 2, 3}, []string{"a"}))
} }
func TestChunk(t *testing.T) { func TestChunk(t *testing.T) {
t1 := []string{"a", "b", "c", "d", "e"} assert := internal.NewAssert(t, "TestChunk")
arr := []string{"a", "b", "c", "d", "e"}
r1 := [][]interface{}{ r1 := [][]interface{}{
{"a"}, {"a"},
{"b"}, {"b"},
@@ -43,26 +43,26 @@ func TestChunk(t *testing.T) {
{"d"}, {"d"},
{"e"}, {"e"},
} }
chunk(t, InterfaceSlice(t1), 1, r1) assert.Equal(r1, Chunk(InterfaceSlice(arr), 1))
r2 := [][]interface{}{ r2 := [][]interface{}{
{"a", "b"}, {"a", "b"},
{"c", "d"}, {"c", "d"},
{"e"}, {"e"},
} }
chunk(t, InterfaceSlice(t1), 2, r2) assert.Equal(r2, Chunk(InterfaceSlice(arr), 2))
r3 := [][]interface{}{ r3 := [][]interface{}{
{"a", "b", "c"}, {"a", "b", "c"},
{"d", "e"}, {"d", "e"},
} }
chunk(t, InterfaceSlice(t1), 3, r3) assert.Equal(r3, Chunk(InterfaceSlice(arr), 3))
r4 := [][]interface{}{ r4 := [][]interface{}{
{"a", "b", "c", "d"}, {"a", "b", "c", "d"},
{"e"}, {"e"},
} }
chunk(t, InterfaceSlice(t1), 4, r4) assert.Equal(r4, Chunk(InterfaceSlice(arr), 4))
r5 := [][]interface{}{ r5 := [][]interface{}{
{"a"}, {"a"},
@@ -71,16 +71,7 @@ func TestChunk(t *testing.T) {
{"d"}, {"d"},
{"e"}, {"e"},
} }
chunk(t, InterfaceSlice(t1), 5, r5) assert.Equal(r5, Chunk(InterfaceSlice(arr), 5))
}
func chunk(t *testing.T, test []interface{}, num int, expected [][]interface{}) {
res := Chunk(test, num)
if !reflect.DeepEqual(res, expected) {
internal.LogFailedTestInfo(t, "Chunk", test, expected, res)
t.FailNow()
}
} }
func TestConvertSlice(t *testing.T) { func TestConvertSlice(t *testing.T) {
@@ -101,42 +92,44 @@ func TestEvery(t *testing.T) {
isEven := func(i, num int) bool { isEven := func(i, num int) bool {
return num%2 == 0 return num%2 == 0
} }
res := Every(nums, isEven)
if res != false { assert := internal.NewAssert(t, "TestEvery")
internal.LogFailedTestInfo(t, "Every", nums, false, res) assert.Equal(false, Every(nums, isEven))
t.FailNow() }
func TestNone(t *testing.T) {
nums := []int{1, 2, 3, 5}
check := func(i, num int) bool {
return num%2 == 1
} }
assert := internal.NewAssert(t, "TestNone")
assert.Equal(false, None(nums, check))
} }
func TestSome(t *testing.T) { func TestSome(t *testing.T) {
nums := []int{1, 2, 3, 5} nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool { hasEven := func(i, num int) bool {
return num%2 == 0 return num%2 == 0
} }
res := Some(nums, isEven)
if res != true { assert := internal.NewAssert(t, "TestSome")
internal.LogFailedTestInfo(t, "Some", nums, true, res) assert.Equal(true, Some(nums, hasEven))
t.FailNow()
}
} }
func TestFilter(t *testing.T) { func TestFilter(t *testing.T) {
nums := []int{1, 2, 3, 4, 5} nums := []int{1, 2, 3, 4, 5}
even := func(i, num int) bool { isEven := func(i, num int) bool {
return num%2 == 0 return num%2 == 0
} }
e1 := []int{2, 4}
r1 := Filter(nums, even) assert := internal.NewAssert(t, "TestFilter")
if !reflect.DeepEqual(r1, e1) { assert.Equal([]int{2, 4}, Filter(nums, isEven))
internal.LogFailedTestInfo(t, "Filter", nums, e1, r1)
t.FailNow()
}
type student struct { type student struct {
name string name string
age int age int
} }
students := []student{ students := []student{
{"a", 10}, {"a", 10},
{"b", 11}, {"b", 11},
@@ -144,8 +137,7 @@ func TestFilter(t *testing.T) {
{"d", 13}, {"d", 13},
{"e", 14}, {"e", 14},
} }
studentsOfAageGreat12 := []student{
e2 := []student{
{"d", 13}, {"d", 13},
{"e", 14}, {"e", 14},
} }
@@ -153,12 +145,7 @@ func TestFilter(t *testing.T) {
return s.age > 12 return s.age > 12
} }
r2 := Filter(students, filterFunc) assert.Equal(studentsOfAageGreat12, Filter(students, filterFunc))
if !reflect.DeepEqual(r2, e2) {
internal.LogFailedTestInfo(t, "Filter", students, e2, r2)
t.FailNow()
}
} }
func TestGroupBy(t *testing.T) { func TestGroupBy(t *testing.T) {
@@ -167,22 +154,22 @@ func TestGroupBy(t *testing.T) {
return (num % 2) == 0 return (num % 2) == 0
} }
expectedEven := []int{2, 4, 6} expectedEven := []int{2, 4, 6}
expectedOdd := []int{1, 3, 5}
even, odd := GroupBy(nums, evenFunc) even, odd := GroupBy(nums, evenFunc)
t.Log("odd", odd) assert := internal.NewAssert(t, "TestGroupBy")
assert.Equal(expectedEven, even)
assert.Equal(expectedOdd, odd)
}
t.Log("even", even) func TestCount(t *testing.T) {
nums := []int{1, 2, 3, 4, 5, 6}
if !reflect.DeepEqual(IntSlice(even), expectedEven) { evenFunc := func(i, num int) bool {
internal.LogFailedTestInfo(t, "GroupBy even", nums, expectedEven, even) return (num % 2) == 0
t.FailNow()
} }
expectedOdd := []int{1, 3, 5} assert := internal.NewAssert(t, "TestCount")
if !reflect.DeepEqual(IntSlice(odd), expectedOdd) { assert.Equal(3, Count(nums, evenFunc))
internal.LogFailedTestInfo(t, "GroupBy odd", nums, expectedOdd, odd)
t.FailNow()
}
} }
func TestFind(t *testing.T) { func TestFind(t *testing.T) {
@@ -195,10 +182,8 @@ func TestFind(t *testing.T) {
t.Fatal("found nothing") t.Fatal("found nothing")
} }
if res != 2 { assert := internal.NewAssert(t, "TestFind")
internal.LogFailedTestInfo(t, "Find", nums, 2, res) assert.Equal(2, res)
t.FailNow()
}
} }
func TestFindFoundNothing(t *testing.T) { func TestFindFoundNothing(t *testing.T) {
@@ -207,33 +192,42 @@ func TestFindFoundNothing(t *testing.T) {
return num > 1 return num > 1
} }
_, ok := Find(nums, findFunc) _, ok := Find(nums, findFunc)
if ok { // if ok {
t.Fatal("found something") // t.Fatal("found something")
} // }
assert := internal.NewAssert(t, "TestFindFoundNothing")
assert.Equal(false, ok)
} }
func TestFlattenDeep(t *testing.T) { func TestFlattenDeep(t *testing.T) {
input := [][][]string{{{"a", "b"}}, {{"c", "d"}}} input := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
expected := []string{"a", "b", "c", "d"} expected := []string{"a", "b", "c", "d"}
res := FlattenDeep(input) assert := internal.NewAssert(t, "TestFlattenDeep")
if !reflect.DeepEqual(res, expected) { assert.Equal(expected, FlattenDeep(input))
internal.LogFailedTestInfo(t, "FlattenDeep", input, expected, res) }
t.FailNow()
} func TestForEach(t *testing.T) {
numbers := []int{1, 2, 3, 4, 5}
expected := []int{3, 4, 5, 6, 7}
var numbersAddTwo []int
ForEach(numbers, func(index int, value int) {
numbersAddTwo = append(numbersAddTwo, value+2)
})
assert := internal.NewAssert(t, "TestForEach")
assert.Equal(expected, numbersAddTwo)
} }
func TestMap(t *testing.T) { func TestMap(t *testing.T) {
s1 := []int{1, 2, 3, 4} nums := []int{1, 2, 3, 4}
multiplyTwo := func(i, num int) int { multiplyTwo := func(i, num int) int {
return num * 2 return num * 2
} }
e1 := []int{2, 4, 6, 8}
r1 := Map(s1, multiplyTwo) assert := internal.NewAssert(t, "TestMap")
if !reflect.DeepEqual(r1, e1) { assert.Equal([]int{2, 4, 6, 8}, Map(nums, multiplyTwo))
internal.LogFailedTestInfo(t, "Map", s1, e1, r1)
t.FailNow()
}
type student struct { type student struct {
name string name string
@@ -244,8 +238,7 @@ func TestMap(t *testing.T) {
{"b", 2}, {"b", 2},
{"c", 3}, {"c", 3},
} }
studentsOfAdd10Aage := []student{
e2 := []student{
{"a", 11}, {"a", 11},
{"b", 12}, {"b", 12},
{"c", 13}, {"c", 13},
@@ -254,11 +247,8 @@ func TestMap(t *testing.T) {
s.age += 10 s.age += 10
return s return s
} }
r2 := Map(students, mapFunc)
if !reflect.DeepEqual(r2, e2) { assert.Equal(studentsOfAdd10Aage, Map(students, mapFunc))
internal.LogFailedTestInfo(t, "Filter", students, e2, r2)
t.FailNow()
}
} }
func TestReduce(t *testing.T) { func TestReduce(t *testing.T) {
@@ -266,239 +256,154 @@ func TestReduce(t *testing.T) {
{}, {},
{1}, {1},
{1, 2, 3, 4}} {1, 2, 3, 4}}
expected := []int{0, 1, 10} expected := []int{0, 1, 10}
f := func(i, v1, v2 int) int { f := func(i, v1, v2 int) int {
return v1 + v2 return v1 + v2
} }
assert := internal.NewAssert(t, "TestReduce")
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
res := Reduce(cases[i], f, 0) actual := Reduce(cases[i], f, 0)
if res != expected[i] { assert.Equal(expected[i], actual)
internal.LogFailedTestInfo(t, "Reduce", cases[i], expected[i], res)
t.FailNow()
}
} }
} }
func TestIntSlice(t *testing.T) { func TestIntSlice(t *testing.T) {
var t1 []interface{} var nums []interface{}
t1 = append(t1, 1, 2, 3, 4, 5) nums = append(nums, 1, 2, 3)
expect := []int{1, 2, 3, 4, 5}
intSlice(t, t1, expect)
}
func intSlice(t *testing.T, test interface{}, expected []int) { assert := internal.NewAssert(t, "TestIntSlice")
res := IntSlice(test) assert.Equal([]int{1, 2, 3}, IntSlice(nums))
if !reflect.DeepEqual(res, expected) {
internal.LogFailedTestInfo(t, "IntSlice", test, expected, res)
t.FailNow()
}
} }
func TestStringSlice(t *testing.T) { func TestStringSlice(t *testing.T) {
var t1 []interface{} var strs []interface{}
t1 = append(t1, "a", "b", "c", "d", "e") strs = append(strs, "a", "b", "c")
expect := []string{"a", "b", "c", "d", "e"}
stringSlice(t, t1, expect)
}
func stringSlice(t *testing.T, test interface{}, expected []string) { assert := internal.NewAssert(t, "TestStringSlice")
res := StringSlice(test) assert.Equal([]string{"a", "b", "c"}, StringSlice(strs))
if !reflect.DeepEqual(res, expected) {
internal.LogFailedTestInfo(t, "StringSlice", test, expected, res)
t.FailNow()
}
} }
func TestInterfaceSlice(t *testing.T) { func TestInterfaceSlice(t *testing.T) {
t1 := []string{"a", "b", "c", "d", "e"} strs := []string{"a", "b", "c"}
expect := []interface{}{"a", "b", "c", "d", "e"} expect := []interface{}{"a", "b", "c"}
interfaceSlice(t, t1, expect)
}
func interfaceSlice(t *testing.T, test interface{}, expected []interface{}) { assert := internal.NewAssert(t, "TestInterfaceSlice")
res := InterfaceSlice(test) assert.Equal(expect, InterfaceSlice(strs))
if !reflect.DeepEqual(res, expected) {
internal.LogFailedTestInfo(t, "InterfaceSlice", test, expected, res)
t.FailNow()
}
} }
func TestDeleteByIndex(t *testing.T) { func TestDeleteByIndex(t *testing.T) {
origin := []string{"a", "b", "c", "d", "e"} assert := internal.NewAssert(t, "TestDeleteByIndex")
t1 := []string{"a", "b", "c", "d", "e"} t1 := []string{"a", "b", "c", "d", "e"}
r1 := []string{"b", "c", "d", "e"} r1 := []string{"b", "c", "d", "e"}
deleteByIndex(t, origin, t1, 0, 0, r1) a1, _ := DeleteByIndex(t1, 0)
assert.Equal(r1, a1)
t1 = []string{"a", "b", "c", "d", "e"} t2 := []string{"a", "b", "c", "d", "e"}
r2 := []string{"a", "b", "c", "e"} r2 := []string{"a", "b", "c", "e"}
deleteByIndex(t, origin, t1, 3, 0, r2) a2, _ := DeleteByIndex(t2, 3)
assert.Equal(r2, a2)
t1 = []string{"a", "b", "c", "d", "e"} t3 := []string{"a", "b", "c", "d", "e"}
r3 := []string{"a", "b", "c", "d"} r3 := []string{"c", "d", "e"}
deleteByIndex(t, origin, t1, 4, 0, r3) a3, _ := DeleteByIndex(t3, 0, 2)
assert.Equal(r3, a3)
t1 = []string{"a", "b", "c", "d", "e"} t4 := []string{"a", "b", "c", "d", "e"}
r4 := []string{"c", "d", "e"} r4 := []string{}
deleteByIndex(t, origin, t1, 0, 2, r4) a4, _ := DeleteByIndex(t4, 0, 5)
assert.Equal(r4, a4)
t1 = []string{"a", "b", "c", "d", "e"} t5 := []string{"a", "b", "c", "d", "e"}
r5 := []string{} // var r5 []string{} failed _, err := DeleteByIndex(t5, 1, 1)
deleteByIndex(t, origin, t1, 0, 5, r5) assert.IsNotNil(err)
// failed _, err = DeleteByIndex(t5, 0, 6)
//t1 = []string{"a", "b", "c", "d","e"} assert.IsNotNil(err)
//r6 := []string{"a", "c", "d","e"}
//deleteByIndex(t, origin, t1, 1, 1, r6)
// failed
//t1 = []string{"a", "b", "c", "d","e"}
//r7 := []string{}
//deleteByIndex(t, origin, t1, 0, 6, r7)
}
func deleteByIndex(t *testing.T, origin, test interface{}, start, end int, expected interface{}) {
var res interface{}
var err error
if end != 0 {
res, err = DeleteByIndex(test, start, end)
} else {
res, err = DeleteByIndex(test, start)
}
if err != nil {
t.Error("DeleteByIndex Error: " + err.Error())
}
if !reflect.DeepEqual(res, expected) {
internal.LogFailedTestInfo(t, "DeleteByIndex", origin, expected, res)
t.FailNow()
}
} }
func TestDrop(t *testing.T) { func TestDrop(t *testing.T) {
drop(t, []int{}, 0, []int{}) assert := internal.NewAssert(t, "TestInterfaceSlice")
drop(t, []int{}, 1, []int{})
drop(t, []int{}, -1, []int{})
drop(t, []int{1, 2, 3, 4, 5}, 0, []int{1, 2, 3, 4, 5}) assert.Equal([]int{}, Drop([]int{}, 0))
drop(t, []int{1, 2, 3, 4, 5}, 1, []int{2, 3, 4, 5}) assert.Equal([]int{}, Drop([]int{}, 1))
drop(t, []int{1, 2, 3, 4, 5}, 5, []int{}) assert.Equal([]int{}, Drop([]int{}, -1))
drop(t, []int{1, 2, 3, 4, 5}, 6, []int{})
drop(t, []int{1, 2, 3, 4, 5}, -1, []int{1, 2, 3, 4}) assert.Equal([]int{1, 2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, 0))
drop(t, []int{1, 2, 3, 4, 5}, -5, []int{}) assert.Equal([]int{2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, 1))
drop(t, []int{1, 2, 3, 4, 5}, -6, []int{}) assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 5))
} assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 6))
func drop(t *testing.T, test interface{}, n int, expected interface{}) { assert.Equal([]int{1, 2, 3, 4}, Drop([]int{1, 2, 3, 4, 5}, -1))
res := Drop(test, n) assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6))
if !reflect.DeepEqual(res, expected) { assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6))
internal.LogFailedTestInfo(t, "Drop", test, expected, res)
t.FailNow()
}
} }
func TestInsertByIndex(t *testing.T) { func TestInsertByIndex(t *testing.T) {
assert := internal.NewAssert(t, "TestInsertByIndex")
t1 := []string{"a", "b", "c"} t1 := []string{"a", "b", "c"}
r1, _ := InsertByIndex(t1, 0, "1")
assert.Equal([]string{"1", "a", "b", "c"}, r1)
r1 := []string{"1", "a", "b", "c"} r2, _ := InsertByIndex(t1, 1, "1")
insertByIndex(t, t1, 0, "1", r1) assert.Equal([]string{"a", "1", "b", "c"}, r2)
r2 := []string{"a", "1", "b", "c"} r3, _ := InsertByIndex(t1, 3, "1")
insertByIndex(t, t1, 1, "1", r2) assert.Equal([]string{"a", "b", "c", "1"}, r3)
r3 := []string{"a", "b", "c", "1"} r4, _ := InsertByIndex(t1, 0, []string{"1", "2", "3"})
insertByIndex(t, t1, 3, "1", r3) assert.Equal([]string{"1", "2", "3", "a", "b", "c"}, r4)
r4 := []string{"1", "2", "3", "a", "b", "c"} r5, _ := InsertByIndex(t1, 3, []string{"1", "2", "3"})
insertByIndex(t, t1, 0, []string{"1", "2", "3"}, r4) assert.Equal([]string{"a", "b", "c", "1", "2", "3"}, r5)
r5 := []string{"a", "1", "2", "3", "b", "c"} _, err := InsertByIndex(t1, 4, "1")
insertByIndex(t, t1, 1, []string{"1", "2", "3"}, r5) assert.IsNotNil(err)
r6 := []string{"a", "b", "1", "2", "3", "c"} _, err = InsertByIndex(t1, 0, 1)
insertByIndex(t, t1, 2, []string{"1", "2", "3"}, r6) assert.IsNotNil(err)
r7 := []string{"a", "b", "c", "1", "2", "3"}
insertByIndex(t, t1, 3, []string{"1", "2", "3"}, r7)
}
func insertByIndex(t *testing.T, test interface{}, index int, value, expected interface{}) {
res, err := InsertByIndex(test, index, value)
if err != nil {
t.Error("InsertByIndex Error: " + err.Error())
}
if !reflect.DeepEqual(res, expected) {
internal.LogFailedTestInfo(t, "InsertByIndex", test, expected, res)
t.FailNow()
}
} }
func TestUpdateByIndex(t *testing.T) { func TestUpdateByIndex(t *testing.T) {
assert := internal.NewAssert(t, "TestUpdateByIndex")
t1 := []string{"a", "b", "c"} t1 := []string{"a", "b", "c"}
r1 := []string{"1", "b", "c"} r1, _ := UpdateByIndex(t1, 0, "1")
updateByIndex(t, t1, 0, "1", r1) assert.Equal([]string{"1", "b", "c"}, r1)
t1 = []string{"a", "b", "c"} t2 := []string{"a", "b", "c"}
r2 := []string{"a", "1", "c"} r2, _ := UpdateByIndex(t2, 1, "1")
updateByIndex(t, t1, 1, "1", r2) assert.Equal([]string{"a", "1", "c"}, r2)
t1 = []string{"a", "b", "c"} _, err := UpdateByIndex([]string{"a", "b", "c"}, 4, "1")
r3 := []string{"a", "b", "1"} assert.IsNotNil(err)
updateByIndex(t, t1, 2, "1", r3)
} _, err = UpdateByIndex([]string{"a", "b", "c"}, 0, 1)
assert.IsNotNil(err)
func updateByIndex(t *testing.T, test interface{}, index int, value, expected interface{}) {
res, err := UpdateByIndex(test, index, value)
if err != nil {
t.Error("UpdateByIndex Error: " + err.Error())
}
if !reflect.DeepEqual(res, expected) {
internal.LogFailedTestInfo(t, "UpdateByIndex", test, expected, res)
t.FailNow()
}
} }
func TestUnique(t *testing.T) { func TestUnique(t *testing.T) {
t1 := []int{1, 2, 2, 3} assert := internal.NewAssert(t, "TestUnique")
e1 := []int{1, 2, 3}
r1 := Unique(t1)
if !reflect.DeepEqual(r1, e1) {
internal.LogFailedTestInfo(t, "Unique", t1, e1, r1)
t.FailNow()
}
t2 := []string{"a", "a", "b", "c"} assert.Equal([]int{1, 2, 3}, Unique([]int{1, 2, 2, 3}))
e2 := []string{"a", "b", "c"} assert.Equal([]string{"a", "b", "c"}, Unique([]string{"a", "a", "b", "c"}))
r2 := Unique(t2)
if !reflect.DeepEqual(r2, e2) {
internal.LogFailedTestInfo(t, "Unique", t2, e2, r2)
t.FailNow()
}
} }
func TestUnion(t *testing.T) { func TestUnion(t *testing.T) {
assert := internal.NewAssert(t, "TestUnion")
s1 := []int{1, 3, 4, 6} s1 := []int{1, 3, 4, 6}
s2 := []int{1, 2, 5, 6} s2 := []int{1, 2, 5, 6}
s3 := []int{0, 4, 5, 7} s3 := []int{0, 4, 5, 7}
expected1 := []int{1, 3, 4, 6, 2, 5, 0, 7} assert.Equal([]int{1, 3, 4, 6, 2, 5, 0, 7}, Union(s1, s2, s3))
res1 := Union(s1, s2, s3) assert.Equal([]int{1, 3, 4, 6, 2, 5}, Union(s1, s2))
if !reflect.DeepEqual(res1, expected1) { assert.Equal([]int{1, 3, 4, 6}, Union(s1))
internal.LogFailedTestInfo(t, "Union", s1, expected1, res1)
t.FailNow()
}
expected2 := []int{1, 3, 4, 6}
res2 := Union(s1)
if !reflect.DeepEqual(res2, expected2) {
internal.LogFailedTestInfo(t, "Union", s1, expected2, res2)
t.FailNow()
}
} }
func TestIntersection(t *testing.T) { func TestIntersection(t *testing.T) {
@@ -519,45 +424,37 @@ func TestIntersection(t *testing.T) {
Intersection(s1), Intersection(s1),
Intersection(s1, s4), Intersection(s1, s4),
} }
for i := 0; i < len(res); i++ {
if !reflect.DeepEqual(res[i], expected[i]) {
internal.LogFailedTestInfo(t, "Intersection", "Intersection", expected[i], res[i])
t.FailNow()
}
}
assert := internal.NewAssert(t, "TestIntersection")
for i := 0; i < len(res); i++ {
assert.Equal(res[i], expected[i])
}
} }
func TestReverseSlice(t *testing.T) { func TestReverseSlice(t *testing.T) {
assert := internal.NewAssert(t, "TestIntersection")
s1 := []int{1, 2, 3, 4, 5} s1 := []int{1, 2, 3, 4, 5}
e1 := []int{5, 4, 3, 2, 1}
ReverseSlice(s1) ReverseSlice(s1)
if !reflect.DeepEqual(s1, e1) { assert.Equal([]int{5, 4, 3, 2, 1}, s1)
internal.LogFailedTestInfo(t, "ReverseSlice", s1, e1, s1)
t.FailNow()
}
s2 := []string{"a", "b", "c", "d", "e"} s2 := []string{"a", "b", "c", "d", "e"}
e2 := []string{"e", "d", "c", "b", "a"}
ReverseSlice(s2) ReverseSlice(s2)
if !reflect.DeepEqual(s2, e2) { assert.Equal([]string{"e", "d", "c", "b", "a"}, s2)
internal.LogFailedTestInfo(t, "ReverseSlice", s2, e2, s2)
t.FailNow()
}
} }
func TestDifference(t *testing.T) { func TestDifference(t *testing.T) {
assert := internal.NewAssert(t, "TestIntersection")
s1 := []int{1, 2, 3, 4, 5} s1 := []int{1, 2, 3, 4, 5}
s2 := []int{4, 5, 6} s2 := []int{4, 5, 6}
e1 := []int{1, 2, 3} assert.Equal([]int{1, 2, 3}, Difference(s1, s2))
r1 := Difference(s1, s2)
if !reflect.DeepEqual(r1, e1) {
internal.LogFailedTestInfo(t, "Difference", s1, e1, r1)
t.FailNow()
}
} }
func TestSortByField(t *testing.T) { func TestSortByFielDesc(t *testing.T) {
assert := internal.NewAssert(t, "TestWithout")
type student struct { type student struct {
name string name string
age int age int
@@ -568,8 +465,7 @@ func TestSortByField(t *testing.T) {
{"c", 5}, {"c", 5},
{"d", 6}, {"d", 6},
} }
studentsOfSortByAge := []student{
sortByAge := []student{
{"b", 15}, {"b", 15},
{"a", 10}, {"a", 10},
{"d", 6}, {"d", 6},
@@ -577,35 +473,61 @@ func TestSortByField(t *testing.T) {
} }
err := SortByField(students, "age", "desc") err := SortByField(students, "age", "desc")
if err != nil { assert.IsNil(err)
t.Error("IntSlice Error: " + err.Error())
assert.Equal(students, studentsOfSortByAge)
}
func TestSortByFieldAsc(t *testing.T) {
assert := internal.NewAssert(t, "TestSortByField")
type student struct {
name string
age int
}
students := []student{
{"a", 10},
{"b", 15},
{"c", 5},
{"d", 6},
}
studentsOfSortByAge := []student{
{"c", 5},
{"d", 6},
{"a", 10},
{"b", 15},
} }
if !reflect.DeepEqual(students, sortByAge) { err := SortByField(students, "age")
internal.LogFailedTestInfo(t, "SortByField", students, sortByAge, students) assert.IsNil(err)
t.FailNow()
}
assert.Equal(students, studentsOfSortByAge)
} }
func TestWithout(t *testing.T) { func TestWithout(t *testing.T) {
s := []int{1, 2, 3, 4, 5} assert := internal.NewAssert(t, "TestWithout")
expected := []int{3, 4, 5} assert.Equal([]int{3, 4, 5}, Without([]int{1, 2, 3, 4, 5}, 1, 2))
res := Without(s, 1, 2) assert.Equal([]int{1, 2, 3, 4, 5}, Without([]int{1, 2, 3, 4, 5}))
if !reflect.DeepEqual(res, expected) {
internal.LogFailedTestInfo(t, "Without", s, expected, res)
t.FailNow()
}
} }
func TestShuffle(t *testing.T) { func TestShuffle(t *testing.T) {
assert := internal.NewAssert(t, "TestShuffle")
s := []int{1, 2, 3, 4, 5} s := []int{1, 2, 3, 4, 5}
res := Shuffle(s) res := Shuffle(s)
t.Log("Shuffle result: ", res) t.Log("Shuffle result: ", res)
if reflect.TypeOf(s) != reflect.TypeOf(res) { assert.Equal(reflect.TypeOf(s), reflect.TypeOf(res))
internal.LogFailedTestInfo(t, "Shuffle", s, res, res)
t.FailNow() rv := reflect.ValueOf(res)
} assert.Equal(5, rv.Len())
assert.Equal(true, rv.Kind() == reflect.Slice)
assert.Equal(true, rv.Type().Elem().Kind() == reflect.Int)
assert.Equal(true, Contain(res, 1))
assert.Equal(true, Contain(res, 2))
assert.Equal(true, Contain(res, 3))
assert.Equal(true, Contain(res, 4))
assert.Equal(true, Contain(res, 5))
} }

View File

@@ -7,231 +7,162 @@ import (
) )
func TestCamelCase(t *testing.T) { func TestCamelCase(t *testing.T) {
camelCase(t, "foo_bar", "fooBar") assert := internal.NewAssert(t, "TestCamelCase")
camelCase(t, "Foo-Bar", "fooBar")
camelCase(t, "Foo&bar", "fooBar")
camelCase(t, "foo bar", "fooBar")
}
func camelCase(t *testing.T, test string, expected string) { assert.Equal("fooBar", CamelCase("foo_bar"))
res := CamelCase(test) assert.Equal("fooBar", CamelCase("Foo-Bar"))
if res != expected { assert.Equal("fooBar", CamelCase("Foo&bar"))
internal.LogFailedTestInfo(t, "CamelCase", test, expected, res) assert.Equal("fooBar", CamelCase("foo bar"))
t.FailNow()
} assert.NotEqual("FooBar", CamelCase("foo_bar"))
} }
func TestCapitalize(t *testing.T) { func TestCapitalize(t *testing.T) {
capitalize(t, "foo", "Foo") assert := internal.NewAssert(t, "TestCapitalize")
capitalize(t, "fOO", "Foo")
capitalize(t, "FOo", "Foo")
}
func capitalize(t *testing.T, test string, expected string) { assert.Equal("Foo", Capitalize("foo"))
res := Capitalize(test) assert.Equal("Foo", Capitalize("Foo"))
if res != expected { assert.Equal("Foo", Capitalize("Foo"))
internal.LogFailedTestInfo(t, "Capitalize", test, expected, res)
t.FailNow() assert.NotEqual("foo", Capitalize("Foo"))
}
} }
func TestKebabCase(t *testing.T) { func TestKebabCase(t *testing.T) {
kebabCase(t, "Foo Bar-", "foo-bar") assert := internal.NewAssert(t, "TestKebabCase")
kebabCase(t, "foo_Bar", "foo-bar")
kebabCase(t, "fooBar", "foo-bar")
kebabCase(t, "__FOO_BAR__", "f-o-o-b-a-r")
}
func kebabCase(t *testing.T, test string, expected string) { assert.Equal("foo-bar", KebabCase("Foo Bar-"))
res := KebabCase(test) assert.Equal("foo-bar", KebabCase("foo_Bar"))
if res != expected { assert.Equal("foo-bar", KebabCase("fooBar"))
internal.LogFailedTestInfo(t, "KebabCase", test, expected, res) assert.Equal("f-o-o-b-a-r", KebabCase("__FOO_BAR__"))
t.FailNow()
} assert.NotEqual("foo_bar", KebabCase("fooBar"))
} }
func TestSnakeCase(t *testing.T) { func TestSnakeCase(t *testing.T) {
snakeCase(t, "Foo Bar-", "foo_bar") assert := internal.NewAssert(t, "TestSnakeCase")
snakeCase(t, "foo_Bar", "foo_bar")
snakeCase(t, "fooBar", "foo_bar")
snakeCase(t, "__FOO_BAR__", "f_o_o_b_a_r")
snakeCase(t, "aBbc-s$@a&%_B.B^C", "a_bbc_s_a_b_b_c")
}
func snakeCase(t *testing.T, test string, expected string) { assert.Equal("foo_bar", SnakeCase("Foo Bar-"))
res := SnakeCase(test) assert.Equal("foo_bar", SnakeCase("foo_Bar"))
if res != expected { assert.Equal("foo_bar", SnakeCase("fooBar"))
internal.LogFailedTestInfo(t, "SnakeCase", test, expected, res) assert.Equal("f_o_o_b_a_r", SnakeCase("__FOO_BAR__"))
t.FailNow() assert.Equal("a_bbc_s_a_b_b_c", SnakeCase("aBbc-s$@a&%_B.B^C"))
}
assert.NotEqual("foo-bar", SnakeCase("foo_Bar"))
} }
func TestLowerFirst(t *testing.T) { func TestLowerFirst(t *testing.T) {
lowerFirst(t, "foo", "foo") assert := internal.NewAssert(t, "TestLowerFirst")
lowerFirst(t, "BAR", "bAR")
lowerFirst(t, "FOo", "fOo")
lowerFirst(t, "FOo大", "fOo大")
}
func lowerFirst(t *testing.T, test string, expected string) { assert.Equal("foo", LowerFirst("foo"))
res := LowerFirst(test) assert.Equal("bAR", LowerFirst("BAR"))
if res != expected { assert.Equal("fOo", LowerFirst("FOo"))
internal.LogFailedTestInfo(t, "LowerFirst", test, expected, res) assert.Equal("fOo大", LowerFirst("FOo大"))
t.FailNow()
} assert.NotEqual("Bar", LowerFirst("BAR"))
} }
func TestPadEnd(t *testing.T) { func TestPadEnd(t *testing.T) {
padEnd(t, "a", 1, "b", "a") assert := internal.NewAssert(t, "TestPadEnd")
padEnd(t, "a", 2, "b", "ab")
padEnd(t, "abcd", 6, "mno", "abcdmn")
padEnd(t, "abcd", 6, "m", "abcdmm")
padEnd(t, "abc", 6, "ab", "abcaba")
}
func padEnd(t *testing.T, source string, size int, fillString string, expected string) { assert.Equal("a", PadEnd("a", 1, "b"))
res := PadEnd(source, size, fillString) assert.Equal("ab", PadEnd("a", 2, "b"))
if res != expected { assert.Equal("abcdmn", PadEnd("abcd", 6, "mno"))
internal.LogFailedTestInfo(t, "PadEnd", source, expected, res) assert.Equal("abcdmm", PadEnd("abcd", 6, "m"))
t.FailNow() assert.Equal("abcaba", PadEnd("abc", 6, "ab"))
}
assert.NotEqual("ba", PadEnd("a", 2, "b"))
} }
func TestPadStart(t *testing.T) { func TestPadStart(t *testing.T) {
padStart(t, "a", 1, "b", "a") assert := internal.NewAssert(t, "TestPadStart")
padStart(t, "a", 2, "b", "ba")
padStart(t, "abcd", 6, "mno", "mnabcd")
padStart(t, "abcd", 6, "m", "mmabcd")
padStart(t, "abc", 6, "ab", "abaabc")
}
func padStart(t *testing.T, source string, size int, fillString string, expected string) { assert.Equal("a", PadStart("a", 1, "b"))
res := PadStart(source, size, fillString) assert.Equal("ba", PadStart("a", 2, "b"))
if res != expected { assert.Equal("mnabcd", PadStart("abcd", 6, "mno"))
internal.LogFailedTestInfo(t, "PadEnd", source, expected, res) assert.Equal("mmabcd", PadStart("abcd", 6, "m"))
t.FailNow() assert.Equal("abaabc", PadStart("abc", 6, "ab"))
}
assert.NotEqual("ab", PadStart("a", 2, "b"))
} }
func TestBefore(t *testing.T) { func TestBefore(t *testing.T) {
before(t, "lancet", "", "lancet") assert := internal.NewAssert(t, "TestBefore")
before(t, "github.com/test/lancet", "/", "github.com")
before(t, "github.com/test/lancet", "test", "github.com/")
}
func before(t *testing.T, source, char, expected string) { assert.Equal("lancet", Before("lancet", ""))
res := Before(source, char) assert.Equal("github.com", Before("github.com/test/lancet", "/"))
if res != expected { assert.Equal("github.com/", Before("github.com/test/lancet", "test"))
internal.LogFailedTestInfo(t, "Before", source, expected, res)
t.FailNow()
}
} }
func TestBeforeLast(t *testing.T) { func TestBeforeLast(t *testing.T) {
beforeLast(t, "lancet", "", "lancet") assert := internal.NewAssert(t, "TestBeforeLast")
beforeLast(t, "github.com/test/lancet", "/", "github.com/test")
beforeLast(t, "github.com/test/test/lancet", "test", "github.com/test/")
}
func beforeLast(t *testing.T, source, char, expected string) { assert.Equal("lancet", BeforeLast("lancet", ""))
res := BeforeLast(source, char) assert.Equal("github.com/test", BeforeLast("github.com/test/lancet", "/"))
if res != expected { assert.Equal("github.com/test/", BeforeLast("github.com/test/test/lancet", "test"))
internal.LogFailedTestInfo(t, "BeforeLast", source, expected, res)
t.FailNow() assert.NotEqual("github.com/", BeforeLast("github.com/test/test/lancet", "test"))
}
} }
func TestAfter(t *testing.T) { func TestAfter(t *testing.T) {
after(t, "lancet", "", "lancet") assert := internal.NewAssert(t, "TestAfter")
after(t, "github.com/test/lancet", "/", "test/lancet")
after(t, "github.com/test/lancet", "test", "/lancet")
}
func after(t *testing.T, source, char, expected string) { assert.Equal("lancet", After("lancet", ""))
res := After(source, char) assert.Equal("test/lancet", After("github.com/test/lancet", "/"))
if res != expected { assert.Equal("/lancet", After("github.com/test/lancet", "test"))
internal.LogFailedTestInfo(t, "After", source, expected, res)
t.FailNow()
}
} }
func TestAfterLast(t *testing.T) { func TestAfterLast(t *testing.T) {
afterLast(t, "lancet", "", "lancet") assert := internal.NewAssert(t, "TestAfterLast")
afterLast(t, "github.com/test/lancet", "/", "lancet")
afterLast(t, "github.com/test/test/lancet", "test", "/lancet")
}
func afterLast(t *testing.T, source, char, expected string) { assert.Equal("lancet", AfterLast("lancet", ""))
res := AfterLast(source, char) assert.Equal("lancet", AfterLast("github.com/test/lancet", "/"))
if res != expected { assert.Equal("/lancet", AfterLast("github.com/test/lancet", "test"))
internal.LogFailedTestInfo(t, "AfterLast", source, expected, res) assert.Equal("/lancet", AfterLast("github.com/test/test/lancet", "test"))
t.FailNow()
} assert.NotEqual("/test/lancet", AfterLast("github.com/test/test/lancet", "test"))
} }
func TestIsString(t *testing.T) { func TestIsString(t *testing.T) {
isString(t, "lancet", true) assert := internal.NewAssert(t, "TestIsString")
isString(t, 1, false)
isString(t, true, false)
isString(t, []string{}, false)
}
func isString(t *testing.T, test interface{}, expected bool) { assert.Equal(true, IsString("lancet"))
res := IsString(test) assert.Equal(true, IsString(""))
if res != expected { assert.Equal(false, IsString(1))
internal.LogFailedTestInfo(t, "IsString", test, expected, res) assert.Equal(false, IsString(true))
t.FailNow() assert.Equal(false, IsString([]string{}))
}
} }
func TestReverseStr(t *testing.T) { func TestReverseStr(t *testing.T) {
reverseStr(t, "abc", "cba") assert := internal.NewAssert(t, "TestReverseStr")
reverseStr(t, "12345", "54321")
}
func reverseStr(t *testing.T, test string, expected string) { assert.Equal("cba", ReverseStr("abc"))
res := ReverseStr(test) assert.Equal("54321", ReverseStr("12345"))
if res != expected {
internal.LogFailedTestInfo(t, "ReverseStr", test, expected, res)
t.FailNow()
}
} }
func TestWrap(t *testing.T) { func TestWrap(t *testing.T) {
wrap(t, "ab", "", "ab") assert := internal.NewAssert(t, "TestWrap")
wrap(t, "", "*", "")
wrap(t, "ab", "*", "*ab*")
wrap(t, "ab", "\"", "\"ab\"")
wrap(t, "ab", "'", "'ab'")
}
func wrap(t *testing.T, test string, wrapWith string, expected string) { assert.Equal("ab", Wrap("ab", ""))
res := Wrap(test, wrapWith) assert.Equal("", Wrap("", "*"))
if res != expected { assert.Equal("*ab*", Wrap("ab", "*"))
internal.LogFailedTestInfo(t, "Wrap", test, expected, res) assert.Equal("\"ab\"", Wrap("ab", "\""))
t.FailNow() assert.Equal("'ab'", Wrap("ab", "'"))
}
} }
func TestUnwrap(t *testing.T) { func TestUnwrap(t *testing.T) {
unwrap(t, "", "*", "") assert := internal.NewAssert(t, "TestUnwrap")
unwrap(t, "ab", "", "ab")
unwrap(t, "ab", "*", "ab")
unwrap(t, "**ab**", "*", "*ab*")
unwrap(t, "**ab**", "**", "ab")
unwrap(t, "\"ab\"", "\"", "ab")
unwrap(t, "*ab", "*", "*ab")
unwrap(t, "ab*", "*", "ab*")
unwrap(t, "***", "*", "*")
unwrap(t, "**", "*", "")
unwrap(t, "***", "**", "***")
unwrap(t, "**", "**", "**")
}
func unwrap(t *testing.T, test string, wrapToken string, expected string) { assert.Equal("", Unwrap("", "*"))
res := Unwrap(test, wrapToken) assert.Equal("ab", Unwrap("ab", ""))
if res != expected { assert.Equal("ab", Unwrap("ab", "*"))
internal.LogFailedTestInfo(t, "Unwrap", test+"->"+wrapToken, expected, res) assert.Equal("*ab*", Unwrap("**ab**", "*"))
t.FailNow() assert.Equal("ab", Unwrap("**ab**", "**"))
} assert.Equal("ab", Unwrap("\"ab\"", "\""))
assert.Equal("*ab", Unwrap("*ab", "*"))
assert.Equal("ab*", Unwrap("ab*", "*"))
assert.Equal("*", Unwrap("***", "*"))
assert.Equal("", Unwrap("**", "*"))
assert.Equal("***", Unwrap("***", "**"))
assert.Equal("**", Unwrap("**", "**"))
} }

69
system/os.go Normal file
View File

@@ -0,0 +1,69 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package system contain some functions about os, runtime, shell command.
package system
import (
"bytes"
"os"
"os/exec"
"runtime"
)
// IsWindows check if current os is windows
func IsWindows() bool {
return runtime.GOOS == "windows"
}
// IsLinux check if current os is linux
func IsLinux() bool {
return runtime.GOOS == "linux"
}
// IsMac check if current os is macos
func IsMac() bool {
return runtime.GOOS == "darwin"
}
// GetOsEnv gets the value of the environment variable named by the key.
func GetOsEnv(key string) string {
return os.Getenv(key)
}
// SetOsEnv sets the value of the environment variable named by the key.
func SetOsEnv(key, value string) error {
return os.Setenv(key, value)
}
// RemoveOsEnv remove a single environment variable.
func RemoveOsEnv(key string) error {
return os.Unsetenv(key)
}
// CompareOsEnv gets env named by the key and compare it with comparedEnv
func CompareOsEnv(key, comparedEnv string) bool {
env := GetOsEnv(key)
if env == "" {
return false
}
return env == comparedEnv
}
// ExecCommand use shell /bin/bash -c to execute command
func ExecCommand(command string) (err error, stdout, stderr string) {
var out bytes.Buffer
var errout bytes.Buffer
cmd := exec.Command("/bin/bash", "-c", command)
cmd.Stdout = &out
cmd.Stderr = &errout
err = cmd.Run()
if err != nil {
stderr = string(errout.Bytes())
}
stdout = string(out.Bytes())
return
}

37
system/os_test.go Normal file
View File

@@ -0,0 +1,37 @@
package system
import (
"testing"
"github.com/duke-git/lancet/internal"
)
func TestOsEnvOperation(t *testing.T) {
assert := internal.NewAssert(t, "TestOsEnvOperation")
envNotExist := GetOsEnv("foo")
assert.Equal("", envNotExist)
SetOsEnv("foo", "foo_value")
envExist := GetOsEnv("foo")
assert.Equal("foo_value", envExist)
assert.Equal(true, CompareOsEnv("foo", "foo_value"))
assert.Equal(false, CompareOsEnv("foo", "abc"))
}
func TestExecCommand(t *testing.T) {
assert := internal.NewAssert(t, "TestExecCommand")
err, out, errout := ExecCommand("ls")
assert.IsNil(err)
err, out, errout = ExecCommand("abc")
t.Log("std out: ", out)
t.Log("std err: ", errout)
if err != nil {
t.Logf("error: %v\n", err)
}
assert.IsNotNil(err)
}

View File

@@ -5,17 +5,72 @@
package validator package validator
import ( import (
"encoding/json"
"net" "net"
"regexp" "regexp"
"strconv" "strconv"
"strings"
"unicode" "unicode"
) )
var isAlphaRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`) var isAlphaRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
// IsAlpha checks if the string contains only letters (a-zA-Z) // IsAlpha checks if the string contains only letters (a-zA-Z)
func IsAlpha(s string) bool { func IsAlpha(str string) bool {
return isAlphaRegexMatcher.MatchString(s) return isAlphaRegexMatcher.MatchString(str)
}
// IsAllUpper check if the string is all upper case letters A-Z
func IsAllUpper(str string) bool {
for _, r := range str {
if !unicode.IsUpper(r) {
return false
}
}
return str != ""
}
// IsAllLower check if the string is all lower case letters a-z
func IsAllLower(str string) bool {
for _, r := range str {
if !unicode.IsLower(r) {
return false
}
}
return str != ""
}
// ContainUpper check if the string contain at least one upper case letter A-Z
func ContainUpper(str string) bool {
for _, r := range str {
if unicode.IsUpper(r) && unicode.IsLetter(r) {
return true
}
}
return false
}
// ContainLower check if the string contain at least one lower case letter A-Z
func ContainLower(str string) bool {
for _, r := range str {
if unicode.IsLower(r) && unicode.IsLetter(r) {
return true
}
}
return false
}
var containLetterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
// ContainLetter check if the string contain at least one letter
func ContainLetter(str string) bool {
return containLetterRegexMatcher.MatchString(str)
}
// Is checks if the string is valid JSON
func IsJSON(str string) bool {
var js json.RawMessage
return json.Unmarshal([]byte(str), &js) == nil
} }
// IsNumberStr check if the string can convert to a number. // IsNumberStr check if the string can convert to a number.
@@ -24,16 +79,16 @@ func IsNumberStr(s string) bool {
} }
// IsFloatStr check if the string can convert to a float. // IsFloatStr check if the string can convert to a float.
func IsFloatStr(s string) bool { func IsFloatStr(str string) bool {
_, e := strconv.ParseFloat(s, 64) _, e := strconv.ParseFloat(str, 64)
return e == nil return e == nil
} }
var isIntStrRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`) var isIntStrRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
// IsIntStr check if the string can convert to a integer. // IsIntStr check if the string can convert to a integer.
func IsIntStr(s string) bool { func IsIntStr(str string) bool {
return isIntStrRegexMatcher.MatchString(s) return isIntStrRegexMatcher.MatchString(str)
} }
// IsIp check if the string is a ip address. // IsIp check if the string is a ip address.
@@ -48,13 +103,7 @@ func IsIpV4(ipstr string) bool {
if ip == nil { if ip == nil {
return false return false
} }
for i := 0; i < len(ipstr); i++ { return strings.Contains(ipstr, ".")
switch ipstr[i] {
case '.':
return true
}
}
return false
} }
// IsIpV6 check if the string is a ipv6 address. // IsIpV6 check if the string is a ipv6 address.
@@ -63,11 +112,13 @@ func IsIpV6(ipstr string) bool {
if ip == nil { if ip == nil {
return false return false
} }
for i := 0; i < len(ipstr); i++ { return strings.Contains(ipstr, ":")
switch ipstr[i] { }
case ':':
return true // IsPort check if the string is a valid net port.
} func IsPort(str string) bool {
if i, err := strconv.ParseInt(str, 10, 64); err == nil && i > 0 && i < 65536 {
return true
} }
return false return false
} }
@@ -130,14 +181,14 @@ func IsBase64(base64 string) bool {
} }
// IsEmptyString check if the string is empty. // IsEmptyString check if the string is empty.
func IsEmptyString(s string) bool { func IsEmptyString(str string) bool {
return len(s) == 0 return len(str) == 0
} }
// IsRegexMatch check if the string match the regexp // IsRegexMatch check if the string match the regexp
func IsRegexMatch(s, regex string) bool { func IsRegexMatch(str, regex string) bool {
reg := regexp.MustCompile(regex) reg := regexp.MustCompile(regex)
return reg.MatchString(s) return reg.MatchString(str)
} }
// IsStrongPassword check if the string is strong password, if len(password) is less than the length param, return false // IsStrongPassword check if the string is strong password, if len(password) is less than the length param, return false

View File

@@ -6,278 +6,266 @@ import (
"github.com/duke-git/lancet/internal" "github.com/duke-git/lancet/internal"
) )
func TestIsNumberStr(t *testing.T) { func TestIsAllUpper(t *testing.T) {
isNumberStr(t, "3.", true) assert := internal.NewAssert(t, "TestIsAllUpper")
isNumberStr(t, "+3.", true)
isNumberStr(t, "-3.", true) assert.Equal(true, IsAllUpper("ABC"))
isNumberStr(t, "+3e2", true) assert.Equal(false, IsAllUpper(""))
isNumberStr(t, "abc", false) assert.Equal(false, IsAllUpper("abc"))
assert.Equal(false, IsAllUpper("aBC"))
assert.Equal(false, IsAllUpper("1BC"))
assert.Equal(false, IsAllUpper("1bc"))
assert.Equal(false, IsAllUpper("123"))
assert.Equal(false, IsAllUpper("你好"))
assert.Equal(false, IsAllUpper("A&"))
assert.Equal(false, IsAllUpper("&@#$%^&*"))
} }
func isNumberStr(t *testing.T, source string, expected bool) { func TestIsAllLower(t *testing.T) {
res := IsNumberStr(source) assert := internal.NewAssert(t, "TestIsAllLower")
if res != expected {
internal.LogFailedTestInfo(t, "IsNumberStr", source, expected, res) assert.Equal(true, IsAllLower("abc"))
t.FailNow() assert.Equal(false, IsAllLower("ABC"))
} assert.Equal(false, IsAllLower(""))
assert.Equal(false, IsAllLower("aBC"))
assert.Equal(false, IsAllLower("1BC"))
assert.Equal(false, IsAllLower("1bc"))
assert.Equal(false, IsAllLower("123"))
assert.Equal(false, IsAllLower("你好"))
assert.Equal(false, IsAllLower("A&"))
assert.Equal(false, IsAllLower("&@#$%^&*"))
}
func TestContainLower(t *testing.T) {
assert := internal.NewAssert(t, "TestContainLower")
assert.Equal(true, ContainLower("abc"))
assert.Equal(true, ContainLower("aBC"))
assert.Equal(true, ContainLower("1bc"))
assert.Equal(true, ContainLower("a&"))
assert.Equal(false, ContainLower("ABC"))
assert.Equal(false, ContainLower(""))
assert.Equal(false, ContainLower("1BC"))
assert.Equal(false, ContainLower("123"))
assert.Equal(false, ContainLower("你好"))
assert.Equal(false, ContainLower("&@#$%^&*"))
}
func TestContainUpper(t *testing.T) {
assert := internal.NewAssert(t, "TestContainUpper")
assert.Equal(true, ContainUpper("ABC"))
assert.Equal(true, ContainUpper("aBC"))
assert.Equal(true, ContainUpper("1BC"))
assert.Equal(true, ContainUpper("A&"))
assert.Equal(false, ContainUpper("abc"))
assert.Equal(false, ContainUpper(""))
assert.Equal(false, ContainUpper("1bc"))
assert.Equal(false, ContainUpper("123"))
assert.Equal(false, ContainUpper("你好"))
assert.Equal(false, ContainUpper("&@#$%^&*"))
}
func TestContainLetter(t *testing.T) {
assert := internal.NewAssert(t, "TestContainLetter")
assert.Equal(true, ContainLetter("ABC"))
assert.Equal(true, ContainLetter("1Bc"))
assert.Equal(true, ContainLetter("1ab"))
assert.Equal(true, ContainLetter("A&"))
assert.Equal(false, ContainLetter(""))
assert.Equal(false, ContainLetter("123"))
assert.Equal(false, ContainLetter("你好"))
assert.Equal(false, ContainLetter("&@#$%^&*"))
}
func TestIsJSON(t *testing.T) {
assert := internal.NewAssert(t, "TestIsJSON")
assert.Equal(true, IsJSON("{}"))
assert.Equal(true, IsJSON("{\"name\": \"test\"}"))
assert.Equal(true, IsJSON("[]"))
assert.Equal(true, IsJSON("123"))
assert.Equal(false, IsJSON(""))
assert.Equal(false, IsJSON("abc"))
assert.Equal(false, IsJSON("你好"))
assert.Equal(false, IsJSON("&@#$%^&*"))
}
func TestIsNumberStr(t *testing.T) {
assert := internal.NewAssert(t, "TestIsNumberStr")
assert.Equal(true, IsNumberStr("3."))
assert.Equal(true, IsNumberStr("+3."))
assert.Equal(true, IsNumberStr("-3."))
assert.Equal(true, IsNumberStr("+3e2"))
assert.Equal(false, IsNumberStr("abc"))
} }
func TestIsFloatStr(t *testing.T) { func TestIsFloatStr(t *testing.T) {
isFloatStr(t, "3.", true) assert := internal.NewAssert(t, "TestIsFloatStr")
isFloatStr(t, "+3.", true)
isFloatStr(t, "-3.", true)
isFloatStr(t, "12", true)
isFloatStr(t, "abc", false)
}
func isFloatStr(t *testing.T, source string, expected bool) { assert.Equal(true, IsFloatStr("3."))
res := IsFloatStr(source) assert.Equal(true, IsFloatStr("+3."))
if res != expected { assert.Equal(true, IsFloatStr("-3."))
internal.LogFailedTestInfo(t, "IsFloatStr", source, expected, res) assert.Equal(true, IsFloatStr("12"))
t.FailNow() assert.Equal(false, IsFloatStr("abc"))
}
} }
func TestIsIntStr(t *testing.T) { func TestIsIntStr(t *testing.T) {
isIntStr(t, "+3", true) assert := internal.NewAssert(t, "TestIsIntStr")
isIntStr(t, "-3", true)
isIntStr(t, "3.", false) assert.Equal(true, IsIntStr("+3"))
isIntStr(t, "abc", false) assert.Equal(true, IsIntStr("-3"))
assert.Equal(false, IsIntStr("3."))
assert.Equal(false, IsIntStr("abc"))
} }
func isIntStr(t *testing.T, source string, expected bool) { func TestIsPort(t *testing.T) {
res := IsIntStr(source) assert := internal.NewAssert(t, "TestIsPort")
if res != expected {
internal.LogFailedTestInfo(t, "IsIntStr", source, expected, res) assert.Equal(true, IsPort("1"))
t.FailNow() assert.Equal(true, IsPort("65535"))
} assert.Equal(false, IsPort("abc"))
assert.Equal(false, IsPort("123abc"))
assert.Equal(false, IsPort(""))
assert.Equal(false, IsPort("-1"))
assert.Equal(false, IsPort("65536"))
} }
func TestIsIp(t *testing.T) { func TestIsIp(t *testing.T) {
isIp(t, "127.0.0.1", true) assert := internal.NewAssert(t, "TestIsIntStr")
isIp(t, "::0:0:0:0:0:0:1", true)
isIp(t, "120.0.0", false)
isIp(t, "abc", false)
}
func isIp(t *testing.T, source string, expected bool) { assert.Equal(true, IsIp("127.0.0.1"))
res := IsIp(source) assert.Equal(true, IsIp("::0:0:0:0:0:0:1"))
if res != expected { assert.Equal(false, IsIp("127.0.0"))
internal.LogFailedTestInfo(t, "IsIp", source, expected, res) assert.Equal(false, IsIp("127"))
t.FailNow()
}
} }
func TestIsIpV4(t *testing.T) { func TestIsIpV4(t *testing.T) {
isIpV4(t, "127.0.0.1", true) assert := internal.NewAssert(t, "TestIsIpV4")
isIpV4(t, "::0:0:0:0:0:0:1", false)
}
func isIpV4(t *testing.T, source string, expected bool) { assert.Equal(true, IsIpV4("127.0.0.1"))
res := IsIpV4(source) assert.Equal(false, IsIpV4("::0:0:0:0:0:0:1"))
if res != expected {
internal.LogFailedTestInfo(t, "IsIpV4", source, expected, res)
t.FailNow()
}
} }
func TestIsIpV6(t *testing.T) { func TestIsIpV6(t *testing.T) {
isIpV6(t, "127.0.0.1", false) assert := internal.NewAssert(t, "TestIsIpV6")
isIpV6(t, "::0:0:0:0:0:0:1", true)
}
func isIpV6(t *testing.T, source string, expected bool) { assert.Equal(false, IsIpV6("127.0.0.1"))
res := IsIpV6(source) assert.Equal(true, IsIpV6("::0:0:0:0:0:0:1"))
if res != expected {
internal.LogFailedTestInfo(t, "IsIpV6", source, expected, res)
t.FailNow()
}
} }
func TestIsDns(t *testing.T) { func TestIsDns(t *testing.T) {
isDns(t, "abc.com", true) assert := internal.NewAssert(t, "TestIsDns")
isDns(t, "a.b.com", false)
}
func isDns(t *testing.T, source string, expected bool) { assert.Equal(true, IsDns("abc.com"))
res := IsDns(source) assert.Equal(false, IsDns("a.b.com"))
if res != expected {
internal.LogFailedTestInfo(t, "IsDns", source, expected, res)
t.FailNow()
}
} }
func TestIsEmail(t *testing.T) { func TestIsEmail(t *testing.T) {
isEmail(t, "abc@xyz.com", true) assert := internal.NewAssert(t, "TestIsEmail")
isEmail(t, "a.b@@com", false)
}
func isEmail(t *testing.T, source string, expected bool) { assert.Equal(true, IsEmail("abc@xyz.com"))
res := IsEmail(source) assert.Equal(false, IsEmail("a.b@@com"))
if res != expected {
internal.LogFailedTestInfo(t, "IsEmail", source, expected, res)
t.FailNow()
}
} }
func TestContainChinese(t *testing.T) { func TestContainChinese(t *testing.T) {
containChinese(t, "你好", true) assert := internal.NewAssert(t, "TestContainChinese")
containChinese(t, "hello", false)
containChinese(t, "hello你好", true)
}
func containChinese(t *testing.T, source string, expected bool) { assert.Equal(true, ContainChinese("你好"))
res := ContainChinese(source) assert.Equal(true, ContainChinese("你好hello"))
if res != expected { assert.Equal(false, ContainChinese("hello"))
internal.LogFailedTestInfo(t, "IsContainChineseChar", source, expected, res)
t.FailNow()
}
} }
func TestIsChineseMobile(t *testing.T) { func TestIsChineseMobile(t *testing.T) {
isChineseMobile(t, "13263527980", true) assert := internal.NewAssert(t, "TestIsChineseMobile")
isChineseMobile(t, "434324324", false)
}
func isChineseMobile(t *testing.T, source string, expected bool) { assert.Equal(true, IsChineseMobile("13263527980"))
res := IsChineseMobile(source) assert.Equal(false, IsChineseMobile("434324324"))
if res != expected {
internal.LogFailedTestInfo(t, "IsChineseMobile", source, expected, res)
t.FailNow()
}
} }
func TestIsChinesePhone(t *testing.T) { func TestIsChinesePhone(t *testing.T) {
isChinesePhone(t, "010-32116675", true) assert := internal.NewAssert(t, "TestIsChinesePhone")
isChinesePhone(t, "0464-8756213", true)
isChinesePhone(t, "123-87562", false) assert.Equal(true, IsChinesePhone("010-32116675"))
} assert.Equal(true, IsChinesePhone("0464-8756213"))
assert.Equal(false, IsChinesePhone("123-87562"))
func isChinesePhone(t *testing.T, source string, expected bool) {
res := IsChinesePhone(source)
if res != expected {
internal.LogFailedTestInfo(t, "IsChinesePhone", source, expected, res)
t.FailNow()
}
} }
func TestIsChineseIdNum(t *testing.T) { func TestIsChineseIdNum(t *testing.T) {
isChineseIdNum(t, "210911192105130715", true) assert := internal.NewAssert(t, "TestIsChineseIdNum")
isChineseIdNum(t, "21091119210513071X", true)
isChineseIdNum(t, "21091119210513071x", true)
isChineseIdNum(t, "123456", false)
}
func isChineseIdNum(t *testing.T, source string, expected bool) { assert.Equal(true, IsChineseIdNum("210911192105130715"))
res := IsChineseIdNum(source) assert.Equal(true, IsChineseIdNum("21091119210513071X"))
if res != expected { assert.Equal(true, IsChineseIdNum("21091119210513071x"))
internal.LogFailedTestInfo(t, "IsChineseIdNum", source, expected, res) assert.Equal(false, IsChineseIdNum("123456"))
t.FailNow()
}
} }
func TestIsCreditCard(t *testing.T) { func TestIsCreditCard(t *testing.T) {
isCreditCard(t, "4111111111111111", true) assert := internal.NewAssert(t, "TestIsCreditCard")
isCreditCard(t, "123456", false)
}
func isCreditCard(t *testing.T, source string, expected bool) { assert.Equal(true, IsCreditCard("4111111111111111"))
res := IsCreditCard(source) assert.Equal(false, IsCreditCard("123456"))
if res != expected {
internal.LogFailedTestInfo(t, "IsCreditCard", source, expected, res)
t.FailNow()
}
} }
func TestIsBase64(t *testing.T) { func TestIsBase64(t *testing.T) {
isBase64(t, "aGVsbG8=", true) assert := internal.NewAssert(t, "TestIsBase64")
isBase64(t, "123456", false)
}
func isBase64(t *testing.T, source string, expected bool) { assert.Equal(true, IsBase64("aGVsbG8="))
res := IsBase64(source) assert.Equal(false, IsBase64("123456"))
if res != expected {
internal.LogFailedTestInfo(t, "IsBase64", source, expected, res)
t.FailNow()
}
} }
func TestIsEmptyString(t *testing.T) { func TestIsEmptyString(t *testing.T) {
isEmptyString(t, "111", false) assert := internal.NewAssert(t, "TestIsEmptyString")
isEmptyString(t, " ", false)
isEmptyString(t, "\t", false)
isEmptyString(t, "", true)
}
func isEmptyString(t *testing.T, source string, expected bool) { assert.Equal(true, IsEmptyString(""))
res := IsEmptyString(source) assert.Equal(false, IsEmptyString("111"))
if res != expected { assert.Equal(false, IsEmptyString(" "))
internal.LogFailedTestInfo(t, "IsEmptyString", source, expected, res) assert.Equal(false, IsEmptyString("\t"))
t.FailNow()
}
} }
func TestIsAlpha(t *testing.T) { func TestIsAlpha(t *testing.T) {
isAlpha(t, "abc", true) assert := internal.NewAssert(t, "TestIsAlpha")
isAlpha(t, "111", false)
isAlpha(t, " ", false)
isAlpha(t, "\t", false)
isAlpha(t, "", false)
}
func isAlpha(t *testing.T, source string, expected bool) { assert.Equal(true, IsAlpha("abc"))
res := IsAlpha(source) assert.Equal(false, IsAlpha("111"))
if res != expected { assert.Equal(false, IsAlpha(" "))
internal.LogFailedTestInfo(t, "IsAlpha", source, expected, res) assert.Equal(false, IsAlpha("\t"))
t.FailNow() assert.Equal(false, IsAlpha(""))
}
} }
func TestIsRegexMatch(t *testing.T) { func TestIsRegexMatch(t *testing.T) {
isRegexMatch(t, "abc", `^[a-zA-Z]+$`, true) assert := internal.NewAssert(t, "TestIsRegexMatch")
isRegexMatch(t, "1ab", `^[a-zA-Z]+$`, false)
isRegexMatch(t, "111", `^[a-zA-Z]+$`, false)
isRegexMatch(t, "", `^[a-zA-Z]+$`, false)
}
func isRegexMatch(t *testing.T, source, regex string, expected bool) { assert.Equal(true, IsRegexMatch("abc", `^[a-zA-Z]+$`))
res := IsRegexMatch(source, regex) assert.Equal(false, IsRegexMatch("1ab", `^[a-zA-Z]+$`))
if res != expected { assert.Equal(false, IsRegexMatch("", `^[a-zA-Z]+$`))
internal.LogFailedTestInfo(t, "IsRegexMatch", source, expected, res)
t.FailNow()
}
} }
func TestIsStrongPassword(t *testing.T) { func TestIsStrongPassword(t *testing.T) {
isStrongPassword(t, "abc", 3, false) assert := internal.NewAssert(t, "TestIsStrongPassword")
isStrongPassword(t, "abc123", 6, false)
isStrongPassword(t, "abcABC", 6, false)
isStrongPassword(t, "abc123@#$", 9, false)
isStrongPassword(t, "abcABC123@#$", 16, false)
isStrongPassword(t, "abcABC123@#$", 12, true)
isStrongPassword(t, "abcABC123@#$", 10, true)
}
func isStrongPassword(t *testing.T, source string, length int, expected bool) { assert.Equal(false, IsStrongPassword("abc", 3))
res := IsStrongPassword(source, length) assert.Equal(false, IsStrongPassword("abc123", 6))
if res != expected { assert.Equal(false, IsStrongPassword("abcABC", 6))
internal.LogFailedTestInfo(t, "IsStrongPassword", source, expected, res) assert.Equal(false, IsStrongPassword("abc123@#$", 9))
t.FailNow() assert.Equal(false, IsStrongPassword("abcABC123@#$", 16))
} assert.Equal(true, IsStrongPassword("abcABC123@#$", 12))
assert.Equal(true, IsStrongPassword("abcABC123@#$", 10))
} }
func TestIsWeakPassword(t *testing.T) { func TestIsWeakPassword(t *testing.T) {
isWeakPassword(t, "abc", true) assert := internal.NewAssert(t, "TestIsWeakPassword")
isWeakPassword(t, "123", true)
isWeakPassword(t, "abc123", true)
isWeakPassword(t, "abcABC123", true)
isWeakPassword(t, "abc123@#$", false)
}
func isWeakPassword(t *testing.T, source string, expected bool) { assert.Equal(true, IsWeakPassword("abc"))
res := IsWeakPassword(source) assert.Equal(true, IsWeakPassword("123"))
if res != expected { assert.Equal(true, IsWeakPassword("abc123"))
internal.LogFailedTestInfo(t, "IsWeakPassword", source, expected, res) assert.Equal(true, IsWeakPassword("abcABC123"))
t.FailNow() assert.Equal(false, IsWeakPassword("abc123@#$"))
}
} }