Skip to content

Commit

Permalink
Merge pull request #36 from nowsprinting/chore/isolate_internals
Browse files Browse the repository at this point in the history
Isolate internal implementation not depending on test-framework codes
  • Loading branch information
nowsprinting authored Oct 30, 2023
2 parents 269e7a5 + 3666ef6 commit d30a554
Show file tree
Hide file tree
Showing 40 changed files with 478 additions and 150 deletions.
22 changes: 2 additions & 20 deletions Runtime/Attributes/FocusGameViewAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,21 @@
using NUnit.Framework;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using UnityEngine;
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
#endif
using TestHelper.RuntimeInternals;

namespace TestHelper.Attributes
{
/// <summary>
/// Focus <c>GameView</c> or <c>SimulatorWindow</c> before run test.
///
/// Example usage: Tests that use <c>InputEventTrace</c> of the Input System package (com.unity.inputsystem).
/// </summary>
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
public class FocusGameViewAttribute : NUnitAttribute, IApplyToContext
{
private static Type s_gameView;

/// <inheritdoc />
public void ApplyToContext(ITestExecutionContext context)
{
#if UNITY_EDITOR
if (s_gameView == null)
{
var assembly = Assembly.Load("UnityEditor.dll");
var viewClass = Application.isBatchMode ? "UnityEditor.GameView" : "UnityEditor.PlayModeView";
// Note: Freezes when getting SimulatorWindow in batchmode

s_gameView = assembly.GetType(viewClass);
}

EditorWindow.GetWindow(s_gameView, false, null, true);
#endif
GameViewControlHelper.Focus();
}
}
}
64 changes: 2 additions & 62 deletions Runtime/Attributes/GameViewResolutionAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@
using NUnit.Framework;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using UnityEngine;
#if UNITY_EDITOR
using TestHelper.Wrappers.UnityEditor;
using UnityEditor;
#endif
using TestHelper.RuntimeInternals;

namespace TestHelper.Attributes
{
Expand Down Expand Up @@ -48,63 +44,7 @@ public GameViewResolutionAttribute(GameViewResolution resolution)
/// <inheritdoc />
public void ApplyToContext(ITestExecutionContext context)
{
#if UNITY_2022_2_OR_NEWER
SetResolutionUsingPlayModeWindow();
#else
SetResolution();
#endif
}

// ReSharper disable once UnusedMember.Local
private void SetResolutionUsingPlayModeWindow()
{
#if UNITY_EDITOR && UNITY_2022_2_OR_NEWER
PlayModeWindow.SetViewType(PlayModeWindow.PlayModeViewTypes.GameView);
PlayModeWindow.SetCustomRenderingResolution(_width, _height, _name);
#endif
}

// ReSharper disable once UnusedMember.Local
private void SetResolution()
{
#if UNITY_EDITOR
var gameViewSizes = GameViewSizesWrapper.CreateInstance();
if (gameViewSizes == null)
{
Debug.LogError("GameViewSizes instance creation failed.");
return;
}

var gameViewSizeGroup = gameViewSizes.CurrentGroup();
if (gameViewSizeGroup == null)
{
Debug.LogError("GameViewSizeGroup instance creation failed.");
return;
}

var gameViewSize = GameViewSizeWrapper.CreateInstance((int)_width, (int)_height, _name);
if (gameViewSize == null)
{
Debug.LogError("GameViewSize instance creation failed.");
return;
}

var index = gameViewSizeGroup.IndexOf(gameViewSize);
if (index == -1)
{
gameViewSizeGroup.AddCustomSize(gameViewSize);
index = gameViewSizeGroup.IndexOf(gameViewSize);
}

var gameView = GameViewWrapper.GetWindow();
if (gameView == null)
{
Debug.LogError("GameView instance creation failed.");
return;
}

gameView.SelectedSizeIndex(index);
#endif
GameViewControlHelper.SetResolution(_width, _height, _name);
}
}
}
3 changes: 2 additions & 1 deletion Runtime/TestHelper.asmdef
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"rootNamespace": "TestHelper",
"references": [
"UnityEngine.TestRunner",
"UnityEditor.TestRunner"
"UnityEditor.TestRunner",
"TestHelper.RuntimeInternals"
],
"includePlatforms": [],
"excludePlatforms": [],
Expand Down
43 changes: 2 additions & 41 deletions Runtime/Utils/ScreenshotHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// This software is released under the MIT License.

using System.Collections;
using System.IO;
using System.Threading;
using NUnit.Framework;
using UnityEngine;

