Created
Some checks failed
Go / build (push) Failing after 7s

This commit is contained in:
scheibling
2025-04-08 19:16:39 +02:00
commit b4eb50ab55
63 changed files with 7333 additions and 0 deletions

177
isx/is.go Normal file
View File

@@ -0,0 +1,177 @@
package isx
import (
"bytes"
"net/url"
"reflect"
"regexp"
"runtime"
"strings"
"time"
"unicode/utf8"
"git.cloudyne.io/go/hiscaler-gox/stringx"
)
var (
rxSafeCharacters = regexp.MustCompile("^[a-zA-Z0-9\\.\\-_][a-zA-Z0-9\\.\\-_]*$")
rxNumber = regexp.MustCompile("^[+-]?\\d+$|^\\d+[.]\\d+$")
rxColorHex = regexp.MustCompile("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$")
)
// OS type
const (
IsAix = "aix"
IsAndroid = "android"
IsDarwin = "darwin"
IsDragonfly = "dragonfly"
IsFreebsd = "freebsd"
IsHurd = "hurd"
IsIllumos = "illumos"
IsIos = "ios"
IsJs = "js"
IsLinux = "linux"
IsNacl = "nacl"
IsNetbsd = "netbsd"
IsOpenbsd = "openbsd"
IsPlan9 = "plan9"
IsSolaris = "solaris"
IsWindows = "windows"
IsZos = "zos"
)
// Number Check any value is a number
func Number(i interface{}) bool {
switch i.(type) {
case string:
s := stringx.TrimAny(strings.TrimSpace(i.(string)), "+", "-")
n := len(s)
if n == 0 {
return false
}
if strings.IndexFunc(s[n-1:], func(c rune) bool {
return c < '0' || c > '9'
}) != -1 {
return false
}
return rxNumber.MatchString(strings.ReplaceAll(s, ",", ""))
case int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64,
complex64, complex128:
return true
default:
return false
}
}
// Empty 判断是否为空
func Empty(value interface{}) bool {
if value == nil {
return true
}
v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.String, reflect.Array, reflect.Map, reflect.Slice:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Invalid:
return true
case reflect.Interface, reflect.Ptr:
if v.IsNil() {
return true
}
return Empty(v.Elem().Interface())
case reflect.Struct:
v, ok := value.(time.Time)
if ok && v.IsZero() {
return true
}
}
return false
}
func Equal(expected interface{}, actual interface{}) bool {
if expected == nil || actual == nil {
return expected == actual
}
if exp, ok := expected.([]byte); ok {
act, ok := actual.([]byte)
if !ok {
return false
}
if exp == nil || act == nil {
return true
}
return bytes.Equal(exp, act)
}
return reflect.DeepEqual(expected, actual)
}
// SafeCharacters Only include a-zA-Z0-9.-_
// Reference https://www.quora.com/What-are-valid-file-names
func SafeCharacters(str string) bool {
if str == "" {
return false
}
return rxSafeCharacters.MatchString(str)
}
// HttpURL checks if the string is a HTTP URL.
// govalidator/IsURL
func HttpURL(str string) bool {
const (
URLSchema string = `((https?):\/\/)`
URLPath string = `((\/|\?|#)[^\s]*)`
URLPort string = `(:(\d{1,5}))`
URLIP string = `([1-9]\d?|1\d\d|2[01]\d|22[0-3]|24\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-5]))`
URLSubdomain string = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))`
URL = `^` + URLSchema + `?` + `((` + URLIP + `|(\[` + `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))` + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$`
)
if str == "" || utf8.RuneCountInString(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
return false
}
if strings.HasPrefix(str, "//") {
str = "http:" + str
}
strTemp := str
if strings.Contains(str, ":") && !strings.Contains(str, "://") {
// support no indicated urlscheme but with colon for port number
// http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
strTemp = "http://" + str
}
u, err := url.Parse(strTemp)
if err != nil {
return false
}
if strings.HasPrefix(u.Host, ".") {
return false
}
if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
return false
}
return regexp.MustCompile(URL).MatchString(str)
}
// OS check typ is a valid OS type
// Usage: isx.OS(isx.IsLinux)
func OS(typ string) bool {
return runtime.GOOS == typ
}
func ColorHex(s string) bool {
return rxColorHex.MatchString(s)
}

231
isx/is_test.go Normal file
View File

