Files
StarterNG/StarterNG.Tests/SceneryExportTests.cs
maj00r 69aa075bfa Keep scenery files intact on save and follow them on disk
Saves keep comments and every byte they do not change. Faults in a scenery's
text are found and described. Files that change while the starter runs are
picked up without a manual reload.
2026-11-01 16:06:15 +01:00

199 lines
6.8 KiB
C#

using StarterNG.Tests.Fakes;
namespace StarterNG.Tests;
public class SceneryExportTests
{
[Fact]
public void An_untouched_scenery_exports_its_trainsets_back_verbatim()
{
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 = TestScenery.Parser().Parse("scenery/x.scn", scn);
string exported = scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom());
Assert.DoesNotContain("{{0}}", exported);
Assert.Contains("trainset pociag tor_1", exported);
Assert.Contains("endtrainset", exported);
}
[Fact]
public void A_consist_emptied_stays_out_of_the_export()
{
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 = TestScenery.Parser().Parse("scenery/x.scn", scn);
scenery.Trainsets[0].RemoveVehicles();
string exported = scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom());
Assert.DoesNotContain("trainset pociag", exported);
Assert.DoesNotContain("ep07-001", exported);
Assert.Contains("FirstInit", exported);
}
[Fact]
public void An_entry_that_could_not_be_read_goes_when_emptied_too()
{
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 = TestScenery.Parser().Parse("scenery/x.scn", scn);
scenery.Trainsets[0].Parsed = false;
scenery.Trainsets[0].RemoveVehicles();
string exported = scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom());
Assert.DoesNotContain("ep07-001", exported);
}
[Fact]
public void Selected_optional_includes_are_written_back_before_FirstInit()
{
const string scn = """
include zima.inc end //$optional 1, Zima
x
endoptional
FirstInit
""";
var scenery = TestScenery.Parser().Parse("scenery/x.scn", scn);
string exported = scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom());
Assert.Contains("include zima.inc end", exported);
Assert.True(exported.IndexOf("include zima.inc", StringComparison.Ordinal) <
exported.IndexOf("FirstInit", StringComparison.Ordinal));
}
[Fact]
public void A_deselected_optional_include_stays_out()
{
const string scn = """
include zima.inc end //$optional 1, Zima
x
endoptional
FirstInit
""";
var scenery = TestScenery.Parser().Parse("scenery/x.scn", scn);
scenery.Includes[0].Selected = false;
string exported = scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom());
Assert.DoesNotContain("include zima.inc", exported);
}
[Fact]
public void A_kind_two_include_is_written_only_without_a_companion_timetable()
{
const string scn = """
include rozklad.inc end //$optional 2, Rozkład
x
endoptional
FirstInit
""";
var scenery = TestScenery.Parser().Parse("scenery/x.scn", scn);
scenery.HasCompanionTimetable = false;
Assert.Contains("include rozklad.inc",
scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom()));
scenery.HasCompanionTimetable = true;
Assert.DoesNotContain("include rozklad.inc",
scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom()));
}
[Fact]
public void Edited_weather_replaces_the_authored_config_block()
{
const string scn = """
config
movelight 100
scenario.weather.temperature 5
eventlauncher.range 200
endconfig
atmo 0 0 0 10 2000 0 0 0 0 endatmo
time 8:30 0 0 endtime
FirstInit
""";
var scenery = TestScenery.Parser().Parse("scenery/x.scn", scn);
scenery.Weather.Day = 200;
scenery.Weather.Temperature = 25;
scenery.Weather.Dirty = true;
string exported = scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom());
Assert.Contains("movelight 200", exported);
Assert.Contains("scenario.weather.temperature 25", exported);
Assert.DoesNotContain("movelight 100", exported);
// Config the scenery author wrote and the starter does not manage survives.
Assert.Contains("eventlauncher.range 200", exported);
}
[Fact]
public void Decor_trainsets_can_be_dropped_from_the_export()
{
const string scn = """
//$n Test
trainset ai_1 tor_1 10 0 //$decor
node -1 -1 ai-1 dynamic PKP/EP07 ep07 ep07.mmd 0 nobody 0
endtrainset
FirstInit
""";
var scenery = TestScenery.Parser().Parse("scenery/x.scn", scn);
Assert.True(scenery.Trainsets[0].Decor);
Assert.DoesNotContain("trainset ai_1",
scenery.BuildExportContent(skipDecorTrainsets: true, new StubRandom()));
Assert.Contains("trainset ai_1",
scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom()));
}
[Fact]
public void Loose_vehicles_are_appended_as_nodes_again()
{
const string scn = """
node -1 -1 wagon_1 dynamic PKP/111A 111a 111a.mmd none 0 nobody 0 enddynamic
FirstInit
""";
var scenery = TestScenery.Parser().Parse("scenery/x.scn", scn);
string exported = scenery.BuildExportContent(skipDecorTrainsets: false, new StubRandom());
Assert.Contains("wagon_1", exported);
Assert.Contains("enddynamic", exported);
}
[Theory]
[InlineData(0, "3 0 enddynamic")]
[InlineData(3, "3 3 pantstate enddynamic")]
public void A_load_type_is_written_only_after_a_count_above_zero(int count, string tail)
{
// After a 0 the simulator would read the type as a destination and take
// the next vehicle with it.
var car = new StarterNG.Classes.Dynamic
{
Name = "en57", DataFolder = "pkp/en57", SkinFile = "s", MmdFile = "m",
LoadType = StarterNG.Classes.Dynamic.PantState, LoadCount = count
};
car.Coupling.Flags = 3;
Assert.EndsWith(tail + "\n", car.ToTrainsetNode());
}
}