Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user