mirror of
https://github.com/larksuite/cli.git
synced 2026-07-06 00:06:28 +08:00
150 lines
6.3 KiB
Go
150 lines
6.3 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package common
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/larksuite/cli/internal/core"
|
|
)
|
|
|
|
func TestParseResourceURL(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
rawURL string
|
|
wantType string
|
|
wantToken string
|
|
wantOK bool
|
|
}{
|
|
// All 9 supported types
|
|
{"docx", "https://xxx.feishu.cn/docx/doxcnABC", "docx", "doxcnABC", true},
|
|
{"doc", "https://xxx.feishu.cn/doc/doccnABC", "doc", "doccnABC", true},
|
|
{"sheet", "https://xxx.feishu.cn/sheets/shtcnABC", "sheet", "shtcnABC", true},
|
|
{"bitable via /base/", "https://xxx.feishu.cn/base/bascnABC", "bitable", "bascnABC", true},
|
|
{"bitable via /bitable/", "https://xxx.feishu.cn/bitable/bascnABC", "bitable", "bascnABC", true},
|
|
{"wiki", "https://xxx.feishu.cn/wiki/wikcnABC", "wiki", "wikcnABC", true},
|
|
{"file", "https://xxx.feishu.cn/file/boxcnABC", "file", "boxcnABC", true},
|
|
{"folder", "https://xxx.feishu.cn/drive/folder/fldcnABC", "folder", "fldcnABC", true},
|
|
{"file via /drive/file/", "https://feishu.doubao.com/drive/file/boxcnABC", "file", "boxcnABC", true},
|
|
{"folder via /chat/drive/", "https://feishu.doubao.com/chat/drive/fldcnABC", "folder", "fldcnABC", true},
|
|
{"folder via /drive/shr/", "https://feishu.doubao.com/drive/shr/fldcnABC", "folder", "fldcnABC", true},
|
|
{"mindnote", "https://xxx.feishu.cn/mindnote/mncnABC", "mindnote", "mncnABC", true},
|
|
{"slides", "https://xxx.feishu.cn/slides/slkcnABC", "slides", "slkcnABC", true},
|
|
|
|
// Lark domain
|
|
{"lark docx", "https://xxx.larksuite.com/docx/doxcnABC", "docx", "doxcnABC", true},
|
|
{"lark wiki", "https://xxx.larksuite.com/wiki/wikcnABC", "wiki", "wikcnABC", true},
|
|
|
|
// With query parameters
|
|
{"with query", "https://xxx.feishu.cn/docx/doxcnABC?from=wiki", "docx", "doxcnABC", true},
|
|
{"with fragment", "https://xxx.feishu.cn/docx/doxcnABC#section", "docx", "doxcnABC", true},
|
|
|
|
// With trailing slash
|
|
{"trailing slash", "https://xxx.feishu.cn/docx/doxcnABC/", "docx", "doxcnABC", true},
|
|
|
|
// With extra path segments after token
|
|
{"extra path", "https://xxx.feishu.cn/docx/doxcnABC/edit", "docx", "doxcnABC", true},
|
|
|
|
// Non-Lark host with Lark-like path (host validation is the caller's responsibility)
|
|
{"non-lark host with lark path", "https://google.com/docx/doxcnABC", "docx", "doxcnABC", true},
|
|
|
|
// Negative cases
|
|
{"unrecognized path", "https://xxx.feishu.cn/calendar/calABC", "", "", false},
|
|
{"non-lark host unrecognized path", "https://example.com/page", "", "", false},
|
|
{"empty input", "", "", "", false},
|
|
{"bare token", "doxcnABC", "", "", false},
|
|
{"invalid url parse", "://not-a-valid-url", "", "", false},
|
|
{"matching prefix but empty token", "https://xxx.feishu.cn/docx/", "", "", false},
|
|
{"matching prefix but whitespace-only token", "https://xxx.feishu.cn/docx/ ", "", "", false},
|
|
{"whitespace-only input", " ", "", "", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ref, ok := ParseResourceURL(tt.rawURL)
|
|
if ok != tt.wantOK {
|
|
t.Errorf("ParseResourceURL(%q) ok = %v, want %v", tt.rawURL, ok, tt.wantOK)
|
|
}
|
|
if ok {
|
|
if ref.Type != tt.wantType {
|
|
t.Errorf("ParseResourceURL(%q) Type = %q, want %q", tt.rawURL, ref.Type, tt.wantType)
|
|
}
|
|
if ref.Token != tt.wantToken {
|
|
t.Errorf("ParseResourceURL(%q) Token = %q, want %q", tt.rawURL, ref.Token, tt.wantToken)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestParseResourceURL_RoundTrip verifies that ParseResourceURL is the inverse
|
|
// of BuildResourceURL for all supported types.
|
|
func TestParseResourceURL_RoundTrip(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
types := []string{"docx", "doc", "sheet", "bitable", "wiki", "file", "folder", "mindnote", "slides"}
|
|
token := "testTOKEN123"
|
|
|
|
for _, kind := range types {
|
|
t.Run(kind, func(t *testing.T) {
|
|
built := BuildResourceURL(core.BrandFeishu, kind, token)
|
|
if built == "" {
|
|
t.Fatalf("BuildResourceURL returned empty for kind %q", kind)
|
|
}
|
|
ref, ok := ParseResourceURL(built)
|
|
if !ok {
|
|
t.Fatalf("ParseResourceURL(%q) returned ok=false", built)
|
|
}
|
|
if ref.Type != kind {
|
|
t.Errorf("round-trip type mismatch: got %q, want %q", ref.Type, kind)
|
|
}
|
|
if ref.Token != token {
|
|
t.Errorf("round-trip token mismatch: got %q, want %q", ref.Token, token)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildResourceURL(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
brand core.LarkBrand
|
|
kind string
|
|
token string
|
|
want string
|
|
}{
|
|
{"feishu docx", core.BrandFeishu, "docx", "doxcnABC", "https://www.feishu.cn/docx/doxcnABC"},
|
|
{"feishu doc legacy", core.BrandFeishu, "doc", "doccnABC", "https://www.feishu.cn/doc/doccnABC"},
|
|
{"feishu sheet", core.BrandFeishu, "sheet", "shtcnABC", "https://www.feishu.cn/sheets/shtcnABC"},
|
|
{"feishu bitable", core.BrandFeishu, "bitable", "bascnABC", "https://www.feishu.cn/base/bascnABC"},
|
|
{"feishu wiki", core.BrandFeishu, "wiki", "wikcnABC", "https://www.feishu.cn/wiki/wikcnABC"},
|
|
{"feishu file", core.BrandFeishu, "file", "boxcnABC", "https://www.feishu.cn/file/boxcnABC"},
|
|
{"feishu folder", core.BrandFeishu, "folder", "fldcnABC", "https://www.feishu.cn/drive/folder/fldcnABC"},
|
|
{"feishu mindnote", core.BrandFeishu, "mindnote", "mncnABC", "https://www.feishu.cn/mindnote/mncnABC"},
|
|
{"feishu slides", core.BrandFeishu, "slides", "slkcnABC", "https://www.feishu.cn/slides/slkcnABC"},
|
|
{"lark docx", core.BrandLark, "docx", "doxcnABC", "https://www.larksuite.com/docx/doxcnABC"},
|
|
{"lark wiki", core.BrandLark, "wiki", "wikcnABC", "https://www.larksuite.com/wiki/wikcnABC"},
|
|
{"empty brand defaults to feishu", core.LarkBrand(""), "docx", "doxcnABC", "https://www.feishu.cn/docx/doxcnABC"},
|
|
{"kind case-insensitive", core.BrandFeishu, "DOCX", "doxcnABC", "https://www.feishu.cn/docx/doxcnABC"},
|
|
{"token whitespace trimmed", core.BrandFeishu, "docx", " doxcnABC ", "https://www.feishu.cn/docx/doxcnABC"},
|
|
{"empty token", core.BrandFeishu, "docx", "", ""},
|
|
{"whitespace-only token", core.BrandFeishu, "docx", " ", ""},
|
|
{"unknown kind", core.BrandFeishu, "calendar", "calABC", ""},
|
|
{"empty kind", core.BrandFeishu, "", "doxcnABC", ""},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := BuildResourceURL(tt.brand, tt.kind, tt.token)
|
|
if got != tt.want {
|
|
t.Errorf("BuildResourceURL(%q, %q, %q) = %q, want %q", tt.brand, tt.kind, tt.token, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|