mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-07 14:12:28 +08:00
Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bb102cb6e | ||
|
|
e07d54d1da | ||
|
|
6f035f710e | ||
|
|
92967e0add | ||
|
|
6a1a0b8677 | ||
|
|
ca88687f3d | ||
|
|
aa64bf5bee | ||
|
|
a3399503f7 | ||
|
|
3ca096b4ac | ||
|
|
28317a1683 | ||
|
|
2ab898741d | ||
|
|
454efd486d | ||
|
|
efa20a97c4 | ||
|
|
25ef78bc64 | ||
|
|
261370e30d | ||
|
|
764a6fe107 | ||
|
|
f3749c52b9 | ||
|
|
f368854b2d | ||
|
|
c424b88d40 | ||
|
|
aeebd63eda | ||
|
|
22b3c4dd42 | ||
|
|
bd976642f6 | ||
|
|
e31fb28003 | ||
|
|
fd271fe176 | ||
|
|
6890bbfe05 | ||
|
|
24ae47a12f | ||
|
|
d8d85efedf | ||
|
|
ba73847b80 | ||
|
|
69453eba19 | ||
|
|
f147f78a41 | ||
|
|
bbfc5b7060 | ||
|
|
1f45937190 | ||
|
|
52c5a91606 | ||
|
|
49f62c3550 | ||
|
|
23701e6998 | ||
|
|
1199c30ef3 | ||
|
|
b0e17c7bc4 | ||
|
|
d3525dfe8f | ||
|
|
9da7115169 | ||
|
|
9cb9aa2f2f | ||
|
|
e4cd7dad35 | ||
|
|
31e08197d4 | ||
|
|
642d0b8077 | ||
|
|
25b2ae6b98 | ||
|
|
65719515bd | ||
|
|
3ffd81a98a | ||
|
|
f490ef2404 | ||
|
|
3438f3b18a | ||
|
|
73f4ae7b35 | ||
|
|
a8996933bf | ||
|
|
3905c0bde1 | ||
|
|
c7e961704d | ||
|
|
cb7df1b57d | ||
|
|
eeff28606e | ||
|
|
86d4b25a2b | ||
|
|
ad287ed99a | ||
|
|
df9de3065b | ||
|
|
71a2ea3f20 | ||
|
|
955f2e6de6 | ||
|
|
4aef9d6d22 | ||
|
|
4752725dd6 | ||
|
|
07d1704cb2 | ||
|
|
74d262e609 | ||
|
|
97e0789ea4 | ||
|
|
bc39b0887b | ||
|
|
4fd8a18677 | ||
|
|
3de906d7c9 | ||
|
|
56fc12c660 | ||
|
|
7a9b0847f9 | ||
|
|
9266d99249 | ||
|
|
f15131f032 | ||
|
|
b4a49fccfd | ||
|
|
94b1a1d383 | ||
|
|
7db46696f6 | ||
|
|
d4f49af2ad | ||
|
|
ed4acc1c67 | ||
|
|
042a00296f | ||
|
|
b42aac53b3 | ||
|
|
c625a88067 | ||
|
|
e15ae9eb98 | ||
|
|
bb4ac01209 | ||
|
|
147c1625b5 | ||
|
|
2aed55f704 | ||
|
|
051f20caef | ||
|
|
613785b07c | ||
|
|
0b0eb695e8 | ||
|
|
745082fff1 | ||
|
|
24b8da360e | ||
|
|
b106c428ae | ||
|
|
8b1171d0cb | ||
|
|
ab012f2545 |
4
.github/workflows/codecov.yml
vendored
4
.github/workflows/codecov.yml
vendored
@@ -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
3
.gitignore
vendored
@@ -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
|
||||||
170
README.md
170
README.md
@@ -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;">
|
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
||||||
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
[](https://codecov.io/gh/duke-git/lancet)
|
[](https://codecov.io/gh/duke-git/lancet)
|
||||||
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
[](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.
|
||||||
- 💪 100+ 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"
|
||||||
@@ -145,6 +142,8 @@ func HmacMd5(data, key string) string //get hmac md5 value
|
|||||||
func HmacSha1(data, key string) string //get hmac sha1 value
|
func HmacSha1(data, key string) string //get hmac sha1 value
|
||||||
func HmacSha256(data, key string) string //get hmac sha256 value
|
func HmacSha256(data, key string) string //get hmac sha256 value
|
||||||
func HmacSha512(data, key string) string //get hmac sha512 value
|
func HmacSha512(data, key string) string //get hmac sha512 value
|
||||||
|
func Md5String(s string) string //return the md5 value of string
|
||||||
|
func Md5File(filename string) (string, error) //return the md5 value of file
|
||||||
func Sha1(data string) string //get sha1 value
|
func Sha1(data string) string //get sha1 value
|
||||||
func Sha256(data string) string //getsha256 value
|
func Sha256(data string) string //getsha256 value
|
||||||
func Sha512(data string) string //get sha512 value
|
func Sha512(data string) string //get sha512 value
|
||||||
@@ -154,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"
|
||||||
@@ -189,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"
|
||||||
@@ -213,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"
|
||||||
@@ -246,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"
|
||||||
@@ -274,11 +278,16 @@ func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value //c
|
|||||||
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value //creates a function that invokes func once it's called less than n times
|
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value //creates a function that invokes func once it's called less than n times
|
||||||
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} //make a curryed function
|
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} //make a curryed function
|
||||||
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} //compose the functions from right to left
|
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} //compose the functions from right to left
|
||||||
|
func Debounced(fn func(), duration time.Duration) func() //creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.
|
||||||
func Delay(delay time.Duration, fn interface{}, args ...interface{}) //invoke function after delayed time
|
func Delay(delay time.Duration, fn interface{}, args ...interface{}) //invoke function after delayed time
|
||||||
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool //invoke function every duration time, util close the returned bool chan
|
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool //invoke function every duration time, util close the returned bool chan
|
||||||
|
func (w *Watcher) Start() //start the watch timer.
|
||||||
|
func (w *Watcher) Stop() //stop the watch timer
|
||||||
|
func (w *Watcher) Reset() {} //reset the watch timer.
|
||||||
|
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".
|
||||||
@@ -326,7 +335,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".
|
||||||
@@ -355,7 +364,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"
|
||||||
@@ -382,13 +433,20 @@ 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 ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //convert originalSlice to newSliceType
|
func Chunk(slice []interface{}, size int) [][]interface{} //creates an slice of elements split into groups the length of `size`
|
||||||
|
func Compact(slice interface{}) interface{} //creates an slice with all falsey values removed. The values false, nil, 0, and "" are falsey
|
||||||
|
func Concat(slice interface{}, values ...interface{}) interface{} //creates a new slice concatenating slice with any additional slices and/or values
|
||||||
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 DifferenceBy(slice interface{}, comparedSlice interface{}, iterateeFn interface{}) interface{} //it accepts iteratee which is invoked for each element of slice and values to generate the criterion by which they're compared.
|
||||||
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 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{} //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 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.
|
||||||
@@ -396,16 +454,19 @@ func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}
|
|||||||
func Map(slice, function interface{}) interface{} //map lisce, function signature should be func(index int, value interface{}) interface{}
|
func Map(slice, function interface{}) interface{} //map lisce, function signature should be func(index int, value interface{}) interface{}
|
||||||
func ReverseSlice(slice interface{}) //revere slice
|
func ReverseSlice(slice interface{}) //revere slice
|
||||||
func Reduce(slice, function, zero interface{}) interface{} //reduce slice, function signature should be func(index int, value1, value2 interface{}) interface{}
|
func Reduce(slice, function, zero interface{}) interface{} //reduce slice, function signature should be func(index int, value1, value2 interface{}) interface{}
|
||||||
|
func Shuffle(slice interface{}) interface{} //creates an slice of shuffled values
|
||||||
func SortByField(slice interface{}, field string, sortType ...string) error //sort struct slice by field
|
func SortByField(slice interface{}, field string, sortType ...string) error //sort struct slice by field
|
||||||
func Some(slice, function interface{}) bool //return true if any of the values in the list pass the predicate function, function signature should be func(index int, value interface{}) bool
|
func 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 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"
|
||||||
@@ -439,13 +500,49 @@ func Capitalize(s string) string //convert the first character of a string to up
|
|||||||
func IsString(v interface{}) bool //check if the value data type is string or not
|
func IsString(v interface{}) bool //check if the value data type is string or not
|
||||||
func KebabCase(s string) string //covert string to kebab-case, "foo_Bar" -> "foo-bar"
|
func KebabCase(s string) string //covert string to kebab-case, "foo_Bar" -> "foo-bar"
|
||||||
func LowerFirst(s string) string //convert the first character of string to lower case
|
func LowerFirst(s string) string //convert the first character of string to lower case
|
||||||
|
func UpperFirst(s string) string //converts the first character of string to upper case
|
||||||
func PadEnd(source string, size int, padStr string) string //pads string on the right side if it's shorter than size
|
func PadEnd(source string, size int, padStr string) string //pads string on the right 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 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) (stdout, stderr string, err error) //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".
|
||||||
@@ -473,6 +570,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
|
||||||
@@ -488,5 +591,6 @@ func IsIp(ipstr string) bool //check if the string is a ip address
|
|||||||
func IsIpV4(ipstr string) bool //check if the string is a ipv4 address
|
func IsIpV4(ipstr string) bool //check if the string is a ipv4 address
|
||||||
func IsIpV6(ipstr string) bool //check if the string is a ipv6 address
|
func IsIpV6(ipstr string) bool //check if the string is a ipv6 address
|
||||||
func IsStrongPassword(password string, length int) bool //check if the string is strong password (alpha(lower+upper) + number + special chars(!@#$%^&*()?><))
|
func IsStrongPassword(password string, length int) bool //check if the string is strong password (alpha(lower+upper) + number + special chars(!@#$%^&*()?><))
|
||||||
|
func IsUrl(str string) bool //check if the string is url
|
||||||
func IsWeakPassword(password string) bool //check if the string is weak password(only letter or only number or letter + number)
|
func IsWeakPassword(password string) bool //check if the string is weak password(only letter or only number or letter + number)
|
||||||
```
|
```
|
||||||
|
|||||||
168
README_zh-CN.md
168
README_zh-CN.md
@@ -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;">
|
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
||||||
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
[](https://codecov.io/gh/duke-git/lancet)
|
[](https://codecov.io/gh/duke-git/lancet)
|
||||||
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
简体中文 | [English](./README.md)
|
简体中文 | [English](./README.md)
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
### 特性
|
## 特性
|
||||||
|
|
||||||
- 👏 全面、高效、可复用
|
- 👏 全面、高效、可复用
|
||||||
- 💪 100+常用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"
|
||||||
@@ -146,6 +142,8 @@ func HmacMd5(data, key string) string //获取hmac md5值
|
|||||||
func HmacSha1(data, key string) string //获取hmac sha1值
|
func HmacSha1(data, key string) string //获取hmac sha1值
|
||||||
func HmacSha256(data, key string) string //获取hmac sha256值
|
func HmacSha256(data, key string) string //获取hmac sha256值
|
||||||
func HmacSha512(data, key string) string //获取hmac sha512值
|
func HmacSha512(data, key string) string //获取hmac sha512值
|
||||||
|
func Md5String(s string) string //获取字符串md5值
|
||||||
|
func Md5File(filename string) (string, error) //获取文件md5值
|
||||||
func Sha1(data string) string //获取sha1值
|
func Sha1(data string) string //获取sha1值
|
||||||
func Sha256(data string) string //获取sha256值
|
func Sha256(data string) string //获取sha256值
|
||||||
func Sha512(data string) string //获取sha512值
|
func Sha512(data string) string //获取sha512值
|
||||||
@@ -155,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"
|
||||||
@@ -190,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"
|
||||||
@@ -212,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"
|
||||||
@@ -247,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"
|
||||||
@@ -276,10 +279,15 @@ func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value //
|
|||||||
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} //函数柯里化
|
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} //函数柯里化
|
||||||
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} //从右至左组合函数
|
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} //从右至左组合函数
|
||||||
func Delay(delay time.Duration, fn interface{}, args ...interface{}) //延迟调用函数
|
func Delay(delay time.Duration, fn interface{}, args ...interface{}) //延迟调用函数
|
||||||
|
func Debounced(fn func(), duration time.Duration) func() //go防抖函数,在duration时间内连续调用只会执行一次.
|
||||||
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool //每隔duration时间调用函数, 关闭返回通道可以停止调用
|
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool //每隔duration时间调用函数, 关闭返回通道可以停止调用
|
||||||
|
func (w *Watcher) Start() //开时watcher
|
||||||
|
func (w *Watcher) Stop() //开时watcher
|
||||||
|
func (w *Watcher) Reset() {} //重置代码watcher
|
||||||
|
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"
|
||||||
@@ -327,7 +335,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"
|
||||||
@@ -356,7 +364,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"
|
||||||
@@ -383,13 +433,20 @@ 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 Compact(slice interface{}) interface{} //去除slice中的false vule. false values are false, nil, 0, and ""
|
||||||
func Difference(slice1, slice2 interface{}) interface{} //返回
|
func Concat(slice interface{}, values ...interface{}) interface{} //连接values到slice中
|
||||||
|
func Difference(slice1, slice2 interface{}) interface{} //返回切片,其元素在slice1中,不在slice2中
|
||||||
|
func DifferenceBy(slice interface{}, comparedSlice interface{}, iterateeFn interface{}) interface{} //将slice 和comparedSlice中每个元素调用iterateeFn后作比较,如果不相等返回slice中的元素。
|
||||||
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 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 Find(slice, function interface{}) interface{} //查找slice中第一个符合条件的元素,函数签名: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 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 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交集,去重
|
||||||
@@ -397,6 +454,7 @@ func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}
|
|||||||
func Map(slice, function interface{}) interface{} //遍历切片, 函数签名:func(index int, value interface{}) interface{}
|
func Map(slice, function interface{}) interface{} //遍历切片, 函数签名:func(index int, value interface{}) interface{}
|
||||||
func ReverseSlice(slice interface{}) //反转切片
|
func ReverseSlice(slice interface{}) //反转切片
|
||||||
func Reduce(slice, function, zero interface{}) interface{} //切片reduce操作, 函数签名:func(index int, value1, value2 interface{}) interface{}
|
func Reduce(slice, function, zero interface{}) interface{} //切片reduce操作, 函数签名:func(index int, value1, value2 interface{}) interface{}
|
||||||
|
func Shuffle(slice interface{}) interface{} //创建一个被打乱值的切片
|
||||||
func Some(slice, function interface{}) bool //slice中任意一个元素都符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool
|
func Some(slice, function interface{}) bool //slice中任意一个元素都符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool
|
||||||
func SortByField(slice interface{}, field string, sortType ...string) error //对struct切片进行排序
|
func SortByField(slice interface{}, field string, sortType ...string) error //对struct切片进行排序
|
||||||
func StringSlice(slice interface{}) []string //转为string切片
|
func StringSlice(slice interface{}) []string //转为string切片
|
||||||
@@ -404,9 +462,11 @@ func Unique(slice interface{}) interface{} //去重切片
|
|||||||
func Union(slices ...interface{}) interface{} //slice并集, 去重
|
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 Count(slice, function interface{}) int
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 10. strutil字符串处理包
|
### 11. strutil字符串处理包
|
||||||
|
|
||||||
- 字符串操作相关函数
|
- 字符串操作相关函数
|
||||||
- 导入包:import "github.com/duke-git/lancet/strutil"
|
- 导入包:import "github.com/duke-git/lancet/strutil"
|
||||||
@@ -439,14 +499,51 @@ func CamelCase(s string) string //字符串转为cameCase, "foo bar" -> "fooBar"
|
|||||||
func Capitalize(s string) string //字符串转为Capitalize, "fOO" -> "Foo"
|
func Capitalize(s string) string //字符串转为Capitalize, "fOO" -> "Foo"
|
||||||
func IsString(v interface{}) bool //判断是否是字符串
|
func IsString(v interface{}) bool //判断是否是字符串
|
||||||
func KebabCase(s string) string //字符串转为KebabCase, "foo_Bar" -> "foo-bar"
|
func KebabCase(s string) string //字符串转为KebabCase, "foo_Bar" -> "foo-bar"
|
||||||
|
func UpperFirst(s string) string //字符串的第一个字母转为大写字母
|
||||||
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) (stdout, stderr string, err error) //执行shell命令(/bin/bash)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 13. validator验证器包
|
||||||
|
|
||||||
- 数据校验相关函数
|
- 数据校验相关函数
|
||||||
- 导入包:import "github.com/duke-git/lancet/validator"
|
- 导入包:import "github.com/duke-git/lancet/validator"
|
||||||
@@ -474,6 +571,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 //判断字符串是否是座机电话号码
|
||||||
@@ -489,5 +592,6 @@ func IsIp(ipstr string) bool //判断字符串是否是ip
|
|||||||
func IsIpV4(ipstr string) bool //判断字符串是否是ipv4
|
func IsIpV4(ipstr string) bool //判断字符串是否是ipv4
|
||||||
func IsIpV6(ipstr string) bool //判断字符串是否是ipv6
|
func IsIpV6(ipstr string) bool //判断字符串是否是ipv6
|
||||||
func IsStrongPassword(password string, length int) bool //判断字符串是否是强密码(大小写字母+数字+特殊字符)
|
func IsStrongPassword(password string, length int) bool //判断字符串是否是强密码(大小写字母+数字+特殊字符)
|
||||||
|
func IsUrl(str string) bool //判断字符串是否是url
|
||||||
func IsWeakPassword(password string) bool //判断字符串是否是弱密码(只有字母或数字)
|
func IsWeakPassword(password string) bool //判断字符串是否是弱密码(只有字母或数字)
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -45,54 +45,44 @@ func ToChar(s string) []string {
|
|||||||
|
|
||||||
// ToString convert value to string
|
// ToString convert value to string
|
||||||
func ToString(value interface{}) string {
|
func ToString(value interface{}) string {
|
||||||
var res string
|
res := ""
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
switch v := value.(type) {
|
|
||||||
case float64:
|
v := reflect.ValueOf(value)
|
||||||
res = strconv.FormatFloat(v, 'f', -1, 64)
|
|
||||||
case float32:
|
switch value.(type) {
|
||||||
res = strconv.FormatFloat(float64(v), 'f', -1, 64)
|
case float32, float64:
|
||||||
case int:
|
res = strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
||||||
res = strconv.Itoa(v)
|
return res
|
||||||
case uint:
|
case int, int8, int16, int32, int64:
|
||||||
res = strconv.Itoa(int(v))
|
res = strconv.FormatInt(v.Int(), 10)
|
||||||
case int8:
|
return res
|
||||||
res = strconv.Itoa(int(v))
|
case uint, uint8, uint16, uint32, uint64:
|
||||||
case uint8:
|
res = strconv.FormatUint(v.Uint(), 10)
|
||||||
res = strconv.Itoa(int(v))
|
return res
|
||||||
case int16:
|
|
||||||
res = strconv.Itoa(int(v))
|
|
||||||
case uint16:
|
|
||||||
res = strconv.Itoa(int(v))
|
|
||||||
case int32:
|
|
||||||
res = strconv.Itoa(int(v))
|
|
||||||
case uint32:
|
|
||||||
res = strconv.Itoa(int(v))
|
|
||||||
case int64:
|
|
||||||
res = strconv.FormatInt(v, 10)
|
|
||||||
case uint64:
|
|
||||||
res = strconv.FormatUint(v, 10)
|
|
||||||
case string:
|
case string:
|
||||||
res = value.(string)
|
res = v.String()
|
||||||
|
return res
|
||||||
case []byte:
|
case []byte:
|
||||||
res = string(value.([]byte))
|
res = string(v.Bytes())
|
||||||
|
return res
|
||||||
default:
|
default:
|
||||||
newValue, _ := json.Marshal(value)
|
newValue, _ := json.Marshal(value)
|
||||||
res = string(newValue)
|
res = string(newValue)
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToJson convert value to a valid json string
|
// ToJson convert value to a valid json 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
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package convertor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"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]) {
|
|
||||||
utils.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)
|
||||||
utils.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]) {
|
|
||||||
utils.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)
|
||||||
utils.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,108 +81,74 @@ 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)
|
||||||
utils.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
|
||||||
}
|
}
|
||||||
aStruct := TestStruct{Name: "TestStruct"}
|
aStruct := TestStruct{Name: "TestStruct"}
|
||||||
|
|
||||||
cases := []interface{}{
|
cases := []interface{}{
|
||||||
|
"", nil,
|
||||||
int(0), int8(1), int16(-1), int32(123), int64(123),
|
int(0), int8(1), int16(-1), int32(123), int64(123),
|
||||||
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
||||||
float64(12.3), float32(12.3),
|
float64(12.3), float32(12.3),
|
||||||
true, false,
|
true, false,
|
||||||
[]int{1, 2, 3}, aMap, aStruct, []byte{104, 101, 108, 108, 111}}
|
[]int{1, 2, 3}, aMap, aStruct, []byte{104, 101, 108, 108, 111}}
|
||||||
|
|
||||||
expected := []string{"0", "1", "-1", "123", "123", "123", "123", "123",
|
expected := []string{
|
||||||
"123", "123", "12.3", "12.300000190734863", "true", "false",
|
"", "",
|
||||||
|
"0", "1", "-1",
|
||||||
|
"123", "123", "123", "123", "123", "123", "123",
|
||||||
|
"12.3", "12.300000190734863",
|
||||||
|
"true", "false",
|
||||||
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
|
"[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)
|
||||||
utils.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)
|
||||||
utils.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 {
|
|
||||||
utils.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) {
|
|
||||||
utils.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) {
|
|
||||||
utils.LogFailedTestInfo(t, "StructToMap", p2, m2, pm2)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestColorHexToRGB(t *testing.T) {
|
func TestColorHexToRGB(t *testing.T) {
|
||||||
@@ -196,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")
|
||||||
utils.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")
|
||||||
utils.LogFailedTestInfo(t, "ColorHexToRGB", colorRGB, expected, colorHex)
|
assert.Equal(expected, colorHex)
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package cryptor
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"github.com/duke-git/lancet/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAesEcbEncrypt(t *testing.T) {
|
func TestAesEcbEncrypt(t *testing.T) {
|
||||||
@@ -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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.LogFailedTestInfo(t, "AesOfbEncrypt/AesOfbDecrypt", data, data, string(aesOfbDecrypt))
|
assert.Equal(data, string(aesOfbDecrypt))
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package cryptor
|
package cryptor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
@@ -13,7 +14,9 @@ import (
|
|||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"io/ioutil"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Base64StdEncode encode string with base64 encoding
|
// Base64StdEncode encode string with base64 encoding
|
||||||
@@ -36,14 +39,34 @@ func Md5String(s string) string {
|
|||||||
|
|
||||||
// Md5File return the md5 value of file
|
// Md5File return the md5 value of file
|
||||||
func Md5File(filename string) (string, error) {
|
func Md5File(filename string) (string, error) {
|
||||||
f, err := ioutil.ReadFile(filename)
|
if fileInfo, err := os.Stat(filename); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else if fileInfo.IsDir() {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
h := md5.New()
|
hash := md5.New()
|
||||||
h.Write(f)
|
|
||||||
return hex.EncodeToString(h.Sum(nil)), nil
|
chunkSize := 65536
|
||||||
|
for buf, reader := make([]byte, chunkSize), bufio.NewReader(file); ; {
|
||||||
|
n, err := reader.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
hash.Write(buf[:n])
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum := fmt.Sprintf("%x", hash.Sum(nil))
|
||||||
|
return checksum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HmacMd5 return the hmac hash of string use md5
|
// HmacMd5 return the hmac hash of string use md5
|
||||||
|
|||||||
@@ -1,66 +1,36 @@
|
|||||||
package cryptor
|
package cryptor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"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=" {
|
|
||||||
utils.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" {
|
|
||||||
utils.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 {
|
|
||||||
utils.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 {
|
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.LogFailedTestInfo(t, "Sha512", s, expected, sha512)
|
assert.Equal(expected, sha512)
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package cryptor
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"github.com/duke-git/lancet/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDesEcbEncrypt(t *testing.T) {
|
func TestDesEcbEncrypt(t *testing.T) {
|
||||||
@@ -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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.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")
|
||||||
utils.LogFailedTestInfo(t, "DesOfbEncrypt/DesOfbDecrypt", data, data, string(desOfbDecrypt))
|
assert.Equal(data, string(desOfbDecrypt))
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package cryptor
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"github.com/duke-git/lancet/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRsaEncrypt(t *testing.T) {
|
func TestRsaEncrypt(t *testing.T) {
|
||||||
@@ -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")
|
||||||
utils.LogFailedTestInfo(t, "RsaEncrypt/RsaDecrypt", string(data), string(data), string(decrypted))
|
assert.Equal(string(data), string(decrypted))
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
package datetime
|
package datetime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -56,24 +56,17 @@ func init() {
|
|||||||
|
|
||||||
// AddMinute add or sub minute to the time
|
// AddMinute add or sub minute to the time
|
||||||
func AddMinute(t time.Time, minute int64) time.Time {
|
func AddMinute(t time.Time, minute int64) time.Time {
|
||||||
s := strconv.FormatInt(minute, 10)
|
return t.Add(time.Minute * time.Duration(minute))
|
||||||
m, _ := time.ParseDuration(s + "m")
|
|
||||||
return t.Add(m)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddHour add or sub hour to the time
|
// AddHour add or sub hour to the time
|
||||||
func AddHour(t time.Time, hour int64) time.Time {
|
func AddHour(t time.Time, hour int64) time.Time {
|
||||||
s := strconv.FormatInt(hour, 10)
|
return t.Add(time.Hour * time.Duration(hour))
|
||||||
h, _ := time.ParseDuration(s + "h")
|
|
||||||
return t.Add(h)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddDay add or sub day to the time
|
// AddDay add or sub day to the time
|
||||||
func AddDay(t time.Time, day int64) time.Time {
|
func AddDay(t time.Time, day int64) time.Time {
|
||||||
dayHours := day * 24
|
return t.Add(24 * time.Hour * time.Duration(day))
|
||||||
d := strconv.FormatInt(dayHours, 10)
|
|
||||||
h, _ := time.ParseDuration(d + "h")
|
|
||||||
return t.Add(h)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNowDate return format yyyy-mm-dd of current date
|
// GetNowDate return format yyyy-mm-dd of current date
|
||||||
@@ -109,7 +102,11 @@ func FormatTimeToStr(t time.Time, format string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FormatStrToTime convert string to time
|
// FormatStrToTime convert string to time
|
||||||
func FormatStrToTime(str, format string) time.Time {
|
func FormatStrToTime(str, format string) (time.Time, error) {
|
||||||
t, _ := time.Parse(timeFormat[format], str)
|
v, ok := timeFormat[format]
|
||||||
return t
|
if !ok {
|
||||||
|
return time.Time{}, fmt.Errorf("format %s not found", format)
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Parse(v, str)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +1,67 @@
|
|||||||
package datetime
|
package datetime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/utils"
|
|
||||||
"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())
|
||||||
utils.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())
|
||||||
utils.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())
|
||||||
utils.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())
|
||||||
utils.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())
|
||||||
utils.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())
|
||||||
utils.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())
|
||||||
utils.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())
|
||||||
utils.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())
|
||||||
utils.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)
|
||||||
utils.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,11 +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 := FormatStrToTime(datetimeStr[i], cases[i])
|
actual, err := FormatStrToTime(datetimeStr[i], cases[i])
|
||||||
expected, _ := time.Parse(formats[i], datetimeStr[i])
|
if err != nil {
|
||||||
if res != expected {
|
t.Fatal(err)
|
||||||
utils.LogFailedTestInfo(t, "FormatTimeToStr", cases[i], expected, res)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
}
|
||||||
|
expected, _ := time.Parse(formats[i], datetimeStr[i])
|
||||||
|
assert.Equal(expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
148
fileutil/file.go
148
fileutil/file.go
@@ -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
|
||||||
|
// param `file` should be string(file path) 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
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,137 +2,201 @@ package fileutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"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)
|
||||||
utils.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)
|
||||||
utils.LogFailedTestInfo(t, "CreateFile", f, f, "create file error: "+err.Error())
|
assert.Equal(f, file.Name())
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
if file.Name() != f {
|
|
||||||
utils.LogFailedTestInfo(t, "CreateFile", f, f, file.Name())
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
utils.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)
|
||||||
utils.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)
|
||||||
utils.LogFailedTestInfo(t, "RemoveFile", f, f, err.Error())
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
utils.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)
|
||||||
utils.LogFailedTestInfo(t, "CopyFile", srcFile, dstFile, "create file error: "+err.Error())
|
assert.Equal(destFile, file.Name())
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
if file.Name() != dstFile {
|
|
||||||
utils.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)
|
||||||
utils.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)
|
||||||
utils.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)
|
||||||
utils.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)
|
||||||
utils.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"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,26 +3,21 @@ package formatter
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"github.com/duke-git/lancet/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
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", ""))
|
||||||
utils.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, ""))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ import (
|
|||||||
|
|
||||||
// After creates a function that invokes func once it's called n or more times
|
// After creates a function that invokes func once it's called n or more times
|
||||||
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
||||||
|
// Catch programming error while constructing the closure
|
||||||
|
mustBeFunction(fn)
|
||||||
return func(args ...interface{}) []reflect.Value {
|
return func(args ...interface{}) []reflect.Value {
|
||||||
n--
|
n--
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
return invokeFunc(fn, args...)
|
return unsafeInvokeFunc(fn, args...)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -22,11 +24,12 @@ func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
|||||||
|
|
||||||
// Before creates a function that invokes func once it's called less than n times
|
// Before creates a function that invokes func once it's called less than n times
|
||||||
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
||||||
|
// Catch programming error while constructing the closure
|
||||||
|
mustBeFunction(fn)
|
||||||
var res []reflect.Value
|
var res []reflect.Value
|
||||||
|
|
||||||
return func(args ...interface{}) []reflect.Value {
|
return func(args ...interface{}) []reflect.Value {
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
res = invokeFunc(fn, args...)
|
res = unsafeInvokeFunc(fn, args...)
|
||||||
}
|
}
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
fn = nil
|
fn = nil
|
||||||
@@ -67,13 +70,31 @@ func Delay(delay time.Duration, fn interface{}, args ...interface{}) {
|
|||||||
invokeFunc(fn, args...)
|
invokeFunc(fn, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule invoke function every duration time, util close the returned bool chan
|
// Debounced creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.
|
||||||
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
|
func Debounced(fn func(), duration time.Duration) func() {
|
||||||
quit := make(chan bool)
|
timer := time.NewTimer(duration)
|
||||||
|
timer.Stop()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
invokeFunc(fn, args...)
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
go fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return func() { timer.Reset(duration) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule invoke function every duration time, util close the returned bool chan
|
||||||
|
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
|
||||||
|
// Catch programming error while constructing the closure
|
||||||
|
mustBeFunction(fn)
|
||||||
|
quit := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
unsafeInvokeFunc(fn, args...)
|
||||||
select {
|
select {
|
||||||
case <-time.After(d):
|
case <-time.After(d):
|
||||||
case <-quit:
|
case <-quit:
|
||||||
|
|||||||
@@ -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,47 @@ 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 TestDebounced(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestDebounced")
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
add := func() {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
debouncedAdd := Debounced(add, 50*time.Microsecond)
|
||||||
|
debouncedAdd()
|
||||||
|
debouncedAdd()
|
||||||
|
debouncedAdd()
|
||||||
|
debouncedAdd()
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
assert.Equal(1, count)
|
||||||
|
|
||||||
|
debouncedAdd()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
assert.Equal(2, count)
|
||||||
|
}
|
||||||
|
|
||||||
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 +127,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")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,15 @@ func invokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
|
|||||||
return fv.Call(params)
|
return fv.Call(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unsafeInvokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
|
||||||
|
fv := reflect.ValueOf(fn)
|
||||||
|
params := make([]reflect.Value, len(args))
|
||||||
|
for i, item := range args {
|
||||||
|
params[i] = reflect.ValueOf(item)
|
||||||
|
}
|
||||||
|
return fv.Call(params)
|
||||||
|
}
|
||||||
|
|
||||||
func functionValue(function interface{}) reflect.Value {
|
func functionValue(function interface{}) reflect.Value {
|
||||||
v := reflect.ValueOf(function)
|
v := reflect.ValueOf(function)
|
||||||
if v.Kind() != reflect.Func {
|
if v.Kind() != reflect.Func {
|
||||||
@@ -21,3 +30,10 @@ func functionValue(function interface{}) reflect.Value {
|
|||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustBeFunction(function interface{}) {
|
||||||
|
v := reflect.ValueOf(function)
|
||||||
|
if v.Kind() != reflect.Func {
|
||||||
|
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
37
function/watcher.go
Normal file
37
function/watcher.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package function
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Watcher is used for record code excution time
|
||||||
|
type Watcher struct {
|
||||||
|
startTime int64
|
||||||
|
stopTime int64
|
||||||
|
excuting bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the watch timer.
|
||||||
|
func (w *Watcher) Start() {
|
||||||
|
w.startTime = time.Now().UnixNano()
|
||||||
|
w.excuting = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the watch timer.
|
||||||
|
func (w *Watcher) Stop() {
|
||||||
|
w.stopTime = time.Now().UnixNano()
|
||||||
|
w.excuting = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetElapsedTime get excute elapsed time.
|
||||||
|
func (w *Watcher) GetElapsedTime() time.Duration {
|
||||||
|
if w.excuting {
|
||||||
|
return time.Duration(time.Now().UnixNano() - w.startTime)
|
||||||
|
}
|
||||||
|
return time.Duration(w.stopTime - w.startTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the watch timer.
|
||||||
|
func (w *Watcher) Reset() {
|
||||||
|
w.startTime = 0
|
||||||
|
w.stopTime = 0
|
||||||
|
w.excuting = false
|
||||||
|
}
|
||||||
37
function/watcher_test.go
Normal file
37
function/watcher_test.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package function
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWatcher(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestWatcher")
|
||||||
|
|
||||||
|
w := &Watcher{}
|
||||||
|
w.Start()
|
||||||
|
|
||||||
|
longRunningTask()
|
||||||
|
|
||||||
|
assert.Equal(true, w.excuting)
|
||||||
|
|
||||||
|
w.Stop()
|
||||||
|
|
||||||
|
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||||
|
t.Log("Elapsed Time (milsecond)", eapsedTime)
|
||||||
|
|
||||||
|
assert.Equal(false, w.excuting)
|
||||||
|
|
||||||
|
w.Reset()
|
||||||
|
|
||||||
|
assert.Equal(int64(0), w.startTime)
|
||||||
|
assert.Equal(int64(0), w.stopTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func longRunningTask() {
|
||||||
|
var slice []int64
|
||||||
|
for i := 0; i < 10000000; i++ {
|
||||||
|
slice = append(slice, int64(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
171
internal/assert.go
Normal file
171
internal/assert.go
Normal 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()
|
||||||
|
}
|
||||||
50
internal/assert_test.go
Normal file
50
internal/assert_test.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAssert(t *testing.T) {
|
||||||
|
assert := NewAssert(t, "TestAssert")
|
||||||
|
assert.Equal(0, 0)
|
||||||
|
assert.NotEqual(1, 0)
|
||||||
|
|
||||||
|
assert.NotEqual("1", 1)
|
||||||
|
var uInt1 uint
|
||||||
|
var uInt2 uint
|
||||||
|
var uInt8 uint8
|
||||||
|
var uInt16 uint16
|
||||||
|
var uInt32 uint32
|
||||||
|
var uInt64 uint64
|
||||||
|
assert.NotEqual(uInt1, uInt8)
|
||||||
|
assert.NotEqual(uInt8, uInt16)
|
||||||
|
assert.NotEqual(uInt16, uInt32)
|
||||||
|
assert.NotEqual(uInt32, uInt64)
|
||||||
|
|
||||||
|
assert.Equal(uInt1, uInt2)
|
||||||
|
|
||||||
|
uInt1 = 1
|
||||||
|
uInt2 = 2
|
||||||
|
assert.Less(uInt1, uInt2)
|
||||||
|
|
||||||
|
assert.Greater(1, 0)
|
||||||
|
assert.GreaterOrEqual(1, 1)
|
||||||
|
assert.Less(0, 1)
|
||||||
|
assert.LessOrEqual(0, 0)
|
||||||
|
|
||||||
|
assert.Equal(0.1, 0.1)
|
||||||
|
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")
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,31 +1,32 @@
|
|||||||
package netutil
|
package netutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"github.com/duke-git/lancet/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
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)
|
||||||
utils.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] {
|
|
||||||
utils.LogFailedTestInfo(t, "IsPublicIP", ips[i], expected[i], res)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,27 +22,27 @@ import (
|
|||||||
|
|
||||||
//HttpGet send get http request
|
//HttpGet send get http request
|
||||||
func HttpGet(url string, params ...interface{}) (*http.Response, error) {
|
func HttpGet(url string, params ...interface{}) (*http.Response, error) {
|
||||||
return request(http.MethodGet, url, params...)
|
return doHttpRequest(http.MethodGet, url, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//HttpPost send post http request
|
//HttpPost send post http request
|
||||||
func HttpPost(url string, params ...interface{}) (*http.Response, error) {
|
func HttpPost(url string, params ...interface{}) (*http.Response, error) {
|
||||||
return request(http.MethodPost, url, params...)
|
return doHttpRequest(http.MethodPost, url, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//HttpPut send put http request
|
//HttpPut send put http request
|
||||||
func HttpPut(url string, params ...interface{}) (*http.Response, error) {
|
func HttpPut(url string, params ...interface{}) (*http.Response, error) {
|
||||||
return request(http.MethodPut, url, params...)
|
return doHttpRequest(http.MethodPut, url, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//HttpDelete send delete http request
|
//HttpDelete send delete http request
|
||||||
func HttpDelete(url string, params ...interface{}) (*http.Response, error) {
|
func HttpDelete(url string, params ...interface{}) (*http.Response, error) {
|
||||||
return request(http.MethodDelete, url, params...)
|
return doHttpRequest(http.MethodDelete, url, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HttpPatch send patch http request
|
// HttpPatch send patch http request
|
||||||
func HttpPatch(url string, params ...interface{}) (*http.Response, error) {
|
func HttpPatch(url string, params ...interface{}) (*http.Response, error) {
|
||||||
return request(http.MethodPatch, url, params...)
|
return doHttpRequest(http.MethodPatch, url, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseHttpResponse decode http response to specified interface
|
// ParseHttpResponse decode http response to specified interface
|
||||||
|
|||||||
@@ -2,123 +2,140 @@ package netutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"github.com/duke-git/lancet/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHttpGet(t *testing.T) {
|
func TestHttpGet(t *testing.T) {
|
||||||
_, e := HttpGet("", nil)
|
url := "https://jsonplaceholder.typicode.com/todos/1"
|
||||||
if e == nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
url := "https://gutendex.com/books?"
|
|
||||||
queryParams := make(map[string]interface{})
|
|
||||||
queryParams["ids"] = "1"
|
|
||||||
|
|
||||||
resp, err := HttpGet(url, nil, queryParams)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("error: ", err)
|
|
||||||
//t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
|
||||||
fmt.Println("response: ", resp.StatusCode, string(body))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHttpPost(t *testing.T) {
|
|
||||||
url := "http://api.postcodes.io/postcodes"
|
|
||||||
type Postcode struct {
|
|
||||||
Postcodes []string `json:"postcodes"`
|
|
||||||
}
|
|
||||||
postcode := Postcode{[]string{"OX49 5NU"}}
|
|
||||||
bodyParams, _ := json.Marshal(postcode)
|
|
||||||
header := map[string]string{
|
header := map[string]string{
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resp, err := HttpGet(url, header)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHttpPost(t *testing.T) {
|
||||||
|
url := "https://jsonplaceholder.typicode.com/todos"
|
||||||
|
header := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
type Todo struct {
|
||||||
|
UserId int `json:"userId"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
todo := Todo{1, "TestAddToDo"}
|
||||||
|
bodyParams, _ := json.Marshal(todo)
|
||||||
|
|
||||||
resp, err := HttpPost(url, header, nil, bodyParams)
|
resp, err := HttpPost(url, header, nil, bodyParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
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) {
|
||||||
url := "http://public-api-v1.aspirantzhang.com/users/10420"
|
url := "https://jsonplaceholder.typicode.com/todos/1"
|
||||||
type User struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
}
|
|
||||||
user := User{
|
|
||||||
"test",
|
|
||||||
"test@test.com",
|
|
||||||
}
|
|
||||||
bodyParams, _ := json.Marshal(user)
|
|
||||||
header := map[string]string{
|
header := map[string]string{
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
|
type Todo struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
UserId int `json:"userId"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
todo := Todo{1, 1, "TestPutToDo"}
|
||||||
|
bodyParams, _ := json.Marshal(todo)
|
||||||
|
|
||||||
resp, err := HttpPut(url, header, nil, bodyParams)
|
resp, err := HttpPut(url, header, nil, bodyParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("error: ", err)
|
log.Fatal(err)
|
||||||
//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) {
|
||||||
|
url := "https://jsonplaceholder.typicode.com/todos/1"
|
||||||
|
header := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
type Todo struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
UserId int `json:"userId"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
todo := Todo{1, 1, "TestPatchToDo"}
|
||||||
|
bodyParams, _ := json.Marshal(todo)
|
||||||
|
|
||||||
|
resp, err := HttpPatch(url, header, nil, bodyParams)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
t.Log("response: ", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHttpDelete(t *testing.T) {
|
func TestHttpDelete(t *testing.T) {
|
||||||
url := "http://public-api-v1.aspirantzhang.com/users/10420"
|
url := "https://jsonplaceholder.typicode.com/todos/1"
|
||||||
resp, err := HttpDelete(url)
|
resp, err := HttpDelete(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("error: ", err)
|
log.Fatal(err)
|
||||||
//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 {
|
|
||||||
utils.LogFailedTestInfo(t, "ConvertMapToQueryString", m, expected, r)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseResponse(t *testing.T) {
|
func TestParseResponse(t *testing.T) {
|
||||||
url := "http://public-api-v1.aspirantzhang.com/users"
|
url := "https://jsonplaceholder.typicode.com/todos/1"
|
||||||
type User struct {
|
header := map[string]string{
|
||||||
Id int `json:"id"`
|
"Content-Type": "application/json",
|
||||||
Name string `json:"name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
}
|
}
|
||||||
type UserResp struct {
|
|
||||||
Data []User `json:"data"`
|
resp, err := HttpGet(url, header)
|
||||||
}
|
|
||||||
resp, err := HttpGet(url)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
userResp := &UserResp{}
|
|
||||||
err = ParseHttpResponse(resp, userResp)
|
type Todo struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
UserId int `json:"userId"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Completed bool `json:"completed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
toDoResp := &Todo{}
|
||||||
|
err = ParseHttpResponse(resp, toDoResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
fmt.Println(userResp.Data)
|
t.Log("response: ", toDoResp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func request(method, reqUrl string, params ...interface{}) (*http.Response, error) {
|
func doHttpRequest(method, reqUrl string, params ...interface{}) (*http.Response, error) {
|
||||||
if len(reqUrl) == 0 {
|
if len(reqUrl) == 0 {
|
||||||
return nil, errors.New("url should be specified")
|
return nil, errors.New("url should be specified")
|
||||||
}
|
}
|
||||||
@@ -24,53 +24,29 @@ func request(method, reqUrl string, params ...interface{}) (*http.Response, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
|
err := setUrl(req, reqUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
switch len(params) {
|
switch len(params) {
|
||||||
case 0:
|
|
||||||
err := setUrl(req, reqUrl)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case 1:
|
case 1:
|
||||||
err := setUrl(req, reqUrl)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = setHeader(req, params[0])
|
err = setHeader(req, params[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
err := setHeader(req, params[0])
|
err := setHeaderAndQueryParam(req, reqUrl, params[0], params[1])
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = setQueryParam(req, reqUrl, params[1])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
err := setHeader(req, params[0])
|
err := setHeaderAndQueryAndBody(req, reqUrl, params[0], params[1], params[2])
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = setQueryParam(req, reqUrl, params[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = setBodyByte(req, params[2])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
err := setHeader(req, params[0])
|
err := setHeaderAndQueryAndBody(req, reqUrl, params[0], params[1], params[2])
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = setQueryParam(req, reqUrl, params[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = setBodyByte(req, params[2])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -78,13 +54,40 @@ func request(method, reqUrl string, params ...interface{}) (*http.Response, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, e := client.Do(req)
|
resp, e := client.Do(req)
|
||||||
return resp, e
|
return resp, e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setHeaderAndQueryParam(req *http.Request, reqUrl string, header, queryParam interface{}) error {
|
||||||
|
err := setHeader(req, header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = setQueryParam(req, reqUrl, queryParam)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setHeaderAndQueryAndBody(req *http.Request, reqUrl string, header, queryParam, body interface{}) error {
|
||||||
|
err := setHeader(req, header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = setQueryParam(req, reqUrl, queryParam)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = setBodyByte(req, body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func setHeader(req *http.Request, header interface{}) error {
|
func setHeader(req *http.Request, header interface{}) error {
|
||||||
if header != nil {
|
if header != nil {
|
||||||
switch v := header.(type) {
|
switch v := header.(type) {
|
||||||
@@ -109,6 +112,7 @@ func setHeader(req *http.Request, header interface{}) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUrl(req *http.Request, reqUrl string) error {
|
func setUrl(req *http.Request, reqUrl string) error {
|
||||||
u, err := url.Parse(reqUrl)
|
u, err := url.Parse(reqUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -117,6 +121,7 @@ func setUrl(req *http.Request, reqUrl string) error {
|
|||||||
req.URL = u
|
req.URL = u
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) error {
|
func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) error {
|
||||||
var values url.Values
|
var values url.Values
|
||||||
if queryParam != nil {
|
if queryParam != nil {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -1,71 +1,49 @@
|
|||||||
/*
|
|
||||||
* @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"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"github.com/duke-git/lancet/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
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)
|
||||||
utils.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 {
|
|
||||||
utils.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)
|
||||||
utils.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)
|
||||||
utils.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))
|
||||||
utils.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())
|
||||||
utils.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 {
|
|
||||||
utils.LogFailedTestInfo(t, "RandBytes", "RandBytes(0)", "RandBytes(0) should return nil", randErr)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
assert.Equal([]byte{}, RandBytes(0))
|
||||||
}
|
}
|
||||||
|
|||||||
91
retry/retry.go
Normal file
91
retry/retry.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// 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 times of retry
|
||||||
|
DefaultRetryTimes = 5
|
||||||
|
// DefaultRetryDuration time duration of two retries
|
||||||
|
DefaultRetryDuration = time.Second * 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// RetryConfig is config for retry
|
||||||
|
type RetryConfig struct {
|
||||||
|
context context.Context
|
||||||
|
retryTimes uint
|
||||||
|
retryDuration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetryFunc 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
80
retry/retry_test.go
Normal 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)
|
||||||
|
}
|
||||||
442
slice/slice.go
442
slice/slice.go
@@ -7,16 +7,18 @@ package slice
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Contain check if the value is in the slice or not
|
// Contain check if the value is in the iterable type or not
|
||||||
func Contain(slice interface{}, value interface{}) bool {
|
func Contain(iterableType interface{}, value interface{}) bool {
|
||||||
v := reflect.ValueOf(slice)
|
v := reflect.ValueOf(iterableType)
|
||||||
switch reflect.TypeOf(slice).Kind() {
|
|
||||||
|
switch kind := reflect.TypeOf(iterableType).Kind(); kind {
|
||||||
case reflect.Slice, reflect.Array:
|
case reflect.Slice, reflect.Array:
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
if v.Index(i).Interface() == value {
|
if v.Index(i).Interface() == value {
|
||||||
@@ -29,14 +31,44 @@ func Contain(slice interface{}, value interface{}) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
s := fmt.Sprintf("%v", slice)
|
s := iterableType.(string)
|
||||||
ss := fmt.Sprintf("%v", value)
|
ss, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
panic("kind mismatch")
|
||||||
|
}
|
||||||
|
|
||||||
return strings.Contains(s, ss)
|
return strings.Contains(s, ss)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("kind %s is not support", iterableType))
|
||||||
}
|
}
|
||||||
|
|
||||||
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{}
|
||||||
@@ -70,25 +102,107 @@ func Chunk(slice []interface{}, size int) [][]interface{} {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Difference creates an slice of whose element not included in the other given slice
|
// Compact creates an slice with all falsey values removed. The values false, nil, 0, and "" are falsey
|
||||||
func Difference(slice1, slice2 interface{}) interface{} {
|
func Compact(slice interface{}) interface{} {
|
||||||
v := sliceValue(slice1)
|
sv := sliceValue(slice)
|
||||||
|
|
||||||
var indexes []int
|
var indexes []int
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < sv.Len(); i++ {
|
||||||
vi := v.Index(i).Interface()
|
item := sv.Index(i).Interface()
|
||||||
if !Contain(slice2, vi) {
|
if item != nil && item != false && item != "" && item != 0 {
|
||||||
|
indexes = append(indexes, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res := reflect.MakeSlice(sv.Type(), len(indexes), len(indexes))
|
||||||
|
for i := range indexes {
|
||||||
|
res.Index(i).Set(sv.Index(indexes[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concat creates a new slice concatenating slice with any additional slices and/or values.
|
||||||
|
func Concat(slice interface{}, values ...interface{}) interface{} {
|
||||||
|
sv := sliceValue(slice)
|
||||||
|
size := sv.Len()
|
||||||
|
|
||||||
|
res := reflect.MakeSlice(sv.Type(), size, size)
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
res.Index(i).Set(sv.Index(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range values {
|
||||||
|
if reflect.TypeOf(v).Kind() == reflect.Slice {
|
||||||
|
vv := reflect.ValueOf(v)
|
||||||
|
for i := 0; i < vv.Len(); i++ {
|
||||||
|
res = reflect.Append(res, vv.Index(i))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = reflect.Append(res, reflect.ValueOf(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Difference creates an slice of whose element in slice1, not in slice2
|
||||||
|
func Difference(slice1, slice2 interface{}) interface{} {
|
||||||
|
sv := sliceValue(slice1)
|
||||||
|
|
||||||
|
var indexes []int
|
||||||
|
for i := 0; i < sv.Len(); i++ {
|
||||||
|
item := sv.Index(i).Interface()
|
||||||
|
if !Contain(slice2, item) {
|
||||||
indexes = append(indexes, i)
|
indexes = append(indexes, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res := reflect.MakeSlice(v.Type(), len(indexes), len(indexes))
|
res := reflect.MakeSlice(sv.Type(), len(indexes), len(indexes))
|
||||||
for i := range indexes {
|
for i := range indexes {
|
||||||
res.Index(i).Set(v.Index(indexes[i]))
|
res.Index(i).Set(sv.Index(indexes[i]))
|
||||||
}
|
}
|
||||||
return res.Interface()
|
return res.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DifferenceBy it accepts iteratee which is invoked for each element of slice
|
||||||
|
// and values to generate the criterion by which they're compared.
|
||||||
|
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy,
|
||||||
|
// the iterateeFn function signature should be func(index int, value interface{}) interface{}.
|
||||||
|
func DifferenceBy(slice interface{}, comparedSlice interface{}, iterateeFn interface{}) interface{} {
|
||||||
|
sv := sliceValue(slice)
|
||||||
|
smv := sliceValue(comparedSlice)
|
||||||
|
fn := functionValue(iterateeFn)
|
||||||
|
|
||||||
|
elemType := sv.Type().Elem()
|
||||||
|
if checkSliceCallbackFuncSignature(fn, elemType, nil) {
|
||||||
|
panic("function param should be of type func(" + elemType.String() + ")" + elemType.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
slice1 := reflect.MakeSlice(sv.Type(), sv.Len(), sv.Len())
|
||||||
|
for i := 0; i < sv.Len(); i++ {
|
||||||
|
slice1.Index(i).Set(fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
slice2 := reflect.MakeSlice(smv.Type(), smv.Len(), smv.Len())
|
||||||
|
for i := 0; i < smv.Len(); i++ {
|
||||||
|
slice2.Index(i).Set(fn.Call([]reflect.Value{reflect.ValueOf(i), smv.Index(i)})[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
sliceAfterMap := slice1.Interface()
|
||||||
|
comparedSliceAfterMap := slice2.Interface()
|
||||||
|
|
||||||
|
res := reflect.MakeSlice(sv.Type(), 0, 0)
|
||||||
|
sm := sliceValue(sliceAfterMap)
|
||||||
|
for i := 0; i < sm.Len(); i++ {
|
||||||
|
item := sm.Index(i).Interface()
|
||||||
|
if !Contain(comparedSliceAfterMap, item) {
|
||||||
|
res = reflect.Append(res, sv.Index(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
// Every return true if all of the values in the slice pass the predicate function.
|
// Every return true if all of the values in the slice pass the predicate function.
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The function signature should be func(index int, value interface{}) bool .
|
||||||
func Every(slice, function interface{}) bool {
|
func Every(slice, function interface{}) bool {
|
||||||
@@ -100,15 +214,37 @@ func Every(slice, function interface{}) bool {
|
|||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var indexes []int
|
var currentLength int
|
||||||
for i := 0; i < sv.Len(); i++ {
|
for i := 0; i < sv.Len(); i++ {
|
||||||
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
|
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
|
||||||
if flag.Bool() {
|
if flag.Bool() {
|
||||||
indexes = append(indexes, i)
|
currentLength++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return len(indexes) == 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.
|
||||||
@@ -144,24 +280,20 @@ func Filter(slice, function interface{}) interface{} {
|
|||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var indexes []int
|
res := reflect.MakeSlice(sv.Type(), 0, 0)
|
||||||
for i := 0; i < sv.Len(); i++ {
|
for i := 0; i < sv.Len(); i++ {
|
||||||
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
|
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
|
||||||
if flag.Bool() {
|
if flag.Bool() {
|
||||||
indexes = append(indexes, i)
|
res = reflect.Append(res, sv.Index(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res := reflect.MakeSlice(sv.Type(), len(indexes), len(indexes))
|
|
||||||
for i := range indexes {
|
|
||||||
res.Index(i).Set(sv.Index(indexes[i]))
|
|
||||||
}
|
|
||||||
return res.Interface()
|
return res.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find iterates over elements of slice, returning the first one that passes a truth test on function.
|
// Count iterates over elements of slice, returns a count of all matched elements
|
||||||
// The function signature should be func(index int, value interface{}) bool .
|
// The function signature should be func(index int, value interface{}) bool .
|
||||||
func Find(slice, function interface{}) interface{} {
|
func Count(slice, function interface{}) int {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
fn := functionValue(function)
|
fn := functionValue(function)
|
||||||
|
|
||||||
@@ -170,7 +302,55 @@ func Find(slice, function interface{}) interface{} {
|
|||||||
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var index int
|
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
|
||||||
|
// The function signature should be func(index int, value interface{}) bool .
|
||||||
|
func GroupBy(slice, function interface{}) (interface{}, interface{}) {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
groupB := reflect.MakeSlice(sv.Type(), 0, 0)
|
||||||
|
groupA := reflect.MakeSlice(sv.Type(), 0, 0)
|
||||||
|
|
||||||
|
for i := 0; i < sv.Len(); i++ {
|
||||||
|
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
|
||||||
|
if flag.Bool() {
|
||||||
|
groupA = reflect.Append(groupA, sv.Index(i))
|
||||||
|
} else {
|
||||||
|
groupB = reflect.Append(groupB, sv.Index(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupA.Interface(), groupB.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find iterates over elements of slice, returning the first one that passes a truth test on function.
|
||||||
|
// The function signature should be func(index int, value interface{}) bool .
|
||||||
|
func Find(slice, function interface{}) (interface{}, 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())
|
||||||
|
}
|
||||||
|
|
||||||
|
index := -1
|
||||||
for i := 0; i < sv.Len(); i++ {
|
for i := 0; i < sv.Len(); i++ {
|
||||||
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
|
flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]
|
||||||
if flag.Bool() {
|
if flag.Bool() {
|
||||||
@@ -178,7 +358,53 @@ func Find(slice, function interface{}) interface{} {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sv.Index(index).Interface()
|
|
||||||
|
if index == -1 {
|
||||||
|
var none interface{}
|
||||||
|
return none, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return sv.Index(index).Interface(), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlattenDeep flattens slice recursive
|
||||||
|
func FlattenDeep(slice interface{}) interface{} {
|
||||||
|
sv := sliceValue(slice)
|
||||||
|
st := sliceElemType(sv.Type())
|
||||||
|
tmp := reflect.MakeSlice(reflect.SliceOf(st), 0, 0)
|
||||||
|
res := flattenRecursive(sv, tmp)
|
||||||
|
return res.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
|
||||||
|
for i := 0; i < value.Len(); i++ {
|
||||||
|
item := value.Index(i)
|
||||||
|
kind := item.Kind()
|
||||||
|
|
||||||
|
if kind == reflect.Slice {
|
||||||
|
result = flattenRecursive(item, result)
|
||||||
|
} else {
|
||||||
|
result = reflect.Append(result, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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`.
|
||||||
@@ -252,52 +478,34 @@ func InterfaceSlice(slice interface{}) []interface{} {
|
|||||||
|
|
||||||
// StringSlice convert param to slice of string.
|
// StringSlice convert param to slice of string.
|
||||||
func StringSlice(slice interface{}) []string {
|
func StringSlice(slice interface{}) []string {
|
||||||
var res []string
|
|
||||||
|
|
||||||
v := sliceValue(slice)
|
v := sliceValue(slice)
|
||||||
|
|
||||||
|
out := make([]string, v.Len())
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
res = append(res, fmt.Sprint(v.Index(i)))
|
v, ok := v.Index(i).Interface().(string)
|
||||||
|
if !ok {
|
||||||
|
panic("invalid element type")
|
||||||
|
}
|
||||||
|
out[i] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntSlice convert param to slice of int.
|
// IntSlice convert param to slice of int.
|
||||||
func IntSlice(slice interface{}) ([]int, error) {
|
func IntSlice(slice interface{}) []int {
|
||||||
var res []int
|
|
||||||
|
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
|
|
||||||
|
out := make([]int, sv.Len())
|
||||||
for i := 0; i < sv.Len(); i++ {
|
for i := 0; i < sv.Len(); i++ {
|
||||||
v := sv.Index(i).Interface()
|
v, ok := sv.Index(i).Interface().(int)
|
||||||
switch v := v.(type) {
|
if !ok {
|
||||||
case int:
|
panic("invalid element type")
|
||||||
res = append(res, v)
|
|
||||||
default:
|
|
||||||
return nil, errors.New("InvalidSliceElementType")
|
|
||||||
}
|
}
|
||||||
|
out[i] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return out
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertSlice convert original slice to new data type element of slice.
|
|
||||||
func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} {
|
|
||||||
sv := sliceValue(originalSlice)
|
|
||||||
if newSliceType.Kind() != reflect.Slice {
|
|
||||||
panic(fmt.Sprintf("Invalid newSliceType(non-slice type of type %T)", newSliceType))
|
|
||||||
}
|
|
||||||
|
|
||||||
newSlice := reflect.New(newSliceType)
|
|
||||||
|
|
||||||
hdr := (*reflect.SliceHeader)(unsafe.Pointer(newSlice.Pointer()))
|
|
||||||
|
|
||||||
var newElemSize = int(sv.Type().Elem().Size()) / int(newSliceType.Elem().Size())
|
|
||||||
|
|
||||||
hdr.Cap = sv.Cap() * newElemSize
|
|
||||||
hdr.Len = sv.Len() * newElemSize
|
|
||||||
hdr.Data = sv.Pointer()
|
|
||||||
|
|
||||||
return newSlice.Elem().Interface()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteByIndex delete the element of slice from start index to end index - 1.
|
// DeleteByIndex delete the element of slice from start index to end index - 1.
|
||||||
@@ -322,6 +530,37 @@ func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error
|
|||||||
return v.Interface(), nil
|
return v.Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drop 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{} {
|
||||||
|
sv := sliceValue(slice)
|
||||||
|
|
||||||
|
if n == 0 {
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
svLen := sv.Len()
|
||||||
|
|
||||||
|
if math.Abs(float64(n)) >= float64(svLen) {
|
||||||
|
return reflect.MakeSlice(sv.Type(), 0, 0).Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
res := reflect.MakeSlice(sv.Type(), svLen-n, svLen-n)
|
||||||
|
for i := 0; i < res.Len(); i++ {
|
||||||
|
res.Index(i).Set(sv.Index(i + n))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
res := reflect.MakeSlice(sv.Type(), svLen+n, svLen+n)
|
||||||
|
for i := 0; i < res.Len(); i++ {
|
||||||
|
res.Index(i).Set(sv.Index(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
// InsertByIndex insert the element into slice at index.
|
// InsertByIndex insert the element into slice at index.
|
||||||
// Insert value: s = append(s[:i], append([]T{x}, s[i:]...)...)
|
// Insert value: s = append(s[:i], append([]T{x}, s[i:]...)...)
|
||||||
// Insert slice: a = append(a[:i], append(b, a[i:]...)...)
|
// Insert slice: a = append(a[:i], append(b, a[i:]...)...)
|
||||||
@@ -363,6 +602,7 @@ func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}
|
|||||||
if index < 0 || index >= v.Len() {
|
if index < 0 || index >= v.Len() {
|
||||||
return slice, errors.New("InvalidSliceIndex")
|
return slice, errors.New("InvalidSliceIndex")
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflect.TypeOf(slice).Elem() != reflect.TypeOf(value) {
|
if reflect.TypeOf(slice).Elem() != reflect.TypeOf(value) {
|
||||||
return slice, errors.New("InvalidValueType")
|
return slice, errors.New("InvalidValueType")
|
||||||
}
|
}
|
||||||
@@ -380,7 +620,7 @@ func Unique(slice interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var temp []interface{}
|
var temp []interface{}
|
||||||
len := 0
|
|
||||||
for i := 0; i < sv.Len(); i++ {
|
for i := 0; i < sv.Len(); i++ {
|
||||||
v := sv.Index(i).Interface()
|
v := sv.Index(i).Interface()
|
||||||
skip := true
|
skip := true
|
||||||
@@ -392,12 +632,11 @@ func Unique(slice interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
if skip {
|
if skip {
|
||||||
temp = append(temp, v)
|
temp = append(temp, v)
|
||||||
len++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res := reflect.MakeSlice(sv.Type(), len, len)
|
res := reflect.MakeSlice(sv.Type(), len(temp), len(temp))
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len(temp); i++ {
|
||||||
res.Index(i).Set(reflect.ValueOf(temp[i]))
|
res.Index(i).Set(reflect.ValueOf(temp[i]))
|
||||||
}
|
}
|
||||||
return res.Interface()
|
return res.Interface()
|
||||||
@@ -423,21 +662,21 @@ func Union(slices ...interface{}) interface{} {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// append all slices, then unique it
|
// append all slices, then unique it
|
||||||
var allSlice []interface{}
|
var allSlices []interface{}
|
||||||
len := 0
|
len := 0
|
||||||
for i := range slices {
|
for i := range slices {
|
||||||
sv := sliceValue(slices[i])
|
sv := sliceValue(slices[i])
|
||||||
len += sv.Len()
|
len += sv.Len()
|
||||||
for j := 0; j < sv.Len(); j++ {
|
for j := 0; j < sv.Len(); j++ {
|
||||||
v := sv.Index(j).Interface()
|
v := sv.Index(j).Interface()
|
||||||
allSlice = append(allSlice, v)
|
allSlices = append(allSlices, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sv := sliceValue(slices[0])
|
sv := sliceValue(slices[0])
|
||||||
res := reflect.MakeSlice(sv.Type(), len, len)
|
res := reflect.MakeSlice(sv.Type(), len, len)
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
res.Index(i).Set(reflect.ValueOf(allSlice[i]))
|
res.Index(i).Set(reflect.ValueOf(allSlices[i]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return Unique(res.Interface())
|
return Unique(res.Interface())
|
||||||
@@ -479,19 +718,32 @@ func Intersection(slices ...interface{}) interface{} {
|
|||||||
|
|
||||||
// ReverseSlice return slice of element order is reversed to the given slice
|
// ReverseSlice return slice of element order is reversed to the given slice
|
||||||
func ReverseSlice(slice interface{}) {
|
func ReverseSlice(slice interface{}) {
|
||||||
v := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
swp := reflect.Swapper(v.Interface())
|
swp := reflect.Swapper(sv.Interface())
|
||||||
for i, j := 0, v.Len()-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, sv.Len()-1; i < j; i, j = i+1, j-1 {
|
||||||
swp(i, j)
|
swp(i, j)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shuffle creates an slice of shuffled values
|
||||||
|
func Shuffle(slice interface{}) interface{} {
|
||||||
|
sv := sliceValue(slice)
|
||||||
|
length := sv.Len()
|
||||||
|
|
||||||
|
res := reflect.MakeSlice(sv.Type(), length, length)
|
||||||
|
for i, v := range rand.Perm(length) {
|
||||||
|
res.Index(i).Set(sv.Index(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
// SortByField return sorted slice by field
|
// SortByField return sorted slice by field
|
||||||
// Slice element should be struct, field type should be int, uint, string, or bool
|
// Slice element should be struct, field type should be int, uint, string, or bool
|
||||||
// default sortType is ascending (asc), if descending order, set sortType to desc
|
// default sortType is ascending (asc), if descending order, set sortType to desc
|
||||||
func SortByField(slice interface{}, field string, sortType ...string) error {
|
func SortByField(slice interface{}, field string, sortType ...string) error {
|
||||||
v := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
t := v.Type().Elem()
|
t := sv.Type().Elem()
|
||||||
|
|
||||||
if t.Kind() == reflect.Ptr {
|
if t.Kind() == reflect.Ptr {
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
@@ -507,37 +759,54 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(slice, func(i, j int) bool {
|
sort.Slice(slice, func(i, j int) bool {
|
||||||
a := v.Index(i)
|
a := sv.Index(i)
|
||||||
b := v.Index(j)
|
b := sv.Index(j)
|
||||||
if t.Kind() == reflect.Ptr {
|
if t.Kind() == reflect.Ptr {
|
||||||
a = a.Elem()
|
a = a.Elem()
|
||||||
b = b.Elem()
|
b = b.Elem()
|
||||||
}
|
}
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,6 +816,7 @@ func Without(slice interface{}, values ...interface{}) interface{} {
|
|||||||
if sv.Len() == 0 {
|
if sv.Len() == 0 {
|
||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
var indexes []int
|
var indexes []int
|
||||||
for i := 0; i < sv.Len(); i++ {
|
for i := 0; i < sv.Len(); i++ {
|
||||||
v := sv.Index(i).Interface()
|
v := sv.Index(i).Interface()
|
||||||
|
|||||||
@@ -4,96 +4,73 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"github.com/duke-git/lancet/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
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"}))
|
||||||
utils.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")
|
||||||
|
|
||||||
r1 := [][]interface{}{
|
arr := []string{"a", "b", "c", "d", "e"}
|
||||||
{"a"},
|
r1 := [][]interface{}{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}}
|
||||||
{"b"},
|
assert.Equal(r1, Chunk(InterfaceSlice(arr), 1))
|
||||||
{"c"},
|
|
||||||
{"d"},
|
|
||||||
{"e"},
|
|
||||||
}
|
|
||||||
chunk(t, InterfaceSlice(t1), 1, r1)
|
|
||||||
|
|
||||||
r2 := [][]interface{}{
|
r2 := [][]interface{}{{"a", "b"}, {"c", "d"}, {"e"}}
|
||||||
{"a", "b"},
|
assert.Equal(r2, Chunk(InterfaceSlice(arr), 2))
|
||||||
{"c", "d"},
|
|
||||||
{"e"},
|
|
||||||
}
|
|
||||||
chunk(t, InterfaceSlice(t1), 2, r2)
|
|
||||||
|
|
||||||
r3 := [][]interface{}{
|
r3 := [][]interface{}{{"a", "b", "c"}, {"d", "e"}}
|
||||||
{"a", "b", "c"},
|
assert.Equal(r3, Chunk(InterfaceSlice(arr), 3))
|
||||||
{"d", "e"},
|
|
||||||
}
|
|
||||||
chunk(t, InterfaceSlice(t1), 3, r3)
|
|
||||||
|
|
||||||
r4 := [][]interface{}{
|
r4 := [][]interface{}{{"a", "b", "c", "d"}, {"e"}}
|
||||||
{"a", "b", "c", "d"},
|
assert.Equal(r4, Chunk(InterfaceSlice(arr), 4))
|
||||||
{"e"},
|
|
||||||
}
|
|
||||||
chunk(t, InterfaceSlice(t1), 4, r4)
|
|
||||||
|
|
||||||
r5 := [][]interface{}{
|
|
||||||
{"a"},
|
|
||||||
{"b"},
|
|
||||||
{"c"},
|
|
||||||
{"d"},
|
|
||||||
{"e"},
|
|
||||||
}
|
|
||||||
chunk(t, InterfaceSlice(t1), 5, r5)
|
|
||||||
|
|
||||||
|
r5 := [][]interface{}{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}}
|
||||||
|
assert.Equal(r5, Chunk(InterfaceSlice(arr), 5))
|
||||||
}
|
}
|
||||||
|
|
||||||
func chunk(t *testing.T, test []interface{}, num int, expected [][]interface{}) {
|
func TestCompact(t *testing.T) {
|
||||||
res := Chunk(test, num)
|
assert := internal.NewAssert(t, "TesCompact")
|
||||||
if !reflect.DeepEqual(res, expected) {
|
|
||||||
utils.LogFailedTestInfo(t, "Chunk", test, expected, res)
|
assert.Equal([]int{}, Compact([]int{0}))
|
||||||
t.FailNow()
|
assert.Equal([]int{1, 2, 3}, Compact([]int{0, 1, 2, 3}))
|
||||||
}
|
assert.Equal([]string{}, Compact([]string{""}))
|
||||||
|
assert.Equal([]string{" "}, Compact([]string{" "}))
|
||||||
|
assert.Equal([]string{"a", "b", "0"}, Compact([]string{"", "a", "b", "0"}))
|
||||||
|
assert.Equal([]bool{true, true}, Compact([]bool{false, true, true}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConvertSlice(t *testing.T) {
|
func TestConcat(t *testing.T) {
|
||||||
//t1 := []string{"1","2"}
|
assert := internal.NewAssert(t, "Concat")
|
||||||
//aInt, _ := strconv.ParseInt("1", 10, 64)
|
|
||||||
//bInt, _ := strconv.ParseInt("2", 10, 64)
|
assert.Equal([]int{0}, Concat([]int{}, 0))
|
||||||
//expected :=[]int64{aInt, bInt}
|
assert.Equal([]int{1, 2, 3, 4, 5}, Concat([]int{1, 2, 3}, 4, 5))
|
||||||
//
|
assert.Equal([]int{1, 2, 3, 4, 5}, Concat([]int{1, 2, 3}, []int{4, 5}))
|
||||||
//a := ConvertSlice(t1, reflect.TypeOf(expected))
|
assert.Equal([]int{1, 2, 3, 4, 5}, Concat([]int{1, 2, 3}, []int{4}, []int{5}))
|
||||||
//if !reflect.DeepEqual(a, expected) {
|
assert.Equal([]int{1, 2, 3, 4, 5}, Concat([]int{1, 2, 3}, []int{4}, 5))
|
||||||
// utils.LogFailedTestInfo(t, "ConvertSlice", t1, expected, a)
|
|
||||||
// t.FailNow()
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEvery(t *testing.T) {
|
func TestEvery(t *testing.T) {
|
||||||
@@ -101,42 +78,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")
|
||||||
utils.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")
|
||||||
utils.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))
|
||||||
utils.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 +123,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 +131,31 @@ 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) {
|
}
|
||||||
utils.LogFailedTestInfo(t, "Filter", students, e2, r2)
|
|
||||||
t.FailNow()
|
func TestGroupBy(t *testing.T) {
|
||||||
|
nums := []int{1, 2, 3, 4, 5, 6}
|
||||||
|
evenFunc := func(i, num int) bool {
|
||||||
|
return (num % 2) == 0
|
||||||
|
}
|
||||||
|
expectedEven := []int{2, 4, 6}
|
||||||
|
expectedOdd := []int{1, 3, 5}
|
||||||
|
even, odd := GroupBy(nums, evenFunc)
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestGroupBy")
|
||||||
|
assert.Equal(expectedEven, even)
|
||||||
|
assert.Equal(expectedOdd, odd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCount(t *testing.T) {
|
||||||
|
nums := []int{1, 2, 3, 4, 5, 6}
|
||||||
|
evenFunc := func(i, num int) bool {
|
||||||
|
return (num % 2) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestCount")
|
||||||
|
assert.Equal(3, Count(nums, evenFunc))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFind(t *testing.T) {
|
func TestFind(t *testing.T) {
|
||||||
@@ -166,24 +163,57 @@ func TestFind(t *testing.T) {
|
|||||||
even := func(i, num int) bool {
|
even := func(i, num int) bool {
|
||||||
return num%2 == 0
|
return num%2 == 0
|
||||||
}
|
}
|
||||||
res := Find(nums, even)
|
res, ok := Find(nums, even)
|
||||||
if res != 2 {
|
if !ok {
|
||||||
utils.LogFailedTestInfo(t, "Find", nums, 2, res)
|
t.Fatal("found nothing")
|
||||||
t.FailNow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestFind")
|
||||||
|
assert.Equal(2, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindFoundNothing(t *testing.T) {
|
||||||
|
nums := []int{1, 1, 1, 1, 1, 1}
|
||||||
|
findFunc := func(i, num int) bool {
|
||||||
|
return num > 1
|
||||||
|
}
|
||||||
|
_, ok := Find(nums, findFunc)
|
||||||
|
// if ok {
|
||||||
|
// t.Fatal("found something")
|
||||||
|
// }
|
||||||
|
assert := internal.NewAssert(t, "TestFindFoundNothing")
|
||||||
|
assert.Equal(false, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlattenDeep(t *testing.T) {
|
||||||
|
input := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
|
||||||
|
expected := []string{"a", "b", "c", "d"}
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestFlattenDeep")
|
||||||
|
assert.Equal(expected, FlattenDeep(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
utils.LogFailedTestInfo(t, "Map", s1, e1, r1)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
type student struct {
|
type student struct {
|
||||||
name string
|
name string
|
||||||
@@ -194,8 +224,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},
|
||||||
@@ -204,11 +233,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))
|
||||||
utils.LogFailedTestInfo(t, "Filter", students, e2, r2)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReduce(t *testing.T) {
|
func TestReduce(t *testing.T) {
|
||||||
@@ -216,218 +242,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)
|
||||||
utils.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, err := IntSlice(test)
|
assert.Equal([]int{1, 2, 3}, IntSlice(nums))
|
||||||
if err != nil {
|
|
||||||
t.Error("IntSlice Error: " + err.Error())
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(res, expected) {
|
|
||||||
utils.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) {
|
|
||||||
utils.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) {
|
|
||||||
utils.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{}) {
|
func TestDrop(t *testing.T) {
|
||||||
var res interface{}
|
assert := internal.NewAssert(t, "TestInterfaceSlice")
|
||||||
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) {
|
assert.Equal([]int{}, Drop([]int{}, 0))
|
||||||
utils.LogFailedTestInfo(t, "DeleteByIndex", origin, expected, res)
|
assert.Equal([]int{}, Drop([]int{}, 1))
|
||||||
t.FailNow()
|
assert.Equal([]int{}, Drop([]int{}, -1))
|
||||||
}
|
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, 0))
|
||||||
|
assert.Equal([]int{2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, 1))
|
||||||
|
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 5))
|
||||||
|
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 6))
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, Drop([]int{1, 2, 3, 4, 5}, -1))
|
||||||
|
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6))
|
||||||
|
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6))
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
utils.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) {
|
|
||||||
utils.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) {
|
|
||||||
utils.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) {
|
|
||||||
utils.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))
|
||||||
utils.LogFailedTestInfo(t, "Union", s1, expected1, res1)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
expected2 := []int{1, 3, 4, 6}
|
|
||||||
res2 := Union(s1)
|
|
||||||
if !reflect.DeepEqual(res2, expected2) {
|
|
||||||
utils.LogFailedTestInfo(t, "Union", s1, expected2, res2)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIntersection(t *testing.T) {
|
func TestIntersection(t *testing.T) {
|
||||||
@@ -448,45 +410,49 @@ 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]) {
|
|
||||||
utils.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])
|
||||||
|
}
|
||||||
|
assert.IsNil(Intersection())
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
utils.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)
|
||||||
utils.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) {
|
|
||||||
utils.LogFailedTestInfo(t, "Difference", s1, e1, r1)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSortByField(t *testing.T) {
|
func TestDifferenceBy(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestDifferenceBy")
|
||||||
|
|
||||||
|
s1 := []int{1, 2, 3, 4, 5} //after add one: 2 3 4 5 6
|
||||||
|
s2 := []int{3, 4, 5} //after add one: 4 5 6
|
||||||
|
addOne := func(i int, v int) int {
|
||||||
|
return v + 1
|
||||||
|
}
|
||||||
|
assert.Equal([]int{1, 2}, DifferenceBy(s1, s2, addOne))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortByFielDesc(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestWithout")
|
||||||
|
|
||||||
type student struct {
|
type student struct {
|
||||||
name string
|
name string
|
||||||
age int
|
age int
|
||||||
@@ -497,8 +463,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},
|
||||||
@@ -506,24 +471,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")
|
||||||
utils.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) {
|
|
||||||
utils.LogFailedTestInfo(t, "Without", s, expected, res)
|
func TestShuffle(t *testing.T) {
|
||||||
t.FailNow()
|
assert := internal.NewAssert(t, "TestShuffle")
|
||||||
}
|
|
||||||
|
s := []int{1, 2, 3, 4, 5}
|
||||||
|
res := Shuffle(s)
|
||||||
|
t.Log("Shuffle result: ", res)
|
||||||
|
|
||||||
|
assert.Equal(reflect.TypeOf(s), reflect.TypeOf(res))
|
||||||
|
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,3 +52,14 @@ func checkSliceCallbackFuncSignature(fn reflect.Value, types ...reflect.Type) bo
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sliceElemType get slice element type
|
||||||
|
func sliceElemType(reflectType reflect.Type) reflect.Type {
|
||||||
|
for {
|
||||||
|
if reflectType.Kind() != reflect.Slice {
|
||||||
|
return reflectType
|
||||||
|
}
|
||||||
|
|
||||||
|
reflectType = reflectType.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CamelCase covert string to camelCase string.
|
// CamelCase covert string to camelCase string.
|
||||||
@@ -53,26 +54,28 @@ func Capitalize(s string) string {
|
|||||||
return string(out)
|
return string(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpperFirst converts the first character of string to upper case.
|
||||||
|
func UpperFirst(s string) string {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
r, size := utf8.DecodeRuneInString(s)
|
||||||
|
r = unicode.ToUpper(r)
|
||||||
|
|
||||||
|
return string(r) + s[size:]
|
||||||
|
}
|
||||||
|
|
||||||
// LowerFirst converts the first character of string to lower case.
|
// LowerFirst converts the first character of string to lower case.
|
||||||
func LowerFirst(s string) string {
|
func LowerFirst(s string) string {
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
res := ""
|
r, size := utf8.DecodeRuneInString(s)
|
||||||
for i, v := range []rune(s) {
|
r = unicode.ToLower(r)
|
||||||
if i == 0 {
|
|
||||||
if v >= 65 && v <= 96 {
|
return string(r) + s[size:]
|
||||||
v += 32
|
|
||||||
res += string(v)
|
|
||||||
} else {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res += string(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PadEnd pads string on the right side if it's shorter than size.
|
// PadEnd pads string on the right side if it's shorter than size.
|
||||||
@@ -214,3 +217,34 @@ func ReverseStr(s string) string {
|
|||||||
}
|
}
|
||||||
return string(r)
|
return string(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrap a string with another string.
|
||||||
|
func Wrap(str string, wrapWith string) string {
|
||||||
|
if str == "" || wrapWith == "" {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString(wrapWith)
|
||||||
|
sb.WriteString(str)
|
||||||
|
sb.WriteString(wrapWith)
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap a given string from anther string. will change str value
|
||||||
|
func Unwrap(str string, wrapToken string) string {
|
||||||
|
if str == "" || wrapToken == "" {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
firstIndex := strings.Index(str, wrapToken)
|
||||||
|
lastIndex := strings.LastIndex(str, wrapToken)
|
||||||
|
|
||||||
|
if firstIndex == 0 && lastIndex > 0 && lastIndex <= len(str)-1 {
|
||||||
|
if len(wrapToken) <= lastIndex {
|
||||||
|
str = str[len(wrapToken):lastIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,198 +3,177 @@ package strutil
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"github.com/duke-git/lancet/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
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"))
|
||||||
utils.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"))
|
||||||
utils.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"))
|
||||||
utils.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")
|
assert.Equal("foo_bar", SnakeCase("Foo Bar-"))
|
||||||
snakeCase(t, "__FOO_BAR__", "f_o_o_b_a_r")
|
assert.Equal("foo_bar", SnakeCase("foo_Bar"))
|
||||||
snakeCase(t, "aBbc-s$@a&%_B.B^C", "a_bbc_s_a_b_b_c")
|
assert.Equal("foo_bar", SnakeCase("fooBar"))
|
||||||
|
assert.Equal("f_o_o_b_a_r", SnakeCase("__FOO_BAR__"))
|
||||||
|
assert.Equal("a_bbc_s_a_b_b_c", SnakeCase("aBbc-s$@a&%_B.B^C"))
|
||||||
|
|
||||||
|
assert.NotEqual("foo-bar", SnakeCase("foo_Bar"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func snakeCase(t *testing.T, test string, expected string) {
|
func TestUpperFirst(t *testing.T) {
|
||||||
res := SnakeCase(test)
|
assert := internal.NewAssert(t, "TestLowerFirst")
|
||||||
if res != expected {
|
|
||||||
utils.LogFailedTestInfo(t, "SnakeCase", test, expected, res)
|
assert.Equal("Foo", UpperFirst("foo"))
|
||||||
t.FailNow()
|
assert.Equal("BAR", UpperFirst("bAR"))
|
||||||
}
|
assert.Equal("FOo", UpperFirst("FOo"))
|
||||||
|
assert.Equal("FOo大", UpperFirst("fOo大"))
|
||||||
|
|
||||||
|
assert.NotEqual("Bar", UpperFirst("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")
|
|
||||||
}
|
|
||||||
|
|
||||||
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"))
|
||||||
utils.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"))
|
||||||
utils.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"))
|
||||||
utils.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"))
|
||||||
utils.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"))
|
||||||
utils.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"))
|
||||||
utils.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"))
|
||||||
utils.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))
|
||||||
utils.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")
|
|
||||||
|
|
||||||
//failed
|
assert.Equal("cba", ReverseStr("abc"))
|
||||||
//reverseStr(t, "abc", "abc")
|
assert.Equal("54321", ReverseStr("12345"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func reverseStr(t *testing.T, test string, expected string) {
|
func TestWrap(t *testing.T) {
|
||||||
res := ReverseStr(test)
|
assert := internal.NewAssert(t, "TestWrap")
|
||||||
if res != expected {
|
|
||||||
utils.LogFailedTestInfo(t, "ReverseStr", test, expected, res)
|
assert.Equal("ab", Wrap("ab", ""))
|
||||||
t.FailNow()
|
assert.Equal("", Wrap("", "*"))
|
||||||
}
|
assert.Equal("*ab*", Wrap("ab", "*"))
|
||||||
|
assert.Equal("\"ab\"", Wrap("ab", "\""))
|
||||||
|
assert.Equal("'ab'", Wrap("ab", "'"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnwrap(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestUnwrap")
|
||||||
|
|
||||||
|
assert.Equal("", Unwrap("", "*"))
|
||||||
|
assert.Equal("ab", Unwrap("ab", ""))
|
||||||
|
assert.Equal("ab", Unwrap("ab", "*"))
|
||||||
|
assert.Equal("*ab*", Unwrap("**ab**", "*"))
|
||||||
|
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("**", "**"))
|
||||||
}
|
}
|
||||||
|
|||||||
72
system/os.go
Normal file
72
system/os.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// 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) (stdout, stderr string, err error) {
|
||||||
|
var out bytes.Buffer
|
||||||
|
var errout bytes.Buffer
|
||||||
|
|
||||||
|
cmd := exec.Command("/bin/bash", "-c", command)
|
||||||
|
if IsWindows() {
|
||||||
|
cmd = exec.Command("cmd")
|
||||||
|
}
|
||||||
|
cmd.Stdout = &out
|
||||||
|
cmd.Stderr = &errout
|
||||||
|
err = cmd.Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
stderr = string(errout.Bytes())
|
||||||
|
}
|
||||||
|
stdout = string(out.Bytes())
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
62
system/os_test.go
Normal file
62
system/os_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOsDetection(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestOsJudgment")
|
||||||
|
|
||||||
|
osType, _, _ := ExecCommand("echo $OSTYPE")
|
||||||
|
if strings.Index(osType, "linux") != -1 {
|
||||||
|
assert.Equal(true, IsLinux())
|
||||||
|
}
|
||||||
|
if strings.Index(osType, "darwin") != -1 {
|
||||||
|
assert.Equal(true, IsMac())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
assert.Equal(false, CompareOsEnv("abc", "abc"))
|
||||||
|
assert.Equal(false, CompareOsEnv("abc", "abc"))
|
||||||
|
|
||||||
|
err := RemoveOsEnv("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
assert.Equal(false, CompareOsEnv("foo", "foo_value"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecCommand(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestExecCommand")
|
||||||
|
|
||||||
|
out, errout, err := ExecCommand("ls")
|
||||||
|
t.Log("std out: ", out)
|
||||||
|
t.Log("std err: ", errout)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
out, errout, err = ExecCommand("abc")
|
||||||
|
t.Log("std out: ", out)
|
||||||
|
t.Log("std err: ", errout)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("error: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !IsWindows() {
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
|
||||||
// Use of this source code is governed by MIT license
|
|
||||||
|
|
||||||
// Package utils implements is for internal use.
|
|
||||||
package utils
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@@ -5,17 +5,73 @@
|
|||||||
package validator
|
package validator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
"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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsJSON 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 +80,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 +104,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,15 +113,38 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isUrlRegexMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
|
||||||
|
|
||||||
|
// IsUrl check if the string is url.
|
||||||
|
func IsUrl(str string) bool {
|
||||||
|
if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
u, err := url.Parse(str)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(u.Host, ".") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return isUrlRegexMatcher.MatchString(str)
|
||||||
|
}
|
||||||
|
|
||||||
var isDnsRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
|
var isDnsRegexMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
|
||||||
|
|
||||||
// IsDns check if the string is dns.
|
// IsDns check if the string is dns.
|
||||||
@@ -130,14 +203,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
|
||||||
|
|||||||
@@ -3,281 +3,279 @@ package validator
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/utils"
|
"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 {
|
|
||||||
utils.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."))
|
||||||
utils.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 {
|
|
||||||
utils.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"))
|
||||||
utils.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 {
|
|
||||||
utils.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)
|
|
||||||
|
assert.Equal(false, IsIpV6("127.0.0.1"))
|
||||||
|
assert.Equal(true, IsIpV6("::0:0:0:0:0:0:1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func isIpV6(t *testing.T, source string, expected bool) {
|
func TestIsUrl(t *testing.T) {
|
||||||
res := IsIpV6(source)
|
assert := internal.NewAssert(t, "TestIsUrl")
|
||||||
if res != expected {
|
|
||||||
utils.LogFailedTestInfo(t, "IsIpV6", source, expected, res)
|
assert.Equal(true, IsUrl("http://abc.com"))
|
||||||
t.FailNow()
|
assert.Equal(true, IsUrl("abc.com"))
|
||||||
}
|
assert.Equal(true, IsUrl("a.b.com"))
|
||||||
|
assert.Equal(false, IsUrl("abc"))
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
assert.Equal(false, IsDns("http://abc.com"))
|
||||||
utils.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 {
|
|
||||||
utils.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"))
|
||||||
utils.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 {
|
|
||||||
utils.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 {
|
|
||||||
utils.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"))
|
||||||
utils.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 {
|
|
||||||
utils.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 {
|
|
||||||
utils.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(" "))
|
||||||
utils.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(" "))
|
||||||
utils.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]+$`))
|
||||||
utils.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))
|
||||||
utils.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"))
|
||||||
utils.LogFailedTestInfo(t, "IsWeakPassword", source, expected, res)
|
assert.Equal(true, IsWeakPassword("abcABC123"))
|
||||||
t.FailNow()
|
assert.Equal(false, IsWeakPassword("abc123@#$"))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user