浏览代码

refactor formula calculation framework, add new function CHOOSE, and update dependencies module

xuri 4 年之前
父节点
当前提交
dd77cfe44c
共有 4 个文件被更改,包括 447 次插入411 次删除
  1. 312 287
      calc.go
  2. 118 109
      calc_test.go
  3. 4 4
      go.mod
  4. 13 11
      go.sum

文件差异内容过多而无法显示
+ 312 - 287
calc.go


+ 118 - 109
calc_test.go

@@ -494,6 +494,10 @@ func TestCalcCellValue(t *testing.T) {
 		"=IF(1<>1)":                             "FALSE",
 		"=IF(5<0, \"negative\", \"positive\")":  "positive",
 		"=IF(-2<0, \"negative\", \"positive\")": "negative",
+		// Excel Lookup and Reference Functions
+		// CHOOSE
+		"=CHOOSE(4,\"red\",\"blue\",\"green\",\"brown\")": "brown",
+		"=CHOOSE(1,\"red\",\"blue\",\"green\",\"brown\")": "red",
 	}
 	for formula, expected := range mathCalc {
 		f := prepareData()
@@ -505,248 +509,248 @@ func TestCalcCellValue(t *testing.T) {
 	mathCalcError := map[string]string{
 		// ABS
 		"=ABS()":    "ABS requires 1 numeric argument",
-		`=ABS("X")`: "#VALUE!",
+		`=ABS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=ABS(~)":   `cannot convert cell "~" to coordinates: invalid cell name "~"`,
 		// ACOS
 		"=ACOS()":    "ACOS requires 1 numeric argument",
-		`=ACOS("X")`: "#VALUE!",
+		`=ACOS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// ACOSH
 		"=ACOSH()":    "ACOSH requires 1 numeric argument",
-		`=ACOSH("X")`: "#VALUE!",
+		`=ACOSH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.ACOT
 		"=_xlfn.ACOT()":    "ACOT requires 1 numeric argument",
-		`=_xlfn.ACOT("X")`: "#VALUE!",
+		`=_xlfn.ACOT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.ACOTH
 		"=_xlfn.ACOTH()":    "ACOTH requires 1 numeric argument",
-		`=_xlfn.ACOTH("X")`: "#VALUE!",
+		`=_xlfn.ACOTH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.ARABIC
 		"=_xlfn.ARABIC()": "ARABIC requires 1 numeric argument",
 		// ASIN
 		"=ASIN()":    "ASIN requires 1 numeric argument",
-		`=ASIN("X")`: "#VALUE!",
+		`=ASIN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// ASINH
 		"=ASINH()":    "ASINH requires 1 numeric argument",
-		`=ASINH("X")`: "#VALUE!",
+		`=ASINH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// ATAN
 		"=ATAN()":    "ATAN requires 1 numeric argument",
-		`=ATAN("X")`: "#VALUE!",
+		`=ATAN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// ATANH
 		"=ATANH()":    "ATANH requires 1 numeric argument",
-		`=ATANH("X")`: "#VALUE!",
+		`=ATANH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// ATAN2
 		"=ATAN2()":      "ATAN2 requires 2 numeric arguments",
-		`=ATAN2("X",0)`: "#VALUE!",
-		`=ATAN2(0,"X")`: "#VALUE!",
+		`=ATAN2("X",0)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=ATAN2(0,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// BASE
 		"=BASE()":        "BASE requires at least 2 arguments",
 		"=BASE(1,2,3,4)": "BASE allows at most 3 arguments",
 		"=BASE(1,1)":     "radix must be an integer >= 2 and <= 36",
-		`=BASE("X",2)`:   "#VALUE!",
-		`=BASE(1,"X")`:   "#VALUE!",
-		`=BASE(1,2,"X")`: "#VALUE!",
+		`=BASE("X",2)`:   "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=BASE(1,"X")`:   "strconv.Atoi: parsing \"X\": invalid syntax",
+		`=BASE(1,2,"X")`: "strconv.Atoi: parsing \"X\": invalid syntax",
 		// CEILING
 		"=CEILING()":      "CEILING requires at least 1 argument",
 		"=CEILING(1,2,3)": "CEILING allows at most 2 arguments",
 		"=CEILING(1,-1)":  "negative sig to CEILING invalid",
-		`=CEILING("X",0)`: "#VALUE!",
-		`=CEILING(0,"X")`: "#VALUE!",
+		`=CEILING("X",0)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=CEILING(0,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.CEILING.MATH
 		"=_xlfn.CEILING.MATH()":        "CEILING.MATH requires at least 1 argument",
 		"=_xlfn.CEILING.MATH(1,2,3,4)": "CEILING.MATH allows at most 3 arguments",
-		`=_xlfn.CEILING.MATH("X")`:     "#VALUE!",
-		`=_xlfn.CEILING.MATH(1,"X")`:   "#VALUE!",
-		`=_xlfn.CEILING.MATH(1,2,"X")`: "#VALUE!",
+		`=_xlfn.CEILING.MATH("X")`:     "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=_xlfn.CEILING.MATH(1,"X")`:   "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=_xlfn.CEILING.MATH(1,2,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.CEILING.PRECISE
 		"=_xlfn.CEILING.PRECISE()":      "CEILING.PRECISE requires at least 1 argument",
 		"=_xlfn.CEILING.PRECISE(1,2,3)": "CEILING.PRECISE allows at most 2 arguments",
-		`=_xlfn.CEILING.PRECISE("X",2)`: "#VALUE!",
+		`=_xlfn.CEILING.PRECISE("X",2)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		`=_xlfn.CEILING.PRECISE(1,"X")`: "#VALUE!",
 		// COMBIN
 		"=COMBIN()":       "COMBIN requires 2 argument",
 		"=COMBIN(-1,1)":   "COMBIN requires number >= number_chosen",
-		`=COMBIN("X",1)`:  "#VALUE!",
-		`=COMBIN(-1,"X")`: "#VALUE!",
+		`=COMBIN("X",1)`:  "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=COMBIN(-1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.COMBINA
 		"=_xlfn.COMBINA()":       "COMBINA requires 2 argument",
 		"=_xlfn.COMBINA(-1,1)":   "COMBINA requires number > number_chosen",
 		"=_xlfn.COMBINA(-1,-1)":  "COMBIN requires number >= number_chosen",
-		`=_xlfn.COMBINA("X",1)`:  "#VALUE!",
-		`=_xlfn.COMBINA(-1,"X")`: "#VALUE!",
+		`=_xlfn.COMBINA("X",1)`:  "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=_xlfn.COMBINA(-1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// COS
 		"=COS()":    "COS requires 1 numeric argument",
-		`=COS("X")`: "#VALUE!",
+		`=COS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// COSH
 		"=COSH()":    "COSH requires 1 numeric argument",
-		`=COSH("X")`: "#VALUE!",
+		`=COSH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.COT
 		"=COT()":    "COT requires 1 numeric argument",
-		`=COT("X")`: "#VALUE!",
+		`=COT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=COT(0)":   "#DIV/0!",
 		// _xlfn.COTH
 		"=COTH()":    "COTH requires 1 numeric argument",
-		`=COTH("X")`: "#VALUE!",
+		`=COTH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=COTH(0)":   "#DIV/0!",
 		// _xlfn.CSC
 		"=_xlfn.CSC()":    "CSC requires 1 numeric argument",
-		`=_xlfn.CSC("X")`: "#VALUE!",
+		`=_xlfn.CSC("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=_xlfn.CSC(0)":   "#DIV/0!",
 		// _xlfn.CSCH
 		"=_xlfn.CSCH()":    "CSCH requires 1 numeric argument",
-		`=_xlfn.CSCH("X")`: "#VALUE!",
+		`=_xlfn.CSCH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=_xlfn.CSCH(0)":   "#DIV/0!",
 		// _xlfn.DECIMAL
 		"=_xlfn.DECIMAL()":          "DECIMAL requires 2 numeric arguments",
-		`=_xlfn.DECIMAL("X", 2)`:    "#VALUE!",
-		`=_xlfn.DECIMAL(2000, "X")`: "#VALUE!",
+		`=_xlfn.DECIMAL("X", 2)`:    "strconv.ParseInt: parsing \"X\": invalid syntax",
+		`=_xlfn.DECIMAL(2000, "X")`: "strconv.Atoi: parsing \"X\": invalid syntax",
 		// DEGREES
 		"=DEGREES()":    "DEGREES requires 1 numeric argument",
-		`=DEGREES("X")`: "#VALUE!",
+		`=DEGREES("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=DEGREES(0)":   "#DIV/0!",
 		// EVEN
 		"=EVEN()":    "EVEN requires 1 numeric argument",
-		`=EVEN("X")`: "#VALUE!",
+		`=EVEN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// EXP
 		"=EXP()":    "EXP requires 1 numeric argument",
-		`=EXP("X")`: "#VALUE!",
+		`=EXP("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// FACT
 		"=FACT()":    "FACT requires 1 numeric argument",
-		`=FACT("X")`: "#VALUE!",
+		`=FACT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=FACT(-1)":  "#NUM!",
 		// FACTDOUBLE
 		"=FACTDOUBLE()":    "FACTDOUBLE requires 1 numeric argument",
-		`=FACTDOUBLE("X")`: "#VALUE!",
+		`=FACTDOUBLE("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=FACTDOUBLE(-1)":  "#NUM!",
 		// FLOOR
 		"=FLOOR()":       "FLOOR requires 2 numeric arguments",
-		`=FLOOR("X",-1)`: "#VALUE!",
-		`=FLOOR(1,"X")`:  "#VALUE!",
-		"=FLOOR(1,-1)":   "#NUM!",
+		`=FLOOR("X",-1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=FLOOR(1,"X")`:  "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		"=FLOOR(1,-1)":   "invalid arguments to FLOOR",
 		// _xlfn.FLOOR.MATH
 		"=_xlfn.FLOOR.MATH()":        "FLOOR.MATH requires at least 1 argument",
 		"=_xlfn.FLOOR.MATH(1,2,3,4)": "FLOOR.MATH allows at most 3 arguments",
-		`=_xlfn.FLOOR.MATH("X",2,3)`: "#VALUE!",
-		`=_xlfn.FLOOR.MATH(1,"X",3)`: "#VALUE!",
-		`=_xlfn.FLOOR.MATH(1,2,"X")`: "#VALUE!",
+		`=_xlfn.FLOOR.MATH("X",2,3)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=_xlfn.FLOOR.MATH(1,"X",3)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=_xlfn.FLOOR.MATH(1,2,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.FLOOR.PRECISE
 		"=_xlfn.FLOOR.PRECISE()":      "FLOOR.PRECISE requires at least 1 argument",
 		"=_xlfn.FLOOR.PRECISE(1,2,3)": "FLOOR.PRECISE allows at most 2 arguments",
-		`=_xlfn.FLOOR.PRECISE("X",2)`: "#VALUE!",
-		`=_xlfn.FLOOR.PRECISE(1,"X")`: "#VALUE!",
+		`=_xlfn.FLOOR.PRECISE("X",2)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=_xlfn.FLOOR.PRECISE(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// GCD
 		"=GCD()":     "GCD requires at least 1 argument",
 		"=GCD(-1)":   "GCD only accepts positive arguments",
 		"=GCD(1,-1)": "GCD only accepts positive arguments",
-		`=GCD("X")`:  "#VALUE!",
+		`=GCD("X")`:  "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// INT
 		"=INT()":    "INT requires 1 numeric argument",
-		`=INT("X")`: "#VALUE!",
+		`=INT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// ISO.CEILING
 		"=ISO.CEILING()":      "ISO.CEILING requires at least 1 argument",
 		"=ISO.CEILING(1,2,3)": "ISO.CEILING allows at most 2 arguments",
-		`=ISO.CEILING("X",2)`: "#VALUE!",
-		`=ISO.CEILING(1,"X")`: "#VALUE!",
+		`=ISO.CEILING("X",2)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=ISO.CEILING(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// LCM
 		"=LCM()":     "LCM requires at least 1 argument",
 		"=LCM(-1)":   "LCM only accepts positive arguments",
 		"=LCM(1,-1)": "LCM only accepts positive arguments",
-		`=LCM("X")`:  "#VALUE!",
+		`=LCM("X")`:  "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// LN
 		"=LN()":    "LN requires 1 numeric argument",
-		`=LN("X")`: "#VALUE!",
+		`=LN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// LOG
 		"=LOG()":      "LOG requires at least 1 argument",
 		"=LOG(1,2,3)": "LOG allows at most 2 arguments",
-		`=LOG("X",1)`: "#VALUE!",
-		`=LOG(1,"X")`: "#VALUE!",
-		"=LOG(0,0)":   "#NUM!",
-		"=LOG(1,0)":   "#NUM!",
+		`=LOG("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=LOG(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		"=LOG(0,0)":   "#DIV/0!",
+		"=LOG(1,0)":   "#DIV/0!",
 		"=LOG(1,1)":   "#DIV/0!",
 		// LOG10
 		"=LOG10()":    "LOG10 requires 1 numeric argument",
-		`=LOG10("X")`: "#VALUE!",
+		`=LOG10("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// MOD
 		"=MOD()":      "MOD requires 2 numeric arguments",
-		"=MOD(6,0)":   "#DIV/0!",
-		`=MOD("X",0)`: "#VALUE!",
-		`=MOD(6,"X")`: "#VALUE!",
+		"=MOD(6,0)":   "MOD divide by zero",
+		`=MOD("X",0)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=MOD(6,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// MROUND
 		"=MROUND()":      "MROUND requires 2 numeric arguments",
 		"=MROUND(1,0)":   "#NUM!",
 		"=MROUND(1,-1)":  "#NUM!",
-		`=MROUND("X",0)`: "#VALUE!",
-		`=MROUND(1,"X")`: "#VALUE!",
+		`=MROUND("X",0)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=MROUND(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// MULTINOMIAL
-		`=MULTINOMIAL("X")`: "#VALUE!",
+		`=MULTINOMIAL("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.MUNIT
-		"=_xlfn.MUNIT()":    "MUNIT requires 1 numeric argument", // not support currently
-		`=_xlfn.MUNIT("X")`: "#VALUE!",                           // not support currently
+		"=_xlfn.MUNIT()":    "MUNIT requires 1 numeric argument",           // not support currently
+		`=_xlfn.MUNIT("X")`: "strconv.Atoi: parsing \"X\": invalid syntax", // not support currently
 		// ODD
 		"=ODD()":    "ODD requires 1 numeric argument",
-		`=ODD("X")`: "#VALUE!",
+		`=ODD("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// PI
 		"=PI(1)": "PI accepts no arguments",
 		// POWER
-		`=POWER("X",1)`: "#VALUE!",
-		`=POWER(1,"X")`: "#VALUE!",
+		`=POWER("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=POWER(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=POWER(0,0)":   "#NUM!",
 		"=POWER(0,-1)":  "#DIV/0!",
 		"=POWER(1)":     "POWER requires 2 numeric arguments",
 		// PRODUCT
-		`=PRODUCT("X")`: "#VALUE!",
+		`=PRODUCT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// QUOTIENT
-		`=QUOTIENT("X",1)`: "#VALUE!",
-		`=QUOTIENT(1,"X")`: "#VALUE!",
+		`=QUOTIENT("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=QUOTIENT(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=QUOTIENT(1,0)":   "#DIV/0!",
 		"=QUOTIENT(1)":     "QUOTIENT requires 2 numeric arguments",
 		// RADIANS
-		`=RADIANS("X")`: "#VALUE!",
+		`=RADIANS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=RADIANS()":    "RADIANS requires 1 numeric argument",
 		// RAND
 		"=RAND(1)": "RAND accepts no arguments",
 		// RANDBETWEEN
-		`=RANDBETWEEN("X",1)`: "#VALUE!",
-		`=RANDBETWEEN(1,"X")`: "#VALUE!",
+		`=RANDBETWEEN("X",1)`: "strconv.ParseInt: parsing \"X\": invalid syntax",
+		`=RANDBETWEEN(1,"X")`: "strconv.ParseInt: parsing \"X\": invalid syntax",
 		"=RANDBETWEEN()":      "RANDBETWEEN requires 2 numeric arguments",
 		"=RANDBETWEEN(2,1)":   "#NUM!",
 		// ROMAN
 		"=ROMAN()":      "ROMAN requires at least 1 argument",
 		"=ROMAN(1,2,3)": "ROMAN allows at most 2 arguments",
-		`=ROMAN("X")`:   "#VALUE!",
-		`=ROMAN("X",1)`: "#VALUE!",
+		`=ROMAN("X")`:   "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=ROMAN("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// ROUND
 		"=ROUND()":      "ROUND requires 2 numeric arguments",
-		`=ROUND("X",1)`: "#VALUE!",
-		`=ROUND(1,"X")`: "#VALUE!",
+		`=ROUND("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=ROUND(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// ROUNDDOWN
 		"=ROUNDDOWN()":      "ROUNDDOWN requires 2 numeric arguments",
-		`=ROUNDDOWN("X",1)`: "#VALUE!",
-		`=ROUNDDOWN(1,"X")`: "#VALUE!",
+		`=ROUNDDOWN("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=ROUNDDOWN(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// ROUNDUP
 		"=ROUNDUP()":      "ROUNDUP requires 2 numeric arguments",
-		`=ROUNDUP("X",1)`: "#VALUE!",
-		`=ROUNDUP(1,"X")`: "#VALUE!",
+		`=ROUNDUP("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=ROUNDUP(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// SEC
 		"=_xlfn.SEC()":    "SEC requires 1 numeric argument",
-		`=_xlfn.SEC("X")`: "#VALUE!",
+		`=_xlfn.SEC("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// _xlfn.SECH
 		"=_xlfn.SECH()":    "SECH requires 1 numeric argument",
-		`=_xlfn.SECH("X")`: "#VALUE!",
+		`=_xlfn.SECH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// SIGN
 		"=SIGN()":    "SIGN requires 1 numeric argument",
-		`=SIGN("X")`: "#VALUE!",
+		`=SIGN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// SIN
 		"=SIN()":    "SIN requires 1 numeric argument",
-		`=SIN("X")`: "#VALUE!",
+		`=SIN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// SINH
 		"=SINH()":    "SINH requires 1 numeric argument",
-		`=SINH("X")`: "#VALUE!",
+		`=SINH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// SQRT
 		"=SQRT()":    "SQRT requires 1 numeric argument",
-		`=SQRT("X")`: "#VALUE!",
+		`=SQRT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		"=SQRT(-1)":  "#NUM!",
 		// SQRTPI
 		"=SQRTPI()":    "SQRTPI requires 1 numeric argument",
-		`=SQRTPI("X")`: "#VALUE!",
+		`=SQRTPI("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// SUM
 		"=SUM((":    "formula not valid",
 		"=SUM(-)":   "formula not valid",
@@ -754,21 +758,21 @@ func TestCalcCellValue(t *testing.T) {
 		"=SUM(1-)":  "formula not valid",
 		"=SUM(1*)":  "formula not valid",
 		"=SUM(1/)":  "formula not valid",
-		`=SUM("X")`: "#VALUE!",
+		`=SUM("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// SUMIF
 		"=SUMIF()": "SUMIF requires at least 2 argument",
 		// SUMSQ
-		`=SUMSQ("X")`: "#VALUE!",
+		`=SUMSQ("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// TAN
 		"=TAN()":    "TAN requires 1 numeric argument",
-		`=TAN("X")`: "#VALUE!",
+		`=TAN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// TANH
 		"=TANH()":    "TANH requires 1 numeric argument",
-		`=TANH("X")`: "#VALUE!",
+		`=TANH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// TRUNC
 		"=TRUNC()":      "TRUNC requires at least 1 argument",
-		`=TRUNC("X")`:   "#VALUE!",
-		`=TRUNC(1,"X")`: "#VALUE!",
+		`=TRUNC("X")`:   "strconv.ParseFloat: parsing \"X\": invalid syntax",
+		`=TRUNC(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// Statistical Functions
 		// MEDIAN
 		"=MEDIAN()": "MEDIAN requires at least 1 argument",
@@ -781,7 +785,7 @@ func TestCalcCellValue(t *testing.T) {
 		"=ISERROR()": "ISERROR requires 1 argument",
 		// ISEVEN
 		"=ISEVEN()":       "ISEVEN requires 1 argument",
-		`=ISEVEN("text")`: "#VALUE!",
+		`=ISEVEN("text")`: "strconv.Atoi: parsing \"text\": invalid syntax",
 		// ISNA
 		"=ISNA()": "ISNA requires 1 argument",
 		// ISNONTEXT
@@ -790,17 +794,17 @@ func TestCalcCellValue(t *testing.T) {
 		"=ISNUMBER()": "ISNUMBER requires 1 argument",
 		// ISODD
 		"=ISODD()":       "ISODD requires 1 argument",
-		`=ISODD("text")`: "#VALUE!",
+		`=ISODD("text")`: "strconv.Atoi: parsing \"text\": invalid syntax",
 		// NA
 		"=NA(1)": "NA accepts no arguments",
 		// Logical Functions
 		// AND
-		`=AND("text")`: "#VALUE!",
+		`=AND("text")`: "strconv.ParseFloat: parsing \"text\": invalid syntax",
 		`=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("text")`:                            "strconv.ParseFloat: parsing \"text\": invalid syntax",
 		`=OR(A1:B1)`:                             "#VALUE!",
 		"=OR()":                                  "OR requires at least 1 argument",
 		"=OR(1" + strings.Repeat(",1", 30) + ")": "OR accepts at most 30 arguments",
@@ -832,13 +836,18 @@ func TestCalcCellValue(t *testing.T) {
 		// IF
 		"=IF()":        "IF requires at least 1 argument",
 		"=IF(0,1,2,3)": "IF accepts at most 3 arguments",
-		"=IF(D1,1,2)":  "#VALUE!",
+		"=IF(D1,1,2)":  "strconv.ParseBool: parsing \"Month\": invalid syntax",
+		// Excel Lookup and Reference Functions
+		// CHOOSE
+		"=CHOOSE()":                "CHOOSE requires 2 arguments",
+		"=CHOOSE(\"index_num\",0)": "CHOOSE requires first argument of type number",
+		"=CHOOSE(2,0)":             "index_num should be <= to the number of values",
 	}
 	for formula, expected := range mathCalcError {
 		f := prepareData()
 		assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
 		result, err := f.CalcCellValue("Sheet1", "C1")
-		assert.EqualError(t, err, expected)
+		assert.EqualError(t, err, expected, formula)
 		assert.Equal(t, "", result, formula)
 	}
 
@@ -976,9 +985,9 @@ func TestISBLANK(t *testing.T) {
 		Type: ArgUnknown,
 	})
 	fn := formulaFuncs{}
-	result, err := fn.ISBLANK(argsList)
-	assert.Equal(t, result, "TRUE")
-	assert.NoError(t, err)
+	result := fn.ISBLANK(argsList)
+	assert.Equal(t, result.String, "TRUE")
+	assert.Empty(t, result.Error)
 }
 
 func TestAND(t *testing.T) {
@@ -987,9 +996,9 @@ func TestAND(t *testing.T) {
 		Type: ArgUnknown,
 	})
 	fn := formulaFuncs{}
-	result, err := fn.AND(argsList)
-	assert.Equal(t, result, "TRUE")
-	assert.NoError(t, err)
+	result := fn.AND(argsList)
+	assert.Equal(t, result.String, "TRUE")
+	assert.Empty(t, result.Error)
 }
 
 func TestOR(t *testing.T) {
@@ -998,9 +1007,9 @@ func TestOR(t *testing.T) {
 		Type: ArgUnknown,
 	})
 	fn := formulaFuncs{}
-	result, err := fn.OR(argsList)
-	assert.Equal(t, result, "FALSE")
-	assert.NoError(t, err)
+	result := fn.OR(argsList)
+	assert.Equal(t, result.String, "FALSE")
+	assert.Empty(t, result.Error)
 }
 
 func TestDet(t *testing.T) {

+ 4 - 4
go.mod

@@ -6,9 +6,9 @@ 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-20201016154823-031c29024257
-	golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee
+	github.com/xuri/efp v0.0.0-20210128032744-13be4fd5dcb5
+	golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
 	golang.org/x/image v0.0.0-20201208152932-35266b937fa6
-	golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0
-	golang.org/x/text v0.3.3
+	golang.org/x/net v0.0.0-20210119194325-5f4716e94777
+	golang.org/x/text v0.3.5
 )

+ 13 - 11
go.sum

@@ -8,28 +8,30 @@ github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj
 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 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
 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-20201016154823-031c29024257 h1:6ldmGEJXtsRMwdR2KuS3esk9wjVJNvgk05/YY2XmOj0=
-github.com/xuri/efp v0.0.0-20201016154823-031c29024257/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk=
+github.com/xuri/efp v0.0.0-20210128032744-13be4fd5dcb5 h1:hO7we8DcWAkmZX/Voqa04Tuo84SbeXIJbdgMj92hIpA=
+github.com/xuri/efp v0.0.0-20210128032744-13be4fd5dcb5/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-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
-golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI=
 golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-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/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 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/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
+golang.org/x/text v0.3.5/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=

部分文件因为文件数量过多而无法显示