diff --git a/README.md b/README.md index 59e372c..cf56ca5 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,7 @@ It has the following benefits: - Can be use same code for running Edit Mode tests, Play Mode tests in Editor, and on Player. - Can be specified scenes that are **NOT** in "Scenes in Build". - Can be specified path by glob pattern. However, there are restrictions, top level and scene name cannot be omitted. +- Can be specified path by relative path from the test class file. - This attribute can attached to the test method only. It can be used with sync Tests, async Tests, and UnityTest. @@ -239,6 +240,20 @@ public class MyTestClass var cube = GameObject.Find("Cube in TestScene"); Assert.That(cube, Is.Not.Null); } + + [Test] + [LoadScene("Packages/YourPackageName/**/SampleScene.unity")] + public void UsingGlobPattern() + { + // snip + } + + [Test] + [LoadScene("../../Scenes/SampleScene.unity")] + public void UsingRelativePath() + { + // snip + } } ``` diff --git a/Runtime/Attributes/LoadSceneAttribute.cs b/Runtime/Attributes/LoadSceneAttribute.cs index 8f0c06c..2302b1e 100644 --- a/Runtime/Attributes/LoadSceneAttribute.cs +++ b/Runtime/Attributes/LoadSceneAttribute.cs @@ -1,8 +1,11 @@ -// Copyright (c) 2023 Koji Hasegawa. +// Copyright (c) 2023-2024 Koji Hasegawa. // This software is released under the MIT License. using System; using System.Collections; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.CompilerServices; using NUnit.Framework; using NUnit.Framework.Interfaces; using TestHelper.Utils; @@ -37,6 +40,7 @@ public class LoadSceneAttribute : NUnitAttribute, IOuterUnityTestAction /// /// Load scene before running test. /// Can be specified path by glob pattern. However, there are restrictions, top level and scene name cannot be omitted. + /// Can be specified relative path. /// /// Scene file path. /// The path starts with `Assets/` or `Packages/`. @@ -44,9 +48,38 @@ public class LoadSceneAttribute : NUnitAttribute, IOuterUnityTestAction /// (e.g., `Packages/com.nowsprinting.test-helper/Tests/Scenes/Scene.unity`) /// /// - public LoadSceneAttribute(string path) + public LoadSceneAttribute(string path, [CallerFilePath] string callerFilePath = null) { - ScenePath = path; + if (path.StartsWith(".")) + { + ScenePath = GetAbsolutePath(path, callerFilePath); + } + else + { + ScenePath = path; + } + } + + [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] + internal static string GetAbsolutePath(string relativePath, string callerFilePath) + { + var callerDirectory = Path.GetDirectoryName(callerFilePath); + var absolutePath = Path.GetFullPath(Path.Combine(callerDirectory, relativePath)); + + var assetsIndexOf = absolutePath.IndexOf("Assets", StringComparison.Ordinal); + if (assetsIndexOf > 0) + { + return absolutePath.Substring(assetsIndexOf); + } + + var packageIndexOf = absolutePath.IndexOf("Packages", StringComparison.Ordinal); + if (packageIndexOf > 0) + { + return absolutePath.Substring(packageIndexOf); + } + + throw new ArgumentException( + $"Can not resolve absolute path. relativePath: {relativePath}, callerFilePath: {callerFilePath}"); } /// diff --git a/Tests/Runtime/Attributes/LoadSceneAttributeTest.cs b/Tests/Runtime/Attributes/LoadSceneAttributeTest.cs index a9a71f1..18abe14 100644 --- a/Tests/Runtime/Attributes/LoadSceneAttributeTest.cs +++ b/Tests/Runtime/Attributes/LoadSceneAttributeTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023 Koji Hasegawa. +// Copyright (c) 2023-2024 Koji Hasegawa. // This software is released under the MIT License. using System.Collections; @@ -56,5 +56,27 @@ public void UsingGlob_LoadedSceneNotInBuild() Object.Destroy(cube); // For not giving false negatives in subsequent tests. } + + [Test] + [LoadScene("../../Scenes/NotInScenesInBuild.unity")] + public void UsingRelativePath_LoadedSceneNotInBuild() + { + var cube = GameObject.Find(ObjectName); + Assert.That(cube, Is.Not.Null); + + Object.Destroy(cube); // For not giving false negatives in subsequent tests. + } + + [TestCase("./Scene.unity", // include `./` + "Assets/Tests/Runtime/Caller.cs", + "Assets/Tests/Runtime/Scene.unity")] + [TestCase("../../BadPath/../Scenes/Scene.unity", // include `../` + "Packages/com.nowsprinting.test-helper/Tests/Runtime/Attributes/Caller.cs", + "Packages/com.nowsprinting.test-helper/Tests/Scenes/Scene.unity")] + public void GetAbsolutePath(string relativePath, string callerFilePath, string expected) + { + var actual = LoadSceneAttribute.GetAbsolutePath(relativePath, callerFilePath); + Assert.That(actual, Is.EqualTo(expected)); + } } }