@mflrevan/ucp 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +1 -1
  2. package/bridge/com.ucp.bridge/CHANGELOG.md +110 -0
  3. package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs +61 -6
  4. package/bridge/com.ucp.bridge/Editor/Bridge/EditorStateSummary.cs +165 -0
  5. package/bridge/com.ucp.bridge/Editor/Bridge/EditorStateSummary.cs.meta +11 -0
  6. package/bridge/com.ucp.bridge/Editor/Compatibility/UnityObjectCompat.cs +22 -5
  7. package/bridge/com.ucp.bridge/Editor/Controllers/EditorController.cs +1 -0
  8. package/bridge/com.ucp.bridge/Editor/Controllers/HierarchyController.cs +10 -10
  9. package/bridge/com.ucp.bridge/Editor/Controllers/LogsController.cs +71 -0
  10. package/bridge/com.ucp.bridge/Editor/Controllers/MaterialController.cs +2 -2
  11. package/bridge/com.ucp.bridge/Editor/Controllers/ObjectLocator.cs +4 -4
  12. package/bridge/com.ucp.bridge/Editor/Controllers/ObjectReferenceResolver.cs +3 -3
  13. package/bridge/com.ucp.bridge/Editor/Controllers/PrefabController.cs +6 -6
  14. package/bridge/com.ucp.bridge/Editor/Controllers/PropertyController.cs +30 -14
  15. package/bridge/com.ucp.bridge/Editor/Controllers/RecordingController.cs +732 -0
  16. package/bridge/com.ucp.bridge/Editor/Controllers/RecordingController.cs.meta +11 -0
  17. package/bridge/com.ucp.bridge/Editor/Controllers/SceneChangeTracker.cs +3 -3
  18. package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs +3 -3
  19. package/bridge/com.ucp.bridge/Editor/Controllers/SnapshotController.cs +5 -5
  20. package/bridge/com.ucp.bridge/Editor/Controllers/TestRunnerController.cs +11 -2
  21. package/bridge/com.ucp.bridge/Editor/Controllers/TransformController.cs +1 -1
  22. package/bridge/com.ucp.bridge/Editor/Controllers/UiController.cs +70 -0
  23. package/bridge/com.ucp.bridge/Editor/Controllers/UiController.cs.meta +11 -0
  24. package/bridge/com.ucp.bridge/Editor/Controllers/ViewController.cs +1 -1
  25. package/bridge/com.ucp.bridge/Editor/Protocol/MiniJson.cs +1 -1
  26. package/bridge/com.ucp.bridge/Editor/Ui/UiHost.cs +468 -0
  27. package/bridge/com.ucp.bridge/Editor/Ui/UiHost.cs.meta +11 -0
  28. package/bridge/com.ucp.bridge/Editor/Ui/UiLintService.cs +554 -0
  29. package/bridge/com.ucp.bridge/Editor/Ui/UiLintService.cs.meta +11 -0
  30. package/bridge/com.ucp.bridge/Editor/Ui/UiOperationManager.cs +870 -0
  31. package/bridge/com.ucp.bridge/Editor/Ui/UiOperationManager.cs.meta +11 -0
  32. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioApplier.cs +496 -0
  33. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioApplier.cs.meta +11 -0
  34. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioLoader.cs +854 -0
  35. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioLoader.cs.meta +11 -0
  36. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioModels.cs +374 -0
  37. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioModels.cs.meta +11 -0
  38. package/bridge/com.ucp.bridge/Editor/Ui/UiVisualTreeInspector.cs +690 -0
  39. package/bridge/com.ucp.bridge/Editor/Ui/UiVisualTreeInspector.cs.meta +11 -0
  40. package/bridge/com.ucp.bridge/{Runtime.meta → Editor/Ui.meta} +1 -1
  41. package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs +191 -3
  42. package/bridge/com.ucp.bridge/Tests/Editor/SpatialVisualControllerTests.cs +2 -2
  43. package/bridge/com.ucp.bridge/Tests/Editor/UiControllerTests.cs +547 -0
  44. package/bridge/com.ucp.bridge/Tests/Editor/UiControllerTests.cs.meta +11 -0
  45. package/bridge/com.ucp.bridge/Tests/Editor/UiLintServiceTests.cs +253 -0
  46. package/bridge/com.ucp.bridge/Tests/Editor/UiLintServiceTests.cs.meta +11 -0
  47. package/bridge/com.ucp.bridge/Tests/Editor/UiScenarioTests.cs +587 -0
  48. package/bridge/com.ucp.bridge/Tests/Editor/UiScenarioTests.cs.meta +11 -0
  49. package/bridge/com.ucp.bridge/package.json +1 -1
  50. package/package.json +1 -1
  51. package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef +0 -14
  52. package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef.meta +0 -7
