Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ with the matching package references in the tool, not in the library:
<PackageReference Include="ktsu.Essentials.SerializationProviders.Json" />
```

Only toggles given a `persistAs` key are remembered, and only the tray reads them: a command line run
Only toggles given a `persistAs` key are remembered, and each needs a key of its own: `Toggle` throws
`ArgumentException` for a blank key or one another toggle already uses, since two toggles sharing a key
would both be restored to whichever was clicked last. Only the tray reads them: a command line run
says what it wants, so letting a remembered setting override an argument would be surprising. Within
the tray, what was typed this time beats what the tray was left set to last time.

Expand Down
40 changes: 40 additions & 0 deletions TrayApp.Test/TrayAppBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,46 @@
Assert.AreEqual(1, builder.Build().Options.Count);
}

[TestMethod]
public void Toggle_WithAPersistAsKeyAnotherToggleTook_Throws()
{
// Both toggles would read and write one remembered value, so the next launch restores both to it.
TrayAppBuilder builder = TrayAppBuilder.Create("demo")
.Toggle("Keep awake", () => false, _ => { }, persistAs: "awake");

ArgumentException ex = Assert.ThrowsExactly<ArgumentException>(
() => builder.Toggle("Keep display on", () => false, _ => { }, persistAs: "awake"));

Assert.Contains("'awake'", ex.Message, StringComparison.Ordinal);
Assert.AreEqual("persistAs", ex.ParamName);
Assert.HasCount(1, builder.Build().Toggles);
}

[TestMethod]
public void Toggle_WithPersistAsKeysThatDifferOnlyInCase_KeepsBoth()
{
// The store compares keys ordinally, so these are two remembered values.
TrayAppDefinition app = TrayAppBuilder.Create("demo")
.Toggle("Keep awake", () => false, _ => { }, persistAs: "awake")
.Toggle("Keep display on", () => false, _ => { }, persistAs: "Awake")
.Toggle("Not remembered", () => false, _ => { })
.Toggle("Not remembered either", () => false, _ => { })
.Build();

Assert.HasCount(4, app.Toggles);
}

[TestMethod]
[DataRow("")]
[DataRow(" ")]
public void Toggle_WithABlankPersistAsKey_Throws(string key)
{
ArgumentException ex = Assert.ThrowsExactly<ArgumentException>(
() => TrayAppBuilder.Create("demo").Toggle("Keep awake", () => false, _ => { }, persistAs: key));

Assert.AreEqual("persistAs", ex.ParamName);
}

[TestMethod]
public void Build_CollectsItemsTogglesAndOptions()
{
Expand Down Expand Up @@ -161,7 +201,7 @@
}

[TestMethod]
public void Preferences_WithTheLongestDebounce_IsAcceptedAndATimerTakesIt()

Check warning on line 204 in TrayApp.Test/TrayAppBuilderTests.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Add at least one assertion to this test case.

Check warning on line 204 in TrayApp.Test/TrayAppBuilderTests.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Add at least one assertion to this test case.
{
InMemoryPersistenceProvider<string> provider = new();
TrayAppDefinition app = TrayAppBuilder.Create("demo")
Expand Down
18 changes: 18 additions & 0 deletions TrayApp/TrayAppBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,16 +205,34 @@ public TrayAppBuilder ActiveWhen(Func<bool> predicate)
/// <param name="persistAs">
/// The name to remember this toggle under between runs, or <see langword="null"/> not to remember it.
/// Only meaningful alongside <see cref="Preferences(IPersistenceProvider{string}, string, TimeSpan?)"/>.
/// Each remembered toggle needs a key of its own, compared ordinally: two toggles sharing one would read and
/// write a single remembered value, and the next launch would restore both to it.
/// </param>
/// <returns>The builder, for chaining.</returns>
/// <exception cref="ArgumentNullException"><paramref name="label"/>, <paramref name="getState"/>, or <paramref name="setState"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="persistAs"/> is empty or white space, or another toggle already uses it.
/// </exception>
public TrayAppBuilder Toggle(
string label,
Func<bool> getState,
Action<bool> setState,
Func<bool>? isEnabled = null,
string? persistAs = null)
{
if (persistAs is not null)
{
if (string.IsNullOrWhiteSpace(persistAs))
{
throw new ArgumentException("A preference key cannot be empty or white space.", nameof(persistAs));
}

if (toggles.Any(existing => string.Equals(existing.PreferenceKey, persistAs, StringComparison.Ordinal)))
{
throw new ArgumentException($"'{persistAs}' is already remembered by another toggle.", nameof(persistAs));
}
}

TrayToggleItem toggle = new(label, getState, setState, isEnabled, persistAs);
items.Add(toggle);
toggles.Add(toggle);
Expand Down
Loading