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));
+ }
}
}