@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.
- package/README.md +1 -1
- package/bridge/com.ucp.bridge/CHANGELOG.md +48 -0
- package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs +55 -6
- package/bridge/com.ucp.bridge/Editor/Bridge/EditorStateSummary.cs +165 -0
- package/bridge/com.ucp.bridge/Editor/Bridge/EditorStateSummary.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Compatibility/UnityObjectCompat.cs +22 -5
- package/bridge/com.ucp.bridge/Editor/Controllers/EditorController.cs +1 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/HierarchyController.cs +10 -10
- package/bridge/com.ucp.bridge/Editor/Controllers/LogsController.cs +71 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/MaterialController.cs +2 -2
- package/bridge/com.ucp.bridge/Editor/Controllers/ObjectLocator.cs +4 -4
- package/bridge/com.ucp.bridge/Editor/Controllers/ObjectReferenceResolver.cs +3 -3
- package/bridge/com.ucp.bridge/Editor/Controllers/PrefabController.cs +6 -6
- package/bridge/com.ucp.bridge/Editor/Controllers/PropertyController.cs +7 -7
- package/bridge/com.ucp.bridge/Editor/Controllers/RecordingController.cs +8 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneChangeTracker.cs +3 -3
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs +3 -3
- package/bridge/com.ucp.bridge/Editor/Controllers/SnapshotController.cs +5 -5
- package/bridge/com.ucp.bridge/Editor/Controllers/TestRunnerController.cs +1 -1
- package/bridge/com.ucp.bridge/Editor/Controllers/TransformController.cs +1 -1
- package/bridge/com.ucp.bridge/Editor/Controllers/UiController.cs +70 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/UiController.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ViewController.cs +1 -1
- package/bridge/com.ucp.bridge/Editor/Protocol/MiniJson.cs +1 -1
- package/bridge/com.ucp.bridge/Editor/Ui/UiHost.cs +468 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiHost.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiLintService.cs +554 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiLintService.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiOperationManager.cs +870 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiOperationManager.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioApplier.cs +496 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioApplier.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioLoader.cs +854 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioLoader.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioModels.cs +374 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioModels.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiVisualTreeInspector.cs +690 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiVisualTreeInspector.cs.meta +11 -0
- package/bridge/com.ucp.bridge/{Runtime.meta → Editor/Ui.meta} +1 -1
- package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs +79 -4
- package/bridge/com.ucp.bridge/Tests/Editor/SpatialVisualControllerTests.cs +2 -2
- package/bridge/com.ucp.bridge/Tests/Editor/UiControllerTests.cs +547 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiControllerTests.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiLintServiceTests.cs +253 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiLintServiceTests.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiScenarioTests.cs +587 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiScenarioTests.cs.meta +11 -0
- package/bridge/com.ucp.bridge/package.json +1 -1
- package/package.json +1 -1
- package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef +0 -14
- 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
|