Add AttractMode deserialization test, fix issues

This commit is contained in:
Matt Nadareski
2023-07-13 13:16:37 -04:00
parent 4153931dfc
commit 11b635e06a
6 changed files with 209 additions and 4 deletions

View File

@@ -0,0 +1,12 @@
namespace SabreTools.Models.AttractMode
{
/// <summary>
/// #Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons /// </summary>
/// </summary>
public class Dat
{
public string[] Header { get; set; }
public Row[]? Row { get; set; }
}
}

View File

@@ -1,10 +1,8 @@
namespace SabreTools.Models.AttractMode
{
/// <summary>
/// #Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons
/// </summary>
public class Row
{
/// <remarks>Also called Romname</remarks>
public string Name { get; set; }
public string Title { get; set; }
@@ -38,5 +36,22 @@ namespace SabreTools.Models.AttractMode
public string Extra { get; set; }
public string Buttons { get; set; }
public string Favorite { get; set; }
public string Tags { get; set; }
public string PlayedCount { get; set; }
public string PlayedTime { get; set; }
public string FileIsAvailable { get; set; }
#region DO NOT USE IN PRODUCTION
/// <remarks>Should be empty</remarks>
public string[] ADDITIONAL_ELEMENTS { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,146 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Readers;
using SabreTools.Models.AttractMode;
namespace SabreTools.Serialization
{
/// <summary>
/// Separated value serializer for AttractMode romlists
/// </summary>
public class AttractMode
{
private const string HeaderWithoutRomname = "#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons";
private const int HeaderWithoutRomnameCount = 17;
private const string HeaderWithRomname = "#Romname;Title;Emulator;Cloneof;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons;Favourite;Tags;PlayedCount;PlayedTime;FileIsAvailable";
private const int HeaderWithRomnameCount = 22;
/// <summary>
/// Deserializes an AttractMode romlist to the defined type
/// </summary>
/// <param name="path">Path to the file to deserialize</param>
/// <returns>Deserialized data on success, null on failure</returns>
public static Dat? Deserialize(string path)
{
try
{
using var stream = PathProcessor.OpenStream(path);
return Deserialize(stream);
}
catch
{
// TODO: Handle logging the exception
return default;
}
}
/// <summary>
/// Deserializes an AttractMode romlist in a stream to the defined type
/// </summary>
/// <param name="stream">Stream to deserialize</param>
/// <returns>Deserialized data on success, null on failure</returns>
public static Dat? Deserialize(Stream? stream)
{
try
{
// If the stream is null
if (stream == null)
return default;
// Setup the reader and output
var reader = new SeparatedValueReader(stream, Encoding.UTF8)
{
Separator = ';',
VerifyFieldCount = false,
};
var dat = new Dat();
// Read the header values first
if (!reader.ReadHeader())
return null;
dat.Header = reader.HeaderValues.ToArray();
// Loop through the rows and parse out values
var rows = new List<Row>();
while (!reader.EndOfStream)
{
// If we have no next line
if (!reader.ReadNextLine())
break;
// Parse the line into a row
Row row = null;
if (reader.Line.Count < HeaderWithRomnameCount)
{
row = new Row
{
Name = reader.Line[0],
Title = reader.Line[1],
Emulator = reader.Line[2],
CloneOf = reader.Line[3],
Year = reader.Line[4],
Manufacturer = reader.Line[5],
Category = reader.Line[6],
Players = reader.Line[7],
Rotation = reader.Line[8],
Control = reader.Line[9],
Status = reader.Line[10],
DisplayCount = reader.Line[11],
DisplayType = reader.Line[12],
AltRomname = reader.Line[13],
AltTitle = reader.Line[14],
Extra = reader.Line[15],
Buttons = reader.Line[16],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithoutRomnameCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithoutRomnameCount).ToArray();
}
else
{
row = new Row
{
Name = reader.Line[0],
Title = reader.Line[1],
Emulator = reader.Line[2],
CloneOf = reader.Line[3],
Year = reader.Line[4],
Manufacturer = reader.Line[5],
Category = reader.Line[6],
Players = reader.Line[7],
Rotation = reader.Line[8],
Control = reader.Line[9],
Status = reader.Line[10],
DisplayCount = reader.Line[11],
DisplayType = reader.Line[12],
AltRomname = reader.Line[13],
AltTitle = reader.Line[14],
Extra = reader.Line[15],
Buttons = reader.Line[16],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithRomnameCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithRomnameCount).ToArray();
}
rows.Add(row);
}
// Assign the rows to the Dat and return
dat.Row = rows.ToArray();
return dat;
}
catch
{
// TODO: Handle logging the exception
return default;
}
}
}
}

View File

@@ -6,6 +6,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\SabreTools.IO\SabreTools.IO.csproj" />
<ProjectReference Include="..\SabreTools.Models\SabreTools.Models.csproj" />
</ItemGroup>

View File

@@ -1,5 +1,4 @@
using System;
using System.Xml.Serialization;
using Xunit;
namespace SabreTools.Test.Parser
@@ -29,6 +28,26 @@ namespace SabreTools.Test.Parser
}
}
[Fact]
public void AttractModeDeserializeTest()
{
// Open the file for reading
string filename = System.IO.Path.Combine(Environment.CurrentDirectory, "TestData", "test-attractmode-files.txt");
// Deserialize the file
var dat = Serialization.AttractMode.Deserialize(filename);
// Validate the values
Assert.NotNull(dat?.Row);
Assert.Equal(11, dat.Row.Length);
// Validate we're not missing any attributes or elements
foreach (var file in dat.Row)
{
Assert.Null(file.ADDITIONAL_ELEMENTS);
}
}
[Fact]
public void ListxmlDeserializeTest()
{

View File

@@ -0,0 +1,12 @@
#Romname;Title;Emulator;Cloneof;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons;Favourite;Tags;PlayedCount;PlayedTime;FileIsAvailable
005;005;advmame;;1981;Sega;Maze / Shooter Small;2P alt;270;joystick (4-way),joystick (4-way);imperfect;1;raster;;;;1;;;0;;1
alpine;Alpine Ski (set 1);advmame;;1982;Taito Corporation;Sports / Skiing;2P alt;270;joystick (2-way),joystick (2-way);good;1;raster;;;;1;;;0;;1
amidar;Amidar;advmame;;1982;Konami;Maze / Outline;2P alt;90;joystick (4-way),joystick (4-way);good;1;raster;;;;1;;;0;;1
anteater;Anteater;advmame;;1982;Tago Electronics;Maze / Collect;2P alt;90;joystick (4-way);good;1;raster;;;;1;;;0;;1
armorcar;Armored Car (set 1);advmame;;1981;Stern Electronics;Maze / Collect;2P alt;90;joystick (4-way),joystick (4-way);good;1;raster;;;;2;;;0;;1
assault;Assault (Rev B);advmame;;1988;Namco;Shooter / Driving;1P;90;double joystick (4-way),double joystick (4-way);good;1;raster;;;;1;;;0;;1
astrob;Astro Blaster (version 3);advmame;;1981;Sega;Shooter / Gallery;2P alt;270;joystick (2-way),joystick (2-way);imperfect;1;raster;;;;2;;;0;;1
astrof;Astro Fighter (set 1);advmame;;1979;Data East;Shooter / Gallery;2P alt;90;joystick (2-way),joystick (2-way);imperfect;1;raster;;;;1;;;0;;1
attckufo;Attack UFO;advmame;;1980;Ryoto Electric Co.;Shooter / Gallery;2P alt;270;joystick (2-way),joystick (2-way);good;1;raster;;;;1;;;0;;1
bagman;Bagman;advmame;;1982;Valadon Automation;Platform / Run Jump;2P alt;270;joystick (4-way),joystick (4-way);good;1;raster;;;;1;;;0;;1
ballbomb;Balloon Bomber;advmame;;1980;Taito;Shooter / Gallery;2P alt;270;joystick (2-way),joystick (2-way);imperfect;1;raster;;;;1;;;0;;1