forked from p30928647/excelize
Fix #701, init new formula function AND and OR, prevent formula lexer panic on retrieving the top token type
This commit is contained in:
parent
ac3dce0bea
commit
02530e8c8a
298
calc.go
298
calc.go
|
@ -93,21 +93,36 @@ type formulaArg struct {
|
|||
// formulaFuncs is the type of the formula functions.
|
||||
type formulaFuncs struct{}
|
||||
|
||||
// tokenPriority defined basic arithmetic operator priority.
|
||||
var tokenPriority = map[string]int{
|
||||
"^": 5,
|
||||
"*": 4,
|
||||
"/": 4,
|
||||
"+": 3,
|
||||
"-": 3,
|
||||
"=": 2,
|
||||
"<": 2,
|
||||
"<=": 2,
|
||||
">": 2,
|
||||
">=": 2,
|
||||
"&": 1,
|
||||
}
|
||||
|
||||
// CalcCellValue provides a function to get calculated cell value. This
|
||||
// feature is currently in working processing. Array formula, table formula
|
||||
// and some other formulas are not supported currently.
|
||||
//
|
||||
// Supported formulas:
|
||||
//
|
||||
// ABS, ACOS, ACOSH, ACOT, ACOTH, ARABIC, ASIN, ASINH, ATAN2, ATANH, BASE,
|
||||
// CEILING, CEILING.MATH, CEILING.PRECISE, COMBIN, COMBINA, COS, COSH, COT,
|
||||
// COTH, COUNTA, CSC, CSCH, DECIMAL, DEGREES, EVEN, EXP, FACT, FACTDOUBLE,
|
||||
// FLOOR, FLOOR.MATH, FLOOR.PRECISE, GCD, INT, ISBLANK, ISERR, ISERROR,
|
||||
// ISEVEN, ISNA, ISNONTEXT, ISNUMBER, ISO.CEILING, ISODD, LCM, LN, LOG,
|
||||
// LOG10, MDETERM, MEDIAN, MOD, MROUND, MULTINOMIAL, MUNIT, NA, ODD, PI,
|
||||
// POWER, PRODUCT, QUOTIENT, RADIANS, RAND, RANDBETWEEN, ROUND, ROUNDDOWN,
|
||||
// ROUNDUP, SEC, SECH, SIGN, SIN, SINH, SQRT, SQRTPI, SUM, SUMIF, SUMSQ,
|
||||
// TAN, TANH, TRUNC
|
||||
// ABS, ACOS, ACOSH, ACOT, ACOTH, AND, ARABIC, ASIN, ASINH, ATAN2, ATANH,
|
||||
// BASE, CEILING, CEILING.MATH, CEILING.PRECISE, COMBIN, COMBINA, COS,
|
||||
// COSH, COT, COTH, COUNTA, CSC, CSCH, DECIMAL, DEGREES, EVEN, EXP, FACT,
|
||||
// FACTDOUBLE, FLOOR, FLOOR.MATH, FLOOR.PRECISE, GCD, INT, ISBLANK, ISERR,
|
||||
// ISERROR, ISEVEN, ISNA, ISNONTEXT, ISNUMBER, ISO.CEILING, ISODD, LCM,
|
||||
// LN, LOG, LOG10, MDETERM, MEDIAN, MOD, MROUND, MULTINOMIAL, MUNIT, NA,
|
||||
// ODD, OR, PI, POWER, PRODUCT, QUOTIENT, RADIANS, RAND, RANDBETWEEN,
|
||||
// ROUND, ROUNDDOWN, ROUNDUP, SEC, SECH, SIGN, SIN, SINH, SQRT, SQRTPI,
|
||||
// SUM, SUMIF, SUMSQ, TAN, TANH, TRUNC
|
||||
//
|
||||
func (f *File) CalcCellValue(sheet, cell string) (result string, err error) {
|
||||
var (
|
||||
|
@ -131,15 +146,9 @@ func (f *File) CalcCellValue(sheet, cell string) (result string, err error) {
|
|||
|
||||
// getPriority calculate arithmetic operator priority.
|
||||
func getPriority(token efp.Token) (pri int) {
|
||||
var priority = map[string]int{
|
||||
"*": 2,
|
||||
"/": 2,
|
||||
"+": 1,
|
||||
"-": 1,
|
||||
}
|
||||
pri, _ = priority[token.TValue]
|
||||
pri, _ = tokenPriority[token.TValue]
|
||||
if token.TValue == "-" && token.TType == efp.TokenTypeOperatorPrefix {
|
||||
pri = 3
|
||||
pri = 6
|
||||
}
|
||||
if token.TSubType == efp.TokenSubTypeStart && token.TType == efp.TokenTypeSubexpression { // (
|
||||
pri = 0
|
||||
|
@ -306,18 +315,96 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
|
|||
return opdStack.Peek().(efp.Token), err
|
||||
}
|
||||
|
||||
// calcAdd evaluate addition arithmetic operations.
|
||||
func calcAdd(opdStack *Stack) error {
|
||||
if opdStack.Len() < 2 {
|
||||
return errors.New("formula not valid")
|
||||
}
|
||||
rOpd := opdStack.Pop().(efp.Token)
|
||||
lOpd := opdStack.Pop().(efp.Token)
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd.TValue, 64)
|
||||
// calcPow evaluate exponentiation arithmetic operations.
|
||||
func calcPow(rOpd, lOpd string, opdStack *Stack) error {
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd.TValue, 64)
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result := math.Pow(lOpdVal, rOpdVal)
|
||||
opdStack.Push(efp.Token{TValue: fmt.Sprintf("%g", result), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
|
||||
return nil
|
||||
}
|
||||
|
||||
// calcEq evaluate equal arithmetic operations.
|
||||
func calcEq(rOpd, lOpd string, opdStack *Stack) error {
|
||||
opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(rOpd == lOpd)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
|
||||
return nil
|
||||
}
|
||||
|
||||
// calcL evaluate less than arithmetic operations.
|
||||
func calcL(rOpd, lOpd string, opdStack *Stack) error {
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(rOpdVal > lOpdVal)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
|
||||
return nil
|
||||
}
|
||||
|
||||
// calcLe evaluate less than or equal arithmetic operations.
|
||||
func calcLe(rOpd, lOpd string, opdStack *Stack) error {
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(rOpdVal >= lOpdVal)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
|
||||
return nil
|
||||
}
|
||||
|
||||
// calcG evaluate greater than or equal arithmetic operations.
|
||||
func calcG(rOpd, lOpd string, opdStack *Stack) error {
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(rOpdVal < lOpdVal)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
|
||||
return nil
|
||||
}
|
||||
|
||||
// calcGe evaluate greater than or equal arithmetic operations.
|
||||
func calcGe(rOpd, lOpd string, opdStack *Stack) error {
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(rOpdVal <= lOpdVal)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
|
||||
return nil
|
||||
}
|
||||
|
||||
// calcSplice evaluate splice '&' operations.
|
||||
func calcSplice(rOpd, lOpd string, opdStack *Stack) error {
|
||||
opdStack.Push(efp.Token{TValue: lOpd + rOpd, TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
|
||||
return nil
|
||||
}
|
||||
|
||||
// calcAdd evaluate addition arithmetic operations.
|
||||
func calcAdd(rOpd, lOpd string, opdStack *Stack) error {
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -327,17 +414,12 @@ func calcAdd(opdStack *Stack) error {
|
|||
}
|
||||
|
||||
// calcSubtract evaluate subtraction arithmetic operations.
|
||||
func calcSubtract(opdStack *Stack) error {
|
||||
if opdStack.Len() < 2 {
|
||||
return errors.New("formula not valid")
|
||||
}
|
||||
rOpd := opdStack.Pop().(efp.Token)
|
||||
lOpd := opdStack.Pop().(efp.Token)
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd.TValue, 64)
|
||||
func calcSubtract(rOpd, lOpd string, opdStack *Stack) error {
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd.TValue, 64)
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -347,17 +429,12 @@ func calcSubtract(opdStack *Stack) error {
|
|||
}
|
||||
|
||||
// calcMultiply evaluate multiplication arithmetic operations.
|
||||
func calcMultiply(opdStack *Stack) error {
|
||||
if opdStack.Len() < 2 {
|
||||
return errors.New("formula not valid")
|
||||
}
|
||||
rOpd := opdStack.Pop().(efp.Token)
|
||||
lOpd := opdStack.Pop().(efp.Token)
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd.TValue, 64)
|
||||
func calcMultiply(rOpd, lOpd string, opdStack *Stack) error {
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd.TValue, 64)
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -366,18 +443,13 @@ func calcMultiply(opdStack *Stack) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// calcDivide evaluate division arithmetic operations.
|
||||
func calcDivide(opdStack *Stack) error {
|
||||
if opdStack.Len() < 2 {
|
||||
return errors.New("formula not valid")
|
||||
}
|
||||
rOpd := opdStack.Pop().(efp.Token)
|
||||
lOpd := opdStack.Pop().(efp.Token)
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd.TValue, 64)
|
||||
// calcDiv evaluate division arithmetic operations.
|
||||
func calcDiv(rOpd, lOpd string, opdStack *Stack) error {
|
||||
lOpdVal, err := strconv.ParseFloat(lOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd.TValue, 64)
|
||||
rOpdVal, err := strconv.ParseFloat(rOpd, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -403,24 +475,36 @@ func calculate(opdStack *Stack, opt efp.Token) error {
|
|||
result := 0 - opdVal
|
||||
opdStack.Push(efp.Token{TValue: fmt.Sprintf("%g", result), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
|
||||
}
|
||||
|
||||
if opt.TValue == "+" {
|
||||
if err := calcAdd(opdStack); err != nil {
|
||||
return err
|
||||
}
|
||||
tokenCalcFunc := map[string]func(rOpd, lOpd string, opdStack *Stack) error{
|
||||
"^": calcPow,
|
||||
"*": calcMultiply,
|
||||
"/": calcDiv,
|
||||
"+": calcAdd,
|
||||
"=": calcEq,
|
||||
"<": calcL,
|
||||
"<=": calcLe,
|
||||
">": calcG,
|
||||
">=": calcGe,
|
||||
"&": calcSplice,
|
||||
}
|
||||
if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorInfix {
|
||||
if err := calcSubtract(opdStack); err != nil {
|
||||
if opdStack.Len() < 2 {
|
||||
return errors.New("formula not valid")
|
||||
}
|
||||
rOpd := opdStack.Pop().(efp.Token)
|
||||
lOpd := opdStack.Pop().(efp.Token)
|
||||
if err := calcSubtract(rOpd.TValue, lOpd.TValue, opdStack); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if opt.TValue == "*" {
|
||||
if err := calcMultiply(opdStack); err != nil {
|
||||
return err
|
||||
fn, ok := tokenCalcFunc[opt.TValue]
|
||||
if ok {
|
||||
if opdStack.Len() < 2 {
|
||||
return errors.New("formula not valid")
|
||||
}
|
||||
}
|
||||
if opt.TValue == "/" {
|
||||
if err := calcDivide(opdStack); err != nil {
|
||||
rOpd := opdStack.Pop().(efp.Token)
|
||||
lOpd := opdStack.Pop().(efp.Token)
|
||||
if err := fn(rOpd.TValue, lOpd.TValue, opdStack); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -459,8 +543,8 @@ func (f *File) parseOperatorPrefixToken(optStack, opdStack *Stack, token efp.Tok
|
|||
// isOperatorPrefixToken determine if the token is parse operator prefix
|
||||
// token.
|
||||
func isOperatorPrefixToken(token efp.Token) bool {
|
||||
if (token.TValue == "-" && token.TType == efp.TokenTypeOperatorPrefix) ||
|
||||
token.TValue == "+" || token.TValue == "-" || token.TValue == "*" || token.TValue == "/" {
|
||||
_, ok := tokenPriority[token.TValue]
|
||||
if (token.TValue == "-" && token.TType == efp.TokenTypeOperatorPrefix) || ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -3140,3 +3224,87 @@ func (fn *formulaFuncs) NA(argsList *list.List) (result string, err error) {
|
|||
result = formulaErrorNA
|
||||
return
|
||||
}
|
||||
|
||||
// Logical Functions
|
||||
|
||||
// AND function tests a number of supplied conditions and returns TRUE or
|
||||
// FALSE.
|
||||
func (fn *formulaFuncs) AND(argsList *list.List) (result string, err error) {
|
||||
if argsList.Len() == 0 {
|
||||
err = errors.New("AND requires at least 1 argument")
|
||||
return
|
||||
}
|
||||
if argsList.Len() > 30 {
|
||||
err = errors.New("AND accepts at most 30 arguments")
|
||||
return
|
||||
}
|
||||
var and = true
|
||||
var val float64
|
||||
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
|
||||
token := arg.Value.(formulaArg)
|
||||
switch token.Type {
|
||||
case ArgUnknown:
|
||||
continue
|
||||
case ArgString:
|
||||
if token.String == "TRUE" {
|
||||
continue
|
||||
}
|
||||
if token.String == "FALSE" {
|
||||
result = token.String
|
||||
return
|
||||
}
|
||||
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
|
||||
err = errors.New(formulaErrorVALUE)
|
||||
return
|
||||
}
|
||||
and = and && (val != 0)
|
||||
case ArgMatrix:
|
||||
// TODO
|
||||
err = errors.New(formulaErrorVALUE)
|
||||
return
|
||||
}
|
||||
}
|
||||
result = strings.ToUpper(strconv.FormatBool(and))
|
||||
return
|
||||
}
|
||||
|
||||
// OR function tests a number of supplied conditions and returns either TRUE
|
||||
// or FALSE.
|
||||
func (fn *formulaFuncs) OR(argsList *list.List) (result string, err error) {
|
||||
if argsList.Len() == 0 {
|
||||
err = errors.New("OR requires at least 1 argument")
|
||||
return
|
||||
}
|
||||
if argsList.Len() > 30 {
|
||||
err = errors.New("OR accepts at most 30 arguments")
|
||||
return
|
||||
}
|
||||
var or bool
|
||||
var val float64
|
||||
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
|
||||
token := arg.Value.(formulaArg)
|
||||
switch token.Type {
|
||||
case ArgUnknown:
|
||||
continue
|
||||
case ArgString:
|
||||
if token.String == "FALSE" {
|
||||
continue
|
||||
}
|
||||
if token.String == "TRUE" {
|
||||
or = true
|
||||
continue
|
||||
}
|
||||
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
|
||||
err = errors.New(formulaErrorVALUE)
|
||||
return
|
||||
}
|
||||
or = val != 0
|
||||
case ArgMatrix:
|
||||
// TODO
|
||||
err = errors.New(formulaErrorVALUE)
|
||||
return
|
||||
}
|
||||
}
|
||||
result = strings.ToUpper(strconv.FormatBool(or))
|
||||
return
|
||||
}
|
||||
|
|
95
calc_test.go
95
calc_test.go
|
@ -1,7 +1,9 @@
|
|||
package excelize
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -31,6 +33,18 @@ func TestCalcCellValue(t *testing.T) {
|
|||
}
|
||||
|
||||
mathCalc := map[string]string{
|
||||
"=2^3": "8",
|
||||
"=1=1": "TRUE",
|
||||
"=1=2": "FALSE",
|
||||
"=1<2": "TRUE",
|
||||
"=3<2": "FALSE",
|
||||
"=2<=3": "TRUE",
|
||||
"=2<=1": "FALSE",
|
||||
"=2>1": "TRUE",
|
||||
"=2>3": "FALSE",
|
||||
"=2>=1": "TRUE",
|
||||
"=2>=3": "FALSE",
|
||||
"=1&2": "12",
|
||||
// ABS
|
||||
"=ABS(-1)": "1",
|
||||
"=ABS(-6.5)": "6.5",
|
||||
|
@ -429,6 +443,20 @@ func TestCalcCellValue(t *testing.T) {
|
|||
"=ISODD(A2)": "FALSE",
|
||||
// NA
|
||||
"=NA()": "#N/A",
|
||||
// AND
|
||||
"=AND(0)": "FALSE",
|
||||
"=AND(1)": "TRUE",
|
||||
"=AND(1,0)": "FALSE",
|
||||
"=AND(0,1)": "FALSE",
|
||||
"=AND(1=1)": "TRUE",
|
||||
"=AND(1<2)": "TRUE",
|
||||
"=AND(1>2,2<3,2>0,3>1)": "FALSE",
|
||||
"=AND(1=1),1=1": "TRUE",
|
||||
// OR
|
||||
"=OR(1)": "TRUE",
|
||||
"=OR(0)": "FALSE",
|
||||
"=OR(1=2,2=2)": "TRUE",
|
||||
"=OR(1=2,2=3)": "FALSE",
|
||||
}
|
||||
for formula, expected := range mathCalc {
|
||||
f := prepareData()
|
||||
|
@ -728,6 +756,16 @@ func TestCalcCellValue(t *testing.T) {
|
|||
`=ISODD("text")`: "#VALUE!",
|
||||
// NA
|
||||
"=NA(1)": "NA accepts no arguments",
|
||||
// AND
|
||||
`=AND("text")`: "#VALUE!",
|
||||
`=AND(A1:B1)`: "#VALUE!",
|
||||
"=AND()": "AND requires at least 1 argument",
|
||||
"=AND(1" + strings.Repeat(",1", 30) + ")": "AND accepts at most 30 arguments",
|
||||
// OR
|
||||
`=OR("text")`: "#VALUE!",
|
||||
`=OR(A1:B1)`: "#VALUE!",
|
||||
"=OR()": "OR requires at least 1 argument",
|
||||
"=OR(1" + strings.Repeat(",1", 30) + ")": "OR accepts at most 30 arguments",
|
||||
}
|
||||
for formula, expected := range mathCalcError {
|
||||
f := prepareData()
|
||||
|
@ -829,6 +867,63 @@ func TestCalcCellValueWithDefinedName(t *testing.T) {
|
|||
assert.Equal(t, "B1 value", result, "=defined_name1")
|
||||
}
|
||||
|
||||
func TestCalcPow(t *testing.T) {
|
||||
err := `strconv.ParseFloat: parsing "text": invalid syntax`
|
||||
assert.EqualError(t, calcPow("1", "text", nil), err)
|
||||
assert.EqualError(t, calcPow("text", "1", nil), err)
|
||||
assert.EqualError(t, calcL("1", "text", nil), err)
|
||||
assert.EqualError(t, calcL("text", "1", nil), err)
|
||||
assert.EqualError(t, calcLe("1", "text", nil), err)
|
||||
assert.EqualError(t, calcLe("text", "1", nil), err)
|
||||
assert.EqualError(t, calcG("1", "text", nil), err)
|
||||
assert.EqualError(t, calcG("text", "1", nil), err)
|
||||
assert.EqualError(t, calcGe("1", "text", nil), err)
|
||||
assert.EqualError(t, calcGe("text", "1", nil), err)
|
||||
assert.EqualError(t, calcAdd("1", "text", nil), err)
|
||||
assert.EqualError(t, calcAdd("text", "1", nil), err)
|
||||
assert.EqualError(t, calcAdd("1", "text", nil), err)
|
||||
assert.EqualError(t, calcAdd("text", "1", nil), err)
|
||||
assert.EqualError(t, calcSubtract("1", "text", nil), err)
|
||||
assert.EqualError(t, calcSubtract("text", "1", nil), err)
|
||||
assert.EqualError(t, calcMultiply("1", "text", nil), err)
|
||||
assert.EqualError(t, calcMultiply("text", "1", nil), err)
|
||||
assert.EqualError(t, calcDiv("1", "text", nil), err)
|
||||
assert.EqualError(t, calcDiv("text", "1", nil), err)
|
||||
}
|
||||
|
||||
func TestISBLANK(t *testing.T) {
|
||||
argsList := list.New()
|
||||
argsList.PushBack(formulaArg{
|
||||
Type: ArgUnknown,
|
||||
})
|
||||
fn := formulaFuncs{}
|
||||
result, err := fn.ISBLANK(argsList)
|
||||
assert.Equal(t, result, "TRUE")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestAND(t *testing.T) {
|
||||
argsList := list.New()
|
||||
argsList.PushBack(formulaArg{
|
||||
Type: ArgUnknown,
|
||||
})
|
||||
fn := formulaFuncs{}
|
||||
result, err := fn.AND(argsList)
|
||||
assert.Equal(t, result, "TRUE")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestOR(t *testing.T) {
|
||||
argsList := list.New()
|
||||
argsList.PushBack(formulaArg{
|
||||
Type: ArgUnknown,
|
||||
})
|
||||
fn := formulaFuncs{}
|
||||
result, err := fn.OR(argsList)
|
||||
assert.Equal(t, result, "FALSE")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDet(t *testing.T) {
|
||||
assert.Equal(t, det([][]float64{
|
||||
{1, 2, 3, 4},
|
||||
|
|
8
go.mod
8
go.mod
|
@ -5,10 +5,8 @@ go 1.11
|
|||
require (
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/richardlehane/mscfb v1.0.3
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/xuri/efp v0.0.0-20200605144744-ba689101faaf
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
||||
golang.org/x/image v0.0.0-20200922025426-e59bae62ef32
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73
|
||||
github.com/xuri/efp v0.0.0-20201016154823-031c29024257
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee
|
||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0
|
||||
golang.org/x/text v0.3.3
|
||||
)
|
||||
|
|
27
go.sum
27
go.sum
|
@ -1,35 +1,22 @@
|
|||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj3nKI=
|
||||
github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
|
||||
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
|
||||
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/xuri/efp v0.0.0-20200605144744-ba689101faaf h1:spotWVWg9DP470pPFQ7LaYtUqDpWEOS/BUrSmwFZE4k=
|
||||
github.com/xuri/efp v0.0.0-20200605144744-ba689101faaf/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk=
|
||||
github.com/xuri/efp v0.0.0-20201016154823-031c29024257 h1:6ldmGEJXtsRMwdR2KuS3esk9wjVJNvgk05/YY2XmOj0=
|
||||
github.com/xuri/efp v0.0.0-20201016154823-031c29024257/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/image v0.0.0-20200922025426-e59bae62ef32 h1:E+SEVulmY8U4+i6vSB88YSc2OKAFfvbHPU/uDTdQu7M=
|
||||
golang.org/x/image v0.0.0-20200922025426-e59bae62ef32/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0 h1:5kGOVHlq0euqwzgTC9Vu15p6fV1Wi0ArVi8da2urnVg=
|
||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
Loading…
Reference in New Issue