using NUnit.Framework; using VMdemo.Core; using VMdemo.Simulation; namespace VMdemo.Tests.EditMode { public class Step2AddressSplitTests { [TestCase(32)] [TestCase(48)] [TestCase(64)] public void AddressGenerator_NextVirtualAddress_StaysWithinRange(int vaBits) { var generator = new AddressGenerator(vaBits, seed: 7); for (var i = 0; i < 1000; i++) { var va = generator.NextVirtualAddress(); Assert.That(va, Is.LessThanOrEqualTo(generator.MaxVirtualAddress)); } } [Test] public void AddressGenerator_SameSeed_GeneratesDeterministicSequence() { var a = new AddressGenerator(48, seed: 99); var b = new AddressGenerator(48, seed: 99); for (var i = 0; i < 20; i++) { Assert.That(a.NextVirtualAddress(), Is.EqualTo(b.NextVirtualAddress())); } } [Test] public void AddressGenerator_DifferentSeed_GeneratesDifferentSequence() { var a = new AddressGenerator(48, seed: 99); var b = new AddressGenerator(48, seed: 100); var hasDifference = false; for (var i = 0; i < 20; i++) { if (a.NextVirtualAddress() != b.NextVirtualAddress()) { hasDifference = true; break; } } Assert.IsTrue(hasDifference); } [TestCase(0x12345ABCUL, 32, 12, 0x12345UL, 0xABCUL, 0x48UL, 0x345UL)] [TestCase(0x0000ABCDEF123456UL, 48, 12, 0xABCDEF123UL, 0x456UL, 0x2AF37UL, 0x2F123UL)] [TestCase(0xFEDCBA9876543210UL, 64, 16, 0xFEDCBA987654UL, 0x3210UL, 0xFEDCBAUL, 0x987654UL)] public void SplitVirtualAddress_SupportedVaBits_ReturnsExpectedParts( ulong va, int vaBits, int offsetBits, ulong expectedVpn, ulong expectedOffset, ulong expectedL1, ulong expectedL2) { var parts = AddressTranslatorUtils.SplitVirtualAddress(va, vaBits, offsetBits); TestContext.WriteLine(AddressTranslatorUtils.FormatSplitResult(va, vaBits, offsetBits, parts)); Assert.That(parts.Vpn, Is.EqualTo(expectedVpn)); Assert.That(parts.Offset, Is.EqualTo(expectedOffset)); Assert.That(parts.L1Index, Is.EqualTo(expectedL1)); Assert.That(parts.L2Index, Is.EqualTo(expectedL2)); } [Test] public void SplitVirtualAddress_OddVpnBits_UsesCeilFloorBitSplit() { const int vaBits = 32; const int offsetBits = 13; const ulong va = 0xDEADBEEFUL; var parts = AddressTranslatorUtils.SplitVirtualAddress(va, vaBits, offsetBits); AddressTranslatorUtils.GetPageTableBitLayout(vaBits - offsetBits, out var l1Bits, out var l2Bits); Assert.That(l1Bits, Is.EqualTo(10)); Assert.That(l2Bits, Is.EqualTo(9)); Assert.That(parts.Vpn, Is.EqualTo(0x6F56DUL)); Assert.That(parts.Offset, Is.EqualTo(0x1EEFUL)); Assert.That(parts.L1Index, Is.EqualTo(0x37AUL)); Assert.That(parts.L2Index, Is.EqualTo(0x16DUL)); } [Test] public void GetPageTableBitLayout_AlwaysSumsToVpnBits() { for (var vpnBits = 1; vpnBits <= 63; vpnBits++) { AddressTranslatorUtils.GetPageTableBitLayout(vpnBits, out var l1Bits, out var l2Bits); Assert.That(l1Bits + l2Bits, Is.EqualTo(vpnBits)); Assert.That(l1Bits, Is.GreaterThanOrEqualTo(l2Bits)); Assert.That(l1Bits - l2Bits, Is.LessThanOrEqualTo(1)); } } [Test] public void SplitVirtualAddress_AddressOutOfRange_Throws() { Assert.Throws(() => AddressTranslatorUtils.SplitVirtualAddress(0x1_0000_0000UL, 32, 12)); } } }