The program stored an operator's window positions but never used them at startup: the entry window was not placed and no window was reopened. It now restores the whole screen both at startup and on a change of operator: the windows that operator had open, where he had them, and the ones he did not have closed. The second radio's entry window no longer saves the layout. It has none of the other windows open, so saving from it dropped every window the first one had. Ctrl+O gets six buttons for the operators last at the radio, newest first. One click changes to that operator. The recordings folder is no longer asked for. It is `Wav/<callsign>` under the data folder, which is where N1MM plays them from, so `StoredOperator.WavPath` is gone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
150 lines
4.3 KiB
C#
150 lines
4.3 KiB
C#
using Nonemm.App.Configuration;
|
|
|
|
namespace Nonemm.App.Tests;
|
|
|
|
public class SettingsTests : IDisposable
|
|
{
|
|
private readonly string path = Path.Combine(Path.GetTempPath(), $"nonemm-{Guid.NewGuid():N}.json");
|
|
|
|
public void Dispose() => File.Delete(path);
|
|
|
|
private Settings Load(string json)
|
|
{
|
|
File.WriteAllText(path, json);
|
|
return Settings.Load(path);
|
|
}
|
|
|
|
[Fact]
|
|
public void AFileWithNullsInItReadsAsTheDefaults()
|
|
{
|
|
Settings settings = Load(
|
|
"""
|
|
{
|
|
"ClusterHost": null,
|
|
"ClusterCommands": null,
|
|
"ClusterNodes": null,
|
|
"TelnetButtons": null,
|
|
"SpotFilter": null,
|
|
"Radios": null,
|
|
"Station": null,
|
|
"CwMessages": null
|
|
}
|
|
""");
|
|
|
|
Assert.Equal("", settings.ClusterHost);
|
|
Assert.Empty(settings.ClusterCommands);
|
|
Assert.Empty(settings.ClusterNodes);
|
|
Assert.Empty(settings.TelnetButtons);
|
|
Assert.Empty(settings.SpotFilter.Bands);
|
|
Assert.Empty(settings.Radios);
|
|
Assert.Equal("", settings.Station.Callsign);
|
|
Assert.Empty(settings.CwMessages);
|
|
}
|
|
|
|
[Fact]
|
|
public void ANullInsideAStoredNodeIsFilledInToo()
|
|
{
|
|
Settings settings = Load(
|
|
"""
|
|
{
|
|
"ClusterNodes": [ { "Name": null, "Host": "dxc.example.net", "Commands": null } ]
|
|
}
|
|
""");
|
|
|
|
StoredClusterNode node = Assert.Single(settings.ClusterNodes);
|
|
Assert.Equal("", node.Name);
|
|
Assert.Empty(node.Commands);
|
|
}
|
|
|
|
[Fact]
|
|
public void WhatTheFileSaysIsKept()
|
|
{
|
|
Settings settings = Load("""{ "ClusterHost": "dxc.example.net", "ClusterPort": 7300 }""");
|
|
|
|
Assert.Equal("dxc.example.net", settings.ClusterHost);
|
|
Assert.Equal(7300, settings.ClusterPort);
|
|
}
|
|
|
|
[Fact]
|
|
public void TheTwelveMessagesAnOlderFileHoldsBecomeAFunctionKeyFile()
|
|
{
|
|
Settings settings = Load(
|
|
"""
|
|
{
|
|
"CwMessages": [ "CQ TEST {MYCALL}", "5NN {EXCH}" ]
|
|
}
|
|
""");
|
|
|
|
Assert.Empty(settings.CwMessages);
|
|
Assert.Equal("F1 CQ,CQ TEST {MYCALL}\nF2 Exch,5NN {EXCH}", settings.CwMessageFile);
|
|
}
|
|
|
|
[Fact]
|
|
public void AFileTextThatIsAlreadyThereIsLeftAlone()
|
|
{
|
|
Settings settings = Load(
|
|
"""
|
|
{
|
|
"CwMessageFile": "F1 CQ,CQ",
|
|
"CwMessages": [ "old" ]
|
|
}
|
|
""");
|
|
|
|
Assert.Equal("F1 CQ,CQ", settings.CwMessageFile);
|
|
}
|
|
|
|
/// An operator's windows and colours survive a trip through the file, and a
|
|
/// file written before operators existed reads as a station with none.
|
|
[Fact]
|
|
public void OperatorsAreStoredAndReadBack()
|
|
{
|
|
Settings settings = new()
|
|
{
|
|
CurrentOperator = "OM3KFF",
|
|
Operators =
|
|
[
|
|
new StoredOperator
|
|
{
|
|
Callsign = "OM3KFF",
|
|
Theme = "dark",
|
|
Windows = [new StoredWindow { Name = "BandmapWindow", X = 10, Y = 20, Width = 300, Height = 400 }],
|
|
},
|
|
],
|
|
};
|
|
settings.Save(path);
|
|
|
|
Settings read = Settings.Load(path);
|
|
|
|
StoredOperator stored = Assert.Single(read.Operators);
|
|
Assert.Equal("OM3KFF", read.CurrentOperator);
|
|
Assert.Equal("dark", stored.Theme);
|
|
StoredWindow window = Assert.Single(stored.Windows);
|
|
Assert.Equal(("BandmapWindow", 10, 20), (window.Name, window.X, window.Y));
|
|
}
|
|
|
|
/// The operator list is kept in the order operators took the radio, so the
|
|
/// dialog's recent buttons read it backwards and stop at the count asked
|
|
/// for.
|
|
[Fact]
|
|
public void RecentOperatorsAreNewestFirst()
|
|
{
|
|
Settings settings = new()
|
|
{
|
|
Operators = [.. new[] { "OM1AB", "OM2CD", "OM3EF", "OM4GH" }
|
|
.Select(call => new StoredOperator { Callsign = call })],
|
|
};
|
|
|
|
Assert.Equal(["OM4GH", "OM3EF", "OM2CD"],
|
|
settings.RecentOperators(3).Select(o => o.Callsign));
|
|
}
|
|
|
|
[Fact]
|
|
public void AFileFromBeforeOperatorsHasNone()
|
|
{
|
|
Settings read = Load("""{ "Theme": "light" }""");
|
|
|
|
Assert.Empty(read.Operators);
|
|
Assert.Equal("", read.CurrentOperator);
|
|
}
|
|
}
|