test(core/browser/platform): 26 extreme RED/GREEN TDD cycles and full regression hardening (3,235 PASS)
This commit is contained in:
parent
bcd242691f
commit
8677853822
100 changed files with 4814 additions and 333 deletions
252
tests/Paca.Tests/Core/P2pAndE2eeVaultExtremeRedTests.cs
Normal file
252
tests/Paca.Tests/Core/P2pAndE2eeVaultExtremeRedTests.cs
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using Paca.Core.Net;
|
||||
using Paca.Core.Security;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.Core;
|
||||
|
||||
public class P2pAndE2eeVaultExtremeRedTests
|
||||
{
|
||||
// ==========================================
|
||||
// 1. P2pSwarmEngine Extreme Scenarios
|
||||
// ==========================================
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(-1024)]
|
||||
public void P2pSwarmEngine_CreateManifestFromBytes_ZeroOrNegativePieceLength_ClampsToDefault512KB(int pieceLength)
|
||||
{
|
||||
byte[] dummyData = new byte[1024 * 1024]; // 1MB
|
||||
var manifest = P2pSwarmEngine.CreateManifestFromBytes("test.mp4", dummyData, pieceLength);
|
||||
Assert.NotNull(manifest);
|
||||
Assert.True(manifest.PieceLength >= 16 * 1024, "PieceLength must be safely clamped to at least 16KB");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void P2pSwarmEngine_CreateManifestFromBytes_NullData_ThrowsArgumentNullException()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
P2pSwarmEngine.CreateManifestFromBytes("test.mp4", null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void P2pSwarmEngine_InitializeSession_NullManifest_ThrowsArgumentNullException()
|
||||
{
|
||||
var engine = new P2pSwarmEngine();
|
||||
Assert.Throws<ArgumentNullException>(() => engine.InitializeSession(null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void P2pSwarmEngine_AddPeer_NullPeer_DoesNotThrow()
|
||||
{
|
||||
var engine = new P2pSwarmEngine();
|
||||
var ex = Record.Exception(() => engine.AddPeer(null!));
|
||||
Assert.Null(ex);
|
||||
Assert.Equal(0, engine.ConnectedPeerCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void P2pSwarmEngine_AddPeer_NullBitfield_InitializesSafeBitfield()
|
||||
{
|
||||
var engine = new P2pSwarmEngine();
|
||||
var peer = new SwarmPeer { PeerId = "peer1", Bitfield = null! };
|
||||
var ex = Record.Exception(() => engine.AddPeer(peer));
|
||||
Assert.Null(ex);
|
||||
Assert.NotNull(peer.Bitfield);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void P2pSwarmEngine_IngestPieceData_NullData_ReturnsFalseWithoutThrowing()
|
||||
{
|
||||
var engine = new P2pSwarmEngine();
|
||||
var manifest = P2pSwarmEngine.CreateManifestFromBytes("sample.mp4", new byte[100], 50);
|
||||
engine.InitializeSession(manifest);
|
||||
|
||||
bool ingested = engine.IngestPieceData(0, null!);
|
||||
Assert.False(ingested);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void P2pSwarmEngine_IngestPieceData_LengthMismatch_ReturnsFalse()
|
||||
{
|
||||
var engine = new P2pSwarmEngine();
|
||||
var data = new byte[100];
|
||||
var manifest = P2pSwarmEngine.CreateManifestFromBytes("sample.mp4", data, 50);
|
||||
engine.InitializeSession(manifest);
|
||||
|
||||
// Piece 0 expects 50 bytes, passing 10 bytes must fail even if empty
|
||||
bool ingested = engine.IngestPieceData(0, new byte[10]);
|
||||
Assert.False(ingested);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 2. CredentialDataExchange Extreme Scenarios
|
||||
// ==========================================
|
||||
|
||||
[Fact]
|
||||
public void CredentialDataExchange_ExportEncryptedVault_NullRecords_ThrowsArgumentNullException()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
CredentialDataExchange.ExportEncryptedVault(null!, "MasterPass123!"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
public void CredentialDataExchange_ExportEncryptedVault_NullOrWhitespacePassword_ThrowsArgumentException(string? badPass)
|
||||
{
|
||||
var records = new List<SiteCredentialRecord>
|
||||
{
|
||||
new() { Id = "1", Domain = "example.com", Username = "user", DecryptedPassword = "pw" }
|
||||
};
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
CredentialDataExchange.ExportEncryptedVault(records, badPass!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CredentialDataExchange_ImportEncryptedVault_DeclaredLengthExceedsAvailableData_ThrowsInvalidDataException()
|
||||
{
|
||||
// Valid header with huge declared ciphertext length
|
||||
byte[] magic = System.Text.Encoding.ASCII.GetBytes("PACAVAULT_V1");
|
||||
using var ms = new MemoryStream();
|
||||
using var bw = new BinaryWriter(ms);
|
||||
bw.Write(magic);
|
||||
bw.Write(new byte[32]); // salt
|
||||
bw.Write(new byte[12]); // nonce
|
||||
bw.Write(new byte[16]); // tag
|
||||
bw.Write(10_000_000); // claimed 10MB
|
||||
bw.Write(new byte[10]); // but only 10 bytes present!
|
||||
bw.Flush();
|
||||
|
||||
var malformedData = ms.ToArray();
|
||||
Assert.Throws<InvalidDataException>(() =>
|
||||
CredentialDataExchange.ImportEncryptedVault(malformedData, "MasterPass123!"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CredentialDataExchange_ExportCsv_NullRecords_ReturnsHeaderOnly()
|
||||
{
|
||||
var csv = CredentialDataExchange.ExportCsv(null!);
|
||||
Assert.NotNull(csv);
|
||||
Assert.Contains("name,url,username,password", csv);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
public void CredentialDataExchange_ImportCsv_NullOrWhitespace_ReturnsEmptyList(string? badCsv)
|
||||
{
|
||||
var list = CredentialDataExchange.ImportCsv(badCsv!);
|
||||
Assert.NotNull(list);
|
||||
Assert.Empty(list);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CredentialDataExchange_ExportCsv_FormulaInjectionPrefixes_SanitizedSafely()
|
||||
{
|
||||
var maliciousRecord = new SiteCredentialRecord
|
||||
{
|
||||
Id = "evil",
|
||||
SiteName = "=cmd|' /C calc'!A0",
|
||||
Domain = "+1234567890",
|
||||
Username = "@dangerousUser",
|
||||
DecryptedPassword = "-unsafePassword",
|
||||
Notes = "\tmaliciousTab"
|
||||
};
|
||||
|
||||
var csv = CredentialDataExchange.ExportCsv(new[] { maliciousRecord });
|
||||
Assert.NotNull(csv);
|
||||
// Formula injection prefixes (=, +, -, @, tab) should be sanitized
|
||||
var lines = csv.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
Assert.True(lines.Length >= 2);
|
||||
string dataRow = lines[1];
|
||||
Assert.DoesNotContain(",=cmd", dataRow);
|
||||
Assert.DoesNotContain(",+123", dataRow);
|
||||
Assert.DoesNotContain(",@dan", dataRow);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 3. CrdtVaultSyncEngine Extreme Scenarios
|
||||
// ==========================================
|
||||
|
||||
[Fact]
|
||||
public void CrdtVaultSyncEngine_Merge_NullRemote_ReturnsZeroWithoutThrowing()
|
||||
{
|
||||
var engine = new CrdtVaultSyncEngine<string>();
|
||||
int applied = engine.Merge(null!);
|
||||
Assert.Equal(0, applied);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CrdtVaultSyncEngine_Merge_NullOrEmptyIds_SkippedSafely()
|
||||
{
|
||||
var engine = new CrdtVaultSyncEngine<string>();
|
||||
var items = new List<CrdtItemRecord<string>>
|
||||
{
|
||||
null!,
|
||||
new() { Id = null!, Value = "A" },
|
||||
new() { Id = "", Value = "B" },
|
||||
new() { Id = "valid_1", Value = "C", LamportTimestamp = 1 }
|
||||
};
|
||||
|
||||
int applied = engine.Merge(items);
|
||||
Assert.Equal(1, applied);
|
||||
Assert.Single(engine.GetActiveItems());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
public void CrdtVaultSyncEngine_Set_NullOrEmptyId_ThrowsArgumentException(string? invalidId)
|
||||
{
|
||||
var engine = new CrdtVaultSyncEngine<string>();
|
||||
Assert.Throws<ArgumentException>(() => engine.Set(invalidId!, "value"));
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 4. E2eeRemoteBackupProvider Extreme Scenarios
|
||||
// ==========================================
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
public void E2eeRemoteBackupProvider_EncryptPayload_NullOrEmptyPassword_ThrowsArgumentException(string? badPass)
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
E2eeRemoteBackupProvider.EncryptPayload("{}", badPass!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void E2eeRemoteBackupProvider_DecryptPayload_InvalidMagic_ThrowsInvalidDataException()
|
||||
{
|
||||
var bogusHeader = new VaultBackupHeader
|
||||
{
|
||||
Magic = "HACKERVAULT",
|
||||
SaltBase64 = Convert.ToBase64String(new byte[16]),
|
||||
NonceBase64 = Convert.ToBase64String(new byte[12]),
|
||||
TagBase64 = Convert.ToBase64String(new byte[16]),
|
||||
CiphertextBase64 = Convert.ToBase64String(new byte[32])
|
||||
};
|
||||
string json = JsonSerializer.Serialize(bogusHeader);
|
||||
|
||||
Assert.Throws<InvalidDataException>(() =>
|
||||
E2eeRemoteBackupProvider.DecryptPayload(json, "MasterPassword123!"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("not-json")]
|
||||
[InlineData("{\"Magic\":\"PACAVAULT\",\"SaltBase64\":\"%%%not-base64%%%\"}")]
|
||||
public void E2eeRemoteBackupProvider_DecryptPayload_CorruptedBase64_ThrowsInvalidDataException(string corruptJson)
|
||||
{
|
||||
Assert.Throws<InvalidDataException>(() =>
|
||||
E2eeRemoteBackupProvider.DecryptPayload(corruptJson, "MasterPassword123!"));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue