Files
larksuite--cli/shortcuts/sheets/csv_put_range_alias_test.go
wehub-resource-sync bf9395e022
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:22:54 +08:00

87 lines
3.4 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package sheets
import (
"testing"
)
// +csv-put locates with --start-cell, while +csv-get / +cells-set locate with
// --range. Agents routinely carry --range over to +csv-put and hit a guaranteed
// first-try failure. csvPutInput now accepts --range as an alias for
// --start-cell; a range value collapses to its top-left cell.
func TestCsvPutInput_RangeAliasForStartCell(t *testing.T) {
tests := []struct {
name string
raw map[string]interface{}
wantAnchor string
}{
{"start-cell direct (unchanged)", map[string]interface{}{"csv": "a,b", "start-cell": "B2"}, "B2"},
{"range alias, single cell", map[string]interface{}{"csv": "a,b", "range": "B2"}, "B2"},
{"range alias collapses to top-left", map[string]interface{}{"csv": "a,b", "range": "A1:H17"}, "A1"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fv := newMapFlagViewForCommand("+csv-put", tt.raw)
input, err := csvPutInput(fv, "tok", "sid", "")
if err != nil {
t.Fatalf("csvPutInput returned error: %v", err)
}
got, _ := input["start_cell"].(string)
if got != tt.wantAnchor {
t.Errorf("start_cell = %q, want %q", got, tt.wantAnchor)
}
})
}
}
func TestCsvPutInput_RejectsStartCellAndRangeTogether(t *testing.T) {
fv := newMapFlagViewForCommand("+csv-put", map[string]interface{}{
"csv": "a,b",
"start-cell": "C3",
"range": "A1:H17",
})
_, err := csvPutInput(fv, "tok", "sid", "")
requireValidation(t, err, "--start-cell and --range are mutually exclusive")
}
// With neither --start-cell nor --range explicitly set, csvPutInput rejects the
// call instead of silently anchoring at the "A1" flag default. Standalone never
// reaches this path — cobra's MarkFlagsOneRequired(start-cell, range) catches it
// first — but a +batch-update sub-op skips cobra, so the guard must live in the
// shared builder too. Otherwise a batch +csv-put with no anchor silently pastes
// at A1, diverging from the standalone contract.
func TestCsvPutInput_RequiresStartCellOrRange(t *testing.T) {
fv := newMapFlagViewForCommand("+csv-put", map[string]interface{}{"csv": "a,b"})
_, err := csvPutInput(fv, "tok", "sid", "")
requireValidation(t, err, "--start-cell or --range is required")
}
// csvPutWriteRangeFromInput surfaces the real paste footprint so agents can see
// how far a CSV reaches from its anchor — it auto-expands to the CSV's own size,
// not to any user-set range.
func TestCsvPutWriteRangeFromInput(t *testing.T) {
tests := []struct {
name string
input map[string]interface{}
want string
ok bool
}{
{"3x3 at B2", map[string]interface{}{"start_cell": "B2", "csv": "a,b,c\n1,2,3\n4,5,6"}, "B2:D4", true},
{"single cell at A1", map[string]interface{}{"start_cell": "A1", "csv": "x"}, "A1:A1", true},
{"1 row 3 cols at C3", map[string]interface{}{"start_cell": "C3", "csv": "a,b,c"}, "C3:E3", true},
{"ragged rows use max width", map[string]interface{}{"start_cell": "A1", "csv": "a,b\nc,d,e"}, "A1:C2", true},
{"missing csv", map[string]interface{}{"start_cell": "A1"}, "", false},
{"non-single anchor", map[string]interface{}{"start_cell": "A1:B2", "csv": "x"}, "", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, ok := csvPutWriteRangeFromInput(tt.input)
if ok != tt.ok || got != tt.want {
t.Errorf("got (%q, %v), want (%q, %v)", got, ok, tt.want, tt.ok)
}
})
}
}