Skip to content

Commit

Permalink
Merge pull request MonoGame#8390 from Mindfulplays/e2e-test
Browse files Browse the repository at this point in the history
Add end-to-end test framework inspired from iOS interactive tests
  • Loading branch information
SimonDarksideJ authored Jul 13, 2024
2 parents 6067da3 + 87577e4 commit f6a3c7d
Show file tree
Hide file tree
Showing 69 changed files with 3,054 additions and 1,561 deletions.
58 changes: 58 additions & 0 deletions Tests/Assets/Effects/Mobile/Macros.fxh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// MonoGame - Copyright (C) MonoGame Foundation, Inc
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.

#ifdef SM4

// Macros for targetting shader model 4.0 (DX11)

#define TECHNIQUE(name, vsname, psname ) \
technique name { pass { VertexShader = compile vs_4_0_level_9_1 vsname (); PixelShader = compile ps_4_0_level_9_1 psname(); } }

#define BEGIN_CONSTANTS cbuffer Parameters : register(b0) {
#define MATRIX_CONSTANTS
#define END_CONSTANTS };

#define _vs(r)
#define _ps(r)
#define _cb(r)

#define DECLARE_TEXTURE(Name, index) \
Texture2D<float4> Name : register(t##index); \
sampler Name##Sampler : register(s##index)

#define DECLARE_CUBEMAP(Name, index) \
TextureCube<float4> Name : register(t##index); \
sampler Name##Sampler : register(s##index)

#define SAMPLE_TEXTURE(Name, texCoord) Name.Sample(Name##Sampler, texCoord)
#define SAMPLE_CUBEMAP(Name, texCoord) Name.Sample(Name##Sampler, texCoord)


#else


// Macros for targetting shader model 2.0 (DX9)

#define TECHNIQUE(name, vsname, psname ) \
technique name { pass { VertexShader = compile vs_2_0 vsname (); PixelShader = compile ps_2_0 psname(); } }

#define BEGIN_CONSTANTS
#define MATRIX_CONSTANTS
#define END_CONSTANTS

#define _vs(r) : register(vs, r)
#define _ps(r) : register(ps, r)
#define _cb(r)

#define DECLARE_TEXTURE(Name, index) \
sampler2D Name : register(s##index);

#define DECLARE_CUBEMAP(Name, index) \
samplerCUBE Name : register(s##index);

#define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name, texCoord)
#define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name, texCoord)


#endif
44 changes: 44 additions & 0 deletions Tests/Assets/Effects/Mobile/test.fx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// MonoGame - Copyright (C) MonoGame Foundation, Inc
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.

#include "Macros.fxh"


DECLARE_TEXTURE(Texture, 0);


BEGIN_CONSTANTS
float tween4 _ps(c1) _cb(c1);
MATRIX_CONSTANTS

float4x4 MatrixTransform _vs(c0) _cb(c0);

END_CONSTANTS


struct VSOutput
{
float4 position : SV_Position;
float4 color : COLOR0;
float2 texCoord : TEXCOORD0;
};

VSOutput SpriteVertexShader( float4 position : POSITION0,
float4 color : COLOR0,
float2 texCoord : TEXCOORD0)
{
VSOutput output;
output.position = mul(position, MatrixTransform);
output.color = color;
output.texCoord = texCoord;
return output;
}


float4 PixelShaderFunction(VSOutput input) : SV_Target0
{
return SAMPLE_TEXTURE(Texture, input.texCoord) * input.color * tween4;
}

TECHNIQUE( SpriteBatch, SpriteVertexShader, PixelShaderFunction );
Binary file added Tests/Assets/Effects/Mobile/test.fx.ogl.mgfxo
Binary file not shown.
19 changes: 19 additions & 0 deletions Tests/Interactive/Common/Categories.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// MonoGame - Copyright (C) MonoGame Foundation, Inc
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.

namespace MonoGame.InteractiveTests
{
/// <summary>
/// Defines test app categories that is provided via a <code>class</code>
/// attribute as well as a human-readable string shown in a UI or provided
/// via command line arg.
/// </summary>
static class Categories
{
public const string Default = General;

public const string General = "General";
public const string Meta = "Meta Tests";
}
}
31 changes: 31 additions & 0 deletions Tests/Interactive/Common/GameDebug.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// MonoGame - Copyright (C) MonoGame Foundation, Inc
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.

using System.Collections.Generic;

namespace MonoGame.InteractiveTests
{
/// <summary>
/// Allows tests to output console messages. This is separate from
/// GraphicsDebug which is an internal class to MonoGame platform code.
///
/// On various platforms, this may be available via console output or via
/// a special console viewer: Console app terminal window output on Mac;
/// <code>adb logcat</code> on Android and so on.
/// </summary>
public partial class GameDebug
{
/// <summary>Output a single console message.</summary>
public static void LogInfo(string message)
{
System.Console.WriteLine($"MGDBG: {message}");
}

/// <summary>Output an error message to the console.</summary>
public static void LogError(string message)
{
System.Console.WriteLine($"****ERROR*****:MGDBG: {message}");
}
}
}
70 changes: 70 additions & 0 deletions Tests/Interactive/Common/InteractiveTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// MonoGame - Copyright (C) MonoGame Foundation, Inc
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using MonoGame.Framework.Utilities;

namespace MonoGame.InteractiveTests
{
/// <summary>
/// Manages creating of interactive test(s) instance(s).
/// </summary>
public class InteractiveTest
{
public static bool TryCreateFrom(Type type, out InteractiveTest test)
{
test = null;
if (!typeof(TestGame).IsAssignableFrom(type)) { return false; }

var attrs = type.GetCustomAttributes(typeof(InteractiveTestAttribute), false);
if (attrs.Length == 0) { return false; }

var attr = (InteractiveTestAttribute)attrs[0];

test = new InteractiveTest(
type, attr.Name ?? type.Name, attr.Category ?? Categories.Default, attr.Platforms);
return true;
}

private InteractiveTest(Type type, string name, string category, MonoGamePlatform[] platforms)
{
_type = type;
_name = name;
_category = category;
_platforms = platforms;
}

private readonly Type _type;
public Type Type { get { return _type; } }

private readonly string _name;
public string Name { get { return _name; } }

private readonly string _category;
public string Category { get { return _category; } }

private readonly MonoGamePlatform[] _platforms;
public MonoGamePlatform[] Platforms { get { return _platforms; } }

public Game Create()
{
return (Game)Activator.CreateInstance(_type);
}

public bool MatchesPlatform(MonoGamePlatform runtimePlatform)
{
// Empty array matches everything.
if (_platforms.Length == 0) { return true; }

foreach (var testPlatform in _platforms)
{
if (testPlatform == runtimePlatform) { return true; }
}

return false;
}
}
}
48 changes: 48 additions & 0 deletions Tests/Interactive/Common/InteractiveTestAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// MonoGame - Copyright (C) MonoGame Foundation, Inc
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.

using System;
using System.Collections.Generic;
using MonoGame.Framework.Utilities;

namespace MonoGame.InteractiveTests
{
/// <summary>
/// Attribute specified on test classes that are automatically
/// discovered and shown/provided via some UI / command-line arg.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class InteractiveTestAttribute : Attribute
{
public InteractiveTestAttribute(string name, string category,
MonoGamePlatform[] platforms = null)
{
_name = name;
_category = category;

// Empty array matches everything.
if (platforms == null) { platforms = new MonoGamePlatform[] { }; }

_platforms = platforms;
}

/// <summary>Human-readable name of the test</summary>
private readonly string _name;

public string Name { get { return _name; } }

/// <summary>Category of the test. See <see cref="Categories"/></summary>
private readonly string _category;

public string Category { get { return _category; } }

/// <summary>
/// Supported platforms that this test can run on (empty array
/// allows running on any platform.
/// </summary>
private readonly MonoGamePlatform[] _platforms;

public MonoGamePlatform[] Platforms { get { return _platforms; } }
}
}
73 changes: 73 additions & 0 deletions Tests/Interactive/Common/InteractiveTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// MonoGame - Copyright (C) MonoGame Foundation, Inc
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.

using System.Collections.Generic;
using System.Reflection;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Framework.Utilities;

namespace MonoGame.InteractiveTests
{
/// <summary>
/// Creates a <see cref="InteractiveTest"/> from applicable types in our binary.
/// Also allows filtering of tests based on platforms/command-line args.
/// </summary>
public class InteractiveTests
{
private readonly List<InteractiveTest> _interactiveTests = new();

private readonly List<InteractiveTest> _filteredTests = new();

public InteractiveTests()
{
_interactiveTests.Clear();
var assembly = Assembly.GetExecutingAssembly();
foreach (var type in assembly.GetTypes())
{
InteractiveTest test;
if (!InteractiveTest.TryCreateFrom(type, out test)) { continue; }

if (test.MatchesPlatform(PlatformInfo.MonoGamePlatform)) { _interactiveTests.Add(test); }
}

GameDebug.LogInfo($"--Discovered {_interactiveTests.Count} tests.");

// Also turn on GraphicsDebug messages. TODO: Enable this once GraphicsDebug changes are in.
// GraphicsDebug.EnableOutputDebugMessagesToConsole();
}

public IReadOnlyList<InteractiveTest> Tests { get { return _interactiveTests; } }

/// <summary>
/// Parses the passed-in arg and returns an `InteractiveTest` game. See HelpStr for more details.
/// </summary>
public IReadOnlyList<InteractiveTest> Parse(string[] args)
{
_filteredTests.Clear();
if (args == null || args.Length == 0) { return _filteredTests; }

foreach (var test in _interactiveTests)
{
foreach (var testName in args)
{
var name = testName.ToLower();
if (test.Category.ToLower().Contains(name)) { _filteredTests.Add(test); }
else if (test.Name.ToLower().Contains(name)) { _filteredTests.Add(test); }
}
}

return _filteredTests;
}

public string HelpStr()
{
var testStr = "";
foreach (var test in _interactiveTests) { testStr += $"{test.Name}\n"; }

return $@"Interactive tests available:
{testStr}
";
}
}
}
13 changes: 13 additions & 0 deletions Tests/Interactive/Common/MonoGame.Interactive.Common.projitems
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>MonoGame</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)\**\*.cs" />
</ItemGroup>
</Project>
11 changes: 11 additions & 0 deletions Tests/Interactive/Common/MonoGame.Interactive.Common.shproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>085B407C-726C-43FE-BB55-64E2B6D143FE</ProjectGuid>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
<Import Project="MonoGame.Interactive.Common.projitems" Label="Shared" />
</Project>
Loading

0 comments on commit f6a3c7d

Please sign in to comment.