177 lines
4.1 KiB
Go
177 lines
4.1 KiB
Go
package clipboard
|
|
|
|
import (
|
|
"aego/core/ids"
|
|
"testing"
|
|
|
|
"aego/core/log"
|
|
"aego/editor/core/command"
|
|
"aego/editor/core/context"
|
|
"aego/editor/core/document"
|
|
"aego/editor/core/history/commands"
|
|
"aego/editor/core/selection"
|
|
"aego/scene"
|
|
"aego/scene/sceneio"
|
|
"aego/schema"
|
|
)
|
|
|
|
type Link struct {
|
|
Target scene.NodeRef `aego:"target"`
|
|
}
|
|
|
|
type fakeClip struct {
|
|
text string
|
|
data map[string][]byte
|
|
}
|
|
|
|
func (f *fakeClip) Text() string {
|
|
return f.text
|
|
}
|
|
|
|
func (f *fakeClip) SetText(s string) {
|
|
f.text = s
|
|
f.data = nil
|
|
}
|
|
|
|
func (f *fakeClip) SetData(mime string, data []byte, text string) bool {
|
|
f.data = map[string][]byte{mime: data}
|
|
f.text = text
|
|
return true
|
|
}
|
|
|
|
func (f *fakeClip) Data(mime string) ([]byte, bool) {
|
|
d, ok := f.data[mime]
|
|
return d, ok
|
|
}
|
|
|
|
func setup(t *testing.T) (*context.Editor, *document.SceneDocument) {
|
|
t.Helper()
|
|
types := scene.NewTypes(schema.NewRegistry())
|
|
if err := scene.RegisterComponent[Link](types, schema.Name("test.Link")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := sceneio.RegisterUnknown(types); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := types.Schema().Freeze(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s := scene.New(types, nil, scene.Options{})
|
|
a := s.Create(s.Root(), "A")
|
|
b := s.Create(a, "B")
|
|
c := s.Create(s.Root(), "C")
|
|
scene.Add[Link](s, a).Target.Set(s, b)
|
|
scene.Add[Link](s, c).Target.Set(s, b)
|
|
s.Flush()
|
|
m := document.NewManager(document.Options{Root: t.TempDir(), Types: types, Log: log.Nop()})
|
|
d := m.New("scenes/t.aescene", s)
|
|
ctx := &context.Editor{
|
|
Types: types,
|
|
Docs: m,
|
|
Selection: selection.New(),
|
|
Commands: command.New(),
|
|
Clipboard: &fakeClip{},
|
|
}
|
|
return ctx, d
|
|
}
|
|
|
|
func TestCopyPasteRemapsInternalRefs(t *testing.T) {
|
|
ctx, d := setup(t)
|
|
s := d.Scene()
|
|
a := s.Find(s.Root(), "A")
|
|
b := s.Find(s.Root(), "A/B")
|
|
ctx.Select(s.ID(a))
|
|
if err := Copy(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := Paste(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sel := ctx.Selected()
|
|
if len(sel) != 1 {
|
|
t.Fatalf("selection = %v", sel)
|
|
}
|
|
pasted := s.Handle(sel[0])
|
|
if pasted == a || s.ChildCount(s.Root()) != 3 || commands.ChildIndex(s, pasted) != 1 {
|
|
t.Fatal("paste must land right after the selected node")
|
|
}
|
|
child := s.Child(pasted, "B")
|
|
if child.IsZero() || child == b {
|
|
t.Fatal("pasted subtree must have its own child")
|
|
}
|
|
link, ok := scene.Get[Link](s, pasted)
|
|
if !ok {
|
|
t.Fatal("component lost")
|
|
}
|
|
if got, ok := link.Target.Resolve(s); !ok || got != child {
|
|
t.Fatal("internal reference must follow the copy")
|
|
}
|
|
d.History.Undo()
|
|
if s.ChildCount(s.Root()) != 2 {
|
|
t.Fatal("paste must be one undo step")
|
|
}
|
|
}
|
|
|
|
func TestExternalRefKeepsTarget(t *testing.T) {
|
|
ctx, d := setup(t)
|
|
s := d.Scene()
|
|
c := s.Find(s.Root(), "C")
|
|
b := s.Find(s.Root(), "A/B")
|
|
ctx.Select(s.ID(c))
|
|
Copy(ctx)
|
|
if err := Paste(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
pasted := s.Handle(ctx.Selected()[0])
|
|
link, _ := scene.Get[Link](s, pasted)
|
|
if got, ok := link.Target.Resolve(s); !ok || got != b {
|
|
t.Fatal("reference outside the fragment must keep pointing at the original")
|
|
}
|
|
}
|
|
|
|
func TestPasteFromPlainText(t *testing.T) {
|
|
ctx, d := setup(t)
|
|
s := d.Scene()
|
|
data, _, err := Fragment(s, []ids.NodeID{s.ID(s.Find(s.Root(), "C"))})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx.Clipboard.SetText(string(data))
|
|
if err := Paste(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if s.ChildCount(s.Root()) != 3 {
|
|
t.Fatal("text clipboard paste failed")
|
|
}
|
|
}
|
|
|
|
func TestDuplicateAndDeleteAreSingleSteps(t *testing.T) {
|
|
ctx, d := setup(t)
|
|
s := d.Scene()
|
|
a := s.Find(s.Root(), "A")
|
|
b := s.Find(s.Root(), "A/B")
|
|
ctx.Select(s.ID(a), s.ID(b))
|
|
if err := Duplicate(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if s.ChildCount(s.Root()) != 3 {
|
|
t.Fatalf("duplicate must copy only the top-level node, root has %d", s.ChildCount(s.Root()))
|
|
}
|
|
d.History.Undo()
|
|
if s.ChildCount(s.Root()) != 2 {
|
|
t.Fatal("duplicate undo failed")
|
|
}
|
|
bID := s.ID(b)
|
|
ctx.Select(s.ID(a), bID)
|
|
if err := Delete(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if s.ChildCount(s.Root()) != 1 {
|
|
t.Fatal("delete failed")
|
|
}
|
|
d.History.Undo()
|
|
if s.ChildCount(s.Root()) != 2 || s.Handle(bID).IsZero() {
|
|
t.Fatal("one undo must restore the whole subtree")
|
|
}
|
|
}
|