Support 5 new kinds of conditional formatting types
- New conditional formatting types: text, blanks, no blanks, errors, and no errors - Support calculate formula with multiple dash arithmetic symbol - Fix empty calculate result with numeric arguments in LEN, LOWER, PROPER, REPT, UPPER, and IF formula functions - Uniform double quote in calculation unit tests - Update unit tests
This commit is contained in:
parent
c7acf4fafe
commit
2499bf6b5b
45
calc.go
45
calc.go
|
@ -844,7 +844,7 @@ func (f *File) calcCellValue(ctx *calcContext, sheet, cell string) (result formu
|
||||||
ps := efp.ExcelParser()
|
ps := efp.ExcelParser()
|
||||||
tokens := ps.Parse(formula)
|
tokens := ps.Parse(formula)
|
||||||
if tokens == nil {
|
if tokens == nil {
|
||||||
return
|
return f.cellResolver(ctx, sheet, cell)
|
||||||
}
|
}
|
||||||
result, err = f.evalInfixExp(ctx, sheet, cell, tokens)
|
result, err = f.evalInfixExp(ctx, sheet, cell, tokens)
|
||||||
return
|
return
|
||||||
|
@ -1225,6 +1225,12 @@ func calcAdd(rOpd, lOpd formulaArg, opdStack *Stack) error {
|
||||||
|
|
||||||
// calcSubtract evaluate subtraction arithmetic operations.
|
// calcSubtract evaluate subtraction arithmetic operations.
|
||||||
func calcSubtract(rOpd, lOpd formulaArg, opdStack *Stack) error {
|
func calcSubtract(rOpd, lOpd formulaArg, opdStack *Stack) error {
|
||||||
|
if rOpd.Value() == "" {
|
||||||
|
rOpd = newNumberFormulaArg(0)
|
||||||
|
}
|
||||||
|
if lOpd.Value() == "" {
|
||||||
|
lOpd = newNumberFormulaArg(0)
|
||||||
|
}
|
||||||
lOpdVal := lOpd.ToNumber()
|
lOpdVal := lOpd.ToNumber()
|
||||||
if lOpdVal.Type != ArgNumber {
|
if lOpdVal.Type != ArgNumber {
|
||||||
return errors.New(lOpdVal.Value())
|
return errors.New(lOpdVal.Value())
|
||||||
|
@ -1300,22 +1306,27 @@ func calculate(opdStack *Stack, opt efp.Token) error {
|
||||||
">=": calcGe,
|
">=": calcGe,
|
||||||
"&": calcSplice,
|
"&": calcSplice,
|
||||||
}
|
}
|
||||||
fn, ok := tokenCalcFunc[opt.TValue]
|
if fn, ok := tokenCalcFunc[opt.TValue]; ok {
|
||||||
if ok {
|
|
||||||
if opdStack.Len() < 2 {
|
if opdStack.Len() < 2 {
|
||||||
return ErrInvalidFormula
|
return ErrInvalidFormula
|
||||||
}
|
}
|
||||||
rOpd := opdStack.Pop().(formulaArg)
|
rOpd := opdStack.Pop().(formulaArg)
|
||||||
lOpd := opdStack.Pop().(formulaArg)
|
lOpd := opdStack.Pop().(formulaArg)
|
||||||
|
if opt.TValue != "&" {
|
||||||
|
if rOpd.Value() == "" {
|
||||||
|
rOpd = newNumberFormulaArg(0)
|
||||||
|
}
|
||||||
|
if lOpd.Value() == "" {
|
||||||
|
lOpd = newNumberFormulaArg(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
if rOpd.Type == ArgError {
|
if rOpd.Type == ArgError {
|
||||||
return errors.New(rOpd.Value())
|
return errors.New(rOpd.Value())
|
||||||
}
|
}
|
||||||
if lOpd.Type == ArgError {
|
if lOpd.Type == ArgError {
|
||||||
return errors.New(lOpd.Value())
|
return errors.New(lOpd.Value())
|
||||||
}
|
}
|
||||||
if err := fn(rOpd, lOpd, opdStack); err != nil {
|
return fn(rOpd, lOpd, opdStack)
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1329,6 +1340,10 @@ func (f *File) parseOperatorPrefixToken(optStack, opdStack *Stack, token efp.Tok
|
||||||
tokenPriority := getPriority(token)
|
tokenPriority := getPriority(token)
|
||||||
topOpt := optStack.Peek().(efp.Token)
|
topOpt := optStack.Peek().(efp.Token)
|
||||||
topOptPriority := getPriority(topOpt)
|
topOptPriority := getPriority(topOpt)
|
||||||
|
if topOpt.TValue == "-" && topOpt.TType == efp.TokenTypeOperatorPrefix && token.TValue == "-" && token.TType == efp.TokenTypeOperatorPrefix {
|
||||||
|
optStack.Pop()
|
||||||
|
return
|
||||||
|
}
|
||||||
if tokenPriority > topOptPriority {
|
if tokenPriority > topOptPriority {
|
||||||
optStack.Push(token)
|
optStack.Push(token)
|
||||||
return
|
return
|
||||||
|
@ -13757,7 +13772,7 @@ func (fn *formulaFuncs) LEN(argsList *list.List) formulaArg {
|
||||||
if argsList.Len() != 1 {
|
if argsList.Len() != 1 {
|
||||||
return newErrorFormulaArg(formulaErrorVALUE, "LEN requires 1 string argument")
|
return newErrorFormulaArg(formulaErrorVALUE, "LEN requires 1 string argument")
|
||||||
}
|
}
|
||||||
return newNumberFormulaArg(float64(utf8.RuneCountInString(argsList.Front().Value.(formulaArg).String)))
|
return newNumberFormulaArg(float64(utf8.RuneCountInString(argsList.Front().Value.(formulaArg).Value())))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LENB returns the number of bytes used to represent the characters in a text
|
// LENB returns the number of bytes used to represent the characters in a text
|
||||||
|
@ -13790,7 +13805,7 @@ func (fn *formulaFuncs) LOWER(argsList *list.List) formulaArg {
|
||||||
if argsList.Len() != 1 {
|
if argsList.Len() != 1 {
|
||||||
return newErrorFormulaArg(formulaErrorVALUE, "LOWER requires 1 argument")
|
return newErrorFormulaArg(formulaErrorVALUE, "LOWER requires 1 argument")
|
||||||
}
|
}
|
||||||
return newStringFormulaArg(strings.ToLower(argsList.Front().Value.(formulaArg).String))
|
return newStringFormulaArg(strings.ToLower(argsList.Front().Value.(formulaArg).Value()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MID function returns a specified number of characters from the middle of a
|
// MID function returns a specified number of characters from the middle of a
|
||||||
|
@ -13881,7 +13896,7 @@ func (fn *formulaFuncs) PROPER(argsList *list.List) formulaArg {
|
||||||
}
|
}
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
isLetter := false
|
isLetter := false
|
||||||
for _, char := range argsList.Front().Value.(formulaArg).String {
|
for _, char := range argsList.Front().Value.(formulaArg).Value() {
|
||||||
if !isLetter && unicode.IsLetter(char) {
|
if !isLetter && unicode.IsLetter(char) {
|
||||||
buf.WriteRune(unicode.ToUpper(char))
|
buf.WriteRune(unicode.ToUpper(char))
|
||||||
} else {
|
} else {
|
||||||
|
@ -13962,7 +13977,7 @@ func (fn *formulaFuncs) REPT(argsList *list.List) formulaArg {
|
||||||
}
|
}
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
for i := 0; i < int(times.Number); i++ {
|
for i := 0; i < int(times.Number); i++ {
|
||||||
buf.WriteString(text.String)
|
buf.WriteString(text.Value())
|
||||||
}
|
}
|
||||||
return newStringFormulaArg(buf.String())
|
return newStringFormulaArg(buf.String())
|
||||||
}
|
}
|
||||||
|
@ -14327,7 +14342,7 @@ func (fn *formulaFuncs) UPPER(argsList *list.List) formulaArg {
|
||||||
if argsList.Len() != 1 {
|
if argsList.Len() != 1 {
|
||||||
return newErrorFormulaArg(formulaErrorVALUE, "UPPER requires 1 argument")
|
return newErrorFormulaArg(formulaErrorVALUE, "UPPER requires 1 argument")
|
||||||
}
|
}
|
||||||
return newStringFormulaArg(strings.ToUpper(argsList.Front().Value.(formulaArg).String))
|
return newStringFormulaArg(strings.ToUpper(argsList.Front().Value.(formulaArg).Value()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// VALUE function converts a text string into a numeric value. The syntax of
|
// VALUE function converts a text string into a numeric value. The syntax of
|
||||||
|
@ -14405,7 +14420,7 @@ func (fn *formulaFuncs) IF(argsList *list.List) formulaArg {
|
||||||
)
|
)
|
||||||
switch token.Type {
|
switch token.Type {
|
||||||
case ArgString:
|
case ArgString:
|
||||||
if cond, err = strconv.ParseBool(token.String); err != nil {
|
if cond, err = strconv.ParseBool(token.Value()); err != nil {
|
||||||
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
|
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
|
||||||
}
|
}
|
||||||
case ArgNumber:
|
case ArgNumber:
|
||||||
|
@ -14421,7 +14436,7 @@ func (fn *formulaFuncs) IF(argsList *list.List) formulaArg {
|
||||||
case ArgNumber:
|
case ArgNumber:
|
||||||
result = value.ToNumber()
|
result = value.ToNumber()
|
||||||
default:
|
default:
|
||||||
result = newStringFormulaArg(value.String)
|
result = newStringFormulaArg(value.Value())
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -14431,7 +14446,7 @@ func (fn *formulaFuncs) IF(argsList *list.List) formulaArg {
|
||||||
case ArgNumber:
|
case ArgNumber:
|
||||||
result = value.ToNumber()
|
result = value.ToNumber()
|
||||||
default:
|
default:
|
||||||
result = newStringFormulaArg(value.String)
|
result = newStringFormulaArg(value.Value())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
@ -14582,7 +14597,7 @@ func compareFormulaArg(lhs, rhs, matchMode formulaArg, caseSensitive bool) byte
|
||||||
}
|
}
|
||||||
return criteriaG
|
return criteriaG
|
||||||
case ArgString:
|
case ArgString:
|
||||||
ls, rs := lhs.String, rhs.String
|
ls, rs := lhs.Value(), rhs.Value()
|
||||||
if !caseSensitive {
|
if !caseSensitive {
|
||||||
ls, rs = strings.ToLower(ls), strings.ToLower(rs)
|
ls, rs = strings.ToLower(ls), strings.ToLower(rs)
|
||||||
}
|
}
|
||||||
|
|
182
calc_test.go
182
calc_test.go
|
@ -58,12 +58,22 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=1>=\"-1\"": "FALSE",
|
"=1>=\"-1\"": "FALSE",
|
||||||
"=\"-1\">=-1": "TRUE",
|
"=\"-1\">=-1": "TRUE",
|
||||||
"=\"-1\">=\"-2\"": "FALSE",
|
"=\"-1\">=\"-2\"": "FALSE",
|
||||||
|
"=-----1+1": "0",
|
||||||
|
"=------1+1": "2",
|
||||||
|
"=---1---1": "-2",
|
||||||
|
"=---1----1": "0",
|
||||||
"=1&2": "12",
|
"=1&2": "12",
|
||||||
"=15%": "0.15",
|
"=15%": "0.15",
|
||||||
"=1+20%": "1.2",
|
"=1+20%": "1.2",
|
||||||
"={1}+2": "3",
|
"={1}+2": "3",
|
||||||
"=1+{2}": "3",
|
"=1+{2}": "3",
|
||||||
"={1}+{2}": "3",
|
"={1}+{2}": "3",
|
||||||
|
"=A1+(B1-C1)": "5",
|
||||||
|
"=A1+(C1-B1)": "-3",
|
||||||
|
"=A1&B1&C1": "14",
|
||||||
|
"=B1+C1": "4",
|
||||||
|
"=C1+B1": "4",
|
||||||
|
"=C1+C1": "0",
|
||||||
"=\"A\"=\"A\"": "TRUE",
|
"=\"A\"=\"A\"": "TRUE",
|
||||||
"=\"A\"<>\"A\"": "FALSE",
|
"=\"A\"<>\"A\"": "FALSE",
|
||||||
"=TRUE()&FALSE()": "TRUEFALSE",
|
"=TRUE()&FALSE()": "TRUEFALSE",
|
||||||
|
@ -1764,6 +1774,8 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=LEN(D1)": "5",
|
"=LEN(D1)": "5",
|
||||||
"=LEN(\"テキスト\")": "4",
|
"=LEN(\"テキスト\")": "4",
|
||||||
"=LEN(\"オリジナルテキスト\")": "9",
|
"=LEN(\"オリジナルテキスト\")": "9",
|
||||||
|
"=LEN(7+LEN(A1&B1&C1))": "1",
|
||||||
|
"=LEN(8+LEN(A1+(C1-B1)))": "2",
|
||||||
// LENB
|
// LENB
|
||||||
"=LENB(\"\")": "0",
|
"=LENB(\"\")": "0",
|
||||||
"=LENB(D1)": "5",
|
"=LENB(D1)": "5",
|
||||||
|
@ -2547,142 +2559,142 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=_xlfn.ARABIC(\"" + strings.Repeat("I", 256) + "\")": {"#VALUE!", "#VALUE!"},
|
"=_xlfn.ARABIC(\"" + strings.Repeat("I", 256) + "\")": {"#VALUE!", "#VALUE!"},
|
||||||
// ASIN
|
// ASIN
|
||||||
"=ASIN()": {"#VALUE!", "ASIN requires 1 numeric argument"},
|
"=ASIN()": {"#VALUE!", "ASIN requires 1 numeric argument"},
|
||||||
`=ASIN("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ASIN(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// ASINH
|
// ASINH
|
||||||
"=ASINH()": {"#VALUE!", "ASINH requires 1 numeric argument"},
|
"=ASINH()": {"#VALUE!", "ASINH requires 1 numeric argument"},
|
||||||
`=ASINH("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ASINH(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// ATAN
|
// ATAN
|
||||||
"=ATAN()": {"#VALUE!", "ATAN requires 1 numeric argument"},
|
"=ATAN()": {"#VALUE!", "ATAN requires 1 numeric argument"},
|
||||||
`=ATAN("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ATAN(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// ATANH
|
// ATANH
|
||||||
"=ATANH()": {"#VALUE!", "ATANH requires 1 numeric argument"},
|
"=ATANH()": {"#VALUE!", "ATANH requires 1 numeric argument"},
|
||||||
`=ATANH("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ATANH(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// ATAN2
|
// ATAN2
|
||||||
"=ATAN2()": {"#VALUE!", "ATAN2 requires 2 numeric arguments"},
|
"=ATAN2()": {"#VALUE!", "ATAN2 requires 2 numeric arguments"},
|
||||||
`=ATAN2("X",0)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ATAN2(\"X\",0)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=ATAN2(0,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ATAN2(0,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// BASE
|
// BASE
|
||||||
"=BASE()": {"#VALUE!", "BASE requires at least 2 arguments"},
|
"=BASE()": {"#VALUE!", "BASE requires at least 2 arguments"},
|
||||||
"=BASE(1,2,3,4)": {"#VALUE!", "BASE allows at most 3 arguments"},
|
"=BASE(1,2,3,4)": {"#VALUE!", "BASE allows at most 3 arguments"},
|
||||||
"=BASE(1,1)": {"#VALUE!", "radix must be an integer >= 2 and <= 36"},
|
"=BASE(1,1)": {"#VALUE!", "radix must be an integer >= 2 and <= 36"},
|
||||||
`=BASE("X",2)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=BASE(\"X\",2)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=BASE(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=BASE(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=BASE(1,2,"X")`: {"#VALUE!", "strconv.Atoi: parsing \"X\": invalid syntax"},
|
"=BASE(1,2,\"X\")": {"#VALUE!", "strconv.Atoi: parsing \"X\": invalid syntax"},
|
||||||
// CEILING
|
// CEILING
|
||||||
"=CEILING()": {"#VALUE!", "CEILING requires at least 1 argument"},
|
"=CEILING()": {"#VALUE!", "CEILING requires at least 1 argument"},
|
||||||
"=CEILING(1,2,3)": {"#VALUE!", "CEILING allows at most 2 arguments"},
|
"=CEILING(1,2,3)": {"#VALUE!", "CEILING allows at most 2 arguments"},
|
||||||
"=CEILING(1,-1)": {"#VALUE!", "negative sig to CEILING invalid"},
|
"=CEILING(1,-1)": {"#VALUE!", "negative sig to CEILING invalid"},
|
||||||
`=CEILING("X",0)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=CEILING(\"X\",0)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=CEILING(0,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=CEILING(0,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// _xlfn.CEILING.MATH
|
// _xlfn.CEILING.MATH
|
||||||
"=_xlfn.CEILING.MATH()": {"#VALUE!", "CEILING.MATH requires at least 1 argument"},
|
"=_xlfn.CEILING.MATH()": {"#VALUE!", "CEILING.MATH requires at least 1 argument"},
|
||||||
"=_xlfn.CEILING.MATH(1,2,3,4)": {"#VALUE!", "CEILING.MATH allows at most 3 arguments"},
|
"=_xlfn.CEILING.MATH(1,2,3,4)": {"#VALUE!", "CEILING.MATH allows at most 3 arguments"},
|
||||||
`=_xlfn.CEILING.MATH("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.CEILING.MATH(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=_xlfn.CEILING.MATH(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.CEILING.MATH(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=_xlfn.CEILING.MATH(1,2,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.CEILING.MATH(1,2,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// _xlfn.CEILING.PRECISE
|
// _xlfn.CEILING.PRECISE
|
||||||
"=_xlfn.CEILING.PRECISE()": {"#VALUE!", "CEILING.PRECISE requires at least 1 argument"},
|
"=_xlfn.CEILING.PRECISE()": {"#VALUE!", "CEILING.PRECISE requires at least 1 argument"},
|
||||||
"=_xlfn.CEILING.PRECISE(1,2,3)": {"#VALUE!", "CEILING.PRECISE allows at most 2 arguments"},
|
"=_xlfn.CEILING.PRECISE(1,2,3)": {"#VALUE!", "CEILING.PRECISE allows at most 2 arguments"},
|
||||||
`=_xlfn.CEILING.PRECISE("X",2)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.CEILING.PRECISE(\"X\",2)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=_xlfn.CEILING.PRECISE(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.CEILING.PRECISE(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// COMBIN
|
// COMBIN
|
||||||
"=COMBIN()": {"#VALUE!", "COMBIN requires 2 argument"},
|
"=COMBIN()": {"#VALUE!", "COMBIN requires 2 argument"},
|
||||||
"=COMBIN(-1,1)": {"#VALUE!", "COMBIN requires number >= number_chosen"},
|
"=COMBIN(-1,1)": {"#VALUE!", "COMBIN requires number >= number_chosen"},
|
||||||
`=COMBIN("X",1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=COMBIN(\"X\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=COMBIN(-1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=COMBIN(-1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// _xlfn.COMBINA
|
// _xlfn.COMBINA
|
||||||
"=_xlfn.COMBINA()": {"#VALUE!", "COMBINA requires 2 argument"},
|
"=_xlfn.COMBINA()": {"#VALUE!", "COMBINA requires 2 argument"},
|
||||||
"=_xlfn.COMBINA(-1,1)": {"#VALUE!", "COMBINA requires number > number_chosen"},
|
"=_xlfn.COMBINA(-1,1)": {"#VALUE!", "COMBINA requires number > number_chosen"},
|
||||||
"=_xlfn.COMBINA(-1,-1)": {"#VALUE!", "COMBIN requires number >= number_chosen"},
|
"=_xlfn.COMBINA(-1,-1)": {"#VALUE!", "COMBIN requires number >= number_chosen"},
|
||||||
`=_xlfn.COMBINA("X",1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.COMBINA(\"X\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=_xlfn.COMBINA(-1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.COMBINA(-1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// COS
|
// COS
|
||||||
"=COS()": {"#VALUE!", "COS requires 1 numeric argument"},
|
"=COS()": {"#VALUE!", "COS requires 1 numeric argument"},
|
||||||
`=COS("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=COS(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// COSH
|
// COSH
|
||||||
"=COSH()": {"#VALUE!", "COSH requires 1 numeric argument"},
|
"=COSH()": {"#VALUE!", "COSH requires 1 numeric argument"},
|
||||||
`=COSH("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=COSH(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// _xlfn.COT
|
// _xlfn.COT
|
||||||
"=COT()": {"#VALUE!", "COT requires 1 numeric argument"},
|
"=COT()": {"#VALUE!", "COT requires 1 numeric argument"},
|
||||||
`=COT("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=COT(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=COT(0)": {"#DIV/0!", "#DIV/0!"},
|
"=COT(0)": {"#DIV/0!", "#DIV/0!"},
|
||||||
// _xlfn.COTH
|
// _xlfn.COTH
|
||||||
"=COTH()": {"#VALUE!", "COTH requires 1 numeric argument"},
|
"=COTH()": {"#VALUE!", "COTH requires 1 numeric argument"},
|
||||||
`=COTH("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=COTH(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=COTH(0)": {"#DIV/0!", "#DIV/0!"},
|
"=COTH(0)": {"#DIV/0!", "#DIV/0!"},
|
||||||
// _xlfn.CSC
|
// _xlfn.CSC
|
||||||
"=_xlfn.CSC()": {"#VALUE!", "CSC requires 1 numeric argument"},
|
"=_xlfn.CSC()": {"#VALUE!", "CSC requires 1 numeric argument"},
|
||||||
`=_xlfn.CSC("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.CSC(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=_xlfn.CSC(0)": {"#DIV/0!", "#DIV/0!"},
|
"=_xlfn.CSC(0)": {"#DIV/0!", "#DIV/0!"},
|
||||||
// _xlfn.CSCH
|
// _xlfn.CSCH
|
||||||
"=_xlfn.CSCH()": {"#VALUE!", "CSCH requires 1 numeric argument"},
|
"=_xlfn.CSCH()": {"#VALUE!", "CSCH requires 1 numeric argument"},
|
||||||
`=_xlfn.CSCH("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.CSCH(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=_xlfn.CSCH(0)": {"#DIV/0!", "#DIV/0!"},
|
"=_xlfn.CSCH(0)": {"#DIV/0!", "#DIV/0!"},
|
||||||
// _xlfn.DECIMAL
|
// _xlfn.DECIMAL
|
||||||
"=_xlfn.DECIMAL()": {"#VALUE!", "DECIMAL requires 2 numeric arguments"},
|
"=_xlfn.DECIMAL()": {"#VALUE!", "DECIMAL requires 2 numeric arguments"},
|
||||||
`=_xlfn.DECIMAL("X",2)`: {"#VALUE!", "strconv.ParseInt: parsing \"X\": invalid syntax"},
|
"=_xlfn.DECIMAL(\"X\",2)": {"#VALUE!", "strconv.ParseInt: parsing \"X\": invalid syntax"},
|
||||||
`=_xlfn.DECIMAL(2000,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.DECIMAL(2000,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// DEGREES
|
// DEGREES
|
||||||
"=DEGREES()": {"#VALUE!", "DEGREES requires 1 numeric argument"},
|
"=DEGREES()": {"#VALUE!", "DEGREES requires 1 numeric argument"},
|
||||||
`=DEGREES("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=DEGREES(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=DEGREES(0)": {"#DIV/0!", "#DIV/0!"},
|
"=DEGREES(0)": {"#DIV/0!", "#DIV/0!"},
|
||||||
// EVEN
|
// EVEN
|
||||||
"=EVEN()": {"#VALUE!", "EVEN requires 1 numeric argument"},
|
"=EVEN()": {"#VALUE!", "EVEN requires 1 numeric argument"},
|
||||||
`=EVEN("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=EVEN(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// EXP
|
// EXP
|
||||||
"=EXP()": {"#VALUE!", "EXP requires 1 numeric argument"},
|
"=EXP()": {"#VALUE!", "EXP requires 1 numeric argument"},
|
||||||
`=EXP("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=EXP(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// FACT
|
// FACT
|
||||||
"=FACT()": {"#VALUE!", "FACT requires 1 numeric argument"},
|
"=FACT()": {"#VALUE!", "FACT requires 1 numeric argument"},
|
||||||
`=FACT("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=FACT(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=FACT(-1)": {"#NUM!", "#NUM!"},
|
"=FACT(-1)": {"#NUM!", "#NUM!"},
|
||||||
// FACTDOUBLE
|
// FACTDOUBLE
|
||||||
"=FACTDOUBLE()": {"#VALUE!", "FACTDOUBLE requires 1 numeric argument"},
|
"=FACTDOUBLE()": {"#VALUE!", "FACTDOUBLE requires 1 numeric argument"},
|
||||||
`=FACTDOUBLE("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=FACTDOUBLE(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=FACTDOUBLE(-1)": {"#NUM!", "#NUM!"},
|
"=FACTDOUBLE(-1)": {"#NUM!", "#NUM!"},
|
||||||
// FLOOR
|
// FLOOR
|
||||||
"=FLOOR()": {"#VALUE!", "FLOOR requires 2 numeric arguments"},
|
"=FLOOR()": {"#VALUE!", "FLOOR requires 2 numeric arguments"},
|
||||||
`=FLOOR("X",-1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=FLOOR(\"X\",-1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=FLOOR(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=FLOOR(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=FLOOR(1,-1)": {"#NUM!", "invalid arguments to FLOOR"},
|
"=FLOOR(1,-1)": {"#NUM!", "invalid arguments to FLOOR"},
|
||||||
// _xlfn.FLOOR.MATH
|
// _xlfn.FLOOR.MATH
|
||||||
"=_xlfn.FLOOR.MATH()": {"#VALUE!", "FLOOR.MATH requires at least 1 argument"},
|
"=_xlfn.FLOOR.MATH()": {"#VALUE!", "FLOOR.MATH requires at least 1 argument"},
|
||||||
"=_xlfn.FLOOR.MATH(1,2,3,4)": {"#VALUE!", "FLOOR.MATH allows at most 3 arguments"},
|
"=_xlfn.FLOOR.MATH(1,2,3,4)": {"#VALUE!", "FLOOR.MATH allows at most 3 arguments"},
|
||||||
`=_xlfn.FLOOR.MATH("X",2,3)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.FLOOR.MATH(\"X\",2,3)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=_xlfn.FLOOR.MATH(1,"X",3)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.FLOOR.MATH(1,\"X\",3)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=_xlfn.FLOOR.MATH(1,2,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.FLOOR.MATH(1,2,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// _xlfn.FLOOR.PRECISE
|
// _xlfn.FLOOR.PRECISE
|
||||||
"=_xlfn.FLOOR.PRECISE()": {"#VALUE!", "FLOOR.PRECISE requires at least 1 argument"},
|
"=_xlfn.FLOOR.PRECISE()": {"#VALUE!", "FLOOR.PRECISE requires at least 1 argument"},
|
||||||
"=_xlfn.FLOOR.PRECISE(1,2,3)": {"#VALUE!", "FLOOR.PRECISE allows at most 2 arguments"},
|
"=_xlfn.FLOOR.PRECISE(1,2,3)": {"#VALUE!", "FLOOR.PRECISE allows at most 2 arguments"},
|
||||||
`=_xlfn.FLOOR.PRECISE("X",2)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.FLOOR.PRECISE(\"X\",2)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=_xlfn.FLOOR.PRECISE(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.FLOOR.PRECISE(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// GCD
|
// GCD
|
||||||
"=GCD()": {"#VALUE!", "GCD requires at least 1 argument"},
|
"=GCD()": {"#VALUE!", "GCD requires at least 1 argument"},
|
||||||
"=GCD(\"\")": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
"=GCD(\"\")": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
||||||
"=GCD(-1)": {"#VALUE!", "GCD only accepts positive arguments"},
|
"=GCD(-1)": {"#VALUE!", "GCD only accepts positive arguments"},
|
||||||
"=GCD(1,-1)": {"#VALUE!", "GCD only accepts positive arguments"},
|
"=GCD(1,-1)": {"#VALUE!", "GCD only accepts positive arguments"},
|
||||||
`=GCD("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=GCD(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// INT
|
// INT
|
||||||
"=INT()": {"#VALUE!", "INT requires 1 numeric argument"},
|
"=INT()": {"#VALUE!", "INT requires 1 numeric argument"},
|
||||||
`=INT("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=INT(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// ISO.CEILING
|
// ISO.CEILING
|
||||||
"=ISO.CEILING()": {"#VALUE!", "ISO.CEILING requires at least 1 argument"},
|
"=ISO.CEILING()": {"#VALUE!", "ISO.CEILING requires at least 1 argument"},
|
||||||
"=ISO.CEILING(1,2,3)": {"#VALUE!", "ISO.CEILING allows at most 2 arguments"},
|
"=ISO.CEILING(1,2,3)": {"#VALUE!", "ISO.CEILING allows at most 2 arguments"},
|
||||||
`=ISO.CEILING("X",2)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ISO.CEILING(\"X\",2)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=ISO.CEILING(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ISO.CEILING(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// LCM
|
// LCM
|
||||||
"=LCM()": {"#VALUE!", "LCM requires at least 1 argument"},
|
"=LCM()": {"#VALUE!", "LCM requires at least 1 argument"},
|
||||||
"=LCM(-1)": {"#VALUE!", "LCM only accepts positive arguments"},
|
"=LCM(-1)": {"#VALUE!", "LCM only accepts positive arguments"},
|
||||||
"=LCM(1,-1)": {"#VALUE!", "LCM only accepts positive arguments"},
|
"=LCM(1,-1)": {"#VALUE!", "LCM only accepts positive arguments"},
|
||||||
`=LCM("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=LCM(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// LN
|
// LN
|
||||||
"=LN()": {"#VALUE!", "LN requires 1 numeric argument"},
|
"=LN()": {"#VALUE!", "LN requires 1 numeric argument"},
|
||||||
"=LN(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=LN(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// LOG
|
// LOG
|
||||||
"=LOG()": {"#VALUE!", "LOG requires at least 1 argument"},
|
"=LOG()": {"#VALUE!", "LOG requires at least 1 argument"},
|
||||||
"=LOG(1,2,3)": {"#VALUE!", "LOG allows at most 2 arguments"},
|
"=LOG(1,2,3)": {"#VALUE!", "LOG allows at most 2 arguments"},
|
||||||
`=LOG("X",1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=LOG(\"X\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=LOG(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=LOG(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=LOG(0,0)": {"#NUM!", "#DIV/0!"},
|
"=LOG(0,0)": {"#NUM!", "#DIV/0!"},
|
||||||
"=LOG(1,0)": {"#NUM!", "#DIV/0!"},
|
"=LOG(1,0)": {"#NUM!", "#DIV/0!"},
|
||||||
"=LOG(1,1)": {"#DIV/0!", "#DIV/0!"},
|
"=LOG(1,1)": {"#DIV/0!", "#DIV/0!"},
|
||||||
|
@ -2704,28 +2716,28 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
// MOD
|
// MOD
|
||||||
"=MOD()": {"#VALUE!", "MOD requires 2 numeric arguments"},
|
"=MOD()": {"#VALUE!", "MOD requires 2 numeric arguments"},
|
||||||
"=MOD(6,0)": {"#DIV/0!", "MOD divide by zero"},
|
"=MOD(6,0)": {"#DIV/0!", "MOD divide by zero"},
|
||||||
`=MOD("X",0)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=MOD(\"X\",0)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=MOD(6,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=MOD(6,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// MROUND
|
// MROUND
|
||||||
"=MROUND()": {"#VALUE!", "MROUND requires 2 numeric arguments"},
|
"=MROUND()": {"#VALUE!", "MROUND requires 2 numeric arguments"},
|
||||||
"=MROUND(1,0)": {"#NUM!", "#NUM!"},
|
"=MROUND(1,0)": {"#NUM!", "#NUM!"},
|
||||||
"=MROUND(1,-1)": {"#NUM!", "#NUM!"},
|
"=MROUND(1,-1)": {"#NUM!", "#NUM!"},
|
||||||
`=MROUND("X",0)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=MROUND(\"X\",0)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=MROUND(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=MROUND(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// MULTINOMIAL
|
// MULTINOMIAL
|
||||||
`=MULTINOMIAL("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=MULTINOMIAL(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// _xlfn.MUNIT
|
// _xlfn.MUNIT
|
||||||
"=_xlfn.MUNIT()": {"#VALUE!", "MUNIT requires 1 numeric argument"},
|
"=_xlfn.MUNIT()": {"#VALUE!", "MUNIT requires 1 numeric argument"},
|
||||||
`=_xlfn.MUNIT("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.MUNIT(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=_xlfn.MUNIT(-1)": {"#VALUE!", ""},
|
"=_xlfn.MUNIT(-1)": {"#VALUE!", ""},
|
||||||
// ODD
|
// ODD
|
||||||
"=ODD()": {"#VALUE!", "ODD requires 1 numeric argument"},
|
"=ODD()": {"#VALUE!", "ODD requires 1 numeric argument"},
|
||||||
`=ODD("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ODD(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// PI
|
// PI
|
||||||
"=PI(1)": {"#VALUE!", "PI accepts no arguments"},
|
"=PI(1)": {"#VALUE!", "PI accepts no arguments"},
|
||||||
// POWER
|
// POWER
|
||||||
`=POWER("X",1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=POWER(\"X\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=POWER(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=POWER(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=POWER(0,0)": {"#NUM!", "#NUM!"},
|
"=POWER(0,0)": {"#NUM!", "#NUM!"},
|
||||||
"=POWER(0,-1)": {"#DIV/0!", "#DIV/0!"},
|
"=POWER(0,-1)": {"#DIV/0!", "#DIV/0!"},
|
||||||
"=POWER(1)": {"#VALUE!", "POWER requires 2 numeric arguments"},
|
"=POWER(1)": {"#VALUE!", "POWER requires 2 numeric arguments"},
|
||||||
|
@ -2733,18 +2745,18 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=PRODUCT(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=PRODUCT(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=PRODUCT(\"\",3,6)": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
"=PRODUCT(\"\",3,6)": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
||||||
// QUOTIENT
|
// QUOTIENT
|
||||||
`=QUOTIENT("X",1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=QUOTIENT(\"X\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=QUOTIENT(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=QUOTIENT(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=QUOTIENT(1,0)": {"#DIV/0!", "#DIV/0!"},
|
"=QUOTIENT(1,0)": {"#DIV/0!", "#DIV/0!"},
|
||||||
"=QUOTIENT(1)": {"#VALUE!", "QUOTIENT requires 2 numeric arguments"},
|
"=QUOTIENT(1)": {"#VALUE!", "QUOTIENT requires 2 numeric arguments"},
|
||||||
// RADIANS
|
// RADIANS
|
||||||
`=RADIANS("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=RADIANS(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=RADIANS()": {"#VALUE!", "RADIANS requires 1 numeric argument"},
|
"=RADIANS()": {"#VALUE!", "RADIANS requires 1 numeric argument"},
|
||||||
// RAND
|
// RAND
|
||||||
"=RAND(1)": {"#VALUE!", "RAND accepts no arguments"},
|
"=RAND(1)": {"#VALUE!", "RAND accepts no arguments"},
|
||||||
// RANDBETWEEN
|
// RANDBETWEEN
|
||||||
`=RANDBETWEEN("X",1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=RANDBETWEEN(\"X\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=RANDBETWEEN(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=RANDBETWEEN(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=RANDBETWEEN()": {"#VALUE!", "RANDBETWEEN requires 2 numeric arguments"},
|
"=RANDBETWEEN()": {"#VALUE!", "RANDBETWEEN requires 2 numeric arguments"},
|
||||||
"=RANDBETWEEN(2,1)": {"#NUM!", "#NUM!"},
|
"=RANDBETWEEN(2,1)": {"#NUM!", "#NUM!"},
|
||||||
// ROMAN
|
// ROMAN
|
||||||
|
@ -2755,16 +2767,16 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=ROMAN(\"\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
"=ROMAN(\"\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
||||||
// ROUND
|
// ROUND
|
||||||
"=ROUND()": {"#VALUE!", "ROUND requires 2 numeric arguments"},
|
"=ROUND()": {"#VALUE!", "ROUND requires 2 numeric arguments"},
|
||||||
`=ROUND("X",1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ROUND(\"X\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=ROUND(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ROUND(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// ROUNDDOWN
|
// ROUNDDOWN
|
||||||
"=ROUNDDOWN()": {"#VALUE!", "ROUNDDOWN requires 2 numeric arguments"},
|
"=ROUNDDOWN()": {"#VALUE!", "ROUNDDOWN requires 2 numeric arguments"},
|
||||||
`=ROUNDDOWN("X",1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ROUNDDOWN(\"X\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=ROUNDDOWN(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ROUNDDOWN(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// ROUNDUP
|
// ROUNDUP
|
||||||
"=ROUNDUP()": {"#VALUE!", "ROUNDUP requires 2 numeric arguments"},
|
"=ROUNDUP()": {"#VALUE!", "ROUNDUP requires 2 numeric arguments"},
|
||||||
`=ROUNDUP("X",1)`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ROUNDUP(\"X\",1)": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
`=ROUNDUP(1,"X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=ROUNDUP(1,\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// SEARCH
|
// SEARCH
|
||||||
"=SEARCH()": {"#VALUE!", "SEARCH requires at least 2 arguments"},
|
"=SEARCH()": {"#VALUE!", "SEARCH requires at least 2 arguments"},
|
||||||
"=SEARCH(1,A1,1,1)": {"#VALUE!", "SEARCH allows at most 3 arguments"},
|
"=SEARCH(1,A1,1,1)": {"#VALUE!", "SEARCH allows at most 3 arguments"},
|
||||||
|
@ -2778,10 +2790,10 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=SEARCHB(1,A1,\"\")": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
"=SEARCHB(1,A1,\"\")": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
||||||
// SEC
|
// SEC
|
||||||
"=_xlfn.SEC()": {"#VALUE!", "SEC requires 1 numeric argument"},
|
"=_xlfn.SEC()": {"#VALUE!", "SEC requires 1 numeric argument"},
|
||||||
`=_xlfn.SEC("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.SEC(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// _xlfn.SECH
|
// _xlfn.SECH
|
||||||
"=_xlfn.SECH()": {"#VALUE!", "SECH requires 1 numeric argument"},
|
"=_xlfn.SECH()": {"#VALUE!", "SECH requires 1 numeric argument"},
|
||||||
`=_xlfn.SECH("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=_xlfn.SECH(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// SERIESSUM
|
// SERIESSUM
|
||||||
"=SERIESSUM()": {"#VALUE!", "SERIESSUM requires 4 arguments"},
|
"=SERIESSUM()": {"#VALUE!", "SERIESSUM requires 4 arguments"},
|
||||||
"=SERIESSUM(\"\",2,3,A1:A4)": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
"=SERIESSUM(\"\",2,3,A1:A4)": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
||||||
|
@ -2790,21 +2802,21 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=SERIESSUM(1,2,3,A1:D1)": {"#VALUE!", "strconv.ParseFloat: parsing \"Month\": invalid syntax"},
|
"=SERIESSUM(1,2,3,A1:D1)": {"#VALUE!", "strconv.ParseFloat: parsing \"Month\": invalid syntax"},
|
||||||
// SIGN
|
// SIGN
|
||||||
"=SIGN()": {"#VALUE!", "SIGN requires 1 numeric argument"},
|
"=SIGN()": {"#VALUE!", "SIGN requires 1 numeric argument"},
|
||||||
`=SIGN("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=SIGN(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// SIN
|
// SIN
|
||||||
"=SIN()": {"#VALUE!", "SIN requires 1 numeric argument"},
|
"=SIN()": {"#VALUE!", "SIN requires 1 numeric argument"},
|
||||||
`=SIN("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=SIN(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// SINH
|
// SINH
|
||||||
"=SINH()": {"#VALUE!", "SINH requires 1 numeric argument"},
|
"=SINH()": {"#VALUE!", "SINH requires 1 numeric argument"},
|
||||||
`=SINH("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=SINH(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// SQRT
|
// SQRT
|
||||||
"=SQRT()": {"#VALUE!", "SQRT requires 1 numeric argument"},
|
"=SQRT()": {"#VALUE!", "SQRT requires 1 numeric argument"},
|
||||||
`=SQRT("")`: {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
"=SQRT(\"\")": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
|
||||||
`=SQRT("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=SQRT(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
"=SQRT(-1)": {"#NUM!", "#NUM!"},
|
"=SQRT(-1)": {"#NUM!", "#NUM!"},
|
||||||
// SQRTPI
|
// SQRTPI
|
||||||
"=SQRTPI()": {"#VALUE!", "SQRTPI requires 1 numeric argument"},
|
"=SQRTPI()": {"#VALUE!", "SQRTPI requires 1 numeric argument"},
|
||||||
`=SQRTPI("X")`: {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
"=SQRTPI(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
|
||||||
// STDEV
|
// STDEV
|
||||||
"=STDEV()": {"#VALUE!", "STDEV requires at least 1 argument"},
|
"=STDEV()": {"#VALUE!", "STDEV requires at least 1 argument"},
|
||||||
"=STDEV(E2:E9)": {"#DIV/0!", "#DIV/0!"},
|
"=STDEV(E2:E9)": {"#DIV/0!", "#DIV/0!"},
|
||||||
|
@ -4666,7 +4678,7 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
f := prepareCalcData(cellData)
|
f := prepareCalcData(cellData)
|
||||||
result, err := f.CalcCellValue("Sheet1", "A1")
|
result, err := f.CalcCellValue("Sheet1", "A1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "", result)
|
assert.Equal(t, "1", result)
|
||||||
// Test get calculated cell value on not exists worksheet
|
// Test get calculated cell value on not exists worksheet
|
||||||
f = prepareCalcData(cellData)
|
f = prepareCalcData(cellData)
|
||||||
_, err = f.CalcCellValue("SheetN", "A1")
|
_, err = f.CalcCellValue("SheetN", "A1")
|
||||||
|
@ -4718,7 +4730,7 @@ func TestCalcWithDefinedName(t *testing.T) {
|
||||||
assert.NoError(t, f.SetCellFormula("Sheet1", "D1", "=IF(\"B1_as_string\"=defined_name1,\"YES\",\"NO\")"))
|
assert.NoError(t, f.SetCellFormula("Sheet1", "D1", "=IF(\"B1_as_string\"=defined_name1,\"YES\",\"NO\")"))
|
||||||
result, err = f.CalcCellValue("Sheet1", "D1")
|
result, err = f.CalcCellValue("Sheet1", "D1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "YES", result, `=IF("B1_as_string"=defined_name1,"YES","NO")`)
|
assert.Equal(t, "YES", result, "=IF(\"B1_as_string\"=defined_name1,\"YES\",\"NO\")")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalcISBLANK(t *testing.T) {
|
func TestCalcISBLANK(t *testing.T) {
|
||||||
|
@ -6140,14 +6152,14 @@ func TestCalcBetainvProbIterator(t *testing.T) {
|
||||||
func TestNestedFunctionsWithOperators(t *testing.T) {
|
func TestNestedFunctionsWithOperators(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
formulaList := map[string]string{
|
formulaList := map[string]string{
|
||||||
`=LEN("KEEP")`: "4",
|
"=LEN(\"KEEP\")": "4",
|
||||||
`=LEN("REMOVEKEEP") - LEN("REMOVE")`: "4",
|
"=LEN(\"REMOVEKEEP\") - LEN(\"REMOVE\")": "4",
|
||||||
`=RIGHT("REMOVEKEEP", 4)`: "KEEP",
|
"=RIGHT(\"REMOVEKEEP\", 4)": "KEEP",
|
||||||
`=RIGHT("REMOVEKEEP", 10 - 6))`: "KEEP",
|
"=RIGHT(\"REMOVEKEEP\", 10 - 6))": "KEEP",
|
||||||
`=RIGHT("REMOVEKEEP", LEN("REMOVEKEEP") - 6)`: "KEEP",
|
"=RIGHT(\"REMOVEKEEP\", LEN(\"REMOVEKEEP\") - 6)": "KEEP",
|
||||||
`=RIGHT("REMOVEKEEP", LEN("REMOVEKEEP") - LEN("REMOV") - 1)`: "KEEP",
|
"=RIGHT(\"REMOVEKEEP\", LEN(\"REMOVEKEEP\") - LEN(\"REMOV\") - 1)": "KEEP",
|
||||||
`=RIGHT("REMOVEKEEP", 10 - LEN("REMOVE"))`: "KEEP",
|
"=RIGHT(\"REMOVEKEEP\", 10 - LEN(\"REMOVE\"))": "KEEP",
|
||||||
`=RIGHT("REMOVEKEEP", LEN("REMOVEKEEP") - LEN("REMOVE"))`: "KEEP",
|
"=RIGHT(\"REMOVEKEEP\", LEN(\"REMOVEKEEP\") - LEN(\"REMOVE\"))": "KEEP",
|
||||||
}
|
}
|
||||||
for formula, expected := range formulaList {
|
for formula, expected := range formulaList {
|
||||||
assert.NoError(t, f.SetCellFormula("Sheet1", "E1", formula))
|
assert.NoError(t, f.SetCellFormula("Sheet1", "E1", formula))
|
||||||
|
|
|
@ -1202,16 +1202,18 @@ func TestConditionalFormat(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
// Test set conditional format with invalid cell reference
|
||||||
|
assert.Equal(t, newCellNameToCoordinatesError("-", newInvalidCellNameError("-")), f.SetConditionalFormat("Sheet1", "A1:-", nil))
|
||||||
// Test set conditional format on not exists worksheet
|
// Test set conditional format on not exists worksheet
|
||||||
assert.EqualError(t, f.SetConditionalFormat("SheetN", "L1:L10", nil), "sheet SheetN does not exist")
|
assert.EqualError(t, f.SetConditionalFormat("SheetN", "L1:L10", nil), "sheet SheetN does not exist")
|
||||||
// Test set conditional format with invalid sheet name
|
// Test set conditional format with invalid sheet name
|
||||||
assert.EqualError(t, f.SetConditionalFormat("Sheet:1", "L1:L10", nil), ErrSheetNameInvalid.Error())
|
assert.Equal(t, ErrSheetNameInvalid, f.SetConditionalFormat("Sheet:1", "L1:L10", nil))
|
||||||
|
|
||||||
err = f.SaveAs(filepath.Join("test", "TestConditionalFormat.xlsx"))
|
err = f.SaveAs(filepath.Join("test", "TestConditionalFormat.xlsx"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Set conditional format with illegal valid type
|
// Set conditional format with illegal valid type
|
||||||
assert.NoError(t, f.SetConditionalFormat(sheet1, "K1:K10",
|
assert.Equal(t, ErrParameterInvalid, f.SetConditionalFormat(sheet1, "K1:K10",
|
||||||
[]ConditionalFormatOptions{
|
[]ConditionalFormatOptions{
|
||||||
{
|
{
|
||||||
Type: "",
|
Type: "",
|
||||||
|
|
194
styles.go
194
styles.go
|
@ -33,12 +33,12 @@ var validType = map[string]string{
|
||||||
"unique": "uniqueValues",
|
"unique": "uniqueValues",
|
||||||
"top": "top10",
|
"top": "top10",
|
||||||
"bottom": "top10",
|
"bottom": "top10",
|
||||||
"text": "text", // Doesn't support currently
|
"text": "text",
|
||||||
"time_period": "timePeriod", // Doesn't support currently
|
"time_period": "timePeriod", // Doesn't support currently
|
||||||
"blanks": "containsBlanks", // Doesn't support currently
|
"blanks": "containsBlanks",
|
||||||
"no_blanks": "notContainsBlanks", // Doesn't support currently
|
"no_blanks": "notContainsBlanks",
|
||||||
"errors": "containsErrors", // Doesn't support currently
|
"errors": "containsErrors",
|
||||||
"no_errors": "notContainsErrors", // Doesn't support currently
|
"no_errors": "notContainsErrors",
|
||||||
"2_color_scale": "2_color_scale",
|
"2_color_scale": "2_color_scale",
|
||||||
"3_color_scale": "3_color_scale",
|
"3_color_scale": "3_color_scale",
|
||||||
"data_bar": "dataBar",
|
"data_bar": "dataBar",
|
||||||
|
@ -1223,12 +1223,17 @@ var (
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// drawContFmtFunc defines functions to create conditional formats.
|
// drawContFmtFunc defines functions to create conditional formats.
|
||||||
drawContFmtFunc = map[string]func(p int, ct, GUID string, fmtCond *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule){
|
drawContFmtFunc = map[string]func(p int, ct, ref, GUID string, fmtCond *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule){
|
||||||
"cellIs": drawCondFmtCellIs,
|
"cellIs": drawCondFmtCellIs,
|
||||||
|
"text": drawCondFmtText,
|
||||||
"top10": drawCondFmtTop10,
|
"top10": drawCondFmtTop10,
|
||||||
"aboveAverage": drawCondFmtAboveAverage,
|
"aboveAverage": drawCondFmtAboveAverage,
|
||||||
"duplicateValues": drawCondFmtDuplicateUniqueValues,
|
"duplicateValues": drawCondFmtDuplicateUniqueValues,
|
||||||
"uniqueValues": drawCondFmtDuplicateUniqueValues,
|
"uniqueValues": drawCondFmtDuplicateUniqueValues,
|
||||||
|
"containsBlanks": drawCondFmtBlanks,
|
||||||
|
"notContainsBlanks": drawCondFmtNoBlanks,
|
||||||
|
"containsErrors": drawCondFmtErrors,
|
||||||
|
"notContainsErrors": drawCondFmtNoErrors,
|
||||||
"2_color_scale": drawCondFmtColorScale,
|
"2_color_scale": drawCondFmtColorScale,
|
||||||
"3_color_scale": drawCondFmtColorScale,
|
"3_color_scale": drawCondFmtColorScale,
|
||||||
"dataBar": drawCondFmtDataBar,
|
"dataBar": drawCondFmtDataBar,
|
||||||
|
@ -1238,10 +1243,18 @@ var (
|
||||||
// extractContFmtFunc defines functions to get conditional formats.
|
// extractContFmtFunc defines functions to get conditional formats.
|
||||||
extractContFmtFunc = map[string]func(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions{
|
extractContFmtFunc = map[string]func(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions{
|
||||||
"cellIs": extractCondFmtCellIs,
|
"cellIs": extractCondFmtCellIs,
|
||||||
|
"containsText": extractCondFmtText,
|
||||||
|
"notContainsText": extractCondFmtText,
|
||||||
|
"beginsWith": extractCondFmtText,
|
||||||
|
"endsWith": extractCondFmtText,
|
||||||
"top10": extractCondFmtTop10,
|
"top10": extractCondFmtTop10,
|
||||||
"aboveAverage": extractCondFmtAboveAverage,
|
"aboveAverage": extractCondFmtAboveAverage,
|
||||||
"duplicateValues": extractCondFmtDuplicateUniqueValues,
|
"duplicateValues": extractCondFmtDuplicateUniqueValues,
|
||||||
"uniqueValues": extractCondFmtDuplicateUniqueValues,
|
"uniqueValues": extractCondFmtDuplicateUniqueValues,
|
||||||
|
"containsBlanks": extractCondFmtBlanks,
|
||||||
|
"notContainsBlanks": extractCondFmtNoBlanks,
|
||||||
|
"containsErrors": extractCondFmtErrors,
|
||||||
|
"notContainsErrors": extractCondFmtNoErrors,
|
||||||
"colorScale": extractCondFmtColorScale,
|
"colorScale": extractCondFmtColorScale,
|
||||||
"dataBar": extractCondFmtDataBar,
|
"dataBar": extractCondFmtDataBar,
|
||||||
"expression": extractCondFmtExp,
|
"expression": extractCondFmtExp,
|
||||||
|
@ -2635,13 +2648,31 @@ func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if strings.Contains(rangeRef, ":") {
|
||||||
|
rect, err := rangeRefToCoordinates(rangeRef)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = sortCoordinates(rect)
|
||||||
|
rangeRef, _ = f.coordinatesToRangeRef(rect, strings.Contains(rangeRef, "$"))
|
||||||
|
}
|
||||||
// Create a pseudo GUID for each unique rule.
|
// Create a pseudo GUID for each unique rule.
|
||||||
var rules int
|
var rules int
|
||||||
for _, cf := range ws.ConditionalFormatting {
|
for _, cf := range ws.ConditionalFormatting {
|
||||||
rules += len(cf.CfRule)
|
rules += len(cf.CfRule)
|
||||||
}
|
}
|
||||||
GUID := fmt.Sprintf("{00000000-0000-0000-%04X-%012X}", f.getSheetID(sheet), rules)
|
var (
|
||||||
var cfRule []*xlsxCfRule
|
GUID = fmt.Sprintf("{00000000-0000-0000-%04X-%012X}", f.getSheetID(sheet), rules)
|
||||||
|
cfRule []*xlsxCfRule
|
||||||
|
noCriteriaTypes = []string{
|
||||||
|
"containsBlanks",
|
||||||
|
"notContainsBlanks",
|
||||||
|
"containsErrors",
|
||||||
|
"notContainsErrors",
|
||||||
|
"expression",
|
||||||
|
"iconSet",
|
||||||
|
}
|
||||||
|
)
|
||||||
for p, v := range opts {
|
for p, v := range opts {
|
||||||
var vt, ct string
|
var vt, ct string
|
||||||
var ok bool
|
var ok bool
|
||||||
|
@ -2650,10 +2681,10 @@ func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFo
|
||||||
if ok {
|
if ok {
|
||||||
// Check for valid criteria types.
|
// Check for valid criteria types.
|
||||||
ct, ok = criteriaType[v.Criteria]
|
ct, ok = criteriaType[v.Criteria]
|
||||||
if ok || vt == "expression" || vt == "iconSet" {
|
if ok || inStrSlice(noCriteriaTypes, vt, true) != -1 {
|
||||||
drawFunc, ok := drawContFmtFunc[vt]
|
drawFunc, ok := drawContFmtFunc[vt]
|
||||||
if ok {
|
if ok {
|
||||||
rule, x14rule := drawFunc(p, ct, GUID, &v)
|
rule, x14rule := drawFunc(p, ct, strings.Split(rangeRef, ":")[0], GUID, &v)
|
||||||
if rule == nil {
|
if rule == nil {
|
||||||
return ErrParameterInvalid
|
return ErrParameterInvalid
|
||||||
}
|
}
|
||||||
|
@ -2669,6 +2700,7 @@ func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFo
|
||||||
}
|
}
|
||||||
return ErrParameterInvalid
|
return ErrParameterInvalid
|
||||||
}
|
}
|
||||||
|
return ErrParameterInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.ConditionalFormatting = append(ws.ConditionalFormatting, &xlsxConditionalFormatting{
|
ws.ConditionalFormatting = append(ws.ConditionalFormatting, &xlsxConditionalFormatting{
|
||||||
|
@ -2740,6 +2772,12 @@ func extractCondFmtCellIs(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOp
|
||||||
return format
|
return format
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractCondFmtText provides a function to extract conditional format
|
||||||
|
// settings for text cell values by given conditional formatting rule.
|
||||||
|
func extractCondFmtText(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
|
||||||
|
return ConditionalFormatOptions{StopIfTrue: c.StopIfTrue, Type: "text", Criteria: operatorType[c.Operator], Format: *c.DxfID, Value: c.Text}
|
||||||
|
}
|
||||||
|
|
||||||
// extractCondFmtTop10 provides a function to extract conditional format
|
// extractCondFmtTop10 provides a function to extract conditional format
|
||||||
// settings for top N (default is top 10) by given conditional formatting
|
// settings for top N (default is top 10) by given conditional formatting
|
||||||
// rule.
|
// rule.
|
||||||
|
@ -2786,6 +2824,46 @@ func extractCondFmtDuplicateUniqueValues(c *xlsxCfRule, extLst *xlsxExtLst) Cond
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractCondFmtBlanks provides a function to extract conditional format
|
||||||
|
// settings for blank cells by given conditional formatting rule.
|
||||||
|
func extractCondFmtBlanks(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
|
||||||
|
return ConditionalFormatOptions{
|
||||||
|
StopIfTrue: c.StopIfTrue,
|
||||||
|
Type: "blanks",
|
||||||
|
Format: *c.DxfID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractCondFmtNoBlanks provides a function to extract conditional format
|
||||||
|
// settings for no blank cells by given conditional formatting rule.
|
||||||
|
func extractCondFmtNoBlanks(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
|
||||||
|
return ConditionalFormatOptions{
|
||||||
|
StopIfTrue: c.StopIfTrue,
|
||||||
|
Type: "no_blanks",
|
||||||
|
Format: *c.DxfID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractCondFmtErrors provides a function to extract conditional format
|
||||||
|
// settings for cells with errors by given conditional formatting rule.
|
||||||
|
func extractCondFmtErrors(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
|
||||||
|
return ConditionalFormatOptions{
|
||||||
|
StopIfTrue: c.StopIfTrue,
|
||||||
|
Type: "errors",
|
||||||
|
Format: *c.DxfID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractCondFmtNoErrors provides a function to extract conditional format
|
||||||
|
// settings for cells without errors by given conditional formatting rule.
|
||||||
|
func extractCondFmtNoErrors(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
|
||||||
|
return ConditionalFormatOptions{
|
||||||
|
StopIfTrue: c.StopIfTrue,
|
||||||
|
Type: "no_errors",
|
||||||
|
Format: *c.DxfID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// extractCondFmtColorScale provides a function to extract conditional format
|
// extractCondFmtColorScale provides a function to extract conditional format
|
||||||
// settings for color scale (include 2 color scale and 3 color scale) by given
|
// settings for color scale (include 2 color scale and 3 color scale) by given
|
||||||
// conditional formatting rule.
|
// conditional formatting rule.
|
||||||
|
@ -2938,7 +3016,7 @@ func (f *File) UnsetConditionalFormat(sheet, rangeRef string) error {
|
||||||
// drawCondFmtCellIs provides a function to create conditional formatting rule
|
// drawCondFmtCellIs provides a function to create conditional formatting rule
|
||||||
// for cell value (include between, not between, equal, not equal, greater
|
// for cell value (include between, not between, equal, not equal, greater
|
||||||
// than and less than) by given priority, criteria type and format settings.
|
// than and less than) by given priority, criteria type and format settings.
|
||||||
func drawCondFmtCellIs(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
func drawCondFmtCellIs(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
c := &xlsxCfRule{
|
c := &xlsxCfRule{
|
||||||
Priority: p + 1,
|
Priority: p + 1,
|
||||||
StopIfTrue: format.StopIfTrue,
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
@ -2950,16 +3028,46 @@ func drawCondFmtCellIs(p int, ct, GUID string, format *ConditionalFormatOptions)
|
||||||
if ct == "between" || ct == "notBetween" {
|
if ct == "between" || ct == "notBetween" {
|
||||||
c.Formula = append(c.Formula, []string{format.MinValue, format.MaxValue}...)
|
c.Formula = append(c.Formula, []string{format.MinValue, format.MaxValue}...)
|
||||||
}
|
}
|
||||||
if idx := inStrSlice([]string{"equal", "notEqual", "greaterThan", "lessThan", "greaterThanOrEqual", "lessThanOrEqual", "containsText", "notContains", "beginsWith", "endsWith"}, ct, true); idx != -1 {
|
if inStrSlice([]string{"equal", "notEqual", "greaterThan", "lessThan", "greaterThanOrEqual", "lessThanOrEqual", "containsText", "notContains", "beginsWith", "endsWith"}, ct, true) != -1 {
|
||||||
c.Formula = append(c.Formula, format.Value)
|
c.Formula = append(c.Formula, format.Value)
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// drawCondFmtText provides a function to create conditional formatting rule for
|
||||||
|
// text cell values by given priority, criteria type and format settings.
|
||||||
|
func drawCondFmtText(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
|
return &xlsxCfRule{
|
||||||
|
Priority: p + 1,
|
||||||
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
Type: map[string]string{
|
||||||
|
"containsText": "containsText",
|
||||||
|
"notContains": "notContainsText",
|
||||||
|
"beginsWith": "beginsWith",
|
||||||
|
"endsWith": "endsWith",
|
||||||
|
}[ct],
|
||||||
|
Text: format.Value,
|
||||||
|
Operator: ct,
|
||||||
|
Formula: []string{
|
||||||
|
map[string]string{
|
||||||
|
"containsText": fmt.Sprintf("NOT(ISERROR(SEARCH(\"%s\",%s)))",
|
||||||
|
strings.NewReplacer(`"`, `""`).Replace(format.Value), ref),
|
||||||
|
"notContains": fmt.Sprintf("ISERROR(SEARCH(\"%s\",%s))",
|
||||||
|
strings.NewReplacer(`"`, `""`).Replace(format.Value), ref),
|
||||||
|
"beginsWith": fmt.Sprintf("LEFT(%[2]s,LEN(\"%[1]s\"))=\"%[1]s\"",
|
||||||
|
strings.NewReplacer(`"`, `""`).Replace(format.Value), ref),
|
||||||
|
"endsWith": fmt.Sprintf("RIGHT(%[2]s,LEN(\"%[1]s\"))=\"%[1]s\"",
|
||||||
|
strings.NewReplacer(`"`, `""`).Replace(format.Value), ref),
|
||||||
|
}[ct],
|
||||||
|
},
|
||||||
|
DxfID: intPtr(format.Format),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// drawCondFmtTop10 provides a function to create conditional formatting rule
|
// drawCondFmtTop10 provides a function to create conditional formatting rule
|
||||||
// for top N (default is top 10) by given priority, criteria type and format
|
// for top N (default is top 10) by given priority, criteria type and format
|
||||||
// settings.
|
// settings.
|
||||||
func drawCondFmtTop10(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
func drawCondFmtTop10(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
c := &xlsxCfRule{
|
c := &xlsxCfRule{
|
||||||
Priority: p + 1,
|
Priority: p + 1,
|
||||||
StopIfTrue: format.StopIfTrue,
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
@ -2978,7 +3086,7 @@ func drawCondFmtTop10(p int, ct, GUID string, format *ConditionalFormatOptions)
|
||||||
// drawCondFmtAboveAverage provides a function to create conditional
|
// drawCondFmtAboveAverage provides a function to create conditional
|
||||||
// formatting rule for above average and below average by given priority,
|
// formatting rule for above average and below average by given priority,
|
||||||
// criteria type and format settings.
|
// criteria type and format settings.
|
||||||
func drawCondFmtAboveAverage(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
func drawCondFmtAboveAverage(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
return &xlsxCfRule{
|
return &xlsxCfRule{
|
||||||
Priority: p + 1,
|
Priority: p + 1,
|
||||||
StopIfTrue: format.StopIfTrue,
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
@ -2991,7 +3099,7 @@ func drawCondFmtAboveAverage(p int, ct, GUID string, format *ConditionalFormatOp
|
||||||
// drawCondFmtDuplicateUniqueValues provides a function to create conditional
|
// drawCondFmtDuplicateUniqueValues provides a function to create conditional
|
||||||
// formatting rule for duplicate and unique values by given priority, criteria
|
// formatting rule for duplicate and unique values by given priority, criteria
|
||||||
// type and format settings.
|
// type and format settings.
|
||||||
func drawCondFmtDuplicateUniqueValues(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
func drawCondFmtDuplicateUniqueValues(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
return &xlsxCfRule{
|
return &xlsxCfRule{
|
||||||
Priority: p + 1,
|
Priority: p + 1,
|
||||||
StopIfTrue: format.StopIfTrue,
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
@ -3003,7 +3111,7 @@ func drawCondFmtDuplicateUniqueValues(p int, ct, GUID string, format *Conditiona
|
||||||
// drawCondFmtColorScale provides a function to create conditional formatting
|
// drawCondFmtColorScale provides a function to create conditional formatting
|
||||||
// rule for color scale (include 2 color scale and 3 color scale) by given
|
// rule for color scale (include 2 color scale and 3 color scale) by given
|
||||||
// priority, criteria type and format settings.
|
// priority, criteria type and format settings.
|
||||||
func drawCondFmtColorScale(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
func drawCondFmtColorScale(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
minValue := format.MinValue
|
minValue := format.MinValue
|
||||||
if minValue == "" {
|
if minValue == "" {
|
||||||
minValue = "0"
|
minValue = "0"
|
||||||
|
@ -3041,7 +3149,7 @@ func drawCondFmtColorScale(p int, ct, GUID string, format *ConditionalFormatOpti
|
||||||
|
|
||||||
// drawCondFmtDataBar provides a function to create conditional formatting
|
// drawCondFmtDataBar provides a function to create conditional formatting
|
||||||
// rule for data bar by given priority, criteria type and format settings.
|
// rule for data bar by given priority, criteria type and format settings.
|
||||||
func drawCondFmtDataBar(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
func drawCondFmtDataBar(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
var x14CfRule *xlsxX14CfRule
|
var x14CfRule *xlsxX14CfRule
|
||||||
var extLst *xlsxExtLst
|
var extLst *xlsxExtLst
|
||||||
if format.BarSolid || format.BarDirection == "leftToRight" || format.BarDirection == "rightToLeft" || format.BarBorderColor != "" {
|
if format.BarSolid || format.BarDirection == "leftToRight" || format.BarDirection == "rightToLeft" || format.BarBorderColor != "" {
|
||||||
|
@ -3078,7 +3186,7 @@ func drawCondFmtDataBar(p int, ct, GUID string, format *ConditionalFormatOptions
|
||||||
|
|
||||||
// drawCondFmtExp provides a function to create conditional formatting rule
|
// drawCondFmtExp provides a function to create conditional formatting rule
|
||||||
// for expression by given priority, criteria type and format settings.
|
// for expression by given priority, criteria type and format settings.
|
||||||
func drawCondFmtExp(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
func drawCondFmtExp(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
return &xlsxCfRule{
|
return &xlsxCfRule{
|
||||||
Priority: p + 1,
|
Priority: p + 1,
|
||||||
StopIfTrue: format.StopIfTrue,
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
@ -3088,9 +3196,57 @@ func drawCondFmtExp(p int, ct, GUID string, format *ConditionalFormatOptions) (*
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// drawCondFmtErrors provides a function to create conditional formatting rule
|
||||||
|
// for cells with errors by given priority, criteria type and format settings.
|
||||||
|
func drawCondFmtErrors(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
|
return &xlsxCfRule{
|
||||||
|
Priority: p + 1,
|
||||||
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
Type: validType[format.Type],
|
||||||
|
Formula: []string{fmt.Sprintf("ISERROR(%s)", ref)},
|
||||||
|
DxfID: intPtr(format.Format),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// drawCondFmtErrors provides a function to create conditional formatting rule
|
||||||
|
// for cells without errors by given priority, criteria type and format settings.
|
||||||
|
func drawCondFmtNoErrors(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
|
return &xlsxCfRule{
|
||||||
|
Priority: p + 1,
|
||||||
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
Type: validType[format.Type],
|
||||||
|
Formula: []string{fmt.Sprintf("NOT(ISERROR(%s))", ref)},
|
||||||
|
DxfID: intPtr(format.Format),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// drawCondFmtErrors provides a function to create conditional formatting rule
|
||||||
|
// for blank cells by given priority, criteria type and format settings.
|
||||||
|
func drawCondFmtBlanks(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
|
return &xlsxCfRule{
|
||||||
|
Priority: p + 1,
|
||||||
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
Type: validType[format.Type],
|
||||||
|
Formula: []string{fmt.Sprintf("LEN(TRIM(%s))=0", ref)},
|
||||||
|
DxfID: intPtr(format.Format),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// drawCondFmtErrors provides a function to create conditional formatting rule
|
||||||
|
// for no blanks cells by given priority, criteria type and format settings.
|
||||||
|
func drawCondFmtNoBlanks(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
|
return &xlsxCfRule{
|
||||||
|
Priority: p + 1,
|
||||||
|
StopIfTrue: format.StopIfTrue,
|
||||||
|
Type: validType[format.Type],
|
||||||
|
Formula: []string{fmt.Sprintf("LEN(TRIM(%s))>0", ref)},
|
||||||
|
DxfID: intPtr(format.Format),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// drawCondFmtIconSet provides a function to create conditional formatting rule
|
// drawCondFmtIconSet provides a function to create conditional formatting rule
|
||||||
// for icon set by given priority, criteria type and format settings.
|
// for icon set by given priority, criteria type and format settings.
|
||||||
func drawCondFmtIconSet(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
func drawCondFmtIconSet(p int, ct, ref, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
|
||||||
cfvo3 := &xlsxCfRule{IconSet: &xlsxIconSet{Cfvo: []*xlsxCfvo{
|
cfvo3 := &xlsxCfRule{IconSet: &xlsxIconSet{Cfvo: []*xlsxCfvo{
|
||||||
{Type: "percent", Val: "0"},
|
{Type: "percent", Val: "0"},
|
||||||
{Type: "percent", Val: "33"},
|
{Type: "percent", Val: "33"},
|
||||||
|
|
|
@ -195,12 +195,7 @@ func TestSetConditionalFormat(t *testing.T) {
|
||||||
for _, val := range []string{
|
for _, val := range []string{
|
||||||
"date",
|
"date",
|
||||||
"time",
|
"time",
|
||||||
"text",
|
|
||||||
"time_period",
|
"time_period",
|
||||||
"blanks",
|
|
||||||
"no_blanks",
|
|
||||||
"errors",
|
|
||||||
"no_errors",
|
|
||||||
} {
|
} {
|
||||||
assert.Equal(t, ErrParameterInvalid, f.SetConditionalFormat("Sheet1", "A1", []ConditionalFormatOptions{{Type: val}}))
|
assert.Equal(t, ErrParameterInvalid, f.SetConditionalFormat("Sheet1", "A1", []ConditionalFormatOptions{{Type: val}}))
|
||||||
}
|
}
|
||||||
|
@ -210,6 +205,10 @@ func TestGetConditionalFormats(t *testing.T) {
|
||||||
for _, format := range [][]ConditionalFormatOptions{
|
for _, format := range [][]ConditionalFormatOptions{
|
||||||
{{Type: "cell", Format: 1, Criteria: "greater than", Value: "6"}},
|
{{Type: "cell", Format: 1, Criteria: "greater than", Value: "6"}},
|
||||||
{{Type: "cell", Format: 1, Criteria: "between", MinValue: "6", MaxValue: "8"}},
|
{{Type: "cell", Format: 1, Criteria: "between", MinValue: "6", MaxValue: "8"}},
|
||||||
|
{{Type: "text", Format: 1, Criteria: "containing", Value: "~!@#$%^&*()_+{}|:<>?\"';"}},
|
||||||
|
{{Type: "text", Format: 1, Criteria: "not containing", Value: "text"}},
|
||||||
|
{{Type: "text", Format: 1, Criteria: "begins with", Value: "prefix"}},
|
||||||
|
{{Type: "text", Format: 1, Criteria: "ends with", Value: "suffix"}},
|
||||||
{{Type: "top", Format: 1, Criteria: "=", Value: "6"}},
|
{{Type: "top", Format: 1, Criteria: "=", Value: "6"}},
|
||||||
{{Type: "bottom", Format: 1, Criteria: "=", Value: "6"}},
|
{{Type: "bottom", Format: 1, Criteria: "=", Value: "6"}},
|
||||||
{{Type: "average", AboveAverage: true, Format: 1, Criteria: "="}},
|
{{Type: "average", AboveAverage: true, Format: 1, Criteria: "="}},
|
||||||
|
@ -220,10 +219,14 @@ func TestGetConditionalFormats(t *testing.T) {
|
||||||
{{Type: "data_bar", Criteria: "=", MinType: "num", MaxType: "num", MinValue: "-10", MaxValue: "10", BarBorderColor: "#0000FF", BarColor: "#638EC6", BarOnly: true, BarSolid: true, StopIfTrue: true}},
|
{{Type: "data_bar", Criteria: "=", MinType: "num", MaxType: "num", MinValue: "-10", MaxValue: "10", BarBorderColor: "#0000FF", BarColor: "#638EC6", BarOnly: true, BarSolid: true, StopIfTrue: true}},
|
||||||
{{Type: "data_bar", Criteria: "=", MinType: "min", MaxType: "max", BarBorderColor: "#0000FF", BarColor: "#638EC6", BarDirection: "rightToLeft", BarOnly: true, BarSolid: true, StopIfTrue: true}},
|
{{Type: "data_bar", Criteria: "=", MinType: "min", MaxType: "max", BarBorderColor: "#0000FF", BarColor: "#638EC6", BarDirection: "rightToLeft", BarOnly: true, BarSolid: true, StopIfTrue: true}},
|
||||||
{{Type: "formula", Format: 1, Criteria: "="}},
|
{{Type: "formula", Format: 1, Criteria: "="}},
|
||||||
|
{{Type: "blanks", Format: 1}},
|
||||||
|
{{Type: "no_blanks", Format: 1}},
|
||||||
|
{{Type: "errors", Format: 1}},
|
||||||
|
{{Type: "no_errors", Format: 1}},
|
||||||
{{Type: "icon_set", IconStyle: "3Arrows", ReverseIcons: true, IconsOnly: true}},
|
{{Type: "icon_set", IconStyle: "3Arrows", ReverseIcons: true, IconsOnly: true}},
|
||||||
} {
|
} {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
err := f.SetConditionalFormat("Sheet1", "A1:A2", format)
|
err := f.SetConditionalFormat("Sheet1", "A2:A1", format)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
opts, err := f.GetConditionalFormats("Sheet1")
|
opts, err := f.GetConditionalFormats("Sheet1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
Loading…
Reference in New Issue