Files
StarterNG/StarterNG.Tests/SceneryParserTests.cs
maj00r 789f0dd1c9 Make Scenery a domain aggregate with no I/O
Parsing and loading move to Infrastructure/Sceneries. Weather becomes a value
object owning the "does this differ from the file" rule.
2026-09-04 20:53:50 +02:00

155 lines
4.8 KiB
C#

using StarterNG.Infrastructure.Sceneries;
using StarterNG.Tests.Fakes;
namespace StarterNG.Tests;
public class SceneryParserTests
{
private static SceneryParser Parser(DateTime? now = null) =>
new(new FixedClock(now ?? new DateTime(2026, 5, 4, 9, 15, 0)), new StubRandom());
[Fact]
public void Directives_become_the_scenery_headline()
{
const string scn = """
//$l Śląsk
//$n Osobowy do Katowic
//$d Pierwszy opis
//$d drugi wiersz
//$i images/kato.jpg
""";
var scenery = Parser().Parse("scenery/kato.scn", scn);
Assert.Equal("Śląsk", scenery.Group);
Assert.Equal("Osobowy do Katowic", scenery.Name);
Assert.Equal("Pierwszy opis\ndrugi wiersz", scenery.Description);
Assert.Equal("images/kato.jpg", scenery.ImageName);
Assert.False(scenery.Archival);
Assert.Equal("kato", scenery.DisplayName);
}
[Fact]
public void The_a_directive_marks_a_scenery_archival()
{
var scenery = Parser().Parse("scenery/old.scn", "//$a\n//$n Stary\n");
Assert.True(scenery.Archival);
}
[Fact]
public void Attachments_take_a_label_from_the_rest_of_the_line()
{
const string scn = """
//$f 01 doc/rozklad.pdf Rozkład jazdy
//$f doc/mapa.png Mapa
//$f doc/notes.txt
""";
var scenery = Parser().Parse("scenery/x.scn", scn);
Assert.Collection(scenery.Attachments,
first =>
{
Assert.Equal("doc/rozklad.pdf", first.FilePath);
Assert.Equal("Rozkład jazdy", first.Label);
},
second =>
{
Assert.Equal("doc/mapa.png", second.FilePath);
Assert.Equal("Mapa", second.Label);
},
third =>
{
Assert.Equal("doc/notes.txt", third.FilePath);
Assert.Equal("notes.txt", third.Label);
});
}
[Fact]
public void Optional_includes_are_lifted_out_of_the_template()
{
const string scn = """
include zima.inc end //$optional 1, Sceneria zimowa
some content
endoptional
FirstInit
""";
var scenery = Parser().Parse("scenery/x.scn", scn);
var include = Assert.Single(scenery.Includes);
Assert.Equal("zima.inc", include.FilePath);
Assert.Equal("Sceneria zimowa", include.Desc);
Assert.Equal(1, include.Kind);
Assert.True(include.Selected);
Assert.DoesNotContain("zima.inc", scenery.Template);
}
[Fact]
public void Includes_of_kind_two_are_off_until_export_decides()
{
const string scn = """
include rozklad.inc end //$optional 2, Rozkład wbudowany
x
endoptional
""";
var include = Assert.Single(Parser().Parse("scenery/x.scn", scn).Includes);
Assert.Equal(2, include.Kind);
Assert.False(include.Selected);
}
[Fact]
public void Trainsets_are_parsed_and_replaced_by_placeholders()
{
const string scn = """
//$n Test
trainset pociag tor_1 10 0
node -1 -1 ep07-001 dynamic PKP/EP07 ep07 ep07.mmd 0 headdriver 0
endtrainset
FirstInit
""";
var scenery = Parser().Parse("scenery/x.scn", scn);
var trainset = Assert.Single(scenery.Trainsets);
Assert.True(trainset.Parsed);
Assert.Equal("pociag", trainset.Name);
Assert.Equal("tor_1", trainset.Track);
Assert.Contains("{{0}}", scenery.Template);
Assert.DoesNotContain("endtrainset", scenery.Template);
}
[Fact]
public void Vehicles_outside_a_trainset_are_collected_as_loose()
{
const string scn = """
node -1 -1 wagon_1 dynamic PKP/111A 111a 111a.mmd none 0 nobody 0 enddynamic
FirstInit
""";
var scenery = Parser().Parse("scenery/x.scn", scn);
var vehicle = Assert.Single(scenery.LooseVehicles);
Assert.Equal("wagon_1", vehicle.Name);
Assert.Equal("PKP/111A", vehicle.DataFolder);
Assert.Equal(new[] { "wagon_1" }, scenery.LooseVehicleNames);
Assert.DoesNotContain("enddynamic", scenery.Template);
}
[Fact]
public void A_malformed_loose_vehicle_is_reported_and_left_in_place()
{
const string scn = "node x -1 wagon_1 dynamic PKP/111A 111a 111a.mmd none 0 nobody 0 enddynamic\n";
var scenery = Parser().Parse("scenery/x.scn", scn);
Assert.Empty(scenery.LooseVehicles);
Assert.Equal(new[] { "wagon_1" }, scenery.LooseVehicleNames);
Assert.Contains(scenery.Faults, fault => fault.Contains("wagon_1"));
Assert.Contains("enddynamic", scenery.Template);
}
}