using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEditor; using UnityEditor.TestTools.TestRunner.Api; using Newtonsoft.Json; namespace SynapticPro.TestRunner { /// /// TestRunner service that can be called from NexusExecutor via reflection. /// This class is only compiled when UNITY_INCLUDE_TESTS is defined. /// public static class NexusTestRunnerService { // Static fields to store test execution state private static bool _isTestRunning = false; private static List _testResults = new List(); private static int _totalTests = 0; private static int _completedTests = 0; private static string _currentTestMode = ""; private static TestRunnerApi _testRunnerApi; private class TestResultInfo { public string name; public string status; public double duration; public string message; } /// /// Main entry point - called from NexusExecutor via reflection /// public static string Execute(string operation, string mode, string filter) { try { switch (operation.ToLower()) { case "run": return RunTestsWithApi(mode, filter); case "results": return GetTestResults(); case "list": return ListAvailableTests(mode); default: return JsonConvert.SerializeObject(new { success = false, error = $"Unknown operation: {operation}. Use 'run', 'results', or 'list'." }); } } catch (Exception e) { return JsonConvert.SerializeObject(new { success = false, error = e.Message }); } } private static string RunTestsWithApi(string testMode, string filter) { if (_isTestRunning) { return JsonConvert.SerializeObject(new { success = true, status = "running", mode = _currentTestMode, totalTests = _totalTests, completedTests = _completedTests, message = "Tests are still running. Use operation='results' to check progress." }); } // Reset state _isTestRunning = true; _testResults.Clear(); _totalTests = 0; _completedTests = 0; _currentTestMode = testMode; // Create TestRunnerApi instance _testRunnerApi = ScriptableObject.CreateInstance(); // Register callbacks _testRunnerApi.RegisterCallbacks(new SynapticTestCallbacks()); // Build filter var testModeEnum = testMode.ToLower() == "playmode" ? TestMode.PlayMode : TestMode.EditMode; var executionSettings = new ExecutionSettings { filters = new[] { new Filter { testMode = testModeEnum } } }; if (!string.IsNullOrEmpty(filter)) { executionSettings.filters[0].testNames = new[] { filter }; } // Start execution _testRunnerApi.Execute(executionSettings); return JsonConvert.SerializeObject(new { success = true, status = "started", mode = testMode, message = "Tests started. Use operation='results' to check progress and get results." }); } private static string GetTestResults() { return JsonConvert.SerializeObject(new { success = true, isRunning = _isTestRunning, mode = _currentTestMode, totalTests = _totalTests, completedTests = _completedTests, results = _testResults.Select(r => new { name = r.name, status = r.status, duration = r.duration, message = r.message }).ToList(), summary = new { passed = _testResults.Count(r => r.status == "Passed"), failed = _testResults.Count(r => r.status == "Failed"), skipped = _testResults.Count(r => r.status == "Skipped") } }, Formatting.Indented); } private static string ListAvailableTests(string testMode) { var api = ScriptableObject.CreateInstance(); var testModeEnum = testMode.ToLower() == "playmode" ? TestMode.PlayMode : TestMode.EditMode; var tests = new List(); api.RetrieveTestList(testModeEnum, (testRoot) => { CollectTestNames(testRoot, tests); }); return JsonConvert.SerializeObject(new { success = true, mode = testMode, testCount = tests.Count, tests = tests }, Formatting.Indented); } private static void CollectTestNames(ITestAdaptor test, List tests) { if (test == null) return; if (test.IsSuite) { foreach (var child in test.Children) { CollectTestNames(child, tests); } } else { tests.Add(test.FullName); } } private class SynapticTestCallbacks : ICallbacks { public void RunStarted(ITestAdaptor testsToRun) { _totalTests = CountTests(testsToRun); Debug.Log($"[Synaptic] Test run started. Total tests: {_totalTests}"); } public void RunFinished(ITestResultAdaptor result) { _isTestRunning = false; Debug.Log($"[Synaptic] Test run finished. Passed: {_testResults.Count(r => r.status == "Passed")}, Failed: {_testResults.Count(r => r.status == "Failed")}"); } public void TestStarted(ITestAdaptor test) { // Optional: Log test start } public void TestFinished(ITestResultAdaptor result) { _completedTests++; var testResult = new TestResultInfo { name = result.Test.FullName, status = result.TestStatus.ToString(), duration = result.Duration, message = result.Message ?? "" }; _testResults.Add(testResult); } private int CountTests(ITestAdaptor test) { if (test == null) return 0; if (test.IsSuite) { int count = 0; foreach (var child in test.Children) { count += CountTests(child); } return count; } return 1; } } } }