@@ -1,5 +1,5 @@
1
1
  fileFormatVersion: 2
2
- guid: ed1329cd64b53ba45b1a53c86007094a
2
+ guid: 72ee32817b4f45abac53f471c69e899e
3
3
  folderAsset: yes
4
4
  DefaultImporter:
5
5
  externalObjects: {}
@@ -7,6 +7,7 @@ using NUnit.Framework;
7
7
  using UnityEditor;
8
8
  using UnityEditor.SceneManagement;
9
9
  using UnityEngine;
10
+ using UnityEngine.SceneManagement;
10
11
  using UnityEngine.Profiling;
11
12
  using UnityEngine.TestTools;
12
13
 
@@ -46,6 +47,7 @@ namespace UCP.Bridge.Tests
46
47
  PlayModeController.Register(_router);
47
48
  ReferenceController.Register(_router);
48
49
  LogsController.Register(_router);
50
+ RecordingController.Register(_router);
49
51
  HierarchyController.Register(_router);
50
52
  ProfilerController.Register(_router);
51
53
  PropertyController.Register(_router);
@@ -72,6 +74,7 @@ namespace UCP.Bridge.Tests
72
74
  DeleteTempLocalPackage();
73
75
  RemoveTempLocalPackageDependencyIfPresent();
74
76
  LogsController.ClearHistoryForTests();
77
+ RecordingController.ResetForTests();
75
78
  AssetImportSupport.ClearTestState();
76
79
  Profiler.enabled = false;
77
80
  Profiler.enableBinaryLog = false;
@@ -97,6 +100,7 @@ namespace UCP.Bridge.Tests
97
100
  DeleteTempLocalPackage();
98
101
  RemoveTempLocalPackageDependencyIfPresent();
99
102
  LogsController.ClearHistoryForTests();
103
+ RecordingController.ResetForTests();
100
104
  AssetImportSupport.ClearTestState();
101
105
  Profiler.enabled = false;
102
106
  Profiler.enableBinaryLog = false;
@@ -123,6 +127,115 @@ namespace UCP.Bridge.Tests
123
127
  Assert.That(Convert.ToBoolean(capabilities["sessionControl"]), Is.True);
124
128
  }
125
129
 
