refactor: move files to hrp

This commit is contained in:
debugtalk
2022-03-23 10:36:24 +08:00
parent 6cb835c6c6
commit 2187d41e65
122 changed files with 23288 additions and 23 deletions
+208
View File
@@ -0,0 +1,208 @@
package builtin
import (
"fmt"
"reflect"
"strings"
"github.com/stretchr/testify/assert"
)
var Assertions = map[string]func(t assert.TestingT, actual interface{}, expected interface{}, msgAndArgs ...interface{}) bool{
"eq": assert.EqualValues,
"equals": assert.EqualValues,
"equal": assert.EqualValues,
"lt": assert.Less,
"less_than": assert.Less,
"le": assert.LessOrEqual,
"less_or_equals": assert.LessOrEqual,
"gt": assert.Greater,
"greater_than": assert.Greater,
"ge": assert.GreaterOrEqual,
"greater_or_equals": assert.GreaterOrEqual,
"ne": assert.NotEqual,
"not_equal": assert.NotEqual,
"contains": assert.Contains,
"type_match": assert.IsType,
// custom assertions
"startswith": StartsWith,
"endswith": EndsWith,
"len_eq": EqualLength,
"length_equals": EqualLength,
"length_equal": EqualLength,
"len_lt": LessThanLength,
"count_lt": LessThanLength,
"length_less_than": LessThanLength,
"len_le": LessOrEqualsLength,
"count_le": LessOrEqualsLength,
"length_less_or_equals": LessOrEqualsLength,
"len_gt": GreaterThanLength,
"count_gt": GreaterThanLength,
"length_greater_than": GreaterThanLength,
"len_ge": GreaterOrEqualsLength,
"count_ge": GreaterOrEqualsLength,
"length_greater_or_equals": GreaterOrEqualsLength,
"contained_by": ContainedBy,
"str_eq": StringEqual,
"string_equals": StringEqual,
"regex_match": RegexMatch,
}
// StartsWith check if string starts with substring
func StartsWith(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
if !assert.IsType(t, "string", actual, fmt.Sprintf("actual is %v", actual)) {
return false
}
if !assert.IsType(t, "string", expected, fmt.Sprintf("expected is %v", expected)) {
return false
}
actualString := actual.(string)
expectedString := expected.(string)
return assert.True(t, strings.HasPrefix(actualString, expectedString), msgAndArgs...)
}
// EndsWith check if string ends with substring
func EndsWith(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
if !assert.IsType(t, "string", actual, fmt.Sprintf("actual is %v", actual)) {
return false
}
if !assert.IsType(t, "string", expected, fmt.Sprintf("expected is %v", expected)) {
return false
}
actualString := actual.(string)
expectedString := expected.(string)
return assert.True(t, strings.HasSuffix(actualString, expectedString), msgAndArgs...)
}
func EqualLength(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
length, err := convertInt(expected)
if err != nil {
return assert.Fail(t, fmt.Sprintf("expected type is not int, got %#v", expected), msgAndArgs...)
}
return assert.Len(t, actual, length, msgAndArgs...)
}
func GreaterThanLength(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
length, err := convertInt(expected)
if err != nil {
return assert.Fail(t, fmt.Sprintf("expected type is not int, got %#v", expected), msgAndArgs...)
}
ok, l := getLen(actual)
if !ok {
return assert.Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", actual), msgAndArgs...)
}
if l <= length {
return assert.Fail(t, fmt.Sprintf("\"%s\" should be more than %d item(s), but has %d", actual, length, l), msgAndArgs...)
}
return true
}
func GreaterOrEqualsLength(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
length, err := convertInt(expected)
if err != nil {
return assert.Fail(t, fmt.Sprintf("expected type is not int, got %#v", expected), msgAndArgs...)
}
ok, l := getLen(actual)
if !ok {
return assert.Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", actual), msgAndArgs...)
}
if l < length {
return assert.Fail(t, fmt.Sprintf("\"%s\" should be no less than %d item(s), but has %d", actual, length, l), msgAndArgs...)
}
return true
}
func LessThanLength(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
length, err := convertInt(expected)
if err != nil {
return assert.Fail(t, fmt.Sprintf("expected type is not int, got %#v", expected), msgAndArgs...)
}
ok, l := getLen(actual)
if !ok {
return assert.Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", actual), msgAndArgs...)
}
if l >= length {
return assert.Fail(t, fmt.Sprintf("\"%s\" should be less than %d item(s), but has %d", actual, length, l), msgAndArgs...)
}
return true
}
func LessOrEqualsLength(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
length, err := convertInt(expected)
if err != nil {
return assert.Fail(t, fmt.Sprintf("expected type is not int, got %#v", expected), msgAndArgs...)
}
ok, l := getLen(actual)
if !ok {
return assert.Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", actual), msgAndArgs...)
}
if l > length {
return assert.Fail(t, fmt.Sprintf("\"%s\" should be no more than %d item(s), but has %d", actual, length, l), msgAndArgs...)
}
return true
}
// ContainedBy assert whether actual element contains expected element
func ContainedBy(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
return assert.Contains(t, expected, actual, msgAndArgs)
}
func StringEqual(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
if !assert.IsType(t, "string", actual, msgAndArgs) {
return false
}
if !assert.IsType(t, "string", expected, msgAndArgs) {
return false
}
actualString := actual.(string)
expectedString := expected.(string)
return assert.True(t, strings.EqualFold(actualString, expectedString), msgAndArgs)
}
func RegexMatch(t assert.TestingT, actual, expected interface{}, msgAndArgs ...interface{}) bool {
return assert.Regexp(t, expected, actual, msgAndArgs)
}
func convertInt(value interface{}) (int, error) {
switch v := value.(type) {
case int:
return v, nil
case int8:
return int(v), nil
case int16:
return int(v), nil
case int32:
return int(v), nil
case int64:
return int(v), nil
case uint:
return int(v), nil
case uint8:
return int(v), nil
case uint16:
return int(v), nil
case uint32:
return int(v), nil
case uint64:
return int(v), nil
case float32:
return int(v), nil
case float64:
return int(v), nil
default:
return 0, fmt.Errorf("unsupported int convertion for %v(%T)", v, v)
}
}
// getLen try to get length of object.
// return (false, 0) if impossible.
func getLen(x interface{}) (ok bool, length int) {
v := reflect.ValueOf(x)
defer func() {
if e := recover(); e != nil {
ok = false
}
}()
return true, v.Len()
}
+191
View File
@@ -0,0 +1,191 @@
package builtin
import (
"regexp"
"testing"
"github.com/stretchr/testify/assert"
)
func TestStartsWith(t *testing.T) {
testData := []struct {
raw string
expected string
}{
{"", ""},
{"a", "a"},
{"abc", "a"},
{"abc", "ab"},
}
for _, data := range testData {
if !assert.True(t, StartsWith(t, data.raw, data.expected)) {
t.Fail()
}
}
}
func TestEndsWith(t *testing.T) {
testData := []struct {
raw string
expected string
}{
{"", ""},
{"a", "a"},
{"abc", "c"},
{"abc", "bc"},
}
for _, data := range testData {
if !assert.True(t, EndsWith(t, data.raw, data.expected)) {
t.Fail()
}
}
}
func TestEqualLength(t *testing.T) {
testData := []struct {
raw interface{}
expected int
}{
{"", 0},
{[]string{}, 0},
{map[string]interface{}{}, 0},
{"a", 1},
{[]string{"a"}, 1},
{map[string]interface{}{"a": 123}, 1},
}
for _, data := range testData {
if !assert.True(t, EqualLength(t, data.raw, data.expected)) {
t.Fail()
}
}
}
func TestLessThanLength(t *testing.T) {
testData := []struct {
raw interface{}
expected int
}{
{"", 1},
{[]string{}, 1},
{map[string]interface{}{}, 1},
{"a", 2},
{[]string{"a"}, 2},
{map[string]interface{}{"a": 123}, 2},
}
for _, data := range testData {
if !assert.True(t, LessThanLength(t, data.raw, data.expected)) {
t.Fail()
}
}
}
func TestLessOrEqualsLength(t *testing.T) {
testData := []struct {
raw interface{}
expected int
}{
{"", 1},
{[]string{}, 1},
{map[string]interface{}{"A": 111}, 1},
{"a", 1},
{[]string{"a"}, 2},
{map[string]interface{}{"a": 123}, 2},
}
for _, data := range testData {
if !assert.True(t, LessOrEqualsLength(t, data.raw, data.expected)) {
t.Fail()
}
}
}
func TestGreaterThanLength(t *testing.T) {
testData := []struct {
raw interface{}
expected int
}{
{"abcd", 3},
{[]string{"a", "b", "c"}, 2},
{map[string]interface{}{"a": 123, "b": 223, "c": 323}, 2},
}
for _, data := range testData {
if !assert.True(t, GreaterThanLength(t, data.raw, data.expected)) {
t.Fail()
}
}
}
func TestGreaterOrEqualsLength(t *testing.T) {
testData := []struct {
raw interface{}
expected int
}{
{"abcd", 3},
{[]string{"w"}, 1},
{map[string]interface{}{"A": 111}, 1},
{"a", 1},
{[]string{"a", "b", "c"}, 2},
{map[string]interface{}{"a": 123, "b": 223, "c": 323}, 2},
}
for _, data := range testData {
if !assert.True(t, GreaterOrEqualsLength(t, data.raw, data.expected)) {
t.Fail()
}
}
}
func TestContainedBy(t *testing.T) {
testData := []struct {
raw interface{}
expected interface{}
}{
{"abcd", "abcdefg"},
{"a", []string{"a", "b", "c"}},
{"A", map[string]interface{}{"A": 111, "B": 222}},
}
for _, data := range testData {
if !assert.True(t, ContainedBy(t, data.raw, data.expected)) {
t.Fail()
}
}
}
func TestStringEqual(t *testing.T) {
testData := []struct {
raw interface{}
expected interface{}
}{
{"abcd", "abcd"},
{"abcd", "ABCD"},
{"ABcd", "abCD"},
}
for _, data := range testData {
if !assert.True(t, StringEqual(t, data.raw, data.expected)) {
t.Fail()
}
}
}
func TestRegexMatch(t *testing.T) {
testData := []struct {
raw interface{}
expected interface{}
}{
{"it's starting...", regexp.MustCompile("start")},
{"it's not starting", "starting$"},
}
for _, data := range testData {
if !assert.True(t, RegexMatch(t, data.raw, data.expected)) {
t.Fail()
}
}
}
+260
View File
@@ -0,0 +1,260 @@
package builtin
import (
"bytes"
"crypto/md5"
"encoding/csv"
"encoding/hex"
builtinJSON "encoding/json"
"errors"
"fmt"
"math"
"math/rand"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v3"
"github.com/httprunner/httprunner/hrp/internal/json"
)
var Functions = map[string]interface{}{
"get_timestamp": getTimestamp, // call without arguments
"sleep": sleep, // call with one argument
"gen_random_string": genRandomString, // call with one argument
"max": math.Max, // call with two arguments
"md5": MD5, // call with one argument
"parameterize": loadFromCSV,
"P": loadFromCSV,
}
func init() {
rand.Seed(time.Now().UnixNano())
}
func getTimestamp() int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}
func sleep(nSecs int) {
time.Sleep(time.Duration(nSecs) * time.Second)
}
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
func genRandomString(n int) string {
lettersLen := len(letters)
b := make([]byte, n)
for i := range b {
b[i] = letters[rand.Intn(lettersLen)]
}
return string(b)
}
func MD5(str string) string {
hasher := md5.New()
hasher.Write([]byte(str))
return hex.EncodeToString(hasher.Sum(nil))
}
func loadFromCSV(path string) []map[string]interface{} {
path, err := filepath.Abs(path)
if err != nil {
log.Error().Str("path", path).Err(err).Msg("convert absolute path failed")
panic(err)
}
log.Info().Str("path", path).Msg("load csv file")
file, err := os.ReadFile(path)
if err != nil {
log.Error().Err(err).Msg("load csv file failed")
panic(err)
}
r := csv.NewReader(strings.NewReader(string(file)))
content, err := r.ReadAll()
if err != nil {
log.Error().Err(err).Msg("parse csv file failed")
panic(err)
}
var result []map[string]interface{}
for i := 1; i < len(content); i++ {
row := make(map[string]interface{})
for j := 0; j < len(content[i]); j++ {
row[content[0][j]] = content[i][j]
}
result = append(result, row)
}
return result
}
func Dump2JSON(data interface{}, path string) error {
path, err := filepath.Abs(path)
if err != nil {
log.Error().Err(err).Msg("convert absolute path failed")
return err
}
log.Info().Str("path", path).Msg("dump data to json")
file, _ := json.MarshalIndent(data, "", " ")
err = os.WriteFile(path, file, 0644)
if err != nil {
log.Error().Err(err).Msg("dump json path failed")
return err
}
return nil
}
func Dump2YAML(data interface{}, path string) error {
path, err := filepath.Abs(path)
if err != nil {
log.Error().Err(err).Msg("convert absolute path failed")
return err
}
log.Info().Str("path", path).Msg("dump data to yaml")
// init yaml encoder
buffer := new(bytes.Buffer)
encoder := yaml.NewEncoder(buffer)
encoder.SetIndent(4)
// encode
err = encoder.Encode(data)
if err != nil {
return err
}
err = os.WriteFile(path, buffer.Bytes(), 0644)
if err != nil {
log.Error().Err(err).Msg("dump yaml path failed")
return err
}
return nil
}
func FormatResponse(raw interface{}) interface{} {
formattedResponse := make(map[string]interface{})
for key, value := range raw.(map[string]interface{}) {
// convert value to json
if key == "body" {
b, _ := json.MarshalIndent(&value, "", " ")
value = string(b)
}
formattedResponse[key] = value
}
return formattedResponse
}
func ExecCommand(cmd *exec.Cmd, cwd string) error {
log.Info().Str("cmd", cmd.String()).Str("cwd", cwd).Msg("exec command")
cmd.Dir = cwd
output, err := cmd.CombinedOutput()
out := strings.TrimSpace(string(output))
if err != nil {
log.Error().Err(err).Str("output", out).Msg("exec command failed")
} else if len(out) != 0 {
log.Info().Str("output", out).Msg("exec command success")
}
return err
}
func CreateFolder(folderPath string) error {
log.Info().Str("path", folderPath).Msg("create folder")
err := os.MkdirAll(folderPath, os.ModePerm)
if err != nil {
log.Error().Err(err).Msg("create folder failed")
return err
}
return nil
}
func CreateFile(filePath string, data string) error {
log.Info().Str("path", filePath).Msg("create file")
err := os.WriteFile(filePath, []byte(data), 0o644)
if err != nil {
log.Error().Err(err).Msg("create file failed")
return err
}
return nil
}
// isFilePathExists returns true if path exists, whether path is file or dir
func isPathExists(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
}
return true
}
// isFilePathExists returns true if path exists and path is file
func isFilePathExists(path string) bool {
info, err := os.Stat(path)
if err != nil {
// path not exists
return false
}
// path exists
if info.IsDir() {
// path is dir, not file
return false
}
return true
}
func EnsureFolderExists(folderPath string) error {
if !isPathExists(folderPath) {
err := CreateFolder(folderPath)
return err
} else if isFilePathExists(folderPath) {
return fmt.Errorf("path %v should be directory", folderPath)
}
return nil
}
func Contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
func GetRandomNumber(min, max int) int {
if min > max {
return 0
}
r := rand.Intn(max - min + 1)
return min + r
}
func Interface2Float64(i interface{}) (float64, error) {
switch i.(type) {
case int:
return float64(i.(int)), nil
case int32:
return float64(i.(int32)), nil
case int64:
return float64(i.(int64)), nil
case float32:
return float64(i.(float32)), nil
case float64:
return i.(float64), nil
case string:
intVar, err := strconv.Atoi(i.(string))
if err != nil {
return 0, err
}
return float64(intVar), err
}
// json.Number
value, ok := i.(builtinJSON.Number)
if ok {
return value.Float64()
}
return 0, errors.New("failed to convert interface to float64")
}