212 lines
5.5 KiB
Go
212 lines
5.5 KiB
Go
package integration
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"aego/app/agent"
|
|
"aego/app/edit"
|
|
"aego/core/ids"
|
|
"aego/core/log"
|
|
"aego/editor/core/context"
|
|
"aego/editor/core/document"
|
|
"aego/project"
|
|
"aego/scene/mutate"
|
|
"aego/scene/sceneio"
|
|
"aego/schema"
|
|
"aego/sdk"
|
|
"aego/tests/fixture"
|
|
)
|
|
|
|
const (
|
|
levelPath = "scenes/main.aescene"
|
|
enemyLeft = "c0000000000000000000000000000004"
|
|
playerNode = "c0000000000000000000000000000003"
|
|
)
|
|
|
|
type external struct {
|
|
t *testing.T
|
|
s *edit.Session
|
|
ctx *context.Editor
|
|
p *project.Project
|
|
opt agent.Options
|
|
}
|
|
|
|
func openExternal(t *testing.T) *external {
|
|
t.Helper()
|
|
p, err := project.Load(fixture.Copy(t, "platformer"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mods := []sdk.Module{fixture.Platformer{}}
|
|
s, err := edit.Open(p, edit.Config{Headless: true, NoWatch: true, Logger: log.Nop()}, mods...)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(s.Close)
|
|
s.Step()
|
|
return &external{t: t, s: s, ctx: s.App.Context(), p: p, opt: agent.Options{Mods: mods}}
|
|
}
|
|
|
|
func (e *external) agent(name string, a agent.Args) {
|
|
e.t.Helper()
|
|
sess, err := agent.Open(e.p, e.opt)
|
|
if err != nil {
|
|
e.t.Fatal(err)
|
|
}
|
|
defer sess.Close()
|
|
if _, err := agent.Run(sess, name, a); err != nil {
|
|
e.t.Fatalf("%s: %v", name, err)
|
|
}
|
|
}
|
|
|
|
func (e *external) scene() *document.SceneDocument {
|
|
e.t.Helper()
|
|
d, err := e.ctx.Docs.Open(levelPath)
|
|
if err != nil {
|
|
e.t.Fatal(err)
|
|
}
|
|
return d
|
|
}
|
|
|
|
func nodeOf(t *testing.T, s string) ids.NodeID {
|
|
t.Helper()
|
|
id, err := ids.ParseNodeID(s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return id
|
|
}
|
|
|
|
func (e *external) field(d *document.SceneDocument, node, comp, field string) schema.Value {
|
|
e.t.Helper()
|
|
sc := d.Scene()
|
|
td, ok := sc.Registry().ByName(comp)
|
|
if !ok {
|
|
e.t.Fatalf("no %s", comp)
|
|
}
|
|
fd, _ := td.Field(field)
|
|
v, err := sc.GetProperty(sc.Handle(nodeOf(e.t, node)), td.ID, fd.ID)
|
|
if err != nil {
|
|
e.t.Fatal(err)
|
|
}
|
|
return v
|
|
}
|
|
|
|
func (e *external) text(d *document.SceneDocument, node, comp, field string) string {
|
|
e.t.Helper()
|
|
td, _ := d.Scene().Registry().ByName(comp)
|
|
fd, _ := td.Field(field)
|
|
return mutate.FormatValue(sceneio.WriteValue(d.Scene().Registry(), fd, e.field(d, node, comp, field)))
|
|
}
|
|
|
|
func TestExternalSceneEdit(t *testing.T) {
|
|
e := openExternal(t)
|
|
e.scene()
|
|
e.agent("scene.set", agent.Args{"file": levelPath, "node": "Player", "path": "Body2D.gravityScale", "value": "3"})
|
|
reloaded, conflicts := e.ctx.Docs.CheckExternal()
|
|
if len(reloaded) != 1 || len(conflicts) != 0 {
|
|
t.Fatalf("reloaded %v, conflicts %v", reloaded, conflicts)
|
|
}
|
|
d := e.scene()
|
|
if got := e.field(d, playerNode, "physics.Body2D", "gravityScale").AsFloat(); got != 3 {
|
|
t.Fatalf("gravityScale %v after the reload", got)
|
|
}
|
|
if err := d.Props.Rename(nil, nodeOf(t, playerNode), "Hero"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
e.agent("scene.set", agent.Args{"file": levelPath, "node": "Player", "path": "Body2D.gravityScale", "value": "4"})
|
|
if _, conflicts := e.ctx.Docs.CheckExternal(); len(conflicts) != 1 {
|
|
t.Fatalf("a dirty document did not raise a conflict: %v", conflicts)
|
|
}
|
|
}
|
|
|
|
func TestExternalPrefabEdit(t *testing.T) {
|
|
e := openExternal(t)
|
|
d := e.scene()
|
|
order := e.field(d, enemyLeft, "engine.SpriteRenderer", "order").I
|
|
if err := d.Props.Rename(nil, nodeOf(t, playerNode), "Hero"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dirty := d.Dirty()
|
|
e.agent("scene.set", agent.Args{"file": "prefabs/enemy.aeprefab", "node": "Enemy", "path": "SpriteRenderer.tint", "value": "#123456ff"})
|
|
id, ok := e.ctx.Pipeline.Lookup("prefabs/enemy.aeprefab")
|
|
if !ok {
|
|
t.Fatal("no enemy prefab")
|
|
}
|
|
batch, err := e.ctx.Pipeline.Reimport(id)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
e.ctx.ApplyBatch(batch)
|
|
if got := e.text(d, enemyLeft, "engine.SpriteRenderer", "tint"); got != "#123456ff" {
|
|
t.Fatalf("the instance has tint %s", got)
|
|
}
|
|
sc := d.Scene()
|
|
if sc.Name(sc.Handle(nodeOf(t, enemyLeft))) != "EnemyLeft" || e.field(d, enemyLeft, "engine.SpriteRenderer", "order").I != order {
|
|
t.Fatal("the instance lost its overrides")
|
|
}
|
|
if d.Dirty() != dirty {
|
|
t.Fatal("refreshing the instances changed the dirty state")
|
|
}
|
|
if err := d.History.Undo(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if sc.Name(sc.Handle(nodeOf(t, playerNode))) != "Player" {
|
|
t.Fatal("undo of the earlier edit failed after the refresh")
|
|
}
|
|
}
|
|
|
|
func TestExternalDataEdit(t *testing.T) {
|
|
e := openExternal(t)
|
|
data := e.s.App.Data()
|
|
id, ok := e.ctx.Pipeline.Lookup("assets/data/enemy_stats.aedata")
|
|
if !ok {
|
|
t.Fatal("no enemy stats")
|
|
}
|
|
doc, err := data.Doc(id)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
fd, _ := doc.Type.Field("speed")
|
|
if err := doc.Set(fd, schema.Float32(7), true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mine := doc.Bytes()
|
|
e.agent("data.set", agent.Args{"file": "assets/data/enemy_stats.aedata", "path": "damage", "value": "9"})
|
|
batch, err := e.ctx.Pipeline.Reimport(id)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
e.ctx.ApplyBatch(batch)
|
|
warnings := func() int {
|
|
n := 0
|
|
for _, x := range e.ctx.Notices() {
|
|
if x.Level == context.LevelWarn && strings.Contains(x.Text, "changed on disk") {
|
|
n++
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
if _, err := data.Doc(id); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if warnings() != 1 {
|
|
t.Fatalf("%d warnings after the external edit", warnings())
|
|
}
|
|
e.ctx.AssetRev++
|
|
if _, err := data.Doc(id); err != nil || warnings() != 1 {
|
|
t.Fatalf("the warning repeated: %d, %v", warnings(), err)
|
|
}
|
|
if err := data.SaveDoc(doc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
disk, _ := os.ReadFile(filepath.Join(e.p.Root, "assets", "data", "enemy_stats.aedata"))
|
|
if !bytes.Equal(disk, mine) {
|
|
t.Fatalf("Save did not write the editor's version:\n%s", disk)
|
|
}
|
|
}
|