mirror of
https://github.com/MaSzyna-EU07/StarterNG.git
synced 2026-11-06 13:48:34 +01:00
Rework the depot, warehouse and vehicle base
A consist added to the warehouse gets a name there. The crew type stays through loading a consist. The vehicle base window replaces the texture base. The depot follows consists changed on the scenarios page, also with the warehouse tab left open.
This commit is contained in:
149
StarterNG.Tests/CargoTests.cs
Normal file
149
StarterNG.Tests/CargoTests.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using StarterNG.Classes;
|
||||
using StarterNG.Domain;
|
||||
using StarterNG.Domain.Vehicles;
|
||||
using StarterNG.Tests.Fakes;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
public class CargoTests
|
||||
{
|
||||
private readonly Consist _consist;
|
||||
private readonly VehicleCatalog _catalog;
|
||||
private readonly VehicleInfo _info;
|
||||
|
||||
public CargoTests()
|
||||
{
|
||||
var installation = new TestInstallation(new InMemoryFileSystem()
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "en57", "textures.txt"), "!=b\nen57-a.mat=en57,EN57")
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "en57", "en57.fiz"),
|
||||
"Load: LoadAccepted=Passengers,Pantstate MaxLoad=50")
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "tram", "textures.txt"), "!=b\ntram-a.mat=tram,TRAM")
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "tram", "tram.fiz"),
|
||||
"Load: LoadAccepted=pantstate,Passengers MaxLoad=52")
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "s1", "textures.txt"), "!=b\ns1-a.mat=s1,S1")
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "s1", "s1.fiz"), "Load: LoadAccepted=Coal,Sand"));
|
||||
installation.Vehicles.Load(installation.Library.Vehicles);
|
||||
|
||||
_catalog = installation.Library.Vehicles;
|
||||
_info = new VehicleInfo(_catalog, installation.Physics);
|
||||
_consist = new Consist(_catalog, _info);
|
||||
}
|
||||
|
||||
private (Dynamic Car, List<ConsistItem> Consist) Wagon(string skin, string? type = null, int count = 0)
|
||||
{
|
||||
var car = _consist.MakeDynamic(_catalog.TextureForSkin(skin)!, null);
|
||||
car.LoadType = type;
|
||||
car.LoadCount = count;
|
||||
return (car, new List<ConsistItem> { new() { Cars = new List<Dynamic> { car } } });
|
||||
}
|
||||
|
||||
private Cargo Picking(int index) => new(_info, new Pick(index));
|
||||
|
||||
private sealed class Pick : Random
|
||||
{
|
||||
private readonly int _index;
|
||||
|
||||
public Pick(int index) => _index = index;
|
||||
|
||||
public override int Next(int maxValue) => _index;
|
||||
|
||||
public override int Next(int minValue, int maxValue) => maxValue - 1;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_random_type_takes_no_more_than_it_holds()
|
||||
{
|
||||
var (car, consist) = Wagon("en57-a", "Passengers", 50);
|
||||
|
||||
Picking(1).RandomTypes(consist);
|
||||
|
||||
Assert.Equal("Pantstate", car.LoadType);
|
||||
Assert.Equal(Dynamic.PantStateMax, car.LoadCount);
|
||||
Assert.Contains(" 3 Pantstate ", car.ToTrainsetNode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_random_type_leaves_a_count_it_can_hold()
|
||||
{
|
||||
var (car, consist) = Wagon("en57-a", "Pantstate", 2);
|
||||
|
||||
Picking(0).RandomTypes(consist);
|
||||
|
||||
Assert.Equal("Passengers", car.LoadType);
|
||||
Assert.Equal(2, car.LoadCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_random_type_with_no_limit_declared_keeps_the_count()
|
||||
{
|
||||
// MaxLoad unset: nothing to hold it to.
|
||||
var (car, consist) = Wagon("s1-a", "Coal", 40);
|
||||
|
||||
Picking(1).RandomTypes(consist);
|
||||
|
||||
Assert.Equal("Sand", car.LoadType);
|
||||
Assert.Equal(40, car.LoadCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Filling_an_empty_car_goes_by_the_type_it_is_given()
|
||||
{
|
||||
// Its first accepted type is pantographs: the 52 of the .fiz is not theirs.
|
||||
var (car, _) = Wagon("tram-a");
|
||||
|
||||
Picking(0).FillToMax(car);
|
||||
|
||||
Assert.Equal("pantstate", car.LoadType);
|
||||
Assert.Equal(Dynamic.PantStateMax, car.LoadCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_random_amount_for_an_empty_car_goes_by_the_type_it_is_given()
|
||||
{
|
||||
var (car, consist) = Wagon("tram-a");
|
||||
|
||||
Picking(0).RandomAmounts(consist);
|
||||
|
||||
Assert.Equal("pantstate", car.LoadType);
|
||||
Assert.InRange(car.LoadCount, 1, Dynamic.PantStateMax);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_count_passed_on_keeps_where_the_next_car_declares_no_limit()
|
||||
{
|
||||
// MaxLoad unset: nothing to hold it to, as when taken from the car before.
|
||||
var (_, consist) = Wagon("s1-a", "Coal", 40);
|
||||
var (next, following) = Wagon("s1-a");
|
||||
consist.AddRange(following);
|
||||
|
||||
Picking(0).CopyToFollowing(consist, consist[0]);
|
||||
|
||||
Assert.Equal("Coal", next.LoadType);
|
||||
Assert.Equal(40, next.LoadCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_count_passed_on_is_held_to_what_the_next_car_declares()
|
||||
{
|
||||
var (_, consist) = Wagon("tram-a", "Passengers", 52);
|
||||
var (next, following) = Wagon("en57-a");
|
||||
consist.AddRange(following);
|
||||
|
||||
Picking(0).CopyToFollowing(consist, consist[0]);
|
||||
|
||||
Assert.Equal("Passengers", next.LoadType);
|
||||
Assert.Equal(50, next.LoadCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_car_with_nothing_declared_stays_untouched()
|
||||
{
|
||||
var (car, _) = Wagon("en57-a");
|
||||
car.MaxLoad = 0;
|
||||
|
||||
Picking(0).FillToMax(car);
|
||||
|
||||
Assert.Null(car.LoadType);
|
||||
Assert.Equal(0, car.LoadCount);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ public class ConsistCrewTests
|
||||
{
|
||||
private readonly Consist _consist;
|
||||
private readonly VehicleCatalog _catalog;
|
||||
private readonly VehicleInfo _info;
|
||||
|
||||
public ConsistCrewTests()
|
||||
{
|
||||
@@ -20,7 +21,129 @@ public class ConsistCrewTests
|
||||
installation.Vehicles.Load(installation.Library.Vehicles);
|
||||
|
||||
_catalog = installation.Library.Vehicles;
|
||||
_consist = new Consist(_catalog, new VehicleInfo(_catalog, installation.Physics));
|
||||
_info = new VehicleInfo(_catalog, installation.Physics);
|
||||
_consist = new Consist(_catalog, _info);
|
||||
}
|
||||
|
||||
private List<Dynamic> Cars(params string[] skins) =>
|
||||
skins.Select(skin => _consist.MakeDynamic(_catalog.TextureForSkin(skin)!, null)).ToList();
|
||||
|
||||
[Theory]
|
||||
[InlineData(eDriverType.Reardriver)]
|
||||
[InlineData(eDriverType.Passenger)]
|
||||
public void A_loaded_consist_keeps_the_kind_of_crew(eDriverType crew)
|
||||
{
|
||||
var before = Cars("ep07-001", "b111-01");
|
||||
before[0].DriverType = crew;
|
||||
var loaded = Cars("ep07-002", "b111-01");
|
||||
loaded[0].DriverType = eDriverType.Headdriver;
|
||||
|
||||
var cars = Consist.LoadedOver(before, loaded, _catalog, _info);
|
||||
|
||||
Assert.Equal(crew, cars[0].DriverType);
|
||||
Assert.Equal(eDriverType.Nobody, cars[1].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_consist_with_nobody_in_it_stays_so_after_loading()
|
||||
{
|
||||
var loaded = Cars("ep07-002");
|
||||
loaded[0].DriverType = eDriverType.Headdriver;
|
||||
|
||||
var cars = Consist.LoadedOver(Cars("ep07-001"), loaded, _catalog, _info);
|
||||
|
||||
Assert.Equal(eDriverType.Nobody, cars[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_driver_does_not_go_into_loaded_wagons()
|
||||
{
|
||||
var before = Cars("ep07-001");
|
||||
before[0].DriverType = eDriverType.Headdriver;
|
||||
|
||||
var cars = Consist.LoadedOver(before, Cars("b111-01"), _catalog, _info);
|
||||
|
||||
Assert.Equal(eDriverType.Nobody, cars[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Loaded_over_an_empty_consist_the_vehicles_keep_their_own_crew()
|
||||
{
|
||||
var loaded = Cars("ep07-002");
|
||||
loaded[0].DriverType = eDriverType.Reardriver;
|
||||
|
||||
Assert.Equal(eDriverType.Reardriver,
|
||||
Consist.LoadedOver(new List<Dynamic>(), loaded, _catalog, _info)[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Vehicles_joining_a_consist_come_without_their_own_crew()
|
||||
{
|
||||
var before = Cars("ep07-001");
|
||||
before[0].DriverType = eDriverType.Headdriver;
|
||||
var added = Cars("ep07-002");
|
||||
added[0].DriverType = eDriverType.Headdriver;
|
||||
|
||||
var cars = Consist.Joined(before, added);
|
||||
|
||||
Assert.Equal(eDriverType.Headdriver, cars[0].DriverType);
|
||||
Assert.Equal(eDriverType.Nobody, cars[1].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_locomotive_moved_to_the_head_takes_the_driver_in_the_same_cab()
|
||||
{
|
||||
var first = Add("ep07-001", 0);
|
||||
var second = Add("ep07-002", 1);
|
||||
first.Driver = eDriverType.Reardriver;
|
||||
first.Cars[0].DriverType = eDriverType.Reardriver;
|
||||
|
||||
_consist.Move(1, 0);
|
||||
|
||||
Assert.Equal(eDriverType.Reardriver, second.Cars[0].DriverType);
|
||||
Assert.Equal(eDriverType.Nobody, first.Cars[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Vehicles_joining_an_empty_consist_keep_their_crew()
|
||||
{
|
||||
var added = Cars("ep07-002");
|
||||
added[0].DriverType = eDriverType.Headdriver;
|
||||
|
||||
Assert.Equal(eDriverType.Headdriver, Consist.Joined(new List<Dynamic>(), added)[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Selecting_a_wagon_keeps_the_locomotive_as_the_starting_vehicle()
|
||||
{
|
||||
var loco = Add("ep07-001", 0);
|
||||
var wagon = Add("b111-01", 1);
|
||||
loco.Cars[0].Name = "loco";
|
||||
wagon.Cars[0].Name = "wagon";
|
||||
|
||||
Assert.Equal("loco", Consist.StartingVehicle(_consist, wagon, "loco"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_wagon_selected_after_a_stale_pick_falls_back_to_the_driver()
|
||||
{
|
||||
var loco = Add("ep07-001", 0);
|
||||
var wagon = Add("b111-01", 1);
|
||||
loco.Cars[0].Name = "loco";
|
||||
|
||||
Assert.Equal("loco", Consist.StartingVehicle(_consist, wagon, "gone"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Selecting_a_crewed_unit_makes_it_the_starting_vehicle()
|
||||
{
|
||||
var first = Add("ep07-001", 0);
|
||||
var wagon = Add("b111-01", 1);
|
||||
first.Cars[0].Name = "loco";
|
||||
wagon.Cars[0].Name = "wagon";
|
||||
wagon.Cars[0].DriverType = eDriverType.Passenger;
|
||||
|
||||
Assert.Equal("wagon", Consist.StartingVehicle(_consist, wagon, "loco"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
98
StarterNG.Tests/ConsistHistoryTests.cs
Normal file
98
StarterNG.Tests/ConsistHistoryTests.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using StarterNG.Classes;
|
||||
using StarterNG.Domain;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
public class ConsistHistoryTests
|
||||
{
|
||||
private static Dynamic Car(string name) => new()
|
||||
{
|
||||
Name = name, DataFolder = "pkp", SkinFile = name, MmdFile = name, PathName = ""
|
||||
};
|
||||
|
||||
private static Trainset With(params string[] names) =>
|
||||
new("trainset none none 0 0\nendtrainset") { Vehicles = names.Select(Car).ToList() };
|
||||
|
||||
private static string[] Names(IEnumerable<Dynamic> vehicles) => vehicles.Select(v => v.Name).ToArray();
|
||||
|
||||
[Fact]
|
||||
public void A_redraw_without_a_change_leaves_nothing_to_undo()
|
||||
{
|
||||
var history = new ConsistHistory();
|
||||
var trainset = With("a", "b");
|
||||
|
||||
history.Record(trainset, 0);
|
||||
history.Record(trainset, 1);
|
||||
|
||||
Assert.False(history.CanUndo(trainset));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Undo_goes_back_one_change_and_redo_forward_again()
|
||||
{
|
||||
var history = new ConsistHistory();
|
||||
var trainset = With("a");
|
||||
history.Record(trainset, 0);
|
||||
trainset.Vehicles.Add(Car("b"));
|
||||
history.Record(trainset, 1);
|
||||
|
||||
var back = history.Undo(trainset, 1);
|
||||
|
||||
Assert.Equal(new[] { "a" }, Names(back!.Vehicles));
|
||||
Assert.True(history.CanRedo(trainset));
|
||||
|
||||
trainset.Vehicles = back.Vehicles.ToList();
|
||||
history.Record(trainset, 0, rebase: true);
|
||||
var forward = history.Redo(trainset, 0);
|
||||
|
||||
Assert.Equal(new[] { "a", "b" }, Names(forward!.Vehicles));
|
||||
Assert.Equal(1, forward.Selected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void An_edit_made_in_place_is_still_undone()
|
||||
{
|
||||
// The vehicles are shared with the editor, so a change to one of them must
|
||||
// not reach the state kept for undo.
|
||||
var history = new ConsistHistory();
|
||||
var trainset = With("a");
|
||||
history.Record(trainset, 0);
|
||||
|
||||
trainset.Vehicles[0].DriverType = eDriverType.Passenger;
|
||||
var back = history.Undo(trainset, 0);
|
||||
|
||||
Assert.NotEqual(eDriverType.Passenger, back!.Vehicles[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_new_change_drops_what_could_be_redone()
|
||||
{
|
||||
var history = new ConsistHistory();
|
||||
var trainset = With("a");
|
||||
history.Record(trainset, 0);
|
||||
trainset.Vehicles.Add(Car("b"));
|
||||
history.Record(trainset, 1);
|
||||
trainset.Vehicles = history.Undo(trainset, 1)!.Vehicles.ToList();
|
||||
history.Record(trainset, 0, rebase: true);
|
||||
|
||||
trainset.Vehicles.Add(Car("c"));
|
||||
history.Record(trainset, 1);
|
||||
|
||||
Assert.False(history.CanRedo(trainset));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Each_trainset_has_its_own_history()
|
||||
{
|
||||
var history = new ConsistHistory();
|
||||
var first = With("a");
|
||||
var second = With("x");
|
||||
history.Record(first, 0);
|
||||
first.Vehicles.Add(Car("b"));
|
||||
history.Record(first, 1);
|
||||
history.Record(second, 0);
|
||||
|
||||
Assert.True(history.CanUndo(first));
|
||||
Assert.False(history.CanUndo(second));
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using StarterNG.Application;
|
||||
using StarterNG.Classes;
|
||||
using StarterNG.Domain;
|
||||
using StarterNG.Domain.Vehicles;
|
||||
@@ -87,6 +88,25 @@ public class ConsistOrientationTests
|
||||
Assert.All(consist, card => Assert.Equal(Consist.IsTurned(card.Cars[0]), card.Flipped));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_turned_unit_comes_back_as_it_was_from_every_load()
|
||||
{
|
||||
AppServices.Initialize(_installation.Paths, _installation.Files, _installation.Clock, _installation.Environment);
|
||||
var consist = NewConsist(out var unit);
|
||||
consist.Flip(unit);
|
||||
string[] turned = Describe(consist);
|
||||
var trainset = new Trainset("trainset a tor 0 0\nendtrainset");
|
||||
|
||||
for (int load = 0; load < 3; load++)
|
||||
{
|
||||
trainset.Vehicles = consist.Flatten();
|
||||
consist.LoadFrom(trainset);
|
||||
|
||||
Assert.True(Assert.Single(consist).Flipped);
|
||||
Assert.Equal(turned, Describe(consist));
|
||||
}
|
||||
}
|
||||
|
||||
private Consist NewConsist(out ConsistItem unit)
|
||||
{
|
||||
var consist = new Consist(_catalog, new VehicleInfo(_catalog, _installation.Physics));
|
||||
|
||||
@@ -21,6 +21,21 @@ public class ConsistTailTests
|
||||
_consist = new Consist(_catalog, new VehicleInfo(_catalog, installation.Physics));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_unit_can_join_the_one_it_is_held_to_from_either_side()
|
||||
{
|
||||
var first = Append("b111-01");
|
||||
var second = Append("b111-02");
|
||||
|
||||
Assert.False(_consist.CanJoin(first, 0));
|
||||
Assert.False(_consist.CanJoin(second, 1));
|
||||
|
||||
first.Cars[0].Coupling.Set(Coupling.WorkshopLock, true);
|
||||
|
||||
Assert.True(_consist.CanJoin(first, 0));
|
||||
Assert.True(_consist.CanJoin(second, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void The_vehicle_count_counts_cars_not_units()
|
||||
{
|
||||
|
||||
@@ -74,6 +74,70 @@ public class PhysicsAndAssetsTests
|
||||
Assert.NotNull(installation.Physics.For("pkp/ep07/", "ep07"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("pkp/21xm_v1/")]
|
||||
[InlineData("pkp/21xm_v1")]
|
||||
[InlineData("PKP\\21XM_V1")]
|
||||
[InlineData("dynamic/pkp/21xm_v1/")]
|
||||
public void Two_fiz_files_of_one_name_are_told_apart_by_their_folder(string folder)
|
||||
{
|
||||
// As in the game: dynamic/**/21xm_v1/214m.fiz and sa134_v1/214m.fiz.
|
||||
var installation = new TestInstallation(new InMemoryFileSystem()
|
||||
.WithFile(Fiz("pkp", "21xm_v1", "214m"), "Param: M=51000\nDimensions: L=24.38")
|
||||
.WithFile(Fiz("pkp", "sa134_v1", "214m"), "Param: M=48000\nDimensions: L=24.5"));
|
||||
|
||||
var physics = installation.Physics.For(folder, "214m.e3d")!;
|
||||
|
||||
Assert.Equal(51000, physics.Mass);
|
||||
Assert.Equal(24.38, physics.Length);
|
||||
Assert.Equal(48000, installation.Physics.For("pkp/sa134_v1/", "214m")!.Mass);
|
||||
// Asked again, the first answer has not stuck to the name.
|
||||
Assert.Equal(51000, installation.Physics.For(folder, "214m")!.Mass);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_folder_without_the_fiz_falls_back_to_the_name_alone()
|
||||
{
|
||||
var installation = new TestInstallation(new InMemoryFileSystem()
|
||||
.WithFile(Fiz("pkp", "ep07", "ep07"), "Param: M=80000"));
|
||||
|
||||
Assert.Equal(80000, installation.Physics.For("pkp/other/", "ep07")!.Mass);
|
||||
Assert.Equal(80000, installation.Physics.For(null, "ep07")!.Mass);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void The_fallback_to_a_name_two_folders_share_is_the_same_on_every_machine()
|
||||
{
|
||||
var installation = new TestInstallation(new InMemoryFileSystem()
|
||||
.WithFile(Fiz("zz", "b", "214m"), "Param: M=2")
|
||||
.WithFile(Fiz("aa", "a", "214m"), "Param: M=1"));
|
||||
|
||||
Assert.Equal(1, installation.Physics.For("elsewhere/", "214m")!.Mass);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_dumb_variant_in_the_vehicles_own_folder_goes_before_a_namesake_elsewhere()
|
||||
{
|
||||
var installation = new TestInstallation(new InMemoryFileSystem()
|
||||
.WithFile(Fiz("pkp", "ep07", "ep07dumb"), "Param: M=1000")
|
||||
.WithFile(Fiz("pkp", "other", "ep07"), "Param: M=2000"));
|
||||
|
||||
Assert.Equal(1000, installation.Physics.For("pkp/ep07/", "ep07")!.Mass);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Two_folders_sharing_a_name_count_once_among_what_is_indexed()
|
||||
{
|
||||
var installation = new TestInstallation(new InMemoryFileSystem()
|
||||
.WithFile(Fiz("pkp", "a", "214m"), "Param: M=1")
|
||||
.WithFile(Fiz("pkp", "b", "214m"), "Param: M=2")
|
||||
.WithFile(Fiz("pkp", "c", "ep07"), "Param: M=3"));
|
||||
|
||||
installation.Physics.Preload();
|
||||
|
||||
Assert.Equal(2, installation.Physics.IndexedCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void An_unknown_model_has_no_physics_and_an_empty_installation_indexes_nothing()
|
||||
{
|
||||
|
||||
47
StarterNG.Tests/RevisionSpanTests.cs
Normal file
47
StarterNG.Tests/RevisionSpanTests.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using StarterNG.Domain.Vehicles;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
public class RevisionSpanTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("14.01.2005", "2005-01-14", "2005-01-14")]
|
||||
[InlineData("06.12.2016", "2016-12-06", "2016-12-06")]
|
||||
[InlineData("xx.06.2008", "2008-06-01", "2008-06-30")]
|
||||
[InlineData("?.06.2008", "2008-06-01", "2008-06-30")]
|
||||
[InlineData("xx.xx.2011", "2011-01-01", "2011-12-31")]
|
||||
[InlineData("?.?.2011", "2011-01-01", "2011-12-31")]
|
||||
[InlineData("02.2016", "2016-02-01", "2016-02-29")]
|
||||
public void A_credit_line_date_is_as_exact_as_it_says(string text, string from, string to)
|
||||
{
|
||||
var span = RevisionSpan.Parse(text);
|
||||
|
||||
Assert.Equal(DateTime.Parse(from), span?.From);
|
||||
Assert.Equal(DateTime.Parse(to), span?.To);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("2016", "2016-01-01", "2016-12-31")]
|
||||
[InlineData("2016-12", "2016-12-01", "2016-12-31")]
|
||||
[InlineData("2016-12-06", "2016-12-06", "2016-12-06")]
|
||||
[InlineData(" 2016-12- ", "2016-12-01", "2016-12-31")]
|
||||
public void What_is_typed_to_filter_by_reads_the_same_way(string text, string from, string to)
|
||||
{
|
||||
var span = RevisionSpan.Parse(text);
|
||||
|
||||
Assert.Equal(DateTime.Parse(from), span?.From);
|
||||
Assert.Equal(DateTime.Parse(to), span?.To);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData("?")]
|
||||
[InlineData("xx.xx.xxxx")]
|
||||
[InlineData("31.02.2015")]
|
||||
[InlineData("01.13.2015")]
|
||||
[InlineData("VRZ-99_Kolowag_Septemwri")]
|
||||
[InlineData("201")]
|
||||
public void Anything_else_is_no_date(string? text) =>
|
||||
Assert.Null(RevisionSpan.Parse(text));
|
||||
}
|
||||
197
StarterNG.Tests/TexRandomizerTests.cs
Normal file
197
StarterNG.Tests/TexRandomizerTests.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using StarterNG.Classes;
|
||||
using StarterNG.Domain;
|
||||
using StarterNG.Domain.Vehicles;
|
||||
using StarterNG.Tests.Fakes;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
public class TexRandomizerTests
|
||||
{
|
||||
private readonly Consist _consist;
|
||||
private readonly VehicleCatalog _catalog;
|
||||
|
||||
public TexRandomizerTests()
|
||||
{
|
||||
var installation = new TestInstallation(new InMemoryFileSystem()
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "ep07", "textures.txt"),
|
||||
"!=e\nep07-001.mat=ep07,EP07\nep07-002.mat=ep07,EP07")
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "en57", "textures.txt"),
|
||||
"!=z\n^2\nen57-a.mat=en57a,EN57\nen57-b.mat=en57b,EN57\nen57-c.mat=en57a,EN57\nen57-d.mat=en57b,EN57")
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "b111", "textures.txt"),
|
||||
"!=b\nb111-01.mat=b111,B111\nb111-02.mat=b111,B111"));
|
||||
installation.Vehicles.Load(installation.Library.Vehicles);
|
||||
|
||||
_catalog = installation.Library.Vehicles;
|
||||
_consist = new Consist(_catalog, new VehicleInfo(_catalog, installation.Physics));
|
||||
}
|
||||
|
||||
private Dynamic Car(string skin) => _consist.MakeDynamic(_catalog.TextureForSkin(skin)!, null);
|
||||
|
||||
private ConsistItem Put(params Dynamic[] cars)
|
||||
{
|
||||
var item = new ConsistItem
|
||||
{
|
||||
Cars = cars.ToList(),
|
||||
Grouped = cars.Length > 1,
|
||||
Driver = Consist.UnitDriver(cars)
|
||||
};
|
||||
_consist.Insert(_consist.Count, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>The randomizer with the next pick in line always the other livery of two.</summary>
|
||||
private int Randomize() => new TexRandomizer(_catalog, new SecondPick()).Apply(_consist, t => _consist.MakeDynamic(t, null));
|
||||
|
||||
private sealed class SecondPick : Random
|
||||
{
|
||||
public override int Next(int maxValue) => 1;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(eDriverType.Headdriver)]
|
||||
[InlineData(eDriverType.Reardriver)]
|
||||
[InlineData(eDriverType.Passenger)]
|
||||
public void The_crew_stays_on_the_vehicle_that_takes_over(eDriverType crew)
|
||||
{
|
||||
var loco = Car("ep07-001");
|
||||
loco.DriverType = crew;
|
||||
Put(loco);
|
||||
|
||||
Assert.Equal(1, Randomize());
|
||||
|
||||
var car = Assert.Single(_consist[0].Cars);
|
||||
Assert.Equal("ep07-002", car.SkinFile);
|
||||
Assert.Equal(crew, car.DriverType);
|
||||
Assert.Equal(crew, _consist[0].Driver);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_driver_kept_is_what_the_export_writes()
|
||||
{
|
||||
var loco = Car("ep07-001");
|
||||
loco.DriverType = eDriverType.Headdriver;
|
||||
Put(loco);
|
||||
|
||||
Randomize();
|
||||
|
||||
Assert.Contains(" headdriver ", _consist[0].Cars[0].ToTrainsetNode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void An_empty_locomotive_stays_empty()
|
||||
{
|
||||
// Consist.Replace would staff it; a driver of its own is not this one's to give.
|
||||
Put(Car("ep07-001"));
|
||||
|
||||
Randomize();
|
||||
|
||||
Assert.Equal(eDriverType.Nobody, _consist[0].Cars[0].DriverType);
|
||||
Assert.Equal(eDriverType.Nobody, _consist[0].Driver);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_vehicle_keeps_facing_the_way_it_did()
|
||||
{
|
||||
var loco = Car("ep07-001");
|
||||
loco.Offset = -1f;
|
||||
var item = Put(loco);
|
||||
item.Flipped = true;
|
||||
|
||||
Randomize();
|
||||
|
||||
Assert.True(_consist[0].Flipped);
|
||||
Assert.True(Consist.IsTurned(_consist[0].Cars[0]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_vehicle_keeps_its_load()
|
||||
{
|
||||
var wagon = Car("b111-01");
|
||||
wagon.LoadType = "Passengers";
|
||||
wagon.LoadCount = 40;
|
||||
wagon.MaxLoad = 60;
|
||||
Put(wagon);
|
||||
|
||||
Assert.Equal(1, Randomize());
|
||||
|
||||
var car = _consist[0].Cars[0];
|
||||
Assert.Equal("b111-02", car.SkinFile);
|
||||
Assert.Equal("Passengers", car.LoadType);
|
||||
Assert.Equal(40, car.LoadCount);
|
||||
Assert.Equal(60, car.MaxLoad);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_unit_of_the_same_length_keeps_all_of_it_car_by_car()
|
||||
{
|
||||
var first = Car("en57-a");
|
||||
var second = Car("en57-b");
|
||||
second.DriverType = eDriverType.Reardriver;
|
||||
first.LoadType = "Passengers";
|
||||
first.LoadCount = 10;
|
||||
second.LoadType = "Passengers";
|
||||
second.LoadCount = 20;
|
||||
first.Offset = -1f;
|
||||
second.Offset = -1f;
|
||||
var item = Put(first, second);
|
||||
item.Flipped = true;
|
||||
|
||||
Assert.Equal(1, Randomize());
|
||||
|
||||
var unit = _consist[0];
|
||||
Assert.Equal(new[] { "en57-c", "en57-d" }, unit.Cars.Select(c => c.SkinFile));
|
||||
Assert.True(unit.Grouped);
|
||||
Assert.True(unit.Flipped);
|
||||
Assert.Equal(new[] { eDriverType.Nobody, eDriverType.Reardriver }, unit.Cars.Select(c => c.DriverType));
|
||||
Assert.Equal(eDriverType.Reardriver, unit.Driver);
|
||||
Assert.Equal(new[] { 10, 20 }, unit.Cars.Select(c => c.LoadCount));
|
||||
Assert.All(unit.Cars, c => Assert.True(Consist.IsTurned(c)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(eDriverType.Headdriver, 0)]
|
||||
[InlineData(eDriverType.Reardriver, 1)]
|
||||
public void A_crew_moving_into_a_longer_unit_sits_in_the_car_with_its_cab(eDriverType crew, int car)
|
||||
{
|
||||
var loco = Car("en57-c");
|
||||
loco.DriverType = crew;
|
||||
Put(loco);
|
||||
|
||||
Assert.Equal(1, new TexRandomizer(_catalog, new FirstPick()).Apply(_consist, t => _consist.MakeDynamic(t, null)));
|
||||
|
||||
var unit = _consist[0];
|
||||
Assert.Equal(2, unit.Cars.Count);
|
||||
Assert.Equal(crew, unit.Cars[car].DriverType);
|
||||
Assert.Equal(eDriverType.Nobody, unit.Cars[1 - car].DriverType);
|
||||
Assert.Equal(crew, unit.Driver);
|
||||
}
|
||||
|
||||
private sealed class FirstPick : Random
|
||||
{
|
||||
public override int Next(int maxValue) => 0;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_selected_vehicle_stays_selected_as_the_one_that_took_over()
|
||||
{
|
||||
var item = Put(Car("ep07-001"));
|
||||
_consist.Selected = item;
|
||||
|
||||
Randomize();
|
||||
|
||||
Assert.Same(_consist[0], _consist.Selected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_vehicle_not_selected_does_not_take_the_selection()
|
||||
{
|
||||
// ep07-001's turn picks ep07-002; ep07-002's turn picks itself and passes.
|
||||
Put(Car("ep07-001"));
|
||||
var selected = Put(Car("ep07-002"));
|
||||
_consist.Selected = selected;
|
||||
|
||||
Assert.Equal(1, Randomize());
|
||||
|
||||
Assert.Same(selected, _consist.Selected);
|
||||
}
|
||||
}
|
||||
77
StarterNG.Tests/TrainsetDisplayTests.cs
Normal file
77
StarterNG.Tests/TrainsetDisplayTests.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using StarterNG.Classes;
|
||||
using StarterNG.Domain;
|
||||
using StarterNG.Views;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
public class TrainsetDisplayTests
|
||||
{
|
||||
private static Trainset Consist(string driver = "headdriver", string? description = null) =>
|
||||
new(string.Concat(
|
||||
description is null ? "" : $"//$o {description}\n",
|
||||
$"trainset a tor 0 0\nnode -1 0 v1 dynamic d s m 0 {driver} 3 0 enddynamic\nendtrainset"));
|
||||
|
||||
[Theory]
|
||||
[InlineData("-ai", true)]
|
||||
[InlineData(" - ai", true)]
|
||||
[InlineData("a - b", false)]
|
||||
[InlineData("rozkladowy", false)]
|
||||
public void A_dash_opening_the_description_says_the_consist_is_ai(string description, bool ai) =>
|
||||
Assert.Equal(ai, TrainsetDisplay.IsAi(Consist(description: description)));
|
||||
|
||||
[Fact]
|
||||
public void No_description_is_no_ai() =>
|
||||
Assert.False(TrainsetDisplay.IsAi(Consist()));
|
||||
|
||||
[Fact]
|
||||
public void An_ai_consist_is_listed_only_when_they_are_shown()
|
||||
{
|
||||
var ai = Consist(description: "-ai");
|
||||
|
||||
Assert.False(TrainsetDisplay.ListedIn(ai, showAi: false, drivableOnly: false, current: null));
|
||||
Assert.True(TrainsetDisplay.ListedIn(ai, showAi: true, drivableOnly: false, current: null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Drivable_only_leaves_out_a_consist_nobody_sits_in()
|
||||
{
|
||||
var empty = Consist(driver: "nobody");
|
||||
|
||||
Assert.False(TrainsetDisplay.ListedIn(empty, showAi: true, drivableOnly: true, current: null));
|
||||
Assert.True(TrainsetDisplay.ListedIn(empty, showAi: true, drivableOnly: false, current: null));
|
||||
Assert.True(TrainsetDisplay.ListedIn(Consist(), showAi: true, drivableOnly: true, current: null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Drivable_only_keeps_the_one_picked_whatever_its_crew()
|
||||
{
|
||||
var picked = Consist(driver: "nobody");
|
||||
|
||||
Assert.True(TrainsetDisplay.ListedIn(picked, showAi: true, drivableOnly: true, current: picked));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Being_picked_does_not_show_an_ai_consist_the_filter_hides()
|
||||
{
|
||||
var picked = Consist(description: "-ai");
|
||||
|
||||
Assert.False(TrainsetDisplay.ListedIn(picked, showAi: false, drivableOnly: true, current: picked));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(eDriverType.Headdriver, 0)]
|
||||
[InlineData(eDriverType.Reardriver, 1)]
|
||||
[InlineData(eDriverType.Passenger, 2)]
|
||||
[InlineData(eDriverType.Nobody, 3)]
|
||||
public void A_crew_keeps_its_place_in_the_list(eDriverType crew, int place)
|
||||
{
|
||||
Assert.Equal(place, CrewChoices.IndexOf(crew));
|
||||
Assert.Equal(crew, CrewChoices.At(place));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1)]
|
||||
[InlineData(4)]
|
||||
public void A_list_with_nothing_selected_means_nobody(int place) =>
|
||||
Assert.Equal(eDriverType.Nobody, CrewChoices.At(place));
|
||||
}
|
||||
162
StarterNG.Tests/VehicleBaseQueryTests.cs
Normal file
162
StarterNG.Tests/VehicleBaseQueryTests.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using StarterNG.Domain.Vehicles;
|
||||
using StarterNG.Tests.Fakes;
|
||||
using StarterNG.Views;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
public class VehicleBaseQueryTests
|
||||
{
|
||||
private static VehicleBaseRow Row(string skin, string? operatorName = null, string? revision = null,
|
||||
string? author = null, string? depot = null, string? photo = null,
|
||||
string directory = "dynamic/pkp/", string? model = "model")
|
||||
{
|
||||
return new VehicleBaseRow(new VehicleTexture
|
||||
{
|
||||
Directory = directory,
|
||||
Skinfile = skin,
|
||||
Model = model,
|
||||
Meta = new VehicleMeta
|
||||
{
|
||||
Operator = operatorName,
|
||||
RevisionDate = revision,
|
||||
TextureAuthor = author,
|
||||
Depot = depot,
|
||||
PhotoAuthor = photo
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static IReadOnlyList<VehicleTexture> Catalogued(params string[] textures)
|
||||
{
|
||||
var files = new InMemoryFileSystem();
|
||||
foreach (string text in textures)
|
||||
files.WithFile(TestInstallation.At("dynamic", "pkp", text[..text.IndexOf('=')], "textures.txt"),
|
||||
text[(text.IndexOf('=') + 1)..]);
|
||||
var installation = new TestInstallation(files);
|
||||
installation.Vehicles.Load(installation.Library.Vehicles);
|
||||
return installation.Library.Vehicles.Textures;
|
||||
}
|
||||
|
||||
private static string[] Skins(IEnumerable<VehicleBaseRow> rows) => rows.Select(r => r.Skin).ToArray();
|
||||
|
||||
private static string[] Selected(VehicleBaseFilters filters, params VehicleBaseRow[] rows) =>
|
||||
Skins(VehicleBaseQuery.Select(rows, filters, r => r.Skin, descending: false));
|
||||
|
||||
[Fact]
|
||||
public void A_question_mark_in_the_credit_line_is_what_its_author_did_not_know()
|
||||
{
|
||||
var row = Row("a", operatorName: "?", revision: "?", author: "Jan");
|
||||
|
||||
Assert.Equal("", row.Operator);
|
||||
Assert.Equal("", row.Revision);
|
||||
Assert.Null(row.Date);
|
||||
Assert.Equal("", row.DateKey);
|
||||
Assert.Equal("Jan", row.Author);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void The_date_key_sorts_as_the_dates_do() =>
|
||||
Assert.Equal("20081201", Row("a", revision: "xx.12.2008").DateKey);
|
||||
|
||||
[Fact]
|
||||
public void Each_filter_looks_in_its_own_field_ignoring_case_and_spaces_around()
|
||||
{
|
||||
var a = Row("alfa", operatorName: "PKP", author: "Jan", depot: "Lublin", photo: "Ewa", directory: "dynamic/one/");
|
||||
var b = Row("beta", operatorName: "CD", author: "Olaf", depot: "Praha", photo: "Karel", directory: "dynamic/two/");
|
||||
|
||||
Assert.Equal(new[] { "alfa" }, Selected(new VehicleBaseFilters { Name = " ALF " }, a, b));
|
||||
Assert.Equal(new[] { "beta" }, Selected(new VehicleBaseFilters { Operator = "cd" }, a, b));
|
||||
Assert.Equal(new[] { "alfa" }, Selected(new VehicleBaseFilters { Author = "jan" }, a, b));
|
||||
Assert.Equal(new[] { "beta" }, Selected(new VehicleBaseFilters { Station = "prah" }, a, b));
|
||||
Assert.Equal(new[] { "alfa" }, Selected(new VehicleBaseFilters { Photo = "EW" }, a, b));
|
||||
Assert.Equal(new[] { "beta" }, Selected(new VehicleBaseFilters { Model = "TWO/" }, a, b));
|
||||
Assert.Empty(Selected(new VehicleBaseFilters { Name = "alf", Operator = "cd" }, a, b));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
public void A_filter_with_nothing_typed_lets_everything_through(string? typed) =>
|
||||
Assert.Equal(new[] { "a", "b" }, Selected(new VehicleBaseFilters { Name = typed }, Row("a"), Row("b")));
|
||||
|
||||
[Theory]
|
||||
[InlineData("2016", null, true)]
|
||||
[InlineData("2016-12", null, true)]
|
||||
[InlineData("2017", null, false)]
|
||||
[InlineData(null, "2016", true)]
|
||||
[InlineData(null, "2015", false)]
|
||||
[InlineData("2010", "2020", true)]
|
||||
public void A_revision_counts_while_its_span_overlaps_what_is_asked(string? from, string? to, bool shown)
|
||||
{
|
||||
var row = Row("a", revision: "xx.xx.2016");
|
||||
|
||||
var found = Selected(new VehicleBaseFilters { RevisionFrom = from, RevisionTo = to }, row);
|
||||
|
||||
Assert.Equal(shown, found.Length == 1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_month_only_date_overlaps_at_both_of_its_ends()
|
||||
{
|
||||
var row = Row("a", revision: "xx.06.2008");
|
||||
|
||||
Assert.Single(Selected(new VehicleBaseFilters { RevisionFrom = "30.06.2008" }, row));
|
||||
Assert.Single(Selected(new VehicleBaseFilters { RevisionTo = "01.06.2008" }, row));
|
||||
Assert.Empty(Selected(new VehicleBaseFilters { RevisionFrom = "01.07.2008" }, row));
|
||||
Assert.Empty(Selected(new VehicleBaseFilters { RevisionTo = "31.05.2008" }, row));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_revision_asked_for_leaves_out_what_has_no_date_and_what_cannot_be_read_asks_nothing()
|
||||
{
|
||||
var dated = Row("dated", revision: "2016");
|
||||
var undated = Row("undated");
|
||||
|
||||
Assert.Equal(new[] { "dated" }, Selected(new VehicleBaseFilters { RevisionFrom = "2000" }, dated, undated));
|
||||
Assert.Equal(new[] { "dated", "undated" },
|
||||
Selected(new VehicleBaseFilters { RevisionFrom = "soon" }, dated, undated));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, new[] { "b", "c", "a", "d" })]
|
||||
[InlineData(true, new[] { "c", "b", "a", "d" })]
|
||||
public void Blanks_stay_at_the_bottom_whichever_way_a_column_is_sorted_and_the_name_settles_a_tie(
|
||||
bool descending, string[] order)
|
||||
{
|
||||
var rows = new[] { Row("d"), Row("c", operatorName: "Z"), Row("a"), Row("b", operatorName: "M") };
|
||||
|
||||
Assert.Equal(order, Skins(VehicleBaseQuery.Select(rows, new VehicleBaseFilters(), r => r.Operator, descending)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void The_class_list_counts_a_class_under_one_name_whatever_its_case_in_order_of_the_names()
|
||||
{
|
||||
var textures = Catalogued("b111=!=b\nb111-01.mat=b111,B111\nb111-02.mat=b222,b111",
|
||||
"ep07=!=e\nep07-01.mat=ep07,AP07");
|
||||
|
||||
var counts = VehicleBaseQuery.ClassCounts(textures.Select(t => new VehicleBaseRow(t)));
|
||||
|
||||
Assert.Equal(new[] { ("AP07", 1), ("B111", 2) },
|
||||
counts.Select(c => (c.Name.ToUpperInvariant(), c.Count)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_row_with_no_class_is_not_counted() =>
|
||||
Assert.Empty(VehicleBaseQuery.ClassCounts(new[] { Row("a") }));
|
||||
|
||||
[Fact]
|
||||
public void The_class_picked_has_to_match_whole_while_the_typed_one_only_has_to_appear()
|
||||
{
|
||||
var textures = Catalogued("b111=!=b\nb111-01.mat=b111,B111");
|
||||
var row = new VehicleBaseRow(textures[0]);
|
||||
Assert.NotEqual("", row.Class);
|
||||
|
||||
Assert.Single(VehicleBaseQuery.Select(new[] { row }, new VehicleBaseFilters { PickedClass = row.Class.ToUpperInvariant() },
|
||||
r => r.Skin, descending: false));
|
||||
Assert.Empty(VehicleBaseQuery.Select(new[] { row }, new VehicleBaseFilters { PickedClass = row.Class[..1] + "?" },
|
||||
r => r.Skin, descending: false));
|
||||
Assert.Single(VehicleBaseQuery.Select(new[] { row }, new VehicleBaseFilters { Class = row.Class[..1] },
|
||||
r => r.Skin, descending: false));
|
||||
}
|
||||
}
|
||||
139
StarterNG.Tests/WarehouseEditTests.cs
Normal file
139
StarterNG.Tests/WarehouseEditTests.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using StarterNG.Application;
|
||||
using StarterNG.Classes;
|
||||
using StarterNG.Tests.Fakes;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
// PresetStore keeps the disk of the first test that reaches it, a fake one as every
|
||||
// composition root in the tests is built on fakes. So each test has a name to itself.
|
||||
public class WarehouseEditTests
|
||||
{
|
||||
private const string Text =
|
||||
"trainset a tor 0 0\nnode -1 0 v1 dynamic d s m 0 headdriver 3 0 enddynamic\nendtrainset\n";
|
||||
|
||||
private static readonly string Entry = ConsistText.Serialize(new Trainset(Text));
|
||||
|
||||
private readonly WarehouseEdit _edit = new();
|
||||
|
||||
public WarehouseEditTests()
|
||||
{
|
||||
var installation = new TestInstallation(new InMemoryFileSystem());
|
||||
AppServices.Initialize(installation.Paths, installation.Files, installation.Clock, installation.Environment);
|
||||
}
|
||||
|
||||
private static TrainsetPreset Preset(string name, string? entry = null) => new() { Name = name, Entry = entry ?? Entry };
|
||||
|
||||
private static TrainsetPreset? Stored(string name) => PresetStore.All().FirstOrDefault(p => p.Name == name);
|
||||
|
||||
[Fact]
|
||||
public void Opening_says_what_is_edited_and_closing_that_nothing_is()
|
||||
{
|
||||
var trainset = _edit.Open(Preset("edit-open"));
|
||||
|
||||
Assert.Same(trainset, _edit.Trainset);
|
||||
Assert.Equal("edit-open", _edit.Name);
|
||||
|
||||
_edit.Close();
|
||||
|
||||
Assert.Null(_edit.Trainset);
|
||||
Assert.Null(_edit.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_consist_opened_again_is_the_same_trainset_so_its_undo_history_outlives_a_switch()
|
||||
{
|
||||
var first = _edit.Open(Preset("edit-switch"));
|
||||
_edit.Open(Preset("edit-switch-other"));
|
||||
|
||||
Assert.Same(first, _edit.Open(Preset("edit-switch")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void An_entry_written_over_from_elsewhere_is_read_afresh()
|
||||
{
|
||||
var first = _edit.Open(Preset("edit-over"));
|
||||
|
||||
var second = _edit.Open(Preset("edit-over", ConsistText.Serialize(new Trainset(Text.Replace(" v1 ", " v9 ")))));
|
||||
|
||||
Assert.NotSame(first, second);
|
||||
Assert.Equal("v9", second.Vehicles.Single().Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void The_name_of_a_consist_goes_with_any_letter_case()
|
||||
{
|
||||
var first = _edit.Open(Preset("edit-case"));
|
||||
|
||||
Assert.Same(first, _edit.Open(Preset("EDIT-CASE")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Nothing_is_written_while_the_consist_stands_as_it_was_read()
|
||||
{
|
||||
PresetStore.Save("edit-unchanged", Entry);
|
||||
_edit.Open(Stored("edit-unchanged")!);
|
||||
PresetStore.Delete("edit-unchanged");
|
||||
|
||||
_edit.Save();
|
||||
|
||||
Assert.Null(Stored("edit-unchanged"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_change_is_written_once()
|
||||
{
|
||||
PresetStore.Save("edit-changed", Entry);
|
||||
var trainset = _edit.Open(Stored("edit-changed")!);
|
||||
trainset.Vehicles.Add(trainset.Vehicles[0].Clone());
|
||||
|
||||
_edit.Save();
|
||||
|
||||
Assert.Equal(ConsistText.Serialize(trainset), Stored("edit-changed")!.Entry);
|
||||
|
||||
PresetStore.Delete("edit-changed");
|
||||
_edit.Save();
|
||||
|
||||
Assert.Null(Stored("edit-changed"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Nothing_is_written_with_nothing_open()
|
||||
{
|
||||
var trainset = _edit.Open(Preset("edit-closed"));
|
||||
trainset.Vehicles.Add(trainset.Vehicles[0].Clone());
|
||||
_edit.Close();
|
||||
|
||||
_edit.Save();
|
||||
|
||||
Assert.Null(Stored("edit-closed"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_rename_keeps_the_trainset_and_saves_under_the_new_name()
|
||||
{
|
||||
var trainset = _edit.Open(Preset("edit-old"));
|
||||
|
||||
_edit.Renamed("edit-old", "edit-new");
|
||||
|
||||
Assert.Equal("edit-new", _edit.Name);
|
||||
trainset.Vehicles.Add(trainset.Vehicles[0].Clone());
|
||||
_edit.Save();
|
||||
Assert.Null(Stored("edit-old"));
|
||||
Assert.Equal(ConsistText.Serialize(trainset), Stored("edit-new")!.Entry);
|
||||
|
||||
Assert.Same(trainset, _edit.Open(Preset("edit-new", Stored("edit-new")!.Entry)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Renaming_another_consist_leaves_the_one_open_alone()
|
||||
{
|
||||
var other = _edit.Open(Preset("edit-other"));
|
||||
var open = _edit.Open(Preset("edit-mine"));
|
||||
|
||||
_edit.Renamed("edit-other", "edit-other-new");
|
||||
|
||||
Assert.Same(open, _edit.Trainset);
|
||||
Assert.Equal("edit-mine", _edit.Name);
|
||||
Assert.Same(other, _edit.Open(Preset("edit-other-new")));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user