changed settings saving (#3)
Reviewed-on: #3 Co-authored-by: Aleksandr Neychev <alexnejchev73@gmail.com>
This commit was merged in pull request #3.
This commit is contained in:
@@ -16,18 +16,115 @@ public sealed class AppSettingsTests
|
||||
Assert.Equal("en", settings.Language);
|
||||
Assert.Equal(AppTheme.System, settings.Theme);
|
||||
Assert.Equal(PopupPlacementMode.AtCursor, settings.PlacementMode);
|
||||
Assert.Equal(AnchorSide.BottomRight, settings.CursorSide);
|
||||
Assert.Equal(16, settings.CursorOffset);
|
||||
Assert.Equal(AnchorSide.BottomRight, settings.CaretSide);
|
||||
Assert.Equal(16, settings.CaretOffset);
|
||||
Assert.Equal(ScreenPosition.BottomRight, settings.ScreenPosition);
|
||||
Assert.Equal(24, settings.ScreenMargin);
|
||||
Assert.Equal(20, settings.FontSize);
|
||||
Assert.Equal(0.9, settings.Opacity);
|
||||
Assert.Equal(500, settings.DurationMilliseconds);
|
||||
Assert.Equal(300, settings.CapsLockHoldMilliseconds);
|
||||
Assert.Equal(Color.FromArgb(0x20, 0x20, 0x20), settings.BackgroundColor);
|
||||
Assert.Equal(Color.FromArgb(0xFF, 0xFF, 0xFF), settings.ForegroundColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Every_mode_starts_out_looking_the_same()
|
||||
{
|
||||
var settings = new AppSettings();
|
||||
|
||||
Assert.Equal(AnchorSide.BottomRight, settings.AtCursor.Side);
|
||||
Assert.Equal(16, settings.AtCursor.Offset);
|
||||
Assert.Equal(CaretSide.Right, settings.AtCaret.Side);
|
||||
Assert.Equal(16, settings.AtCaret.Offset);
|
||||
|
||||
// The middle of the monitor, where there is no edge to stand off from
|
||||
Assert.Equal(ScreenPosition.Center, settings.FixedPoint.Position);
|
||||
Assert.Equal(0, settings.FixedPoint.Offset);
|
||||
|
||||
PopupModeSettings[] modes = [settings.AtCursor, settings.AtCaret, settings.FixedPoint];
|
||||
|
||||
Assert.All(modes, mode =>
|
||||
{
|
||||
Assert.Equal(20, mode.FontSize);
|
||||
Assert.Equal(0.9, mode.Opacity);
|
||||
Assert.Equal(Color.FromArgb(0x20, 0x20, 0x20), mode.BackgroundColor);
|
||||
Assert.Equal(Color.FromArgb(0xFF, 0xFF, 0xFF), mode.ForegroundColor);
|
||||
});
|
||||
|
||||
// Three modes and three sets of settings: none of them is shared
|
||||
Assert.Equal(3, modes.Distinct().Count());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(PopupPlacementMode.AtCursor)]
|
||||
[InlineData(PopupPlacementMode.AtCaret)]
|
||||
[InlineData(PopupPlacementMode.FixedPoint)]
|
||||
public void The_chosen_mode_is_the_one_handed_out(PopupPlacementMode mode)
|
||||
{
|
||||
var settings = new AppSettings { PlacementMode = mode };
|
||||
|
||||
PopupModeSettings expected = mode switch
|
||||
{
|
||||
PopupPlacementMode.AtCaret => settings.AtCaret,
|
||||
PopupPlacementMode.FixedPoint => settings.FixedPoint,
|
||||
_ => settings.AtCursor,
|
||||
};
|
||||
|
||||
Assert.Same(expected, settings.Current);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The settings of a mode are its own: setting one up leaves the others alone.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the whole point of keeping them per mode. A look shared by the modes
|
||||
/// meant setting it up again after every switch, and switching modes to see what
|
||||
/// they do undid what had just been set up.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public void Setting_one_mode_up_leaves_the_others_where_they_were()
|
||||
{
|
||||
var settings = new AppSettings();
|
||||
|
||||
settings.AtCaret.FontSize = 12;
|
||||
settings.AtCaret.Side = CaretSide.Left;
|
||||
settings.AtCaret.BackgroundColor = Color.FromArgb(0x11, 0x22, 0x33);
|
||||
|
||||
Assert.Equal(20, settings.AtCursor.FontSize);
|
||||
Assert.Equal(AnchorSide.BottomRight, settings.AtCursor.Side);
|
||||
Assert.Equal(20, settings.FixedPoint.FontSize);
|
||||
Assert.Equal(Color.FromArgb(0x20, 0x20, 0x20), settings.FixedPoint.BackgroundColor);
|
||||
}
|
||||
|
||||
// The mode in force decides what the look means, so a switch of it is a change of
|
||||
// everything the window shows through the current mode
|
||||
[Fact]
|
||||
public void A_switch_of_the_mode_is_announced_as_a_change_of_the_current_one()
|
||||
{
|
||||
var settings = new AppSettings();
|
||||
List<string?> changed = [];
|
||||
settings.PropertyChanged += (_, e) => changed.Add(e.PropertyName);
|
||||
|
||||
settings.PlacementMode = PopupPlacementMode.FixedPoint;
|
||||
|
||||
Assert.Contains(nameof(AppSettings.PlacementMode), changed);
|
||||
Assert.Contains(nameof(AppSettings.Current), changed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A change inside a mode is passed on as a change of the settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The service that writes the file listens to the settings alone. Without this, a
|
||||
/// font size dragged in the window would never reach the disk.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public void A_change_inside_a_mode_is_announced_by_the_settings()
|
||||
{
|
||||
var settings = new AppSettings();
|
||||
List<string?> changed = [];
|
||||
settings.PropertyChanged += (_, e) => changed.Add(e.PropertyName);
|
||||
|
||||
settings.AtCaret.FontSize = 42;
|
||||
settings.FixedPoint.Position = ScreenPosition.Bottom;
|
||||
settings.AtCursor.Offset = 8;
|
||||
|
||||
Assert.Contains("AtCaret.FontSize", changed);
|
||||
Assert.Contains("FixedPoint.Position", changed);
|
||||
Assert.Contains("AtCursor.Offset", changed);
|
||||
}
|
||||
|
||||
// The app must not change how the system behaves until it is asked to
|
||||
@@ -82,8 +179,60 @@ public sealed class AppSettingsTests
|
||||
Assert.Empty(changed);
|
||||
}
|
||||
|
||||
// Duration and CapsLockHoldDelay are derived from other settings and have
|
||||
// no business being in the file
|
||||
/// <summary>
|
||||
/// Pouring another instance in fills the modes in place rather than replacing them.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the agent's side of the connection: the fresh values arrive as a freshly
|
||||
/// parsed instance. Replacing the mode objects would leave the popup bound to the
|
||||
/// old ones.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public void Taking_other_settings_over_fills_the_modes_that_are_already_there()
|
||||
{
|
||||
var settings = new AppSettings();
|
||||
CursorModeSettings cursor = settings.AtCursor;
|
||||
|
||||
var other = new AppSettings
|
||||
{
|
||||
Language = "ru",
|
||||
Theme = AppTheme.Dark,
|
||||
PlacementMode = PopupPlacementMode.FixedPoint,
|
||||
DurationMilliseconds = 900,
|
||||
UseCapsLockHotkey = true,
|
||||
CapsLockHoldMilliseconds = 450,
|
||||
};
|
||||
|
||||
other.AtCursor.Side = AnchorSide.TopLeft;
|
||||
other.AtCursor.Offset = 5;
|
||||
other.AtCursor.FontSize = 11;
|
||||
other.AtCaret.Side = CaretSide.Left;
|
||||
other.AtCaret.ForegroundColor = Color.FromArgb(0x0A, 0x0B, 0x0C);
|
||||
other.FixedPoint.Position = ScreenPosition.Top;
|
||||
other.FixedPoint.Offset = 64;
|
||||
|
||||
settings.CopyFrom(other);
|
||||
|
||||
Assert.Same(cursor, settings.AtCursor);
|
||||
|
||||
Assert.Equal("ru", settings.Language);
|
||||
Assert.Equal(AppTheme.Dark, settings.Theme);
|
||||
Assert.Equal(PopupPlacementMode.FixedPoint, settings.PlacementMode);
|
||||
Assert.Equal(900, settings.DurationMilliseconds);
|
||||
Assert.True(settings.UseCapsLockHotkey);
|
||||
Assert.Equal(450, settings.CapsLockHoldMilliseconds);
|
||||
|
||||
Assert.Equal(AnchorSide.TopLeft, settings.AtCursor.Side);
|
||||
Assert.Equal(5, settings.AtCursor.Offset);
|
||||
Assert.Equal(11, settings.AtCursor.FontSize);
|
||||
Assert.Equal(CaretSide.Left, settings.AtCaret.Side);
|
||||
Assert.Equal(Color.FromArgb(0x0A, 0x0B, 0x0C), settings.AtCaret.ForegroundColor);
|
||||
Assert.Equal(ScreenPosition.Top, settings.FixedPoint.Position);
|
||||
Assert.Equal(64, settings.FixedPoint.Offset);
|
||||
}
|
||||
|
||||
// Derived values and the modes handed out for convenience are computed from what
|
||||
// is stored and have no business being in the file themselves
|
||||
[Fact]
|
||||
public void Derived_values_stay_out_of_the_file()
|
||||
{
|
||||
@@ -93,10 +242,14 @@ public sealed class AppSettingsTests
|
||||
|
||||
Assert.DoesNotContain(nameof(AppSettings.Duration), names);
|
||||
Assert.DoesNotContain(nameof(AppSettings.CapsLockHoldDelay), names);
|
||||
Assert.DoesNotContain(nameof(AppSettings.Current), names);
|
||||
|
||||
// What they are derived from, on the other hand, has to be stored
|
||||
Assert.Contains(nameof(AppSettings.DurationMilliseconds), names);
|
||||
Assert.Contains(nameof(AppSettings.CapsLockHoldMilliseconds), names);
|
||||
Assert.Contains(nameof(AppSettings.AtCursor), names);
|
||||
Assert.Contains(nameof(AppSettings.AtCaret), names);
|
||||
Assert.Contains(nameof(AppSettings.FixedPoint), names);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -118,6 +271,11 @@ public sealed class AppSettingsTests
|
||||
}
|
||||
|
||||
/// <summary>Names of the settings the user is able to change.</summary>
|
||||
/// <remarks>
|
||||
/// The modes are handed out rather than assigned — they are filled in place — so
|
||||
/// they are not among these. What is inside them is checked by
|
||||
/// <see cref="PopupModeSettingsTests"/>.
|
||||
/// </remarks>
|
||||
internal static IEnumerable<string> WritablePropertyNames() =>
|
||||
typeof(AppSettings).GetProperties()
|
||||
.Where(property => property.CanWrite)
|
||||
|
||||
Reference in New Issue
Block a user