Files
Omika/tests/Omika.Tests/Connection/HfsqlConnectionTests.cs
T
2026-10-23 18:46:50 +02:00

323 lines
11 KiB
C#

using System.Collections;
using System.Data;
using System.Data.Common;
using Omika.Data.Configuration;
using Omika.Data.Connection;
namespace Omika.Tests.Connection;
public class HfsqlConnectionTests
{
private static HfsqlOptions CreateOptions() => new()
{
Driver = "HFSQL Client/Server",
Server = "hfsql-serveur",
Port = 4900,
DatabaseName = "Omika"
};
[Fact]
public void InitialState_IsClosed()
{
var connection = new HfsqlConnection(CreateOptions(), new FakeFactory());
Assert.Equal(HfsqlConnectionState.Closed, connection.State);
}
[Fact]
public async Task OpenAsync_Success_SetsOpen()
{
var connection = new HfsqlConnection(CreateOptions(), new FakeFactory());
await connection.OpenAsync();
Assert.Equal(HfsqlConnectionState.Open, connection.State);
}
[Fact]
public async Task OpenAsync_Failure_SetsFaulted()
{
var factory = new FakeFactory(throwOnOpen: true);
var connection = new HfsqlConnection(CreateOptions(), factory);
await Assert.ThrowsAsync<InvalidOperationException>(() => connection.OpenAsync());
Assert.Equal(HfsqlConnectionState.Faulted, connection.State);
}
[Fact]
public async Task OpenAsync_Twice_DoesNotCreateSecondConnection()
{
var factory = new FakeFactory();
var connection = new HfsqlConnection(CreateOptions(), factory);
await connection.OpenAsync();
await connection.OpenAsync();
Assert.Equal(HfsqlConnectionState.Open, connection.State);
Assert.Equal(1, factory.CreatedCount);
}
[Fact]
public async Task CloseAsync_SetsClosed()
{
var connection = new HfsqlConnection(CreateOptions(), new FakeFactory());
await connection.OpenAsync();
await connection.CloseAsync();
Assert.Equal(HfsqlConnectionState.Closed, connection.State);
}
[Fact]
public async Task CloseAsync_Twice_DoesNotThrow()
{
var connection = new HfsqlConnection(CreateOptions(), new FakeFactory());
await connection.OpenAsync();
await connection.CloseAsync();
await connection.CloseAsync();
Assert.Equal(HfsqlConnectionState.Closed, connection.State);
}
[Fact]
public async Task DisposeAsync_ClosesConnection()
{
var connection = new HfsqlConnection(CreateOptions(), new FakeFactory());
await connection.OpenAsync();
await connection.DisposeAsync();
Assert.Equal(HfsqlConnectionState.Closed, connection.State);
}
[Fact]
public async Task ExecuteScalarAsync_WhenClosed_Throws()
{
var connection = new HfsqlConnection(CreateOptions(), new FakeFactory());
await Assert.ThrowsAsync<InvalidOperationException>(
() => connection.ExecuteScalarAsync("SELECT 1"));
}
[Fact]
public async Task ExecuteScalarAsync_WhenOpen_ReturnsValue()
{
var factory = new FakeFactory();
var connection = new HfsqlConnection(CreateOptions(), factory);
await connection.OpenAsync();
var result = await connection.ExecuteScalarAsync("SELECT 1");
Assert.Equal(42, result);
}
[Fact]
public async Task ExecuteNonQueryAsync_WhenOpen_ReturnsAffectedRows()
{
var factory = new FakeFactory();
var connection = new HfsqlConnection(CreateOptions(), factory);
await connection.OpenAsync();
var result = await connection.ExecuteNonQueryAsync("UPDATE T SET X = 1");
Assert.Equal(3, result);
}
[Fact]
public async Task QueryAsync_WhenOpen_ReturnsRows()
{
var factory = new FakeFactory();
var connection = new HfsqlConnection(CreateOptions(), factory);
await connection.OpenAsync();
var rows = await connection.QueryAsync("SELECT * FROM T");
Assert.Single(rows);
Assert.Equal("valeur", rows[0]["Col"]);
}
[Fact]
public async Task ExecuteScalarAsync_EmptySql_Throws()
{
var connection = new HfsqlConnection(CreateOptions(), new FakeFactory());
await connection.OpenAsync();
await Assert.ThrowsAsync<ArgumentException>(
() => connection.ExecuteScalarAsync(" "));
}
[Fact]
public async Task GetColumnsAsync_WhenOpen_ReturnsColumns()
{
var factory = new FakeFactory();
var connection = new HfsqlConnection(CreateOptions(), factory);
await connection.OpenAsync();
var columns = await connection.GetColumnsAsync("Lieu");
Assert.Equal(2, columns.Count);
Assert.Contains(columns, c => c.ColumnName == "LI_PKID");
Assert.Contains(columns, c => c.ColumnName == "LI_CleType");
}
[Fact]
public async Task GetColumnsAsync_WhenClosed_Throws()
{
var connection = new HfsqlConnection(CreateOptions(), new FakeFactory());
await Assert.ThrowsAsync<InvalidOperationException>(
() => connection.GetColumnsAsync("Lieu"));
}
private sealed class FakeFactory : IHfsqlConnectionFactory
{
private readonly bool _throwOnOpen;
public FakeFactory(bool throwOnOpen = false)
{
_throwOnOpen = throwOnOpen;
}
public int CreatedCount { get; private set; }
public DbConnection Create(HfsqlOptions options)
{
CreatedCount++;
return new FakeDbConnection(_throwOnOpen);
}
}
private sealed class FakeDbConnection : DbConnection
{
private readonly bool _throwOnOpen;
private ConnectionState _state = ConnectionState.Closed;
public FakeDbConnection(bool throwOnOpen)
{
_throwOnOpen = throwOnOpen;
}
public override string ConnectionString { get; set; } = string.Empty;
public override string Database => "Omika";
public override string DataSource => "fake";
public override string ServerVersion => "1.0";
public override ConnectionState State => _state;
public override void ChangeDatabase(string databaseName) { }
public override void Close() => _state = ConnectionState.Closed;
public override void Open()
{
if (_throwOnOpen)
throw new InvalidOperationException("Échec contrôlé de l'ouverture.");
_state = ConnectionState.Open;
}
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
=> throw new NotSupportedException();
protected override DbCommand CreateDbCommand() => new FakeDbCommand(this);
public override DataTable GetSchema(string collectionName, string[] restrictionValues)
{
var table = new DataTable();
table.Columns.Add("COLUMN_NAME", typeof(string));
table.Rows.Add("LI_PKID");
table.Rows.Add("LI_CleType");
return table;
}
}
private sealed class FakeDbCommand : DbCommand
{
private readonly FakeDbConnection _connection;
public FakeDbCommand(FakeDbConnection connection)
{
_connection = connection;
}
public override string CommandText { get; set; } = string.Empty;
public override int CommandTimeout { get; set; }
public override CommandType CommandType { get; set; }
public override bool DesignTimeVisible { get; set; }
public override UpdateRowSource UpdatedRowSource { get; set; }
protected override DbConnection? DbConnection { get; set; } = null;
protected override DbParameterCollection DbParameterCollection { get; } = null!;
protected override DbTransaction? DbTransaction { get; set; } = null;
public override void Cancel() { }
public override int ExecuteNonQuery() => 3;
public override object? ExecuteScalar() => 42;
public override void Prepare() { }
protected override DbParameter CreateDbParameter() => throw new NotSupportedException();
protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
=> new FakeDbDataReader();
}
private sealed class FakeDbDataReader : DbDataReader
{
private int _readCount;
public override int FieldCount => 1;
public override bool HasRows => true;
public override bool IsClosed => false;
public override int RecordsAffected => 0;
public override object this[int ordinal] => "valeur";
public override object this[string name] => "valeur";
public override bool Read() => _readCount++ == 0;
public override bool NextResult() => false;
public override IEnumerator GetEnumerator() => throw new NotSupportedException();
public override int Depth => 0;
public override string GetName(int ordinal) => "Col";
public override int GetOrdinal(string name) => 0;
public override string GetDataTypeName(int ordinal) => "string";
public override Type GetFieldType(int ordinal) => typeof(string);
public override object GetValue(int ordinal) => "valeur";
public override int GetValues(object[] values)
{
values[0] = "valeur";
return 1;
}
public override bool IsDBNull(int ordinal) => false;
public override bool GetBoolean(int ordinal) => throw new NotSupportedException();
public override byte GetByte(int ordinal) => throw new NotSupportedException();
public override long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length)
=> throw new NotSupportedException();
public override char GetChar(int ordinal) => throw new NotSupportedException();
public override long GetChars(int ordinal, long dataOffset, char[]? buffer, int bufferOffset, int length)
=> throw new NotSupportedException();
public override DateTime GetDateTime(int ordinal) => throw new NotSupportedException();
public override decimal GetDecimal(int ordinal) => throw new NotSupportedException();
public override double GetDouble(int ordinal) => throw new NotSupportedException();
public override float GetFloat(int ordinal) => throw new NotSupportedException();
public override Guid GetGuid(int ordinal) => throw new NotSupportedException();
public override short GetInt16(int ordinal) => throw new NotSupportedException();
public override int GetInt32(int ordinal) => throw new NotSupportedException();
public override long GetInt64(int ordinal) => throw new NotSupportedException();
public override string GetString(int ordinal) => throw new NotSupportedException();
}
}