130
+ [Test]
131
+ public void RecordingController_RegistersLifecycleMethodsAndReportsIdle()
132
+ {
133
+ Assert.That(_router.HasMethod("record/start"), Is.True);
134
+ Assert.That(_router.HasMethod("record/stop"), Is.True);
135
+ Assert.That(_router.HasMethod("record/status"), Is.True);
136
+ Assert.That(_router.HasMethod("record/arm"), Is.True);
137
+ Assert.That(_router.HasMethod("record/signal"), Is.True);
138
+
139
+ var response = _router.Dispatch("record/status", 1, "{}");
140
+ Assert.That(response.error, Is.Null);
141
+ var result = (Dictionary<string, object>)response.result;
142
+ Assert.That(result["state"], Is.EqualTo("idle"));
143
+ }
144
+
145
+ [Test]
146
+ public void RecordingController_ResolvesEvenAspectPreservingDimensions()
147
+ {
148
+ Assert.That(RecordingController.ResolveDimensionsForTests(16f / 9f, 960, null, null),
149
+ Is.EqualTo((960, 540)));
150
+ Assert.That(RecordingController.ResolveDimensionsForTests(9f / 16f, 960, null, null),
151
+ Is.EqualTo((540, 960)));
152
+ Assert.That(RecordingController.ResolveDimensionsForTests(4f / 3f, 960, 640, null),
153
+ Is.EqualTo((640, 480)));
154
+ Assert.That(RecordingController.ResolveDimensionsForTests(4f / 3f, 960, null, 600),
155
+ Is.EqualTo((800, 600)));
156
+ }
157
+
158
+ [Test]
159
+ public void RecordingController_ArmsAndMatchesNamedSignal()
160
+ {
161
+ var response = _router.Dispatch(
162
+ "record/arm",
163
+ 1,
164
+ "{\"trigger\":\"signal:not-this-one\",\"duration\":1,\"timeout\":5}");
165
+ Assert.That(response.error, Is.Null);
166
+
167
+ var signal = _router.Dispatch("record/signal", 2, "{\"name\":\"different\"}");
168
+ Assert.That(signal.error, Is.Null);
169
+ var result = (Dictionary<string, object>)signal.result;
170
+ Assert.That(Convert.ToBoolean(result["matched"]), Is.False);
171
+ Assert.That(result["state"], Is.EqualTo("armed"));
172
+
173
+ var stop = _router.Dispatch("record/stop", 3, "{}");
174
+ Assert.That(stop.error, Is.Null);
175
+ var stopped = (Dictionary<string, object>)stop.result;
176
+ Assert.That(stopped["state"], Is.EqualTo("idle"));
177
+ }
178
+
179
+ [Test]
180
+ public void GetProperty_ReturnsCompositeValuesRatherThanTypeNames()
181
+ {
182
+ // Regression: when SerializedObject.FindProperty resolves a name, the value it returns
183
+ // is already JSON-shaped. That result used to be converted a second time, match no
184
+ // case, and fall through to value.ToString() -- so a Vector3 arrived as
185
+ // "System.Collections.Generic.List`1[System.Object]". Querying the serialized name
186
+ // (m_LocalPosition) is what forces the FindProperty path; the public alias (position)
187
+ // has no serialized entry and takes the reflection fallback instead, which is why that
188
+ // one never looked broken.
189
+ var go = new GameObject("UcpPropertyProbe");
190
+ try
191
+ {
192
+ go.transform.localPosition = new Vector3(1.5f, 2.5f, 3.5f);
193
+ var id = go.GetId();
194
+
195
+ var serialized = _router.Dispatch("object/get-property", 1, "{\"instanceId\":ID,\"component\":\"Transform\",\"property\":\"m_LocalPosition\"}".Replace("ID", id.ToString()));
196
+ Assert.That(serialized.error, Is.Null);
197
+ var serializedResult = (Dictionary<string, object>)serialized.result;
198
+ var localPosition = serializedResult["value"] as IList;
199
+ Assert.That(localPosition, Is.Not.Null,
200
+ "a serialized Vector3 must come back as an array, not a stringified type name");
201
+ Assert.That(localPosition.Count, Is.EqualTo(3));
202
+ Assert.That(Convert.ToDouble(localPosition[0]), Is.EqualTo(1.5d).Within(1e-4));
203
+ Assert.That(Convert.ToDouble(localPosition[2]), Is.EqualTo(3.5d).Within(1e-4));
204
+ Assert.That(serializedResult["type"], Is.EqualTo("Vector3"),
205
+ "type must describe the field, not the container it was shaped into");
206
+
207
+ // Reflection fallback: no serialized entry named "position".
208
+ var reflected = _router.Dispatch("object/get-property", 2, "{\"instanceId\":ID,\"component\":\"Transform\",\"property\":\"position\"}".Replace("ID", id.ToString()));
209
+ Assert.That(reflected.error, Is.Null);
210
+ var reflectedResult = (Dictionary<string, object>)reflected.result;
211
+ Assert.That(reflectedResult["value"] as IList, Is.Not.Null);
212
+ Assert.That(reflectedResult["type"], Is.EqualTo("Vector3"));
213
+ }
214
+ finally
215
+ {
216
+ UnityEngine.Object.DestroyImmediate(go);
217
+ }
218
+ }
219
+
220
+ [Test]
221
+ public void RecordingController_ValidatesSlowdownRange()
222
+ {
223
+ // --slowdown exists to raise effective temporal resolution for models that sample a
224
+ // clip at a fixed low rate, so an out-of-range factor must fail loudly rather than
225
+ // silently producing a file whose playback rate is meaningless.
226
+ var tooLarge = _router.Dispatch("record/arm", 1, "{\"trigger\":\"signal:sd\",\"duration\":1,\"timeout\":5,\"slowdown\":40}");
227
+ Assert.That(tooLarge.error, Is.Not.Null, "a slowdown above the supported range must be rejected");
228
+
229
+ var accepted = _router.Dispatch("record/arm", 2, "{\"trigger\":\"signal:sd\",\"duration\":1,\"timeout\":5,\"slowdown\":6}");
230
+ Assert.That(accepted.error, Is.Null);
231
+ var armed = (Dictionary<string, object>)accepted.result;
232
+ Assert.That(armed["state"], Is.EqualTo("armed"));
233
+
234
+ var stop = _router.Dispatch("record/stop", 3, "{}");
235
+ Assert.That(stop.error, Is.Null);
236
+ Assert.That(((Dictionary<string, object>)stop.result)["state"], Is.EqualTo("idle"));
237
+ }
238
+
126
239
  [Test]
