From 3bca0081afca4a4256dbd409166577e0960c8c47 Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Tue, 24 Dec 2024 15:55:07 +0900
Subject: [PATCH 01/12] Add F# library and file
---
Startwatch.Library.FSharp/Library.fs | 45 +++++++++++++++++++
.../Startwatch.Library.FSharp.fsproj | 12 +++++
Startwatch.sln | 6 +++
3 files changed, 63 insertions(+)
create mode 100644 Startwatch.Library.FSharp/Library.fs
create mode 100644 Startwatch.Library.FSharp/Startwatch.Library.FSharp.fsproj
diff --git a/Startwatch.Library.FSharp/Library.fs b/Startwatch.Library.FSharp/Library.fs
new file mode 100644
index 0000000..0067ad1
--- /dev/null
+++ b/Startwatch.Library.FSharp/Library.fs
@@ -0,0 +1,45 @@
+namespace Startwatch.Library.FSharp
+
+open System
+open System.Diagnostics
+
+module Startwatch =
+ type Watch() =
+ let startedAt = Stopwatch.GetTimestamp()
+
+ let elapsedFriendly (startedAt: int64) =
+ let timeSpan = Stopwatch.GetElapsedTime(startedAt)
+ match timeSpan with
+ | t when t.TotalMilliseconds < 1 -> sprintf "%s" (t.TotalNanoseconds.ToString("#,##0ns"))
+ | t when t.TotalMilliseconds < 1000 -> sprintf "%s" (t.TotalMilliseconds.ToString("#,##0ms"))
+ | t ->
+ let days = t.Days
+ let hours = t.Hours
+ let mins = t.Minutes
+ let secs = t.Seconds
+
+ let prependText = if secs = 0 then "exactly " else String.Empty
+
+ let hoursText =
+ match (days, hours) with
+ | d, _ when d > 0 -> sprintf "%s" ((hours + (days * 24)).ToString("#,##0h"))
+ | _, h when h > 0 -> sprintf "%s" ((hours + (days * 24)).ToString("#,##0h"))
+ | _ -> String.Empty
+
+ let minsText =
+ match (hours, mins) with
+ | h, m when h > 0 && m > 0 -> sprintf "%s" (m.ToString("00m"))
+ | _, m when m > 0 -> sprintf "%s" (m.ToString("0m"))
+ | _ -> String.Empty
+
+ let secsText =
+ match (hours, mins, secs) with
+ | 0, 0, s when s > 0 -> sprintf "%s\\.%ff" (t.ToString("s")) (t.TotalSeconds % 1.0)
+ | h, _, s when h > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
+ | _, m, s when m > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
+ | _, _, s when s > 0 -> sprintf "%ss" (t.ToString("s"))
+ | _ -> String.Empty
+
+ $"{prependText}{hoursText}{minsText}{secsText}"
+
+ member this.ElapsedFriendly = elapsedFriendly startedAt
diff --git a/Startwatch.Library.FSharp/Startwatch.Library.FSharp.fsproj b/Startwatch.Library.FSharp/Startwatch.Library.FSharp.fsproj
new file mode 100644
index 0000000..850ca49
--- /dev/null
+++ b/Startwatch.Library.FSharp/Startwatch.Library.FSharp.fsproj
@@ -0,0 +1,12 @@
+
+
+
+ net9.0
+ true
+
+
+
+
+
+
+
diff --git a/Startwatch.sln b/Startwatch.sln
index 09434bb..a6c9551 100644
--- a/Startwatch.sln
+++ b/Startwatch.sln
@@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Startwatch.Library", ".\Sta
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Startwatch.Tests", ".\Startwatch.Tests\Startwatch.Tests.csproj", "{295D954F-453F-4311-8D72-1EFF57261A38}"
EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Startwatch.Library.FSharp", "Startwatch.Library.FSharp\Startwatch.Library.FSharp.fsproj", "{2D3CE51D-304B-41F5-B86A-C6794E5364E8}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +23,10 @@ Global
{295D954F-453F-4311-8D72-1EFF57261A38}.Debug|Any CPU.Build.0 = Debug|Any CPU
{295D954F-453F-4311-8D72-1EFF57261A38}.Release|Any CPU.ActiveCfg = Release|Any CPU
{295D954F-453F-4311-8D72-1EFF57261A38}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2D3CE51D-304B-41F5-B86A-C6794E5364E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2D3CE51D-304B-41F5-B86A-C6794E5364E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2D3CE51D-304B-41F5-B86A-C6794E5364E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2D3CE51D-304B-41F5-B86A-C6794E5364E8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
From 80319d8d0bfe32da582301a58a63f4154baaac2c Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Tue, 24 Dec 2024 22:19:02 +0900
Subject: [PATCH 02/12] Recreate tests in F#
---
.../Startwatch.Library.FSharp.fsproj | 12 -
Startwatch.Library/ExtensionMethods.cs | 51 ----
.../Library.fs | 23 +-
Startwatch.Library/Startwatch.Library.csproj | 20 --
Startwatch.Library/Startwatch.Library.fsproj | 27 ++
Startwatch.Library/Watch.cs | 42 ---
Startwatch.Tests.FSharp/Program.fs | 4 +
.../Startwatch.Tests.FSharp.fsproj | 25 ++
Startwatch.Tests.FSharp/Tests.fs | 188 ++++++++++++++
Startwatch.Tests/Startwatch.Tests.csproj | 24 --
Startwatch.Tests/StartwatchTests.cs | 242 ------------------
Startwatch.Tests/Usings.cs | 1 -
Startwatch.sln | 18 +-
13 files changed, 262 insertions(+), 415 deletions(-)
delete mode 100644 Startwatch.Library.FSharp/Startwatch.Library.FSharp.fsproj
delete mode 100644 Startwatch.Library/ExtensionMethods.cs
rename {Startwatch.Library.FSharp => Startwatch.Library}/Library.fs (78%)
delete mode 100644 Startwatch.Library/Startwatch.Library.csproj
create mode 100644 Startwatch.Library/Startwatch.Library.fsproj
delete mode 100644 Startwatch.Library/Watch.cs
create mode 100644 Startwatch.Tests.FSharp/Program.fs
create mode 100644 Startwatch.Tests.FSharp/Startwatch.Tests.FSharp.fsproj
create mode 100644 Startwatch.Tests.FSharp/Tests.fs
delete mode 100644 Startwatch.Tests/Startwatch.Tests.csproj
delete mode 100644 Startwatch.Tests/StartwatchTests.cs
delete mode 100644 Startwatch.Tests/Usings.cs
diff --git a/Startwatch.Library.FSharp/Startwatch.Library.FSharp.fsproj b/Startwatch.Library.FSharp/Startwatch.Library.FSharp.fsproj
deleted file mode 100644
index 850ca49..0000000
--- a/Startwatch.Library.FSharp/Startwatch.Library.FSharp.fsproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- net9.0
- true
-
-
-
-
-
-
-
diff --git a/Startwatch.Library/ExtensionMethods.cs b/Startwatch.Library/ExtensionMethods.cs
deleted file mode 100644
index 82502f6..0000000
--- a/Startwatch.Library/ExtensionMethods.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System;
-
-namespace Startwatch.Library;
-
-public static class ExtensionMethods
-{
- ///
- /// Get a short, friendly, human-readable string representation of a TimeSpan.
- ///
- public static string ElapsedFriendly(this TimeSpan timeSpan)
- {
- if (timeSpan.TotalMilliseconds < 1000)
- {
- return timeSpan switch
- {
- { TotalMilliseconds: <1 } => $"{timeSpan.TotalNanoseconds:#,##0}ns",
- _ => $"{timeSpan.TotalMilliseconds:#,##0}ms"
- };
- }
-
- int days = timeSpan.Days;
- int hours = timeSpan.Hours;
- int mins = timeSpan.Minutes;
- int secs = timeSpan.Seconds;
-
- var prependText = secs == 0 ? "exactly " : string.Empty;
-
- var hoursText = (days, hours) switch
- {
- (>0, _) or (_, >0) => $"{hours + (days * 24):#,##0}h",
- _ => string.Empty
- };
-
- var minsText = (hours, mins) switch
- {
- (>0, >0) => $"{mins:00}m",
- (_, >0) => $"{mins:0}m",
- _ => string.Empty
- };
-
- var secsText = (hours, mins, secs) switch
- {
- (0, 0, >0) => $"{timeSpan:s\\.ff}s",
- (>0, _, >0) or (_, >0, >0) => $"{timeSpan:ss}s",
- (_, _, >0) => $"{timeSpan:s}s",
- _ => string.Empty
- };
-
- return $"{prependText}{hoursText}{minsText}{secsText}";
- }
-}
diff --git a/Startwatch.Library.FSharp/Library.fs b/Startwatch.Library/Library.fs
similarity index 78%
rename from Startwatch.Library.FSharp/Library.fs
rename to Startwatch.Library/Library.fs
index 0067ad1..412a96b 100644
--- a/Startwatch.Library.FSharp/Library.fs
+++ b/Startwatch.Library/Library.fs
@@ -1,15 +1,12 @@
-namespace Startwatch.Library.FSharp
+namespace Startwatch.Library
open System
open System.Diagnostics
-module Startwatch =
- type Watch() =
- let startedAt = Stopwatch.GetTimestamp()
-
- let elapsedFriendly (startedAt: int64) =
- let timeSpan = Stopwatch.GetElapsedTime(startedAt)
- match timeSpan with
+module Extensions =
+ type TimeSpan with
+ member this.ElapsedFriendly() =
+ match this with
| t when t.TotalMilliseconds < 1 -> sprintf "%s" (t.TotalNanoseconds.ToString("#,##0ns"))
| t when t.TotalMilliseconds < 1000 -> sprintf "%s" (t.TotalMilliseconds.ToString("#,##0ms"))
| t ->
@@ -34,12 +31,16 @@ module Startwatch =
let secsText =
match (hours, mins, secs) with
- | 0, 0, s when s > 0 -> sprintf "%s\\.%ff" (t.ToString("s")) (t.TotalSeconds % 1.0)
+ | 0, 0, s when s > 0 -> sprintf "%ss" (t.ToString("s\\.ff"))
| h, _, s when h > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
| _, m, s when m > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
- | _, _, s when s > 0 -> sprintf "%ss" (t.ToString("s"))
+ | _, _, s when s > 0 -> sprintf "%s" (t.ToString("s"))
| _ -> String.Empty
$"{prependText}{hoursText}{minsText}{secsText}"
- member this.ElapsedFriendly = elapsedFriendly startedAt
+module Startwatch =
+ type Watch() =
+ let startedAt = Stopwatch.GetTimestamp()
+
+ member this.ElapsedFriendly = Stopwatch.GetElapsedTime(startedAt)
diff --git a/Startwatch.Library/Startwatch.Library.csproj b/Startwatch.Library/Startwatch.Library.csproj
deleted file mode 100644
index e3fc4dd..0000000
--- a/Startwatch.Library/Startwatch.Library.csproj
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- net9.0
- disable
- enable
- CodeConscious.Startwatch
- 0.0.4
- CodeConscious
- CodeConscious
- A simple Stopwatch wrapper.
- https://github.com/codeconscious/startwatch
- https://github.com/codeconscious/startwatch
- readme.md
- MIT
- true
-
-
-
-
-
diff --git a/Startwatch.Library/Startwatch.Library.fsproj b/Startwatch.Library/Startwatch.Library.fsproj
new file mode 100644
index 0000000..cdba923
--- /dev/null
+++ b/Startwatch.Library/Startwatch.Library.fsproj
@@ -0,0 +1,27 @@
+
+
+
+ net9.0
+ true
+ CodeConscious.Startwatch
+ 0.0.5
+ CodeConscious
+ CodeConscious
+ A simple wrapper for System.Diagnostics.Stopwatch.
+ https://github.com/codeconscious/startwatch
+ https://github.com/codeconscious/startwatch
+ readme.md
+ MIT
+ true
+ Startwatch.Library
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Startwatch.Library/Watch.cs b/Startwatch.Library/Watch.cs
deleted file mode 100644
index e8c8151..0000000
--- a/Startwatch.Library/Watch.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-using System.Diagnostics;
-
-namespace Startwatch.Library;
-
-///
-/// A `Stopwatch` wrapper. Starts the enclosed `Stopwatch` upon instantiation.
-///
-public sealed class Watch
-{
- private readonly Stopwatch _stopwatch = new();
-
- ///
- /// Returns a formatted version of the elapsed time since the timer was started.
- ///
- ///
- /// Using ticks because .ElapsedMilliseconds can be wildly inaccurate.
- /// (Reference: https://stackoverflow.com/q/5113750/11767771)
- ///
- /// Also, use `Stopwatch.Elapsed.Ticks` over `Stopwatch.ElapsedTicks`.
- /// For reasons of which I'm unware, the latter returns unexpected values.
- ///
- public string ElapsedFriendly =>
- TimeSpan.FromTicks(_stopwatch.Elapsed.Ticks).ElapsedFriendly();
-
- ///
- /// A constructor that automatically starts the enclosed `Stopwatch`.
- ///
- public Watch()
- {
- _stopwatch.Start();
- }
-
- ///
- /// Stops time interval measurement, resets the elapsed time to zero,
- /// and starts measuring elapsed time.
- ///
- public void Restart()
- {
- _stopwatch.Restart();
- }
-}
diff --git a/Startwatch.Tests.FSharp/Program.fs b/Startwatch.Tests.FSharp/Program.fs
new file mode 100644
index 0000000..52113d0
--- /dev/null
+++ b/Startwatch.Tests.FSharp/Program.fs
@@ -0,0 +1,4 @@
+module Program
+
+[]
+let main _ = 0
\ No newline at end of file
diff --git a/Startwatch.Tests.FSharp/Startwatch.Tests.FSharp.fsproj b/Startwatch.Tests.FSharp/Startwatch.Tests.FSharp.fsproj
new file mode 100644
index 0000000..7859d12
--- /dev/null
+++ b/Startwatch.Tests.FSharp/Startwatch.Tests.FSharp.fsproj
@@ -0,0 +1,25 @@
+
+
+
+ net9.0
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Startwatch.Tests.FSharp/Tests.fs b/Startwatch.Tests.FSharp/Tests.fs
new file mode 100644
index 0000000..043d016
--- /dev/null
+++ b/Startwatch.Tests.FSharp/Tests.fs
@@ -0,0 +1,188 @@
+module Tests
+
+open System
+open Startwatch.Library.Extensions
+open Xunit
+
+[]
+let ``nanosecond with three digits are formatted correctly`` () =
+ // Assert.True(true)
+ let timeSpan = TimeSpan.FromTicks(1) // 1 tick == 100 nanoseconds
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "100ns"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Nanoseconds_FiveDigits_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan.FromTicks(100L) // 1 tick == 100 nanoseconds
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "10,000ns"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Milliseconds_OneDigit_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(1.0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "1ms"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Milliseconds_TwoDigits_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(99.0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "99ms"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Milliseconds_ThreeDigits_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(999.0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "999ms"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Milliseconds_ThreeDigitsWithSmallDecimal_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(999.3)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "999ms"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Milliseconds_ThreeDigitsWithLargeDecimal_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(999.9)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "1,000ms"
+ Assert.Equal(expected, actual)
+
+[]
+let ``SecondsOnly_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(0, 0, 3)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "3.00s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Seconds_With500Milliseconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(0, 0, 0, 3, 500)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "3.50s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Seconds_With520Milliseconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(0, 0, 0, 3, 520)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "3.52s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Minute_NoSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(0, 1, 0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "exactly 1m"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Minute_30Seconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(0, 1, 30)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "1m30s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Minutes_TwoDigits_NoSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(0, 59, 0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "exactly 59m"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Minutes_TwoDigits_NoSeconds_WithSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(0, 59, 30)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "59m30s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``SingleDigitHour_NoMinutes_NoSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(7, 0, 0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "exactly 7h"
+ Assert.Equal(expected, actual)
+
+[]
+let ``SingleDigitHour_WithMinutes_NoSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(7, 20, 0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "exactly 7h20m"
+ Assert.Equal(expected, actual)
+
+[]
+let ``SingleDigitHour_NoMinutes_WithSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(7, 0, 47)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "7h47s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``DoubleDigitHour_NoMinutes_NoSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(13, 0, 0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "exactly 13h"
+ Assert.Equal(expected, actual)
+
+[]
+let ``SingleDigitHour_SingleDigitMinutes_NoSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(1, 5, 0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "exactly 1h05m"
+ Assert.Equal(expected, actual)
+
+[]
+let ``SingleDigitHour_DoubleDigitMinutes_NoSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(1, 55, 0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "exactly 1h55m"
+ Assert.Equal(expected, actual)
+
+[]
+let ``SingleDigitHour_DoubleDigitMinutes_SingleDigitSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(1, 55, 8)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "1h55m08s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``DoubleDigitHour_SingleDigitMinutes_SingleDigitSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(12, 5, 8)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "12h05m08s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``TripleDigitHour_SingleDigitMinutes_SingleDigitSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(36, 59, 59)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "36h59m59s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``SingleDigitDay_NoHoursMinutesOrSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(10, 0, 0, 0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "exactly 240h"
+ Assert.Equal(expected, actual)
+
+[]
+let ``SingleDigitDay_WithHoursMinutesOrSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(4, 4, 59, 59)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "100h59m59s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``TripleDigitDay_WithHoursMinutesOrSeconds_FormatsCorrectly`` () =
+ let timeSpan = TimeSpan(100, 23, 59, 59)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "2,423h59m59s"
+ Assert.Equal(expected, actual)
diff --git a/Startwatch.Tests/Startwatch.Tests.csproj b/Startwatch.Tests/Startwatch.Tests.csproj
deleted file mode 100644
index 85fe16c..0000000
--- a/Startwatch.Tests/Startwatch.Tests.csproj
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
- net9.0
- disable
- enable
- false
- true
-
-
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
-
-
-
-
diff --git a/Startwatch.Tests/StartwatchTests.cs b/Startwatch.Tests/StartwatchTests.cs
deleted file mode 100644
index 8a8f626..0000000
--- a/Startwatch.Tests/StartwatchTests.cs
+++ /dev/null
@@ -1,242 +0,0 @@
-using System;
-using Startwatch.Library;
-
-namespace Startwatch.Tests;
-
-public sealed class StartwatchTests
-{
- [Fact]
- public void Nanoseconds_ThreeDigits_FormatsCorrectly()
- {
- var timeSpan = TimeSpan.FromTicks(1); // 1 tick == 100 nanoseconds
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "100ns";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Nanoseconds_FiveDigits_FormatsCorrectly()
- {
- var timeSpan = TimeSpan.FromTicks(100); // 1 tick == 100 nanoseconds
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "10,000ns";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Milliseconds_OneDigit_FormatsCorrectly()
- {
- var timeSpan = TimeSpan.FromMilliseconds(1);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "1ms";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Milliseconds_TwoDigits_FormatsCorrectly()
- {
- var timeSpan = TimeSpan.FromMilliseconds(99);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "99ms";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Milliseconds_ThreeDigits_FormatsCorrectly()
- {
- var timeSpan = TimeSpan.FromMilliseconds(999);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "999ms";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Milliseconds_ThreeDigitsWithSmallDecimal_FormatsCorrectly()
- {
- var timeSpan = TimeSpan.FromMilliseconds(999.3);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "999ms";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Milliseconds_ThreeDigitsWithLargeDecimal_FormatsCorrectly()
- {
- var timeSpan = TimeSpan.FromMilliseconds(999.9);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "1,000ms";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void SecondsOnly_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(0, 0, 3);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "3.00s";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Seconds_With500Milliseconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(0, 0, 0, 3, 500);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "3.50s";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Seconds_With520Milliseconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(0, 0, 0, 3, 520);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "3.52s";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Minute_NoSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(0, 1, 0);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "exactly 1m";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Minute_30Seconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(0, 1, 30);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "1m30s";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Minutes_TwoDigits_NoSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(0, 59, 0);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "exactly 59m";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void Minutes_TwoDigits_NoSeconds_WithSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(0, 59, 30);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "59m30s";
- Assert.Equal(expected, actual);
- }
-
-
- [Fact]
- public void SingleDigitHour_NoMinutes_NoSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(7, 0, 0);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "exactly 7h";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void SingleDigitHour_WithMinutes_NoSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(7, 20, 0);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "exactly 7h20m";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void SingleDigitHour_NoMinutes_WithSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(7, 0, 47);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "7h47s";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void DoubleDigitHour_NoMinutes_NoSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(13, 0, 0);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "exactly 13h";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void SingleDigitHour_SingleDigitMinutes_NoSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(1, 5, 0);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "exactly 1h05m";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void SingleDigitHour_DoubleDigitMinutes_NoSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(1, 55, 0);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "exactly 1h55m";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void SingleDigitHour_DoubleDigitMinutes_SingleDigitSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(1, 55, 8);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "1h55m08s";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void DoubleDigitHour_SingleDigitMinutes_SingleDigitSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(12, 5, 8);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "12h05m08s";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void TripleDigitHour_SingleDigitMinutes_SingleDigitSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(36, 59, 59);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "36h59m59s";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void SingleDigitDay_NoHoursMinutesOrSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(10, 0, 0, 0);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "exactly 240h";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void SingleDigitDay_WithHoursMinutesOrSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(4, 4, 59, 59);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "100h59m59s";
- Assert.Equal(expected, actual);
- }
-
- [Fact]
- public void TripleDigitDay_WithHoursMinutesOrSeconds_FormatsCorrectly()
- {
- TimeSpan timeSpan = new(100, 23, 59, 59);
- string actual = timeSpan.ElapsedFriendly();
- const string expected = "2,423h59m59s";
- Assert.Equal(expected, actual);
- }
-}
diff --git a/Startwatch.Tests/Usings.cs b/Startwatch.Tests/Usings.cs
deleted file mode 100644
index 9df1d42..0000000
--- a/Startwatch.Tests/Usings.cs
+++ /dev/null
@@ -1 +0,0 @@
-global using Xunit;
diff --git a/Startwatch.sln b/Startwatch.sln
index a6c9551..bd09414 100644
--- a/Startwatch.sln
+++ b/Startwatch.sln
@@ -3,11 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 25.0.1706.0
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Startwatch.Library", ".\Startwatch.Library\Startwatch.Library.csproj", "{598A49D6-9724-400C-853A-8B950297DEBD}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Startwatch.Library", "Startwatch.Library\Startwatch.Library.fsproj", "{2D3CE51D-304B-41F5-B86A-C6794E5364E8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Startwatch.Tests", ".\Startwatch.Tests\Startwatch.Tests.csproj", "{295D954F-453F-4311-8D72-1EFF57261A38}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Startwatch.Library.FSharp", "Startwatch.Library.FSharp\Startwatch.Library.FSharp.fsproj", "{2D3CE51D-304B-41F5-B86A-C6794E5364E8}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Startwatch.Tests.FSharp", "Startwatch.Tests.FSharp\Startwatch.Tests.FSharp.fsproj", "{88AB89DE-6161-48E8-A95B-5E49FC2F1BED}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,18 +13,14 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {598A49D6-9724-400C-853A-8B950297DEBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {598A49D6-9724-400C-853A-8B950297DEBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {598A49D6-9724-400C-853A-8B950297DEBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {598A49D6-9724-400C-853A-8B950297DEBD}.Release|Any CPU.Build.0 = Release|Any CPU
- {295D954F-453F-4311-8D72-1EFF57261A38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {295D954F-453F-4311-8D72-1EFF57261A38}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {295D954F-453F-4311-8D72-1EFF57261A38}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {295D954F-453F-4311-8D72-1EFF57261A38}.Release|Any CPU.Build.0 = Release|Any CPU
{2D3CE51D-304B-41F5-B86A-C6794E5364E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D3CE51D-304B-41F5-B86A-C6794E5364E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D3CE51D-304B-41F5-B86A-C6794E5364E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D3CE51D-304B-41F5-B86A-C6794E5364E8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {88AB89DE-6161-48E8-A95B-5E49FC2F1BED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {88AB89DE-6161-48E8-A95B-5E49FC2F1BED}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {88AB89DE-6161-48E8-A95B-5E49FC2F1BED}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {88AB89DE-6161-48E8-A95B-5E49FC2F1BED}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
From 5e229111c8e733b087b8a4b1a7eb92d2f505d037 Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Tue, 24 Dec 2024 22:20:10 +0900
Subject: [PATCH 03/12] Rename test project
---
{Startwatch.Tests.FSharp => Startwatch.Tests}/Program.fs | 0
.../Startwatch.Tests.fsproj | 0
{Startwatch.Tests.FSharp => Startwatch.Tests}/Tests.fs | 3 +--
Startwatch.sln | 2 +-
4 files changed, 2 insertions(+), 3 deletions(-)
rename {Startwatch.Tests.FSharp => Startwatch.Tests}/Program.fs (100%)
rename Startwatch.Tests.FSharp/Startwatch.Tests.FSharp.fsproj => Startwatch.Tests/Startwatch.Tests.fsproj (100%)
rename {Startwatch.Tests.FSharp => Startwatch.Tests}/Tests.fs (99%)
diff --git a/Startwatch.Tests.FSharp/Program.fs b/Startwatch.Tests/Program.fs
similarity index 100%
rename from Startwatch.Tests.FSharp/Program.fs
rename to Startwatch.Tests/Program.fs
diff --git a/Startwatch.Tests.FSharp/Startwatch.Tests.FSharp.fsproj b/Startwatch.Tests/Startwatch.Tests.fsproj
similarity index 100%
rename from Startwatch.Tests.FSharp/Startwatch.Tests.FSharp.fsproj
rename to Startwatch.Tests/Startwatch.Tests.fsproj
diff --git a/Startwatch.Tests.FSharp/Tests.fs b/Startwatch.Tests/Tests.fs
similarity index 99%
rename from Startwatch.Tests.FSharp/Tests.fs
rename to Startwatch.Tests/Tests.fs
index 043d016..cc0b561 100644
--- a/Startwatch.Tests.FSharp/Tests.fs
+++ b/Startwatch.Tests/Tests.fs
@@ -1,12 +1,11 @@
module Tests
open System
-open Startwatch.Library.Extensions
open Xunit
+open Startwatch.Library.Extensions
[]
let ``nanosecond with three digits are formatted correctly`` () =
- // Assert.True(true)
let timeSpan = TimeSpan.FromTicks(1) // 1 tick == 100 nanoseconds
let actual = timeSpan.ElapsedFriendly()
let expected = "100ns"
diff --git a/Startwatch.sln b/Startwatch.sln
index bd09414..7f52969 100644
--- a/Startwatch.sln
+++ b/Startwatch.sln
@@ -5,7 +5,7 @@ VisualStudioVersion = 25.0.1706.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Startwatch.Library", "Startwatch.Library\Startwatch.Library.fsproj", "{2D3CE51D-304B-41F5-B86A-C6794E5364E8}"
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Startwatch.Tests.FSharp", "Startwatch.Tests.FSharp\Startwatch.Tests.FSharp.fsproj", "{88AB89DE-6161-48E8-A95B-5E49FC2F1BED}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Startwatch.Tests", "Startwatch.Tests\Startwatch.Tests.fsproj", "{88AB89DE-6161-48E8-A95B-5E49FC2F1BED}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
From 0bd40f0789ab9adfd99ba58ebf246f551aef1287 Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Wed, 25 Dec 2024 10:34:36 +0900
Subject: [PATCH 04/12] Update tests
---
Startwatch.Library/Library.fs | 11 ++--
Startwatch.Tests/Tests.fs | 117 ++++++++++++++++++++++++----------
2 files changed, 89 insertions(+), 39 deletions(-)
diff --git a/Startwatch.Library/Library.fs b/Startwatch.Library/Library.fs
index 412a96b..3b8ed50 100644
--- a/Startwatch.Library/Library.fs
+++ b/Startwatch.Library/Library.fs
@@ -30,11 +30,12 @@ module Extensions =
| _ -> String.Empty
let secsText =
- match (hours, mins, secs) with
- | 0, 0, s when s > 0 -> sprintf "%ss" (t.ToString("s\\.ff"))
- | h, _, s when h > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
- | _, m, s when m > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
- | _, _, s when s > 0 -> sprintf "%s" (t.ToString("s"))
+ match (days, hours, mins, secs) with
+ | d, _, 0, s when d > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
+ | _, 0, 0, s when s > 0 -> sprintf "%ss" (t.ToString("s\\.ff"))
+ | _, h, _, s when h > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
+ | _, _, m, s when m > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
+ | _, _, _, s when s > 0 -> sprintf "%s" (t.ToString("s"))
| _ -> String.Empty
$"{prependText}{hoursText}{minsText}{secsText}"
diff --git a/Startwatch.Tests/Tests.fs b/Startwatch.Tests/Tests.fs
index cc0b561..e7b3654 100644
--- a/Startwatch.Tests/Tests.fs
+++ b/Startwatch.Tests/Tests.fs
@@ -5,182 +5,231 @@ open Xunit
open Startwatch.Library.Extensions
[]
-let ``nanosecond with three digits are formatted correctly`` () =
+let ``Nanoseconds with 3 digits`` () =
let timeSpan = TimeSpan.FromTicks(1) // 1 tick == 100 nanoseconds
let actual = timeSpan.ElapsedFriendly()
let expected = "100ns"
Assert.Equal(expected, actual)
[]
-let ``Nanoseconds_FiveDigits_FormatsCorrectly`` () =
+let ``Nanoseconds with 5 digits`` () =
let timeSpan = TimeSpan.FromTicks(100L) // 1 tick == 100 nanoseconds
let actual = timeSpan.ElapsedFriendly()
let expected = "10,000ns"
Assert.Equal(expected, actual)
[]
-let ``Milliseconds_OneDigit_FormatsCorrectly`` () =
+let ``Single-digit milliseconds`` () =
let timeSpan = TimeSpan.FromMilliseconds(1.0)
let actual = timeSpan.ElapsedFriendly()
let expected = "1ms"
Assert.Equal(expected, actual)
[]
-let ``Milliseconds_TwoDigits_FormatsCorrectly`` () =
+let ``Double-digit milliseconds`` () =
let timeSpan = TimeSpan.FromMilliseconds(99.0)
let actual = timeSpan.ElapsedFriendly()
let expected = "99ms"
Assert.Equal(expected, actual)
[]
-let ``Milliseconds_ThreeDigits_FormatsCorrectly`` () =
+let ``Double-digit milliseconds with a small decimal`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(99.2)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "99ms"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Double-digit milliseconds with a large decimal`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(99.9)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "100ms"
+ Assert.Equal(expected, actual)
+
+
+[]
+let ``Triple-digit milliseconds`` () =
let timeSpan = TimeSpan.FromMilliseconds(999.0)
let actual = timeSpan.ElapsedFriendly()
let expected = "999ms"
Assert.Equal(expected, actual)
[]
-let ``Milliseconds_ThreeDigitsWithSmallDecimal_FormatsCorrectly`` () =
+let ``Triple-digit milliseconds with a small decimal`` () =
let timeSpan = TimeSpan.FromMilliseconds(999.3)
let actual = timeSpan.ElapsedFriendly()
let expected = "999ms"
Assert.Equal(expected, actual)
[]
-let ``Milliseconds_ThreeDigitsWithLargeDecimal_FormatsCorrectly`` () =
+let ``Triple-digit milliseconds with a large decimal`` () =
let timeSpan = TimeSpan.FromMilliseconds(999.9)
let actual = timeSpan.ElapsedFriendly()
let expected = "1,000ms"
Assert.Equal(expected, actual)
[]
-let ``SecondsOnly_FormatsCorrectly`` () =
+let ``Single-digit seconds`` () =
let timeSpan = TimeSpan(0, 0, 3)
let actual = timeSpan.ElapsedFriendly()
let expected = "3.00s"
Assert.Equal(expected, actual)
[]
-let ``Seconds_With500Milliseconds_FormatsCorrectly`` () =
+let ``Single-digit seconds with 500 milliseconds`` () =
let timeSpan = TimeSpan(0, 0, 0, 3, 500)
let actual = timeSpan.ElapsedFriendly()
let expected = "3.50s"
Assert.Equal(expected, actual)
[]
-let ``Seconds_With520Milliseconds_FormatsCorrectly`` () =
+let ``Single-digit seconds with 520 milliseconds`` () =
let timeSpan = TimeSpan(0, 0, 0, 3, 520)
let actual = timeSpan.ElapsedFriendly()
let expected = "3.52s"
Assert.Equal(expected, actual)
[]
-let ``Minute_NoSeconds_FormatsCorrectly`` () =
+let ``Single-digit minute with no seconds`` () =
let timeSpan = TimeSpan(0, 1, 0)
let actual = timeSpan.ElapsedFriendly()
let expected = "exactly 1m"
Assert.Equal(expected, actual)
[]
-let ``Minute_30Seconds_FormatsCorrectly`` () =
+let ``Single-digit minute with single-digit seconds`` () =
+ let timeSpan = TimeSpan(0, 1, 5)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "1m05s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Single-digit minute with double-digit seconds`` () =
let timeSpan = TimeSpan(0, 1, 30)
let actual = timeSpan.ElapsedFriendly()
let expected = "1m30s"
Assert.Equal(expected, actual)
[]
-let ``Minutes_TwoDigits_NoSeconds_FormatsCorrectly`` () =
+let ``Single-digit minute with maximum seconds`` () =
+ let timeSpan = TimeSpan(0, 1, 59)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "1m59s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Two-digit minutes with no seconds`` () =
let timeSpan = TimeSpan(0, 59, 0)
let actual = timeSpan.ElapsedFriendly()
let expected = "exactly 59m"
Assert.Equal(expected, actual)
[]
-let ``Minutes_TwoDigits_NoSeconds_WithSeconds_FormatsCorrectly`` () =
+let ``Two-digit minutes with 30 seconds`` () =
let timeSpan = TimeSpan(0, 59, 30)
let actual = timeSpan.ElapsedFriendly()
let expected = "59m30s"
Assert.Equal(expected, actual)
[]
-let ``SingleDigitHour_NoMinutes_NoSeconds_FormatsCorrectly`` () =
+let ``Single-digit hour with no minutes or seconds`` () =
let timeSpan = TimeSpan(7, 0, 0)
let actual = timeSpan.ElapsedFriendly()
let expected = "exactly 7h"
Assert.Equal(expected, actual)
[]
-let ``SingleDigitHour_WithMinutes_NoSeconds_FormatsCorrectly`` () =
+let ``Single-digit hour with single-digit minutes but no seconds`` () =
+ let timeSpan = TimeSpan(7, 7, 0)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "exactly 7h07m"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Single-digit hour with single-digit minutes and single-digit seconds`` () =
+ let timeSpan = TimeSpan(7, 7, 4)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "7h07m04s"
+ Assert.Equal(expected, actual)
+
+let ``Single-digit hour with double-digit minutes but no seconds`` () =
let timeSpan = TimeSpan(7, 20, 0)
let actual = timeSpan.ElapsedFriendly()
let expected = "exactly 7h20m"
Assert.Equal(expected, actual)
[]
-let ``SingleDigitHour_NoMinutes_WithSeconds_FormatsCorrectly`` () =
+let ``Single-digit hour without minutes but with seconds`` () =
let timeSpan = TimeSpan(7, 0, 47)
let actual = timeSpan.ElapsedFriendly()
let expected = "7h47s"
Assert.Equal(expected, actual)
[]
-let ``DoubleDigitHour_NoMinutes_NoSeconds_FormatsCorrectly`` () =
+let ``Double-digit hour with no minutes or seconds`` () =
let timeSpan = TimeSpan(13, 0, 0)
let actual = timeSpan.ElapsedFriendly()
let expected = "exactly 13h"
Assert.Equal(expected, actual)
[]
-let ``SingleDigitHour_SingleDigitMinutes_NoSeconds_FormatsCorrectly`` () =
- let timeSpan = TimeSpan(1, 5, 0)
- let actual = timeSpan.ElapsedFriendly()
- let expected = "exactly 1h05m"
- Assert.Equal(expected, actual)
-
-[]
-let ``SingleDigitHour_DoubleDigitMinutes_NoSeconds_FormatsCorrectly`` () =
- let timeSpan = TimeSpan(1, 55, 0)
+let ``Single-digit hour with single-digit minutes and with seconds`` () =
+ let timeSpan = TimeSpan(1, 3, 8)
let actual = timeSpan.ElapsedFriendly()
- let expected = "exactly 1h55m"
+ let expected = "1h03m08s"
Assert.Equal(expected, actual)
[]
-let ``SingleDigitHour_DoubleDigitMinutes_SingleDigitSeconds_FormatsCorrectly`` () =
+let ``Single-digit hour with double-digit minutes and with seconds`` () =
let timeSpan = TimeSpan(1, 55, 8)
let actual = timeSpan.ElapsedFriendly()
let expected = "1h55m08s"
Assert.Equal(expected, actual)
[]
-let ``DoubleDigitHour_SingleDigitMinutes_SingleDigitSeconds_FormatsCorrectly`` () =
+let ``Double-digit hour with single-digit minutes and with seconds`` () =
let timeSpan = TimeSpan(12, 5, 8)
let actual = timeSpan.ElapsedFriendly()
let expected = "12h05m08s"
Assert.Equal(expected, actual)
[]
-let ``TripleDigitHour_SingleDigitMinutes_SingleDigitSeconds_FormatsCorrectly`` () =
+let ``Double-digit hour over 24 hours with maximum minutes and seconds`` () =
let timeSpan = TimeSpan(36, 59, 59)
let actual = timeSpan.ElapsedFriendly()
let expected = "36h59m59s"
Assert.Equal(expected, actual)
[]
-let ``SingleDigitDay_NoHoursMinutesOrSeconds_FormatsCorrectly`` () =
+let ``Single-digit day with no minutes, hours, or seconds`` () =
let timeSpan = TimeSpan(10, 0, 0, 0)
let actual = timeSpan.ElapsedFriendly()
let expected = "exactly 240h"
Assert.Equal(expected, actual)
[]
-let ``SingleDigitDay_WithHoursMinutesOrSeconds_FormatsCorrectly`` () =
+let ``Single-digit day with no minutes, hours, but with single-digit seconds`` () =
+ let timeSpan = TimeSpan(10, 0, 0, 2)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "240h02s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Single-digit day with no hours, but with single-digit minutes seconds`` () =
+ let timeSpan = TimeSpan(10, 0, 0, 2)
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "240h02s"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Single-digit day with minutes, hours, and seconds`` () =
let timeSpan = TimeSpan(4, 4, 59, 59)
let actual = timeSpan.ElapsedFriendly()
let expected = "100h59m59s"
Assert.Equal(expected, actual)
[]
-let ``TripleDigitDay_WithHoursMinutesOrSeconds_FormatsCorrectly`` () =
+let ``Triple-digit day with minutes, hours, and seconds`` () =
let timeSpan = TimeSpan(100, 23, 59, 59)
let actual = timeSpan.ElapsedFriendly()
let expected = "2,423h59m59s"
From cd8c8635b9ecdd40f3bfa5a8a6e2bdfec67a3132 Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Wed, 25 Dec 2024 12:32:08 +0900
Subject: [PATCH 05/12] Add logic and tests for negative and empty TimeSpans
---
Startwatch.Library/Library.fs | 12 +++++++-----
Startwatch.Tests/Tests.fs | 12 ++++++++++++
2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/Startwatch.Library/Library.fs b/Startwatch.Library/Library.fs
index 3b8ed50..6ce0613 100644
--- a/Startwatch.Library/Library.fs
+++ b/Startwatch.Library/Library.fs
@@ -7,6 +7,8 @@ module Extensions =
type TimeSpan with
member this.ElapsedFriendly() =
match this with
+ | t when t.Ticks < 0 -> raise <| NotSupportedException("Negative TimeSpans are currently not supported.")
+ | t when t.Ticks = 0 -> "no time"
| t when t.TotalMilliseconds < 1 -> sprintf "%s" (t.TotalNanoseconds.ToString("#,##0ns"))
| t when t.TotalMilliseconds < 1000 -> sprintf "%s" (t.TotalMilliseconds.ToString("#,##0ms"))
| t ->
@@ -17,19 +19,19 @@ module Extensions =
let prependText = if secs = 0 then "exactly " else String.Empty
- let hoursText =
+ let hourText =
match (days, hours) with
| d, _ when d > 0 -> sprintf "%s" ((hours + (days * 24)).ToString("#,##0h"))
| _, h when h > 0 -> sprintf "%s" ((hours + (days * 24)).ToString("#,##0h"))
| _ -> String.Empty
- let minsText =
+ let minText =
match (hours, mins) with
| h, m when h > 0 && m > 0 -> sprintf "%s" (m.ToString("00m"))
| _, m when m > 0 -> sprintf "%s" (m.ToString("0m"))
| _ -> String.Empty
- let secsText =
+ let secText =
match (days, hours, mins, secs) with
| d, _, 0, s when d > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
| _, 0, 0, s when s > 0 -> sprintf "%ss" (t.ToString("s\\.ff"))
@@ -38,10 +40,10 @@ module Extensions =
| _, _, _, s when s > 0 -> sprintf "%s" (t.ToString("s"))
| _ -> String.Empty
- $"{prependText}{hoursText}{minsText}{secsText}"
+ $"{prependText}{hourText}{minText}{secText}"
module Startwatch =
type Watch() =
let startedAt = Stopwatch.GetTimestamp()
- member this.ElapsedFriendly = Stopwatch.GetElapsedTime(startedAt)
+ member _.ElapsedFriendly = Stopwatch.GetElapsedTime(startedAt)
diff --git a/Startwatch.Tests/Tests.fs b/Startwatch.Tests/Tests.fs
index e7b3654..a26cf4a 100644
--- a/Startwatch.Tests/Tests.fs
+++ b/Startwatch.Tests/Tests.fs
@@ -4,6 +4,18 @@ open System
open Xunit
open Startwatch.Library.Extensions
+[]
+let ``Throws for negative TimeSpans`` () =
+ let timeSpan = TimeSpan.FromTicks(-7)
+ Assert.Throws(fun _ -> timeSpan.ElapsedFriendly() :> obj)
+
+[]
+let ``Zero timespan`` () =
+ let timeSpan = TimeSpan.Zero // 1 tick == 100 nanoseconds
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "no time"
+ Assert.Equal(expected, actual)
+
[]
let ``Nanoseconds with 3 digits`` () =
let timeSpan = TimeSpan.FromTicks(1) // 1 tick == 100 nanoseconds
From 989be170c5d7eb1a829556886ddfe87ba8f4144f Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Wed, 25 Dec 2024 14:09:35 +0900
Subject: [PATCH 06/12] Relocate Watch class; readd Restart member
---
Startwatch.Library/Library.fs | 10 ++++++----
Startwatch.Library/Startwatch.Library.fsproj | 2 +-
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/Startwatch.Library/Library.fs b/Startwatch.Library/Library.fs
index 6ce0613..1d119f3 100644
--- a/Startwatch.Library/Library.fs
+++ b/Startwatch.Library/Library.fs
@@ -42,8 +42,10 @@ module Extensions =
$"{prependText}{hourText}{minText}{secText}"
-module Startwatch =
- type Watch() =
- let startedAt = Stopwatch.GetTimestamp()
+type Watch() =
+ let mutable startedAt = Stopwatch.GetTimestamp()
- member _.ElapsedFriendly = Stopwatch.GetElapsedTime(startedAt)
+ member _.ElapsedFriendly = Stopwatch.GetElapsedTime(startedAt)
+
+ member _.Restart =
+ startedAt <- Stopwatch.GetTimestamp()
diff --git a/Startwatch.Library/Startwatch.Library.fsproj b/Startwatch.Library/Startwatch.Library.fsproj
index cdba923..c10db64 100644
--- a/Startwatch.Library/Startwatch.Library.fsproj
+++ b/Startwatch.Library/Startwatch.Library.fsproj
@@ -4,7 +4,7 @@
net9.0
true
CodeConscious.Startwatch
- 0.0.5
+ 0.0.6
CodeConscious
CodeConscious
A simple wrapper for System.Diagnostics.Stopwatch.
From 4128ae54654d9b5d6547ace61f70be0d46116f5c Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Wed, 25 Dec 2024 20:29:34 +0900
Subject: [PATCH 07/12] Fix ElapsedFriendly; add TimeSpan.MaxValue test
---
Startwatch.Library/Library.fs | 8 +++++++-
Startwatch.Library/Startwatch.Library.fsproj | 2 +-
Startwatch.Tests/Tests.fs | 7 +++++++
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/Startwatch.Library/Library.fs b/Startwatch.Library/Library.fs
index 1d119f3..05d6266 100644
--- a/Startwatch.Library/Library.fs
+++ b/Startwatch.Library/Library.fs
@@ -42,10 +42,16 @@ module Extensions =
$"{prependText}{hourText}{minText}{secText}"
+open Extensions
+
type Watch() =
+
let mutable startedAt = Stopwatch.GetTimestamp()
- member _.ElapsedFriendly = Stopwatch.GetElapsedTime(startedAt)
+ member _.ElapsedFriendly =
+ Stopwatch
+ .GetElapsedTime(startedAt)
+ .ElapsedFriendly()
member _.Restart =
startedAt <- Stopwatch.GetTimestamp()
diff --git a/Startwatch.Library/Startwatch.Library.fsproj b/Startwatch.Library/Startwatch.Library.fsproj
index c10db64..ea64785 100644
--- a/Startwatch.Library/Startwatch.Library.fsproj
+++ b/Startwatch.Library/Startwatch.Library.fsproj
@@ -4,7 +4,7 @@
net9.0
true
CodeConscious.Startwatch
- 0.0.6
+ 0.0.7-beta
CodeConscious
CodeConscious
A simple wrapper for System.Diagnostics.Stopwatch.
diff --git a/Startwatch.Tests/Tests.fs b/Startwatch.Tests/Tests.fs
index a26cf4a..d9c4edb 100644
--- a/Startwatch.Tests/Tests.fs
+++ b/Startwatch.Tests/Tests.fs
@@ -246,3 +246,10 @@ let ``Triple-digit day with minutes, hours, and seconds`` () =
let actual = timeSpan.ElapsedFriendly()
let expected = "2,423h59m59s"
Assert.Equal(expected, actual)
+
+[]
+let ``Maximum TimeSpan`` () =
+ let timeSpan = TimeSpan.MaxValue
+ let actual = timeSpan.ElapsedFriendly()
+ let expected = "256,204,778h48m05s"
+ Assert.Equal(expected, actual)
From 268d50564e582d9882d52d86f8865440f4aaf8bf Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Wed, 25 Dec 2024 21:43:26 +0900
Subject: [PATCH 08/12] Refactor formatting not to be an extension method
---
Startwatch.Library/Library.fs | 84 +++++++++++++++++------------------
Startwatch.Tests/Tests.fs | 80 ++++++++++++++++-----------------
2 files changed, 80 insertions(+), 84 deletions(-)
diff --git a/Startwatch.Library/Library.fs b/Startwatch.Library/Library.fs
index 05d6266..855cca9 100644
--- a/Startwatch.Library/Library.fs
+++ b/Startwatch.Library/Library.fs
@@ -3,55 +3,51 @@
open System
open System.Diagnostics
-module Extensions =
- type TimeSpan with
- member this.ElapsedFriendly() =
- match this with
- | t when t.Ticks < 0 -> raise <| NotSupportedException("Negative TimeSpans are currently not supported.")
- | t when t.Ticks = 0 -> "no time"
- | t when t.TotalMilliseconds < 1 -> sprintf "%s" (t.TotalNanoseconds.ToString("#,##0ns"))
- | t when t.TotalMilliseconds < 1000 -> sprintf "%s" (t.TotalMilliseconds.ToString("#,##0ms"))
- | t ->
- let days = t.Days
- let hours = t.Hours
- let mins = t.Minutes
- let secs = t.Seconds
-
- let prependText = if secs = 0 then "exactly " else String.Empty
-
- let hourText =
- match (days, hours) with
- | d, _ when d > 0 -> sprintf "%s" ((hours + (days * 24)).ToString("#,##0h"))
- | _, h when h > 0 -> sprintf "%s" ((hours + (days * 24)).ToString("#,##0h"))
- | _ -> String.Empty
-
- let minText =
- match (hours, mins) with
- | h, m when h > 0 && m > 0 -> sprintf "%s" (m.ToString("00m"))
- | _, m when m > 0 -> sprintf "%s" (m.ToString("0m"))
- | _ -> String.Empty
-
- let secText =
- match (days, hours, mins, secs) with
- | d, _, 0, s when d > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
- | _, 0, 0, s when s > 0 -> sprintf "%ss" (t.ToString("s\\.ff"))
- | _, h, _, s when h > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
- | _, _, m, s when m > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
- | _, _, _, s when s > 0 -> sprintf "%s" (t.ToString("s"))
- | _ -> String.Empty
-
- $"{prependText}{hourText}{minText}{secText}"
-
-open Extensions
+module Logic =
+ let format (timespan: TimeSpan) =
+ match timespan with
+ | t when t.Ticks < 0 -> raise <| NotSupportedException("Negative TimeSpans are currently not supported.")
+ | t when t.Ticks = 0 -> "no time"
+ | t when t.TotalMilliseconds < 1 -> sprintf "%s" (t.TotalNanoseconds.ToString("#,##0ns"))
+ | t when t.TotalMilliseconds < 1000 -> sprintf "%s" (t.TotalMilliseconds.ToString("#,##0ms"))
+ | t ->
+ let days = t.Days
+ let hours = t.Hours
+ let mins = t.Minutes
+ let secs = t.Seconds
+
+ let prependText = if secs = 0 then "exactly " else String.Empty
+
+ let hourText =
+ match (days, hours) with
+ | d, _ when d > 0 -> sprintf "%s" ((hours + (days * 24)).ToString("#,##0h"))
+ | _, h when h > 0 -> sprintf "%s" ((hours + (days * 24)).ToString("#,##0h"))
+ | _ -> String.Empty
+
+ let minText =
+ match (hours, mins) with
+ | h, m when h > 0 && m > 0 -> sprintf "%s" (m.ToString("00m"))
+ | _, m when m > 0 -> sprintf "%s" (m.ToString("0m"))
+ | _ -> String.Empty
+
+ let secText =
+ match (days, hours, mins, secs) with
+ | d, _, 0, s when d > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
+ | _, 0, 0, s when s > 0 -> sprintf "%ss" (t.ToString("s\\.ff"))
+ | _, h, _, s when h > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
+ | _, _, m, s when m > 0 && s > 0 -> sprintf "%ss" (t.ToString("ss"))
+ | _, _, _, s when s > 0 -> sprintf "%s" (t.ToString("s"))
+ | _ -> String.Empty
+
+ $"{prependText}{hourText}{minText}{secText}"
+
+open Logic
type Watch() =
-
let mutable startedAt = Stopwatch.GetTimestamp()
member _.ElapsedFriendly =
- Stopwatch
- .GetElapsedTime(startedAt)
- .ElapsedFriendly()
+ format <| Stopwatch.GetElapsedTime(startedAt)
member _.Restart =
startedAt <- Stopwatch.GetTimestamp()
diff --git a/Startwatch.Tests/Tests.fs b/Startwatch.Tests/Tests.fs
index d9c4edb..cd0d2bf 100644
--- a/Startwatch.Tests/Tests.fs
+++ b/Startwatch.Tests/Tests.fs
@@ -2,59 +2,59 @@
open System
open Xunit
-open Startwatch.Library.Extensions
+open Startwatch.Library.Logic
[]
let ``Throws for negative TimeSpans`` () =
let timeSpan = TimeSpan.FromTicks(-7)
- Assert.Throws(fun _ -> timeSpan.ElapsedFriendly() :> obj)
+ Assert.Throws(fun _ -> format timeSpan :> obj)
[]
-let ``Zero timespan`` () =
+let ``Zero timespans`` () =
let timeSpan = TimeSpan.Zero // 1 tick == 100 nanoseconds
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "no time"
Assert.Equal(expected, actual)
[]
-let ``Nanoseconds with 3 digits`` () =
+let ``Three-digit nanoseconds`` () =
let timeSpan = TimeSpan.FromTicks(1) // 1 tick == 100 nanoseconds
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "100ns"
Assert.Equal(expected, actual)
[]
-let ``Nanoseconds with 5 digits`` () =
+let ``Five-digit nanoseconds`` () =
let timeSpan = TimeSpan.FromTicks(100L) // 1 tick == 100 nanoseconds
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "10,000ns"
Assert.Equal(expected, actual)
[]
let ``Single-digit milliseconds`` () =
let timeSpan = TimeSpan.FromMilliseconds(1.0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "1ms"
Assert.Equal(expected, actual)
[]
let ``Double-digit milliseconds`` () =
let timeSpan = TimeSpan.FromMilliseconds(99.0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "99ms"
Assert.Equal(expected, actual)
[]
let ``Double-digit milliseconds with a small decimal`` () =
let timeSpan = TimeSpan.FromMilliseconds(99.2)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "99ms"
Assert.Equal(expected, actual)
[]
let ``Double-digit milliseconds with a large decimal`` () =
let timeSpan = TimeSpan.FromMilliseconds(99.9)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "100ms"
Assert.Equal(expected, actual)
@@ -62,194 +62,194 @@ let ``Double-digit milliseconds with a large decimal`` () =
[]
let ``Triple-digit milliseconds`` () =
let timeSpan = TimeSpan.FromMilliseconds(999.0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "999ms"
Assert.Equal(expected, actual)
[]
let ``Triple-digit milliseconds with a small decimal`` () =
let timeSpan = TimeSpan.FromMilliseconds(999.3)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "999ms"
Assert.Equal(expected, actual)
[]
let ``Triple-digit milliseconds with a large decimal`` () =
let timeSpan = TimeSpan.FromMilliseconds(999.9)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "1,000ms"
Assert.Equal(expected, actual)
[]
let ``Single-digit seconds`` () =
let timeSpan = TimeSpan(0, 0, 3)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "3.00s"
Assert.Equal(expected, actual)
[]
let ``Single-digit seconds with 500 milliseconds`` () =
let timeSpan = TimeSpan(0, 0, 0, 3, 500)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "3.50s"
Assert.Equal(expected, actual)
[]
let ``Single-digit seconds with 520 milliseconds`` () =
let timeSpan = TimeSpan(0, 0, 0, 3, 520)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "3.52s"
Assert.Equal(expected, actual)
[]
let ``Single-digit minute with no seconds`` () =
let timeSpan = TimeSpan(0, 1, 0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "exactly 1m"
Assert.Equal(expected, actual)
[]
let ``Single-digit minute with single-digit seconds`` () =
let timeSpan = TimeSpan(0, 1, 5)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "1m05s"
Assert.Equal(expected, actual)
[]
let ``Single-digit minute with double-digit seconds`` () =
let timeSpan = TimeSpan(0, 1, 30)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "1m30s"
Assert.Equal(expected, actual)
[]
let ``Single-digit minute with maximum seconds`` () =
let timeSpan = TimeSpan(0, 1, 59)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "1m59s"
Assert.Equal(expected, actual)
[]
let ``Two-digit minutes with no seconds`` () =
let timeSpan = TimeSpan(0, 59, 0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "exactly 59m"
Assert.Equal(expected, actual)
[]
let ``Two-digit minutes with 30 seconds`` () =
let timeSpan = TimeSpan(0, 59, 30)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "59m30s"
Assert.Equal(expected, actual)
[]
let ``Single-digit hour with no minutes or seconds`` () =
let timeSpan = TimeSpan(7, 0, 0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "exactly 7h"
Assert.Equal(expected, actual)
[]
let ``Single-digit hour with single-digit minutes but no seconds`` () =
let timeSpan = TimeSpan(7, 7, 0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "exactly 7h07m"
Assert.Equal(expected, actual)
[]
let ``Single-digit hour with single-digit minutes and single-digit seconds`` () =
let timeSpan = TimeSpan(7, 7, 4)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "7h07m04s"
Assert.Equal(expected, actual)
let ``Single-digit hour with double-digit minutes but no seconds`` () =
let timeSpan = TimeSpan(7, 20, 0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "exactly 7h20m"
Assert.Equal(expected, actual)
[]
let ``Single-digit hour without minutes but with seconds`` () =
let timeSpan = TimeSpan(7, 0, 47)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "7h47s"
Assert.Equal(expected, actual)
[]
let ``Double-digit hour with no minutes or seconds`` () =
let timeSpan = TimeSpan(13, 0, 0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "exactly 13h"
Assert.Equal(expected, actual)
[]
let ``Single-digit hour with single-digit minutes and with seconds`` () =
let timeSpan = TimeSpan(1, 3, 8)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "1h03m08s"
Assert.Equal(expected, actual)
[]
let ``Single-digit hour with double-digit minutes and with seconds`` () =
let timeSpan = TimeSpan(1, 55, 8)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "1h55m08s"
Assert.Equal(expected, actual)
[]
let ``Double-digit hour with single-digit minutes and with seconds`` () =
let timeSpan = TimeSpan(12, 5, 8)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "12h05m08s"
Assert.Equal(expected, actual)
[]
let ``Double-digit hour over 24 hours with maximum minutes and seconds`` () =
let timeSpan = TimeSpan(36, 59, 59)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "36h59m59s"
Assert.Equal(expected, actual)
[]
let ``Single-digit day with no minutes, hours, or seconds`` () =
let timeSpan = TimeSpan(10, 0, 0, 0)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "exactly 240h"
Assert.Equal(expected, actual)
[]
let ``Single-digit day with no minutes, hours, but with single-digit seconds`` () =
let timeSpan = TimeSpan(10, 0, 0, 2)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "240h02s"
Assert.Equal(expected, actual)
[]
let ``Single-digit day with no hours, but with single-digit minutes seconds`` () =
let timeSpan = TimeSpan(10, 0, 0, 2)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "240h02s"
Assert.Equal(expected, actual)
[]
let ``Single-digit day with minutes, hours, and seconds`` () =
let timeSpan = TimeSpan(4, 4, 59, 59)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "100h59m59s"
Assert.Equal(expected, actual)
[]
let ``Triple-digit day with minutes, hours, and seconds`` () =
let timeSpan = TimeSpan(100, 23, 59, 59)
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "2,423h59m59s"
Assert.Equal(expected, actual)
[]
let ``Maximum TimeSpan`` () =
let timeSpan = TimeSpan.MaxValue
- let actual = timeSpan.ElapsedFriendly()
+ let actual = format timeSpan
let expected = "256,204,778h48m05s"
Assert.Equal(expected, actual)
From 43efd9309f6f17a3398b5af0ea9421014c689e67 Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Thu, 26 Dec 2024 18:19:04 +0900
Subject: [PATCH 09/12] Update logic and tests for tiny times; add comments
---
Startwatch.Library/Library.fs | 20 ++++++++--
Startwatch.Library/Startwatch.Library.fsproj | 3 +-
Startwatch.Tests/Tests.fs | 41 +++++++++++++++-----
3 files changed, 49 insertions(+), 15 deletions(-)
diff --git a/Startwatch.Library/Library.fs b/Startwatch.Library/Library.fs
index 855cca9..30125e5 100644
--- a/Startwatch.Library/Library.fs
+++ b/Startwatch.Library/Library.fs
@@ -6,10 +6,18 @@ open System.Diagnostics
module Logic =
let format (timespan: TimeSpan) =
match timespan with
- | t when t.Ticks < 0 -> raise <| NotSupportedException("Negative TimeSpans are currently not supported.")
- | t when t.Ticks = 0 -> "no time"
- | t when t.TotalMilliseconds < 1 -> sprintf "%s" (t.TotalNanoseconds.ToString("#,##0ns"))
- | t when t.TotalMilliseconds < 1000 -> sprintf "%s" (t.TotalMilliseconds.ToString("#,##0ms"))
+ | t when t.Ticks < 0 ->
+ raise <| NotSupportedException("Negative TimeSpans are currently not supported.")
+ | t when t.Ticks = 0 ->
+ "no time"
+ | t when t.TotalMilliseconds < 0.01 ->
+ sprintf "%s (%s)"
+ (t.TotalMilliseconds.ToString("#,##0.#####ms"))
+ (t.TotalNanoseconds.ToString("#,##0ns"))
+ | t when t.TotalMilliseconds < 1 ->
+ sprintf "%s" (t.TotalMilliseconds.ToString("#,##0.#####ms"))
+ | t when t.TotalMilliseconds < 1000 ->
+ sprintf "%s" (t.TotalMilliseconds.ToString("#,##0ms"))
| t ->
let days = t.Days
let hours = t.Hours
@@ -43,11 +51,15 @@ module Logic =
open Logic
+/// A simple wrapper for `System.Diagnostic.Stopwatch` class saves its start time
+/// and provides friendly representations of the elapsed time.
type Watch() =
let mutable startedAt = Stopwatch.GetTimestamp()
+ /// Returns a formatted "friendly" version of the elapsed time.
member _.ElapsedFriendly =
format <| Stopwatch.GetElapsedTime(startedAt)
+ /// Sets the start time for this instance to the current time.
member _.Restart =
startedAt <- Stopwatch.GetTimestamp()
diff --git a/Startwatch.Library/Startwatch.Library.fsproj b/Startwatch.Library/Startwatch.Library.fsproj
index ea64785..3043eed 100644
--- a/Startwatch.Library/Startwatch.Library.fsproj
+++ b/Startwatch.Library/Startwatch.Library.fsproj
@@ -4,7 +4,7 @@
net9.0
true
CodeConscious.Startwatch
- 0.0.7-beta
+ 0.0.7-rc
CodeConscious
CodeConscious
A simple wrapper for System.Diagnostics.Stopwatch.
@@ -13,6 +13,7 @@
readme.md
MIT
true
+ true
Startwatch.Library
diff --git a/Startwatch.Tests/Tests.fs b/Startwatch.Tests/Tests.fs
index cd0d2bf..4fcda03 100644
--- a/Startwatch.Tests/Tests.fs
+++ b/Startwatch.Tests/Tests.fs
@@ -6,33 +6,54 @@ open Startwatch.Library.Logic
[]
let ``Throws for negative TimeSpans`` () =
- let timeSpan = TimeSpan.FromTicks(-7)
+ let timeSpan = TimeSpan.FromTicks(-8001)
Assert.Throws(fun _ -> format timeSpan :> obj)
[]
let ``Zero timespans`` () =
- let timeSpan = TimeSpan.Zero // 1 tick == 100 nanoseconds
+ let timeSpan = TimeSpan.Zero
let actual = format timeSpan
let expected = "no time"
Assert.Equal(expected, actual)
[]
-let ``Three-digit nanoseconds`` () =
- let timeSpan = TimeSpan.FromTicks(1) // 1 tick == 100 nanoseconds
+let ``Millisecond ten-thousandths (with nanoseconds)`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(0.0001)
let actual = format timeSpan
- let expected = "100ns"
+ let expected = "0.0001ms (100ns)"
Assert.Equal(expected, actual)
[]
-let ``Five-digit nanoseconds`` () =
- let timeSpan = TimeSpan.FromTicks(100L) // 1 tick == 100 nanoseconds
+let ``Millisecond thousandths (with nanoseconds)`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(0.001)
let actual = format timeSpan
- let expected = "10,000ns"
+ let expected = "0.001ms (1,000ns)"
Assert.Equal(expected, actual)
[]
-let ``Single-digit milliseconds`` () =
- let timeSpan = TimeSpan.FromMilliseconds(1.0)
+let ``Millisecond hundredths`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(0.01)
+ let actual = format timeSpan
+ let expected = "0.01ms"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Millisecond tenths`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(0.1)
+ let actual = format timeSpan
+ let expected = "0.1ms"
+ Assert.Equal(expected, actual)
+
+[]
+let ``Milliseconds with 4 decimals`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(0.9598)
+ let actual = format timeSpan
+ let expected = "0.9598ms"
+ Assert.Equal(expected, actual)
+
+[]
+let ``One millisecond`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(1)
let actual = format timeSpan
let expected = "1ms"
Assert.Equal(expected, actual)
From ed5012b93dc8b98aacac9edfbf79a2d419143fc8 Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Thu, 26 Dec 2024 20:27:30 +0900
Subject: [PATCH 10/12] Update version and readme
---
Startwatch.Library/Startwatch.Library.fsproj | 3 ++-
Startwatch.Library/docs/readme.md | 6 +++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/Startwatch.Library/Startwatch.Library.fsproj b/Startwatch.Library/Startwatch.Library.fsproj
index 3043eed..16ab552 100644
--- a/Startwatch.Library/Startwatch.Library.fsproj
+++ b/Startwatch.Library/Startwatch.Library.fsproj
@@ -4,7 +4,7 @@
net9.0
true
CodeConscious.Startwatch
- 0.0.7-rc
+ 1.0.0-alpha
CodeConscious
CodeConscious
A simple wrapper for System.Diagnostics.Stopwatch.
@@ -14,6 +14,7 @@
MIT
true
true
+ Rewrote in F# and changed the display of very short times.
Startwatch.Library
diff --git a/Startwatch.Library/docs/readme.md b/Startwatch.Library/docs/readme.md
index 8e8b148..035a69c 100644
--- a/Startwatch.Library/docs/readme.md
+++ b/Startwatch.Library/docs/readme.md
@@ -1,7 +1,7 @@
# Startwatch
-This is a very simple wrapper around `System.Diagnostics.Stopwatch`. Since its stopwatch starts automatically, its name is "Startwatch." ^_^
+This is a very simple wrapper around the `System.Diagnostics.Stopwatch` class that just shows "friendly" versions of elapsed times via its `GetElapsedTime` property.
-I largely created this to get some experience uploading a package to Nuget.org, but also to use in some of my personal projects.
+Since it starts tracking time at class instantiation, its name is "Startwatch." ^_^
-Note that the API of this library could change significantly at any moment.
+I largely created this to get some experience uploading packages to Nuget.org, but I also use it in some of my personal projects.
From fcb84f0a81a8cd2a71f788d3fb0fb2b18fff70e4 Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Fri, 27 Dec 2024 12:09:32 +0900
Subject: [PATCH 11/12] Move test up
---
Startwatch.Tests/Tests.fs | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/Startwatch.Tests/Tests.fs b/Startwatch.Tests/Tests.fs
index 4fcda03..dc85600 100644
--- a/Startwatch.Tests/Tests.fs
+++ b/Startwatch.Tests/Tests.fs
@@ -23,6 +23,14 @@ let ``Millisecond ten-thousandths (with nanoseconds)`` () =
let expected = "0.0001ms (100ns)"
Assert.Equal(expected, actual)
+
+[]
+let ``Milliseconds with 4 decimals`` () =
+ let timeSpan = TimeSpan.FromMilliseconds(0.9598)
+ let actual = format timeSpan
+ let expected = "0.9598ms"
+ Assert.Equal(expected, actual)
+
[]
let ``Millisecond thousandths (with nanoseconds)`` () =
let timeSpan = TimeSpan.FromMilliseconds(0.001)
@@ -44,13 +52,6 @@ let ``Millisecond tenths`` () =
let expected = "0.1ms"
Assert.Equal(expected, actual)
-[]
-let ``Milliseconds with 4 decimals`` () =
- let timeSpan = TimeSpan.FromMilliseconds(0.9598)
- let actual = format timeSpan
- let expected = "0.9598ms"
- Assert.Equal(expected, actual)
-
[]
let ``One millisecond`` () =
let timeSpan = TimeSpan.FromMilliseconds(1)
From cad97927d2252c70394b875211f2daf4d90a025d Mon Sep 17 00:00:00 2001
From: CodeConscious <50596087+codeconscious@users.noreply.github.com>
Date: Fri, 27 Dec 2024 12:13:06 +0900
Subject: [PATCH 12/12] Update to v1.0.0; add tags
---
Startwatch.Library/Startwatch.Library.fsproj | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Startwatch.Library/Startwatch.Library.fsproj b/Startwatch.Library/Startwatch.Library.fsproj
index 16ab552..8a2c2de 100644
--- a/Startwatch.Library/Startwatch.Library.fsproj
+++ b/Startwatch.Library/Startwatch.Library.fsproj
@@ -4,7 +4,7 @@
net9.0
true
CodeConscious.Startwatch
- 1.0.0-alpha
+ 1.0.0
CodeConscious
CodeConscious
A simple wrapper for System.Diagnostics.Stopwatch.
@@ -15,6 +15,7 @@
true
true
Rewrote in F# and changed the display of very short times.
+ startwatch stopwatch timer fsharp codeconscious
Startwatch.Library