using System.Text; using PrepStep; namespace PrepStep.Tests; public class AsmRecordReaderTests { private static string ScriviFile(byte[] dati) { string percorso = Path.GetTempFileName(); File.WriteAllBytes(percorso, dati); return percorso; } private static byte[] Bytes(params object[] parti) { using var ms = new MemoryStream(); foreach (var p in parti) { switch (p) { case byte b: ms.WriteByte(b); break; case int i: ms.WriteByte((byte)i); break; case string s: var buf = Encoding.Latin1.GetBytes(s); ms.Write(buf); break; case byte[] arr: ms.Write(arr); break; default: throw new ArgumentException($"tipo non gestito: {p.GetType()}"); } } return ms.ToArray(); } // \xe3 id type name\0 family_name\0 - id/type come singolo byte (0x00-0x7f, un byte) private static byte[] Membro(int id, int tipo, string nome, string? nomeFamiglia = null) => Bytes(0xe3, id, tipo, nome, 0, nomeFamiglia ?? nome, 0); // \xe3 ConfigName\0 \xe23 \0 \x82\x7b private static byte[] ConfigName(string istanza, int idMembro) => Bytes(0xe3, "ConfigName", 0, 0xe2, (byte)'3', istanza, 0, idMembro, 0x82, 0x7b); private static byte[] Asm(int conteggioDichiarato, byte[] membri, byte[]? extra = null) => Bytes("header ", extra ?? Array.Empty(), "\0members\0", 0xf1, 0xf8, conteggioDichiarato, membri, "#MdlStatus"); [Fact] public void Legge_membri_semplici_senza_family_table() { byte[] dati = Asm(2, Bytes( Membro(1, 2, "9244206098"), Membro(2, 1, "9244228558_C01"))); var membri = AsmRecordReader.LeggiMembri(dati); Assert.Equal(2, membri.Count); Assert.Equal((1, 2, "9244206098", "9244206098"), (membri[0].Id, membri[0].Tipo, membri[0].Nome, membri[0].Generico)); Assert.Equal((2, 1, "9244228558_C01", "9244228558_C01"), (membri[1].Id, membri[1].Tipo, membri[1].Nome, membri[1].Generico)); } [Fact] public void Risolve_il_nome_istanza_di_una_family_table_da_ConfigName() { // Il membro cita solo il generico (UNI6592); il nome che la BOM mostra // (R8--_-_U6592) sta nel parametro ConfigName, collegato per id membro. byte[] dati = Asm(1, Membro(1, 2, "UNI6592"), extra: ConfigName("R8--_-_U6592", idMembro: 1)); var membri = AsmRecordReader.LeggiMembri(dati); Assert.Single(membri); Assert.Equal("R8--_-_U6592", membri[0].Nome); Assert.Equal("UNI6592", membri[0].Generico); } [Fact] public void Componente_senza_ConfigName_non_e_toccato_da_istanze_di_altri_membri() { byte[] dati = Asm(2, Bytes( Membro(1, 2, "UNI6592"), Membro(2, 2, "9244206098")), extra: ConfigName("R8--_-_U6592", idMembro: 1)); var membri = AsmRecordReader.LeggiMembri(dati); Assert.Equal("R8--_-_U6592", membri.Single(m => m.Id == 1).Nome); Assert.Equal("9244206098", membri.Single(m => m.Id == 2).Nome); } [Fact] public void Conteggio_dichiarato_diverso_da_quello_letto_lancia_eccezione() { // Dichiara 2 membri ma ne fornisce solo 1: lettura disallineata, va segnalata invece // di restituire un risultato parziale silenzioso. byte[] dati = Asm(2, Membro(1, 2, "9244206098")); Assert.Throws(() => AsmRecordReader.LeggiMembri(dati)); } [Fact] public void Sezione_members_assente_lancia_eccezione() { byte[] dati = Encoding.Latin1.GetBytes("un file qualunque senza la sezione attesa"); Assert.Throws(() => AsmRecordReader.LeggiMembri(dati)); } [Fact] public void EstraiCodiciReferenziati_restituisce_i_generici_distinti() { byte[] dati = Asm(3, Bytes( Membro(1, 2, "9144210327"), Membro(2, 2, "9144210327"), // stesso codice montato due volte: un solo codice distinto Membro(3, 1, "9244238563_D100"))); string percorso = ScriviFile(dati); try { var codici = AsmRecordReader.EstraiCodiciReferenziati(percorso); Assert.Equal(new[] { "9144210327", "9244238563_D100" }, codici.OrderBy(c => c)); } finally { File.Delete(percorso); } } [Fact] public void File_inesistente_lancia_eccezione_IO() => Assert.Throws(() => AsmRecordReader.EstraiCodiciReferenziati(@"C:\non\esiste\pippo.asm.1")); }