127
240
  public void ProfilerSessionStartStop_TogglesProfilerState()
128
241
  {
@@ -545,6 +658,80 @@ namespace UCP.Bridge.Tests
545
658
  Assert.That(getResult["stackTrace"], Is.EqualTo("stack line 1\nstack line 2"));
546
659
  }
547
660
 
661
+ [Test]
662
+ public void EditorStateSummary_ReportsModeSceneAndConsoleAndCountsNewEntries()
663
+ {
664
+ var cursor = LogsController.GetLatestId();
665
+ var summary = EditorStateSummary.Capture(cursor);
666
+
667
+ Assert.That(summary["mode"], Is.EqualTo("edit"));
668
+ var scene = (Dictionary<string, object>)summary["scene"];
669
+ Assert.That(scene["name"], Is.EqualTo(SceneManager.GetActiveScene().name));
670
+ Assert.That(scene["dirty"], Is.EqualTo(SceneManager.GetActiveScene().isDirty));
671
+ var console = (Dictionary<string, object>)summary["console"];
672
+ Assert.That(Convert.ToInt32(console["errors"]), Is.GreaterThanOrEqualTo(0));
673
+ Assert.That(Convert.ToInt32(console["warnings"]), Is.GreaterThanOrEqualTo(0));
674
+ Assert.That(console.ContainsKey("newWarnings"), Is.False, "nothing was logged after the cursor");
675
+ Assert.That(summary.ContainsKey("recording"), Is.False);
676
+
677
+ LogAssert.Expect(LogType.Warning, "ucp summary probe warning");
678
+ Debug.LogWarning("ucp summary probe warning");
679
+
680
+ var after = (Dictionary<string, object>)EditorStateSummary.Capture(cursor)["console"];
681
+ Assert.That(Convert.ToInt32(after["newWarnings"]), Is.EqualTo(1));
682
+ Assert.That(after.ContainsKey("newErrors"), Is.False);
683
+ LogsController.CountLevels(cursor, out var errors, out var warnings);
684
+ Assert.That(errors, Is.EqualTo(0));
685
+ Assert.That(warnings, Is.EqualTo(1));
686
+ }
687
+
688
+ [Test]
689
+ public void EditorStateSummary_ReadsTheConsoleBadgeCounts()
690
+ {
691
+ Assert.That(EditorStateSummary.TryReadConsoleCounts(out var errors, out var warnings), Is.True,
692
+ "UnityEditor.LogEntries.GetCountsByType must be reachable on this editor");
693
+ Assert.That(errors, Is.GreaterThanOrEqualTo(0));
694
+ Assert.That(warnings, Is.GreaterThanOrEqualTo(0));
695
+ }
696
+
697
+ [Test]
698
+ public void Responses_CarryTheEditorSummaryOnlyWhenDispatchedOnTheMainThread()
699
+ {
700
+ var response = JsonRpcResponse.Success(7, new Dictionary<string, object> { ["ok"] = true });
701
+
702
+ var offThread = BridgeServer.ResponseToDict(response);
703
+ Assert.That(offThread.ContainsKey("editor"), Is.False);
704
+
705
+ var onThread = BridgeServer.ResponseToDict(response, LogsController.GetLatestId());
706
+ var editor = (Dictionary<string, object>)onThread["editor"];
707
+ Assert.That(editor["mode"], Is.EqualTo("edit"));
708
+ Assert.That(onThread["result"], Is.SameAs(response.result));
709
+
710
+ var json = MiniJson.Serialize(onThread);
711
+ var parsed = (Dictionary<string, object>)MiniJson.Deserialize(json);
712
+ Assert.That(((Dictionary<string, object>)parsed["editor"]).ContainsKey("console"), Is.True);
713
+ }
714
+
715
+ [Test]
716
+ public void TestGuard_IgnoresLogsInsideIgnoreFailingMessagesWindows()
717
+ {
718
+ var entries = new List<string>
719
+ {
720
+ "real error before",
721
+ "\n" + LogsController.IgnoreFailingMessagesOnMarker,
722
+ "expected importer error",
723
+ "expected warning",
724
+ LogsController.IgnoreFailingMessagesOffMarker + "\n",
725
+ "real error after",
726
+ LogsController.IgnoreFailingMessagesOnMarker,
727
+ "still ignored when a test never resets the flag"
728
+ };
729
+
730
+ var kept = LogsController.ExcludeExpectedNoise(entries, entry => entry);
731
+
732
+ Assert.That(kept, Is.EqualTo(new[] { "real error before", "real error after" }));
733
+ }
734
+
548
735
  [Test]
