mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 22:24:31 +08:00
254 lines
6.8 KiB
Go
254 lines
6.8 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package apps
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/larksuite/cli/errs"
|
|
)
|
|
|
|
// --- pluginResolveProjectPath ---
|
|
|
|
func TestPluginResolveProjectPath_DefaultToCwd(t *testing.T) {
|
|
got, err := pluginResolveProjectPath("")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
cwd, _ := os.Getwd() //nolint:forbidigo
|
|
if got != cwd {
|
|
t.Errorf("got %q, want cwd %q", got, cwd)
|
|
}
|
|
}
|
|
|
|
func TestPluginResolveProjectPath_ExplicitPath(t *testing.T) {
|
|
got, err := pluginResolveProjectPath("/tmp/myapp")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if got != "/tmp/myapp" {
|
|
t.Errorf("got %q, want /tmp/myapp", got)
|
|
}
|
|
}
|
|
|
|
// --- pluginCheckProjectDir ---
|
|
|
|
func TestPluginCheckProjectDir_OK(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.WriteFile(filepath.Join(dir, "package.json"), []byte("{}"), 0o644); err != nil { //nolint:forbidigo
|
|
t.Fatal(err)
|
|
}
|
|
if err := pluginCheckProjectDir(dir); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestPluginCheckProjectDir_Missing(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := pluginCheckProjectDir(dir)
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
p, ok := errs.ProblemOf(err)
|
|
if !ok {
|
|
t.Fatalf("expected typed error, got %T: %v", err, err)
|
|
}
|
|
if p.Subtype != errs.SubtypeFailedPrecondition {
|
|
t.Errorf("subtype = %q, want failed_precondition", p.Subtype)
|
|
}
|
|
}
|
|
|
|
// --- pluginResolveCapDir ---
|
|
|
|
func TestPluginResolveCapDir_EnvVar(t *testing.T) {
|
|
t.Setenv("MIAODA_CAPABILITIES_DIR", "envdir/caps")
|
|
got, err := pluginResolveCapDir("/proj")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if want := filepath.Join("/proj", "envdir/caps"); got != want {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestPluginResolveCapDir_AppTypeEnv(t *testing.T) {
|
|
t.Setenv("MIAODA_APP_TYPE", "2")
|
|
got, err := pluginResolveCapDir("/proj")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if want := filepath.Join("/proj", "server", "capabilities"); got != want {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestPluginResolveCapDir_AppTypeEnvShared(t *testing.T) {
|
|
t.Setenv("MIAODA_APP_TYPE", "6")
|
|
got, err := pluginResolveCapDir("/proj")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if want := filepath.Join("/proj", "shared", "capabilities"); got != want {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestPluginResolveCapDir_EnvLocal(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.WriteFile(filepath.Join(dir, ".env.local"), []byte("MIAODA_APP_TYPE=2\n"), 0o644); err != nil { //nolint:forbidigo
|
|
t.Fatal(err)
|
|
}
|
|
got, err := pluginResolveCapDir(dir)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if want := filepath.Join(dir, "server", "capabilities"); got != want {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestPluginResolveCapDir_DetectServer(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.MkdirAll(filepath.Join(dir, "server", "capabilities"), 0o755); err != nil { //nolint:forbidigo
|
|
t.Fatal(err)
|
|
}
|
|
got, err := pluginResolveCapDir(dir)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if want := filepath.Join(dir, "server", "capabilities"); got != want {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestPluginResolveCapDir_DetectShared(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.MkdirAll(filepath.Join(dir, "shared", "capabilities"), 0o755); err != nil { //nolint:forbidigo
|
|
t.Fatal(err)
|
|
}
|
|
got, err := pluginResolveCapDir(dir)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if want := filepath.Join(dir, "shared", "capabilities"); got != want {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestPluginResolveCapDir_Ambiguous(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.MkdirAll(filepath.Join(dir, "server", "capabilities"), 0o755); err != nil { //nolint:forbidigo
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.MkdirAll(filepath.Join(dir, "shared", "capabilities"), 0o755); err != nil { //nolint:forbidigo
|
|
t.Fatal(err)
|
|
}
|
|
_, err := pluginResolveCapDir(dir)
|
|
if err == nil {
|
|
t.Fatal("expected ambiguous error")
|
|
}
|
|
p, ok := errs.ProblemOf(err)
|
|
if !ok {
|
|
t.Fatalf("expected typed error, got %T: %v", err, err)
|
|
}
|
|
if p.Subtype != errs.SubtypeFailedPrecondition {
|
|
t.Errorf("subtype = %q, want failed_precondition", p.Subtype)
|
|
}
|
|
}
|
|
|
|
func TestPluginResolveCapDir_NeitherExists_DefaultsToServer(t *testing.T) {
|
|
dir := t.TempDir()
|
|
got, err := pluginResolveCapDir(dir)
|
|
if err != nil {
|
|
t.Fatalf("should default to server/capabilities, got error: %v", err)
|
|
}
|
|
if want := filepath.Join(dir, "server", "capabilities"); got != want {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestPluginResolveCapDir_AppType3_UsesServer(t *testing.T) {
|
|
t.Setenv("MIAODA_APP_TYPE", "3")
|
|
got, err := pluginResolveCapDir("/proj")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if want := filepath.Join("/proj", "server", "capabilities"); got != want {
|
|
t.Errorf("got %q, want %q (appType=3 should use server)", got, want)
|
|
}
|
|
}
|
|
|
|
// --- pluginListCapabilities ---
|
|
|
|
func TestPluginListCapabilities_Empty(t *testing.T) {
|
|
dir := t.TempDir()
|
|
caps, err := pluginListCapabilities(dir)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if len(caps) != 0 {
|
|
t.Errorf("got %d caps, want 0", len(caps))
|
|
}
|
|
}
|
|
|
|
func TestPluginListCapabilities_DirNotExist(t *testing.T) {
|
|
caps, err := pluginListCapabilities("/nonexistent/path")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if caps != nil {
|
|
t.Errorf("got %v, want nil", caps)
|
|
}
|
|
}
|
|
|
|
func TestPluginListCapabilities_WithFiles(t *testing.T) {
|
|
dir := t.TempDir()
|
|
writeTestCapJSON(t, dir, "cap1.json", map[string]interface{}{"id": "cap1", "name": "Cap One"})
|
|
writeTestCapJSON(t, dir, "cap2.json", map[string]interface{}{"id": "cap2", "name": "Cap Two"})
|
|
// non-JSON file should be skipped
|
|
if err := os.WriteFile(filepath.Join(dir, "readme.txt"), []byte("ignore"), 0o644); err != nil { //nolint:forbidigo
|
|
t.Fatal(err)
|
|
}
|
|
|
|
caps, err := pluginListCapabilities(dir)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if len(caps) != 2 {
|
|
t.Fatalf("got %d caps, want 2", len(caps))
|
|
}
|
|
}
|
|
|
|
func TestPluginListCapabilities_SkipsMalformed(t *testing.T) {
|
|
dir := t.TempDir()
|
|
writeTestCapJSON(t, dir, "good.json", map[string]interface{}{"id": "good"})
|
|
if err := os.WriteFile(filepath.Join(dir, "bad.json"), []byte("not json"), 0o644); err != nil { //nolint:forbidigo
|
|
t.Fatal(err)
|
|
}
|
|
|
|
caps, err := pluginListCapabilities(dir)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if len(caps) != 1 {
|
|
t.Fatalf("got %d caps, want 1", len(caps))
|
|
}
|
|
}
|
|
|
|
// --- helpers ---
|
|
|
|
func writeTestCapJSON(t *testing.T, dir, filename string, data map[string]interface{}) {
|
|
t.Helper()
|
|
b, err := json.Marshal(data)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, filename), b, 0o644); err != nil { //nolint:forbidigo
|
|
t.Fatal(err)
|
|
}
|
|
}
|