Skip to content

[UUM-138957] Remove runtime test dependency on UnityEditor APIs#664

Open
lopezt-unity wants to merge 8 commits intomasterfrom
bugfix/uum-138957-remove-runtime-test-dependency-on-unityeditor-apis
Open

[UUM-138957] Remove runtime test dependency on UnityEditor APIs#664
lopezt-unity wants to merge 8 commits intomasterfrom
bugfix/uum-138957-remove-runtime-test-dependency-on-unityeditor-apis

Conversation

@lopezt-unity
Copy link
Copy Markdown
Collaborator

Purpose of this PR

The PR changes the way Framework and Runtime tests are working in ProBuilder.

Previously these supposedly runtime tests where using UnityEditor APIs, which was failing on some trunk tests.

For more context:
Two probuilder test assembly definitions (Unity.ProBuilder.Tests.Framework.asmdef and Unity.ProBuilder.Tests.asmdef) had "includePlatforms": [] (all platforms) despite using UnityEditor.* APIs (AssetDatabase, EditorSceneManager, PackageManager.PackageInfo). These editor-only APIs are unavailable to runtime assemblies, causing CS0234/CS0103 compilation errors, that's why I wanted to merge those changes in my PR. By changing both "includePlatforms": ["Editor"] to match their actual dependencies, consistent with the existing Unity.ProBuilder.Editor.Tests.asmdef , the jobs no longer fail.

However, runtime tests should not be relying on Editor APIs.
This PR update the runtime tests to get rid of the different Editor APIs used in it.

Most changes are:

  • Runtime test asmdef does not rely on Tests.Framework anymore
  • Needed methods from TestUtility.cs (in Tests.Framework) have been moved to RuntimeUtility.cs
  • Assets used to compare a mesh edited in a test vs the expected result have been moved from the Template folder to a Resources one so that they can be loaded directly using Resources.Load()
  • RuntimeUtility.cs have been updated accordingly

Links

Jira: https://jira.unity3d.com/browse/UUM-138957

Comments to Reviewers

All the tests have be re-run in the Editor (Editor and Playmode) and are all 🟢

Copy link
Copy Markdown

@u-pr u-pr bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May require changes
The PR introduces significant improvements for runtime testing, but there are a few critical issues that need to be addressed:

  • Logic Error: A logic error in submesh index comparison in RuntimeUtility will lead to incorrect test results.
  • Build Failure Risk: Including UnityEditor.TestRunner in a runtime assembly definition will cause build failures on standalone platforms.
  • Resource Loading: The resource path resolution relies on StackTrace, which is unreliable in non-development runtime builds.
  • Memory Management: Several tests destroy components instead of GameObjects, leading to object leaks in the test runner.

🤖 Helpful? 👍/👎

int vertexCount = expected.vertexCount;
int subMeshCount = expected.subMeshCount;

Assert.AreEqual(vertexCount, result.vertexCount, expected.name + " != " + result.name + " (submesh count)");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium
In AssertAreEqual, the assertion message for the vertexCount check incorrectly identifies it as a "submesh count" failure. This will make it difficult to debug test failures.

Suggested change
Assert.AreEqual(vertexCount, result.vertexCount, expected.name + " != " + result.name + " (submesh count)");
Assert.AreEqual(vertexCount, result.vertexCount, expected.name + " != " + result.name + " (vertex count)");

🤖 Helpful? 👍/👎

