Files
prep-step/PrepStep.Tests/CaseInsensitiveLookupIntegrationTests.cs
T
davideandClaude Sonnet 5 13798ad47c Add explicit working folder; rename project from CadSearchGui to PrepStep
Working folder (phase 1): CSV/raw/step/step_finali all used to live split
across two different implicit locations (CSV in the "repo root" found by
walking up for CLAUDE.md, raw/step next to the input distinta file) with
neither shown to the user. That repo-root lookup also silently breaks once
the app runs as a standalone published exe on a machine with no repo/
CLAUDE.md at all. Replaced both with one explicit "cartella di lavoro",
auto-suggested (last used, remembered the same way as the DB path) and
changeable from phase 1, with no dependency on any repo marker file.

Rename: CadSearchGui was the working name from before the app had a
product identity; renamed folders, csproj files, namespace and the
AppData settings folder to PrepStep throughout, matching the exe name
already in use. Product-facing name stays "Cevolani StepPrep".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 11:18:43 +02:00

125 lines
5.6 KiB
C#

using PrepStep;
using Microsoft.Data.Sqlite;
namespace PrepStep.Tests;
/// <summary>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.</summary>
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();
}
/// <summary>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:\).</summary>
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"));
}
}