@mflrevan/ucp 0.6.2 → 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 (51) hide show
  1. package/README.md +1 -1
  2. package/bridge/com.ucp.bridge/CHANGELOG.md +48 -0
  3. package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs +55 -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 +7 -7
  15. package/bridge/com.ucp.bridge/Editor/Controllers/RecordingController.cs +8 -0
  16. package/bridge/com.ucp.bridge/Editor/Controllers/SceneChangeTracker.cs +3 -3
  17. package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs +3 -3
  18. package/bridge/com.ucp.bridge/Editor/Controllers/SnapshotController.cs +5 -5
  19. package/bridge/com.ucp.bridge/Editor/Controllers/TestRunnerController.cs +1 -1
  20. package/bridge/com.ucp.bridge/Editor/Controllers/TransformController.cs +1 -1
  21. package/bridge/com.ucp.bridge/Editor/Controllers/UiController.cs +70 -0
  22. package/bridge/com.ucp.bridge/Editor/Controllers/UiController.cs.meta +11 -0
  23. package/bridge/com.ucp.bridge/Editor/Controllers/ViewController.cs +1 -1
  24. package/bridge/com.ucp.bridge/Editor/Protocol/MiniJson.cs +1 -1
  25. package/bridge/com.ucp.bridge/Editor/Ui/UiHost.cs +468 -0
  26. package/bridge/com.ucp.bridge/Editor/Ui/UiHost.cs.meta +11 -0
  27. package/bridge/com.ucp.bridge/Editor/Ui/UiLintService.cs +554 -0
  28. package/bridge/com.ucp.bridge/Editor/Ui/UiLintService.cs.meta +11 -0
  29. package/bridge/com.ucp.bridge/Editor/Ui/UiOperationManager.cs +870 -0
  30. package/bridge/com.ucp.bridge/Editor/Ui/UiOperationManager.cs.meta +11 -0
  31. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioApplier.cs +496 -0
  32. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioApplier.cs.meta +11 -0
  33. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioLoader.cs +854 -0
  34. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioLoader.cs.meta +11 -0
  35. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioModels.cs +374 -0
  36. package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioModels.cs.meta +11 -0
  37. package/bridge/com.ucp.bridge/Editor/Ui/UiVisualTreeInspector.cs +690 -0
  38. package/bridge/com.ucp.bridge/Editor/Ui/UiVisualTreeInspector.cs.meta +11 -0
  39. package/bridge/com.ucp.bridge/{Runtime.meta → Editor/Ui.meta} +1 -1
  40. package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs +79 -4
  41. package/bridge/com.ucp.bridge/Tests/Editor/SpatialVisualControllerTests.cs +2 -2
  42. package/bridge/com.ucp.bridge/Tests/Editor/UiControllerTests.cs +547 -0
  43. package/bridge/com.ucp.bridge/Tests/Editor/UiControllerTests.cs.meta +11 -0
  44. package/bridge/com.ucp.bridge/Tests/Editor/UiLintServiceTests.cs +253 -0
  45. package/bridge/com.ucp.bridge/Tests/Editor/UiLintServiceTests.cs.meta +11 -0
  46. package/bridge/com.ucp.bridge/Tests/Editor/UiScenarioTests.cs +587 -0
  47. package/bridge/com.ucp.bridge/Tests/Editor/UiScenarioTests.cs.meta +11 -0
  48. package/bridge/com.ucp.bridge/package.json +1 -1
  49. package/package.json +1 -1
  50. package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef +0 -14
  51. package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef.meta +0 -7
