using PrepStep;
using Microsoft.Data.Sqlite;
namespace PrepStep.Tests;
/// Ricrea lo schema reale del DB (stessa costante SQL usata da Indexer.ScanAsync) e
/// verifica, con dati inseriti a mano, i due comportamenti che in passato hanno causato bug
/// silenziosi: il confronto case-insensitive su codice/tipo_file e la vista
/// files_ultima_versione che tiene solo l'ultima versione per cartella_radice+codice+tipo.
public class CaseInsensitiveLookupIntegrationTests : IDisposable
{
private readonly string _dbPath = Path.Combine(Path.GetTempPath(), $"cadsearch_test_{Guid.NewGuid():N}.db");
private readonly SqliteConnection _connection;
public CaseInsensitiveLookupIntegrationTests()
{
_connection = new SqliteConnection($"Data Source={_dbPath}");
_connection.Open();
using var schemaCmd = _connection.CreateCommand();
schemaCmd.CommandText = Indexer.Schema;
schemaCmd.ExecuteNonQuery();
}
public void Dispose()
{
_connection.Dispose();
SqliteConnection.ClearPool(_connection);
File.Delete(_dbPath);
}
private void InserisciFile(string percorso, string cartella, string codice, string tipo, int versione, string dataModifica)
{
using var cmd = _connection.CreateCommand();
cmd.CommandText = """
INSERT INTO files (percorso_completo, percorso_relativo, nome_file, cartella_radice,
famiglia, codice, tipo_file, versione, dimensione_byte, data_modifica, scansionato_il)
VALUES (@p, @p, @p, @cartella, NULL, @codice, @tipo, @versione, 1, @modifica, @modifica)
""";
cmd.Parameters.AddWithValue("@p", percorso);
cmd.Parameters.AddWithValue("@cartella", cartella);
cmd.Parameters.AddWithValue("@codice", codice);
cmd.Parameters.AddWithValue("@tipo", tipo);
cmd.Parameters.AddWithValue("@versione", versione);
cmd.Parameters.AddWithValue("@modifica", dataModifica);
cmd.ExecuteNonQuery();
}
/// Stessa query (LOWER su entrambi i lati) usata da Form1 per risolvere un codice
/// referenziato in un .asm: la scansione euristica del binario può restituire maiuscole
/// diverse da quelle del file reale su disco (es. "_D100" estratto vs "_d100" su X:\).
private List<(string Tipo, string Percorso)> CercaCasoInsensitive(string codiceCercato)
{
using var cmd = _connection.CreateCommand();
cmd.CommandText = "SELECT tipo_file, percorso_completo FROM files_ultima_versione "
+ "WHERE LOWER(codice) = LOWER(@codice) AND LOWER(tipo_file) IN ('prt', 'asm') "
+ "ORDER BY tipo_file, data_modifica DESC";
cmd.Parameters.AddWithValue("@codice", codiceCercato);
using var reader = cmd.ExecuteReader();
var risultati = new List<(string, string)>();
while (reader.Read())
risultati.Add((reader.GetString(0), reader.GetString(1)));
return risultati;
}
[Fact]
public void Trova_il_file_anche_se_la_maiuscola_del_codice_non_corrisponde()
{
InserisciFile(@"X:\__Corpi\442\M_B\9244228573_d100.asm.16", "__Corpi", "9244228573_d100", "asm", 16, "2018-08-22T14:51:19Z");
var risultati = CercaCasoInsensitive("9244228573_D100");
Assert.Single(risultati);
Assert.Equal("asm", risultati[0].Tipo);
}
[Fact]
public void Trova_il_file_anche_se_il_tipo_e_maiuscolo()
{
InserisciFile(@"X:\Commerciali\Elettrici\1504240807.PRT.1", "Commerciali", "1504240807", "PRT", 1, "2020-01-01T00:00:00Z");
var risultati = CercaCasoInsensitive("1504240807");
Assert.Single(risultati);
Assert.Equal("PRT", risultati[0].Tipo);
}
[Fact]
public void Tra_due_cartelle_radice_diverse_tiene_solo_la_versione_piu_recente()
{
// Stesso codice+tipo duplicato su due cartelle radice diverse (capitato con temp_paris
// vs __Corpi): la vista files_ultima_versione deve restituire il più recente per
// cartella, ma la query applicativa a valle deve poi tenerne solo uno in assoluto
// (comportamento verificato qui a livello di dati grezzi restituiti dalla vista).
InserisciFile(@"X:\temp_paris\gabbia45_modelli_copia\9244228573.asm.1", "temp_paris", "9244228573", "asm", 1, "2014-06-25T07:38:13Z");
InserisciFile(@"X:\__Corpi\442\M_B\9244228573.asm.41", "__Corpi", "9244228573", "asm", 41, "2019-05-08T13:27:23Z");
var risultati = CercaCasoInsensitive("9244228573");
// La vista non deduplica tra cartelle radice diverse: la query applicativa ordina per
// data_modifica DESC e tiene solo la prima per tipo, cioè quella più recente.
Assert.Equal(2, risultati.Count);
Assert.Equal(@"X:\__Corpi\442\M_B\9244228573.asm.41", risultati[0].Percorso);
}
[Fact]
public void La_vista_ultima_versione_scarta_le_versioni_precedenti_nella_stessa_cartella()
{
InserisciFile(@"X:\__Corpi\442\M_B\9244228573.asm.40", "__Corpi", "9244228573", "asm", 40, "2018-08-22T14:51:27Z");
InserisciFile(@"X:\__Corpi\442\M_B\9244228573.asm.41", "__Corpi", "9244228573", "asm", 41, "2019-05-08T13:27:23Z");
var risultati = CercaCasoInsensitive("9244228573");
Assert.Single(risultati);
Assert.Contains(".asm.41", risultati[0].Percorso);
}
[Fact]
public void Nessun_risultato_per_un_codice_non_indicizzato()
{
InserisciFile(@"X:\__Corpi\442\M_B\9244228573.asm.41", "__Corpi", "9244228573", "asm", 41, "2019-05-08T13:27:23Z");
Assert.Empty(CercaCasoInsensitive("0000000000"));
}
}