135 lines
6.1 KiB
C#
135 lines
6.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using NUnit.Framework;
|
|
using NUnit.Framework.Interfaces;
|
|
using Unity.Pipeline.Editor.Testing;
|
|
using UnityEditor.TestTools.TestRunner.Api;
|
|
|
|
namespace Unity.Pipeline.Tests.Editor
|
|
{
|
|
/// <summary>
|
|
/// Coverage for <see cref="TestResultCollector"/> completion handling: a collector completes
|
|
/// exactly once, and late/duplicate deliveries are harmless no-ops. Combines the regression
|
|
/// tests for UUM-149016 (InvalidOperationException from a stale collector re-delivered a
|
|
/// later run's RunFinished) and AUTHAPI-36 (RunFinished must not throw when the completion
|
|
/// source was already completed by SetError()/Cancel() or an earlier RunFinished, and must
|
|
/// preserve the original error).
|
|
/// </summary>
|
|
class TestResultCollectorTests
|
|
{
|
|
[Test]
|
|
public void RunFinished_CalledTwiceOnSameCollector_SecondCallDoesNotThrow()
|
|
{
|
|
var collector = new TestResultCollector();
|
|
collector.Results.Add(new TestResult()); // skip the leaf-result rebuild path
|
|
var result = new FakeTestResultAdaptor();
|
|
|
|
Assert.DoesNotThrow(() => collector.RunFinished(result),
|
|
"First RunFinished call should complete normally");
|
|
Assert.DoesNotThrow(() => collector.RunFinished(result),
|
|
"A second RunFinished delivered to an already-completed collector must not throw");
|
|
}
|
|
|
|
[Test]
|
|
public void RunFinished_CalledAgainAfterInterveningRunStarted_SecondCallDoesNotThrow()
|
|
{
|
|
// RunStarted resets IsComplete on any non-cancelled collector, so the guard in
|
|
// RunFinished must not rely on IsComplete.
|
|
var collector = new TestResultCollector();
|
|
collector.Results.Add(new TestResult());
|
|
var result = new FakeTestResultAdaptor();
|
|
|
|
collector.RunFinished(result);
|
|
collector.RunStarted(new FakeTestAdaptor());
|
|
|
|
Assert.DoesNotThrow(() => collector.RunFinished(result),
|
|
"A stale collector redelivered RunFinished after an intervening RunStarted " +
|
|
"broadcast must still not throw");
|
|
}
|
|
|
|
[Test]
|
|
public void RunFinished_AfterSetError_DoesNotThrow_AndKeepsError()
|
|
{
|
|
var collector = new TestResultCollector();
|
|
collector.Results.Add(new TestResult());
|
|
var task = collector.WaitForCompletionAsync();
|
|
|
|
// A timed-out/errored run completes the sync task with an exception first.
|
|
var boom = new InvalidOperationException("run errored");
|
|
collector.SetError(boom);
|
|
Assert.IsTrue(task.IsFaulted, "SetError should fault the completion task");
|
|
|
|
// The framework then still delivers RunFinished. It must be a no-op (AUTHAPI-36):
|
|
// no throw, and the original error wins — RunFinished must not overwrite it.
|
|
Assert.DoesNotThrow(() => collector.RunFinished(new FakeTestResultAdaptor()));
|
|
Assert.IsTrue(task.IsFaulted, "Task should remain faulted after late RunFinished");
|
|
Assert.AreSame(boom, task.Exception?.InnerException, "Original error should be preserved");
|
|
}
|
|
|
|
[Test]
|
|
public void RunFinished_CompletesWaitTaskWithResult()
|
|
{
|
|
var collector = new TestResultCollector();
|
|
collector.Results.Add(new TestResult());
|
|
var task = collector.WaitForCompletionAsync();
|
|
var result = new FakeTestResultAdaptor();
|
|
|
|
collector.RunFinished(result);
|
|
|
|
Assert.AreEqual(System.Threading.Tasks.TaskStatus.RanToCompletion, task.Status);
|
|
Assert.AreSame(result, task.Result);
|
|
Assert.IsTrue(collector.IsComplete);
|
|
}
|
|
|
|
private sealed class FakeTestResultAdaptor : ITestResultAdaptor
|
|
{
|
|
public ITestAdaptor Test => throw new NotImplementedException();
|
|
public string Name => "Fake";
|
|
public string FullName => "Fake";
|
|
public string ResultState => "Passed";
|
|
public UnityEditor.TestTools.TestRunner.Api.TestStatus TestStatus => UnityEditor.TestTools.TestRunner.Api.TestStatus.Passed;
|
|
public double Duration => 0;
|
|
public DateTime StartTime => default;
|
|
public DateTime EndTime => default;
|
|
public string Message => null;
|
|
public string StackTrace => null;
|
|
public int AssertCount => 0;
|
|
public int FailCount => 0;
|
|
public int PassCount => 1;
|
|
public int SkipCount => 0;
|
|
public int InconclusiveCount => 0;
|
|
public bool HasChildren => false;
|
|
public IEnumerable<ITestResultAdaptor> Children => null;
|
|
public string Output => null;
|
|
public TNode ToXml() => throw new NotImplementedException();
|
|
}
|
|
|
|
private sealed class FakeTestAdaptor : ITestAdaptor
|
|
{
|
|
public string Id => "Fake";
|
|
public string Name => "Fake";
|
|
public string FullName => "Fake";
|
|
public int TestCaseCount => 1;
|
|
public bool HasChildren => false;
|
|
public bool IsSuite => false;
|
|
public IEnumerable<ITestAdaptor> Children => null;
|
|
public ITestAdaptor Parent => null;
|
|
public int TestCaseTimeout => 0;
|
|
public ITypeInfo TypeInfo => null;
|
|
public IMethodInfo Method => null;
|
|
public object[] Arguments => Array.Empty<object>();
|
|
public string[] Categories => Array.Empty<string>();
|
|
public bool IsTestAssembly => false;
|
|
public UnityEditor.TestTools.TestRunner.Api.RunState RunState => UnityEditor.TestTools.TestRunner.Api.RunState.Runnable;
|
|
public string Description => null;
|
|
public string SkipReason => null;
|
|
public string ParentId => null;
|
|
public string ParentFullName => null;
|
|
public string UniqueName => "Fake";
|
|
public string ParentUniqueName => null;
|
|
public int ChildIndex => 0;
|
|
public TestMode TestMode => TestMode.EditMode;
|
|
}
|
|
}
|
|
}
|