Skip to content

Commit 97fd800

Browse files
committed
Add unit tests for the formula function UNIQUE
- Update dependencies modules
1 parent 8c97b95 commit 97fd800

File tree

4 files changed

+39
-33
lines changed

4 files changed

+39
-33
lines changed

calc.go

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14582,21 +14582,19 @@ func (fn *formulaFuncs) UNICODE(argsList *list.List) formulaArg {
1458214582
return fn.code("UNICODE", argsList)
1458314583
}
1458414584

14585-
// UNIQUE function returns a list of unique values in a list or range.
14586-
// For syntax refer to
14587-
// https://support.microsoft.com/en-us/office/unique-function-c5ab87fd-30a3-4ce9-9d1a-40204fb85e1e.
14585+
// UNIQUE function returns a list of unique values in a list or range. The
14586+
// syntax of the function is:
14587+
//
14588+
// UNIQUE(array,[by_col],[exactly_once])
1458814589
func (fn *formulaFuncs) UNIQUE(argsList *list.List) formulaArg {
1458914590
args, errArg := getFormulaUniqueArgs(argsList)
1459014591
if errArg != nil {
1459114592
return *errArg
1459214593
}
14593-
1459414594
if args.byColumn {
1459514595
args.cellRange, args.cols, args.rows = transposeFormulaArgsList(args.cellRange, args.cols, args.rows)
1459614596
}
14597-
1459814597
counts := map[string]int{}
14599-
1460014598
for i := 0; i < len(args.cellRange); i += args.cols {
1460114599
key := concatValues(args.cellRange[i : i+args.cols])
1460214600

@@ -14605,9 +14603,7 @@ func (fn *formulaFuncs) UNIQUE(argsList *list.List) formulaArg {
1460514603
}
1460614604
counts[key]++
1460714605
}
14608-
1460914606
uniqueAxes := [][]formulaArg{}
14610-
1461114607
for i := 0; i < len(args.cellRange); i += args.cols {
1461214608
key := concatValues(args.cellRange[i : i+args.cols])
1461314609

@@ -14616,37 +14612,33 @@ func (fn *formulaFuncs) UNIQUE(argsList *list.List) formulaArg {
1461614612
}
1461714613
delete(counts, key)
1461814614
}
14619-
1462014615
if args.byColumn {
1462114616
uniqueAxes = transposeFormulaArgsMatrix(uniqueAxes)
1462214617
}
14623-
1462414618
return newMatrixFormulaArg(uniqueAxes)
1462514619
}
1462614620

14621+
// transposeFormulaArgsMatrix transposes a 2D slice of formulaArg.
1462714622
func transposeFormulaArgsMatrix(args [][]formulaArg) [][]formulaArg {
1462814623
if len(args) == 0 {
1462914624
return args
1463014625
}
14631-
1463214626
transposedArgs := make([][]formulaArg, len(args[0]))
14633-
1463414627
for i := 0; i < len(args[0]); i++ {
1463514628
transposedArgs[i] = make([]formulaArg, len(args))
1463614629
}
14637-
1463814630
for i := 0; i < len(args); i++ {
1463914631
for j := 0; j < len(args[i]); j++ {
1464014632
transposedArgs[j][i] = args[i][j]
1464114633
}
1464214634
}
14643-
1464414635
return transposedArgs
1464514636
}
1464614637