549
736
  public void ObjectLifecycle_CreateMutateAndDelete_WorksEndToEnd()
550
737
  {
@@ -552,7 +739,7 @@ namespace UCP.Bridge.Tests
552
739
  Assert.That(create.error, Is.Null);
553
740
 
554
741
  var createResult = (Dictionary<string, object>)create.result;
555
- var instanceId = Convert.ToInt32(createResult["instanceId"]);
742
+ var instanceId = Convert.ToInt64(createResult["instanceId"]);
556
743
 
557
744
  var rename = _router.Dispatch("object/set-name", 1, "{\"instanceId\":" + instanceId + ",\"name\":\"RenamedSmoke\"}");
558
745
  Assert.That(rename.error, Is.Null);
@@ -1264,7 +1451,7 @@ namespace UCP.Bridge.Tests
1264
1451
  {
1265
1452
  var create = _router.Dispatch("object/create", 1, "{\"name\":\"PrefabSource\"}");
1266
1453
  Assert.That(create.error, Is.Null);
1267
- var sourceId = Convert.ToInt32(((Dictionary<string, object>)create.result)["instanceId"]);
1454
+ var sourceId = Convert.ToInt64(((Dictionary<string, object>)create.result)["instanceId"]);
1268
1455
 
1269
1456
  var createPrefab = _router.Dispatch(
1270
1457
  "prefab/create",
@@ -1279,7 +1466,7 @@ namespace UCP.Bridge.Tests
1279
1466
  "{\"prefab\":\"Assets/UcpControllerSmoke.prefab\",\"name\":\"PrefabInstance\"}"
1280
1467
  );
1281
1468
  Assert.That(instantiate.error, Is.Null);
1282
- var instanceId = Convert.ToInt32(((Dictionary<string, object>)instantiate.result)["instanceId"]);
1469
+ var instanceId = Convert.ToInt64(((Dictionary<string, object>)instantiate.result)["instanceId"]);
1283
1470
 
1284
1471
  var status = _router.Dispatch("prefab/status", 1, "{\"instanceId\":" + instanceId + "}");
1285
1472
  Assert.That(status.error, Is.Null);
@@ -1647,4 +1834,5 @@ namespace UCP.Bridge.Tests
1647
1834
  public SearchRootAsset referenceAsset;
1648
1835
  }
1649
1836
  }
1837
+
1650
1838
  }
@@ -62,7 +62,7 @@ namespace UCP.Bridge.Tests
62
62
  {
63
63
  var res = Result(_router.Dispatch("object/create", 1,
64
64
  "{\"name\":\"Greybox\",\"primitive\":\"Cube\"}"));
65
- var id = Convert.ToInt32(res["instanceId"]);
65
+ var id = Convert.ToInt64(res["instanceId"]);
66
66
  var go = ObjectLocator.FindByInstanceId(id);
67
67
  _spawned.Add(go);
68
68
 
@@ -179,7 +179,7 @@ namespace UCP.Bridge.Tests
179
179
  var res = Result(_router.Dispatch("physics/raycast", 1,
180
180
  "{\"origin\":[0,5,0],\"direction\":[0,-1,0]}"));
181
181
  Assert.That(Convert.ToBoolean(res["hit"]), Is.True);
182
- Assert.That(Convert.ToInt32(res["instanceId"]), Is.EqualTo(ground.GetId()));
182
+ Assert.That(Convert.ToInt64(res["instanceId"]), Is.EqualTo(ground.GetId()));
183
183
  }
184
184
 
185
185
  [Test]