Сгруппировать тестовые проекты по областям

Deal.Tests.Unit, Deal.Telegram.Tests, Deal.Ai.Tests, Deal.Ml.Tests
разложены по областям (Modules/<X>, Api, Infrastructure, Contracts,
Grpc, ...), общие хелперы -> Support; namespace = папка, using
между областями добавлены итеративно по ошибкам сборки.
This commit is contained in:
Rustam Khalimov
2026-09-11 13:28:26 +03:00
parent e3a2692507
commit 5bfa92a4ac
212 changed files with 1982 additions and 1686 deletions
@@ -0,0 +1,95 @@
using Deal.Infrastructure.Security;
using Deal.Modules.Settings.Application.Abstractions;
using Deal.Modules.Settings.Application.Models;
using Deal.Modules.Settings.Application.Registrars;
using Deal.Modules.Settings.Application.Services;
using Deal.Tests.Unit.Support;
namespace Deal.Tests.Unit.Infrastructure;
/// <summary>
/// Тесты AES-256-GCM-шифра секретов: roundtrip, nonce, устойчивость к повреждению (Task 1, Ruling 2).
/// </summary>
public sealed class SecretCipherTests
{
private const int KeySizeBytes = 32;
private const string SomeSecret = "sk-ant-секретный-ключ-провайдера";
// Фиксированный тестовый ключ (не нулевой, байты 1..32).
private static readonly byte[] Key =
Enumerable.Range(1, KeySizeBytes).Select(index => (byte)index).ToArray();
private readonly ISecretCipher _cipher = new AesGcmSecretCipher(Key);
[Theory]
[InlineData("")]
[InlineData("простой текст")]
[InlineData("кириллица и спецсимволы: !@#$%^&*()_+=-")]
[InlineData("https://api.anthropic.com/v1?key=тоже-секрет")]
public void Decrypt_AfterEncrypt_ReturnsOriginalText(string plainText)
{
string encrypted = _cipher.Encrypt(plainText);
Assert.Equal(plainText, _cipher.Decrypt(encrypted));
}
[Fact]
public void Encrypt_EmptyText_ReturnsEmptyString()
{
Assert.Equal(string.Empty, _cipher.Encrypt(string.Empty));
}
[Fact]
public void Encrypt_NonEmptyText_ProducesTokenWithEncPrefix()
{
string token = _cipher.Encrypt(SomeSecret);
Assert.StartsWith("enc:", token);
}
[Fact]
public void Encrypt_SameTextTwice_ProducesDifferentTokensBecauseOfNonce()
{
string first = _cipher.Encrypt(SomeSecret);
string second = _cipher.Encrypt(SomeSecret);
Assert.NotEqual(first, second);
}
[Fact]
public void Decrypt_TokenWithoutEncPrefix_ReturnsEmptyString()
{
Assert.Equal(string.Empty, _cipher.Decrypt("незашифрованное значение"));
}
[Theory]
[InlineData("enc:")]
[InlineData("enc:не-base64!")]
[InlineData("enc:AAAA")]
public void Decrypt_MalformedToken_ReturnsEmptyStringWithoutException(string token)
{
Assert.Equal(string.Empty, _cipher.Decrypt(token));
}
[Fact]
public void Decrypt_TokenWithCorruptedTag_ReturnsEmptyString()
{
string token = _cipher.Encrypt(SomeSecret);
byte[] payload = Convert.FromBase64String(token[4..]);
payload[^1] ^= 0xFF; // портим последний байт тега аутентичности
string corruptedToken = "enc:" + Convert.ToBase64String(payload);
Assert.Equal(string.Empty, _cipher.Decrypt(corruptedToken));
}
[Fact]
public void Decrypt_TokenEncryptedWithAnotherKey_ReturnsEmptyString()
{
byte[] otherKey = Enumerable.Range(1, KeySizeBytes).Select(index => (byte)(index * 2)).ToArray();
ISecretCipher otherCipher = new AesGcmSecretCipher(otherKey);
string token = otherCipher.Encrypt(SomeSecret);
Assert.Equal(string.Empty, _cipher.Decrypt(token));
}
}