using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Unity.Pipeline.Editor.Commands.GameObjects;
using Unity.Pipeline.Models;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
using Unity.Pipeline;
namespace Unity.Pipeline.Tests.Editor.GameObjects
{
///
/// Tests for the GameObject authoring commands (CLI-192), exercised directly and via
/// . Covers creation (empty + primitive), hierarchy build via
/// set_parent, the find query, transform/active/tag/layer/rename mutations, deletion, and the
/// Undo-revert contract. Test GameObjects are created with plain UnityEngine/UnityEditor APIs and
/// torn down explicitly so the suite leaves no scene residue.
///
public class GameObjectCommandsTests
{
private readonly List m_Spawned = new List();
private GameObject Track(GameObject go)
{
m_Spawned.Add(go);
return go;
}
private static ObjectRef RefTo(Object obj) => new ObjectRef { InstanceId = PipelineUtils.GetObjectId(obj) };
[TearDown]
public void TearDown()
{
foreach (var go in m_Spawned)
{
if (go != null)
Object.DestroyImmediate(go);
}
m_Spawned.Clear();
}
#region Direct
[Test]
public void CreateGameObject_Empty_ReturnsIdentity()
{
var result = GameObjectCommands.CreateGameObject("Empty_CLI192");
var go = PipelineUtils.IdToObject(result.InstanceId.Value) as GameObject;
Track(go);
Assert.IsNotNull(go, "Created object should be resolvable by instanceId");
Assert.AreEqual("Empty_CLI192", go.name);
Assert.IsNull(go.GetComponent(), "Empty GO has no mesh");
Assert.IsNotNull(result.HierarchyPath, "Scene object should report a hierarchy path");
}
[Test]
public void CreateGameObject_Primitive_AttachesMeshAndCollider()
{
var result = GameObjectCommands.CreateGameObject("Cube_CLI192", "cube");
var go = PipelineUtils.IdToObject(result.InstanceId.Value) as GameObject;
Track(go);
Assert.IsNotNull(go.GetComponent(), "Primitive cube should have a MeshFilter");
Assert.IsNotNull(go.GetComponent(), "Primitive cube should have a BoxCollider");
}
[Test]
public void CreateGameObject_WithParent_BuildsHierarchy()
{
var parent = Track(new GameObject("Parent_CLI192"));
var childResult = GameObjectCommands.CreateGameObject("Child_CLI192", null, RefTo(parent));
var child = PipelineUtils.IdToObject(childResult.InstanceId.Value) as GameObject;
Assert.AreEqual(parent.transform, child.transform.parent, "Child should be parented");
}
[Test]
public void SetTransform_PrimitiveChannels_Apply()
{
var go = Track(new GameObject("Xform_CLI192"));
GameObjectCommands.SetTransform(RefTo(go),
position: new[] { 1f, 2f, 3f },
rotation: new[] { 0f, 90f, 0f },
scale: new[] { 2f, 2f, 2f });
Assert.AreEqual(new Vector3(1, 2, 3), go.transform.localPosition);
Assert.AreEqual(new Vector3(2, 2, 2), go.transform.localScale);
Assert.AreEqual(90f, go.transform.localEulerAngles.y, 0.01f);
}
[Test]
public void SetParent_ToNull_DetachesToRoot()
{
var parent = Track(new GameObject("P_CLI192"));
var child = Track(new GameObject("C_CLI192"));
child.transform.SetParent(parent.transform);
GameObjectCommands.SetParent(RefTo(child), null);
Assert.IsNull(child.transform.parent, "Child should be detached to scene root");
}
[Test]
public void SetActive_TogglesState()
{
var go = Track(new GameObject("Active_CLI192"));
GameObjectCommands.SetActive(RefTo(go), false);
Assert.IsFalse(go.activeSelf);
GameObjectCommands.SetActive(RefTo(go), true);
Assert.IsTrue(go.activeSelf);
}
[Test]
public void SetLayer_ByIndex_Applies()
{
var go = Track(new GameObject("Layer_CLI192"));
GameObjectCommands.SetLayer(RefTo(go), "5"); // UI layer index
Assert.AreEqual(5, go.layer);
}
[Test]
public void SetTag_UnknownTag_Throws()
{
var go = Track(new GameObject("Tag_CLI192"));
Assert.Throws(
() => GameObjectCommands.SetTag(RefTo(go), "__definitely_not_a_real_tag__"));
}
[Test]
public void Rename_ChangesName()
{
var go = Track(new GameObject("Old_CLI192"));
GameObjectCommands.RenameGameObject(RefTo(go), "New_CLI192");
Assert.AreEqual("New_CLI192", go.name);
}
[Test]
public void FindGameObjects_ByNameAndType_Filters()
{
var go = Track(new GameObject("Findable_CLI192"));
go.AddComponent();
var result = GameObjectCommands.FindGameObjects(name: "Findable_CLI192", type: "Rigidbody");
Assert.AreEqual(1, result.Count);
Assert.AreEqual(PipelineUtils.GetObjectId(go), result.GameObjects[0].InstanceId);
}
[Test]
public void Delete_RemovesFromScene()
{
var go = new GameObject("Doomed_CLI192");
var id = PipelineUtils.GetObjectId(go);
GameObjectCommands.DeleteGameObject(new ObjectRef { InstanceId = id });
Assert.IsNull(PipelineUtils.IdToObject(id), "GameObject should be destroyed");
}
[Test]
public void SetTransform_IsUndone()
{
var go = Track(new GameObject("Undo_CLI192"));
go.transform.localPosition = Vector3.zero;
GameObjectCommands.SetTransform(RefTo(go), position: new[] { 5f, 5f, 5f });
Assert.AreEqual(new Vector3(5, 5, 5), go.transform.localPosition);
Undo.PerformUndo();
Assert.AreEqual(Vector3.zero, go.transform.localPosition, "Undo should revert the transform change");
}
#endregion
#region ViaClient
[Test]
public void CreateGameObject_ViaClient_Succeeds()
{
using (var server = new PipelineTestServer())
{
var response = server.Execute("create_gameobject", new { name = "ViaClient_CLI192", primitive = "sphere" });
Assert.IsTrue(response.IsSuccess, $"create_gameobject should succeed: {response.Error}");
Assert.IsTrue(response.HasValidJson, "Response should have valid JSON");
Assert.IsTrue(response.JsonResponse.ContainsKey("result"), "Should have result field");
var instanceId = response.JsonResponse["result"]?["instanceId"]?.ToObject();
Assert.IsTrue(instanceId.HasValue, "Result should carry an instanceId");
var go = PipelineUtils.IdToObject(instanceId.Value) as GameObject;
Track(go);
Assert.IsNotNull(go, "Created object should be resolvable");
Assert.IsNotNull(go.GetComponent(), "Sphere primitive should have a SphereCollider");
}
}
[Test]
public void FindGameObjects_ViaClient_ReturnsMatches()
{
var go = Track(new GameObject("ViaFind_CLI192"));
using (var server = new PipelineTestServer())
{
var response = server.Execute("find_gameobjects", new { name = "ViaFind_CLI192" });
Assert.IsTrue(response.IsSuccess, $"find_gameobjects should succeed: {response.Error}");
var count = response.JsonResponse["result"]?["count"]?.ToObject();
Assert.AreEqual(1, count, "Should find exactly the one named GameObject");
}
}
#endregion
}
}