UnityLogCheckDelegatingCommand.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Reflection;
  6. using NUnit.Framework.Internal;
  7. using NUnit.Framework.Internal.Commands;
  8. using UnityEngine.TestTools;
  9. using UnityEngine.TestTools.Logging;
  10. using UnityEngine.TestTools.TestRunner;
  11. namespace UnityEngine.TestRunner.NUnitExtensions.Runner
  12. {
  13. class UnityLogCheckDelegatingCommand : DelegatingTestCommand, IEnumerableTestMethodCommand
  14. {
  15. static Dictionary<object, bool?> s_AttributeCache = new Dictionary<object, bool?>();
  16. public UnityLogCheckDelegatingCommand(TestCommand innerCommand)
  17. : base(innerCommand) {}
  18. public override TestResult Execute(ITestExecutionContext context)
  19. {
  20. using (var logScope = new LogScope())
  21. {
  22. if (ExecuteAndCheckLog(logScope, context.CurrentResult, () => innerCommand.Execute(context)))
  23. PostTestValidation(logScope, innerCommand, context.CurrentResult);
  24. }
  25. return context.CurrentResult;
  26. }
  27. public IEnumerable ExecuteEnumerable(ITestExecutionContext context)
  28. {
  29. if (!(innerCommand is IEnumerableTestMethodCommand enumerableTestMethodCommand))
  30. {
  31. Execute(context);
  32. yield break;
  33. }
  34. using (var logScope = new LogScope())
  35. {
  36. IEnumerable executeEnumerable = null;
  37. if (!ExecuteAndCheckLog(logScope, context.CurrentResult,
  38. () => executeEnumerable = enumerableTestMethodCommand.ExecuteEnumerable(context)))
  39. yield break;
  40. foreach (var step in executeEnumerable)
  41. {
  42. // do not check expected logs here - we want to permit expecting and receiving messages to run
  43. // across frames. (but we do always want to catch a fail immediately.)
  44. if (!CheckFailingLogs(logScope, context.CurrentResult))
  45. yield break;
  46. yield return step;
  47. }
  48. if (!CheckLogs(context.CurrentResult, logScope))
  49. yield break;
  50. PostTestValidation(logScope, innerCommand, context.CurrentResult);
  51. }
  52. }
  53. static bool CaptureException(TestResult result, Action action)
  54. {
  55. try
  56. {
  57. action();
  58. return true;
  59. }
  60. catch (Exception e)
  61. {
  62. result.RecordException(e);
  63. return false;
  64. }
  65. }
  66. static bool ExecuteAndCheckLog(LogScope logScope, TestResult result, Action action)
  67. => CaptureException(result, action) && CheckLogs(result, logScope);
  68. static void PostTestValidation(LogScope logScope, TestCommand command, TestResult result)
  69. {
  70. if (MustExpect(command.Test.Method.MethodInfo))
  71. CaptureException(result, logScope.NoUnexpectedReceived);
  72. }
  73. static bool CheckLogs(TestResult result, LogScope logScope)
  74. => CheckFailingLogs(logScope, result) && CheckExpectedLogs(logScope, result);
  75. static bool CheckFailingLogs(LogScope logScope, TestResult result)
  76. {
  77. if (!logScope.AnyFailingLogs())
  78. return true;
  79. var failingLog = logScope.FailingLogs.First();
  80. result.RecordException(new UnhandledLogMessageException(failingLog));
  81. return false;
  82. }
  83. static bool CheckExpectedLogs(LogScope logScope, TestResult result)
  84. {
  85. if (!logScope.ExpectedLogs.Any())
  86. return true;
  87. var expectedLog = logScope.ExpectedLogs.Peek();
  88. result.RecordException(new UnexpectedLogMessageException(expectedLog));
  89. return false;
  90. }
  91. static bool MustExpect(MemberInfo method)
  92. {
  93. // method
  94. var methodAttr = method.GetCustomAttributes<TestMustExpectAllLogsAttribute>(true).FirstOrDefault();
  95. if (methodAttr != null)
  96. return methodAttr.MustExpect;
  97. // fixture
  98. var fixture = method.DeclaringType;
  99. if (!s_AttributeCache.TryGetValue(fixture, out var mustExpect))
  100. {
  101. var fixtureAttr = fixture.GetCustomAttributes<TestMustExpectAllLogsAttribute>(true).FirstOrDefault();
  102. mustExpect = s_AttributeCache[fixture] = fixtureAttr?.MustExpect;
  103. }
  104. if (mustExpect != null)
  105. return mustExpect.Value;
  106. // assembly
  107. var assembly = fixture.Assembly;
  108. if (!s_AttributeCache.TryGetValue(assembly, out mustExpect))
  109. {
  110. var assemblyAttr = assembly.GetCustomAttributes<TestMustExpectAllLogsAttribute>().FirstOrDefault();
  111. mustExpect = s_AttributeCache[assembly] = assemblyAttr?.MustExpect;
  112. }
  113. return mustExpect == true;
  114. }
  115. }
  116. }