@@ -0,0 +1,231 @@
package isx
import (
"github.com/stretchr/testify/assert"
"testing"
"time"
)
func TestNumber(t *testing.T) {
uintPtr := uintptr(12)
testCases := []struct {
Value interface{}
IsNumber bool
}{
{"a", false},
{"111", true},
{"1.23", true},
{"1,234.5", true},
{"1234.5,", false},
{"12345.", false},
{" 12345.6 ", true},
{" 12345. 6 ", false},
{"-1", true},
{"+1", true},
{1, true},
{1.1, true},
{0, true},
{uintPtr, true},
}
for _, testCase := range testCases {
v := Number(testCase.Value)
if v != testCase.IsNumber {
t.Errorf("%s except %v actual %v", testCase.Value, testCase.IsNumber, v)
}
}
}
func TestEmpty(t *testing.T) {
var s1 string
var s2 = "a"
var s3 *string
s4 := struct{}{}
time1 := time.Now()
var time2 time.Time
tests := []struct {
tag string
value interface{}
empty bool
}{
// nil
{"t0", nil, true},
// string
{"t1.1", "", true},
{"t1.2", "1", false},
// slice
{"t2.1", []byte(""), true},
{"t2.2", []byte("1"), false},
// map
{"t3.1", map[string]int{}, true},
{"t3.2", map[string]int{"a": 1}, false},
// bool
{"t4.1", false, true},
{"t4.2", true, false},
// int
{"t5.1", 0, true},
{"t5.2", int8(0), true},
{"t5.3", int16(0), true},
{"t5.4", int32(0), true},
{"t5.5", int64(0), true},
{"t5.6", 1, false},
{"t5.7", int8(1), false},
{"t5.8", int16(1), false},
{"t5.9", int32(1), false},
{"t5.10", int64(1), false},
// uint
{"t6.1", uint(0), true},
{"t6.2", uint8(0), true},
{"t6.3", uint16(0), true},
{"t6.4", uint32(0), true},
{"t6.5", uint64(0), true},
{"t6.6", uint(1), false},
{"t6.7", uint8(1), false},
{"t6.8", uint16(1), false},
{"t6.9", uint32(1), false},
{"t6.10", uint64(1), false},
// float
{"t7.1", float32(0), true},
{"t7.2", float64(0), true},
{"t7.3", float32(1), false},
{"t7.4", float64(1), false},
// interface, ptr
{"t8.1", &s1, true},
{"t8.2", &s2, false},
{"t8.3", s3, true},
// struct
{"t9.1", s4, false},
{"t9.2", &s4, false},
// time.Time
{"t10.1", time1, false},
{"t10.2", &time1, false},
{"t10.3", time2, true},
{"t10.4", &time2, true},
// rune
{"t11.1", 'a', false},
// byte
{"t12.1", []byte(""), true},
{"t12.2", []byte(" "), false},
}
for _, test := range tests {
empty := Empty(test.value)
assert.Equal(t, test.empty, empty, test.tag)
}
}
func TestIsEqual(t *testing.T) {
s1 := "hello"
s2 := s1
s3 := "hello"
t1 := time.Now()
t2 := time.Now().AddDate(0, 0, 1)
type1 := []struct {
username string
}{
{"john"},
}
type2 := []struct {
username string
}{
{"john"},
}
tests := []struct {
tag string
a interface{}
b interface{}
except bool
}{
{"t0", nil, nil, true},
{"t1", nil, "", false},
{"t2", "", "", true},
{"t3", "", " ", false},
{"t4", s1, s2, true},
{"t5", s2, s3, true},
{"t6", t1, t2, false},
{"t7", type1, type2, true},
}
for _, test := range tests {
equal := Equal(test.a, test.b)
assert.Equal(t, test.except, equal, test.tag)
}
}
func TestSafeCharacters(t *testing.T) {
type testCast struct {
String string
Safe bool
}
testCasts := []testCast{
{"", false},
{" ", false},
{"a", true},
{"111", true},
{"", false},
{"A_B", true},
{"A_中B", false},
{"a.b-c_", true},
{"_.a.b-c_", true},
{`\.a.b-c_`, false},
}
for _, tc := range testCasts {
safe := SafeCharacters(tc.String)
if safe != tc.Safe {
t.Errorf("%s except %v, actual%v", tc.String, tc.Safe, safe)
}
}
}
func BenchmarkSafeCharacters(b *testing.B) {
for i := 0; i < b.N; i++ {
SafeCharacters("_.a.b-c_")
}
}
func TestHttpURL(t *testing.T) {
tests := []struct {
tag string
url string
except bool
}{
{"t0", "www.example.com", true},
{"t1", "http://www.example.com", true},
{"t2", "https://www.example.com", true},
{"t3", "https://www.com", true},
{"t4", "https://a", true}, // is valid URL?
{"t5", "https://127.0.0.1", true},
{"t6", "https://", false},
{"t7", "https://a", true},
{"t8", "", false},
{"t9", "aaa", false},
{"t10", "https://www.example.com:8080", true},
{"t11", "//www.example.com:8080", true},
{"t12", "//a.b", true},
}
for _, test := range tests {
equal := HttpURL(test.url)
assert.Equal(t, test.except, equal, test.tag)
}
}
func TestColorHex(t *testing.T) {
tests := []struct {
tag string
color string
except bool
}{
{"t0", "#fff", true},
{"t1", "#ffffff", true},
{"t2", "#000000", true},
{"t3", "#ffff", false},
{"t4", "ffffff", false},
{"t5", "#ggg", false},
{"t6", "#-100000", false},
}
for _, test := range tests {
equal := ColorHex(test.color)
assert.Equal(t, test.except, equal, test.tag)
}
}