From 24f65c29c73d43e12f2d571859bcfb8f335d6bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?JasonXuDeveloper=20-=20=E5=82=91?= Date: Sun, 1 Feb 2026 13:08:49 +1100 Subject: [PATCH 1/3] test(ui): add comprehensive tests for PanelUI and BootstrapEditorUI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add unit tests for internal UI editor classes: - PanelUITests: tests for JEngine Panel build configuration UI - BootstrapEditorUITests: tests for Bootstrap inspector UI Integration tests (Build All, Build Assets Only with XOR/AES/ChaCha20): - Marked with [Category("Integration")] for separate execution - Test real build functionality against active build target Test infrastructure improvements: - JEngineTestBase: base class with LogAssert.ignoreFailingMessages - TestsSetUp: assembly-level setup to disable auto-baking - AssemblyInfo.cs: InternalsVisibleTo for test assembly access BuildManager improvements: - Simplified error filtering with unified IgnoredErrors array - Added "Bake Ambient Probe" to ignored errors (Unity lighting issue) - Added "catalog file failed" to ignored errors (YooAsset bug) Co-Authored-By: Claude Opus 4.5 Signed-off-by: JasonXuDeveloper - 傑 --- .../Editor/CustomEditor/BuildManager.cs | 56 +- .../Editor/AssemblyInfo.cs | 29 + .../Editor/AssemblyInfo.cs.meta | 11 + .../Tests/Editor/Internal.meta | 8 + .../Editor/Internal/BootstrapEditorUITests.cs | 561 ++++++++++++++ .../Internal/BootstrapEditorUITests.cs.meta | 11 + .../Tests/Editor/Internal/PanelUITests.cs | 690 ++++++++++++++++++ .../Editor/Internal/PanelUITests.cs.meta | 11 + .../Editor/JEngine.UI.Editor.Tests.asmdef | 2 + .../Tests/Editor/JEngineTestBase.cs | 33 + .../Tests/Editor/JEngineTestBase.cs.meta | 11 + .../Tests/Editor/MessageBoxTests.cs | 8 +- .../Tests/Editor/TestsSetUp.cs | 38 + .../Tests/Editor/TestsSetUp.cs.meta | 11 + 14 files changed, 1454 insertions(+), 26 deletions(-) create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Editor/AssemblyInfo.cs create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Editor/AssemblyInfo.cs.meta create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal.meta create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal/BootstrapEditorUITests.cs create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal/BootstrapEditorUITests.cs.meta create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal/PanelUITests.cs create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal/PanelUITests.cs.meta create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/JEngineTestBase.cs create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/JEngineTestBase.cs.meta create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/TestsSetUp.cs create mode 100644 UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/TestsSetUp.cs.meta diff --git a/UnityProject/Packages/com.jasonxudeveloper.jengine.core/Editor/CustomEditor/BuildManager.cs b/UnityProject/Packages/com.jasonxudeveloper.jengine.core/Editor/CustomEditor/BuildManager.cs index 046a1356..2ff548f7 100644 --- a/UnityProject/Packages/com.jasonxudeveloper.jengine.core/Editor/CustomEditor/BuildManager.cs +++ b/UnityProject/Packages/com.jasonxudeveloper.jengine.core/Editor/CustomEditor/BuildManager.cs @@ -234,11 +234,10 @@ private void ExecuteCurrentStep() UpdateProgress(0.3f, "Compiling and Obfuscating"); ExecuteMenuItem("HybridCLR/ObfuzExtension/GenerateAll", "Step 3/4"); - CheckForErrorsExcluding("Step 3/4 failed - HybridCLR generation failed", - "Create package main catalog file failed"); + CheckForErrors("Step 3/4 failed - HybridCLR generation failed"); // Reset error baseline after filtering excluded errors - // so subsequent steps don't see the ignored YooAsset catalog errors + // so subsequent steps don't see the ignored errors _errorCountAtStart = GetUnityErrorCount(); _currentStep = BuildStep.GeneratePolymorphicCodes; @@ -451,38 +450,37 @@ private void ExecuteMenuItem(string menuPath, string stepName) } } - private void CheckForErrors(string context) + // Error messages that should always be ignored during build + // These are Unity internal errors or known issues unrelated to the actual build process + private static readonly string[] IgnoredErrors = { - int currentErrorCount = GetUnityErrorCount(); - if (currentErrorCount > _errorCountAtStart) - { - throw new Exception($"{context}: {currentErrorCount - _errorCountAtStart} error(s) occurred. Check Unity Console for details."); - } - } + "Bake Ambient Probe", // Unity lighting error that occurs during editor operations + "catalog file failed", // YooAsset catalog bug during HybridCLR generation (any package) + }; - private void CheckForErrorsExcluding(string context, string excludeMessageContaining) + private void CheckForErrors(string context) { int currentErrorCount = GetUnityErrorCount(); if (currentErrorCount > _errorCountAtStart) { - // Check if the new errors are only the excluded error + // Check if the new errors are only ignored errors int newErrorCount = currentErrorCount - _errorCountAtStart; - int nonExcludedErrors = CountNonExcludedErrors(excludeMessageContaining, newErrorCount); + int realErrors = CountRealErrors(newErrorCount); - if (nonExcludedErrors > 0) + if (realErrors > 0) { - throw new Exception($"{context}: {nonExcludedErrors} error(s) occurred. Check Unity Console for details."); + throw new Exception($"{context}: {realErrors} error(s) occurred. Check Unity Console for details."); } - // If we have errors but they're all excluded, log a warning but continue + // If we have errors but they're all ignored, log a note but continue if (newErrorCount > 0) { - Log($"Note: {newErrorCount} known error(s) ignored (YooAsset catalog bug)"); + Log($"Note: {newErrorCount} known error(s) ignored"); } } } - private int CountNonExcludedErrors(string excludeMessageContaining, int recentErrorCount) + private int CountRealErrors(int recentErrorCount) { try { @@ -505,7 +503,7 @@ private int CountNonExcludedErrors(string excludeMessageContaining, int recentEr int totalCount = (int)getCountMethod.Invoke(null, null); startGettingEntriesMethod.Invoke(null, null); - int nonExcludedCount = 0; + int realErrorCount = 0; int checkedErrors = 0; // Check recent errors from the end of the log @@ -528,21 +526,21 @@ private int CountNonExcludedErrors(string excludeMessageContaining, int recentEr if (messageField != null) { string message = (string)messageField.GetValue(entry); - if (!message.Contains(excludeMessageContaining)) + if (!IsIgnoredError(message)) { - nonExcludedCount++; + realErrorCount++; } } else { - nonExcludedCount++; + realErrorCount++; } } } } endGettingEntriesMethod.Invoke(null, null); - return nonExcludedCount; + return realErrorCount; } catch { @@ -551,6 +549,18 @@ private int CountNonExcludedErrors(string excludeMessageContaining, int recentEr } } + private static bool IsIgnoredError(string errorMessage) + { + foreach (var ignoredError in IgnoredErrors) + { + if (errorMessage.Contains(ignoredError)) + { + return true; + } + } + return false; + } + private int GetUnityErrorCount() { var logEntriesType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.LogEntries"); diff --git a/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Editor/AssemblyInfo.cs b/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Editor/AssemblyInfo.cs new file mode 100644 index 00000000..a04aa950 --- /dev/null +++ b/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Editor/AssemblyInfo.cs @@ -0,0 +1,29 @@ +// AssemblyInfo.cs +// +// Author: +// JasonXuDeveloper +// +// Copyright (c) 2025 JEngine +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System.Runtime.CompilerServices; + +// Allow test assembly to access internal types +[assembly: InternalsVisibleTo("JEngine.UI.Editor.Tests")] diff --git a/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Editor/AssemblyInfo.cs.meta b/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Editor/AssemblyInfo.cs.meta new file mode 100644 index 00000000..48ff598a --- /dev/null +++ b/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Editor/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6d03c2b029ee4d059d63fd5aa04b61f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal.meta b/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal.meta new file mode 100644 index 00000000..2a247188 --- /dev/null +++ b/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0b809e9e98e240a5904d343786cb85c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal/BootstrapEditorUITests.cs b/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal/BootstrapEditorUITests.cs new file mode 100644 index 00000000..41aba578 --- /dev/null +++ b/UnityProject/Packages/com.jasonxudeveloper.jengine.ui/Tests/Editor/Internal/BootstrapEditorUITests.cs @@ -0,0 +1,561 @@ +// BootstrapEditorUITests.cs +// EditMode unit tests for BootstrapEditorUI + +using System.Reflection; +using NUnit.Framework; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; +using JEngine.Core; +using JEngine.Core.Encrypt; +using JEngine.Core.Update; +using JEngine.UI.Editor.Components.Button; +using JEngine.UI.Editor.Components.Form; +using JEngine.UI.Editor.Components.Layout; +using JEngine.UI.Editor.Internal; +using JEngine.UI.Tests; + +namespace JEngine.UI.Tests.Editor.Internal +{ + [TestFixture] + public class BootstrapEditorUITests : JEngineTestBase + { + private Bootstrap _bootstrap; + private SerializedObject _serializedObject; + private GameObject _gameObject; + + [SetUp] + public override void BaseSetUp() + { + base.BaseSetUp(); + _gameObject = new GameObject("TestBootstrap"); + _bootstrap = _gameObject.AddComponent(); + _serializedObject = new SerializedObject(_bootstrap); + + // Set default values + _bootstrap.defaultHostServer = "http://127.0.0.1/"; + _bootstrap.fallbackHostServer = "http://127.0.0.1/"; + _bootstrap.useDefaultAsFallback = true; + _bootstrap.appendTimeTicks = true; + _bootstrap.targetPlatform = TargetPlatform.Regular; + _bootstrap.packageName = "main"; + _bootstrap.hotCodeName = "HotUpdate.Code.dll"; + _bootstrap.encryptionOption = EncryptionOption.Xor; + } + + [TearDown] + public override void BaseTearDown() + { + base.BaseTearDown(); + if (_gameObject != null) + UnityEngine.Object.DestroyImmediate(_gameObject); + } + + #region UI Creation Tests + + [Test] + public void CreateInspector_ReturnsNonNullRoot() + { + var root = BootstrapEditorUI.CreateInspector(_serializedObject, _bootstrap); + + Assert.IsNotNull(root); + } + + [Test] + public void CreateInspector_ContainsHeader() + { + var root = BootstrapEditorUI.CreateInspector(_serializedObject, _bootstrap); + + var labels = root.Query