1 // OpenTween - Client of Twitter
2 // Copyright (c) 2022 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
5 // This file is part of OpenTween.
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
17 // You should have received a copy of the GNU General public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
23 using System.Collections.Generic;
26 using System.Threading.Tasks;
31 public class DebounceTimerTest
33 private class TestDebounceTimer : DebounceTimer
35 public MockTimer MockTimer = new(() => Task.CompletedTask);
37 public TestDebounceTimer(Func<Task> timerCallback, TimeSpan interval, bool leading, bool trailing)
38 : base(timerCallback, interval, leading, trailing)
42 protected override ITimer CreateTimer(Func<Task> callback)
43 => this.MockTimer = new MockTimer(callback);
47 public async Task Callback_Debounce_Trailing_Test()
49 using (TestUtils.FreezeTime(new DateTimeUtc(2022, 1, 1, 0, 0, 0)))
56 TestUtils.DriftTime(TimeSpan.FromSeconds(10));
57 return Task.CompletedTask;
60 var interval = TimeSpan.FromMinutes(2);
61 var maxWait = TimeSpan.MaxValue;
62 using var debouncing = new TestDebounceTimer(Callback, interval, leading: false, trailing: true);
63 var mockTimer = debouncing.MockTimer;
65 debouncing.Enabled = true;
67 Assert.Equal(0, count);
68 Assert.False(mockTimer.IsTimerRunning);
71 await debouncing.Call();
74 Assert.Equal(0, count);
75 Assert.True(mockTimer.IsTimerRunning);
76 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
79 TestUtils.DriftTime(TimeSpan.FromMinutes(1));
80 await debouncing.Call();
83 Assert.Equal(0, count);
84 Assert.True(mockTimer.IsTimerRunning);
87 TestUtils.DriftTime(TimeSpan.FromMinutes(1));
88 await mockTimer.Invoke();
91 Assert.Equal(0, count);
92 Assert.True(mockTimer.IsTimerRunning);
93 Assert.Equal(TimeSpan.FromMinutes(1), mockTimer.DueTime);
96 TestUtils.DriftTime(TimeSpan.FromMinutes(2));
97 await mockTimer.Invoke();
100 Assert.Equal(1, count); // invoked (trailing)
101 Assert.False(mockTimer.IsTimerRunning);
106 public async Task Callback_Debounce_Trailing_CallOnceTest()
108 using (TestUtils.FreezeTime(new DateTimeUtc(2022, 1, 1, 0, 0, 0)))
115 TestUtils.DriftTime(TimeSpan.FromSeconds(10));
116 return Task.CompletedTask;
119 var interval = TimeSpan.FromMinutes(2);
120 var maxWait = TimeSpan.MaxValue;
121 using var debouncing = new TestDebounceTimer(Callback, interval, leading: false, trailing: true);
122 var mockTimer = debouncing.MockTimer;
124 debouncing.Enabled = true;
126 Assert.Equal(0, count);
127 Assert.False(mockTimer.IsTimerRunning);
130 await debouncing.Call();
133 Assert.Equal(0, count);
134 Assert.True(mockTimer.IsTimerRunning);
135 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
138 TestUtils.DriftTime(TimeSpan.FromMinutes(2));
139 await mockTimer.Invoke();
142 Assert.Equal(1, count); // invoked (trailing)
143 Assert.False(mockTimer.IsTimerRunning);
148 public async Task Callback_Debounce_Trailing_ResumeTest()
150 using (TestUtils.FreezeTime(new DateTimeUtc(2022, 1, 1, 0, 0, 0)))
157 TestUtils.DriftTime(TimeSpan.FromSeconds(10));
158 return Task.CompletedTask;
161 var interval = TimeSpan.FromMinutes(2);
162 var maxWait = TimeSpan.MaxValue;
163 using var debouncing = new TestDebounceTimer(Callback, interval, leading: false, trailing: true);
164 var mockTimer = debouncing.MockTimer;
166 debouncing.Enabled = true;
168 Assert.Equal(0, count);
169 Assert.False(mockTimer.IsTimerRunning);
172 await debouncing.Call();
175 Assert.Equal(0, count);
176 Assert.True(mockTimer.IsTimerRunning);
177 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
180 TestUtils.DriftTime(TimeSpan.FromMinutes(2));
181 await mockTimer.Invoke();
184 Assert.Equal(1, count); // invoked (trailing)
185 Assert.False(mockTimer.IsTimerRunning);
188 await debouncing.Call();
191 Assert.Equal(1, count);
192 Assert.True(mockTimer.IsTimerRunning);
193 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
196 TestUtils.DriftTime(TimeSpan.FromMinutes(2));
197 await mockTimer.Invoke();
200 Assert.Equal(2, count); // invoked (trailing)
201 Assert.False(mockTimer.IsTimerRunning);
206 public async Task Callback_Debounce_LeadingAndTrailing_Test()
208 using (TestUtils.FreezeTime(new DateTimeUtc(2022, 1, 1, 0, 0, 0)))
215 TestUtils.DriftTime(TimeSpan.FromSeconds(10));
216 return Task.CompletedTask;
219 var interval = TimeSpan.FromMinutes(2);
220 var maxWait = TimeSpan.MaxValue;
221 using var debouncing = new TestDebounceTimer(Callback, interval, leading: true, trailing: true);
222 var mockTimer = debouncing.MockTimer;
224 debouncing.Enabled = true;
226 Assert.Equal(0, count);
227 Assert.False(mockTimer.IsTimerRunning);
230 await debouncing.Call();
233 Assert.Equal(1, count); // invoked (leading)
234 Assert.True(mockTimer.IsTimerRunning);
235 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
238 TestUtils.DriftTime(TimeSpan.FromMinutes(1));
239 await debouncing.Call();
242 Assert.Equal(1, count);
243 Assert.True(mockTimer.IsTimerRunning);
246 TestUtils.DriftTime(TimeSpan.FromMinutes(1));
247 await mockTimer.Invoke();
250 Assert.Equal(1, count);
251 Assert.True(mockTimer.IsTimerRunning);
252 Assert.Equal(TimeSpan.FromMinutes(1), mockTimer.DueTime);
255 TestUtils.DriftTime(TimeSpan.FromMinutes(1));
256 await mockTimer.Invoke();
259 Assert.Equal(2, count); // invoked (trailing)
260 Assert.False(mockTimer.IsTimerRunning);
265 public async Task Callback_Debounce_LeadingAndTrailing_CallOnceTest()
267 using (TestUtils.FreezeTime(new DateTimeUtc(2022, 1, 1, 0, 0, 0)))
274 TestUtils.DriftTime(TimeSpan.FromSeconds(10));
275 return Task.CompletedTask;
278 var interval = TimeSpan.FromMinutes(2);
279 var maxWait = TimeSpan.MaxValue;
280 using var debouncing = new TestDebounceTimer(Callback, interval, leading: true, trailing: true);
281 var mockTimer = debouncing.MockTimer;
283 debouncing.Enabled = true;
285 Assert.Equal(0, count);
286 Assert.False(mockTimer.IsTimerRunning);
289 await debouncing.Call();
292 Assert.Equal(1, count); // invoked (leading)
293 Assert.True(mockTimer.IsTimerRunning);
294 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
297 TestUtils.DriftTime(TimeSpan.FromMinutes(2));
298 await mockTimer.Invoke();
301 Assert.Equal(1, count); // skip trailing
302 Assert.False(mockTimer.IsTimerRunning);
307 public async Task Callback_Debounce_LeadingAndTrailing_ResumeTest()
309 using (TestUtils.FreezeTime(new DateTimeUtc(2022, 1, 1, 0, 0, 0)))
316 TestUtils.DriftTime(TimeSpan.FromSeconds(10));
317 return Task.CompletedTask;
320 var interval = TimeSpan.FromMinutes(2);
321 var maxWait = TimeSpan.MaxValue;
322 using var debouncing = new TestDebounceTimer(Callback, interval, leading: true, trailing: true);
323 var mockTimer = debouncing.MockTimer;
325 debouncing.Enabled = true;
327 Assert.Equal(0, count);
328 Assert.False(mockTimer.IsTimerRunning);
331 await debouncing.Call();
334 Assert.Equal(1, count); // invoked (leading)
335 Assert.True(mockTimer.IsTimerRunning);
336 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
339 TestUtils.DriftTime(TimeSpan.FromMinutes(1));
340 await debouncing.Call();
343 Assert.Equal(1, count);
344 Assert.True(mockTimer.IsTimerRunning);
347 TestUtils.DriftTime(TimeSpan.FromMinutes(1));
348 await mockTimer.Invoke();
351 Assert.Equal(1, count);
352 Assert.True(mockTimer.IsTimerRunning);
353 Assert.Equal(TimeSpan.FromMinutes(1), mockTimer.DueTime);
356 TestUtils.DriftTime(TimeSpan.FromMinutes(1));
357 await mockTimer.Invoke();
360 Assert.Equal(2, count); // invoked (trailing)
361 Assert.False(mockTimer.IsTimerRunning);
364 await debouncing.Call();
367 Assert.Equal(3, count); // invoked (leading)
368 Assert.True(mockTimer.IsTimerRunning);
369 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
372 TestUtils.DriftTime(TimeSpan.FromMinutes(2));
373 await mockTimer.Invoke();
376 Assert.Equal(3, count); // skip trailing
377 Assert.False(mockTimer.IsTimerRunning);
382 public async Task Callback_Debounce_SystemClockChangedTest()
384 using (TestUtils.FreezeTime(new DateTimeUtc(2022, 1, 1, 1, 0, 0)))
391 TestUtils.DriftTime(TimeSpan.FromSeconds(10));
392 return Task.CompletedTask;
395 var interval = TimeSpan.FromMinutes(2);
396 var maxWait = TimeSpan.MaxValue;
397 using var debouncing = new TestDebounceTimer(Callback, interval, leading: false, trailing: true);
398 var mockTimer = debouncing.MockTimer;
400 debouncing.Enabled = true;
402 Assert.Equal(0, count);
403 Assert.False(mockTimer.IsTimerRunning);
406 await debouncing.Call();
409 Assert.Equal(0, count);
410 Assert.True(mockTimer.IsTimerRunning);
411 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
414 // システムの時刻が変更され1時間前に戻った場合
415 TestUtils.DriftTime(TimeSpan.FromHours(-1));
418 TestUtils.DriftTime(TimeSpan.FromMinutes(2));
419 await mockTimer.Invoke();
422 Assert.Equal(0, count);
423 Assert.True(mockTimer.IsTimerRunning);
424 Assert.Equal(TimeSpan.FromMinutes(2), mockTimer.DueTime);
427 TestUtils.DriftTime(TimeSpan.FromMinutes(2));
428 await mockTimer.Invoke();
431 Assert.Equal(1, count);
432 Assert.False(mockTimer.IsTimerRunning);
437 public async Task Call_DisabledTest()
439 using (TestUtils.FreezeTime(new DateTimeUtc(2022, 1, 1, 0, 0, 0)))
441 static Task Callback()
442 => Task.CompletedTask;
444 var interval = TimeSpan.FromMinutes(2);
445 var maxWait = TimeSpan.MaxValue;
446 using var debouncing = new TestDebounceTimer(Callback, interval, leading: false, trailing: true);
447 var mockTimer = debouncing.MockTimer;
449 debouncing.Enabled = false;
451 await debouncing.Call();
452 Assert.False(mockTimer.IsTimerRunning);
457 public async Task DisabledWhileTimerIsRunning()
459 using (TestUtils.FreezeTime(new DateTimeUtc(2022, 1, 1, 0, 0, 0)))
461 static Task Callback()
462 => Task.CompletedTask;
464 var interval = TimeSpan.FromMinutes(2);
465 var maxWait = TimeSpan.MaxValue;
466 using var debouncing = new TestDebounceTimer(Callback, interval, leading: false, trailing: true);
467 var mockTimer = debouncing.MockTimer;
469 debouncing.Enabled = true;
471 await debouncing.Call();
472 Assert.True(mockTimer.IsTimerRunning);
474 debouncing.Enabled = false;
475 Assert.False(mockTimer.IsTimerRunning);