14638+
// transposeFormulaArgsList transposes a flat slice of formulaArg given the
14639+
// number of columns and rows.
1464714640
func transposeFormulaArgsList(args []formulaArg, cols, rows int) ([]formulaArg, int, int) {
1464814641
transposedArgs := make([]formulaArg, len(args))
14649-
1465014642
for i := 0; i < rows; i++ {
1465114643
for j := 0; j < cols; j++ {
1465214644
transposedArgs[j*rows+i] = args[i*cols+j]
@@ -14655,6 +14647,8 @@ func transposeFormulaArgsList(args []formulaArg, cols, rows int) ([]formulaArg,
1465514647
return transposedArgs, rows, cols
1465614648
}
1465714649

14650+
// concatValues concatenates the values of a slice of formulaArg into a single
14651+
// string.
1465814652
func concatValues(args []formulaArg) string {
1465914653
val := ""
1466014654
for _, arg := range args {
@@ -14664,6 +14658,7 @@ func concatValues(args []formulaArg) string {
1466414658
return val
1466514659
}
1466614660

14661+
// uniqueArgs holds the parsed arguments for the UNIQUE function.
1466714662
type uniqueArgs struct {
1466814663
cellRange []formulaArg
1466914664
cols int
@@ -14672,22 +14667,21 @@ type uniqueArgs struct {
1467214667
exactlyOnce bool
1467314668
}
1467414669

14670+
// getFormulaUniqueArgs parses and validates the arguments for the UNIQUE
14671+
// function.
1467514672
func getFormulaUniqueArgs(argsList *list.List) (uniqueArgs, *formulaArg) {
1467614673
res := uniqueArgs{}
14677-
1467814674
argsLen := argsList.Len()
1467914675
if argsLen == 0 {
1468014676
errArg := newErrorFormulaArg(formulaErrorVALUE, "UNIQUE requires at least 1 argument")
1468114677
return res, &errArg
1468214678
}
14683-
1468414679
if argsLen > 3 {
1468514680
msg := fmt.Sprintf("UNIQUE takes at most 3 arguments, received %d arguments", argsLen)
1468614681
errArg := newErrorFormulaArg(formulaErrorVALUE, msg)
1468714682

1468814683
return res, &errArg
1468914684
}
14690-
1469114685
firstArg := argsList.Front()
1469214686
res.cellRange = firstArg.Value.(formulaArg).ToList()
1469314687
if len(res.cellRange) == 0 {
@@ -14697,33 +14691,27 @@ func getFormulaUniqueArgs(argsList *list.List) (uniqueArgs, *formulaArg) {
1469714691
if res.cellRange[0].Type == ArgError {
1469814692
return res, &res.cellRange[0]
1469914693
}
14700-
1470114694
rmin, rmax := calcColsRowsMinMax(false, argsList)
1470214695
cmin, cmax := calcColsRowsMinMax(true, argsList)
1470314696
res.cols, res.rows = cmax-cmin+1, rmax-rmin+1
14704-
1470514697
secondArg := firstArg.Next()
1470614698
if secondArg == nil {
1470714699
return res, nil
1470814700
}
14709-
1471014701
argByColumn := secondArg.Value.(formulaArg).ToBool()
1471114702
if argByColumn.Type == ArgError {
1471214703
return res, &argByColumn
1471314704
}
1471414705
res.byColumn = (argByColumn.Value() == "TRUE")
14715-
1471614706
thirdArg := secondArg.Next()
1471714707
if thirdArg == nil {
1471814708
return res, nil
1471914709
}
14720-
1472114710
argExactlyOnce := thirdArg.Value.(formulaArg).ToBool()
1472214711
if argExactlyOnce.Type == ArgError {
1472314712
return res, &argExactlyOnce
1472414713
}
1472514714
res.exactlyOnce = (argExactlyOnce.Value() == "TRUE")
14726-
1472714715
return res, nil
1472814716
}
1472914717

calc_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5240,6 +5240,24 @@ func TestCalcUniqueErrors(t *testing.T) {
52405240
}
52415241
}
52425242

5243+
func TestTransposeFormulaArgsMatrix(t *testing.T) {
5244+
assert.Empty(t, transposeFormulaArgsMatrix([][]formulaArg{}))
5245+
}
5246+
5247+
func TestGetFormulaUniqueArgs(t *testing.T) {
5248+
argsList := list.New()
5249+
emptyArg := newEmptyFormulaArg()
5250+
argsList.PushBack(emptyArg)
5251+
5252+
_, err := getFormulaUniqueArgs(argsList)
5253+
assert.Equal(t, "missing first argument to UNIQUE", err.Error)
5254+
5255+
argsList = list.New()
5256+
argsList.PushBack(newListFormulaArg([]formulaArg{newErrorFormulaArg(formulaErrorNAME, formulaErrorNAME)}))
5257+
_, err = getFormulaUniqueArgs(argsList)
5258+
assert.Equal(t, formulaErrorNAME, err.Error)
5259+
}
5260+
52435261
func TestCalcDatabase(t *testing.T) {
52445262
cellData := [][]interface{}{
52455263
{"Tree", "Height", "Age", "Yield", "Profit", "Height"},

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ require (
88
github.com/tiendc/go-deepcopy v1.7.1
99
github.com/xuri/efp v0.0.1
1010
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9
11-
golang.org/x/crypto v0.43.0
11+
golang.org/x/crypto v0.45.0
1212
golang.org/x/image v0.25.0
13-
golang.org/x/net v0.46.0
14-
golang.org/x/text v0.30.0
13+
golang.org/x/net v0.47.0
14+
golang.org/x/text v0.31.0
1515
)
1616

1717
require (

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
1515
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
1616
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
1717
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
18-
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
19-
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
18+
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
19+
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
2020
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
2121
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
22-
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
23-
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
24-
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
25-
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
22+
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
23+
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
24+
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
25+
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
2626
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2727
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2828
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

0 commit comments

Comments
 (0)