UnityLogCheckDelegatingCommand.cs
5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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;
}
}
}