|
|
using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Reflection;using NUnit.Framework.Internal;using NUnit.Framework.Internal.Commands;using UnityEngine.TestTools;using UnityEngine.TestTools.Logging;using UnityEngine.TestTools.TestRunner;
namespace UnityEngine.TestRunner.NUnitExtensions.Runner{ class UnityLogCheckDelegatingCommand : DelegatingTestCommand, IEnumerableTestMethodCommand { static Dictionary<object, bool?> s_AttributeCache = new Dictionary<object, bool?>();
public UnityLogCheckDelegatingCommand(TestCommand innerCommand) : base(innerCommand) {}
public override TestResult Execute(ITestExecutionContext context) { using (var logScope = new LogScope()) { if (ExecuteAndCheckLog(logScope, context.CurrentResult, () => innerCommand.Execute(context))) PostTestValidation(logScope, innerCommand, context.CurrentResult); }
return context.CurrentResult; }
public IEnumerable ExecuteEnumerable(ITestExecutionContext context) { if (!(innerCommand is IEnumerableTestMethodCommand enumerableTestMethodCommand)) { Execute(context); yield break; }
using (var logScope = new LogScope()) { IEnumerable executeEnumerable = null;
if (!ExecuteAndCheckLog(logScope, context.CurrentResult, () => executeEnumerable = enumerableTestMethodCommand.ExecuteEnumerable(context))) yield break;
foreach (var step in executeEnumerable) { // do not check expected logs here - we want to permit expecting and receiving messages to run
// across frames. (but we do always want to catch a fail immediately.)
if (!CheckFailingLogs(logScope, context.CurrentResult)) yield break;
yield return step; }
if (!CheckLogs(context.CurrentResult, logScope)) yield break; PostTestValidation(logScope, innerCommand, context.CurrentResult); } }
static bool CaptureException(TestResult result, Action action) { try { action(); return true; } catch (Exception e) { result.RecordException(e); return false; } } static bool ExecuteAndCheckLog(LogScope logScope, TestResult result, Action action) => CaptureException(result, action) && CheckLogs(result, logScope);
static void PostTestValidation(LogScope logScope, TestCommand command, TestResult result) { if (MustExpect(command.Test.Method.MethodInfo)) CaptureException(result, logScope.NoUnexpectedReceived); }
static bool CheckLogs(TestResult result, LogScope logScope) => CheckFailingLogs(logScope, result) && CheckExpectedLogs(logScope, result);
static bool CheckFailingLogs(LogScope logScope, TestResult result) { if (!logScope.AnyFailingLogs()) return true; var failingLog = logScope.FailingLogs.First(); result.RecordException(new UnhandledLogMessageException(failingLog)); return false; } static bool CheckExpectedLogs(LogScope logScope, TestResult result) { if (!logScope.ExpectedLogs.Any()) return true; var expectedLog = logScope.ExpectedLogs.Peek(); result.RecordException(new UnexpectedLogMessageException(expectedLog)); return false; } static bool MustExpect(MemberInfo method) { // method
var methodAttr = method.GetCustomAttributes<TestMustExpectAllLogsAttribute>(true).FirstOrDefault(); if (methodAttr != null) return methodAttr.MustExpect; // fixture
var fixture = method.DeclaringType; if (!s_AttributeCache.TryGetValue(fixture, out var mustExpect)) { var fixtureAttr = fixture.GetCustomAttributes<TestMustExpectAllLogsAttribute>(true).FirstOrDefault(); mustExpect = s_AttributeCache[fixture] = fixtureAttr?.MustExpect; } if (mustExpect != null) return mustExpect.Value;
// assembly
var assembly = fixture.Assembly; if (!s_AttributeCache.TryGetValue(assembly, out mustExpect)) { var assemblyAttr = assembly.GetCustomAttributes<TestMustExpectAllLogsAttribute>().FirstOrDefault(); mustExpect = s_AttributeCache[assembly] = assemblyAttr?.MustExpect; }
return mustExpect == true; } }}
|