暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

UnityLogCheckDelegatingCommand.cs 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. namespace UnityEngine.TestRunner.NUnitExtensions.Runner
  11. {
  12. internal class UnityLogCheckDelegatingCommand : DelegatingTestCommand, IEnumerableTestMethodCommand
  13. {
  14. private static Dictionary<object, bool?> s_AttributeCache = new Dictionary<object, bool?>();
  15. public UnityLogCheckDelegatingCommand(TestCommand innerCommand)
  16. : base(innerCommand) {}
  17. public override TestResult Execute(ITestExecutionContext context)
  18. {
  19. using (var logScope = new LogScope())
  20. {
  21. if (ExecuteAndCheckLog(logScope, context.CurrentResult, () => innerCommand.Execute(context)))
  22. PostTestValidation(logScope, innerCommand, context.CurrentResult);
  23. }
  24. return context.CurrentResult;
  25. }
  26. public IEnumerable ExecuteEnumerable(ITestExecutionContext context)
  27. {
  28. if (!(innerCommand is IEnumerableTestMethodCommand enumerableTestMethodCommand))
  29. {
  30. Execute(context);
  31. yield break;
  32. }
  33. using (var logScope = new LogScope())
  34. {
  35. IEnumerable executeEnumerable = null;
  36. if (!ExecuteAndCheckLog(logScope, context.CurrentResult,
  37. () => executeEnumerable = enumerableTestMethodCommand.ExecuteEnumerable(context)))
  38. yield break;
  39. var innerCommandIsTask = enumerableTestMethodCommand is TaskTestMethodCommand;
  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. This means that we break on failing logs and fail on next frame.
  44. // An exception is async (Task), in which case we first fail after the task has run, as we cannot cancel the task.
  45. if (!innerCommandIsTask && !CheckFailingLogs(logScope, context.CurrentResult))
  46. {
  47. yield break;
  48. }
  49. yield return step;
  50. }
  51. if (!CheckLogs(context.CurrentResult, logScope))
  52. yield break;
  53. PostTestValidation(logScope, innerCommand, context.CurrentResult);
  54. }
  55. }
  56. private static bool CaptureException(TestResult result, Action action)
  57. {
  58. try
  59. {
  60. action();
  61. return true;
  62. }
  63. catch (Exception e)
  64. {
  65. result.RecordException(e);
  66. return false;
  67. }
  68. }
  69. private static bool ExecuteAndCheckLog(LogScope logScope, TestResult result, Action action)
  70. => CaptureException(result, action) && CheckLogs(result, logScope);
  71. private static void PostTestValidation(LogScope logScope, TestCommand command, TestResult result)
  72. {
  73. if (MustExpect(command.Test.Method.MethodInfo))
  74. CaptureException(result, logScope.NoUnexpectedReceived);
  75. }
  76. private static bool CheckLogs(TestResult result, LogScope logScope)
  77. {
  78. try
  79. {
  80. logScope.EvaluateLogScope(true);
  81. }
  82. catch (Exception e)
  83. {
  84. result.RecordException(e);
  85. return false;
  86. }
  87. return true;
  88. }
  89. private static bool CheckFailingLogs(LogScope logScope, TestResult result)
  90. {
  91. try
  92. {
  93. logScope.EvaluateLogScope(false);
  94. }
  95. catch (Exception e)
  96. {
  97. result.RecordException(e);
  98. return false;
  99. }
  100. return true;
  101. }
  102. private static bool MustExpect(MemberInfo method)
  103. {
  104. // method
  105. var methodAttr = method.GetCustomAttributes<TestMustExpectAllLogsAttribute>(true).FirstOrDefault();
  106. if (methodAttr != null)
  107. return methodAttr.MustExpect;
  108. // fixture
  109. var fixture = method.DeclaringType;
  110. if (!s_AttributeCache.TryGetValue(fixture, out var mustExpect))
  111. {
  112. var fixtureAttr = fixture.GetCustomAttributes<TestMustExpectAllLogsAttribute>(true).FirstOrDefault();
  113. mustExpect = s_AttributeCache[fixture] = fixtureAttr?.MustExpect;
  114. }
  115. if (mustExpect != null)
  116. return mustExpect.Value;
  117. // assembly
  118. var assembly = fixture.Assembly;
  119. if (!s_AttributeCache.TryGetValue(assembly, out mustExpect))
  120. {
  121. var assemblyAttr = assembly.GetCustomAttributes<TestMustExpectAllLogsAttribute>().FirstOrDefault();
  122. mustExpect = s_AttributeCache[assembly] = assemblyAttr?.MustExpect;
  123. }
  124. return mustExpect == true;
  125. }
  126. }
  127. }