Integra il parser esatto del .asm nella GUI (fase 4 e 5)
AsmRecordReader (spostato da scripts/CreoBom.cs nel progetto principale, unica fonte di verita' condivisa con lo script via #:project) sostituisce AssemblyComponentScanner in Form1.RisolviAlberoComponenti (fase "Trova componenti referenziati") e AssiemeCompleto (fase "Verifica completezza"): legge esattamente la sezione "members" del binario invece di contare occorrenze testuali, eliminando i falsi positivi/negativi noti dell'euristica (riferimenti fantasma, placement senza suffisso, ecc.). Se un file non rispetta il formato validato (InvalidDataException, coperto solo dagli 8 campioni usati per il reverse engineering) Form1 ripiega sull'euristica di AssemblyComponentScanner, che resta quindi come fallback e come fonte di verita' per gli script BomViaDb.cs/ExtractCreoStrings.cs. Aggiunti test per AsmRecordReader (fixture binarie costruite a mano: lettura membri, risoluzione ConfigName, conteggio disallineato, sezione assente). Aggiornata la documentazione (CLAUDE.md, docs/architettura.md, docs/formato-asm.md, docs/formato-asm-record.md) di conseguenza. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
60dfd26e8b
commit
cce377a091
8 files changed
+363
-163
No files matched your search
@@ -0,0 +1,123 @@
|
||||
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 <istanza>\0 <idMembro> \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<byte>(), "\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<InvalidDataException>(() => 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<InvalidDataException>(() => 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<DirectoryNotFoundException>(() =>
|
||||
AsmRecordReader.EstraiCodiciReferenziati(@"C:\non\esiste\pippo.asm.1"));
|
||||
}
|
||||
Reference in new issue
Block a user