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

306 lines
12 KiB
C#

using System.Data;
using System.Data.Common;
using Omika.Data.Configuration;
using Omika.Data.Connection;
using Omika.Data.HfSql.Connection;
namespace Omika.Tests.Connection;
public class SyncOleDbConnectionTests
{
private static SyncConnectionOptions CreateOptions() => new()
{
Server = "127.0.0.1",
Port = 4900,
DatabaseName = "BASE_SYNC",
Login = "susana",
Password = "secret",
FilePasswords = new SyncFilePasswordOptions
{
ProtectionStd = "STD_PASSWORD",
ProtectionPlus = null
}
};
[Fact]
public void CreateForSync_MapsAllFields()
{
var options = CreateOptions();
var result = HfSqlConnectionOptionsFactory.CreateForSync(options);
Assert.Equal("127.0.0.1", result.Server);
Assert.Equal(4900, result.Port);
Assert.Equal("BASE_SYNC", result.Database);
Assert.Equal("susana", result.User);
Assert.Equal("secret", result.Credential);
Assert.Equal("STD_PASSWORD", result.FilePasswords.ProtectionStd);
Assert.Null(result.FilePasswords.ProtectionPlus);
}
[Fact]
public void CreateForSync_NullOptions_Throws()
{
Assert.Throws<ArgumentNullException>(() => HfSqlConnectionOptionsFactory.CreateForSync(null!));
}
[Fact]
public async Task OpenAsync_OpensConnection()
{
var factory = new FakeFactory();
await using var connection = new SyncOleDbConnection(CreateOptions(), factory);
Assert.Equal(HfsqlConnectionState.Closed, connection.State);
await connection.OpenAsync();
Assert.Equal(HfsqlConnectionState.Open, connection.State);
}
[Fact]
public async Task OpenAsync_Twice_DoesNotReopen()
{
var factory = new FakeFactory();
await using var connection = new SyncOleDbConnection(CreateOptions(), factory);
await connection.OpenAsync();
await connection.OpenAsync();
Assert.Equal(HfsqlConnectionState.Open, connection.State);
Assert.Equal(1, factory.OpenCount);
}
[Fact]
public async Task CloseAsync_ClosesConnection()
{
var factory = new FakeFactory();
await using var connection = new SyncOleDbConnection(CreateOptions(), factory);
await connection.OpenAsync();
await connection.CloseAsync();
Assert.Equal(HfsqlConnectionState.Closed, connection.State);
}
[Fact]
public async Task QueryAsync_ReturnsRows()
{
var factory = new FakeFactory();
await using var connection = new SyncOleDbConnection(CreateOptions(), factory);
await connection.OpenAsync();
var rows = await connection.QueryAsync("SELECT * FROM TOSRV");
Assert.Single(rows);
Assert.Equal("TS-001", rows[0]["TS_JSON"]);
}
[Fact]
public async Task ExecuteScalarAsync_ReturnsValue()
{
var factory = new FakeFactory();
await using var connection = new SyncOleDbConnection(CreateOptions(), factory);
await connection.OpenAsync();
var value = await connection.ExecuteScalarAsync("SELECT COUNT(*) FROM TOSRV");
Assert.Equal(1L, value);
}
[Fact]
public async Task QueryAsync_NotOpen_Throws()
{
var factory = new FakeFactory();
await using var connection = new SyncOleDbConnection(CreateOptions(), factory);
await Assert.ThrowsAsync<InvalidOperationException>(
() => connection.QueryAsync("SELECT * FROM TOSRV"));
}
[Fact]
public async Task Options_ExposesConnectionName()
{
var factory = new FakeFactory();
await using var connection = new SyncOleDbConnection(CreateOptions(), factory);
Assert.Equal(SyncConnectionOptions.ConnectionName, connection.Options.ConnectionName);
Assert.Equal("BASE_SYNC", connection.Options.DatabaseName);
Assert.Equal("susana", connection.Options.Login);
}
[Fact]
public async Task Options_DoesNotExposePassword()
{
var factory = new FakeFactory();
await using var connection = new SyncOleDbConnection(CreateOptions(), factory);
var text = connection.Options.ToString();
Assert.DoesNotContain("secret", text, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("STD_PASSWORD", text, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Fabrique simulée qui retourne une connexion factice sans serveur HFSQL.
/// </summary>
private sealed class FakeFactory : IHfSqlOleDbConnectionFactory
{
public int OpenCount { get; private set; }
public DbConnection Create(HfSqlConnectionOptions options, string? extendedProperties = null)
{
return new FakeConnection(() => OpenCount++);
}
}
private sealed class FakeConnection : DbConnection
{
private readonly Action _onOpen;
private ConnectionState _state = ConnectionState.Closed;
public FakeConnection(Action onOpen)
{
_onOpen = onOpen;
}
public override string ConnectionString { get; set; } = "";
public override string Database => "BASE_SYNC";
public override string DataSource => "127.0.0.1:4900";
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()
{
_onOpen();
_state = ConnectionState.Open;
}
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
=> throw new NotSupportedException();
protected override DbCommand CreateDbCommand() => new FakeCommand();
protected override void Dispose(bool disposing)
{
_state = ConnectionState.Closed;
base.Dispose(disposing);
}
}
private sealed class FakeCommand : DbCommand
{
public override string CommandText { get; set; } = "";
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; }
protected override DbParameterCollection DbParameterCollection { get; } = new FakeParameterCollection();
protected override DbTransaction? DbTransaction { get; set; }
public override void Cancel() { }
public override int ExecuteNonQuery() => 0;
public override object? ExecuteScalar() => 1L;
public override void Prepare() { }
protected override DbParameter CreateDbParameter() => new FakeParameter();
protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) => new FakeReader();
}
private sealed class FakeReader : DbDataReader
{
private bool _read;
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] => GetValue(ordinal);
public override object this[string name] => GetValue(GetOrdinal(name));
public override int Depth => 0;
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 string GetDataTypeName(int ordinal) => 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 Type GetFieldType(int ordinal) => typeof(string);
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 GetName(int ordinal) => "TS_JSON";
public override int GetOrdinal(string name) => name == "TS_JSON" ? 0 : throw new IndexOutOfRangeException();
public override string GetString(int ordinal) => "TS-001";
public override object GetValue(int ordinal) => "TS-001";
public override int GetValues(object[] values)
{
values[0] = "TS-001";
return 1;
}
public override bool IsDBNull(int ordinal) => false;
public override bool NextResult() => false;
public override bool Read()
{
if (_read)
return false;
_read = true;
return true;
}
public override System.Collections.IEnumerator GetEnumerator() => Array.Empty<object>().GetEnumerator();
}
private sealed class FakeParameterCollection : DbParameterCollection
{
public override int Count => 0;
public override object SyncRoot => this;
public override int Add(object value) => 0;
public override void AddRange(Array values) { }
public override void Clear() { }
public override bool Contains(object value) => false;
public override bool Contains(string value) => false;
public override void CopyTo(Array array, int index) { }
public override System.Collections.IEnumerator GetEnumerator() => Array.Empty<object>().GetEnumerator();
public override int IndexOf(object value) => -1;
public override int IndexOf(string value) => -1;
public override void Insert(int index, object value) { }
public override void Remove(object value) { }
public override void RemoveAt(int index) { }
public override void RemoveAt(string parameterName) { }
protected override DbParameter GetParameter(int index) => new FakeParameter();
protected override DbParameter GetParameter(string parameterName) => new FakeParameter();
protected override void SetParameter(int index, DbParameter value) { }
protected override void SetParameter(string parameterName, DbParameter value) { }
}
private sealed class FakeParameter : DbParameter
{
public override DbType DbType { get; set; }
public override ParameterDirection Direction { get; set; }
public override bool IsNullable { get; set; }
public override string ParameterName { get; set; } = "";
public override string SourceColumn { get; set; } = "";
public override object? Value { get; set; }
public override bool SourceColumnNullMapping { get; set; }
public override int Size { get; set; }
public override void ResetDbType() { }
}
}