Comment on lines +192 to +204
for (int i = 0; i < subMeshCount; i++)
{
uint indexCount = expected.GetIndexCount(i);

Assert.AreEqual(expected.GetTopology(i), result.GetTopology(i));
Assert.AreEqual(indexCount, result.GetIndexCount(i));

expected.GetIndices(leftIndices, i);
result.GetIndices(rightIndices, i);

for (int n = 0; n < indexCount; n++)
Assert.AreEqual(leftIndices[n], rightIndices[n], message);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high
There is a logic error in how submesh indices are compared. The leftIndices and rightIndices lists are declared outside the subMeshCount loop (lines 189-190) and mesh.GetIndices(list, submesh) in Unity appends to the list rather than clearing it.

Consequently, for any submesh after the first (i > 0), the lists will contain indices from all previous submeshes, and the inner loop (line 202) will re-validate the indices of the first submesh rather than the current one. The lists should be cleared at the start of each iteration.

Suggested change
for (int i = 0; i < subMeshCount; i++)
{
uint indexCount = expected.GetIndexCount(i);
Assert.AreEqual(expected.GetTopology(i), result.GetTopology(i));
Assert.AreEqual(indexCount, result.GetIndexCount(i));
expected.GetIndices(leftIndices, i);
result.GetIndices(rightIndices, i);
for (int n = 0; n < indexCount; n++)
Assert.AreEqual(leftIndices[n], rightIndices[n], message);
}
for (int i = 0; i < subMeshCount; i++)
{
uint indexCount = expected.GetIndexCount(i);
Assert.AreEqual(expected.GetTopology(i), result.GetTopology(i));
Assert.AreEqual(indexCount, result.GetIndexCount(i));
leftIndices.Clear();
rightIndices.Clear();
expected.GetIndices(leftIndices, i);
result.GetIndices(rightIndices, i);
for (int n = 0; n < (int)indexCount; n++)
Assert.AreEqual(leftIndices[n], rightIndices[n], message);
}

🤖 Helpful? 👍/👎

"optionalUnityReferences": [
"TestAssemblies"
"UnityEngine.TestRunner",
"UnityEditor.TestRunner"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high
Adding UnityEditor.TestRunner to the references list of an assembly with empty includePlatforms (which means all platforms) will cause build failures when targeting non-Editor platforms (e.g., Standalone, Android, iOS).

Since this PR's goal is to remove references to UnityEditor from runtime tests, this reference should likely be removed or the assembly should be restricted to the Editor platform.

🤖 Helpful? 👍/👎


UnityEngine.Object.DestroyImmediate(cube);
}
Object.DestroyImmediate(cube);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium
Calling Object.DestroyImmediate(cube) where cube is a ProBuilderMesh component will only destroy the component itself, leaving the GameObject (and any other components attached to it) orphaned in the scene.

Given that these tests often use ValueSource or are run repeatedly, this causes a significant memory and object leak in the test environment. It should be changed to Object.DestroyImmediate(cube.gameObject), as correctly done in RuntimeUtility.BuiltInPrimitives.Dispose (line 48).

Suggested change
Object.DestroyImmediate(cube);
Object.DestroyImmediate(cube.gameObject);

🤖 Helpful? 👍/👎

StackTrace trace = new StackTrace(1 + methodOffset, true);
StackFrame calling = trace.GetFrame(0);

string filePath = calling.GetFileName();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium
The GetResourcesPath method relies on StackTrace.GetFileName() to construct resource paths. In Unity, GetFileName() returns null in built players (non-editor) unless full symbols are provided and the build is a Development Build.

Since this utility is intended to support the transition to runtime tests, this implementation detail effectively prevents these tests from running successfully in a standalone player environment. Consider using the [System.Runtime.CompilerServices.CallerFilePath] attribute; it is resolved at compile-time and provides a more reliable way to identify the caller's file path.

🤖 Helpful? 👍/👎

RuntimeUtility.AssertSequenceEqual(submesh0, compiled0);
RuntimeUtility.AssertSequenceEqual(submesh1, compiled1);

UObject.DestroyImmediate(mesh);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium
This call destroys only the component. To ensure proper cleanup of the test environment, consider destroying the gameObject instead to avoid orphaning objects in the scene.

Suggested change
UObject.DestroyImmediate(mesh);
UObject.DestroyImmediate(mesh.gameObject);

🤖 Helpful? 👍/👎

if (string.IsNullOrEmpty(filePath))
{
UnityEngine.Debug.LogError(
"Cannot generate mesh templates directory path from calling method. Please use the explicit SaveMeshTemplate overload.");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low
The error message mentions SaveMeshTemplate, which appears to be a copy-paste error from TestUtility.SaveAssetTemplate. It should probably refer to GetResourcesPath or a more general error.

Suggested change
"Cannot generate mesh templates directory path from calling method. Please use the explicit SaveMeshTemplate overload.");
"Cannot generate mesh templates directory path from calling method. Please use the explicit GetResourcesPath overload."

🤖 Helpful? 👍/👎

}

// Get the calling file path relative to the `Tests/` directory
string fullFilePath = Path.GetFullPath(filePath).Replace("\\", "/");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low
The variable fullFilePath is assigned but never used. Additionally, there are several lines of commented-out code (lines 225-227) that should likely be removed to keep the utility class maintainable.

🤖 Helpful? 👍/👎

@lopezt-unity lopezt-unity requested a review from xianenli30 April 2, 2026 19:02
@codecov-github-com
Copy link
Copy Markdown

codecov-github-com bot commented Apr 2, 2026

Codecov Report

All modified and coverable lines are covered by tests ✅

@@            Coverage Diff             @@
##           master     #664      +/-   ##
==========================================
+ Coverage   36.05%   37.02%   +0.96%     
==========================================
  Files         277      277              
  Lines       34909    34970      +61     
==========================================
+ Hits        12588    12948     +360     
+ Misses      22321    22022     -299     
Flag Coverage Δ
probuilder_MacOS_6000.0 35.54% <ø> (+0.96%) ⬆️
probuilder_MacOS_6000.3 35.54% <ø> (+0.96%) ⬆️
probuilder_MacOS_6000.4 35.54% <ø> (+0.97%) ⬆️
probuilder_MacOS_6000.5 35.54% <ø> (+0.96%) ⬆️
probuilder_MacOS_6000.6 35.54% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

see 47 files with indirect coverage changes

ℹ️ Need help interpreting these results?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant