Files
magpie/groups_copy_cli_test.go
yetone ddd4f43144 provider: a routing group can be duplicated, from its menu on the Routing page or with magpie group copy (lc on Discord)
provider.CopyGroup(id, name) saves a copy of the group as it is now: its
models and patterns, routing, stays, rules, classifier, effort, context,
levels, and fast and off members. The copy is deep, so its rules' time
windows aren't shared. Its name is the one given, or "<name> copy", with a
number added past a name in use. Its id comes from the name, numbered past
any id in use, removed ones included. It is listed right after the group
it copies. The copy is a group of the user's and switched on, even when
it copies a found group or a switched-off one. The original is unchanged.

Surfaces:
- GUI: a group row's menu (right-click, or a click on its logos) has
  Duplicate under Move up and Move down. It posts /api/groups/copy with
  the id and t("{name} copy"), so the name is in the reader's language.
  It asks before discarding an editor with unsaved changes. The status
  then says "Duplicated {name}". No click scrolls the page.
- CLI: magpie group copy <id> [name]; duplicate, dup and clone work too.
- zh, zh-TW, ja and de strings. docs/reference.md and the site's start
  page (en, zh, ja) list the command.

Run:
- TestGroupCopy (internal/gui): the copy has the models, pattern,
  routing, rule and off member, is on, and is listed after the original.
  The original stays off and unchanged. A second copy is "Fast copy 2" /
  fast-copy-2. An unknown id is refused.
- TestGroupCopyCLI (root): the default name, a given name, a found
  group's copy as the user's, and the errors.
- group-duplicate.test.cjs: Chromium and WebKit, en/zh/zh-TW/ja/de at
  420px, 10/10. It fails 10/10 on the old routing.js. Siblings
  group-arrange, removed-groups-menu-scroll, group-bulk-remove and
  click-scroll pass 36/36.
- Sandbox CLI (sandbox HOME): group copy and duplicate made "DupTest copy"
  and "DupTest copy 2", listed after DupTest.
- gofmt -l clean. go vet darwin/linux/windows on the root, provider and
  gui packages: ok.
2026-10-10 15:08:14 +08:00

53 lines
1.8 KiB
Go

package main
import (
"slices"
"strings"
"testing"
"github.com/yetone/magpie/internal/provider"
)
// magpie group copy <id> [name] duplicates a group (lc on Discord): its
// models and routing under "<name> copy", or the name given, and says what
// agents pick it as. A found group copies too, as one of the user's; a
// removed one is brought back first.
func TestGroupCopyCLI(t *testing.T) {
groupsHome(t)
if err := provider.SaveGroup(provider.Group{ID: "fast", Name: "Fast", Members: []string{"a/m", "a/only-a"}, Routing: provider.Ordered}); err != nil {
t.Fatal(err)
}
out, err := stdoutOf(t, func() error { return groupCmd([]string{"group", "copy", "fast"}) })
if err != nil {
t.Fatal(err)
}
if !strings.Contains(out, "Fast copy") || !strings.Contains(out, "group/fast-copy") {
t.Fatalf("copy said %q", out)
}
c, err := findGroup("fast-copy")
if err != nil || c.Name != "Fast copy" || c.Routing != provider.Ordered || !slices.Equal(c.Members, []string{"a/m", "a/only-a"}) {
t.Fatalf("%v %+v", err, c)
}
if _, err := stdoutOf(t, func() error { return groupCmd([]string{"group", "duplicate", "Fast", "Fast", "B"}) }); err != nil {
t.Fatal(err)
}
if c, err := findGroup("fast-b"); err != nil || c.Name != "Fast B" {
t.Fatalf("named copy: %v %+v", err, c)
}
if _, err := stdoutOf(t, func() error { return groupCmd([]string{"group", "copy", "auto-m", "Mine"}) }); err != nil {
t.Fatal(err)
}
if c, err := findGroup("mine"); err != nil || c.Auto || len(c.Members) != 2 {
t.Fatalf("found group's copy: %v %+v", err, c)
}
if err := groupCmd([]string{"group", "copy", "nope"}); err == nil {
t.Error("copied a group that isn't")
}
if err := groupCmd([]string{"group", "copy"}); err == nil || !strings.Contains(err.Error(), "magpie group copy <id>") {
t.Errorf("no id: %v", err)
}
}