using Npgsql; using Xunit; namespace Azaion.Missions.E2E.Helpers; /// /// Side-channel database assertions. Used to verify state the API does not /// expose directly (default-vehicle invariants, mission row counts after /// cascade-delete, audit-table side effects). /// /// /// Marked with [Trait("db_access","seed-or-assert-only")] at the /// consumer-test level — this helper itself is a pure utility. /// public static class DbAssertions { public static long ScalarCount(string sql, params (string Name, object Value)[] parameters) { using var conn = new NpgsqlConnection(TestEnvironment.DbSideChannel); conn.Open(); using var cmd = conn.CreateCommand(); cmd.CommandText = sql; foreach (var (name, value) in parameters) cmd.Parameters.AddWithValue(name, value); var result = cmd.ExecuteScalar(); if (result is null || result is DBNull) throw new InvalidOperationException($"Scalar query '{sql}' returned NULL"); return Convert.ToInt64(result, System.Globalization.CultureInfo.InvariantCulture); } public static void AssertExactlyOneDefaultVehicle() { var count = ScalarCount("SELECT COUNT(*) FROM vehicles WHERE is_default = TRUE"); Assert.True(count <= 1, $"default-vehicle invariant violated: {count} vehicles flagged is_default=TRUE"); } public static long TableRowCount(string table) { if (!IsValidIdentifier(table)) throw new ArgumentException($"Invalid table identifier '{table}'", nameof(table)); return ScalarCount($"SELECT COUNT(*) FROM {table}"); } private static bool IsValidIdentifier(string s) { if (string.IsNullOrEmpty(s) || s.Length > 63) return false; foreach (var c in s) { if (!(char.IsLetterOrDigit(c) || c == '_')) return false; } return true; } }