using System.Data.OleDb; using System.Text; using System.Text.Json; using Omika.Data.HfSql.Connection; namespace Omika.Tests.Connection; /// /// Sonde RUNTIME (lecture seule) : résout la racine documentaire et un échantillon /// de photos Omika pour valider le chemin physique réel. N'écrit jamais en base. /// Résultats dans artifacts/runtime-photopath.txt. /// public class PhotoPathRuntimeTests { private const string ConfigPath = @"D:\Avalonia\Omika\config\hfsql-test.local.json"; private const string OutputPath = @"D:\Avalonia\Omika\artifacts\runtime-photopath.txt"; [Fact] public async Task Runtime_PhotoPath_Resolve() { var sb = new StringBuilder(); sb.AppendLine("=== OMIKA PHOTO PATH — RUNTIME PROBE (read-only) ==="); var config = LoadConfig(); if (config is null) { sb.AppendLine("CONFIG: MISSING (skip)"); await File.WriteAllTextAsync(OutputPath, sb.ToString()); return; } var options = new HfSqlConnectionOptions { Server = config.Server, Port = config.Port, Database = config.Omika.Database, User = config.Omika.User, Credential = config.Omika.Credential, FilePasswords = new HfSqlFilePasswordOptions { ProtectionStd = config.FilePasswords.ProtectionStd, ProtectionPlus = config.FilePasswords.ProtectionPlus } }; var factory = new HfSqlOleDbConnectionFactory(); using var connection = (OleDbConnection)factory.Create(options); try { connection.Open(); sb.AppendLine("CONNECTION: OPEN"); // 1. Racine documentaire. string root = Scalar(connection, "SELECT PAP_Valeur FROM ParametreApplication WHERE PAP_Code = 'CHEMIN_REPERTOIRE_BASE_DOCUMENTS'"); sb.AppendLine($"DOCUMENT ROOT = {root}"); // 2. Un échantillon de documents (photos par extension). var photos = Query(connection, "SELECT DC_PKID, DC_Nom, DC_Chemin, DC_CleCategorie FROM Document " + "WHERE DC_Nom LIKE '%.jpg' OR DC_Nom LIKE '%.jpeg' OR DC_Nom LIKE '%.png' OR DC_Nom LIKE '%.bmp'"); sb.AppendLine($"PHOTO CANDIDATES = {photos.Count}"); foreach (var p in photos.Take(6)) { string pkid = p.GetValueOrDefault("DC_PKID", ""); string nom = p.GetValueOrDefault("DC_Nom", ""); string chemin = p.GetValueOrDefault("DC_Chemin", ""); string candidat = Combine(root, chemin, nom); sb.AppendLine($" DC_PKID={pkid} DC_Nom={nom} DC_Chemin={chemin} candidate={candidat} exists={File.Exists(candidat)}"); } } catch (Exception ex) { sb.AppendLine($"ERROR: {ex.GetType().Name} {ex.Message}"); } finally { await File.WriteAllTextAsync(OutputPath, sb.ToString()); } } private static string Scalar(OleDbConnection c, string sql) { using var cmd = new OleDbCommand(sql, c); return cmd.ExecuteScalar()?.ToString() ?? ""; } private static List> Query(OleDbConnection c, string sql) { var result = new List>(); using var cmd = new OleDbCommand(sql, c); using var reader = cmd.ExecuteReader(); while (reader.Read()) { var row = new Dictionary(); for (int i = 0; i < reader.FieldCount; i++) { row[reader.GetName(i)] = reader.IsDBNull(i) ? "" : reader.GetValue(i)?.ToString() ?? ""; } result.Add(row); } return result; } private static string Combine(string root, string chemin, string nom) { if (string.IsNullOrWhiteSpace(root)) return ""; string combined = string.IsNullOrWhiteSpace(chemin) ? nom : System.IO.Path.Combine(chemin.Trim('\\', '/'), nom); try { return System.IO.Path.GetFullPath(System.IO.Path.Combine(root, combined)); } catch { return ""; } } private sealed class TestConfig { public int Port { get; set; } public string Server { get; set; } = ""; public FilePasswordsConfig FilePasswords { get; set; } = new(); public DatabaseConfig Omika { get; set; } = new(); } private sealed class FilePasswordsConfig { public string? ProtectionStd { get; set; } public string? ProtectionPlus { get; set; } } private sealed class DatabaseConfig { public string Credential { get; set; } = ""; public string Database { get; set; } = ""; public string User { get; set; } = ""; } private static TestConfig? LoadConfig() { if (!File.Exists(ConfigPath)) return null; try { return JsonSerializer.Deserialize( File.ReadAllText(ConfigPath), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); } catch { return null; } } }