diff --git a/SabreTools.Serialization.Test/CrossModel/ArchiveDotOrgTests.cs b/SabreTools.Serialization.Test/CrossModel/ArchiveDotOrgTests.cs
new file mode 100644
index 00000000..9f13f5dc
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/ArchiveDotOrgTests.cs
@@ -0,0 +1,173 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class ArchiveDotOrgTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.ArchiveDotOrg();
+
+ // Build the data
+ Models.ArchiveDotOrg.Files files = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(files);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.ArchiveDotOrg.Files? newFiles = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newFiles);
+ Assert.NotNull(newFiles.File);
+ var newFile = Assert.Single(newFiles.File);
+ Validate(newFile);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.ArchiveDotOrg.Files Build()
+ {
+ var file = new Models.ArchiveDotOrg.File
+ {
+ Name = "XXXXXX",
+ Source = "XXXXXX",
+ BitTorrentMagnetHash = "XXXXXX",
+ LastModifiedTime = "XXXXXX",
+ Size = "XXXXXX",
+ MD5 = "XXXXXX",
+ CRC32 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ FileCount = "XXXXXX",
+ Format = "XXXXXX",
+ Original = "XXXXXX",
+ Summation = "XXXXXX",
+ MatrixNumber = "XXXXXX",
+ CollectionCatalogNumber = "XXXXXX",
+ Publisher = "XXXXXX",
+ Comment = "XXXXXX",
+ ASRDetectedLang = "XXXXXX",
+ ASRDetectedLangConf = "XXXXXX",
+ ASRTranscribedLang = "XXXXXX",
+ WhisperASRModuleVersion = "XXXXXX",
+ WhisperModelHash = "XXXXXX",
+ WhisperModelName = "XXXXXX",
+ WhisperVersion = "XXXXXX",
+ ClothCoverDetectionModuleVersion = "XXXXXX",
+ hOCRCharToWordhOCRVersion = "XXXXXX",
+ hOCRCharToWordModuleVersion = "XXXXXX",
+ hOCRFtsTexthOCRVersion = "XXXXXX",
+ hOCRFtsTextModuleVersion = "XXXXXX",
+ hOCRPageIndexhOCRVersion = "XXXXXX",
+ hOCRPageIndexModuleVersion = "XXXXXX",
+ TesseractOCR = "XXXXXX",
+ TesseractOCRConverted = "XXXXXX",
+ TesseractOCRDetectedLang = "XXXXXX",
+ TesseractOCRDetectedLangConf = "XXXXXX",
+ TesseractOCRDetectedScript = "XXXXXX",
+ TesseractOCRDetectedScriptConf = "XXXXXX",
+ TesseractOCRModuleVersion = "XXXXXX",
+ TesseractOCRParameters = "XXXXXX",
+ PDFModuleVersion = "XXXXXX",
+ WordConfidenceInterval0To10 = "XXXXXX",
+ WordConfidenceInterval11To20 = "XXXXXX",
+ WordConfidenceInterval21To30 = "XXXXXX",
+ WordConfidenceInterval31To40 = "XXXXXX",
+ WordConfidenceInterval41To50 = "XXXXXX",
+ WordConfidenceInterval51To60 = "XXXXXX",
+ WordConfidenceInterval61To70 = "XXXXXX",
+ WordConfidenceInterval71To80 = "XXXXXX",
+ WordConfidenceInterval81To90 = "XXXXXX",
+ WordConfidenceInterval91To100 = "XXXXXX",
+ Album = "XXXXXX",
+ Artist = "XXXXXX",
+ Bitrate = "XXXXXX",
+ Creator = "XXXXXX",
+ Height = "XXXXXX",
+ Length = "XXXXXX",
+ PreviewImage = "XXXXXX",
+ Rotation = "XXXXXX",
+ Title = "XXXXXX",
+ Track = "XXXXXX",
+ Width = "XXXXXX",
+ };
+
+ return new Models.ArchiveDotOrg.Files
+ {
+ File = [file]
+ };
+ }
+
+ ///
+ /// Validate a File
+ ///
+ private static void Validate(Models.ArchiveDotOrg.File? file)
+ {
+ Assert.NotNull(file);
+ Assert.Equal("XXXXXX", file.Name);
+ Assert.Equal("XXXXXX", file.Source);
+ Assert.Equal("XXXXXX", file.BitTorrentMagnetHash);
+ Assert.Equal("XXXXXX", file.LastModifiedTime);
+ Assert.Equal("XXXXXX", file.Size);
+ Assert.Equal("XXXXXX", file.MD5);
+ Assert.Equal("XXXXXX", file.CRC32);
+ Assert.Equal("XXXXXX", file.SHA1);
+ Assert.Equal("XXXXXX", file.FileCount);
+ Assert.Equal("XXXXXX", file.Format);
+ Assert.Equal("XXXXXX", file.Original);
+ Assert.Equal("XXXXXX", file.Summation);
+ Assert.Equal("XXXXXX", file.MatrixNumber);
+ Assert.Equal("XXXXXX", file.CollectionCatalogNumber);
+ Assert.Equal("XXXXXX", file.Publisher);
+ Assert.Equal("XXXXXX", file.Comment);
+ Assert.Equal("XXXXXX", file.ASRDetectedLang);
+ Assert.Equal("XXXXXX", file.ASRDetectedLangConf);
+ Assert.Equal("XXXXXX", file.ASRTranscribedLang);
+ Assert.Equal("XXXXXX", file.WhisperASRModuleVersion);
+ Assert.Equal("XXXXXX", file.WhisperModelHash);
+ Assert.Equal("XXXXXX", file.WhisperModelName);
+ Assert.Equal("XXXXXX", file.WhisperVersion);
+ Assert.Equal("XXXXXX", file.ClothCoverDetectionModuleVersion);
+ Assert.Equal("XXXXXX", file.hOCRCharToWordhOCRVersion);
+ Assert.Equal("XXXXXX", file.hOCRCharToWordModuleVersion);
+ Assert.Equal("XXXXXX", file.hOCRFtsTexthOCRVersion);
+ Assert.Equal("XXXXXX", file.hOCRFtsTextModuleVersion);
+ Assert.Equal("XXXXXX", file.hOCRPageIndexhOCRVersion);
+ Assert.Equal("XXXXXX", file.hOCRPageIndexModuleVersion);
+ Assert.Equal("XXXXXX", file.TesseractOCR);
+ Assert.Equal("XXXXXX", file.TesseractOCRConverted);
+ Assert.Equal("XXXXXX", file.TesseractOCRDetectedLang);
+ Assert.Equal("XXXXXX", file.TesseractOCRDetectedLangConf);
+ Assert.Equal("XXXXXX", file.TesseractOCRDetectedScript);
+ Assert.Equal("XXXXXX", file.TesseractOCRDetectedScriptConf);
+ Assert.Equal("XXXXXX", file.TesseractOCRModuleVersion);
+ Assert.Equal("XXXXXX", file.TesseractOCRParameters);
+ Assert.Equal("XXXXXX", file.PDFModuleVersion);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval0To10);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval11To20);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval21To30);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval31To40);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval41To50);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval51To60);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval61To70);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval71To80);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval81To90);
+ Assert.Equal("XXXXXX", file.WordConfidenceInterval91To100);
+ Assert.Equal("XXXXXX", file.Album);
+ Assert.Equal("XXXXXX", file.Artist);
+ Assert.Equal("XXXXXX", file.Bitrate);
+ Assert.Equal("XXXXXX", file.Creator);
+ Assert.Equal("XXXXXX", file.Height);
+ Assert.Equal("XXXXXX", file.Length);
+ Assert.Equal("XXXXXX", file.PreviewImage);
+ Assert.Equal("XXXXXX", file.Rotation);
+ Assert.Equal("XXXXXX", file.Title);
+ Assert.Equal("XXXXXX", file.Track);
+ Assert.Equal("XXXXXX", file.Width);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/AttractModeTests.cs b/SabreTools.Serialization.Test/CrossModel/AttractModeTests.cs
new file mode 100644
index 00000000..59c13b8f
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/AttractModeTests.cs
@@ -0,0 +1,111 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class AttractModeTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.AttractMode();
+
+ // Build the data
+ Models.AttractMode.MetadataFile mf = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.AttractMode.MetadataFile? newMf = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newMf);
+ Validate(newMf.Header);
+ Assert.NotNull(newMf.Row);
+ var newRow = Assert.Single(newMf.Row);
+ Validate(newRow);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.AttractMode.MetadataFile Build()
+ {
+ string[] header = ["header"];
+
+ var row = new Models.AttractMode.Row
+ {
+ Name = "XXXXXX",
+ Title = "XXXXXX",
+ Emulator = "XXXXXX",
+ CloneOf = "XXXXXX",
+ Year = "XXXXXX",
+ Manufacturer = "XXXXXX",
+ Category = "XXXXXX",
+ Players = "XXXXXX",
+ Rotation = "XXXXXX",
+ Control = "XXXXXX",
+ Status = "XXXXXX",
+ DisplayCount = "XXXXXX",
+ DisplayType = "XXXXXX",
+ AltRomname = "XXXXXX",
+ AltTitle = "XXXXXX",
+ Extra = "XXXXXX",
+ Buttons = "XXXXXX",
+ Favorite = "XXXXXX",
+ Tags = "XXXXXX",
+ PlayedCount = "XXXXXX",
+ PlayedTime = "XXXXXX",
+ FileIsAvailable = "XXXXXX",
+ };
+
+ return new Models.AttractMode.MetadataFile
+ {
+ Header = header,
+ Row = [row],
+ };
+ }
+
+ ///
+ /// Validate a header
+ ///
+ private static void Validate(string[]? header)
+ {
+ Assert.NotNull(header);
+ string column = Assert.Single(header);
+ Assert.Equal("header", column);
+ }
+
+ ///
+ /// Validate a Row
+ ///
+ private static void Validate(Models.AttractMode.Row? row)
+ {
+ Assert.NotNull(row);
+ Assert.Equal("XXXXXX", row.Name);
+ Assert.Equal("XXXXXX", row.Title);
+ Assert.Equal("XXXXXX", row.Emulator);
+ Assert.Equal("XXXXXX", row.CloneOf);
+ Assert.Equal("XXXXXX", row.Year);
+ Assert.Equal("XXXXXX", row.Manufacturer);
+ Assert.Equal("XXXXXX", row.Category);
+ Assert.Equal("XXXXXX", row.Players);
+ Assert.Equal("XXXXXX", row.Rotation);
+ Assert.Equal("XXXXXX", row.Control);
+ Assert.Equal("XXXXXX", row.Status);
+ Assert.Equal("XXXXXX", row.DisplayCount);
+ Assert.Equal("XXXXXX", row.DisplayType);
+ Assert.Equal("XXXXXX", row.AltRomname);
+ Assert.Equal("XXXXXX", row.AltTitle);
+ Assert.Equal("XXXXXX", row.Extra);
+ Assert.Equal("XXXXXX", row.Buttons);
+ Assert.Equal("XXXXXX", row.Favorite);
+ Assert.Equal("XXXXXX", row.Tags);
+ Assert.Equal("XXXXXX", row.PlayedCount);
+ Assert.Equal("XXXXXX", row.PlayedTime);
+ Assert.Equal("XXXXXX", row.FileIsAvailable);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/ClrMameProTests.cs b/SabreTools.Serialization.Test/CrossModel/ClrMameProTests.cs
new file mode 100644
index 00000000..b660e2e0
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/ClrMameProTests.cs
@@ -0,0 +1,492 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class ClrMameProTests
+ {
+ [Fact]
+ public void RoundTripGameTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.ClrMamePro();
+
+ // Build the data
+ Models.ClrMamePro.MetadataFile mf = Build(game: true);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.ClrMamePro.MetadataFile? newMf = serializer.Deserialize(metadata, game: true);
+
+ // Validate the data
+ Assert.NotNull(newMf);
+ Validate(newMf.ClrMamePro);
+ Assert.NotNull(newMf.Game);
+ var newGame = Assert.Single(newMf.Game);
+ Validate(newGame);
+ }
+
+ [Fact]
+ public void RoundTripMachineTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.ClrMamePro();
+
+ // Build the data
+ Models.ClrMamePro.MetadataFile mf = Build(game: false);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.ClrMamePro.MetadataFile? newMf = serializer.Deserialize(metadata, game: false);
+
+ // Validate the data
+ Assert.NotNull(newMf);
+ Validate(newMf.ClrMamePro);
+ Assert.NotNull(newMf.Game);
+ var newGame = Assert.Single(newMf.Game);
+ Validate(newGame);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.ClrMamePro.MetadataFile Build(bool game)
+ {
+ var cmp = new Models.ClrMamePro.ClrMamePro
+ {
+ Name = "XXXXXX",
+ Description = "XXXXXX",
+ RootDir = "XXXXXX",
+ Category = "XXXXXX",
+ Version = "XXXXXX",
+ Date = "XXXXXX",
+ Author = "XXXXXX",
+ Homepage = "XXXXXX",
+ Url = "XXXXXX",
+ Comment = "XXXXXX",
+ Header = "XXXXXX",
+ Type = "XXXXXX",
+ ForceMerging = "XXXXXX",
+ ForceZipping = "XXXXXX",
+ ForcePacking = "XXXXXX",
+ };
+
+ var release = new Models.ClrMamePro.Release
+ {
+ Name = "XXXXXX",
+ Region = "XXXXXX",
+ Language = "XXXXXX",
+ Date = "XXXXXX",
+ Default = "XXXXXX",
+ };
+
+ var biosset = new Models.ClrMamePro.BiosSet
+ {
+ Name = "XXXXXX",
+ Description = "XXXXXX",
+ Default = "XXXXXX",
+ };
+
+ var rom = new Models.ClrMamePro.Rom
+ {
+ Name = "XXXXXX",
+ Size = "XXXXXX",
+ CRC = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Merge = "XXXXXX",
+ Status = "XXXXXX",
+ Flags = "XXXXXX",
+ Date = "XXXXXX",
+ SHA256 = "XXXXXX",
+ SHA384 = "XXXXXX",
+ SHA512 = "XXXXXX",
+ SpamSum = "XXXXXX",
+ xxHash364 = "XXXXXX",
+ xxHash3128 = "XXXXXX",
+ Region = "XXXXXX",
+ Offs = "XXXXXX",
+ Serial = "XXXXXX",
+ Header = "XXXXXX",
+ Inverted = "XXXXXX",
+ MIA = "XXXXXX",
+ };
+
+ var disk = new Models.ClrMamePro.Disk
+ {
+ Name = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Merge = "XXXXXX",
+ Status = "XXXXXX",
+ Flags = "XXXXXX",
+ };
+
+ var sample = new Models.ClrMamePro.Sample
+ {
+ Name = "XXXXXX",
+ };
+
+ var archive = new Models.ClrMamePro.Archive
+ {
+ Name = "XXXXXX",
+ };
+
+ var media = new Models.ClrMamePro.Media
+ {
+ Name = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ SHA256 = "XXXXXX",
+ SpamSum = "XXXXXX",
+ };
+
+ var chip = new Models.ClrMamePro.Chip
+ {
+ Type = "XXXXXX",
+ Name = "XXXXXX",
+ Flags = "XXXXXX",
+ Clock = "XXXXXX",
+ };
+
+ var video = new Models.ClrMamePro.Video
+ {
+ Screen = "XXXXXX",
+ Orientation = "XXXXXX",
+ X = "XXXXXX",
+ Y = "XXXXXX",
+ AspectX = "XXXXXX",
+ AspectY = "XXXXXX",
+ Freq = "XXXXXX",
+ };
+
+ var sound = new Models.ClrMamePro.Sound
+ {
+ Channels = "XXXXXX",
+ };
+
+ var input = new Models.ClrMamePro.Input
+ {
+ Players = "XXXXXX",
+ Control = "XXXXXX",
+ Buttons = "XXXXXX",
+ Coins = "XXXXXX",
+ Tilt = "XXXXXX",
+ Service = "XXXXXX",
+ };
+
+ var dipswitch = new Models.ClrMamePro.DipSwitch
+ {
+ Name = "XXXXXX",
+ Entry = ["XXXXXX"],
+ Default = "XXXXXX",
+ };
+
+ var driver = new Models.ClrMamePro.Driver
+ {
+ Status = "XXXXXX",
+ Color = "XXXXXX",
+ Sound = "XXXXXX",
+ PaletteSize = "XXXXXX",
+ Blit = "XXXXXX",
+ };
+
+ // TODO: This omits Set, should that have a separate case?
+ Models.ClrMamePro.GameBase gameBase = game
+ ? new Models.ClrMamePro.Game()
+ : new Models.ClrMamePro.Machine();
+ gameBase.Name = "XXXXXX";
+ gameBase.Description = "XXXXXX";
+ gameBase.Year = "XXXXXX";
+ gameBase.Manufacturer = "XXXXXX";
+ gameBase.Category = "XXXXXX";
+ gameBase.CloneOf = "XXXXXX";
+ gameBase.RomOf = "XXXXXX";
+ gameBase.SampleOf = "XXXXXX";
+ gameBase.Release = [release];
+ gameBase.BiosSet = [biosset];
+ gameBase.Rom = [rom];
+ gameBase.Disk = [disk];
+ gameBase.Sample = [sample];
+ gameBase.Archive = [archive];
+ gameBase.Media = [media];
+ gameBase.Chip = [chip];
+ gameBase.Video = [video];
+ gameBase.Sound = sound;
+ gameBase.Input = input;
+ gameBase.DipSwitch = [dipswitch];
+ gameBase.Driver = driver;
+
+ return new Models.ClrMamePro.MetadataFile
+ {
+ ClrMamePro = cmp,
+ Game = [gameBase],
+ };
+ }
+
+ ///
+ /// Validate a ClrMamePro
+ ///
+ private static void Validate(Models.ClrMamePro.ClrMamePro? cmp)
+ {
+ Assert.NotNull(cmp);
+ Assert.Equal("XXXXXX", cmp.Name);
+ Assert.Equal("XXXXXX", cmp.Description);
+ Assert.Equal("XXXXXX", cmp.RootDir);
+ Assert.Equal("XXXXXX", cmp.Category);
+ Assert.Equal("XXXXXX", cmp.Version);
+ Assert.Equal("XXXXXX", cmp.Date);
+ Assert.Equal("XXXXXX", cmp.Author);
+ Assert.Equal("XXXXXX", cmp.Homepage);
+ Assert.Equal("XXXXXX", cmp.Url);
+ Assert.Equal("XXXXXX", cmp.Comment);
+ Assert.Equal("XXXXXX", cmp.Header);
+ Assert.Equal("XXXXXX", cmp.Type);
+ Assert.Equal("XXXXXX", cmp.ForceMerging);
+ Assert.Equal("XXXXXX", cmp.ForceZipping);
+ Assert.Equal("XXXXXX", cmp.ForcePacking);
+ }
+
+ ///
+ /// Validate a GameBase
+ ///
+ private static void Validate(Models.ClrMamePro.GameBase? gb)
+ {
+ Assert.NotNull(gb);
+ Assert.Equal("XXXXXX", gb.Name);
+ Assert.Equal("XXXXXX", gb.Description);
+ Assert.Equal("XXXXXX", gb.Year);
+ Assert.Equal("XXXXXX", gb.Manufacturer);
+ Assert.Equal("XXXXXX", gb.Category);
+ Assert.Equal("XXXXXX", gb.CloneOf);
+ Assert.Equal("XXXXXX", gb.RomOf);
+ Assert.Equal("XXXXXX", gb.SampleOf);
+
+ Assert.NotNull(gb.Release);
+ var release = Assert.Single(gb.Release);
+ Validate(release);
+
+ Assert.NotNull(gb.BiosSet);
+ var biosset = Assert.Single(gb.BiosSet);
+ Validate(biosset);
+
+ Assert.NotNull(gb.Rom);
+ var rom = Assert.Single(gb.Rom);
+ Validate(rom);
+
+ Assert.NotNull(gb.Disk);
+ var disk = Assert.Single(gb.Disk);
+ Validate(disk);
+
+ Assert.NotNull(gb.Sample);
+ var sample = Assert.Single(gb.Sample);
+ Validate(sample);
+
+ Assert.NotNull(gb.Archive);
+ var archive = Assert.Single(gb.Archive);
+ Validate(archive);
+
+ Assert.NotNull(gb.Media);
+ var media = Assert.Single(gb.Media);
+ Validate(media);
+
+ Assert.NotNull(gb.Chip);
+ var chip = Assert.Single(gb.Chip);
+ Validate(chip);
+
+ Assert.NotNull(gb.Video);
+ var video = Assert.Single(gb.Video);
+ Validate(video);
+
+ Validate(gb.Sound);
+ Validate(gb.Input);
+
+ Assert.NotNull(gb.DipSwitch);
+ var dipswitch = Assert.Single(gb.DipSwitch);
+ Validate(dipswitch);
+
+ Validate(gb.Driver);
+ }
+
+ ///
+ /// Validate a Release
+ ///
+ private static void Validate(Models.ClrMamePro.Release? release)
+ {
+ Assert.NotNull(release);
+ Assert.Equal("XXXXXX", release.Name);
+ Assert.Equal("XXXXXX", release.Region);
+ Assert.Equal("XXXXXX", release.Language);
+ Assert.Equal("XXXXXX", release.Date);
+ Assert.Equal("XXXXXX", release.Default);
+ }
+
+ ///
+ /// Validate a BiosSet
+ ///
+ private static void Validate(Models.ClrMamePro.BiosSet? biosset)
+ {
+ Assert.NotNull(biosset);
+ Assert.Equal("XXXXXX", biosset.Name);
+ Assert.Equal("XXXXXX", biosset.Description);
+ Assert.Equal("XXXXXX", biosset.Default);
+ }
+
+ ///
+ /// Validate a Rom
+ ///
+ private static void Validate(Models.ClrMamePro.Rom? rom)
+ {
+ Assert.NotNull(rom);
+ Assert.Equal("XXXXXX", rom.Name);
+ Assert.Equal("XXXXXX", rom.Size);
+ Assert.Equal("XXXXXX", rom.CRC);
+ Assert.Equal("XXXXXX", rom.MD5);
+ Assert.Equal("XXXXXX", rom.SHA1);
+ Assert.Equal("XXXXXX", rom.Merge);
+ Assert.Equal("XXXXXX", rom.Status);
+ Assert.Equal("XXXXXX", rom.Flags);
+ Assert.Equal("XXXXXX", rom.Date);
+ Assert.Equal("XXXXXX", rom.SHA256);
+ Assert.Equal("XXXXXX", rom.SHA384);
+ Assert.Equal("XXXXXX", rom.SHA512);
+ Assert.Equal("XXXXXX", rom.SpamSum);
+ Assert.Equal("XXXXXX", rom.xxHash364);
+ Assert.Equal("XXXXXX", rom.xxHash3128);
+ Assert.Equal("XXXXXX", rom.Region);
+ Assert.Equal("XXXXXX", rom.Offs);
+ Assert.Equal("XXXXXX", rom.Serial);
+ Assert.Equal("XXXXXX", rom.Header);
+ Assert.Equal("XXXXXX", rom.Inverted);
+ Assert.Equal("XXXXXX", rom.MIA);
+ }
+
+ ///
+ /// Validate a Disk
+ ///
+ private static void Validate(Models.ClrMamePro.Disk? disk)
+ {
+ Assert.NotNull(disk);
+ Assert.Equal("XXXXXX", disk.Name);
+ Assert.Equal("XXXXXX", disk.MD5);
+ Assert.Equal("XXXXXX", disk.SHA1);
+ Assert.Equal("XXXXXX", disk.Merge);
+ Assert.Equal("XXXXXX", disk.Status);
+ Assert.Equal("XXXXXX", disk.Flags);
+ }
+
+ ///
+ /// Validate a Sample
+ ///
+ private static void Validate(Models.ClrMamePro.Sample? sample)
+ {
+ Assert.NotNull(sample);
+ Assert.Equal("XXXXXX", sample.Name);
+ }
+
+ ///
+ /// Validate a Archive
+ ///
+ private static void Validate(Models.ClrMamePro.Archive? archive)
+ {
+ Assert.NotNull(archive);
+ Assert.Equal("XXXXXX", archive.Name);
+ }
+
+ ///
+ /// Validate a Media
+ ///
+ private static void Validate(Models.ClrMamePro.Media? media)
+ {
+ Assert.NotNull(media);
+ Assert.Equal("XXXXXX", media.Name);
+ Assert.Equal("XXXXXX", media.MD5);
+ Assert.Equal("XXXXXX", media.SHA1);
+ Assert.Equal("XXXXXX", media.SHA256);
+ Assert.Equal("XXXXXX", media.SpamSum);
+ }
+
+ ///
+ /// Validate a Chip
+ ///
+ private static void Validate(Models.ClrMamePro.Chip? chip)
+ {
+ Assert.NotNull(chip);
+ Assert.Equal("XXXXXX", chip.Type);
+ Assert.Equal("XXXXXX", chip.Name);
+ Assert.Equal("XXXXXX", chip.Flags);
+ Assert.Equal("XXXXXX", chip.Clock);
+ }
+
+ ///
+ /// Validate a Video
+ ///
+ private static void Validate(Models.ClrMamePro.Video? video)
+ {
+ Assert.NotNull(video);
+ Assert.Equal("XXXXXX", video.Screen);
+ Assert.Equal("XXXXXX", video.Orientation);
+ Assert.Equal("XXXXXX", video.X);
+ Assert.Equal("XXXXXX", video.Y);
+ Assert.Equal("XXXXXX", video.AspectX);
+ Assert.Equal("XXXXXX", video.AspectY);
+ Assert.Equal("XXXXXX", video.Freq);
+ }
+
+ ///
+ /// Validate a Sound
+ ///
+ private static void Validate(Models.ClrMamePro.Sound? sound)
+ {
+ Assert.NotNull(sound);
+ Assert.Equal("XXXXXX", sound.Channels);
+ }
+
+ ///
+ /// Validate a Input
+ ///
+ private static void Validate(Models.ClrMamePro.Input? input)
+ {
+ Assert.NotNull(input);
+ Assert.Equal("XXXXXX", input.Players);
+ Assert.Equal("XXXXXX", input.Control);
+ Assert.Equal("XXXXXX", input.Buttons);
+ Assert.Equal("XXXXXX", input.Coins);
+ Assert.Equal("XXXXXX", input.Tilt);
+ Assert.Equal("XXXXXX", input.Service);
+ }
+
+ ///
+ /// Validate a DipSwitch
+ ///
+ private static void Validate(Models.ClrMamePro.DipSwitch? dipswitch)
+ {
+ Assert.NotNull(dipswitch);
+ Assert.Equal("XXXXXX", dipswitch.Name);
+
+ Assert.NotNull(dipswitch.Entry);
+ string entry = Assert.Single(dipswitch.Entry);
+ Assert.Equal("XXXXXX", entry);
+
+ Assert.Equal("XXXXXX", dipswitch.Default);
+ }
+
+ ///
+ /// Validate a Driver
+ ///
+ private static void Validate(Models.ClrMamePro.Driver? driver)
+ {
+ Assert.NotNull(driver);
+ Assert.Equal("XXXXXX", driver.Status);
+ Assert.Equal("XXXXXX", driver.Color);
+ Assert.Equal("XXXXXX", driver.Sound);
+ Assert.Equal("XXXXXX", driver.PaletteSize);
+ Assert.Equal("XXXXXX", driver.Blit);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/DosCenterTests.cs b/SabreTools.Serialization.Test/CrossModel/DosCenterTests.cs
new file mode 100644
index 00000000..cc2d47e8
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/DosCenterTests.cs
@@ -0,0 +1,108 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class DosCenterTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.DosCenter();
+
+ // Build the data
+ Models.DosCenter.MetadataFile mf = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.DosCenter.MetadataFile? newMf = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newMf);
+ Validate(newMf.DosCenter);
+ Assert.NotNull(newMf.Game);
+ var newGame = Assert.Single(newMf.Game);
+ Validate(newGame);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.DosCenter.MetadataFile Build()
+ {
+ var dc = new Models.DosCenter.DosCenter
+ {
+ Name = "XXXXXX",
+ Description = "XXXXXX",
+ Version = "XXXXXX",
+ Date = "XXXXXX",
+ Author = "XXXXXX",
+ Homepage = "XXXXXX",
+ Comment = "XXXXXX",
+ };
+
+ var file = new Models.DosCenter.File
+ {
+ Name = "XXXXXX",
+ Size = "XXXXXX",
+ CRC = "XXXXXX",
+ Date = "XXXXXX",
+ };
+
+ var game = new Models.DosCenter.Game
+ {
+ Name = "XXXXXX",
+ File = [file],
+ };
+
+ return new Models.DosCenter.MetadataFile
+ {
+ DosCenter = dc,
+ Game = [game],
+ };
+ }
+
+ ///
+ /// Validate a DosCenter
+ ///
+ private static void Validate(Models.DosCenter.DosCenter? cmp)
+ {
+ Assert.NotNull(cmp);
+ Assert.Equal("XXXXXX", cmp.Name);
+ Assert.Equal("XXXXXX", cmp.Description);
+ Assert.Equal("XXXXXX", cmp.Version);
+ Assert.Equal("XXXXXX", cmp.Date);
+ Assert.Equal("XXXXXX", cmp.Author);
+ Assert.Equal("XXXXXX", cmp.Homepage);
+ Assert.Equal("XXXXXX", cmp.Comment);
+ }
+
+ ///
+ /// Validate a Game
+ ///
+ private static void Validate(Models.DosCenter.Game? game)
+ {
+ Assert.NotNull(game);
+ Assert.Equal("XXXXXX", game.Name);
+
+ Assert.NotNull(game.File);
+ var file = Assert.Single(game.File);
+ Validate(file);
+ }
+
+ ///
+ /// Validate a File
+ ///
+ private static void Validate(Models.DosCenter.File? rom)
+ {
+ Assert.NotNull(rom);
+ Assert.Equal("XXXXXX", rom.Name);
+ Assert.Equal("XXXXXX", rom.Size);
+ Assert.Equal("XXXXXX", rom.CRC);
+ Assert.Equal("XXXXXX", rom.Date);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/EverdriveSMDBTests.cs b/SabreTools.Serialization.Test/CrossModel/EverdriveSMDBTests.cs
new file mode 100644
index 00000000..9217a761
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/EverdriveSMDBTests.cs
@@ -0,0 +1,65 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class EverdriveSMDBTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.EverdriveSMDB();
+
+ // Build the data
+ Models.EverdriveSMDB.MetadataFile mf = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.EverdriveSMDB.MetadataFile? newMf = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newMf);
+ Assert.NotNull(newMf.Row);
+ var newRow = Assert.Single(newMf.Row);
+ Validate(newRow);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.EverdriveSMDB.MetadataFile Build()
+ {
+ var row = new Models.EverdriveSMDB.Row
+ {
+ SHA256 = "XXXXXX",
+ Name = "XXXXXX",
+ SHA1 = "XXXXXX",
+ MD5 = "XXXXXX",
+ CRC32 = "XXXXXX",
+ Size = "XXXXXX",
+ };
+
+ return new Models.EverdriveSMDB.MetadataFile
+ {
+ Row = [row],
+ };
+ }
+
+ ///
+ /// Validate a Row
+ ///
+ private static void Validate(Models.EverdriveSMDB.Row? row)
+ {
+ Assert.NotNull(row);
+ Assert.Equal("XXXXXX", row.SHA256);
+ Assert.Equal("XXXXXX", row.Name);
+ Assert.Equal("XXXXXX", row.SHA1);
+ Assert.Equal("XXXXXX", row.MD5);
+ Assert.Equal("XXXXXX", row.CRC32);
+ Assert.Equal("XXXXXX", row.Size);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/HashfileTests.cs b/SabreTools.Serialization.Test/CrossModel/HashfileTests.cs
new file mode 100644
index 00000000..93926212
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/HashfileTests.cs
@@ -0,0 +1,326 @@
+using System;
+using SabreTools.Hashing;
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class HashfileTests
+ {
+ [Fact]
+ public void RoundTripSFVTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Hashfile();
+
+ // Build the data
+ Models.Hashfile.Hashfile hf = Build(HashType.CRC32);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.CRC32);
+
+ // Validate the data
+ Assert.NotNull(newHf);
+ Assert.NotNull(newHf.SFV);
+ var newSfv = Assert.Single(newHf.SFV);
+ Validate(newSfv);
+ }
+
+ [Fact]
+ public void RoundTripMD2Test()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Hashfile();
+
+ // Build the data
+ Models.Hashfile.Hashfile hf = Build(HashType.MD2);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.MD2);
+
+ // Validate the data
+ Assert.NotNull(newHf);
+ Assert.NotNull(newHf.MD2);
+ var newMd2 = Assert.Single(newHf.MD2);
+ Validate(newMd2);
+ }
+
+ [Fact]
+ public void RoundTripMD4Test()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Hashfile();
+
+ // Build the data
+ Models.Hashfile.Hashfile hf = Build(HashType.MD4);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.MD4);
+
+ // Validate the data
+ Assert.NotNull(newHf);
+ Assert.NotNull(newHf.MD4);
+ var newMd4 = Assert.Single(newHf.MD4);
+ Validate(newMd4);
+ }
+
+ [Fact]
+ public void RoundTripMD5Test()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Hashfile();
+
+ // Build the data
+ Models.Hashfile.Hashfile hf = Build(HashType.MD5);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.MD5);
+
+ // Validate the data
+ Assert.NotNull(newHf);
+ Assert.NotNull(newHf.MD5);
+ var newMd5 = Assert.Single(newHf.MD5);
+ Validate(newMd5);
+ }
+
+ [Fact]
+ public void RoundTripSHA1Test()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Hashfile();
+
+ // Build the data
+ Models.Hashfile.Hashfile hf = Build(HashType.SHA1);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.SHA1);
+
+ // Validate the data
+ Assert.NotNull(newHf);
+ Assert.NotNull(newHf.SHA1);
+ var newSha1 = Assert.Single(newHf.SHA1);
+ Validate(newSha1);
+ }
+
+ [Fact]
+ public void RoundTripSHA256Test()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Hashfile();
+
+ // Build the data
+ Models.Hashfile.Hashfile hf = Build(HashType.SHA256);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.SHA256);
+
+ // Validate the data
+ Assert.NotNull(newHf);
+ Assert.NotNull(newHf.SHA256);
+ var newSha256 = Assert.Single(newHf.SHA256);
+ Validate(newSha256);
+ }
+
+ [Fact]
+ public void RoundTripSHA384Test()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Hashfile();
+
+ // Build the data
+ Models.Hashfile.Hashfile hf = Build(HashType.SHA384);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.SHA384);
+
+ // Validate the data
+ Assert.NotNull(newHf);
+ Assert.NotNull(newHf.SHA384);
+ var newSha384 = Assert.Single(newHf.SHA384);
+ Validate(newSha384);
+ }
+
+ [Fact]
+ public void RoundTripSHA512Test()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Hashfile();
+
+ // Build the data
+ Models.Hashfile.Hashfile hf = Build(HashType.SHA512);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.SHA512);
+
+ // Validate the data
+ Assert.NotNull(newHf);
+ Assert.NotNull(newHf.SHA512);
+ var newSha512 = Assert.Single(newHf.SHA512);
+ Validate(newSha512);
+ }
+
+ [Fact]
+ public void RoundTripSpamSumTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Hashfile();
+
+ // Build the data
+ Models.Hashfile.Hashfile hf = Build(HashType.SpamSum);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.SpamSum);
+
+ // Validate the data
+ Assert.NotNull(newHf);
+ Assert.NotNull(newHf.SpamSum);
+ var newSpamsum = Assert.Single(newHf.SpamSum);
+ Validate(newSpamsum);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.Hashfile.Hashfile Build(HashType hashType)
+ {
+ return hashType switch
+ {
+ HashType.CRC32 => new Models.Hashfile.Hashfile { SFV = [new Models.Hashfile.SFV { File = "XXXXXX", Hash = "XXXXXX" }] },
+ HashType.MD2 => new Models.Hashfile.Hashfile { MD2 = [new Models.Hashfile.MD2 { Hash = "XXXXXX", File = "XXXXXX" }] },
+ HashType.MD4 => new Models.Hashfile.Hashfile { MD4 = [new Models.Hashfile.MD4 { Hash = "XXXXXX", File = "XXXXXX" }] },
+ HashType.MD5 => new Models.Hashfile.Hashfile { MD5 = [new Models.Hashfile.MD5 { Hash = "XXXXXX", File = "XXXXXX" }] },
+ HashType.SHA1 => new Models.Hashfile.Hashfile { SHA1 = [new Models.Hashfile.SHA1 { Hash = "XXXXXX", File = "XXXXXX" }] },
+ HashType.SHA256 => new Models.Hashfile.Hashfile { SHA256 = [new Models.Hashfile.SHA256 { Hash = "XXXXXX", File = "XXXXXX" }] },
+ HashType.SHA384 => new Models.Hashfile.Hashfile { SHA384 = [new Models.Hashfile.SHA384 { Hash = "XXXXXX", File = "XXXXXX" }] },
+ HashType.SHA512 => new Models.Hashfile.Hashfile { SHA512 = [new Models.Hashfile.SHA512 { Hash = "XXXXXX", File = "XXXXXX" }] },
+ HashType.SpamSum => new Models.Hashfile.Hashfile { SpamSum = [new Models.Hashfile.SpamSum { Hash = "XXXXXX", File = "XXXXXX" }] },
+ _ => throw new ArgumentOutOfRangeException(),
+ };
+ }
+
+ ///
+ /// Validate a SFV
+ ///
+ private static void Validate(Models.Hashfile.SFV? sfv)
+ {
+ Assert.NotNull(sfv);
+ Assert.Equal("XXXXXX", sfv.File);
+ Assert.Equal("XXXXXX", sfv.Hash);
+ }
+
+ ///
+ /// Validate a MD2
+ ///
+ private static void Validate(Models.Hashfile.MD2? md2)
+ {
+ Assert.NotNull(md2);
+ Assert.Equal("XXXXXX", md2.Hash);
+ Assert.Equal("XXXXXX", md2.File);
+ }
+
+ ///
+ /// Validate a MD4
+ ///
+ private static void Validate(Models.Hashfile.MD4? md4)
+ {
+ Assert.NotNull(md4);
+ Assert.Equal("XXXXXX", md4.Hash);
+ Assert.Equal("XXXXXX", md4.File);
+ }
+
+ ///
+ /// Validate a MD5
+ ///
+ private static void Validate(Models.Hashfile.MD5? md5)
+ {
+ Assert.NotNull(md5);
+ Assert.Equal("XXXXXX", md5.Hash);
+ Assert.Equal("XXXXXX", md5.File);
+ }
+
+ ///
+ /// Validate a SHA1
+ ///
+ private static void Validate(Models.Hashfile.SHA1? sha1)
+ {
+ Assert.NotNull(sha1);
+ Assert.Equal("XXXXXX", sha1.Hash);
+ Assert.Equal("XXXXXX", sha1.File);
+ }
+
+ ///
+ /// Validate a SHA256
+ ///
+ private static void Validate(Models.Hashfile.SHA256? sha256)
+ {
+ Assert.NotNull(sha256);
+ Assert.Equal("XXXXXX", sha256.Hash);
+ Assert.Equal("XXXXXX", sha256.File);
+ }
+
+ ///
+ /// Validate a SHA384
+ ///
+ private static void Validate(Models.Hashfile.SHA384? sha384)
+ {
+ Assert.NotNull(sha384);
+ Assert.Equal("XXXXXX", sha384.Hash);
+ Assert.Equal("XXXXXX", sha384.File);
+ }
+
+ ///
+ /// Validate a SHA512
+ ///
+ private static void Validate(Models.Hashfile.SHA512? sha512)
+ {
+ Assert.NotNull(sha512);
+ Assert.Equal("XXXXXX", sha512.Hash);
+ Assert.Equal("XXXXXX", sha512.File);
+ }
+
+ ///
+ /// Validate a SpamSum
+ ///
+ private static void Validate(Models.Hashfile.SpamSum? spamsum)
+ {
+ Assert.NotNull(spamsum);
+ Assert.Equal("XXXXXX", spamsum.Hash);
+ Assert.Equal("XXXXXX", spamsum.File);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/ListromTests.cs b/SabreTools.Serialization.Test/CrossModel/ListromTests.cs
new file mode 100644
index 00000000..e36cf1d2
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/ListromTests.cs
@@ -0,0 +1,127 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class ListromTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Listrom();
+
+ // Build the data
+ Models.Listrom.MetadataFile mf = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Listrom.MetadataFile? newMf = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newMf);
+ Assert.NotNull(newMf.Set);
+ Assert.Equal(2, newMf.Set.Length);
+
+ ValidateDevice(newMf.Set[0]);
+ ValidateDriver(newMf.Set[1]);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.Listrom.MetadataFile Build()
+ {
+ var rom = new Models.Listrom.Row
+ {
+ Name = "XXXXXX",
+ Size = "XXXXXX",
+ Bad = true,
+ CRC = "XXXXXX",
+ SHA1 = "XXXXXX",
+ NoGoodDumpKnown = false,
+ };
+
+ var disk = new Models.Listrom.Row
+ {
+ Name = "XXXXXX",
+ Bad = false,
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ NoGoodDumpKnown = true,
+ };
+
+ var device = new Models.Listrom.Set()
+ {
+ Device = "XXXXXX",
+ Row = [rom],
+ };
+
+ var driver = new Models.Listrom.Set()
+ {
+ Driver = "XXXXXX",
+ Row = [disk],
+ };
+
+ return new Models.Listrom.MetadataFile
+ {
+ Set = [device, driver],
+ };
+ }
+
+ ///
+ /// Validate a Set
+ ///
+ private static void ValidateDevice(Models.Listrom.Set? set)
+ {
+ Assert.NotNull(set);
+ Assert.Equal("XXXXXX", set.Device);
+
+ Assert.NotNull(set.Row);
+ var row = Assert.Single(set.Row);
+ ValidateRom(row);
+ }
+
+ ///
+ /// Validate a Set
+ ///
+ private static void ValidateDriver(Models.Listrom.Set? set)
+ {
+ Assert.NotNull(set);
+ Assert.Equal("XXXXXX", set.Driver);
+
+ Assert.NotNull(set.Row);
+ var row = Assert.Single(set.Row);
+ ValidateDisk(row);
+ }
+
+ ///
+ /// Validate a Row
+ ///
+ private static void ValidateRom(Models.Listrom.Row? row)
+ {
+ Assert.NotNull(row);
+ Assert.Equal("XXXXXX", row.Name);
+ Assert.Equal("XXXXXX", row.Size);
+ Assert.True(row.Bad);
+ Assert.Equal("XXXXXX", row.CRC);
+ Assert.Equal("XXXXXX", row.SHA1);
+ Assert.False(row.NoGoodDumpKnown);
+ }
+
+ ///
+ /// Validate a Row
+ ///
+ private static void ValidateDisk(Models.Listrom.Row? row)
+ {
+ Assert.NotNull(row);
+ Assert.Equal("XXXXXX", row.Name);
+ Assert.False(row.Bad);
+ Assert.Equal("XXXXXX", row.MD5);
+ Assert.Equal("XXXXXX", row.SHA1);
+ Assert.True(row.NoGoodDumpKnown);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/ListxmlTests.cs b/SabreTools.Serialization.Test/CrossModel/ListxmlTests.cs
new file mode 100644
index 00000000..a5cc0b82
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/ListxmlTests.cs
@@ -0,0 +1,878 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class ListxmlTests
+ {
+ [Fact]
+ public void RoundTripGameTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Listxml();
+
+ // Build the data
+ Models.Listxml.Mame mame = Build(game: true);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mame);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Listxml.Mame? newMame = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newMame);
+ Assert.Equal("XXXXXX", newMame.Build);
+ Assert.Equal("XXXXXX", newMame.Debug);
+ Assert.Equal("XXXXXX", newMame.MameConfig);
+
+ Assert.NotNull(newMame.Game);
+ var newGame = Assert.Single(newMame.Game);
+ Validate(newGame);
+ }
+
+ [Fact]
+ public void RoundTripMachineTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Listxml();
+
+ // Build the data
+ Models.Listxml.Mame mame = Build(game: false);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mame);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Listxml.Mame? newMame = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newMame);
+ Assert.Equal("XXXXXX", newMame.Build);
+ Assert.Equal("XXXXXX", newMame.Debug);
+ Assert.Equal("XXXXXX", newMame.MameConfig);
+
+ Assert.NotNull(newMame.Game);
+ var newGame = Assert.Single(newMame.Game);
+ Validate(newGame);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.Listxml.Mame Build(bool game)
+ {
+ var biosset = new Models.Listxml.BiosSet
+ {
+ Name = "XXXXXX",
+ Description = "XXXXXX",
+ Default = "XXXXXX",
+ };
+
+ var rom = new Models.Listxml.Rom
+ {
+ Name = "XXXXXX",
+ Bios = "XXXXXX",
+ Size = "XXXXXX",
+ CRC = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Merge = "XXXXXX",
+ Region = "XXXXXX",
+ Offset = "XXXXXX",
+ Status = "XXXXXX",
+ Optional = "XXXXXX",
+ Dispose = "XXXXXX",
+ SoundOnly = "XXXXXX",
+ };
+
+ var disk = new Models.Listxml.Disk
+ {
+ Name = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Merge = "XXXXXX",
+ Region = "XXXXXX",
+ Index = "XXXXXX",
+ Writable = "XXXXXX",
+ Status = "XXXXXX",
+ Optional = "XXXXXX",
+ };
+
+ var deviceref = new Models.Listxml.DeviceRef
+ {
+ Name = "XXXXXX",
+ };
+
+ var sample = new Models.Listxml.Sample
+ {
+ Name = "XXXXXX",
+ };
+
+ var chip = new Models.Listxml.Chip
+ {
+ Name = "XXXXXX",
+ Tag = "XXXXXX",
+ Type = "XXXXXX",
+ SoundOnly = "XXXXXX",
+ Clock = "XXXXXX",
+ };
+
+ var display = new Models.Listxml.Display
+ {
+ Tag = "XXXXXX",
+ Type = "XXXXXX",
+ Rotate = "XXXXXX",
+ FlipX = "XXXXXX",
+ Width = "XXXXXX",
+ Height = "XXXXXX",
+ Refresh = "XXXXXX",
+ PixClock = "XXXXXX",
+ HTotal = "XXXXXX",
+ HBEnd = "XXXXXX",
+ HBStart = "XXXXXX",
+ VTotal = "XXXXXX",
+ VBEnd = "XXXXXX",
+ VBStart = "XXXXXX",
+ };
+
+ var video = new Models.Listxml.Video
+ {
+ Screen = "XXXXXX",
+ Orientation = "XXXXXX",
+ Width = "XXXXXX",
+ Height = "XXXXXX",
+ AspectX = "XXXXXX",
+ AspectY = "XXXXXX",
+ Refresh = "XXXXXX",
+ };
+
+ var sound = new Models.Listxml.Sound
+ {
+ Channels = "XXXXXX",
+ };
+
+ var control = new Models.Listxml.Control
+ {
+ Type = "XXXXXX",
+ Player = "XXXXXX",
+ Buttons = "XXXXXX",
+ ReqButtons = "XXXXXX",
+ Minimum = "XXXXXX",
+ Maximum = "XXXXXX",
+ Sensitivity = "XXXXXX",
+ KeyDelta = "XXXXXX",
+ Reverse = "XXXXXX",
+ Ways = "XXXXXX",
+ Ways2 = "XXXXXX",
+ Ways3 = "XXXXXX",
+ };
+
+ var input = new Models.Listxml.Input
+ {
+ Service = "XXXXXX",
+ Tilt = "XXXXXX",
+ Players = "XXXXXX",
+ //ControlAttr = "XXXXXX", // Mututally exclusive with input.Control
+ Buttons = "XXXXXX",
+ Coins = "XXXXXX",
+ Control = [control],
+ };
+
+ var condition = new Models.Listxml.Condition
+ {
+ Tag = "XXXXXX",
+ Mask = "XXXXXX",
+ Relation = "XXXXXX",
+ Value = "XXXXXX",
+ };
+
+ var diplocation = new Models.Listxml.DipLocation
+ {
+ Name = "XXXXXX",
+ Number = "XXXXXX",
+ Inverted = "XXXXXX",
+ };
+
+ var dipvalue = new Models.Listxml.DipValue
+ {
+ Name = "XXXXXX",
+ Value = "XXXXXX",
+ Default = "XXXXXX",
+ Condition = condition,
+ };
+
+ var dipswitch = new Models.Listxml.DipSwitch
+ {
+ Name = "XXXXXX",
+ Tag = "XXXXXX",
+ Mask = "XXXXXX",
+ Condition = condition,
+ DipLocation = [diplocation],
+ DipValue = [dipvalue],
+ };
+
+ var conflocation = new Models.Listxml.ConfLocation
+ {
+ Name = "XXXXXX",
+ Number = "XXXXXX",
+ Inverted = "XXXXXX",
+ };
+
+ var confsetting = new Models.Listxml.ConfSetting
+ {
+ Name = "XXXXXX",
+ Value = "XXXXXX",
+ Default = "XXXXXX",
+ Condition = condition,
+ };
+
+ var configuration = new Models.Listxml.Configuration
+ {
+ Name = "XXXXXX",
+ Tag = "XXXXXX",
+ Mask = "XXXXXX",
+ Condition = condition,
+ ConfLocation = [conflocation],
+ ConfSetting = [confsetting],
+ };
+
+ var analog = new Models.Listxml.Analog
+ {
+ Mask = "XXXXXX",
+ };
+
+ var port = new Models.Listxml.Port
+ {
+ Tag = "XXXXXX",
+ Analog = [analog],
+ };
+
+ var adjuster = new Models.Listxml.Adjuster
+ {
+ Name = "XXXXXX",
+ Default = "XXXXXX",
+ Condition = condition,
+ };
+
+ var driver = new Models.Listxml.Driver
+ {
+ Status = "XXXXXX",
+ Color = "XXXXXX",
+ Sound = "XXXXXX",
+ PaletteSize = "XXXXXX",
+ Emulation = "XXXXXX",
+ Cocktail = "XXXXXX",
+ SaveState = "XXXXXX",
+ RequiresArtwork = "XXXXXX",
+ Unofficial = "XXXXXX",
+ NoSoundHardware = "XXXXXX",
+ Incomplete = "XXXXXX",
+ };
+
+ var feature = new Models.Listxml.Feature
+ {
+ Type = "XXXXXX",
+ Status = "XXXXXX",
+ Overall = "XXXXXX",
+ };
+
+ var instance = new Models.Listxml.Instance
+ {
+ Name = "XXXXXX",
+ BriefName = "XXXXXX",
+ };
+
+ var extension = new Models.Listxml.Extension
+ {
+ Name = "XXXXXX",
+ };
+
+ var device = new Models.Listxml.Device
+ {
+ Type = "XXXXXX",
+ Tag = "XXXXXX",
+ FixedImage = "XXXXXX",
+ Mandatory = "XXXXXX",
+ Interface = "XXXXXX",
+ Instance = instance,
+ Extension = [extension],
+ };
+
+ var slotOption = new Models.Listxml.SlotOption
+ {
+ Name = "XXXXXX",
+ DevName = "XXXXXX",
+ Default = "XXXXXX",
+ };
+
+ var slot = new Models.Listxml.Slot
+ {
+ Name = "XXXXXX",
+ SlotOption = [slotOption],
+ };
+
+ var softwarelist = new Models.Listxml.SoftwareList
+ {
+ Tag = "XXXXXX",
+ Name = "XXXXXX",
+ Status = "XXXXXX",
+ Filter = "XXXXXX",
+ };
+
+ var ramoption = new Models.Listxml.RamOption
+ {
+ Name = "XXXXXX",
+ Default = "XXXXXX",
+ Content = "XXXXXX",
+ };
+
+ Models.Listxml.GameBase gameBase = game
+ ? new Models.Listxml.Game()
+ : new Models.Listxml.Machine();
+ gameBase.Name = "XXXXXX";
+ gameBase.SourceFile = "XXXXXX";
+ gameBase.IsBios = "XXXXXX";
+ gameBase.IsDevice = "XXXXXX";
+ gameBase.IsMechanical = "XXXXXX";
+ gameBase.Runnable = "XXXXXX";
+ gameBase.CloneOf = "XXXXXX";
+ gameBase.RomOf = "XXXXXX";
+ gameBase.SampleOf = "XXXXXX";
+ gameBase.Description = "XXXXXX";
+ gameBase.Year = "XXXXXX";
+ gameBase.Manufacturer = "XXXXXX";
+ gameBase.History = "XXXXXX";
+ gameBase.BiosSet = [biosset];
+ gameBase.Rom = [rom];
+ gameBase.Disk = [disk];
+ gameBase.DeviceRef = [deviceref];
+ gameBase.Sample = [sample];
+ gameBase.Chip = [chip];
+ gameBase.Display = [display];
+ gameBase.Video = [video];
+ gameBase.Sound = sound;
+ gameBase.Input = input;
+ gameBase.DipSwitch = [dipswitch];
+ gameBase.Configuration = [configuration];
+ gameBase.Port = [port];
+ gameBase.Adjuster = [adjuster];
+ gameBase.Driver = driver;
+ gameBase.Feature = [feature];
+ gameBase.Device = [device];
+ gameBase.Slot = [slot];
+ gameBase.SoftwareList = [softwarelist];
+ gameBase.RamOption = [ramoption];
+
+ return new Models.Listxml.Mame
+ {
+ Build = "XXXXXX",
+ Debug = "XXXXXX",
+ MameConfig = "XXXXXX",
+ Game = [gameBase],
+ };
+ }
+
+ ///
+ /// Validate a GameBase
+ ///
+ private static void Validate(Models.Listxml.GameBase? gb)
+ {
+ Assert.NotNull(gb);
+ Assert.Equal("XXXXXX", gb.Name);
+ Assert.Equal("XXXXXX", gb.SourceFile);
+ Assert.Equal("XXXXXX", gb.IsBios);
+ Assert.Equal("XXXXXX", gb.IsDevice);
+ Assert.Equal("XXXXXX", gb.IsMechanical);
+ Assert.Equal("XXXXXX", gb.Runnable);
+ Assert.Equal("XXXXXX", gb.CloneOf);
+ Assert.Equal("XXXXXX", gb.RomOf);
+ Assert.Equal("XXXXXX", gb.SampleOf);
+ Assert.Equal("XXXXXX", gb.Description);
+ Assert.Equal("XXXXXX", gb.Year);
+ Assert.Equal("XXXXXX", gb.Manufacturer);
+ Assert.Equal("XXXXXX", gb.History);
+
+ Assert.NotNull(gb.BiosSet);
+ var biosset = Assert.Single(gb.BiosSet);
+ Validate(biosset);
+
+ Assert.NotNull(gb.Rom);
+ var rom = Assert.Single(gb.Rom);
+ Validate(rom);
+
+ Assert.NotNull(gb.Disk);
+ var disk = Assert.Single(gb.Disk);
+ Validate(disk);
+
+ Assert.NotNull(gb.DeviceRef);
+ var deviceref = Assert.Single(gb.DeviceRef);
+ Validate(deviceref);
+
+ Assert.NotNull(gb.Sample);
+ var sample = Assert.Single(gb.Sample);
+ Validate(sample);
+
+ Assert.NotNull(gb.Chip);
+ var chip = Assert.Single(gb.Chip);
+ Validate(chip);
+
+ Assert.NotNull(gb.Display);
+ var display = Assert.Single(gb.Display);
+ Validate(display);
+
+ Assert.NotNull(gb.Video);
+ var video = Assert.Single(gb.Video);
+ Validate(video);
+
+ Validate(gb.Sound);
+ Validate(gb.Input);
+
+ Assert.NotNull(gb.DipSwitch);
+ var dipswitch = Assert.Single(gb.DipSwitch);
+ Validate(dipswitch);
+
+ Assert.NotNull(gb.Configuration);
+ var configuration = Assert.Single(gb.Configuration);
+ Validate(configuration);
+
+ Assert.NotNull(gb.Port);
+ var port = Assert.Single(gb.Port);
+ Validate(port);
+
+ Assert.NotNull(gb.Adjuster);
+ var adjuster = Assert.Single(gb.Adjuster);
+ Validate(adjuster);
+
+ Validate(gb.Driver);
+
+ Assert.NotNull(gb.Feature);
+ var feature = Assert.Single(gb.Feature);
+ Validate(feature);
+
+ Assert.NotNull(gb.Device);
+ var device = Assert.Single(gb.Device);
+ Validate(device);
+
+ Assert.NotNull(gb.Slot);
+ var slot = Assert.Single(gb.Slot);
+ Validate(slot);
+
+ Assert.NotNull(gb.SoftwareList);
+ var softwarelist = Assert.Single(gb.SoftwareList);
+ Validate(softwarelist);
+
+ Assert.NotNull(gb.RamOption);
+ var ramoption = Assert.Single(gb.RamOption);
+ Validate(ramoption);
+ }
+
+ ///
+ /// Validate a BiosSet
+ ///
+ private static void Validate(Models.Listxml.BiosSet? biosset)
+ {
+ Assert.NotNull(biosset);
+ Assert.Equal("XXXXXX", biosset.Name);
+ Assert.Equal("XXXXXX", biosset.Description);
+ Assert.Equal("XXXXXX", biosset.Default);
+ }
+
+ ///
+ /// Validate a Rom
+ ///
+ private static void Validate(Models.Listxml.Rom? rom)
+ {
+ Assert.NotNull(rom);
+ Assert.Equal("XXXXXX", rom.Name);
+ Assert.Equal("XXXXXX", rom.Bios);
+ Assert.Equal("XXXXXX", rom.Size);
+ Assert.Equal("XXXXXX", rom.CRC);
+ Assert.Equal("XXXXXX", rom.SHA1);
+ Assert.Equal("XXXXXX", rom.Merge);
+ Assert.Equal("XXXXXX", rom.Region);
+ Assert.Equal("XXXXXX", rom.Offset);
+ Assert.Equal("XXXXXX", rom.Status);
+ Assert.Equal("XXXXXX", rom.Optional);
+ Assert.Equal("XXXXXX", rom.Dispose);
+ Assert.Equal("XXXXXX", rom.SoundOnly);
+ }
+
+ ///
+ /// Validate a Disk
+ ///
+ private static void Validate(Models.Listxml.Disk? disk)
+ {
+ Assert.NotNull(disk);
+ Assert.Equal("XXXXXX", disk.Name);
+ Assert.Equal("XXXXXX", disk.MD5);
+ Assert.Equal("XXXXXX", disk.SHA1);
+ Assert.Equal("XXXXXX", disk.Merge);
+ Assert.Equal("XXXXXX", disk.Region);
+ Assert.Equal("XXXXXX", disk.Index);
+ Assert.Equal("XXXXXX", disk.Writable);
+ Assert.Equal("XXXXXX", disk.Status);
+ Assert.Equal("XXXXXX", disk.Optional);
+ }
+
+ ///
+ /// Validate a DeviceRef
+ ///
+ private static void Validate(Models.Listxml.DeviceRef? deviceref)
+ {
+ Assert.NotNull(deviceref);
+ Assert.Equal("XXXXXX", deviceref.Name);
+ }
+
+ ///
+ /// Validate a Sample
+ ///
+ private static void Validate(Models.Listxml.Sample? sample)
+ {
+ Assert.NotNull(sample);
+ Assert.Equal("XXXXXX", sample.Name);
+ }
+
+ ///
+ /// Validate a Chip
+ ///
+ private static void Validate(Models.Listxml.Chip? chip)
+ {
+ Assert.NotNull(chip);
+ Assert.Equal("XXXXXX", chip.Name);
+ Assert.Equal("XXXXXX", chip.Tag);
+ Assert.Equal("XXXXXX", chip.Type);
+ Assert.Equal("XXXXXX", chip.SoundOnly);
+ Assert.Equal("XXXXXX", chip.Clock);
+ }
+
+ ///
+ /// Validate a Display
+ ///
+ private static void Validate(Models.Listxml.Display? display)
+ {
+ Assert.NotNull(display);
+ Assert.Equal("XXXXXX", display.Tag);
+ Assert.Equal("XXXXXX", display.Type);
+ Assert.Equal("XXXXXX", display.Rotate);
+ Assert.Equal("XXXXXX", display.FlipX);
+ Assert.Equal("XXXXXX", display.Width);
+ Assert.Equal("XXXXXX", display.Height);
+ Assert.Equal("XXXXXX", display.Refresh);
+ Assert.Equal("XXXXXX", display.PixClock);
+ Assert.Equal("XXXXXX", display.HTotal);
+ Assert.Equal("XXXXXX", display.HBEnd);
+ Assert.Equal("XXXXXX", display.HBStart);
+ Assert.Equal("XXXXXX", display.VTotal);
+ Assert.Equal("XXXXXX", display.VBEnd);
+ Assert.Equal("XXXXXX", display.VBStart);
+ }
+
+ ///
+ /// Validate a Video
+ ///
+ private static void Validate(Models.Listxml.Video? video)
+ {
+ Assert.NotNull(video);
+ Assert.Equal("XXXXXX", video.Screen);
+ Assert.Equal("XXXXXX", video.Orientation);
+ Assert.Equal("XXXXXX", video.Width);
+ Assert.Equal("XXXXXX", video.Height);
+ Assert.Equal("XXXXXX", video.AspectX);
+ Assert.Equal("XXXXXX", video.AspectY);
+ Assert.Equal("XXXXXX", video.Refresh);
+ }
+
+ ///
+ /// Validate a Sound
+ ///
+ private static void Validate(Models.Listxml.Sound? sound)
+ {
+ Assert.NotNull(sound);
+ Assert.Equal("XXXXXX", sound.Channels);
+ }
+
+ ///
+ /// Validate a Input
+ ///
+ private static void Validate(Models.Listxml.Input? input)
+ {
+ Assert.NotNull(input);
+ Assert.Equal("XXXXXX", input.Service);
+ Assert.Equal("XXXXXX", input.Tilt);
+ Assert.Equal("XXXXXX", input.Players);
+ //Assert.Equal("XXXXXX", input.ControlAttr); // Mututally exclusive with input.Control
+ Assert.Equal("XXXXXX", input.Buttons);
+ Assert.Equal("XXXXXX", input.Coins);
+
+ Assert.NotNull(input.Control);
+ var control = Assert.Single(input.Control);
+ Validate(control);
+ }
+
+ ///
+ /// Validate a Control
+ ///
+ private static void Validate(Models.Listxml.Control? control)
+ {
+ Assert.NotNull(control);
+ Assert.Equal("XXXXXX", control.Type);
+ Assert.Equal("XXXXXX", control.Player);
+ Assert.Equal("XXXXXX", control.Buttons);
+ Assert.Equal("XXXXXX", control.ReqButtons);
+ Assert.Equal("XXXXXX", control.Minimum);
+ Assert.Equal("XXXXXX", control.Maximum);
+ Assert.Equal("XXXXXX", control.Sensitivity);
+ Assert.Equal("XXXXXX", control.KeyDelta);
+ Assert.Equal("XXXXXX", control.Reverse);
+ Assert.Equal("XXXXXX", control.Ways);
+ Assert.Equal("XXXXXX", control.Ways2);
+ Assert.Equal("XXXXXX", control.Ways3);
+ }
+
+ ///
+ /// Validate a DipSwitch
+ ///
+ private static void Validate(Models.Listxml.DipSwitch? dipswitch)
+ {
+ Assert.NotNull(dipswitch);
+ Assert.Equal("XXXXXX", dipswitch.Name);
+ Assert.Equal("XXXXXX", dipswitch.Tag);
+ Assert.Equal("XXXXXX", dipswitch.Mask);
+ Validate(dipswitch.Condition);
+
+ Assert.NotNull(dipswitch.DipLocation);
+ var diplocation = Assert.Single(dipswitch.DipLocation);
+ Validate(diplocation);
+
+ Assert.NotNull(dipswitch.DipValue);
+ var dipvalue = Assert.Single(dipswitch.DipValue);
+ Validate(dipvalue);
+ }
+
+ ///
+ /// Validate a Condition
+ ///
+ private static void Validate(Models.Listxml.Condition? condition)
+ {
+ Assert.NotNull(condition);
+ Assert.Equal("XXXXXX", condition.Tag);
+ Assert.Equal("XXXXXX", condition.Mask);
+ Assert.Equal("XXXXXX", condition.Relation);
+ Assert.Equal("XXXXXX", condition.Value);
+ }
+
+ ///
+ /// Validate a DipLocation
+ ///
+ private static void Validate(Models.Listxml.DipLocation? diplocation)
+ {
+ Assert.NotNull(diplocation);
+ Assert.Equal("XXXXXX", diplocation.Name);
+ Assert.Equal("XXXXXX", diplocation.Number);
+ Assert.Equal("XXXXXX", diplocation.Inverted);
+ }
+
+ ///
+ /// Validate a DipValue
+ ///
+ private static void Validate(Models.Listxml.DipValue? dipvalue)
+ {
+ Assert.NotNull(dipvalue);
+ Assert.Equal("XXXXXX", dipvalue.Name);
+ Assert.Equal("XXXXXX", dipvalue.Value);
+ Assert.Equal("XXXXXX", dipvalue.Default);
+ Validate(dipvalue.Condition);
+ }
+
+ ///
+ /// Validate a Configuration
+ ///
+ private static void Validate(Models.Listxml.Configuration? configuration)
+ {
+ Assert.NotNull(configuration);
+ Assert.Equal("XXXXXX", configuration.Name);
+ Assert.Equal("XXXXXX", configuration.Tag);
+ Assert.Equal("XXXXXX", configuration.Mask);
+ Validate(configuration.Condition);
+
+ Assert.NotNull(configuration.ConfLocation);
+ var conflocation = Assert.Single(configuration.ConfLocation);
+ Validate(conflocation);
+
+ Assert.NotNull(configuration.ConfSetting);
+ var confsetting = Assert.Single(configuration.ConfSetting);
+ Validate(confsetting);
+ }
+
+ ///
+ /// Validate a ConfLocation
+ ///
+ private static void Validate(Models.Listxml.ConfLocation? conflocation)
+ {
+ Assert.NotNull(conflocation);
+ Assert.Equal("XXXXXX", conflocation.Name);
+ Assert.Equal("XXXXXX", conflocation.Number);
+ Assert.Equal("XXXXXX", conflocation.Inverted);
+ }
+
+ ///
+ /// Validate a ConfSetting
+ ///
+ private static void Validate(Models.Listxml.ConfSetting? confsetting)
+ {
+ Assert.NotNull(confsetting);
+ Assert.Equal("XXXXXX", confsetting.Name);
+ Assert.Equal("XXXXXX", confsetting.Value);
+ Assert.Equal("XXXXXX", confsetting.Default);
+ Validate(confsetting.Condition);
+ }
+
+ ///
+ /// Validate a Port
+ ///
+ private static void Validate(Models.Listxml.Port? port)
+ {
+ Assert.NotNull(port);
+ Assert.Equal("XXXXXX", port.Tag);
+
+ Assert.NotNull(port.Analog);
+ var analog = Assert.Single(port.Analog);
+ Validate(analog);
+ }
+
+ ///
+ /// Validate a Analog
+ ///
+ private static void Validate(Models.Listxml.Analog? analog)
+ {
+ Assert.NotNull(analog);
+ Assert.Equal("XXXXXX", analog.Mask);
+ }
+
+ ///
+ /// Validate a Adjuster
+ ///
+ private static void Validate(Models.Listxml.Adjuster? adjuster)
+ {
+ Assert.NotNull(adjuster);
+ Assert.Equal("XXXXXX", adjuster.Name);
+ Assert.Equal("XXXXXX", adjuster.Default);
+ Validate(adjuster.Condition);
+ }
+
+ ///
+ /// Validate a Driver
+ ///
+ private static void Validate(Models.Listxml.Driver? driver)
+ {
+ Assert.NotNull(driver);
+ Assert.Equal("XXXXXX", driver.Status);
+ Assert.Equal("XXXXXX", driver.Color);
+ Assert.Equal("XXXXXX", driver.Sound);
+ Assert.Equal("XXXXXX", driver.PaletteSize);
+ Assert.Equal("XXXXXX", driver.Emulation);
+ Assert.Equal("XXXXXX", driver.Cocktail);
+ Assert.Equal("XXXXXX", driver.SaveState);
+ Assert.Equal("XXXXXX", driver.RequiresArtwork);
+ Assert.Equal("XXXXXX", driver.Unofficial);
+ Assert.Equal("XXXXXX", driver.NoSoundHardware);
+ Assert.Equal("XXXXXX", driver.Incomplete);
+ }
+
+ ///
+ /// Validate a Feature
+ ///
+ private static void Validate(Models.Listxml.Feature? feature)
+ {
+ Assert.NotNull(feature);
+ Assert.Equal("XXXXXX", feature.Type);
+ Assert.Equal("XXXXXX", feature.Status);
+ Assert.Equal("XXXXXX", feature.Overall);
+ }
+
+ ///
+ /// Validate a Device
+ ///
+ private static void Validate(Models.Listxml.Device? device)
+ {
+ Assert.NotNull(device);
+ Assert.Equal("XXXXXX", device.Type);
+ Assert.Equal("XXXXXX", device.Tag);
+ Assert.Equal("XXXXXX", device.FixedImage);
+ Assert.Equal("XXXXXX", device.Mandatory);
+ Assert.Equal("XXXXXX", device.Interface);
+ Validate(device.Instance);
+
+ Assert.NotNull(device.Extension);
+ var extension = Assert.Single(device.Extension);
+ Validate(extension);
+ }
+
+ ///
+ /// Validate a Instance
+ ///
+ private static void Validate(Models.Listxml.Instance? instance)
+ {
+ Assert.NotNull(instance);
+ Assert.Equal("XXXXXX", instance.Name);
+ Assert.Equal("XXXXXX", instance.BriefName);
+ }
+
+ ///
+ /// Validate a Extension
+ ///
+ private static void Validate(Models.Listxml.Extension? extension)
+ {
+ Assert.NotNull(extension);
+ Assert.Equal("XXXXXX", extension.Name);
+ }
+
+ ///
+ /// Validate a Slot
+ ///
+ private static void Validate(Models.Listxml.Slot? slot)
+ {
+ Assert.NotNull(slot);
+ Assert.Equal("XXXXXX", slot.Name);
+
+ Assert.NotNull(slot.SlotOption);
+ var slotoption = Assert.Single(slot.SlotOption);
+ Validate(slotoption);
+ }
+
+ ///
+ /// Validate a SlotOption
+ ///
+ private static void Validate(Models.Listxml.SlotOption? slotoption)
+ {
+ Assert.NotNull(slotoption);
+ Assert.Equal("XXXXXX", slotoption.Name);
+ Assert.Equal("XXXXXX", slotoption.DevName);
+ Assert.Equal("XXXXXX", slotoption.Default);
+ }
+
+ ///
+ /// Validate a SoftwareList
+ ///
+ private static void Validate(Models.Listxml.SoftwareList? softwarelist)
+ {
+ Assert.NotNull(softwarelist);
+ Assert.Equal("XXXXXX", softwarelist.Tag);
+ Assert.Equal("XXXXXX", softwarelist.Name);
+ Assert.Equal("XXXXXX", softwarelist.Status);
+ Assert.Equal("XXXXXX", softwarelist.Filter);
+ }
+
+ ///
+ /// Validate a RamOption
+ ///
+ private static void Validate(Models.Listxml.RamOption? ramoption)
+ {
+ Assert.NotNull(ramoption);
+ Assert.Equal("XXXXXX", ramoption.Name);
+ Assert.Equal("XXXXXX", ramoption.Default);
+ Assert.Equal("XXXXXX", ramoption.Content);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/LogiqxTests.cs b/SabreTools.Serialization.Test/CrossModel/LogiqxTests.cs
new file mode 100644
index 00000000..425fd0d4
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/LogiqxTests.cs
@@ -0,0 +1,545 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class LogiqxTests
+ {
+ [Fact]
+ public void RoundTripGameTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Logiqx();
+
+ // Build the data
+ Models.Logiqx.Datafile df = Build(game: true);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(df);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Logiqx.Datafile? newDf = serializer.Deserialize(metadata, game: true);
+
+ // Validate the data
+ Assert.NotNull(newDf);
+ Assert.Equal("XXXXXX", newDf.Build);
+ Assert.Equal("XXXXXX", newDf.Debug);
+ Assert.Equal("XXXXXX", newDf.SchemaLocation);
+ Validate(newDf.Header);
+
+ Assert.NotNull(newDf.Game);
+ var newGame = Assert.Single(newDf.Game);
+ Validate(newGame);
+
+ // TODO: Unsupported
+ Assert.Null(newDf.Dir);
+ }
+
+ [Fact]
+ public void RoundTripMachineTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.Logiqx();
+
+ // Build the data
+ Models.Logiqx.Datafile df = Build(game: false);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(df);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Logiqx.Datafile? newDf = serializer.Deserialize(metadata, game: false);
+
+ // Validate the data
+ Assert.NotNull(newDf);
+ Assert.Equal("XXXXXX", newDf.Build);
+ Assert.Equal("XXXXXX", newDf.Debug);
+ Assert.Equal("XXXXXX", newDf.SchemaLocation);
+ Validate(newDf.Header);
+
+ Assert.NotNull(newDf.Game);
+ var newGame = Assert.Single(newDf.Game);
+ Validate(newGame);
+
+ // TODO: Unsupported
+ Assert.Null(newDf.Dir);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.Logiqx.Datafile Build(bool game)
+ {
+ var clrmamepro = new Models.Logiqx.ClrMamePro
+ {
+ Header = "XXXXXX",
+ ForceMerging = "XXXXXX",
+ ForceNodump = "XXXXXX",
+ ForcePacking = "XXXXXX",
+ };
+
+ var romcenter = new Models.Logiqx.RomCenter
+ {
+ Plugin = "XXXXXX",
+ RomMode = "XXXXXX",
+ BiosMode = "XXXXXX",
+ SampleMode = "XXXXXX",
+ LockRomMode = "XXXXXX",
+ LockBiosMode = "XXXXXX",
+ LockSampleMode = "XXXXXX",
+ };
+
+ var header = new Models.Logiqx.Header
+ {
+ Id = "XXXXXX",
+ Name = "XXXXXX",
+ Description = "XXXXXX",
+ RootDir = "XXXXXX",
+ Category = "XXXXXX",
+ Version = "XXXXXX",
+ Date = "XXXXXX",
+ Author = "XXXXXX",
+ Email = "XXXXXX",
+ Homepage = "XXXXXX",
+ Url = "XXXXXX",
+ Comment = "XXXXXX",
+ Type = "XXXXXX",
+ ClrMamePro = clrmamepro,
+ RomCenter = romcenter,
+ };
+
+ var trurip = new Models.Logiqx.Trurip
+ {
+ TitleID = "XXXXXX",
+ Publisher = "XXXXXX",
+ Developer = "XXXXXX",
+ Year = "XXXXXX",
+ Genre = "XXXXXX",
+ Subgenre = "XXXXXX",
+ Ratings = "XXXXXX",
+ Score = "XXXXXX",
+ Players = "XXXXXX",
+ Enabled = "XXXXXX",
+ CRC = "XXXXXX",
+ Source = "XXXXXX",
+ CloneOf = "XXXXXX",
+ RelatedTo = "XXXXXX",
+ };
+
+ var release = new Models.Logiqx.Release
+ {
+ Name = "XXXXXX",
+ Region = "XXXXXX",
+ Language = "XXXXXX",
+ Date = "XXXXXX",
+ Default = "XXXXXX",
+ };
+
+ var biosset = new Models.Logiqx.BiosSet
+ {
+ Name = "XXXXXX",
+ Description = "XXXXXX",
+ Default = "XXXXXX",
+ };
+
+ var rom = new Models.Logiqx.Rom
+ {
+ Name = "XXXXXX",
+ Size = "XXXXXX",
+ CRC = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ SHA256 = "XXXXXX",
+ SHA384 = "XXXXXX",
+ SHA512 = "XXXXXX",
+ SpamSum = "XXXXXX",
+ xxHash364 = "XXXXXX",
+ xxHash3128 = "XXXXXX",
+ Merge = "XXXXXX",
+ Status = "XXXXXX",
+ Serial = "XXXXXX",
+ Header = "XXXXXX",
+ Date = "XXXXXX",
+ Inverted = "XXXXXX",
+ MIA = "XXXXXX",
+ };
+
+ var disk = new Models.Logiqx.Disk
+ {
+ Name = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Merge = "XXXXXX",
+ Status = "XXXXXX",
+ Region = "XXXXXX",
+ };
+
+ var media = new Models.Logiqx.Media
+ {
+ Name = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ SHA256 = "XXXXXX",
+ SpamSum = "XXXXXX",
+ };
+
+ var deviceRef = new Models.Logiqx.DeviceRef
+ {
+ Name = "XXXXXX",
+ };
+
+ var sample = new Models.Logiqx.Sample
+ {
+ Name = "XXXXXX",
+ };
+
+ var archive = new Models.Logiqx.Archive
+ {
+ Name = "XXXXXX",
+ };
+
+ var driver = new Models.Logiqx.Driver
+ {
+ Status = "XXXXXX",
+ Emulation = "XXXXXX",
+ Cocktail = "XXXXXX",
+ SaveState = "XXXXXX",
+ RequiresArtwork = "XXXXXX",
+ Unofficial = "XXXXXX",
+ NoSoundHardware = "XXXXXX",
+ Incomplete = "XXXXXX",
+ };
+
+ var softwarelist = new Models.Logiqx.SoftwareList
+ {
+ Tag = "XXXXXX",
+ Name = "XXXXXX",
+ Status = "XXXXXX",
+ Filter = "XXXXXX",
+ };
+
+ Models.Logiqx.GameBase gameBase = game
+ ? new Models.Logiqx.Game()
+ : new Models.Logiqx.Machine();
+ gameBase.Name = "XXXXXX";
+ gameBase.SourceFile = "XXXXXX";
+ gameBase.IsBios = "XXXXXX";
+ gameBase.IsDevice = "XXXXXX";
+ gameBase.IsMechanical = "XXXXXX";
+ gameBase.CloneOf = "XXXXXX";
+ gameBase.RomOf = "XXXXXX";
+ gameBase.SampleOf = "XXXXXX";
+ gameBase.Board = "XXXXXX";
+ gameBase.RebuildTo = "XXXXXX";
+ gameBase.Id = "XXXXXX";
+ gameBase.CloneOfId = "XXXXXX";
+ gameBase.Runnable = "XXXXXX";
+ gameBase.Comment = ["XXXXXX"];
+ gameBase.Description = "XXXXXX";
+ gameBase.Year = "XXXXXX";
+ gameBase.Manufacturer = "XXXXXX";
+ gameBase.Publisher = "XXXXXX";
+ gameBase.Category = ["XXXXXX"];
+ gameBase.Trurip = trurip;
+ gameBase.Release = [release];
+ gameBase.BiosSet = [biosset];
+ gameBase.Rom = [rom];
+ gameBase.Disk = [disk];
+ gameBase.Media = [media];
+ gameBase.DeviceRef = [deviceRef];
+ gameBase.Sample = [sample];
+ gameBase.Archive = [archive];
+ gameBase.Driver = driver;
+ gameBase.SoftwareList = [softwarelist];
+
+ return new Models.Logiqx.Datafile
+ {
+ Build = "XXXXXX",
+ Debug = "XXXXXX",
+ SchemaLocation = "XXXXXX",
+ Header = header,
+ Game = [gameBase],
+ // Dir = [dir], // TODO: Unsupported
+ };
+ }
+
+ ///
+ /// Validate a Header
+ ///
+ private static void Validate(Models.Logiqx.Header? header)
+ {
+ Assert.NotNull(header);
+ Assert.Equal("XXXXXX", header.Id);
+ Assert.Equal("XXXXXX", header.Name);
+ Assert.Equal("XXXXXX", header.Description);
+ Assert.Equal("XXXXXX", header.RootDir);
+ Assert.Equal("XXXXXX", header.Category);
+ Assert.Equal("XXXXXX", header.Version);
+ Assert.Equal("XXXXXX", header.Date);
+ Assert.Equal("XXXXXX", header.Author);
+ Assert.Equal("XXXXXX", header.Email);
+ Assert.Equal("XXXXXX", header.Homepage);
+ Assert.Equal("XXXXXX", header.Url);
+ Assert.Equal("XXXXXX", header.Comment);
+ Assert.Equal("XXXXXX", header.Type);
+ Validate(header.ClrMamePro);
+ Validate(header.RomCenter);
+ }
+
+ ///
+ /// Validate a ClrMamePro
+ ///
+ private static void Validate(Models.Logiqx.ClrMamePro? cmp)
+ {
+ Assert.NotNull(cmp);
+ Assert.Equal("XXXXXX", cmp.Header);
+ Assert.Equal("XXXXXX", cmp.ForceMerging);
+ Assert.Equal("XXXXXX", cmp.ForceNodump);
+ Assert.Equal("XXXXXX", cmp.ForcePacking);
+ }
+
+ ///
+ /// Validate a RomCenter
+ ///
+ private static void Validate(Models.Logiqx.RomCenter? rc)
+ {
+ Assert.NotNull(rc);
+ Assert.Equal("XXXXXX", rc.Plugin);
+ Assert.Equal("XXXXXX", rc.RomMode);
+ Assert.Equal("XXXXXX", rc.BiosMode);
+ Assert.Equal("XXXXXX", rc.SampleMode);
+ Assert.Equal("XXXXXX", rc.LockRomMode);
+ Assert.Equal("XXXXXX", rc.LockBiosMode);
+ Assert.Equal("XXXXXX", rc.LockSampleMode);
+ }
+
+ ///
+ /// Validate a GameBase
+ ///
+ private static void Validate(Models.Logiqx.GameBase? gb)
+ {
+ Assert.NotNull(gb);
+ Assert.Equal("XXXXXX", gb.Name);
+ Assert.Equal("XXXXXX", gb.SourceFile);
+ Assert.Equal("XXXXXX", gb.IsBios);
+ Assert.Equal("XXXXXX", gb.IsDevice);
+ Assert.Equal("XXXXXX", gb.IsMechanical);
+ Assert.Equal("XXXXXX", gb.CloneOf);
+ Assert.Equal("XXXXXX", gb.RomOf);
+ Assert.Equal("XXXXXX", gb.SampleOf);
+ Assert.Equal("XXXXXX", gb.Board);
+ Assert.Equal("XXXXXX", gb.RebuildTo);
+ Assert.Equal("XXXXXX", gb.Id);
+ Assert.Equal("XXXXXX", gb.CloneOfId);
+ Assert.Equal("XXXXXX", gb.Runnable);
+
+ Assert.NotNull(gb.Comment);
+ string comment = Assert.Single(gb.Comment);
+ Assert.Equal("XXXXXX", comment);
+
+ Assert.Equal("XXXXXX", gb.Description);
+ Assert.Equal("XXXXXX", gb.Year);
+ Assert.Equal("XXXXXX", gb.Manufacturer);
+ Assert.Equal("XXXXXX", gb.Publisher);
+
+ Assert.NotNull(gb.Category);
+ string category = Assert.Single(gb.Category);
+ Assert.Equal("XXXXXX", category);
+
+ Validate(gb.Trurip);
+
+ Assert.NotNull(gb.Release);
+ var release = Assert.Single(gb.Release);
+ Validate(release);
+
+ Assert.NotNull(gb.BiosSet);
+ var biosset = Assert.Single(gb.BiosSet);
+ Validate(biosset);
+
+ Assert.NotNull(gb.Rom);
+ var rom = Assert.Single(gb.Rom);
+ Validate(rom);
+
+ Assert.NotNull(gb.Disk);
+ var disk = Assert.Single(gb.Disk);
+ Validate(disk);
+
+ Assert.NotNull(gb.Media);
+ var media = Assert.Single(gb.Media);
+ Validate(media);
+
+ Assert.NotNull(gb.DeviceRef);
+ var deviceref = Assert.Single(gb.DeviceRef);
+ Validate(deviceref);
+
+ Assert.NotNull(gb.Sample);
+ var sample = Assert.Single(gb.Sample);
+ Validate(sample);
+
+ Assert.NotNull(gb.Archive);
+ var archive = Assert.Single(gb.Archive);
+ Validate(archive);
+
+ Validate(gb.Driver);
+
+ Assert.NotNull(gb.SoftwareList);
+ var softwarelist = Assert.Single(gb.SoftwareList);
+ Validate(softwarelist);
+ }
+
+ ///
+ /// Validate a Trurip
+ ///
+ private static void Validate(Models.Logiqx.Trurip? trurip)
+ {
+ Assert.NotNull(trurip);
+ Assert.Equal("XXXXXX", trurip.TitleID);
+ Assert.Equal("XXXXXX", trurip.Publisher);
+ Assert.Equal("XXXXXX", trurip.Developer);
+ Assert.Equal("XXXXXX", trurip.Year);
+ Assert.Equal("XXXXXX", trurip.Genre);
+ Assert.Equal("XXXXXX", trurip.Subgenre);
+ Assert.Equal("XXXXXX", trurip.Ratings);
+ Assert.Equal("XXXXXX", trurip.Score);
+ Assert.Equal("XXXXXX", trurip.Players);
+ Assert.Equal("XXXXXX", trurip.Enabled);
+ Assert.Equal("XXXXXX", trurip.CRC);
+ Assert.Equal("XXXXXX", trurip.Source);
+ Assert.Equal("XXXXXX", trurip.CloneOf);
+ Assert.Equal("XXXXXX", trurip.RelatedTo);
+ }
+
+ ///
+ /// Validate a Release
+ ///
+ private static void Validate(Models.Logiqx.Release? release)
+ {
+ Assert.NotNull(release);
+ Assert.Equal("XXXXXX", release.Name);
+ Assert.Equal("XXXXXX", release.Region);
+ Assert.Equal("XXXXXX", release.Language);
+ Assert.Equal("XXXXXX", release.Date);
+ Assert.Equal("XXXXXX", release.Default);
+ }
+
+ ///
+ /// Validate a BiosSet
+ ///
+ private static void Validate(Models.Logiqx.BiosSet? biosset)
+ {
+ Assert.NotNull(biosset);
+ Assert.Equal("XXXXXX", biosset.Name);
+ Assert.Equal("XXXXXX", biosset.Description);
+ Assert.Equal("XXXXXX", biosset.Default);
+ }
+
+ ///
+ /// Validate a Rom
+ ///
+ private static void Validate(Models.Logiqx.Rom? rom)
+ {
+ Assert.NotNull(rom);
+ Assert.Equal("XXXXXX", rom.Name);
+ Assert.Equal("XXXXXX", rom.Size);
+ Assert.Equal("XXXXXX", rom.CRC);
+ Assert.Equal("XXXXXX", rom.MD5);
+ Assert.Equal("XXXXXX", rom.SHA1);
+ Assert.Equal("XXXXXX", rom.SHA256);
+ Assert.Equal("XXXXXX", rom.SHA384);
+ Assert.Equal("XXXXXX", rom.SHA512);
+ Assert.Equal("XXXXXX", rom.SpamSum);
+ Assert.Equal("XXXXXX", rom.xxHash364);
+ Assert.Equal("XXXXXX", rom.xxHash3128);
+ Assert.Equal("XXXXXX", rom.Merge);
+ Assert.Equal("XXXXXX", rom.Status);
+ Assert.Equal("XXXXXX", rom.Serial);
+ Assert.Equal("XXXXXX", rom.Header);
+ Assert.Equal("XXXXXX", rom.Date);
+ Assert.Equal("XXXXXX", rom.Inverted);
+ Assert.Equal("XXXXXX", rom.MIA);
+ }
+
+ ///
+ /// Validate a Disk
+ ///
+ private static void Validate(Models.Logiqx.Disk? disk)
+ {
+ Assert.NotNull(disk);
+ Assert.Equal("XXXXXX", disk.Name);
+ Assert.Equal("XXXXXX", disk.MD5);
+ Assert.Equal("XXXXXX", disk.SHA1);
+ Assert.Equal("XXXXXX", disk.Merge);
+ Assert.Equal("XXXXXX", disk.Status);
+ Assert.Equal("XXXXXX", disk.Region);
+ }
+
+ ///
+ /// Validate a Media
+ ///
+ private static void Validate(Models.Logiqx.Media? media)
+ {
+ Assert.NotNull(media);
+ Assert.Equal("XXXXXX", media.Name);
+ Assert.Equal("XXXXXX", media.MD5);
+ Assert.Equal("XXXXXX", media.SHA1);
+ Assert.Equal("XXXXXX", media.SHA256);
+ Assert.Equal("XXXXXX", media.SpamSum);
+ }
+
+ ///
+ /// Validate a DeviceRef
+ ///
+ private static void Validate(Models.Logiqx.DeviceRef? deviceref)
+ {
+ Assert.NotNull(deviceref);
+ Assert.Equal("XXXXXX", deviceref.Name);
+ }
+
+ ///
+ /// Validate a Sample
+ ///
+ private static void Validate(Models.Logiqx.Sample? sample)
+ {
+ Assert.NotNull(sample);
+ Assert.Equal("XXXXXX", sample.Name);
+ }
+
+ ///
+ /// Validate a Archive
+ ///
+ private static void Validate(Models.Logiqx.Archive? archive)
+ {
+ Assert.NotNull(archive);
+ Assert.Equal("XXXXXX", archive.Name);
+ }
+
+ ///
+ /// Validate a Driver
+ ///
+ private static void Validate(Models.Logiqx.Driver? driver)
+ {
+ Assert.NotNull(driver);
+ Assert.Equal("XXXXXX", driver.Status);
+ Assert.Equal("XXXXXX", driver.Emulation);
+ Assert.Equal("XXXXXX", driver.Cocktail);
+ Assert.Equal("XXXXXX", driver.SaveState);
+ Assert.Equal("XXXXXX", driver.RequiresArtwork);
+ Assert.Equal("XXXXXX", driver.Unofficial);
+ Assert.Equal("XXXXXX", driver.NoSoundHardware);
+ Assert.Equal("XXXXXX", driver.Incomplete);
+ }
+
+ ///
+ /// Validate a SoftwareList
+ ///
+ private static void Validate(Models.Logiqx.SoftwareList? softwarelist)
+ {
+ Assert.NotNull(softwarelist);
+ Assert.Equal("XXXXXX", softwarelist.Tag);
+ Assert.Equal("XXXXXX", softwarelist.Name);
+ Assert.Equal("XXXXXX", softwarelist.Status);
+ Assert.Equal("XXXXXX", softwarelist.Filter);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/M1Tests.cs b/SabreTools.Serialization.Test/CrossModel/M1Tests.cs
new file mode 100644
index 00000000..6dac112b
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/M1Tests.cs
@@ -0,0 +1,872 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class M1Tests
+ {
+ [Fact]
+ public void RoundTripGameTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.M1();
+
+ // Build the data
+ Models.Listxml.M1 m1 = Build(game: true);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(m1);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Listxml.M1? newM1 = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newM1);
+ Assert.Equal("XXXXXX", newM1.Version);
+
+ Assert.NotNull(newM1.Game);
+ var newGame = Assert.Single(newM1.Game);
+ Validate(newGame);
+ }
+
+ [Fact]
+ public void RoundTripMachineTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.M1();
+
+ // Build the data
+ Models.Listxml.M1 m1 = Build(game: false);
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(m1);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.Listxml.M1? newM1 = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newM1);
+ Assert.Equal("XXXXXX", newM1.Version);
+
+ Assert.NotNull(newM1.Game);
+ var newGame = Assert.Single(newM1.Game);
+ Validate(newGame);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.Listxml.M1 Build(bool game)
+ {
+ var biosset = new Models.Listxml.BiosSet
+ {
+ Name = "XXXXXX",
+ Description = "XXXXXX",
+ Default = "XXXXXX",
+ };
+
+ var rom = new Models.Listxml.Rom
+ {
+ Name = "XXXXXX",
+ Bios = "XXXXXX",
+ Size = "XXXXXX",
+ CRC = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Merge = "XXXXXX",
+ Region = "XXXXXX",
+ Offset = "XXXXXX",
+ Status = "XXXXXX",
+ Optional = "XXXXXX",
+ Dispose = "XXXXXX",
+ SoundOnly = "XXXXXX",
+ };
+
+ var disk = new Models.Listxml.Disk
+ {
+ Name = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Merge = "XXXXXX",
+ Region = "XXXXXX",
+ Index = "XXXXXX",
+ Writable = "XXXXXX",
+ Status = "XXXXXX",
+ Optional = "XXXXXX",
+ };
+
+ var deviceref = new Models.Listxml.DeviceRef
+ {
+ Name = "XXXXXX",
+ };
+
+ var sample = new Models.Listxml.Sample
+ {
+ Name = "XXXXXX",
+ };
+
+ var chip = new Models.Listxml.Chip
+ {
+ Name = "XXXXXX",
+ Tag = "XXXXXX",
+ Type = "XXXXXX",
+ SoundOnly = "XXXXXX",
+ Clock = "XXXXXX",
+ };
+
+ var display = new Models.Listxml.Display
+ {
+ Tag = "XXXXXX",
+ Type = "XXXXXX",
+ Rotate = "XXXXXX",
+ FlipX = "XXXXXX",
+ Width = "XXXXXX",
+ Height = "XXXXXX",
+ Refresh = "XXXXXX",
+ PixClock = "XXXXXX",
+ HTotal = "XXXXXX",
+ HBEnd = "XXXXXX",
+ HBStart = "XXXXXX",
+ VTotal = "XXXXXX",
+ VBEnd = "XXXXXX",
+ VBStart = "XXXXXX",
+ };
+
+ var video = new Models.Listxml.Video
+ {
+ Screen = "XXXXXX",
+ Orientation = "XXXXXX",
+ Width = "XXXXXX",
+ Height = "XXXXXX",
+ AspectX = "XXXXXX",
+ AspectY = "XXXXXX",
+ Refresh = "XXXXXX",
+ };
+
+ var sound = new Models.Listxml.Sound
+ {
+ Channels = "XXXXXX",
+ };
+
+ var control = new Models.Listxml.Control
+ {
+ Type = "XXXXXX",
+ Player = "XXXXXX",
+ Buttons = "XXXXXX",
+ ReqButtons = "XXXXXX",
+ Minimum = "XXXXXX",
+ Maximum = "XXXXXX",
+ Sensitivity = "XXXXXX",
+ KeyDelta = "XXXXXX",
+ Reverse = "XXXXXX",
+ Ways = "XXXXXX",
+ Ways2 = "XXXXXX",
+ Ways3 = "XXXXXX",
+ };
+
+ var input = new Models.Listxml.Input
+ {
+ Service = "XXXXXX",
+ Tilt = "XXXXXX",
+ Players = "XXXXXX",
+ //ControlAttr = "XXXXXX", // Mututally exclusive with input.Control
+ Buttons = "XXXXXX",
+ Coins = "XXXXXX",
+ Control = [control],
+ };
+
+ var condition = new Models.Listxml.Condition
+ {
+ Tag = "XXXXXX",
+ Mask = "XXXXXX",
+ Relation = "XXXXXX",
+ Value = "XXXXXX",
+ };
+
+ var diplocation = new Models.Listxml.DipLocation
+ {
+ Name = "XXXXXX",
+ Number = "XXXXXX",
+ Inverted = "XXXXXX",
+ };
+
+ var dipvalue = new Models.Listxml.DipValue
+ {
+ Name = "XXXXXX",
+ Value = "XXXXXX",
+ Default = "XXXXXX",
+ Condition = condition,
+ };
+
+ var dipswitch = new Models.Listxml.DipSwitch
+ {
+ Name = "XXXXXX",
+ Tag = "XXXXXX",
+ Mask = "XXXXXX",
+ Condition = condition,
+ DipLocation = [diplocation],
+ DipValue = [dipvalue],
+ };
+
+ var conflocation = new Models.Listxml.ConfLocation
+ {
+ Name = "XXXXXX",
+ Number = "XXXXXX",
+ Inverted = "XXXXXX",
+ };
+
+ var confsetting = new Models.Listxml.ConfSetting
+ {
+ Name = "XXXXXX",
+ Value = "XXXXXX",
+ Default = "XXXXXX",
+ Condition = condition,
+ };
+
+ var configuration = new Models.Listxml.Configuration
+ {
+ Name = "XXXXXX",
+ Tag = "XXXXXX",
+ Mask = "XXXXXX",
+ Condition = condition,
+ ConfLocation = [conflocation],
+ ConfSetting = [confsetting],
+ };
+
+ var analog = new Models.Listxml.Analog
+ {
+ Mask = "XXXXXX",
+ };
+
+ var port = new Models.Listxml.Port
+ {
+ Tag = "XXXXXX",
+ Analog = [analog],
+ };
+
+ var adjuster = new Models.Listxml.Adjuster
+ {
+ Name = "XXXXXX",
+ Default = "XXXXXX",
+ Condition = condition,
+ };
+
+ var driver = new Models.Listxml.Driver
+ {
+ Status = "XXXXXX",
+ Color = "XXXXXX",
+ Sound = "XXXXXX",
+ PaletteSize = "XXXXXX",
+ Emulation = "XXXXXX",
+ Cocktail = "XXXXXX",
+ SaveState = "XXXXXX",
+ RequiresArtwork = "XXXXXX",
+ Unofficial = "XXXXXX",
+ NoSoundHardware = "XXXXXX",
+ Incomplete = "XXXXXX",
+ };
+
+ var feature = new Models.Listxml.Feature
+ {
+ Type = "XXXXXX",
+ Status = "XXXXXX",
+ Overall = "XXXXXX",
+ };
+
+ var instance = new Models.Listxml.Instance
+ {
+ Name = "XXXXXX",
+ BriefName = "XXXXXX",
+ };
+
+ var extension = new Models.Listxml.Extension
+ {
+ Name = "XXXXXX",
+ };
+
+ var device = new Models.Listxml.Device
+ {
+ Type = "XXXXXX",
+ Tag = "XXXXXX",
+ FixedImage = "XXXXXX",
+ Mandatory = "XXXXXX",
+ Interface = "XXXXXX",
+ Instance = instance,
+ Extension = [extension],
+ };
+
+ var slotOption = new Models.Listxml.SlotOption
+ {
+ Name = "XXXXXX",
+ DevName = "XXXXXX",
+ Default = "XXXXXX",
+ };
+
+ var slot = new Models.Listxml.Slot
+ {
+ Name = "XXXXXX",
+ SlotOption = [slotOption],
+ };
+
+ var softwarelist = new Models.Listxml.SoftwareList
+ {
+ Tag = "XXXXXX",
+ Name = "XXXXXX",
+ Status = "XXXXXX",
+ Filter = "XXXXXX",
+ };
+
+ var ramoption = new Models.Listxml.RamOption
+ {
+ Name = "XXXXXX",
+ Default = "XXXXXX",
+ Content = "XXXXXX",
+ };
+
+ Models.Listxml.GameBase gameBase = game
+ ? new Models.Listxml.Game()
+ : new Models.Listxml.Machine();
+ gameBase.Name = "XXXXXX";
+ gameBase.SourceFile = "XXXXXX";
+ gameBase.IsBios = "XXXXXX";
+ gameBase.IsDevice = "XXXXXX";
+ gameBase.IsMechanical = "XXXXXX";
+ gameBase.Runnable = "XXXXXX";
+ gameBase.CloneOf = "XXXXXX";
+ gameBase.RomOf = "XXXXXX";
+ gameBase.SampleOf = "XXXXXX";
+ gameBase.Description = "XXXXXX";
+ gameBase.Year = "XXXXXX";
+ gameBase.Manufacturer = "XXXXXX";
+ gameBase.History = "XXXXXX";
+ gameBase.BiosSet = [biosset];
+ gameBase.Rom = [rom];
+ gameBase.Disk = [disk];
+ gameBase.DeviceRef = [deviceref];
+ gameBase.Sample = [sample];
+ gameBase.Chip = [chip];
+ gameBase.Display = [display];
+ gameBase.Video = [video];
+ gameBase.Sound = sound;
+ gameBase.Input = input;
+ gameBase.DipSwitch = [dipswitch];
+ gameBase.Configuration = [configuration];
+ gameBase.Port = [port];
+ gameBase.Adjuster = [adjuster];
+ gameBase.Driver = driver;
+ gameBase.Feature = [feature];
+ gameBase.Device = [device];
+ gameBase.Slot = [slot];
+ gameBase.SoftwareList = [softwarelist];
+ gameBase.RamOption = [ramoption];
+
+ return new Models.Listxml.M1
+ {
+ Version = "XXXXXX",
+ Game = [gameBase],
+ };
+ }
+
+ ///
+ /// Validate a GameBase
+ ///
+ private static void Validate(Models.Listxml.GameBase? gb)
+ {
+ Assert.NotNull(gb);
+ Assert.Equal("XXXXXX", gb.Name);
+ Assert.Equal("XXXXXX", gb.SourceFile);
+ Assert.Equal("XXXXXX", gb.IsBios);
+ Assert.Equal("XXXXXX", gb.IsDevice);
+ Assert.Equal("XXXXXX", gb.IsMechanical);
+ Assert.Equal("XXXXXX", gb.Runnable);
+ Assert.Equal("XXXXXX", gb.CloneOf);
+ Assert.Equal("XXXXXX", gb.RomOf);
+ Assert.Equal("XXXXXX", gb.SampleOf);
+ Assert.Equal("XXXXXX", gb.Description);
+ Assert.Equal("XXXXXX", gb.Year);
+ Assert.Equal("XXXXXX", gb.Manufacturer);
+ Assert.Equal("XXXXXX", gb.History);
+
+ Assert.NotNull(gb.BiosSet);
+ var biosset = Assert.Single(gb.BiosSet);
+ Validate(biosset);
+
+ Assert.NotNull(gb.Rom);
+ var rom = Assert.Single(gb.Rom);
+ Validate(rom);
+
+ Assert.NotNull(gb.Disk);
+ var disk = Assert.Single(gb.Disk);
+ Validate(disk);
+
+ Assert.NotNull(gb.DeviceRef);
+ var deviceref = Assert.Single(gb.DeviceRef);
+ Validate(deviceref);
+
+ Assert.NotNull(gb.Sample);
+ var sample = Assert.Single(gb.Sample);
+ Validate(sample);
+
+ Assert.NotNull(gb.Chip);
+ var chip = Assert.Single(gb.Chip);
+ Validate(chip);
+
+ Assert.NotNull(gb.Display);
+ var display = Assert.Single(gb.Display);
+ Validate(display);
+
+ Assert.NotNull(gb.Video);
+ var video = Assert.Single(gb.Video);
+ Validate(video);
+
+ Validate(gb.Sound);
+ Validate(gb.Input);
+
+ Assert.NotNull(gb.DipSwitch);
+ var dipswitch = Assert.Single(gb.DipSwitch);
+ Validate(dipswitch);
+
+ Assert.NotNull(gb.Configuration);
+ var configuration = Assert.Single(gb.Configuration);
+ Validate(configuration);
+
+ Assert.NotNull(gb.Port);
+ var port = Assert.Single(gb.Port);
+ Validate(port);
+
+ Assert.NotNull(gb.Adjuster);
+ var adjuster = Assert.Single(gb.Adjuster);
+ Validate(adjuster);
+
+ Validate(gb.Driver);
+
+ Assert.NotNull(gb.Feature);
+ var feature = Assert.Single(gb.Feature);
+ Validate(feature);
+
+ Assert.NotNull(gb.Device);
+ var device = Assert.Single(gb.Device);
+ Validate(device);
+
+ Assert.NotNull(gb.Slot);
+ var slot = Assert.Single(gb.Slot);
+ Validate(slot);
+
+ Assert.NotNull(gb.SoftwareList);
+ var softwarelist = Assert.Single(gb.SoftwareList);
+ Validate(softwarelist);
+
+ Assert.NotNull(gb.RamOption);
+ var ramoption = Assert.Single(gb.RamOption);
+ Validate(ramoption);
+ }
+
+ ///
+ /// Validate a BiosSet
+ ///
+ private static void Validate(Models.Listxml.BiosSet? biosset)
+ {
+ Assert.NotNull(biosset);
+ Assert.Equal("XXXXXX", biosset.Name);
+ Assert.Equal("XXXXXX", biosset.Description);
+ Assert.Equal("XXXXXX", biosset.Default);
+ }
+
+ ///
+ /// Validate a Rom
+ ///
+ private static void Validate(Models.Listxml.Rom? rom)
+ {
+ Assert.NotNull(rom);
+ Assert.Equal("XXXXXX", rom.Name);
+ Assert.Equal("XXXXXX", rom.Bios);
+ Assert.Equal("XXXXXX", rom.Size);
+ Assert.Equal("XXXXXX", rom.CRC);
+ Assert.Equal("XXXXXX", rom.SHA1);
+ Assert.Equal("XXXXXX", rom.Merge);
+ Assert.Equal("XXXXXX", rom.Region);
+ Assert.Equal("XXXXXX", rom.Offset);
+ Assert.Equal("XXXXXX", rom.Status);
+ Assert.Equal("XXXXXX", rom.Optional);
+ Assert.Equal("XXXXXX", rom.Dispose);
+ Assert.Equal("XXXXXX", rom.SoundOnly);
+ }
+
+ ///
+ /// Validate a Disk
+ ///
+ private static void Validate(Models.Listxml.Disk? disk)
+ {
+ Assert.NotNull(disk);
+ Assert.Equal("XXXXXX", disk.Name);
+ Assert.Equal("XXXXXX", disk.MD5);
+ Assert.Equal("XXXXXX", disk.SHA1);
+ Assert.Equal("XXXXXX", disk.Merge);
+ Assert.Equal("XXXXXX", disk.Region);
+ Assert.Equal("XXXXXX", disk.Index);
+ Assert.Equal("XXXXXX", disk.Writable);
+ Assert.Equal("XXXXXX", disk.Status);
+ Assert.Equal("XXXXXX", disk.Optional);
+ }
+
+ ///
+ /// Validate a DeviceRef
+ ///
+ private static void Validate(Models.Listxml.DeviceRef? deviceref)
+ {
+ Assert.NotNull(deviceref);
+ Assert.Equal("XXXXXX", deviceref.Name);
+ }
+
+ ///
+ /// Validate a Sample
+ ///
+ private static void Validate(Models.Listxml.Sample? sample)
+ {
+ Assert.NotNull(sample);
+ Assert.Equal("XXXXXX", sample.Name);
+ }
+
+ ///
+ /// Validate a Chip
+ ///
+ private static void Validate(Models.Listxml.Chip? chip)
+ {
+ Assert.NotNull(chip);
+ Assert.Equal("XXXXXX", chip.Name);
+ Assert.Equal("XXXXXX", chip.Tag);
+ Assert.Equal("XXXXXX", chip.Type);
+ Assert.Equal("XXXXXX", chip.SoundOnly);
+ Assert.Equal("XXXXXX", chip.Clock);
+ }
+
+ ///
+ /// Validate a Display
+ ///
+ private static void Validate(Models.Listxml.Display? display)
+ {
+ Assert.NotNull(display);
+ Assert.Equal("XXXXXX", display.Tag);
+ Assert.Equal("XXXXXX", display.Type);
+ Assert.Equal("XXXXXX", display.Rotate);
+ Assert.Equal("XXXXXX", display.FlipX);
+ Assert.Equal("XXXXXX", display.Width);
+ Assert.Equal("XXXXXX", display.Height);
+ Assert.Equal("XXXXXX", display.Refresh);
+ Assert.Equal("XXXXXX", display.PixClock);
+ Assert.Equal("XXXXXX", display.HTotal);
+ Assert.Equal("XXXXXX", display.HBEnd);
+ Assert.Equal("XXXXXX", display.HBStart);
+ Assert.Equal("XXXXXX", display.VTotal);
+ Assert.Equal("XXXXXX", display.VBEnd);
+ Assert.Equal("XXXXXX", display.VBStart);
+ }
+
+ ///
+ /// Validate a Video
+ ///
+ private static void Validate(Models.Listxml.Video? video)
+ {
+ Assert.NotNull(video);
+ Assert.Equal("XXXXXX", video.Screen);
+ Assert.Equal("XXXXXX", video.Orientation);
+ Assert.Equal("XXXXXX", video.Width);
+ Assert.Equal("XXXXXX", video.Height);
+ Assert.Equal("XXXXXX", video.AspectX);
+ Assert.Equal("XXXXXX", video.AspectY);
+ Assert.Equal("XXXXXX", video.Refresh);
+ }
+
+ ///
+ /// Validate a Sound
+ ///
+ private static void Validate(Models.Listxml.Sound? sound)
+ {
+ Assert.NotNull(sound);
+ Assert.Equal("XXXXXX", sound.Channels);
+ }
+
+ ///
+ /// Validate a Input
+ ///
+ private static void Validate(Models.Listxml.Input? input)
+ {
+ Assert.NotNull(input);
+ Assert.Equal("XXXXXX", input.Service);
+ Assert.Equal("XXXXXX", input.Tilt);
+ Assert.Equal("XXXXXX", input.Players);
+ //Assert.Equal("XXXXXX", input.ControlAttr); // Mututally exclusive with input.Control
+ Assert.Equal("XXXXXX", input.Buttons);
+ Assert.Equal("XXXXXX", input.Coins);
+
+ Assert.NotNull(input.Control);
+ var control = Assert.Single(input.Control);
+ Validate(control);
+ }
+
+ ///
+ /// Validate a Control
+ ///
+ private static void Validate(Models.Listxml.Control? control)
+ {
+ Assert.NotNull(control);
+ Assert.Equal("XXXXXX", control.Type);
+ Assert.Equal("XXXXXX", control.Player);
+ Assert.Equal("XXXXXX", control.Buttons);
+ Assert.Equal("XXXXXX", control.ReqButtons);
+ Assert.Equal("XXXXXX", control.Minimum);
+ Assert.Equal("XXXXXX", control.Maximum);
+ Assert.Equal("XXXXXX", control.Sensitivity);
+ Assert.Equal("XXXXXX", control.KeyDelta);
+ Assert.Equal("XXXXXX", control.Reverse);
+ Assert.Equal("XXXXXX", control.Ways);
+ Assert.Equal("XXXXXX", control.Ways2);
+ Assert.Equal("XXXXXX", control.Ways3);
+ }
+
+ ///
+ /// Validate a DipSwitch
+ ///
+ private static void Validate(Models.Listxml.DipSwitch? dipswitch)
+ {
+ Assert.NotNull(dipswitch);
+ Assert.Equal("XXXXXX", dipswitch.Name);
+ Assert.Equal("XXXXXX", dipswitch.Tag);
+ Assert.Equal("XXXXXX", dipswitch.Mask);
+ Validate(dipswitch.Condition);
+
+ Assert.NotNull(dipswitch.DipLocation);
+ var diplocation = Assert.Single(dipswitch.DipLocation);
+ Validate(diplocation);
+
+ Assert.NotNull(dipswitch.DipValue);
+ var dipvalue = Assert.Single(dipswitch.DipValue);
+ Validate(dipvalue);
+ }
+
+ ///
+ /// Validate a Condition
+ ///
+ private static void Validate(Models.Listxml.Condition? condition)
+ {
+ Assert.NotNull(condition);
+ Assert.Equal("XXXXXX", condition.Tag);
+ Assert.Equal("XXXXXX", condition.Mask);
+ Assert.Equal("XXXXXX", condition.Relation);
+ Assert.Equal("XXXXXX", condition.Value);
+ }
+
+ ///
+ /// Validate a DipLocation
+ ///
+ private static void Validate(Models.Listxml.DipLocation? diplocation)
+ {
+ Assert.NotNull(diplocation);
+ Assert.Equal("XXXXXX", diplocation.Name);
+ Assert.Equal("XXXXXX", diplocation.Number);
+ Assert.Equal("XXXXXX", diplocation.Inverted);
+ }
+
+ ///
+ /// Validate a DipValue
+ ///
+ private static void Validate(Models.Listxml.DipValue? dipvalue)
+ {
+ Assert.NotNull(dipvalue);
+ Assert.Equal("XXXXXX", dipvalue.Name);
+ Assert.Equal("XXXXXX", dipvalue.Value);
+ Assert.Equal("XXXXXX", dipvalue.Default);
+ Validate(dipvalue.Condition);
+ }
+
+ ///
+ /// Validate a Configuration
+ ///
+ private static void Validate(Models.Listxml.Configuration? configuration)
+ {
+ Assert.NotNull(configuration);
+ Assert.Equal("XXXXXX", configuration.Name);
+ Assert.Equal("XXXXXX", configuration.Tag);
+ Assert.Equal("XXXXXX", configuration.Mask);
+ Validate(configuration.Condition);
+
+ Assert.NotNull(configuration.ConfLocation);
+ var conflocation = Assert.Single(configuration.ConfLocation);
+ Validate(conflocation);
+
+ Assert.NotNull(configuration.ConfSetting);
+ var confsetting = Assert.Single(configuration.ConfSetting);
+ Validate(confsetting);
+ }
+
+ ///
+ /// Validate a ConfLocation
+ ///
+ private static void Validate(Models.Listxml.ConfLocation? conflocation)
+ {
+ Assert.NotNull(conflocation);
+ Assert.Equal("XXXXXX", conflocation.Name);
+ Assert.Equal("XXXXXX", conflocation.Number);
+ Assert.Equal("XXXXXX", conflocation.Inverted);
+ }
+
+ ///
+ /// Validate a ConfSetting
+ ///
+ private static void Validate(Models.Listxml.ConfSetting? confsetting)
+ {
+ Assert.NotNull(confsetting);
+ Assert.Equal("XXXXXX", confsetting.Name);
+ Assert.Equal("XXXXXX", confsetting.Value);
+ Assert.Equal("XXXXXX", confsetting.Default);
+ Validate(confsetting.Condition);
+ }
+
+ ///
+ /// Validate a Port
+ ///
+ private static void Validate(Models.Listxml.Port? port)
+ {
+ Assert.NotNull(port);
+ Assert.Equal("XXXXXX", port.Tag);
+
+ Assert.NotNull(port.Analog);
+ var analog = Assert.Single(port.Analog);
+ Validate(analog);
+ }
+
+ ///
+ /// Validate a Analog
+ ///
+ private static void Validate(Models.Listxml.Analog? analog)
+ {
+ Assert.NotNull(analog);
+ Assert.Equal("XXXXXX", analog.Mask);
+ }
+
+ ///
+ /// Validate a Adjuster
+ ///
+ private static void Validate(Models.Listxml.Adjuster? adjuster)
+ {
+ Assert.NotNull(adjuster);
+ Assert.Equal("XXXXXX", adjuster.Name);
+ Assert.Equal("XXXXXX", adjuster.Default);
+ Validate(adjuster.Condition);
+ }
+
+ ///
+ /// Validate a Driver
+ ///
+ private static void Validate(Models.Listxml.Driver? driver)
+ {
+ Assert.NotNull(driver);
+ Assert.Equal("XXXXXX", driver.Status);
+ Assert.Equal("XXXXXX", driver.Color);
+ Assert.Equal("XXXXXX", driver.Sound);
+ Assert.Equal("XXXXXX", driver.PaletteSize);
+ Assert.Equal("XXXXXX", driver.Emulation);
+ Assert.Equal("XXXXXX", driver.Cocktail);
+ Assert.Equal("XXXXXX", driver.SaveState);
+ Assert.Equal("XXXXXX", driver.RequiresArtwork);
+ Assert.Equal("XXXXXX", driver.Unofficial);
+ Assert.Equal("XXXXXX", driver.NoSoundHardware);
+ Assert.Equal("XXXXXX", driver.Incomplete);
+ }
+
+ ///
+ /// Validate a Feature
+ ///
+ private static void Validate(Models.Listxml.Feature? feature)
+ {
+ Assert.NotNull(feature);
+ Assert.Equal("XXXXXX", feature.Type);
+ Assert.Equal("XXXXXX", feature.Status);
+ Assert.Equal("XXXXXX", feature.Overall);
+ }
+
+ ///
+ /// Validate a Device
+ ///
+ private static void Validate(Models.Listxml.Device? device)
+ {
+ Assert.NotNull(device);
+ Assert.Equal("XXXXXX", device.Type);
+ Assert.Equal("XXXXXX", device.Tag);
+ Assert.Equal("XXXXXX", device.FixedImage);
+ Assert.Equal("XXXXXX", device.Mandatory);
+ Assert.Equal("XXXXXX", device.Interface);
+ Validate(device.Instance);
+
+ Assert.NotNull(device.Extension);
+ var extension = Assert.Single(device.Extension);
+ Validate(extension);
+ }
+
+ ///
+ /// Validate a Instance
+ ///
+ private static void Validate(Models.Listxml.Instance? instance)
+ {
+ Assert.NotNull(instance);
+ Assert.Equal("XXXXXX", instance.Name);
+ Assert.Equal("XXXXXX", instance.BriefName);
+ }
+
+ ///
+ /// Validate a Extension
+ ///
+ private static void Validate(Models.Listxml.Extension? extension)
+ {
+ Assert.NotNull(extension);
+ Assert.Equal("XXXXXX", extension.Name);
+ }
+
+ ///
+ /// Validate a Slot
+ ///
+ private static void Validate(Models.Listxml.Slot? slot)
+ {
+ Assert.NotNull(slot);
+ Assert.Equal("XXXXXX", slot.Name);
+
+ Assert.NotNull(slot.SlotOption);
+ var slotoption = Assert.Single(slot.SlotOption);
+ Validate(slotoption);
+ }
+
+ ///
+ /// Validate a SlotOption
+ ///
+ private static void Validate(Models.Listxml.SlotOption? slotoption)
+ {
+ Assert.NotNull(slotoption);
+ Assert.Equal("XXXXXX", slotoption.Name);
+ Assert.Equal("XXXXXX", slotoption.DevName);
+ Assert.Equal("XXXXXX", slotoption.Default);
+ }
+
+ ///
+ /// Validate a SoftwareList
+ ///
+ private static void Validate(Models.Listxml.SoftwareList? softwarelist)
+ {
+ Assert.NotNull(softwarelist);
+ Assert.Equal("XXXXXX", softwarelist.Tag);
+ Assert.Equal("XXXXXX", softwarelist.Name);
+ Assert.Equal("XXXXXX", softwarelist.Status);
+ Assert.Equal("XXXXXX", softwarelist.Filter);
+ }
+
+ ///
+ /// Validate a RamOption
+ ///
+ private static void Validate(Models.Listxml.RamOption? ramoption)
+ {
+ Assert.NotNull(ramoption);
+ Assert.Equal("XXXXXX", ramoption.Name);
+ Assert.Equal("XXXXXX", ramoption.Default);
+ Assert.Equal("XXXXXX", ramoption.Content);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/OfflineListTests.cs b/SabreTools.Serialization.Test/CrossModel/OfflineListTests.cs
new file mode 100644
index 00000000..10763040
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/OfflineListTests.cs
@@ -0,0 +1,450 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class OfflineListTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.OfflineList();
+
+ // Build the data
+ Models.OfflineList.Dat dat = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(dat);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.OfflineList.Dat? newDat = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newDat);
+ Assert.Equal("XXXXXX", newDat.NoNamespaceSchemaLocation);
+ Validate(newDat.Configuration);
+ Validate(newDat.Games);
+ Validate(newDat.GUI);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.OfflineList.Dat Build()
+ {
+ var infos = new Models.OfflineList.Infos
+ {
+ Title = new Models.OfflineList.Title
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ Location = new Models.OfflineList.Location
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ Publisher = new Models.OfflineList.Publisher
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ SourceRom = new Models.OfflineList.SourceRom
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ SaveType = new Models.OfflineList.SaveType
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ RomSize = new Models.OfflineList.RomSize
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ ReleaseNumber = new Models.OfflineList.ReleaseNumber
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ ImageNumber = new Models.OfflineList.ImageNumber
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ LanguageNumber = new Models.OfflineList.LanguageNumber
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ Comment = new Models.OfflineList.Comment
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ RomCRC = new Models.OfflineList.RomCRC
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ Im1CRC = new Models.OfflineList.Im1CRC
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ Im2CRC = new Models.OfflineList.Im2CRC
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ Languages = new Models.OfflineList.Languages
+ {
+ Visible = "XXXXXX",
+ InNamingOption = "XXXXXX",
+ Default = "XXXXXX",
+ },
+ };
+
+ var canopen = new Models.OfflineList.CanOpen
+ {
+ Extension = ["XXXXXX"],
+ };
+
+ var daturl = new Models.OfflineList.DatUrl
+ {
+ FileName = "XXXXXX",
+ Content = "XXXXXX",
+ };
+
+ var newdat = new Models.OfflineList.NewDat
+ {
+ DatVersionUrl = "XXXXXX",
+ DatUrl = daturl,
+ ImUrl = "XXXXXX",
+ };
+
+ var find = new Models.OfflineList.Find
+ {
+ Operation = "XXXXXX",
+ Value = "XXXXXX",
+ Content = "XXXXXX",
+ };
+
+ var to = new Models.OfflineList.To
+ {
+ Value = "XXXXXX",
+ Default = "XXXXXX",
+ Auto = "XXXXXX",
+ Find = [find],
+ };
+
+ var search = new Models.OfflineList.Search
+ {
+ To = [to],
+ };
+
+ var configuration = new Models.OfflineList.Configuration
+ {
+ DatName = "XXXXXX",
+ ImFolder = "XXXXXX",
+ DatVersion = "XXXXXX",
+ System = "XXXXXX",
+ ScreenshotsWidth = "XXXXXX",
+ ScreenshotsHeight = "XXXXXX",
+ Infos = infos,
+ CanOpen = canopen,
+ NewDat = newdat,
+ Search = search,
+ RomTitle = "XXXXXX",
+ };
+
+ var fileromcrc = new Models.OfflineList.FileRomCRC
+ {
+ Extension = "XXXXXX",
+ Content = "XXXXXX",
+ };
+
+ var files = new Models.OfflineList.Files
+ {
+ RomCRC = [fileromcrc],
+ };
+
+ var game = new Models.OfflineList.Game
+ {
+ ImageNumber = "XXXXXX",
+ ReleaseNumber = "XXXXXX",
+ Title = "XXXXXX",
+ SaveType = "XXXXXX",
+ RomSize = "XXXXXX",
+ Publisher = "XXXXXX",
+ Location = "XXXXXX",
+ SourceRom = "XXXXXX",
+ Language = "XXXXXX",
+ Files = files,
+ Im1CRC = "XXXXXX",
+ Im2CRC = "XXXXXX",
+ Comment = "XXXXXX",
+ DuplicateID = "XXXXXX",
+ };
+
+ var games = new Models.OfflineList.Games
+ {
+ Game = [game],
+ };
+
+ var image = new Models.OfflineList.Image
+ {
+ X = "XXXXXX",
+ Y = "XXXXXX",
+ Width = "XXXXXX",
+ Height = "XXXXXX",
+ };
+
+ var images = new Models.OfflineList.Images
+ {
+ Width = "XXXXXX",
+ Height = "XXXXXX",
+ Image = [image],
+ };
+
+ var gui = new Models.OfflineList.GUI
+ {
+ Images = images,
+ };
+
+ return new Models.OfflineList.Dat
+ {
+ NoNamespaceSchemaLocation = "XXXXXX",
+ Configuration = configuration,
+ Games = games,
+ GUI = gui,
+ };
+ }
+
+ ///
+ /// Validate a Configuration
+ ///
+ private static void Validate(Models.OfflineList.Configuration? configuration)
+ {
+ Assert.NotNull(configuration);
+ Assert.Equal("XXXXXX", configuration.DatName);
+ Assert.Equal("XXXXXX", configuration.ImFolder);
+ Assert.Equal("XXXXXX", configuration.DatVersion);
+ Assert.Equal("XXXXXX", configuration.System);
+ Assert.Equal("XXXXXX", configuration.ScreenshotsWidth);
+ Assert.Equal("XXXXXX", configuration.ScreenshotsHeight);
+ Validate(configuration.Infos);
+ Validate(configuration.CanOpen);
+ Validate(configuration.NewDat);
+ Validate(configuration.Search);
+ Assert.Equal("XXXXXX", configuration.RomTitle);
+ }
+
+ ///
+ /// Validate a Infos
+ ///
+ private static void Validate(Models.OfflineList.Infos? infos)
+ {
+ Assert.NotNull(infos);
+ Validate(infos.Title);
+ Validate(infos.Location);
+ Validate(infos.Publisher);
+ Validate(infos.SourceRom);
+ Validate(infos.SaveType);
+ Validate(infos.RomSize);
+ Validate(infos.ReleaseNumber);
+ Validate(infos.ImageNumber);
+ Validate(infos.LanguageNumber);
+ Validate(infos.Comment);
+ Validate(infos.RomCRC);
+ Validate(infos.Im1CRC);
+ Validate(infos.Im2CRC);
+ Validate(infos.Languages);
+ }
+
+ ///
+ /// Validate a InfoBase
+ ///
+ private static void Validate(Models.OfflineList.InfoBase? info)
+ {
+ Assert.NotNull(info);
+ Assert.Equal("XXXXXX", info.Visible);
+ Assert.Equal("XXXXXX", info.InNamingOption);
+ Assert.Equal("XXXXXX", info.Default);
+ }
+
+ ///
+ /// Validate a CanOpen
+ ///
+ private static void Validate(Models.OfflineList.CanOpen? canopen)
+ {
+ Assert.NotNull(canopen);
+ Assert.NotNull(canopen.Extension);
+ string extension = Assert.Single(canopen.Extension);
+ Assert.Equal("XXXXXX", extension);
+ }
+
+ ///
+ /// Validate a NewDat
+ ///
+ private static void Validate(Models.OfflineList.NewDat? newdat)
+ {
+ Assert.NotNull(newdat);
+ Assert.Equal("XXXXXX", newdat.DatVersionUrl);
+ Validate(newdat.DatUrl);
+ Assert.Equal("XXXXXX", newdat.ImUrl);
+ }
+
+ ///
+ /// Validate a DatUrl
+ ///
+ private static void Validate(Models.OfflineList.DatUrl? daturl)
+ {
+ Assert.NotNull(daturl);
+ Assert.Equal("XXXXXX", daturl.FileName);
+ Assert.Equal("XXXXXX", daturl.Content);
+ }
+
+ ///
+ /// Validate a Search
+ ///
+ private static void Validate(Models.OfflineList.Search? search)
+ {
+ Assert.NotNull(search);
+ Assert.NotNull(search.To);
+ var to = Assert.Single(search.To);
+ Validate(to);
+ }
+
+ ///
+ /// Validate a To
+ ///
+ private static void Validate(Models.OfflineList.To? to)
+ {
+ Assert.NotNull(to);
+ Assert.Equal("XXXXXX", to.Value);
+ Assert.Equal("XXXXXX", to.Default);
+ Assert.Equal("XXXXXX", to.Auto);
+
+ Assert.NotNull(to.Find);
+ var find = Assert.Single(to.Find);
+ Validate(find);
+ }
+
+ ///
+ /// Validate a Find
+ ///
+ private static void Validate(Models.OfflineList.Find? find)
+ {
+ Assert.NotNull(find);
+ Assert.Equal("XXXXXX", find.Operation);
+ Assert.Equal("XXXXXX", find.Value);
+ Assert.Equal("XXXXXX", find.Content);
+ }
+
+ ///
+ /// Validate a Games
+ ///
+ private static void Validate(Models.OfflineList.Games? games)
+ {
+ Assert.NotNull(games);
+ Assert.NotNull(games.Game);
+ var game = Assert.Single(games.Game);
+ Validate(game);
+ }
+
+ ///
+ /// Validate a Game
+ ///
+ private static void Validate(Models.OfflineList.Game? game)
+ {
+ Assert.NotNull(game);
+ Assert.Equal("XXXXXX", game.ImageNumber);
+ Assert.Equal("XXXXXX", game.ReleaseNumber);
+ Assert.Equal("XXXXXX", game.Title);
+ Assert.Equal("XXXXXX", game.SaveType);
+ Assert.Equal("0", game.RomSize); // Converted due to filtering
+ Assert.Equal("XXXXXX", game.Publisher);
+ Assert.Equal("XXXXXX", game.Location);
+ Assert.Equal("XXXXXX", game.SourceRom);
+ Assert.Equal("XXXXXX", game.Language);
+ Validate(game.Files);
+ Assert.Equal("XXXXXX", game.Im1CRC);
+ Assert.Equal("XXXXXX", game.Im2CRC);
+ Assert.Equal("XXXXXX", game.Comment);
+ Assert.Equal("XXXXXX", game.DuplicateID);
+ }
+
+ ///
+ /// Validate a Files
+ ///
+ private static void Validate(Models.OfflineList.Files? files)
+ {
+ Assert.NotNull(files);
+ Assert.NotNull(files.RomCRC);
+ var fileromcrc = Assert.Single(files.RomCRC);
+ Validate(fileromcrc);
+ }
+
+ ///
+ /// Validate a FileRomCRC
+ ///
+ private static void Validate(Models.OfflineList.FileRomCRC? fileromcrc)
+ {
+ Assert.NotNull(fileromcrc);
+ Assert.Equal("XXXXXX", fileromcrc.Extension);
+ Assert.Equal("XXXXXX", fileromcrc.Content);
+ }
+
+ ///
+ /// Validate a GUI
+ ///
+ private static void Validate(Models.OfflineList.GUI? gui)
+ {
+ Assert.NotNull(gui);
+ Validate(gui.Images);
+ }
+
+ ///
+ /// Validate a Images
+ ///
+ private static void Validate(Models.OfflineList.Images? images)
+ {
+ Assert.NotNull(images);
+ Assert.Equal("XXXXXX", images.Width);
+ Assert.Equal("XXXXXX", images.Height);
+
+ Assert.NotNull(images.Image);
+ var image = Assert.Single(images.Image);
+ Validate(image);
+ }
+
+ ///
+ /// Validate a Image
+ ///
+ private static void Validate(Models.OfflineList.Image? image)
+ {
+ Assert.NotNull(image);
+ Assert.Equal("XXXXXX", image.X);
+ Assert.Equal("XXXXXX", image.Y);
+ Assert.Equal("XXXXXX", image.Width);
+ Assert.Equal("XXXXXX", image.Height);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/OpenMSXTests.cs b/SabreTools.Serialization.Test/CrossModel/OpenMSXTests.cs
new file mode 100644
index 00000000..5a62b282
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/OpenMSXTests.cs
@@ -0,0 +1,156 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class OpenMSXTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.OpenMSX();
+
+ // Build the data
+ Models.OpenMSX.SoftwareDb sdb = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(sdb);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.OpenMSX.SoftwareDb? newSdb = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newSdb);
+ Assert.Equal("XXXXXX", newSdb.Timestamp);
+
+ Assert.NotNull(newSdb.Software);
+ var software = Assert.Single(newSdb.Software);
+ Validate(software);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.OpenMSX.SoftwareDb Build()
+ {
+ var original = new Models.OpenMSX.Original
+ {
+ Value = "XXXXXX",
+ Content = "XXXXXX",
+ };
+
+ var rom = new Models.OpenMSX.Rom
+ {
+ Start = "XXXXXX",
+ Type = "XXXXXX",
+ Hash = "XXXXXX",
+ Remark = "XXXXXX",
+ };
+
+ var dump_rom = new Models.OpenMSX.Dump
+ {
+ Original = original,
+ Rom = rom,
+ };
+
+ var megarom = new Models.OpenMSX.MegaRom
+ {
+ Start = "XXXXXX",
+ Type = "XXXXXX",
+ Hash = "XXXXXX",
+ Remark = "XXXXXX",
+ };
+
+ var dump_megarom = new Models.OpenMSX.Dump
+ {
+ Original = original,
+ Rom = megarom,
+ };
+
+ var sccpluscart = new Models.OpenMSX.SCCPlusCart
+ {
+ Start = "XXXXXX",
+ Type = "XXXXXX",
+ Hash = "XXXXXX",
+ Remark = "XXXXXX",
+ };
+
+ var dump_sccpluscart = new Models.OpenMSX.Dump
+ {
+ Original = original,
+ Rom = sccpluscart,
+ };
+
+ var software = new Models.OpenMSX.Software
+ {
+ Title = "XXXXXX",
+ GenMSXID = "XXXXXX",
+ System = "XXXXXX",
+ Company = "XXXXXX",
+ Year = "XXXXXX",
+ Country = "XXXXXX",
+ Dump = [dump_rom, dump_megarom, dump_sccpluscart],
+ };
+
+ return new Models.OpenMSX.SoftwareDb
+ {
+ Timestamp = "XXXXXX",
+ Software = [software],
+ };
+ }
+
+ ///
+ /// Validate a Software
+ ///
+ private static void Validate(Models.OpenMSX.Software? software)
+ {
+ Assert.NotNull(software);
+ Assert.Equal("XXXXXX", software.Title);
+ Assert.Equal("XXXXXX", software.GenMSXID);
+ Assert.Equal("XXXXXX", software.System);
+ Assert.Equal("XXXXXX", software.Company);
+ Assert.Equal("XXXXXX", software.Year);
+ Assert.Equal("XXXXXX", software.Country);
+
+ Assert.NotNull(software.Dump);
+ Assert.Equal(3, software.Dump.Length);
+ foreach (var dump in software.Dump)
+ {
+ Validate(dump);
+ }
+ }
+
+ ///
+ /// Validate a Dump
+ ///
+ private static void Validate(Models.OpenMSX.Dump? dump)
+ {
+ Assert.NotNull(dump);
+ Validate(dump.Original);
+ Validate(dump.Rom);
+ }
+
+ ///
+ /// Validate a Original
+ ///
+ private static void Validate(Models.OpenMSX.Original? original)
+ {
+ Assert.NotNull(original);
+ Assert.Equal("XXXXXX", original.Value);
+ Assert.Equal("XXXXXX", original.Content);
+ }
+
+ ///
+ /// Validate a RomBase
+ ///
+ private static void Validate(Models.OpenMSX.RomBase? rombase)
+ {
+ Assert.NotNull(rombase);
+ Assert.Equal("XXXXXX", rombase.Start);
+ Assert.Equal("XXXXXX", rombase.Type);
+ Assert.Equal("XXXXXX", rombase.Hash);
+ Assert.Equal("XXXXXX", rombase.Remark);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/RomCenterTests.cs b/SabreTools.Serialization.Test/CrossModel/RomCenterTests.cs
new file mode 100644
index 00000000..41c9b278
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/RomCenterTests.cs
@@ -0,0 +1,153 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class RomCenterTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.RomCenter();
+
+ // Build the data
+ Models.RomCenter.MetadataFile mf = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.RomCenter.MetadataFile? newMf = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newMf);
+ Validate(newMf.Credits);
+ Validate(newMf.Dat);
+ Validate(newMf.Emulator);
+ Validate(newMf.Games);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.RomCenter.MetadataFile Build()
+ {
+ var credits = new Models.RomCenter.Credits
+ {
+ Author = "XXXXXX",
+ Version = "XXXXXX",
+ Email = "XXXXXX",
+ Homepage = "XXXXXX",
+ Url = "XXXXXX",
+ Date = "XXXXXX",
+ Comment = "XXXXXX",
+ };
+
+ var dat = new Models.RomCenter.Dat
+ {
+ Version = "XXXXXX",
+ Plugin = "XXXXXX",
+ Split = "XXXXXX",
+ Merge = "XXXXXX",
+ };
+
+ var emulator = new Models.RomCenter.Emulator
+ {
+ RefName = "XXXXXX",
+ Version = "XXXXXX",
+ };
+
+ var rom = new Models.RomCenter.Rom
+ {
+ ParentName = "XXXXXX",
+ ParentDescription = "XXXXXX",
+ GameName = "XXXXXX",
+ GameDescription = "XXXXXX",
+ RomName = "XXXXXX",
+ RomCRC = "XXXXXX",
+ RomSize = "XXXXXX",
+ RomOf = "XXXXXX",
+ MergeName = "XXXXXX",
+ };
+
+ var games = new Models.RomCenter.Games
+ {
+ Rom = [rom],
+ };
+
+ return new Models.RomCenter.MetadataFile
+ {
+ Credits = credits,
+ Dat = dat,
+ Emulator = emulator,
+ Games = games,
+ };
+ }
+
+ ///
+ /// Validate a Credits
+ ///
+ private static void Validate(Models.RomCenter.Credits? credits)
+ {
+ Assert.NotNull(credits);
+ Assert.Equal("XXXXXX", credits.Author);
+ Assert.Equal("XXXXXX", credits.Version);
+ Assert.Equal("XXXXXX", credits.Email);
+ Assert.Equal("XXXXXX", credits.Homepage);
+ Assert.Equal("XXXXXX", credits.Url);
+ Assert.Equal("XXXXXX", credits.Date);
+ Assert.Equal("XXXXXX", credits.Comment);
+ }
+
+ ///
+ /// Validate a Dat
+ ///
+ private static void Validate(Models.RomCenter.Dat? dat)
+ {
+ Assert.NotNull(dat);
+ Assert.Equal("XXXXXX", dat.Version);
+ Assert.Equal("XXXXXX", dat.Plugin);
+ Assert.Equal("no", dat.Split); // Converted due to filtering
+ Assert.Equal("no", dat.Merge); // Converted due to filtering
+ }
+
+ ///
+ /// Validate a Emulator
+ ///
+ private static void Validate(Models.RomCenter.Emulator? emulator)
+ {
+ Assert.NotNull(emulator);
+ Assert.Equal("XXXXXX", emulator.RefName);
+ Assert.Equal("XXXXXX", emulator.Version);
+ }
+
+ ///
+ /// Validate a Games
+ ///
+ private static void Validate(Models.RomCenter.Games? games)
+ {
+ Assert.NotNull(games);
+ Assert.NotNull(games.Rom);
+ var rom = Assert.Single(games.Rom);
+ Validate(rom);
+ }
+
+ ///
+ /// Validate a Rom
+ ///
+ private static void Validate(Models.RomCenter.Rom? rom)
+ {
+ Assert.NotNull(rom);
+ Assert.Equal("XXXXXX", rom.ParentName);
+ Assert.Null(rom.ParentDescription); // This is unmappable
+ Assert.Equal("XXXXXX", rom.GameName);
+ Assert.Equal("XXXXXX", rom.GameDescription);
+ Assert.Equal("XXXXXX", rom.RomName);
+ Assert.Equal("XXXXXX", rom.RomCRC);
+ Assert.Equal("XXXXXX", rom.RomSize);
+ Assert.Equal("XXXXXX", rom.RomOf);
+ Assert.Equal("XXXXXX", rom.MergeName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/SeparatedValueTests.cs b/SabreTools.Serialization.Test/CrossModel/SeparatedValueTests.cs
new file mode 100644
index 00000000..44861e0a
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/SeparatedValueTests.cs
@@ -0,0 +1,168 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class SeparatedValueTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.SeparatedValue();
+
+ // Build the data
+ Models.SeparatedValue.MetadataFile mf = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(mf);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.SeparatedValue.MetadataFile? newMf = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newMf);
+ Validate(newMf.Header);
+ Assert.NotNull(newMf.Row);
+ Assert.Equal(3, newMf.Row.Length);
+
+ ValidateDisk(newMf.Row[0]);
+ ValidateMedia(newMf.Row[1]);
+ ValidateRom(newMf.Row[2]);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.SeparatedValue.MetadataFile Build()
+ {
+ string[] header = ["header"];
+
+ var disk = new Models.SeparatedValue.Row
+ {
+ FileName = "XXXXXX",
+ InternalName = "XXXXXX",
+ Description = "XXXXXX",
+ GameName = "XXXXXX",
+ GameDescription = "XXXXXX",
+ Type = "disk",
+ DiskName = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Status = "XXXXXX",
+ };
+
+ var media = new Models.SeparatedValue.Row
+ {
+ FileName = "XXXXXX",
+ InternalName = "XXXXXX",
+ Description = "XXXXXX",
+ GameName = "XXXXXX",
+ GameDescription = "XXXXXX",
+ Type = "media",
+ DiskName = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ SHA256 = "XXXXXX",
+ SpamSum = "XXXXXX",
+ };
+
+ var rom = new Models.SeparatedValue.Row
+ {
+ FileName = "XXXXXX",
+ InternalName = "XXXXXX",
+ Description = "XXXXXX",
+ GameName = "XXXXXX",
+ GameDescription = "XXXXXX",
+ Type = "rom",
+ RomName = "XXXXXX",
+ Size = "XXXXXX",
+ CRC = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ SHA256 = "XXXXXX",
+ SHA384 = "XXXXXX",
+ SHA512 = "XXXXXX",
+ SpamSum = "XXXXXX",
+ Status = "XXXXXX",
+ };
+
+ return new Models.SeparatedValue.MetadataFile
+ {
+ Header = header,
+ Row = [disk, media, rom],
+ };
+ }
+
+ ///
+ /// Validate a header
+ ///
+ private static void Validate(string[]? header)
+ {
+ Assert.NotNull(header);
+ string column = Assert.Single(header);
+ Assert.Equal("header", column);
+ }
+
+ ///
+ /// Validate a Row
+ ///
+ private static void ValidateDisk(Models.SeparatedValue.Row? row)
+ {
+ Assert.NotNull(row);
+ Assert.Equal("XXXXXX", row.FileName);
+ Assert.Equal("XXXXXX", row.InternalName);
+ Assert.Equal("XXXXXX", row.Description);
+ Assert.Equal("XXXXXX", row.GameName);
+ Assert.Equal("XXXXXX", row.GameDescription);
+ Assert.Equal("disk", row.Type);
+ Assert.Equal("XXXXXX", row.DiskName);
+ Assert.Equal("XXXXXX", row.MD5);
+ Assert.Equal("XXXXXX", row.SHA1);
+ Assert.Equal("XXXXXX", row.Status);
+ }
+
+ ///
+ /// Validate a Row
+ ///
+ private static void ValidateMedia(Models.SeparatedValue.Row? row)
+ {
+ Assert.NotNull(row);
+ Assert.Equal("XXXXXX", row.FileName);
+ Assert.Equal("XXXXXX", row.InternalName);
+ Assert.Equal("XXXXXX", row.Description);
+ Assert.Equal("XXXXXX", row.GameName);
+ Assert.Equal("XXXXXX", row.GameDescription);
+ Assert.Equal("media", row.Type);
+ Assert.Equal("XXXXXX", row.DiskName);
+ Assert.Equal("XXXXXX", row.MD5);
+ Assert.Equal("XXXXXX", row.SHA1);
+ Assert.Equal("XXXXXX", row.SHA256);
+ Assert.Equal("XXXXXX", row.SpamSum);
+ }
+
+ ///
+ /// Validate a Row
+ ///
+ private static void ValidateRom(Models.SeparatedValue.Row? row)
+ {
+ Assert.NotNull(row);
+ Assert.Equal("XXXXXX", row.FileName);
+ Assert.Equal("XXXXXX", row.InternalName);
+ Assert.Equal("XXXXXX", row.Description);
+ Assert.Equal("XXXXXX", row.GameName);
+ Assert.Equal("XXXXXX", row.GameDescription);
+ Assert.Equal("rom", row.Type);
+ Assert.Equal("XXXXXX", row.RomName);
+ Assert.Equal("XXXXXX", row.Size);
+ Assert.Equal("XXXXXX", row.CRC);
+ Assert.Equal("XXXXXX", row.MD5);
+ Assert.Equal("XXXXXX", row.SHA1);
+ Assert.Equal("XXXXXX", row.SHA256);
+ Assert.Equal("XXXXXX", row.SHA384);
+ Assert.Equal("XXXXXX", row.SHA512);
+ Assert.Equal("XXXXXX", row.SpamSum);
+ Assert.Equal("XXXXXX", row.Status);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization.Test/CrossModel/SoftwareListTests.cs b/SabreTools.Serialization.Test/CrossModel/SoftwareListTests.cs
new file mode 100644
index 00000000..7767884c
--- /dev/null
+++ b/SabreTools.Serialization.Test/CrossModel/SoftwareListTests.cs
@@ -0,0 +1,310 @@
+using Xunit;
+
+namespace SabreTools.Serialization.Test.CrossModel
+{
+ public class SoftwareListTests
+ {
+ [Fact]
+ public void RoundTripTest()
+ {
+ // Get the cross-model serializer
+ var serializer = new Serialization.CrossModel.SoftwareList();
+
+ // Build the data
+ Models.SoftwareList.SoftwareList sl = Build();
+
+ // Serialize to generic model
+ Models.Metadata.MetadataFile? metadata = serializer.Serialize(sl);
+ Assert.NotNull(metadata);
+
+ // Serialize back to original model
+ Models.SoftwareList.SoftwareList? newSl = serializer.Deserialize(metadata);
+
+ // Validate the data
+ Assert.NotNull(newSl);
+ Assert.Equal("XXXXXX", newSl.Name);
+ Assert.Equal("XXXXXX", newSl.Description);
+ Assert.Equal("XXXXXX", newSl.Notes);
+
+ Assert.NotNull(newSl.Software);
+ var newSoftware = Assert.Single(newSl.Software);
+ Validate(newSoftware);
+ }
+
+ ///
+ /// Build model for serialization and deserialization
+ ///
+ private static Models.SoftwareList.SoftwareList Build()
+ {
+ var info = new Models.SoftwareList.Info
+ {
+ Name = "XXXXXX",
+ Value = "XXXXXX",
+ };
+
+ var sharedfeat = new Models.SoftwareList.SharedFeat
+ {
+ Name = "XXXXXX",
+ Value = "XXXXXX",
+ };
+
+ var feature = new Models.SoftwareList.Feature
+ {
+ Name = "XXXXXX",
+ Value = "XXXXXX",
+ };
+
+ var rom = new Models.SoftwareList.Rom
+ {
+ Name = "XXXXXX",
+ Size = "XXXXXX",
+ Length = "XXXXXX",
+ CRC = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Offset = "XXXXXX",
+ Value = "XXXXXX",
+ Status = "XXXXXX",
+ LoadFlag = "XXXXXX",
+ };
+
+ var dataarea = new Models.SoftwareList.DataArea
+ {
+ Name = "XXXXXX",
+ Size = "XXXXXX",
+ Width = "XXXXXX",
+ Endianness = "XXXXXX",
+ Rom = [rom],
+ };
+
+ var disk = new Models.SoftwareList.Disk
+ {
+ Name = "XXXXXX",
+ MD5 = "XXXXXX",
+ SHA1 = "XXXXXX",
+ Status = "XXXXXX",
+ Writeable = "XXXXXX",
+ };
+
+ var diskarea = new Models.SoftwareList.DiskArea
+ {
+ Name = "XXXXXX",
+ Disk = [disk],
+ };
+
+ var dipvalue = new Models.SoftwareList.DipValue
+ {
+ Name = "XXXXXX",
+ Value = "XXXXXX",
+ Default = "XXXXXX",
+ };
+
+ var dipswitch = new Models.SoftwareList.DipSwitch
+ {
+ Name = "XXXXXX",
+ Tag = "XXXXXX",
+ Mask = "XXXXXX",
+ DipValue = [dipvalue],
+ };
+
+ var part = new Models.SoftwareList.Part
+ {
+ Name = "XXXXXX",
+ Interface = "XXXXXX",
+ Feature = [feature],
+ DataArea = [dataarea],
+ DiskArea = [diskarea],
+ DipSwitch = [dipswitch],
+ };
+
+ var software = new Models.SoftwareList.Software
+ {
+ Name = "XXXXXX",
+ CloneOf = "XXXXXX",
+ Supported = "XXXXXX",
+ Description = "XXXXXX",
+ Year = "XXXXXX",
+ Publisher = "XXXXXX",
+ Notes = "XXXXXX",
+ Info = [info],
+ SharedFeat = [sharedfeat],
+ Part = [part],
+ };
+
+ return new Models.SoftwareList.SoftwareList
+ {
+ Name = "XXXXXX",
+ Description = "XXXXXX",
+ Notes = "XXXXXX",
+ Software = [software],
+ };
+ }
+
+ ///
+ /// Validate a Software
+ ///
+ private static void Validate(Models.SoftwareList.Software? software)
+ {
+ Assert.NotNull(software);
+ Assert.Equal("XXXXXX", software.Name);
+ Assert.Equal("XXXXXX", software.CloneOf);
+ Assert.Equal("XXXXXX", software.Supported);
+ Assert.Equal("XXXXXX", software.Description);
+ Assert.Equal("XXXXXX", software.Year);
+ Assert.Equal("XXXXXX", software.Publisher);
+ Assert.Equal("XXXXXX", software.Notes);
+
+ Assert.NotNull(software.Info);
+ var info = Assert.Single(software.Info);
+ Validate(info);
+
+ Assert.NotNull(software.SharedFeat);
+ var sharedfeat = Assert.Single(software.SharedFeat);
+ Validate(sharedfeat);
+
+ Assert.NotNull(software.Part);
+ var part = Assert.Single(software.Part);
+ Validate(part);
+ }
+
+ ///
+ /// Validate a Info
+ ///
+ private static void Validate(Models.SoftwareList.Info? info)
+ {
+ Assert.NotNull(info);
+ Assert.Equal("XXXXXX", info.Name);
+ Assert.Equal("XXXXXX", info.Value);
+ }
+
+ ///
+ /// Validate a SharedFeat
+ ///
+ private static void Validate(Models.SoftwareList.SharedFeat? sharedfeat)
+ {
+ Assert.NotNull(sharedfeat);
+ Assert.Equal("XXXXXX", sharedfeat.Name);
+ Assert.Equal("XXXXXX", sharedfeat.Value);
+ }
+
+ ///
+ /// Validate a Part
+ ///
+ private static void Validate(Models.SoftwareList.Part? part)
+ {
+ Assert.NotNull(part);
+ Assert.Equal("XXXXXX", part.Name);
+ Assert.Equal("XXXXXX", part.Interface);
+
+ Assert.NotNull(part.Feature);
+ var feature = Assert.Single(part.Feature);
+ Validate(feature);
+
+ Assert.NotNull(part.DataArea);
+ var dataarea = Assert.Single(part.DataArea);
+ Validate(dataarea);
+
+ Assert.NotNull(part.DiskArea);
+ var diskarea = Assert.Single(part.DiskArea);
+ Validate(diskarea);
+
+ Assert.NotNull(part.DipSwitch);
+ var dipswitch = Assert.Single(part.DipSwitch);
+ Validate(dipswitch);
+ }
+
+ ///
+ /// Validate a Feature
+ ///
+ private static void Validate(Models.SoftwareList.Feature? feature)
+ {
+ Assert.NotNull(feature);
+ Assert.Equal("XXXXXX", feature.Name);
+ Assert.Equal("XXXXXX", feature.Value);
+ }
+
+ ///
+ /// Validate a DataArea
+ ///
+ private static void Validate(Models.SoftwareList.DataArea? dataarea)
+ {
+ Assert.NotNull(dataarea);
+ Assert.Equal("XXXXXX", dataarea.Name);
+ Assert.Equal("XXXXXX", dataarea.Size);
+ Assert.Equal("XXXXXX", dataarea.Width);
+ Assert.Equal("XXXXXX", dataarea.Endianness);
+
+ Assert.NotNull(dataarea.Rom);
+ var rom = Assert.Single(dataarea.Rom);
+ Validate(rom);
+ }
+
+ ///
+ /// Validate a Rom
+ ///
+ private static void Validate(Models.SoftwareList.Rom? rom)
+ {
+ Assert.NotNull(rom);
+ Assert.Equal("XXXXXX", rom.Name);
+ Assert.Equal("XXXXXX", rom.Size);
+ Assert.Equal("XXXXXX", rom.Length);
+ Assert.Equal("XXXXXX", rom.CRC);
+ Assert.Equal("XXXXXX", rom.SHA1);
+ Assert.Equal("XXXXXX", rom.Offset);
+ Assert.Equal("XXXXXX", rom.Value);
+ Assert.Equal("XXXXXX", rom.Status);
+ Assert.Equal("XXXXXX", rom.LoadFlag);
+ }
+
+ ///
+ /// Validate a DiskArea
+ ///
+ private static void Validate(Models.SoftwareList.DiskArea? diskarea)
+ {
+ Assert.NotNull(diskarea);
+ Assert.Equal("XXXXXX", diskarea.Name);
+
+ Assert.NotNull(diskarea.Disk);
+ var disk = Assert.Single(diskarea.Disk);
+ Validate(disk);
+ }
+
+ ///
+ /// Validate a Disk
+ ///
+ private static void Validate(Models.SoftwareList.Disk? disk)
+ {
+ Assert.NotNull(disk);
+ Assert.Equal("XXXXXX", disk.Name);
+ Assert.Equal("XXXXXX", disk.MD5);
+ Assert.Equal("XXXXXX", disk.SHA1);
+ Assert.Equal("XXXXXX", disk.Status);
+ Assert.Equal("XXXXXX", disk.Writeable);
+ }
+
+ ///
+ /// Validate a DipSwitch
+ ///
+ private static void Validate(Models.SoftwareList.DipSwitch? dipswitch)
+ {
+ Assert.NotNull(dipswitch);
+ Assert.Equal("XXXXXX", dipswitch.Name);
+ Assert.Equal("XXXXXX", dipswitch.Tag);
+ Assert.Equal("XXXXXX", dipswitch.Mask);
+
+ Assert.NotNull(dipswitch.DipValue);
+ var dipvalue = Assert.Single(dipswitch.DipValue);
+ Validate(dipvalue);
+ }
+
+ ///
+ /// Validate a DipValue
+ ///
+ private static void Validate(Models.SoftwareList.DipValue? dipvalue)
+ {
+ Assert.NotNull(dipvalue);
+ Assert.Equal("XXXXXX", dipvalue.Name);
+ Assert.Equal("XXXXXX", dipvalue.Value);
+ Assert.Equal("XXXXXX", dipvalue.Default);
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/CrossModel/ArchiveDotOrg.Deserializer.cs b/SabreTools.Serialization/CrossModel/ArchiveDotOrg.Deserializer.cs
index 5c9bc10c..797439f2 100644
--- a/SabreTools.Serialization/CrossModel/ArchiveDotOrg.Deserializer.cs
+++ b/SabreTools.Serialization/CrossModel/ArchiveDotOrg.Deserializer.cs
@@ -58,6 +58,7 @@ namespace SabreTools.Serialization.CrossModel
Summation = item.ReadString(Models.Metadata.Rom.SummationKey),
MatrixNumber = item.ReadString(Models.Metadata.Rom.MatrixNumberKey),
CollectionCatalogNumber = item.ReadString(Models.Metadata.Rom.CollectionCatalogNumberKey),
+ Publisher = item.ReadString(Models.Metadata.Rom.PublisherKey),
Comment = item.ReadString(Models.Metadata.Rom.CommentKey),
ASRDetectedLang = item.ReadString(Models.Metadata.Rom.ASRDetectedLangKey),
diff --git a/SabreTools.Serialization/CrossModel/AttractMode.Serializer.cs b/SabreTools.Serialization/CrossModel/AttractMode.Serializer.cs
index c9615970..a9ca54ee 100644
--- a/SabreTools.Serialization/CrossModel/AttractMode.Serializer.cs
+++ b/SabreTools.Serialization/CrossModel/AttractMode.Serializer.cs
@@ -67,7 +67,7 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Machine.PlayedCountKey] = item.PlayedCount,
[Models.Metadata.Machine.PlayedTimeKey] = item.PlayedTime,
[Models.Metadata.Machine.PlayedTimeKey] = item.PlayedTime,
- [Models.Metadata.Machine.RomKey] = ConvertToInternalModel(item),
+ [Models.Metadata.Machine.RomKey] = new Models.Metadata.Rom[] { ConvertToInternalModel(item) },
};
return machine;
}
diff --git a/SabreTools.Serialization/CrossModel/ClrMamePro.Deserializer.cs b/SabreTools.Serialization/CrossModel/ClrMamePro.Deserializer.cs
index 9232fa8d..5eae3ca5 100644
--- a/SabreTools.Serialization/CrossModel/ClrMamePro.Deserializer.cs
+++ b/SabreTools.Serialization/CrossModel/ClrMamePro.Deserializer.cs
@@ -7,7 +7,7 @@ namespace SabreTools.Serialization.CrossModel
public partial class ClrMamePro : IModelSerializer
{
///
- public MetadataFile? Deserialize(Models.Metadata.MetadataFile? obj) => Deserialize(obj, false);
+ public MetadataFile? Deserialize(Models.Metadata.MetadataFile? obj) => Deserialize(obj, true);
///
public MetadataFile? Deserialize(Models.Metadata.MetadataFile? obj, bool game)
@@ -25,7 +25,7 @@ namespace SabreTools.Serialization.CrossModel
if (machines != null && machines.Length > 0)
{
metadataFile.Game
- = Array.ConvertAll(machines, m => ConvertMachineFromInternalModel(m));
+ = Array.ConvertAll(machines, m => ConvertMachineFromInternalModel(m, game));
}
return metadataFile;
@@ -60,7 +60,7 @@ namespace SabreTools.Serialization.CrossModel
///
/// Convert from to
///
- private static GameBase ConvertMachineFromInternalModel(Models.Metadata.Machine item, bool game = false)
+ private static GameBase ConvertMachineFromInternalModel(Models.Metadata.Machine item, bool game)
{
GameBase gameBase = game ? new Models.ClrMamePro.Game() : new Models.ClrMamePro.Machine();
diff --git a/SabreTools.Serialization/CrossModel/DosCenter.Deserializer.cs b/SabreTools.Serialization/CrossModel/DosCenter.Deserializer.cs
index 10667292..649f8872 100644
--- a/SabreTools.Serialization/CrossModel/DosCenter.Deserializer.cs
+++ b/SabreTools.Serialization/CrossModel/DosCenter.Deserializer.cs
@@ -63,9 +63,9 @@ namespace SabreTools.Serialization.CrossModel
///
/// Convert from to
///
- private static Models.DosCenter.File ConvertFromInternalModel(Models.Metadata.Rom item)
+ private static File ConvertFromInternalModel(Models.Metadata.Rom item)
{
- var file = new Models.DosCenter.File
+ var file = new File
{
Name = item.ReadString(Models.Metadata.Rom.NameKey),
Size = item.ReadString(Models.Metadata.Rom.SizeKey),
diff --git a/SabreTools.Serialization/CrossModel/DosCenter.Serializer.cs b/SabreTools.Serialization/CrossModel/DosCenter.Serializer.cs
index 75010662..f1a577bb 100644
--- a/SabreTools.Serialization/CrossModel/DosCenter.Serializer.cs
+++ b/SabreTools.Serialization/CrossModel/DosCenter.Serializer.cs
@@ -66,7 +66,7 @@ namespace SabreTools.Serialization.CrossModel
///
/// Convert from to
///
- private static Models.Metadata.Rom ConvertToInternalModel(Models.DosCenter.File item)
+ private static Models.Metadata.Rom ConvertToInternalModel(File item)
{
var rom = new Models.Metadata.Rom
{
diff --git a/SabreTools.Serialization/CrossModel/EverdriveSMDB.Serializer.cs b/SabreTools.Serialization/CrossModel/EverdriveSMDB.Serializer.cs
index 70ccc83e..cfee2030 100644
--- a/SabreTools.Serialization/CrossModel/EverdriveSMDB.Serializer.cs
+++ b/SabreTools.Serialization/CrossModel/EverdriveSMDB.Serializer.cs
@@ -11,7 +11,7 @@ namespace SabreTools.Serialization.CrossModel
{
if (obj == null)
return null;
-
+
var metadataFile = new Models.Metadata.MetadataFile
{
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(),
@@ -45,7 +45,7 @@ namespace SabreTools.Serialization.CrossModel
{
var machine = new Models.Metadata.Machine
{
- [Models.Metadata.Machine.RomKey] = ConvertToInternalModel(item),
+ [Models.Metadata.Machine.RomKey] = new Models.Metadata.Rom[] { ConvertToInternalModel(item) },
};
return machine;
}
diff --git a/SabreTools.Serialization/CrossModel/Hashfile.Deserializer.cs b/SabreTools.Serialization/CrossModel/Hashfile.Deserializer.cs
index d2d5db1a..c7756677 100644
--- a/SabreTools.Serialization/CrossModel/Hashfile.Deserializer.cs
+++ b/SabreTools.Serialization/CrossModel/Hashfile.Deserializer.cs
@@ -21,9 +21,12 @@ namespace SabreTools.Serialization.CrossModel
if (machines == null || machines.Length == 0)
return null;
- var hashfiles = Array.ConvertAll(machines, m => ConvertMachineFromInternalModel(m, hash));
+ var hashfiles = Array.ConvertAll(machines,
+ m => ConvertMachineFromInternalModel(m, hash));
var sfvs = new List();
+ var md2s = new List();
+ var md4s = new List();
var md5s = new List();
var sha1s = new List();
var sha256s = new List();
@@ -35,6 +38,10 @@ namespace SabreTools.Serialization.CrossModel
{
if (hashfile.SFV != null && hashfile.SFV.Length > 0)
sfvs.AddRange(hashfile.SFV);
+ if (hashfile.MD2 != null && hashfile.MD2.Length > 0)
+ md2s.AddRange(hashfile.MD2);
+ if (hashfile.MD4 != null && hashfile.MD4.Length > 0)
+ md4s.AddRange(hashfile.MD4);
if (hashfile.MD5 != null && hashfile.MD5.Length > 0)
md5s.AddRange(hashfile.MD5);
if (hashfile.SHA1 != null && hashfile.SHA1.Length > 0)
@@ -53,6 +60,10 @@ namespace SabreTools.Serialization.CrossModel
if (sfvs.Count > 0)
hashfileItem.SFV = [.. sfvs];
+ if (md2s.Count > 0)
+ hashfileItem.MD2 = [.. md2s];
+ if (md4s.Count > 0)
+ hashfileItem.MD4 = [.. md4s];
if (md5s.Count > 0)
hashfileItem.MD5 = [.. md5s];
if (sha1s.Count > 0)
@@ -69,21 +80,6 @@ namespace SabreTools.Serialization.CrossModel
return hashfileItem;
}
- ///
- /// Convert from to an array of
- ///
- public static Models.Hashfile.Hashfile[]? ConvertArrayFromInternalModel(Models.Metadata.MetadataFile? item, HashType hash)
- {
- if (item == null)
- return null;
-
- var machines = item.Read(Models.Metadata.MetadataFile.MachineKey);
- if (machines != null && machines.Length > 0)
- return Array.ConvertAll(machines, m => ConvertMachineFromInternalModel(m, hash));
-
- return null;
- }
-
///
/// Convert from to
///
@@ -98,6 +94,12 @@ namespace SabreTools.Serialization.CrossModel
SFV = hash == HashType.CRC32
? Array.ConvertAll(roms, ConvertToSFV)
: null,
+ MD2 = hash == HashType.MD2
+ ? Array.ConvertAll(roms, ConvertToMD2)
+ : null,
+ MD4 = hash == HashType.MD4
+ ? Array.ConvertAll(roms, ConvertToMD4)
+ : null,
MD5 = hash == HashType.MD5
? Array.ConvertAll(roms, ConvertToMD5)
: null,
@@ -119,6 +121,32 @@ namespace SabreTools.Serialization.CrossModel
};
}
+ ///
+ /// Convert from to
+ ///
+ private static MD2 ConvertToMD2(Models.Metadata.Rom item)
+ {
+ var md2 = new MD2
+ {
+ Hash = item.ReadString(Models.Metadata.Rom.MD2Key),
+ File = item.ReadString(Models.Metadata.Rom.NameKey),
+ };
+ return md2;
+ }
+
+ ///
+ /// Convert from to
+ ///
+ private static MD4 ConvertToMD4(Models.Metadata.Rom item)
+ {
+ var md4 = new MD4
+ {
+ Hash = item.ReadString(Models.Metadata.Rom.MD4Key),
+ File = item.ReadString(Models.Metadata.Rom.NameKey),
+ };
+ return md4;
+ }
+
///
/// Convert from to
///
diff --git a/SabreTools.Serialization/CrossModel/Hashfile.Serializer.cs b/SabreTools.Serialization/CrossModel/Hashfile.Serializer.cs
index adc2dc66..1168579a 100644
--- a/SabreTools.Serialization/CrossModel/Hashfile.Serializer.cs
+++ b/SabreTools.Serialization/CrossModel/Hashfile.Serializer.cs
@@ -44,6 +44,10 @@ namespace SabreTools.Serialization.CrossModel
if (item.SFV != null && item.SFV.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.SFV, ConvertToInternalModel);
+ else if (item.MD2 != null && item.MD2.Length > 0)
+ machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.MD2, ConvertToInternalModel);
+ else if (item.MD4 != null && item.MD4.Length > 0)
+ machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.MD4, ConvertToInternalModel);
else if (item.MD5 != null && item.MD5.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.MD5, ConvertToInternalModel);
else if (item.SHA1 != null && item.SHA1.Length > 0)
@@ -60,6 +64,32 @@ namespace SabreTools.Serialization.CrossModel
return machine;
}
+ ///
+ /// Convert from to
+ ///
+ private static Models.Metadata.Rom ConvertToInternalModel(MD2 item)
+ {
+ var rom = new Models.Metadata.Rom
+ {
+ [Models.Metadata.Rom.MD2Key] = item.Hash,
+ [Models.Metadata.Rom.NameKey] = item.File,
+ };
+ return rom;
+ }
+
+ ///
+ /// Convert from to
+ ///
+ private static Models.Metadata.Rom ConvertToInternalModel(MD4 item)
+ {
+ var rom = new Models.Metadata.Rom
+ {
+ [Models.Metadata.Rom.MD4Key] = item.Hash,
+ [Models.Metadata.Rom.NameKey] = item.File,
+ };
+ return rom;
+ }
+
///
/// Convert from to
///
diff --git a/SabreTools.Serialization/CrossModel/Listxml.Deserializer.cs b/SabreTools.Serialization/CrossModel/Listxml.Deserializer.cs
index 4802c067..bb77c077 100644
--- a/SabreTools.Serialization/CrossModel/Listxml.Deserializer.cs
+++ b/SabreTools.Serialization/CrossModel/Listxml.Deserializer.cs
@@ -22,24 +22,6 @@ namespace SabreTools.Serialization.CrossModel
return mame;
}
- ///
- /// Convert from to
- ///
- public static Mame? ConvertMameFromInternalModel(Models.Metadata.MetadataFile? item)
- {
- if (item == null)
- return null;
-
- var header = item.Read(Models.Metadata.MetadataFile.HeaderKey);
- var mame = header != null ? ConvertMameFromInternalModel(header) : new Mame();
-
- var machines = item.Read(Models.Metadata.MetadataFile.MachineKey);
- if (machines != null && machines.Length > 0)
- mame.Game = Array.ConvertAll(machines, ConvertMachineFromInternalModel);
-
- return mame;
- }
-
///
/// Convert from to
///
@@ -518,11 +500,14 @@ namespace SabreTools.Serialization.CrossModel
Service = item.ReadString(Models.Metadata.Input.ServiceKey),
Tilt = item.ReadString(Models.Metadata.Input.TiltKey),
Players = item.ReadString(Models.Metadata.Input.PlayersKey),
- ControlAttr = item.ReadString(Models.Metadata.Input.ControlKey),
Buttons = item.ReadString(Models.Metadata.Input.ButtonsKey),
Coins = item.ReadString(Models.Metadata.Input.CoinsKey),
};
+ var controlAttr = item.ReadString(Models.Metadata.Input.ControlKey);
+ if (controlAttr != null)
+ input.ControlAttr = controlAttr;
+
var controls = item.Read(Models.Metadata.Input.ControlKey);
if (controls != null && controls.Length > 0)
input.Control = Array.ConvertAll(controls, ConvertFromInternalModel);
diff --git a/SabreTools.Serialization/CrossModel/Logiqx.Deserializer.cs b/SabreTools.Serialization/CrossModel/Logiqx.Deserializer.cs
index 193859e9..8e8401cc 100644
--- a/SabreTools.Serialization/CrossModel/Logiqx.Deserializer.cs
+++ b/SabreTools.Serialization/CrossModel/Logiqx.Deserializer.cs
@@ -15,16 +15,16 @@ namespace SabreTools.Serialization.CrossModel
if (obj == null)
return null;
- var datafile = new Datafile
- {
- Build = obj.ReadString(Models.Metadata.Header.BuildKey),
- Debug = obj.ReadString(Models.Metadata.Header.DebugKey),
- SchemaLocation = obj.ReadString(Models.Metadata.Header.SchemaLocationKey),
- };
+ var datafile = new Datafile();
var header = obj.Read(Models.Metadata.MetadataFile.HeaderKey);
if (header != null)
+ {
+ datafile.Build = header.ReadString(Models.Metadata.Header.BuildKey);
+ datafile.Debug = header.ReadString(Models.Metadata.Header.DebugKey);
+ datafile.SchemaLocation = header.ReadString(Models.Metadata.Header.SchemaLocationKey);
datafile.Header = ConvertHeaderFromInternalModel(header);
+ }
// TODO: Handle Dir items - Currently need to be generated from the machines
var machines = obj.Read(Models.Metadata.MetadataFile.MachineKey);
@@ -56,38 +56,58 @@ namespace SabreTools.Serialization.CrossModel
Type = item.ReadString(Models.Metadata.Header.TypeKey),
};
- if (item.ContainsKey(Models.Metadata.Header.HeaderKey)
- || item.ContainsKey(Models.Metadata.Header.ForceMergingKey)
- || item.ContainsKey(Models.Metadata.Header.ForceNodumpKey)
- || item.ContainsKey(Models.Metadata.Header.ForcePackingKey))
+ string? headerVal = item.ReadString(Models.Metadata.Header.HeaderKey);
+ string? forceMerging = item.ReadString(Models.Metadata.Header.ForceMergingKey);
+ string? forceNodump = item.ReadString(Models.Metadata.Header.ForceNodumpKey);
+ string? forceUnpacking = item.ReadString(Models.Metadata.Header.ForcePackingKey);
+
+ if (headerVal != null
+ || forceMerging != null
+ || forceNodump != null
+ || forceUnpacking != null)
{
- header.ClrMamePro = new Models.Logiqx.ClrMamePro
- {
- Header = item.ReadString(Models.Metadata.Header.HeaderKey),
- ForceMerging = item.ReadString(Models.Metadata.Header.ForceMergingKey),
- ForceNodump = item.ReadString(Models.Metadata.Header.ForceNodumpKey),
- ForcePacking = item.ReadString(Models.Metadata.Header.ForcePackingKey),
- };
+ header.ClrMamePro = new Models.Logiqx.ClrMamePro();
+ if (headerVal != null)
+ header.ClrMamePro.Header = headerVal;
+ if (forceMerging != null)
+ header.ClrMamePro.ForceMerging = forceMerging;
+ if (forceNodump != null)
+ header.ClrMamePro.ForceNodump = forceNodump;
+ if (forceUnpacking != null)
+ header.ClrMamePro.ForcePacking = forceUnpacking;
}
- if (item.ContainsKey(Models.Metadata.Header.PluginKey)
- || item.ContainsKey(Models.Metadata.Header.RomModeKey)
- || item.ContainsKey(Models.Metadata.Header.BiosModeKey)
- || item.ContainsKey(Models.Metadata.Header.SampleModeKey)
- || item.ContainsKey(Models.Metadata.Header.LockRomModeKey)
- || item.ContainsKey(Models.Metadata.Header.LockBiosModeKey)
- || item.ContainsKey(Models.Metadata.Header.LockSampleModeKey))
+ string? plugin = item.ReadString(Models.Metadata.Header.PluginKey);
+ string? romMode = item.ReadString(Models.Metadata.Header.RomModeKey);
+ string? biosMode = item.ReadString(Models.Metadata.Header.BiosModeKey);
+ string? sampleMode = item.ReadString(Models.Metadata.Header.SampleModeKey);
+ string? lockRomMode = item.ReadString(Models.Metadata.Header.LockRomModeKey);
+ string? lockBiosMode = item.ReadString(Models.Metadata.Header.LockBiosModeKey);
+ string? lockSampleMode = item.ReadString(Models.Metadata.Header.LockSampleModeKey);
+
+ if (plugin != null
+ || romMode != null
+ || biosMode != null
+ || sampleMode != null
+ || lockRomMode != null
+ || lockBiosMode != null
+ || lockSampleMode != null)
{
- header.RomCenter = new Models.Logiqx.RomCenter
- {
- Plugin = item.ReadString(Models.Metadata.Header.PluginKey),
- RomMode = item.ReadString(Models.Metadata.Header.RomModeKey),
- BiosMode = item.ReadString(Models.Metadata.Header.BiosModeKey),
- SampleMode = item.ReadString(Models.Metadata.Header.SampleModeKey),
- LockRomMode = item.ReadString(Models.Metadata.Header.LockRomModeKey),
- LockBiosMode = item.ReadString(Models.Metadata.Header.LockBiosModeKey),
- LockSampleMode = item.ReadString(Models.Metadata.Header.LockSampleModeKey),
- };
+ header.RomCenter = new Models.Logiqx.RomCenter();
+ if (plugin != null)
+ header.RomCenter.Plugin = plugin;
+ if (romMode != null)
+ header.RomCenter.RomMode = romMode;
+ if (biosMode != null)
+ header.RomCenter.BiosMode = biosMode;
+ if (sampleMode != null)
+ header.RomCenter.SampleMode = sampleMode;
+ if (lockRomMode != null)
+ header.RomCenter.LockRomMode = lockRomMode;
+ if (lockBiosMode != null)
+ header.RomCenter.LockBiosMode = lockBiosMode;
+ if (lockSampleMode != null)
+ header.RomCenter.LockSampleMode = lockSampleMode;
}
return header;
diff --git a/SabreTools.Serialization/CrossModel/OfflineList.Deserializer.cs b/SabreTools.Serialization/CrossModel/OfflineList.Deserializer.cs
index 0ee129ee..ae07fe16 100644
--- a/SabreTools.Serialization/CrossModel/OfflineList.Deserializer.cs
+++ b/SabreTools.Serialization/CrossModel/OfflineList.Deserializer.cs
@@ -104,7 +104,7 @@ namespace SabreTools.Serialization.CrossModel
game.RomSize = Array.Find(romSizes, s => s > -1).ToString();
var romCRCs = Array.ConvertAll(roms, ConvertFromInternalModel);;
- game.Files = new Models.OfflineList.Files { RomCRC = romCRCs };
+ game.Files = new Files { RomCRC = romCRCs };
}
return game;
diff --git a/SabreTools.Serialization/CrossModel/RomCenter.Deserializer.cs b/SabreTools.Serialization/CrossModel/RomCenter.Deserializer.cs
index a155bfd9..eaf08ff4 100644
--- a/SabreTools.Serialization/CrossModel/RomCenter.Deserializer.cs
+++ b/SabreTools.Serialization/CrossModel/RomCenter.Deserializer.cs
@@ -99,15 +99,15 @@ namespace SabreTools.Serialization.CrossModel
{
var row = new Rom
{
- RomName = item.ReadString(Models.Metadata.Rom.NameKey),
- RomCRC = item.ReadString(Models.Metadata.Rom.CRCKey),
- RomSize = item.ReadString(Models.Metadata.Rom.SizeKey),
- MergeName = item.ReadString(Models.Metadata.Rom.MergeKey),
-
- ParentName = parent.ReadString(Models.Metadata.Machine.RomOfKey),
+ ParentName = parent.ReadString(Models.Metadata.Machine.CloneOfKey),
//ParentDescription = parent.ReadString(Models.Metadata.Machine.ParentDescriptionKey), // This is unmappable
GameName = parent.ReadString(Models.Metadata.Machine.NameKey),
GameDescription = parent.ReadString(Models.Metadata.Machine.DescriptionKey),
+ RomName = item.ReadString(Models.Metadata.Rom.NameKey),
+ RomCRC = item.ReadString(Models.Metadata.Rom.CRCKey),
+ RomSize = item.ReadString(Models.Metadata.Rom.SizeKey),
+ RomOf = parent.ReadString(Models.Metadata.Machine.RomOfKey),
+ MergeName = item.ReadString(Models.Metadata.Rom.MergeKey),
};
return row;
}
diff --git a/SabreTools.Serialization/CrossModel/RomCenter.Serializer.cs b/SabreTools.Serialization/CrossModel/RomCenter.Serializer.cs
index d35cd06c..4eb98f07 100644
--- a/SabreTools.Serialization/CrossModel/RomCenter.Serializer.cs
+++ b/SabreTools.Serialization/CrossModel/RomCenter.Serializer.cs
@@ -71,7 +71,8 @@ namespace SabreTools.Serialization.CrossModel
{
var machine = new Models.Metadata.Machine
{
- [Models.Metadata.Machine.RomOfKey] = item.ParentName,
+ [Models.Metadata.Machine.RomOfKey] = item.RomOf,
+ [Models.Metadata.Machine.CloneOfKey] = item.ParentName,
//[Models.Metadata.Machine.ParentDescriptionKey] = item.ParentDescription, // This is unmappable
[Models.Metadata.Machine.NameKey] = item.GameName,
[Models.Metadata.Machine.DescriptionKey] = item.GameDescription,
diff --git a/SabreTools.Serialization/CrossModel/SeparatedValue.Deserializer.cs b/SabreTools.Serialization/CrossModel/SeparatedValue.Deserializer.cs
index a30395d9..92e4f1a9 100644
--- a/SabreTools.Serialization/CrossModel/SeparatedValue.Deserializer.cs
+++ b/SabreTools.Serialization/CrossModel/SeparatedValue.Deserializer.cs
@@ -105,7 +105,7 @@ namespace SabreTools.Serialization.CrossModel
{
var row = new Row
{
- FileName = header?.ReadString("FILENAME"), // TODO: Make this an actual key to retrieve
+ FileName = header?.ReadString("FILENAME"), // TODO: Make this an actual key to retrieve on an item -- OriginalFilename
InternalName = header?.ReadString(Models.Metadata.Header.NameKey),
Description = header?.ReadString(Models.Metadata.Header.DescriptionKey),
GameName = parent.ReadString(Models.Metadata.Machine.NameKey),
diff --git a/SabreTools.Serialization/CrossModel/SeparatedValue.Serializer.cs b/SabreTools.Serialization/CrossModel/SeparatedValue.Serializer.cs
index 14e2f543..60f07acc 100644
--- a/SabreTools.Serialization/CrossModel/SeparatedValue.Serializer.cs
+++ b/SabreTools.Serialization/CrossModel/SeparatedValue.Serializer.cs
@@ -39,7 +39,7 @@ namespace SabreTools.Serialization.CrossModel
if (item.Row != null && item.Row.Length > 0)
{
var first = item.Row[0];
- //header[Models.Metadata.Header.FileNameKey] = first.FileName; // Not possible to map
+ header["FILENAME"] = first.FileName; // TODO: Make this an actual key to retrieve on an item -- OriginalFilename
header[Models.Metadata.Header.NameKey] = first.FileName;
header[Models.Metadata.Header.DescriptionKey] = first.Description;
}