using NUnit.Framework; using System; using UnityEngine; namespace Tests { public interface ITime { float delta { get; } } public class TimeMock : ITime { public float delta { get; set; } } class Timer { private ITime time; public float duration { get; private set; } public float remaining { get; private set; } public event Action expired; private bool active; public Timer(ITime time) : this(time, 0) { } public Timer(ITime time, float duration) { ResetDuration(duration); this.time = time; } public void Update() { remaining = Mathf.Max(remaining - time.delta, 0); if (remaining == 0 && active) { active = false; expired?.Invoke(); } } public void ResetDuration(float duration) { this.duration = duration; remaining = duration; active = true; } } public class CountDownTimerTest { const float ONE_SECOND = 1.0f; int callbacks; TimeMock timeMock; Timer timer; private void AssertTimeRemaining(int remaining) { Assert.That(timer.remaining, Is.EqualTo(remaining).Within(0.1f)); } private void AssertCallbacks(int times) { Assert.That(callbacks, Is.EqualTo(times)); } private void UpdateForTicks(int ticks) { for (int i = 0; i < ticks; ++i) timer.Update(); } [SetUp] public void SetUp() { // Mock timer to make testable code. // Implement ITime with a real implementation // for your own implementation. timeMock = new TimeMock(); timeMock.delta = ONE_SECOND; // Create 0 second timer with fixed mock delta. timer = new Timer(timeMock); // Every time expired is raised, // remember how many times it's been called. timer.expired += () => callbacks++; callbacks = 0; } [Test] public void DoesNotExpireOnLongDuration() { timer.ResetDuration(60); UpdateForTicks(1); AssertTimeRemaining(59); AssertCallbacks(0); } [Test] public void ExpiresOnZeroDuration() { UpdateForTicks(1); AssertTimeRemaining(0); AssertCallbacks(1); } [Test] public void ExpiresOnceOnLongRunthrough() { timer.ResetDuration(60); UpdateForTicks(61); AssertTimeRemaining(0); AssertCallbacks(1); } [Test] public void ExpiresTwiceAfterResetDuration() { timer.ResetDuration(60); UpdateForTicks(61); timer.ResetDuration(60); UpdateForTicks(61); AssertTimeRemaining(0); AssertCallbacks(2); } } }