Expand All @@ -14,11 +12,6 @@ namespace TestHelper.Utils
/// </summary>
public static class ScreenshotHelper
{
private static string DefaultDirectoryPath()
{
return Path.Combine(Application.persistentDataPath, "TestHelper", "Screenshots");
}

private static string DefaultFilename()
{
return $"{TestContext.CurrentTestExecutionContext.CurrentTest.Name}.png"
Expand Down Expand Up @@ -52,45 +45,13 @@ public static IEnumerator TakeScreenshot(
ScreenCapture.StereoScreenCaptureMode stereoCaptureMode = ScreenCapture.StereoScreenCaptureMode.LeftEye
)
{
if (superSize != 1 && stereoCaptureMode != ScreenCapture.StereoScreenCaptureMode.LeftEye)
{
Debug.LogError("superSize and stereoCaptureMode cannot be specified at the same time.");
yield break;
}

if (Thread.CurrentThread.ManagedThreadId != 1)
{
Debug.LogError("Must be called from the main thread.");
yield break;
// Note: This is not the case since it is a coroutine.
}

if (Application.isEditor && directory != null)
{
directory = Path.GetFullPath(directory);
}
else
{
directory = DefaultDirectoryPath(); // Not apply specific directory when running on player
}

Directory.CreateDirectory(directory);

if (filename == null)
{
filename = DefaultFilename();
}

yield return new WaitForEndOfFrame(); // Required to take screenshots

var texture = superSize != 1
? ScreenCapture.CaptureScreenshotAsTexture(superSize)
: ScreenCapture.CaptureScreenshotAsTexture(stereoCaptureMode);

var path = Path.Combine(directory, filename);
var bytes = texture.EncodeToPNG();
File.WriteAllBytes(path, bytes);
Debug.Log($"Save screenshot to {path}");
yield return RuntimeInternals.ScreenshotHelper.TakeScreenshot(
directory, filename, superSize, stereoCaptureMode);
}
}
}
8 changes: 8 additions & 0 deletions RuntimeInternals.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions RuntimeInternals/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) 2023 Koji Hasegawa.
// This software is released under the MIT License.

using System.Reflection;
using System.Runtime.CompilerServices;

[assembly: AssemblyTitle("Internal implementation for the TestHelper package")]
[assembly: AssemblyDescription(
@"This assembly can be used from the runtime code because it does not depend on test-framework.
This assembly is named ""Internal"", however, the included classes are public.")]

[assembly: InternalsVisibleTo("TestHelper.RuntimeInternals.Tests")]
3 changes: 3 additions & 0 deletions RuntimeInternals/AssemblyInfo.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 106 additions & 0 deletions RuntimeInternals/GameViewControlHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) 2023 Koji Hasegawa.
// This software is released under the MIT License.

using System;
using System.Reflection;
using TestHelper.RuntimeInternals.Wrappers.UnityEditor;
using UnityEditor;
using UnityEngine;

namespace TestHelper.RuntimeInternals
{
/// <summary>
/// <c>GameView</c> control helper.
/// This class can be used from the runtime code because it does not depend on test-framework.
/// </summary>
public static class GameViewControlHelper
{
private static Type s_gameView;

/// <summary>
/// Focus <c>GameView</c> or <c>SimulatorWindow</c>.
/// </summary>
public static void Focus()
{
#if UNITY_EDITOR
if (s_gameView == null)
{
var assembly = Assembly.Load("UnityEditor.dll");
var viewClass = Application.isBatchMode ? "UnityEditor.GameView" : "UnityEditor.PlayModeView";
// Note: Freezes when getting SimulatorWindow in batchmode

s_gameView = assembly.GetType(viewClass);
}

EditorWindow.GetWindow(s_gameView, false, null, true);
#endif
}

/// <summary>
/// Set <c>GameView</c> resolution.
/// </summary>
/// <param name="width">GameView width [px]</param>
/// <param name="height">GameView height [px]</param>
/// <param name="name">GameViewSize name</param>
public static void SetResolution(uint width, uint height, string name)
{
#if UNITY_2022_2_OR_NEWER
SetResolutionUsingPlayModeWindow(width, height, name);
#else
SetResolutionUsingReflection(width, height, name);
#endif
}

// ReSharper disable once UnusedMember.Local
private static void SetResolutionUsingPlayModeWindow(uint width, uint height, string name)
{
#if UNITY_EDITOR && UNITY_2022_2_OR_NEWER
PlayModeWindow.SetViewType(PlayModeWindow.PlayModeViewTypes.GameView);
PlayModeWindow.SetCustomRenderingResolution(width, height, name);
#endif
}

// ReSharper disable once UnusedMember.Local
private static void SetResolutionUsingReflection(uint width, uint height, string name)
{
#if UNITY_EDITOR
var gameViewSizes = GameViewSizesWrapper.CreateInstance();
if (gameViewSizes == null)
{
Debug.LogError("GameViewSizes instance creation failed.");
return;
}

var gameViewSizeGroup = gameViewSizes.CurrentGroup();
if (gameViewSizeGroup == null)
{
Debug.LogError("GameViewSizeGroup instance creation failed.");
return;
}

var gameViewSize = GameViewSizeWrapper.CreateInstance((int)width, (int)height, name);
if (gameViewSize == null)
{
Debug.LogError("GameViewSize instance creation failed.");
return;
}

var index = gameViewSizeGroup.IndexOf(gameViewSize);
if (index == -1)
{
gameViewSizeGroup.AddCustomSize(gameViewSize);
index = gameViewSizeGroup.IndexOf(gameViewSize);
}

var gameView = GameViewWrapper.GetWindow();
if (gameView == null)
{
Debug.LogError("GameView instance creation failed.");
return;
}

gameView.SelectedSizeIndex(index);
#endif
}
}
}
3 changes: 3 additions & 0 deletions RuntimeInternals/GameViewControlHelper.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d30a554

Please sign in to comment.