forked from p30928647/excelize
init new formula function: VLOOKUP
This commit is contained in:
parent
1f329e8f96
commit
66d85dae13
256
calc.go
256
calc.go
|
@ -74,6 +74,7 @@ const (
|
||||||
criteriaG
|
criteriaG
|
||||||
criteriaBeg
|
criteriaBeg
|
||||||
criteriaEnd
|
criteriaEnd
|
||||||
|
criteriaErr
|
||||||
)
|
)
|
||||||
|
|
||||||
// formulaCriteria defined formula criteria parser result.
|
// formulaCriteria defined formula criteria parser result.
|
||||||
|
@ -142,6 +143,24 @@ func (fa formulaArg) ToNumber() formulaArg {
|
||||||
return newNumberFormulaArg(n)
|
return newNumberFormulaArg(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToBool returns a formula argument with boolean data type.
|
||||||
|
func (fa formulaArg) ToBool() formulaArg {
|
||||||
|
var b bool
|
||||||
|
var err error
|
||||||
|
switch fa.Type {
|
||||||
|
case ArgString:
|
||||||
|
b, err = strconv.ParseBool(fa.String)
|
||||||
|
if err != nil {
|
||||||
|
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
|
||||||
|
}
|
||||||
|
case ArgNumber:
|
||||||
|
if fa.Boolean && fa.Number == 1 {
|
||||||
|
b = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newBoolFormulaArg(b)
|
||||||
|
}
|
||||||
|
|
||||||
// formulaFuncs is the type of the formula functions.
|
// formulaFuncs is the type of the formula functions.
|
||||||
type formulaFuncs struct{}
|
type formulaFuncs struct{}
|
||||||
|
|
||||||
|
@ -312,6 +331,11 @@ func newMatrixFormulaArg(m [][]formulaArg) formulaArg {
|
||||||
return formulaArg{Type: ArgMatrix, Matrix: m}
|
return formulaArg{Type: ArgMatrix, Matrix: m}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newListFormulaArg create a list formula argument.
|
||||||
|
func newListFormulaArg(l []formulaArg) formulaArg {
|
||||||
|
return formulaArg{Type: ArgList, List: l}
|
||||||
|
}
|
||||||
|
|
||||||
// newBoolFormulaArg constructs a boolean formula argument.
|
// newBoolFormulaArg constructs a boolean formula argument.
|
||||||
func newBoolFormulaArg(b bool) formulaArg {
|
func newBoolFormulaArg(b bool) formulaArg {
|
||||||
var n float64
|
var n float64
|
||||||
|
@ -321,11 +345,17 @@ func newBoolFormulaArg(b bool) formulaArg {
|
||||||
return formulaArg{Type: ArgNumber, Number: n, Boolean: true}
|
return formulaArg{Type: ArgNumber, Number: n, Boolean: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
// newErrorFormulaArg create an error formula argument of a given type with a specified error message.
|
// newErrorFormulaArg create an error formula argument of a given type with a
|
||||||
|
// specified error message.
|
||||||
func newErrorFormulaArg(formulaError, msg string) formulaArg {
|
func newErrorFormulaArg(formulaError, msg string) formulaArg {
|
||||||
return formulaArg{Type: ArgError, String: formulaError, Error: msg}
|
return formulaArg{Type: ArgError, String: formulaError, Error: msg}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newEmptyFormulaArg create an empty formula argument.
|
||||||
|
func newEmptyFormulaArg() formulaArg {
|
||||||
|
return formulaArg{Type: ArgEmpty}
|
||||||
|
}
|
||||||
|
|
||||||
// evalInfixExp evaluate syntax analysis by given infix expression after
|
// evalInfixExp evaluate syntax analysis by given infix expression after
|
||||||
// lexical analysis. Evaluate an infix expression containing formulas by
|
// lexical analysis. Evaluate an infix expression containing formulas by
|
||||||
// stacks:
|
// stacks:
|
||||||
|
@ -428,6 +458,12 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
|
||||||
// current token is logical
|
// current token is logical
|
||||||
if token.TType == efp.OperatorsInfix && token.TSubType == efp.TokenSubTypeLogical {
|
if token.TType == efp.OperatorsInfix && token.TSubType == efp.TokenSubTypeLogical {
|
||||||
}
|
}
|
||||||
|
if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeLogical {
|
||||||
|
argsStack.Peek().(*list.List).PushBack(formulaArg{
|
||||||
|
String: token.TValue,
|
||||||
|
Type: ArgString,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// current token is text
|
// current token is text
|
||||||
if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeText {
|
if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeText {
|
||||||
|
@ -841,6 +877,15 @@ func (f *File) parseReference(sheet, reference string) (arg formulaArg, err erro
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if cr.Col, cr.Row, err = CellNameToCoordinates(tokens[0]); err != nil {
|
if cr.Col, cr.Row, err = CellNameToCoordinates(tokens[0]); err != nil {
|
||||||
|
if cr.Col, err = ColumnNameToNumber(tokens[0]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cellRanges.PushBack(cellRange{
|
||||||
|
From: cellRef{Sheet: sheet, Col: cr.Col, Row: 1},
|
||||||
|
To: cellRef{Sheet: sheet, Col: cr.Col, Row: TotalRows},
|
||||||
|
})
|
||||||
|
cellRefs.Init()
|
||||||
|
arg, err = f.rangeResolver(cellRefs, cellRanges)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e := refs.Back()
|
e := refs.Back()
|
||||||
|
@ -3189,14 +3234,13 @@ func (fn *formulaFuncs) ISNUMBER(argsList *list.List) formulaArg {
|
||||||
if argsList.Len() != 1 {
|
if argsList.Len() != 1 {
|
||||||
return newErrorFormulaArg(formulaErrorVALUE, "ISNUMBER requires 1 argument")
|
return newErrorFormulaArg(formulaErrorVALUE, "ISNUMBER requires 1 argument")
|
||||||
}
|
}
|
||||||
token := argsList.Front().Value.(formulaArg)
|
token, result := argsList.Front().Value.(formulaArg), false
|
||||||
result := "FALSE"
|
|
||||||
if token.Type == ArgString && token.String != "" {
|
if token.Type == ArgString && token.String != "" {
|
||||||
if _, err := strconv.Atoi(token.String); err == nil {
|
if _, err := strconv.Atoi(token.String); err == nil {
|
||||||
result = "TRUE"
|
result = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newStringFormulaArg(result)
|
return newBoolFormulaArg(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ISODD function tests if a supplied number (or numeric expression) evaluates
|
// ISODD function tests if a supplied number (or numeric expression) evaluates
|
||||||
|
@ -3529,3 +3573,205 @@ func (fn *formulaFuncs) CHOOSE(argsList *list.List) formulaArg {
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deepMatchRune finds whether the text deep matches/satisfies the pattern
|
||||||
|
// string.
|
||||||
|
func deepMatchRune(str, pattern []rune, simple bool) bool {
|
||||||
|
for len(pattern) > 0 {
|
||||||
|
switch pattern[0] {
|
||||||
|
default:
|
||||||
|
if len(str) == 0 || str[0] != pattern[0] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case '?':
|
||||||
|
if len(str) == 0 && !simple {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case '*':
|
||||||
|
return deepMatchRune(str, pattern[1:], simple) ||
|
||||||
|
(len(str) > 0 && deepMatchRune(str[1:], pattern, simple))
|
||||||
|
}
|
||||||
|
str = str[1:]
|
||||||
|
pattern = pattern[1:]
|
||||||
|
}
|
||||||
|
return len(str) == 0 && len(pattern) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchPattern finds whether the text matches or satisfies the pattern
|
||||||
|
// string. The pattern supports '*' and '?' wildcards in the pattern string.
|
||||||
|
func matchPattern(pattern, name string) (matched bool) {
|
||||||
|
if pattern == "" {
|
||||||
|
return name == pattern
|
||||||
|
}
|
||||||
|
if pattern == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
rname := make([]rune, 0, len(name))
|
||||||
|
rpattern := make([]rune, 0, len(pattern))
|
||||||
|
for _, r := range name {
|
||||||
|
rname = append(rname, r)
|
||||||
|
}
|
||||||
|
for _, r := range pattern {
|
||||||
|
rpattern = append(rpattern, r)
|
||||||
|
}
|
||||||
|
simple := false // Does extended wildcard '*' and '?' match.
|
||||||
|
return deepMatchRune(rname, rpattern, simple)
|
||||||
|
}
|
||||||
|
|
||||||
|
// compareFormulaArg compares the left-hand sides and the right-hand sides
|
||||||
|
// formula arguments by given conditions such as case sensitive, if exact
|
||||||
|
// match, and make compare result as formula criteria condition type.
|
||||||
|
func compareFormulaArg(lhs, rhs formulaArg, caseSensitive, exactMatch bool) byte {
|
||||||
|
if lhs.Type != rhs.Type {
|
||||||
|
return criteriaErr
|
||||||
|
}
|
||||||
|
switch lhs.Type {
|
||||||
|
case ArgNumber:
|
||||||
|
if lhs.Number == rhs.Number {
|
||||||
|
return criteriaEq
|
||||||
|
}
|
||||||
|
if lhs.Number < rhs.Number {
|
||||||
|
return criteriaL
|
||||||
|
}
|
||||||
|
return criteriaG
|
||||||
|
case ArgString:
|
||||||
|
ls := lhs.String
|
||||||
|
rs := rhs.String
|
||||||
|
if !caseSensitive {
|
||||||
|
ls = strings.ToLower(ls)
|
||||||
|
rs = strings.ToLower(rs)
|
||||||
|
}
|
||||||
|
if exactMatch {
|
||||||
|
match := matchPattern(rs, ls)
|
||||||
|
if match {
|
||||||
|
return criteriaEq
|
||||||
|
}
|
||||||
|
return criteriaG
|
||||||
|
}
|
||||||
|
return byte(strings.Compare(ls, rs))
|
||||||
|
case ArgEmpty:
|
||||||
|
return criteriaEq
|
||||||
|
case ArgList:
|
||||||
|
return compareFormulaArgList(lhs, rhs, caseSensitive, exactMatch)
|
||||||
|
case ArgMatrix:
|
||||||
|
return compareFormulaArgMatrix(lhs, rhs, caseSensitive, exactMatch)
|
||||||
|
}
|
||||||
|
return criteriaErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// compareFormulaArgList compares the left-hand sides and the right-hand sides
|
||||||
|
// list type formula arguments.
|
||||||
|
func compareFormulaArgList(lhs, rhs formulaArg, caseSensitive, exactMatch bool) byte {
|
||||||
|
if len(lhs.List) < len(rhs.List) {
|
||||||
|
return criteriaL
|
||||||
|
}
|
||||||
|
if len(lhs.List) > len(rhs.List) {
|
||||||
|
return criteriaG
|
||||||
|
}
|
||||||
|
for arg := range lhs.List {
|
||||||
|
criteria := compareFormulaArg(lhs.List[arg], rhs.List[arg], caseSensitive, exactMatch)
|
||||||
|
if criteria != criteriaEq {
|
||||||
|
return criteria
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return criteriaEq
|
||||||
|
}
|
||||||
|
|
||||||
|
// compareFormulaArgMatrix compares the left-hand sides and the right-hand sides
|
||||||
|
// matrix type formula arguments.
|
||||||
|
func compareFormulaArgMatrix(lhs, rhs formulaArg, caseSensitive, exactMatch bool) byte {
|
||||||
|
if len(lhs.Matrix) < len(rhs.Matrix) {
|
||||||
|
return criteriaL
|
||||||
|
}
|
||||||
|
if len(lhs.Matrix) > len(rhs.Matrix) {
|
||||||
|
return criteriaG
|
||||||
|
}
|
||||||
|
for i := range lhs.Matrix {
|
||||||
|
left := lhs.Matrix[i]
|
||||||
|
right := lhs.Matrix[i]
|
||||||
|
if len(left) < len(right) {
|
||||||
|
return criteriaL
|
||||||
|
}
|
||||||
|
if len(left) > len(right) {
|
||||||
|
return criteriaG
|
||||||
|
}
|
||||||
|
for arg := range left {
|
||||||
|
criteria := compareFormulaArg(left[arg], right[arg], caseSensitive, exactMatch)
|
||||||
|
if criteria != criteriaEq {
|
||||||
|
return criteria
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return criteriaEq
|
||||||
|
}
|
||||||
|
|
||||||
|
// VLOOKUP function 'looks up' a given value in the left-hand column of a
|
||||||
|
// data array (or table), and returns the corresponding value from another
|
||||||
|
// column of the array. The syntax of the function is:
|
||||||
|
//
|
||||||
|
// VLOOKUP(lookup_value,table_array,col_index_num,[range_lookup])
|
||||||
|
//
|
||||||
|
func (fn *formulaFuncs) VLOOKUP(argsList *list.List) formulaArg {
|
||||||
|
if argsList.Len() < 3 {
|
||||||
|
return newErrorFormulaArg(formulaErrorVALUE, "VLOOKUP requires at least 3 arguments")
|
||||||
|
}
|
||||||
|
if argsList.Len() > 4 {
|
||||||
|
return newErrorFormulaArg(formulaErrorVALUE, "VLOOKUP requires at most 4 arguments")
|
||||||
|
}
|
||||||
|
lookupValue := argsList.Front().Value.(formulaArg)
|
||||||
|
tableArray := argsList.Front().Next().Value.(formulaArg)
|
||||||
|
if tableArray.Type != ArgMatrix {
|
||||||
|
return newErrorFormulaArg(formulaErrorVALUE, "VLOOKUP requires second argument of table array")
|
||||||
|
}
|
||||||
|
colIdx := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
|
||||||
|
if colIdx.Type != ArgNumber {
|
||||||
|
return newErrorFormulaArg(formulaErrorVALUE, "VLOOKUP requires numeric col argument")
|
||||||
|
}
|
||||||
|
col, matchIdx, wasExact, exactMatch := int(colIdx.Number)-1, -1, false, false
|
||||||
|
if argsList.Len() == 4 {
|
||||||
|
rangeLookup := argsList.Back().Value.(formulaArg).ToBool()
|
||||||
|
if rangeLookup.Type == ArgError {
|
||||||
|
return newErrorFormulaArg(formulaErrorVALUE, rangeLookup.Error)
|
||||||
|
}
|
||||||
|
if rangeLookup.Number == 0 {
|
||||||
|
exactMatch = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start:
|
||||||
|
for idx, mtx := range tableArray.Matrix {
|
||||||
|
if len(mtx) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lhs := mtx[0]
|
||||||
|
switch lookupValue.Type {
|
||||||
|
case ArgNumber:
|
||||||
|
if !lookupValue.Boolean {
|
||||||
|
lhs = mtx[0].ToNumber()
|
||||||
|
if lhs.Type == ArgError {
|
||||||
|
lhs = mtx[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ArgMatrix:
|
||||||
|
lhs = tableArray
|
||||||
|
}
|
||||||
|
switch compareFormulaArg(lhs, lookupValue, false, exactMatch) {
|
||||||
|
case criteriaL:
|
||||||
|
matchIdx = idx
|
||||||
|
case criteriaEq:
|
||||||
|
matchIdx = idx
|
||||||
|
wasExact = true
|
||||||
|
break start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if matchIdx == -1 {
|
||||||
|
return newErrorFormulaArg(formulaErrorNA, "VLOOKUP no result found")
|
||||||
|
}
|
||||||
|
mtx := tableArray.Matrix[matchIdx]
|
||||||
|
if col < 0 || col >= len(mtx) {
|
||||||
|
return newErrorFormulaArg(formulaErrorNA, "VLOOKUP has invalid column index")
|
||||||
|
}
|
||||||
|
if wasExact || !exactMatch {
|
||||||
|
return mtx[col]
|
||||||
|
}
|
||||||
|
return newErrorFormulaArg(formulaErrorNA, "VLOOKUP no result found")
|
||||||
|
}
|
||||||
|
|
45
calc_test.go
45
calc_test.go
|
@ -560,19 +560,26 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=CHOOSE(4,\"red\",\"blue\",\"green\",\"brown\")": "brown",
|
"=CHOOSE(4,\"red\",\"blue\",\"green\",\"brown\")": "brown",
|
||||||
"=CHOOSE(1,\"red\",\"blue\",\"green\",\"brown\")": "red",
|
"=CHOOSE(1,\"red\",\"blue\",\"green\",\"brown\")": "red",
|
||||||
"=SUM(CHOOSE(A2,A1,B1:B2,A1:A3,A1:A4))": "9",
|
"=SUM(CHOOSE(A2,A1,B1:B2,A1:A3,A1:A4))": "9",
|
||||||
|
// VLOOKUP
|
||||||
|
"=VLOOKUP(D2,D:D,1,FALSE)": "Jan",
|
||||||
|
"=VLOOKUP(D2,D:D,1,TRUE)": "Month", // should be Feb
|
||||||
|
"=VLOOKUP(INT(36693),F2:F2,1,FALSE)": "36693",
|
||||||
|
"=VLOOKUP(INT(F2),F3:F9,1)": "32080",
|
||||||
|
"=VLOOKUP(MUNIT(3),MUNIT(2),1)": "0", // should be 1
|
||||||
|
"=VLOOKUP(MUNIT(3),MUNIT(3),1)": "1",
|
||||||
}
|
}
|
||||||
for formula, expected := range mathCalc {
|
for formula, expected := range mathCalc {
|
||||||
f := prepareData()
|
f := prepareData()
|
||||||
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
|
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
|
||||||
result, err := f.CalcCellValue("Sheet1", "C1")
|
result, err := f.CalcCellValue("Sheet1", "C1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err, formula)
|
||||||
assert.Equal(t, expected, result, formula)
|
assert.Equal(t, expected, result, formula)
|
||||||
}
|
}
|
||||||
mathCalcError := map[string]string{
|
mathCalcError := map[string]string{
|
||||||
// ABS
|
// ABS
|
||||||
"=ABS()": "ABS requires 1 numeric argument",
|
"=ABS()": "ABS requires 1 numeric argument",
|
||||||
`=ABS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
|
`=ABS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
|
||||||
"=ABS(~)": `cannot convert cell "~" to coordinates: invalid cell name "~"`,
|
"=ABS(~)": `invalid column name "~"`,
|
||||||
// ACOS
|
// ACOS
|
||||||
"=ACOS()": "ACOS requires 1 numeric argument",
|
"=ACOS()": "ACOS requires 1 numeric argument",
|
||||||
`=ACOS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
|
`=ACOS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
|
||||||
|
@ -907,6 +914,19 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=CHOOSE()": "CHOOSE requires 2 arguments",
|
"=CHOOSE()": "CHOOSE requires 2 arguments",
|
||||||
"=CHOOSE(\"index_num\",0)": "CHOOSE requires first argument of type number",
|
"=CHOOSE(\"index_num\",0)": "CHOOSE requires first argument of type number",
|
||||||
"=CHOOSE(2,0)": "index_num should be <= to the number of values",
|
"=CHOOSE(2,0)": "index_num should be <= to the number of values",
|
||||||
|
// VLOOKUP
|
||||||
|
"=VLOOKUP()": "VLOOKUP requires at least 3 arguments",
|
||||||
|
"=VLOOKUP(D2,D1,1,FALSE)": "VLOOKUP requires second argument of table array",
|
||||||
|
"=VLOOKUP(D2,D:D,FALSE,FALSE)": "VLOOKUP requires numeric col argument",
|
||||||
|
"=VLOOKUP(D2,D:D,1,FALSE,FALSE)": "VLOOKUP requires at most 4 arguments",
|
||||||
|
"=VLOOKUP(D2,D:D,1,2)": "strconv.ParseBool: parsing \"2\": invalid syntax",
|
||||||
|
"=VLOOKUP(D2,D10:D10,1,FALSE)": "VLOOKUP no result found",
|
||||||
|
"=VLOOKUP(D2,D:D,2,FALSE)": "VLOOKUP has invalid column index",
|
||||||
|
"=VLOOKUP(D2,C:C,1,FALSE)": "VLOOKUP no result found",
|
||||||
|
"=VLOOKUP(ISNUMBER(1),F3:F9,1)": "VLOOKUP no result found",
|
||||||
|
"=VLOOKUP(INT(1),E2:E9,1)": "VLOOKUP no result found",
|
||||||
|
"=VLOOKUP(MUNIT(2),MUNIT(3),1)": "VLOOKUP no result found",
|
||||||
|
"=VLOOKUP(A1:B2,B2:B3,1)": "VLOOKUP no result found",
|
||||||
}
|
}
|
||||||
for formula, expected := range mathCalcError {
|
for formula, expected := range mathCalcError {
|
||||||
f := prepareData()
|
f := prepareData()
|
||||||
|
@ -1085,3 +1105,24 @@ func TestDet(t *testing.T) {
|
||||||
{4, 5, 6, 7},
|
{4, 5, 6, 7},
|
||||||
}), float64(0))
|
}), float64(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompareFormulaArg(t *testing.T) {
|
||||||
|
assert.Equal(t, compareFormulaArg(newEmptyFormulaArg(), newEmptyFormulaArg(), false, false), criteriaEq)
|
||||||
|
lhs := newListFormulaArg([]formulaArg{newEmptyFormulaArg()})
|
||||||
|
rhs := newListFormulaArg([]formulaArg{newEmptyFormulaArg(), newEmptyFormulaArg()})
|
||||||
|
assert.Equal(t, compareFormulaArg(lhs, rhs, false, false), criteriaL)
|
||||||
|
assert.Equal(t, compareFormulaArg(rhs, lhs, false, false), criteriaG)
|
||||||
|
|
||||||
|
lhs = newListFormulaArg([]formulaArg{newBoolFormulaArg(true)})
|
||||||
|
rhs = newListFormulaArg([]formulaArg{newBoolFormulaArg(true)})
|
||||||
|
assert.Equal(t, compareFormulaArg(lhs, rhs, false, false), criteriaEq)
|
||||||
|
|
||||||
|
assert.Equal(t, compareFormulaArg(formulaArg{Type: ArgUnknown}, formulaArg{Type: ArgUnknown}, false, false), criteriaErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMatchPattern(t *testing.T) {
|
||||||
|
assert.True(t, matchPattern("", ""))
|
||||||
|
assert.True(t, matchPattern("file/*", "file/abc/bcd/def"))
|
||||||
|
assert.True(t, matchPattern("*", ""))
|
||||||
|
assert.False(t, matchPattern("file/?", "file/abc/bcd/def"))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue