Forráskód Böngészése

Move time string formatting code to a new class and add tests

Daniel Chalmers 3 hónapja
szülő
commit
dcff172045

+ 160 - 0
DesktopClock.Tests/TimeStringFormatterTests.cs

@@ -0,0 +1,160 @@
+using System;
+using System.Globalization;
+using Humanizer;
+
+namespace DesktopClock.Tests;
+
+public class TimeStringFormatterTests
+{
+    [Fact]
+    public void Format_UsesFormatWhenNoCountdown()
+    {
+        var now = new DateTimeOffset(2024, 1, 1, 10, 15, 0, TimeSpan.Zero);
+        var timeZone = TimeZoneInfo.CreateCustomTimeZone("UtcPlus2", TimeSpan.FromHours(2), "UtcPlus2", "UtcPlus2");
+
+        var result = TimeStringFormatter.Format(
+            now,
+            now.DateTime,
+            timeZone,
+            default,
+            "HH:mm",
+            null,
+            TextTransform.None,
+            CultureInfo.InvariantCulture);
+
+        Assert.Equal("12:15", result);
+    }
+
+    [Fact]
+    public void Format_UsesFormatProviderForStandardFormats()
+    {
+        var now = new DateTimeOffset(2024, 1, 2, 10, 15, 0, TimeSpan.Zero);
+        var formatProvider = new CultureInfo("en-GB");
+
+        var result = TimeStringFormatter.Format(
+            now,
+            now.DateTime,
+            TimeZoneInfo.Utc,
+            default,
+            "d",
+            null,
+            TextTransform.None,
+            formatProvider);
+
+        Assert.Equal(now.ToString("d", formatProvider), result);
+    }
+
+    [Fact]
+    public void Format_UsesTokenizedCountdownFormat()
+    {
+        var now = new DateTimeOffset(2024, 1, 1, 10, 0, 0, TimeSpan.Zero);
+        var nowDateTime = now.DateTime;
+        var countdownTo = nowDateTime.AddHours(1).AddMinutes(2).AddSeconds(3);
+
+        var result = TimeStringFormatter.Format(
+            now,
+            nowDateTime,
+            TimeZoneInfo.Utc,
+            countdownTo,
+            "HH:mm",
+            "{hh\\:mm}",
+            TextTransform.None,
+            CultureInfo.InvariantCulture);
+
+        Assert.Equal("01:02", result);
+    }
+
+    [Fact]
+    public void Format_UsesCountdownFormatWhenProvided()
+    {
+        var now = new DateTimeOffset(2024, 1, 1, 10, 0, 0, TimeSpan.Zero);
+        var nowDateTime = now.DateTime;
+        var countdownTo = nowDateTime.AddMinutes(90);
+        var formatProvider = CultureInfo.InvariantCulture;
+
+        var result = TimeStringFormatter.Format(
+            now,
+            nowDateTime,
+            TimeZoneInfo.Utc,
+            countdownTo,
+            "HH:mm",
+            "c",
+            TextTransform.None,
+            formatProvider);
+
+        Assert.Equal((countdownTo - nowDateTime).ToString("c", formatProvider), result);
+    }
+
+    [Fact]
+    public void Format_UsesHumanizerWhenCountdownFormatMissing()
+    {
+        var originalCulture = CultureInfo.CurrentCulture;
+        var originalUiCulture = CultureInfo.CurrentUICulture;
+
+        try
+        {
+            var enUs = new CultureInfo("en-US");
+            CultureInfo.CurrentCulture = enUs;
+            CultureInfo.CurrentUICulture = enUs;
+
+            var now = new DateTimeOffset(2024, 1, 1, 10, 0, 0, TimeSpan.Zero);
+            var nowDateTime = now.DateTime;
+            var countdownTo = nowDateTime.AddDays(1);
+
+            var result = TimeStringFormatter.Format(
+                now,
+                nowDateTime,
+                TimeZoneInfo.Utc,
+                countdownTo,
+                "HH:mm",
+                " ",
+                TextTransform.None,
+                CultureInfo.CurrentCulture);
+
+            Assert.Equal(countdownTo.Humanize(utcDate: false, dateToCompareAgainst: nowDateTime), result);
+        }
+        finally
+        {
+            CultureInfo.CurrentCulture = originalCulture;
+            CultureInfo.CurrentUICulture = originalUiCulture;
+        }
+    }
+
+    [Fact]
+    public void Format_ConvertsUsingSelectedTimeZone()
+    {
+        var now = new DateTimeOffset(2024, 1, 1, 23, 30, 0, TimeSpan.Zero);
+        var timeZone = TimeZoneInfo.CreateCustomTimeZone("UtcMinus5", TimeSpan.FromHours(-5), "UtcMinus5", "UtcMinus5");
+
+        var result = TimeStringFormatter.Format(
+            now,
+            now.DateTime,
+            timeZone,
+            default,
+            "HH:mm",
+            null,
+            TextTransform.None,
+            CultureInfo.InvariantCulture);
+
+        Assert.Equal("18:30", result);
+    }
+
+    [Fact]
+    public void Format_AppliesTextTransform()
+    {
+        var now = new DateTimeOffset(2024, 1, 1, 13, 5, 0, TimeSpan.Zero);
+        var formatProvider = new CultureInfo("en-US");
+
+        var result = TimeStringFormatter.Format(
+            now,
+            now.DateTime,
+            TimeZoneInfo.Utc,
+            default,
+            "h:mm tt",
+            null,
+            TextTransform.Lowercase,
+            formatProvider);
+
+        Assert.Equal("1:05 pm", result);
+    }
+}

+ 12 - 30
DesktopClock/MainWindow.xaml.cs

@@ -13,7 +13,6 @@ using DesktopClock.Properties;
 using DesktopClock.Utilities;
 using H.NotifyIcon;
 using H.NotifyIcon.EfficiencyMode;
-using Humanizer;
 using WpfWindowPlacement;
 
 namespace DesktopClock;
@@ -227,35 +226,18 @@ public partial class MainWindow : Window
 
     private void UpdateTimeString()
     {
-        string GetTimeString()
-        {
-            var timeInSelectedZone = TimeZoneInfo.ConvertTime(DateTimeOffset.Now, _timeZone);
-
-            string result;
-            if (Settings.Default.CountdownTo == default)
-            {
-                result = Tokenizer.FormatWithTokenizerOrFallBack(timeInSelectedZone, Settings.Default.Format, CultureInfo.DefaultThreadCurrentCulture);
-            }
-            else
-            {
-                if (string.IsNullOrWhiteSpace(Settings.Default.CountdownFormat))
-                    result = Settings.Default.CountdownTo.Humanize(utcDate: false, dateToCompareAgainst: DateTime.Now);
-                else
-                    result = Tokenizer.FormatWithTokenizerOrFallBack(Settings.Default.CountdownTo - DateTime.Now, Settings.Default.CountdownFormat, CultureInfo.DefaultThreadCurrentCulture);
-            }
-
-            // Apply text transformation
-            result = Settings.Default.TextTransform switch
-            {
-                TextTransform.Uppercase => result.ToUpper(),
-                TextTransform.Lowercase => result.ToLower(),
-                _ => result
-            };
-
-            return result;
-        }
-
-        CurrentTimeOrCountdownString = GetTimeString();
+        var now = DateTimeOffset.Now;
+        var nowDateTime = now.DateTime;
+
+        CurrentTimeOrCountdownString = TimeStringFormatter.Format(
+            now,
+            nowDateTime,
+            _timeZone,
+            Settings.Default.CountdownTo,
+            Settings.Default.Format,
+            Settings.Default.CountdownFormat,
+            Settings.Default.TextTransform,
+            CultureInfo.DefaultThreadCurrentCulture);
     }
 
     private void Window_MouseDown(object sender, MouseButtonEventArgs e)

+ 53 - 0
DesktopClock/Utilities/TimeStringFormatter.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Globalization;
+using Humanizer;
+
+namespace DesktopClock;
+
+public static class TimeStringFormatter
+{
+    public static string Format(
+        DateTimeOffset now,
+        DateTime nowDateTime,
+        TimeZoneInfo timeZone,
+        DateTime countdownTo,
+        string format,
+        string countdownFormat,
+        TextTransform textTransform,
+        IFormatProvider formatProvider)
+    {
+        var timeInSelectedZone = TimeZoneInfo.ConvertTime(now, timeZone);
+
+        string result;
+        if (countdownTo == default)
+        {
+            result = Tokenizer.FormatWithTokenizerOrFallBack(timeInSelectedZone, format, formatProvider);
+        }
+        else if (string.IsNullOrWhiteSpace(countdownFormat))
+        {
+            result = countdownTo.Humanize(utcDate: false, dateToCompareAgainst: nowDateTime);
+        }
+        else
+        {
+            var countdown = countdownTo - nowDateTime;
+            result = Tokenizer.FormatWithTokenizerOrFallBack(countdown, countdownFormat, formatProvider);
+        }
+
+        return ApplyTransform(result, textTransform, formatProvider);
+    }
+
+    private static string ApplyTransform(string value, TextTransform textTransform, IFormatProvider formatProvider)
+    {
+        if (textTransform == TextTransform.None)
+            return value;
+
+        var culture = formatProvider as CultureInfo;
+
+        return textTransform switch
+        {
+            TextTransform.Uppercase => culture == null ? value.ToUpper() : value.ToUpper(culture),
+            TextTransform.Lowercase => culture == null ? value.ToLower() : value.ToLower(culture),
+            _ => value,
+        };
+    }
+}