@@ -0,0 +1,253 @@
1
+ #if UNITY_6000_0_OR_NEWER
2
+ using System;
3
+ using System.Collections.Generic;
4
+ using System.IO;
5
+ using System.Linq;
6
+ using NUnit.Framework;
7
+ using UnityEditor;
8
+ using UnityEngine;
9
+ using UnityEngine.TestTools;
10
+
11
+ namespace UCP.Bridge.Tests
12
+ {
13
+ public sealed class UiLintServiceTests
14
+ {
15
+ private const string Root = "Assets/UcpUiLintServiceTests";
16
+
17
+ [SetUp]
18
+ public void SetUp()
19
+ {
20
+ AssetDatabase.DeleteAsset(Root);
21
+ AssetDatabase.CreateFolder("Assets", "UcpUiLintServiceTests");
22
+ }
23
+
24
+ [TearDown]
25
+ public void TearDown()
26
+ {
27
+ AssetDatabase.DeleteAsset(Root);
28
+ }
29
+
30
+ [Test]
31
+ public void ValidUxmlAndUss_AreImportedAndCloned()
32
+ {
33
+ var ussPath = Root + "/Valid.uss";
34
+ var uxmlPath = Root + "/Valid.uxml";
35
+ WriteAsset(ussPath, ".probe { width: 100px; }\n");
36
+ WriteAsset(
37
+ uxmlPath,
38
+ "<ui:UXML xmlns:ui=\"UnityEngine.UIElements\" editor-extension-mode=\"True\">\n" +
39
+ " <ui:Label name=\"probe\" text=\"Ready\" />\n" +
40
+ "</ui:UXML>\n");
41
+
42
+ var result = UiLintService.Run(new Dictionary<string, object>
43
+ {
44
+ ["paths"] = new List<object> { uxmlPath, ussPath },
45
+ ["failOnWarnings"] = true,
46
+ ["maxDiagnostics"] = 50
47
+ });
48
+
49
+ Assert.That(result["passed"], Is.True);
50
+ Assert.That(Convert.ToInt32(result["errorCount"]), Is.EqualTo(0));
51
+ Assert.That(Convert.ToInt32(result["warningCount"]), Is.EqualTo(0));
52
+ var assets = ((List<object>)result["assets"])
53
+ .Cast<Dictionary<string, object>>()
54
+ .ToList();
55
+ var uxml = assets.Single(asset => asset["path"].ToString() == uxmlPath);
56
+ Assert.That(uxml["cloneAttempted"], Is.True);
57
+ Assert.That(uxml["cloneSucceeded"], Is.True);
58
+ Assert.That(Convert.ToInt32(uxml["cloneElementCount"]), Is.GreaterThanOrEqualTo(2));
59
+ }
60
+
61
+ [TestCase("ImportError", "error")]
62
+ [TestCase("Warning", "warning")]
63
+ [TestCase("Info", null)]
64
+ [TestCase(null, null)]
65
+ public void ImportSeverity_IsClassifiedWithoutEmittingConsoleErrors(
66
+ string flags,
67
+ string expected)
68
+ {
69
+ Assert.That(UiLintService.ClassifyImportSeverity(flags), Is.EqualTo(expected));
70
+ }
71
+
72
+ [TestCase(LogType.Error, "error")]
73
+ [TestCase(LogType.Assert, "error")]
74
+ [TestCase(LogType.Exception, "error")]
75
+ [TestCase(LogType.Warning, "warning")]
76
+ [TestCase(LogType.Log, null)]
77
+ public void CloneLogSeverity_IsClassifiedWithoutEmittingConsoleErrors(
78
+ LogType type,
79
+ string expected)
80
+ {
81
+ Assert.That(UiLintService.ClassifyLogSeverity(type), Is.EqualTo(expected));
82
+ }
83
+
84
+ [Test]
85
+ public void WarningFailurePolicy_IsExplicit()
86
+ {
87
+ Assert.That(UiLintService.Passes(0, 1, false), Is.True);
88
+ Assert.That(UiLintService.Passes(0, 1, true), Is.False);
89
+ Assert.That(UiLintService.Passes(1, 0, false), Is.False);
90
+ }
91
+
92
+ [TestCase(1)]
93
+ [TestCase(3)]
94
+ public void DiagnosticLimit_PreservesErrorsAndCountsEverySeverity(int limit)
95
+ {
96
+ var collector = new UiLintService.DiagnosticCollector(limit);
97
+ for (var index = 0; index < limit + 1; index++)
98
+ collector.Add("warning", "warning-" + index, Root, "test", "warning");
99
+ collector.Add("error", "late-error", Root, "test", "cause of failure");
100
+ Assert.That(collector.ErrorCount, Is.EqualTo(1));
101
+ Assert.That(collector.WarningCount, Is.EqualTo(limit + 1));
102
+ Assert.That(collector.Truncated, Is.True);
103
+ Assert.That(collector.Items, Has.Count.EqualTo(limit));
104
+ var details = collector.Items.Cast<Dictionary<string, object>>().ToList();
105
+ Assert.That(details.Last()["code"], Is.EqualTo("late-error"));
106
+ if (limit > 1)
107
+ Assert.That(details[limit - 2]["code"], Is.EqualTo("warning-" + (limit - 2)));
108
+ for (var index = 0; index < limit; index++)
109
+ collector.Add("error", "error-" + index, Root, "test", "error");
110
+ collector.Add("warning", "dropped", Root, "test", "warning");
111
+ Assert.That(collector.ErrorCount, Is.EqualTo(limit + 1));
112
+ Assert.That(collector.WarningCount, Is.EqualTo(limit + 2));
113
+ Assert.That(collector.Items, Has.Count.EqualTo(limit));
114
+ Assert.That(collector.Items.Cast<Dictionary<string, object>>()
115
+ .All(item => Equals(item["severity"], "error")), Is.True);
116
+ Assert.That(((Dictionary<string, object>)collector.Items[0])["code"], Is.EqualTo("late-error"));
117
+ }
118
+
119
+ [TestCase(false)]
120
+ [TestCase(true)]
121
+ public void ThemeStyleSheets_AreLintedWithTheirDependencies(bool folder)
122
+ {
123
+ WriteAsset(Root + "/Theme.uss", ".probe { width: 100px; }\n");
124
+ WriteAsset(Root + "/Theme.tss", "@import url(\"Theme.uss\");\n");
125
+ var result = UiLintService.Run(new Dictionary<string, object>
126
+ {
127
+ ["paths"] = new List<object> { folder ? Root : Root + "/Theme.tss" },
128
+ ["failOnWarnings"] = true
129
+ });
130
+ Assert.That(result["passed"], Is.True, MiniJson.Serialize(result));
131
+ var assets = ((List<object>)result["assets"]).Cast<Dictionary<string, object>>().ToList();
132
+ Assert.That(assets.Select(asset => asset["path"]),
133
+ Does.Contain(Root + "/Theme.tss").And.Contain(Root + "/Theme.uss"));
134
+ Assert.That(assets.All(asset => Equals(asset["reimported"], true)), Is.True);
135
+ }
136
+
137
+ [Test]
138
+ public void ImmutablePackageStyleSheet_UsesExistingImport()
139
+ {
140
+ var path = AssetDatabase.GetAllAssetPaths().FirstOrDefault(candidate =>
141
+ candidate.StartsWith("Packages/", StringComparison.Ordinal) &&
142
+ (candidate.EndsWith(".uss", StringComparison.OrdinalIgnoreCase) ||
143
+ candidate.EndsWith(".tss", StringComparison.OrdinalIgnoreCase)) &&
144
+ !UiLintService.ShouldReimport(candidate));
145
+ if (path == null)
146
+ Assert.Ignore("No immutable package stylesheet is installed");
147
+ var result = UiLintService.Run(new Dictionary<string, object>
148
+ {
149
+ ["paths"] = new List<object> { path }
150
+ });
151
+ var asset = ((List<object>)result["assets"]).Cast<Dictionary<string, object>>()
152
+ .SingleOrDefault(item => Equals(item["path"], path));
153
+ Assert.That(asset, Is.Not.Null, MiniJson.Serialize(result));
154
+ Assert.That(asset["reimported"], Is.False);
155
+ Assert.That(asset["assetType"], Is.Not.Null);
156
+ Assert.That(((List<object>)result["diagnostics"]).Cast<Dictionary<string, object>>()
157
+ .Any(item => Equals(item["code"], "UI_IMPORT_FAILED")), Is.False);
158
+ }
159
+
160
+ [Test]
161
+ public void BrokenStyleSheet_FailsLintThroughTheRouterWithAssetScopedDiagnostics()
162
+ {
163
+ var ussPath = Root + "/Broken.uss";
164
+ LogAssert.ignoreFailingMessages = true;
165
+ try
166
+ {
167
+ WriteAsset(ussPath, ".probe { widht: 100px; colr: red }\n");
168
+ var router = new CommandRouter();
169
+ UiController.Register(router);
170
+
171
+ var response = router.Dispatch(
172
+ "ui/lint",
173
+ 1,
174
+ "{\"paths\":[\"" + ussPath + "\"],\"failOnWarnings\":true}");
175
+
176
+ Assert.That(response.error, Is.Null);
177
+ var result = (Dictionary<string, object>)response.result;
178
+ Assert.That(result["passed"], Is.False, MiniJson.Serialize(result));
179
+ Assert.That(
180
+ Convert.ToInt32(result["errorCount"]) + Convert.ToInt32(result["warningCount"]),
181
+ Is.GreaterThanOrEqualTo(1));
182
+ var diagnostics = ((List<object>)result["diagnostics"]).Cast<Dictionary<string, object>>().ToList();
183
+ Assert.That(
184
+ diagnostics.Any(item => Equals(item["assetPath"], ussPath) && Equals(item["source"], "import")),
185
+ Is.True,
186
+ MiniJson.Serialize(result));
187
+ }
188
+ finally
189
+ {
190
+ LogAssert.ignoreFailingMessages = false;
191
+ }
192
+ }
193
+
194
+ [Test]
195
+ public void UnknownUxmlElement_IsReportedAgainstTheDocument()
196
+ {
197
+ var uxmlPath = Root + "/Unknown.uxml";
198
+ LogAssert.ignoreFailingMessages = true;
199
+ try
200
+ {
201
+ WriteAsset(
202
+ uxmlPath,
203
+ "<ui:UXML xmlns:ui=\"UnityEngine.UIElements\">\n" +
204
+ " <ui:NoSuchElement name=\"probe\" />\n" +
205
+ "</ui:UXML>\n");
206
+
207
+ var result = UiLintService.Run(new Dictionary<string, object>
208
+ {
209
+ ["paths"] = new List<object> { uxmlPath },
210
+ ["failOnWarnings"] = true
211
+ });
212
+
213
+ Assert.That(result["passed"], Is.False, MiniJson.Serialize(result));
214
+ var diagnostics = ((List<object>)result["diagnostics"]).Cast<Dictionary<string, object>>().ToList();
215
+ Assert.That(diagnostics.Any(item => Equals(item["assetPath"], uxmlPath)), Is.True, MiniJson.Serialize(result));
216
+ var asset = ((List<object>)result["assets"]).Cast<Dictionary<string, object>>()
217
+ .Single(item => Equals(item["path"], uxmlPath));
218
+ Assert.That(asset["cloneAttempted"], Is.True);
219
+ }
220
+ finally
221
+ {
222
+ LogAssert.ignoreFailingMessages = false;
223
+ }
224
+ }
225
+
226
+ [Test]
227
+ public void MissingAndUnsupportedPaths_BecomeDiagnosticsInsteadOfExceptions()
228
+ {
229
+ var result = UiLintService.Run(new Dictionary<string, object>
230
+ {
231
+ ["paths"] = new List<object> { Root + "/Missing.uxml", Root + "/Notes.txt" }
232
+ });
233
+
234
+ Assert.That(result["passed"], Is.False);
235
+ Assert.That(Convert.ToInt32(result["assetCount"]), Is.EqualTo(0));
236
+ var codes = ((List<object>)result["diagnostics"]).Cast<Dictionary<string, object>>()
237
+ .Select(item => item["code"]).ToList();
238
+ Assert.That(codes, Does.Contain("UI_ASSET_NOT_FOUND"));
239
+ Assert.That(codes, Does.Contain("UI_PATH_UNSUPPORTED"));
240
+ }
241
+
242
+ private static void WriteAsset(string assetPath, string contents)
243
+ {
244
+ var projectRoot = Path.GetFullPath(Path.Combine(Application.dataPath, ".."));
245
+ var absolutePath = Path.Combine(projectRoot, assetPath);
246
+ File.WriteAllText(absolutePath, contents);
247
+ AssetDatabase.ImportAsset(
248
+ assetPath,
249
+ ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport);
250
+ }
251
+ }
252
+ }
253
+ #endif
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: c81e33a1de8b49f9b9820567cb3e4b40
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant: