|
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Reflection;
- using System.Linq; // welcome to the dark side
-
- using Svelto.Tasks;
- using Svelto.Tasks.Lean;
- using Svelto.Tasks.Enumerators;
- using UnityEngine;
-
- using GamecraftModdingAPI.App;
- using GamecraftModdingAPI.Tasks;
- using GamecraftModdingAPI.Utility;
-
- namespace GamecraftModdingAPI.Tests
- {
- /// <summary>
- /// API test system root class.
- /// </summary>
- public static class TestRoot
- {
- public static bool AutoShutdown = true;
-
- public const string ReportFile = "GamecraftModdingAPI_tests.log";
-
- private static bool _testsPassed = false;
-
- private static uint _testsCount = 0;
-
- private static uint _testsCountPassed = 0;
-
- private static uint _testsCountFailed = 0;
-
- private static string state = "StartingUp";
-
- private static Stopwatch timer;
-
- private static List<Type> testTypes = null;
-
- public static bool TestsPassed
- {
- get => _testsPassed;
- set
- {
- _testsPassed = _testsPassed && value;
- _testsCount++;
- if (value)
- {
- _testsCountPassed++;
- }
- else
- {
- _testsCountFailed++;
- }
- }
- }
-
- private static void StartUp()
- {
- // init
- timer = Stopwatch.StartNew();
- _testsPassed = true;
- _testsCount = 0;
- _testsCountPassed = 0;
- _testsCountFailed = 0;
- // flow control
- Game.Enter += (sender, args) => { GameTests().RunOn(RobocraftX.Schedulers.Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING); };
- Game.Exit += (s, a) => state = "ReturningFromGame";
- Client.EnterMenu += (sender, args) =>
- {
- if (state == "EnteringMenu")
- {
- MenuTests().RunOn(Scheduler.leanRunner);
- state = "EnteringGame";
- }
- if (state == "ReturningFromGame")
- {
- TearDown().RunOn(Scheduler.leanRunner);
- state = "ShuttingDown";
- }
- };
- // init tests here
- foreach (Type t in testTypes)
- {
- foreach (MethodBase m in t.GetMethods())
- {
- if (m.GetCustomAttribute<APITestStartUpAttribute>() != null)
- {
- try
- {
- m.Invoke(null, new object[0]);
- }
- catch (Exception e)
- {
- Assert.Fail($"Start up method '{m}' raised an exception: {e.ToString()}");
- }
- }
- }
- }
- state = "EnteringMenu";
- }
-
- private static IEnumerator<TaskContract> MenuTests()
- {
- yield return Yield.It;
- // menu tests
- foreach (Type t in testTypes)
- {
- foreach (MethodBase m in t.GetMethods())
- {
- APITestCaseAttribute a = m.GetCustomAttribute<APITestCaseAttribute>();
- if (a != null && a.TestType == TestType.Menu)
- {
- try
- {
- m.Invoke(null, new object[0]);
- }
- catch (Exception e)
- {
- Assert.Fail($"Menu test '{m}' raised an exception: {e.ToString()}");
- }
- yield return Yield.It;
- }
- }
- }
- // load game
- yield return GoToGameTests().Continue();
- }
-
- private static IEnumerator<TaskContract> GoToGameTests()
- {
- /*Client app = new Client();
- int oldLength = 0;
- while (app.MyGames.Length == 0 || oldLength != app.MyGames.Length)
- {
- oldLength = app.MyGames.Length;
- yield return new WaitForSecondsEnumerator(1).Continue();
- }
- yield return Yield.It;
- app.MyGames[0].EnterGame();*/
- Game newGame = Game.NewGame();
- yield return new WaitForSecondsEnumerator(5).Continue(); // wait for sync
- newGame.EnterGame();
- }
-
- private static IEnumerator<TaskContract> GameTests()
- {
- yield return Yield.It;
- Game currentGame = Game.CurrentGame();
- // in-game tests
- yield return new WaitForSecondsEnumerator(5).Continue(); // wait for game to finish loading
- foreach (Type t in testTypes)
- {
- foreach (MethodBase m in t.GetMethods())
- {
- APITestCaseAttribute a = m.GetCustomAttribute<APITestCaseAttribute>();
- if (a != null && a.TestType == TestType.Game)
- {
- try
- {
- m.Invoke(null, new object[0]);
- }
- catch (Exception e)
- {
- Assert.Fail($"Game test '{m}' raised an exception: {e.ToString()}");
- }
- yield return Yield.It;
- }
- }
- }
- currentGame.ToggleTimeMode();
- yield return new WaitForSecondsEnumerator(5).Continue();
- // simulation tests
- foreach (Type t in testTypes)
- {
- foreach (MethodBase m in t.GetMethods())
- {
- APITestCaseAttribute a = m.GetCustomAttribute<APITestCaseAttribute>();
- if (a != null && a.TestType == TestType.SimulationMode)
- {
- try
- {
- m.Invoke(null, new object[0]);
- }
- catch (Exception e)
- {
- Assert.Fail($"Simulation test '{m}' raised an exception: {e.ToString()}");
- }
- yield return Yield.It;
- }
- }
- }
- currentGame.ToggleTimeMode();
- yield return new WaitForSecondsEnumerator(5).Continue();
- // build tests
- foreach (Type t in testTypes)
- {
- foreach (MethodBase m in t.GetMethods())
- {
- APITestCaseAttribute a = m.GetCustomAttribute<APITestCaseAttribute>();
- if (a != null && a.TestType == TestType.EditMode)
- {
- try
- {
- m.Invoke(null, new object[0]);
- }
- catch (Exception e)
- {
- Assert.Fail($"Build test '{m}' raised an exception: {e.ToString()}");
- }
- yield return Yield.It;
- }
- }
- }
- // exit game
- yield return new WaitForSecondsEnumerator(5).Continue();
- yield return ReturnToMenu().Continue();
- }
-
- private static IEnumerator<TaskContract> ReturnToMenu()
- {
- Logging.MetaLog("Returning to main menu");
- yield return Yield.It;
- Game.CurrentGame().ExitGame();
- }
-
- private static IEnumerator<TaskContract> TearDown()
- {
- yield return new WaitForSecondsEnumerator(5).Continue();
- Logging.MetaLog("Tearing down test run");
- // dispose tests here
- foreach (Type t in testTypes)
- {
- foreach (MethodBase m in t.GetMethods())
- {
- if (m.GetCustomAttribute<APITestTearDownAttribute>() != null)
- {
- try
- {
- m.Invoke(null, new object[0]);
- }
- catch (Exception e)
- {
- Assert.Warn($"Tear down method '{m}' raised an exception: {e.ToString()}");
- }
- yield return Yield.It;
- }
- }
- }
- // finish up
- Assert.CallsComplete();
- timer.Stop();
- string verdict = _testsPassed ? "--- PASSED :) ---" : "--- FAILED :( ---";
- Assert.Log($"VERDICT: {verdict} ({_testsCountPassed}/{_testsCountFailed}/{_testsCount} P/F/T in {timer.ElapsedMilliseconds}ms)");
- yield return Yield.It;
- // end game
- Logging.MetaLog("Completed test run: " + verdict);
- yield return Yield.It;
- Assert.CloseLog();
- if (AutoShutdown) Application.Quit();
- }
-
- private static void FindTests(Assembly asm)
- {
- testTypes = new List<Type>();
- foreach (Type t in asm.GetTypes())
- {
- if (t.GetCustomAttribute<APITestClassAttribute>() != null)
- {
- testTypes.Add(t);
- }
- }
- }
-
- /// <summary>
- /// Runs the tests.
- /// </summary>
- /// <param name="asm">Assembly to search for tests. When set to null, this uses the GamecraftModdingAPI assembly. </param>
- public static void RunTests(Assembly asm = null)
- {
- if (asm == null) asm = Assembly.GetExecutingAssembly();
- FindTests(asm);
- Logging.MetaLog("Starting test run");
- // log metadata
- Assert.Log($"Unity {Application.unityVersion}");
- Assert.Log($"Gamecraft {Application.version}");
- Assert.Log($"GamecraftModdingAPI {Assembly.GetExecutingAssembly().GetName().Version}");
- Assert.Log($"Testing {asm.GetName().Name} {asm.GetName().Version}");
- Assert.Log($"START: --- {DateTime.Now.ToString()} --- ({testTypes.Count} tests classes detected)");
- StartUp();
- Logging.MetaLog("Test StartUp complete");
- }
- }
- }
|