diff --git a/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs b/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs index 85a1ac02bc..8b42b8b342 100644 --- a/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs +++ b/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs @@ -79,7 +79,7 @@ namespace Ryujinx.Tests.Memory IEnumerable IVirtualMemoryManager.GetPhysicalRegions(ulong va, ulong size) { - return NoMappings ? Array.Empty() : new MemoryRange[] { new MemoryRange(va, size) }; + return NoMappings ? Array.Empty() : new[] { new MemoryRange(va, size) }; } public bool IsMapped(ulong va) diff --git a/src/Ryujinx.Tests.Memory/MultiRegionTrackingTests.cs b/src/Ryujinx.Tests.Memory/MultiRegionTrackingTests.cs index c71a3e1f03..18e9c8e6fd 100644 --- a/src/Ryujinx.Tests.Memory/MultiRegionTrackingTests.cs +++ b/src/Ryujinx.Tests.Memory/MultiRegionTrackingTests.cs @@ -1,13 +1,13 @@ -using NUnit.Framework; using Ryujinx.Memory; using Ryujinx.Memory.Tracking; using System; using System.Collections.Generic; using System.Linq; +using Xunit; namespace Ryujinx.Tests.Memory { - public class MultiRegionTrackingTests + public class MultiRegionTrackingTests : IDisposable { private const ulong MemorySize = 0x8000; private const int PageSize = 4096; @@ -16,17 +16,16 @@ namespace Ryujinx.Tests.Memory private MemoryTracking _tracking; private MockVirtualMemoryManager _memoryManager; - [SetUp] - public void Setup() + public MultiRegionTrackingTests() { _memoryBlock = new MemoryBlock(MemorySize); _memoryManager = new MockVirtualMemoryManager(MemorySize, PageSize); _tracking = new MemoryTracking(_memoryManager, PageSize); } - [TearDown] - public void Teardown() + public void Dispose() { + GC.SuppressFinalize(this); _memoryBlock.Dispose(); } @@ -56,8 +55,8 @@ namespace Ryujinx.Tests.Memory handle.QueryModified(startAddress, size, (address, range) => { - Assert.IsTrue(addressPredicate(address)); // Written pages must be even. - Assert.GreaterOrEqual(address, lastAddress); // Must be signalled in ascending order, regardless of write order. + Assert.True(addressPredicate(address)); // Written pages must be even. + Assert.True(address >= lastAddress); // Must be signalled in ascending order, regardless of write order. lastAddress = address; regionCount++; }); @@ -72,8 +71,8 @@ namespace Ryujinx.Tests.Memory handle.QueryModified(startAddress, size, (address, range) => { - Assert.IsTrue(addressPredicate(address)); // Written pages must be even. - Assert.GreaterOrEqual(address, lastAddress); // Must be signalled in ascending order, regardless of write order. + Assert.True(addressPredicate(address)); // Written pages must be even. + Assert.True(address >= lastAddress); // Must be signalled in ascending order, regardless of write order. lastAddress = address; regionCount++; }, sequenceNumber); @@ -93,12 +92,14 @@ namespace Ryujinx.Tests.Memory { resultAddress = address; }); - Assert.AreEqual(resultAddress, (ulong)i * PageSize + address); + Assert.Equal((ulong)i * PageSize + address, resultAddress); }); } - [Test] - public void DirtyRegionOrdering([Values] bool smart) + [Theory] + [InlineData(true)] + [InlineData(false)] + public void DirtyRegionOrdering(bool smart) { const int PageCount = 32; IMultiRegionHandle handle = GetGranular(smart, 0, PageSize * PageCount, PageSize); @@ -119,7 +120,7 @@ namespace Ryujinx.Tests.Memory int oddRegionCount = ExpectQueryInOrder(handle, 0, PageSize * PageCount, (address) => (address / PageSize) % 2 == 1); - Assert.AreEqual(oddRegionCount, PageCount / 2); // Must have written to all odd pages. + Assert.Equal(PageCount / 2, oddRegionCount); // Must have written to all odd pages. // Write to all the even pages. RandomOrder(random, even, (i) => @@ -129,11 +130,13 @@ namespace Ryujinx.Tests.Memory int evenRegionCount = ExpectQueryInOrder(handle, 0, PageSize * PageCount, (address) => (address / PageSize) % 2 == 0); - Assert.AreEqual(evenRegionCount, PageCount / 2); + Assert.Equal(PageCount / 2, evenRegionCount); } - [Test] - public void SequenceNumber([Values] bool smart) + [Theory] + [InlineData(true)] + [InlineData(false)] + public void SequenceNumber(bool smart) { // The sequence number can be used to ignore dirty flags, and defer their consumption until later. // If a user consumes a dirty flag with sequence number 1, then there is a write to the protected region, @@ -172,7 +175,7 @@ namespace Ryujinx.Tests.Memory }, 1); } - Assert.AreEqual(oddRegionCount, PageCount / 2); // Must have written to all odd pages. + Assert.Equal(PageCount / 2, oddRegionCount); // Must have written to all odd pages. // Write to all pages. @@ -182,22 +185,22 @@ namespace Ryujinx.Tests.Memory int evenRegionCount = ExpectQueryInOrder(handle, 0, PageSize * PageCount, (address) => (address / PageSize) % 2 == 0, 1); - Assert.AreEqual(evenRegionCount, PageCount / 2); // Must have written to all even pages. + Assert.Equal(PageCount / 2, evenRegionCount); // Must have written to all even pages. oddRegionCount = 0; handle.QueryModified(0, PageSize * PageCount, (address, range) => { oddRegionCount++; }, 1); - Assert.AreEqual(oddRegionCount, 0); // Sequence number has not changed, so found no dirty subregions. + Assert.Equal(0, oddRegionCount); // Sequence number has not changed, so found no dirty subregions. // With sequence number 2, all all pages should be reported as modified. oddRegionCount = ExpectQueryInOrder(handle, 0, PageSize * PageCount, (address) => (address / PageSize) % 2 == 1, 2); - Assert.AreEqual(oddRegionCount, PageCount / 2); // Must have written to all odd pages. + Assert.Equal(PageCount / 2, oddRegionCount); // Must have written to all odd pages. } - [Test] + [Fact] public void SmartRegionTracking() { // Smart multi region handles dynamically change their tracking granularity based on QueryMemory calls. @@ -208,7 +211,7 @@ namespace Ryujinx.Tests.Memory // Query some large regions to prep the subdivision of the tracking region. - int[] regionSizes = new int[] { 6, 4, 3, 2, 6, 1 }; + int[] regionSizes = { 6, 4, 3, 2, 6, 1 }; ulong address = 0; for (int i = 0; i < regionSizes.Length; i++) @@ -242,26 +245,28 @@ namespace Ryujinx.Tests.Memory { int region = regionSizes[regionInd++]; - Assert.AreEqual(address, expectedAddress); - Assert.AreEqual(size, (ulong)(PageSize * region)); + Assert.Equal(expectedAddress, address); + Assert.Equal((ulong)(PageSize * region), size); expectedAddress += (ulong)(PageSize * (region + 1)); }); } - [Test] - public void DisposeMultiHandles([Values] bool smart) + [Theory] + [InlineData(true)] + [InlineData(false)] + public void DisposeMultiHandles(bool smart) { // Create and initialize two overlapping Multi Region Handles, with PageSize granularity. const int PageCount = 32; const int OverlapStart = 16; - Assert.AreEqual(0, _tracking.GetRegionCount()); + Assert.Equal(0, _tracking.GetRegionCount()); IMultiRegionHandle handleLow = GetGranular(smart, 0, PageSize * PageCount, PageSize); PreparePages(handleLow, PageCount); - Assert.AreEqual(PageCount, _tracking.GetRegionCount()); + Assert.Equal(PageCount, _tracking.GetRegionCount()); IMultiRegionHandle handleHigh = GetGranular(smart, PageSize * OverlapStart, PageSize * PageCount, PageSize); PreparePages(handleHigh, PageCount, PageSize * OverlapStart); @@ -269,18 +274,18 @@ namespace Ryujinx.Tests.Memory // Combined pages (and assuming overlapStart <= pageCount) should be pageCount after overlapStart. int totalPages = OverlapStart + PageCount; - Assert.AreEqual(totalPages, _tracking.GetRegionCount()); + Assert.Equal(totalPages, _tracking.GetRegionCount()); handleLow.Dispose(); // After disposing one, the pages for the other remain. - Assert.AreEqual(PageCount, _tracking.GetRegionCount()); + Assert.Equal(PageCount, _tracking.GetRegionCount()); handleHigh.Dispose(); // After disposing the other, there are no pages left. - Assert.AreEqual(0, _tracking.GetRegionCount()); + Assert.Equal(0, _tracking.GetRegionCount()); } - [Test] + [Fact] public void InheritHandles() { // Test merging the following into a granular region handle: @@ -333,8 +338,7 @@ namespace Ryujinx.Tests.Memory // Finally, create a granular handle that inherits all these handles. - IEnumerable[] handleGroups = new IEnumerable[] - { + IEnumerable[] handleGroups = { granular.GetHandles(), singlePages, doublePages, @@ -342,8 +346,7 @@ namespace Ryujinx.Tests.Memory MultiRegionHandle combined = _tracking.BeginGranularTracking(0, PageSize * 18, handleGroups.SelectMany((handles) => handles), PageSize, 0); - bool[] expectedDirty = new bool[] - { + bool[] expectedDirty = { true, true, true, // Gap. false, true, false, // Multi-region. true, true, // Gap. @@ -357,19 +360,19 @@ namespace Ryujinx.Tests.Memory bool modified = false; combined.QueryModified(PageSize * (ulong)i, PageSize, (_, _) => { modified = true; }); - Assert.AreEqual(expectedDirty[i], modified); + Assert.Equal(expectedDirty[i], modified); } - Assert.AreEqual(new bool[3], actionsTriggered); + Assert.Equal(new bool[3], actionsTriggered); _tracking.VirtualMemoryEvent(PageSize * 5, PageSize, false); - Assert.IsTrue(actionsTriggered[0]); + Assert.True(actionsTriggered[0]); _tracking.VirtualMemoryEvent(PageSize * 10, PageSize, false); - Assert.IsTrue(actionsTriggered[1]); + Assert.True(actionsTriggered[1]); _tracking.VirtualMemoryEvent(PageSize * 15, PageSize, false); - Assert.IsTrue(actionsTriggered[2]); + Assert.True(actionsTriggered[2]); // The double page handles should be disposed, as they were split into granular handles. foreach (RegionHandle doublePage in doublePages) @@ -386,21 +389,21 @@ namespace Ryujinx.Tests.Memory throws = true; } - Assert.IsTrue(throws); + Assert.True(throws); } IEnumerable combinedHandles = combined.GetHandles(); - Assert.AreEqual(handleGroups[0].ElementAt(0), combinedHandles.ElementAt(3)); - Assert.AreEqual(handleGroups[0].ElementAt(1), combinedHandles.ElementAt(4)); - Assert.AreEqual(handleGroups[0].ElementAt(2), combinedHandles.ElementAt(5)); + Assert.Equal(handleGroups[0].ElementAt(0), combinedHandles.ElementAt(3)); + Assert.Equal(handleGroups[0].ElementAt(1), combinedHandles.ElementAt(4)); + Assert.Equal(handleGroups[0].ElementAt(2), combinedHandles.ElementAt(5)); - Assert.AreEqual(singlePages[0], combinedHandles.ElementAt(8)); - Assert.AreEqual(singlePages[1], combinedHandles.ElementAt(9)); - Assert.AreEqual(singlePages[2], combinedHandles.ElementAt(10)); + Assert.Equal(singlePages[0], combinedHandles.ElementAt(8)); + Assert.Equal(singlePages[1], combinedHandles.ElementAt(9)); + Assert.Equal(singlePages[2], combinedHandles.ElementAt(10)); } - [Test] + [Fact] public void PreciseAction() { bool actionTriggered = false; @@ -413,11 +416,11 @@ namespace Ryujinx.Tests.Memory // Precise write to first handle in the multiregion. _tracking.VirtualMemoryEvent(PageSize * 3, PageSize, true, precise: true); - Assert.IsFalse(actionTriggered); // Action not triggered. + Assert.False(actionTriggered); // Action not triggered. bool firstPageModified = false; granular.QueryModified(PageSize * 3, PageSize, (_, _) => { firstPageModified = true; }); - Assert.IsTrue(firstPageModified); // First page is modified. + Assert.True(firstPageModified); // First page is modified. // Precise write to all handles in the multiregion. _tracking.VirtualMemoryEvent(PageSize * 3, PageSize * 3, true, precise: true); @@ -430,10 +433,10 @@ namespace Ryujinx.Tests.Memory granular.QueryModified(PageSize * (ulong)i, PageSize, (_, _) => { pagesModified[index] = true; }); } - Assert.IsTrue(actionTriggered); // Action triggered. + Assert.True(actionTriggered); // Action triggered. // Precise writes are ignored on two later handles due to the action returning true. - Assert.AreEqual(pagesModified, new bool[] { true, false, false }); + Assert.Equal(new[] { true, false, false }, pagesModified); } } } diff --git a/src/Ryujinx.Tests.Memory/RandomRangeUL2TheoryData.cs b/src/Ryujinx.Tests.Memory/RandomRangeUL2TheoryData.cs new file mode 100644 index 0000000000..3c11bbf86e --- /dev/null +++ b/src/Ryujinx.Tests.Memory/RandomRangeUL2TheoryData.cs @@ -0,0 +1,27 @@ +using System; +using Xunit; + +namespace Ryujinx.Tests.Memory +{ + public class RandomRangeUL2TheoryData : TheoryData + { + public RandomRangeUL2TheoryData(ulong from, ulong to, int count) + { + byte[] buffer = new byte[8]; + + for (int i = 0; i < count; i++) + { + ulong[] results = new ulong[2]; + + for (int j = 0; j < results.Length; j++) + { + Random.Shared.NextBytes(buffer); + // NOTE: The result won't be perfectly random, but it should be random enough for tests + results[j] = BitConverter.ToUInt64(buffer) % (to + 1 - from) + from; + } + + Add(results[0], results[1]); + } + } + } +} diff --git a/src/Ryujinx.Tests.Memory/Tests.cs b/src/Ryujinx.Tests.Memory/Tests.cs index bfc6344b7a..5d7da7ab6a 100644 --- a/src/Ryujinx.Tests.Memory/Tests.cs +++ b/src/Ryujinx.Tests.Memory/Tests.cs @@ -1,47 +1,44 @@ -using NUnit.Framework; using Ryujinx.Memory; using System; using System.Runtime.InteropServices; +using Xunit; namespace Ryujinx.Tests.Memory { - public class Tests + public class Tests : IDisposable { private static readonly ulong _memorySize = MemoryBlock.GetPageSize() * 8; private MemoryBlock _memoryBlock; - [SetUp] - public void Setup() + public Tests() { _memoryBlock = new MemoryBlock(_memorySize); } - [TearDown] - public void Teardown() + public void Dispose() { + GC.SuppressFinalize(this); _memoryBlock.Dispose(); } - [Test] + [Fact] public void Test_Read() { Marshal.WriteInt32(_memoryBlock.Pointer, 0x2020, 0x1234abcd); - Assert.AreEqual(_memoryBlock.Read(0x2020), 0x1234abcd); + Assert.Equal(0x1234abcd, _memoryBlock.Read(0x2020)); } - [Test] + [Fact] public void Test_Write() { _memoryBlock.Write(0x2040, 0xbadc0de); - Assert.AreEqual(Marshal.ReadInt32(_memoryBlock.Pointer, 0x2040), 0xbadc0de); + Assert.Equal(0xbadc0de, Marshal.ReadInt32(_memoryBlock.Pointer, 0x2040)); } - [Test] - // Memory aliasing tests fail on CI at the moment. - [Platform(Exclude = "MacOsX")] + [Fact] public void Test_Alias() { ulong pageSize = MemoryBlock.GetPageSize(); @@ -54,14 +51,15 @@ namespace Ryujinx.Tests.Memory toAlias.UnmapView(backing, pageSize * 3, pageSize); toAlias.Write(0, 0xbadc0de); - Assert.AreEqual(Marshal.ReadInt32(backing.Pointer, (int)pageSize), 0xbadc0de); + Assert.Equal(0xbadc0de, Marshal.ReadInt32(backing.Pointer, (int)pageSize)); } - [Test] - // Memory aliasing tests fail on CI at the moment. - [Platform(Exclude = "MacOsX")] + [Fact] public void Test_AliasRandom() { + // Memory aliasing tests fail on CI at the moment. + Skip.If(OperatingSystem.IsMacOS()); + ulong pageSize = MemoryBlock.GetPageSize(); int pageBits = (int)ulong.Log2(pageSize); ulong blockSize = MemoryBlock.GetPageSize() * 128; @@ -84,7 +82,7 @@ namespace Ryujinx.Tests.Memory int offset = rng.Next(0, (int)pageSize - sizeof(int)); toAlias.Write((ulong)((dstPage << pageBits) + offset), 0xbadc0de); - Assert.AreEqual(Marshal.ReadInt32(backing.Pointer, (srcPage << pageBits) + offset), 0xbadc0de); + Assert.Equal(0xbadc0de, Marshal.ReadInt32(backing.Pointer, (srcPage << pageBits) + offset)); } else { @@ -93,11 +91,12 @@ namespace Ryujinx.Tests.Memory } } - [Test] - // Memory aliasing tests fail on CI at the moment. - [Platform(Exclude = "MacOsX")] + [Fact] public void Test_AliasMapLeak() { + // Memory aliasing tests fail on CI at the moment. + Skip.If(OperatingSystem.IsMacOS()); + ulong pageSize = MemoryBlock.GetPageSize(); ulong size = 100000 * pageSize; // The mappings limit on Linux is usually around 65K, so let's make sure we are above that. @@ -109,7 +108,7 @@ namespace Ryujinx.Tests.Memory toAlias.MapView(backing, 0, offset, pageSize); toAlias.Write(offset, 0xbadc0de); - Assert.AreEqual(0xbadc0de, backing.Read(0)); + Assert.Equal(0xbadc0de, backing.Read(0)); toAlias.UnmapView(backing, offset, pageSize); } diff --git a/src/Ryujinx.Tests.Memory/TrackingTests.cs b/src/Ryujinx.Tests.Memory/TrackingTests.cs index c74446cfb3..e6657e5e4e 100644 --- a/src/Ryujinx.Tests.Memory/TrackingTests.cs +++ b/src/Ryujinx.Tests.Memory/TrackingTests.cs @@ -1,14 +1,14 @@ -using NUnit.Framework; using Ryujinx.Memory; using Ryujinx.Memory.Tracking; using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; +using Xunit; namespace Ryujinx.Tests.Memory { - public class TrackingTests + public class TrackingTests : IDisposable { private const int RndCnt = 3; @@ -19,17 +19,16 @@ namespace Ryujinx.Tests.Memory private MemoryTracking _tracking; private MockVirtualMemoryManager _memoryManager; - [SetUp] - public void Setup() + public TrackingTests() { _memoryBlock = new MemoryBlock(MemorySize); _memoryManager = new MockVirtualMemoryManager(MemorySize, PageSize); _tracking = new MemoryTracking(_memoryManager, PageSize); } - [TearDown] - public void Teardown() + public void Dispose() { + GC.SuppressFinalize(this); _memoryBlock.Dispose(); } @@ -42,7 +41,7 @@ namespace Ryujinx.Tests.Memory return handle.Dirty; } - [Test] + [Fact] public void SingleRegion() { RegionHandle handle = _tracking.BeginTracking(0, PageSize, 0); @@ -66,13 +65,13 @@ namespace Ryujinx.Tests.Memory bool dirtyAfterUnrelatedReadWrite = handle.Dirty; Assert.False(dirtyAfterUnrelatedReadWrite); // Not dirtied, as the write was to an unrelated address. - Assert.IsNull(readTrackingTriggered); // Hasn't been triggered yet + Assert.Null(readTrackingTriggered); // Hasn't been triggered yet _tracking.VirtualMemoryEvent(0, 4, false); bool dirtyAfterRelatedRead = handle.Dirty; Assert.False(dirtyAfterRelatedRead); // Only triggers on write. - Assert.AreEqual(readTrackingTriggered, (0UL, 4UL)); // Read action was triggered. + Assert.Equal(readTrackingTriggered, (0UL, 4UL)); // Read action was triggered. readTrackingTriggered = null; _tracking.VirtualMemoryEvent(0, 4, true); @@ -95,7 +94,7 @@ namespace Ryujinx.Tests.Memory Assert.False(dirtyAfterDispose); // Handle cannot be triggered when disposed } - [Test] + [Fact] public void OverlappingRegions() { RegionHandle allHandle = _tracking.BeginTracking(0, PageSize * 16, 0); @@ -127,7 +126,7 @@ namespace Ryujinx.Tests.Memory { // No handles are dirty. Assert.False(allHandle.Dirty); - Assert.IsNull(readTrackingTriggeredAll); + Assert.Null(readTrackingTriggeredAll); for (int j = 0; j < 16; j++) { Assert.False(containedHandles[j].Dirty); @@ -137,7 +136,7 @@ namespace Ryujinx.Tests.Memory // Only the handle covering the entire range and the relevant contained handle are dirty. Assert.True(allHandle.Dirty); - Assert.AreEqual(readTrackingTriggeredAll, ((ulong)i * PageSize, 1UL)); // Triggered read tracking + Assert.Equal(readTrackingTriggeredAll, ((ulong)i * PageSize, 1UL)); // Triggered read tracking for (int j = 0; j < 16; j++) { if (j == i) @@ -157,10 +156,16 @@ namespace Ryujinx.Tests.Memory } } - [Test] - public void PageAlignment( - [Values(1ul, 512ul, 2048ul, 4096ul, 65536ul)][Random(1ul, 65536ul, RndCnt)] ulong address, - [Values(1ul, 4ul, 1024ul, 4096ul, 65536ul)][Random(1ul, 65536ul, RndCnt)] ulong size) + public static readonly RandomRangeUL2TheoryData TestDataPageAlignment = new(1ul, 65536ul, RndCnt); + + [Theory] + [InlineData(1ul, 1ul)] + [InlineData(512ul, 4ul)] + [InlineData(2048ul, 1024ul)] + [InlineData(4096ul, 4096ul)] + [InlineData(65536ul, 65536ul)] + [MemberData(nameof(TestDataPageAlignment))] + public void PageAlignment(ulong address, ulong size) { ulong alignedStart = (address / PageSize) * PageSize; ulong alignedEnd = ((address + size + PageSize - 1) / PageSize) * PageSize; @@ -191,7 +196,8 @@ namespace Ryujinx.Tests.Memory Assert.False(alignedAfterTriggers); } - [Test, Explicit, Timeout(1000)] + // This test used to be skipped unless explicitly executed + [Fact(Timeout = 1000)] public void Multithreading() { // Multithreading sanity test @@ -287,12 +293,12 @@ namespace Ryujinx.Tests.Memory thread.Join(); } - Assert.Greater(dirtyFlagReprotects, 10); - Assert.Greater(writeTriggers, 10); - Assert.Greater(handleLifecycles, 10); + Assert.True(dirtyFlagReprotects > 10); + Assert.True(writeTriggers >= 10); + Assert.True(handleLifecycles >= 10); } - [Test] + [Fact] public void ReadActionThreadConsumption() { // Read actions should only be triggered once for each registration. @@ -354,10 +360,10 @@ namespace Ryujinx.Tests.Memory // The action should trigger exactly once for every registration, // then we register once after all the threads signalling it cease. - Assert.AreEqual(registeredCount, triggeredCount + 1); + Assert.Equal(registeredCount, triggeredCount + 1); } - [Test] + [Fact] public void DisposeHandles() { // Ensure that disposed handles correctly remove their virtual and physical regions. @@ -365,11 +371,11 @@ namespace Ryujinx.Tests.Memory RegionHandle handle = _tracking.BeginTracking(0, PageSize, 0); handle.Reprotect(); - Assert.AreEqual(1, _tracking.GetRegionCount()); + Assert.Equal(1, _tracking.GetRegionCount()); handle.Dispose(); - Assert.AreEqual(0, _tracking.GetRegionCount()); + Assert.Equal(0, _tracking.GetRegionCount()); // Two handles, small entirely contains big. // We expect there to be three regions after creating both, one for the small region and two covering the big one around it. @@ -378,33 +384,33 @@ namespace Ryujinx.Tests.Memory RegionHandle handleSmall = _tracking.BeginTracking(PageSize, PageSize, 0); RegionHandle handleBig = _tracking.BeginTracking(0, PageSize * 4, 0); - Assert.AreEqual(3, _tracking.GetRegionCount()); + Assert.Equal(3, _tracking.GetRegionCount()); // After disposing the big region, only the small one will remain. handleBig.Dispose(); - Assert.AreEqual(1, _tracking.GetRegionCount()); + Assert.Equal(1, _tracking.GetRegionCount()); handleSmall.Dispose(); - Assert.AreEqual(0, _tracking.GetRegionCount()); + Assert.Equal(0, _tracking.GetRegionCount()); } - [Test] + [Fact] public void ReadAndWriteProtection() { MemoryPermission protection = MemoryPermission.ReadAndWrite; _memoryManager.OnProtect += (va, size, newProtection) => { - Assert.AreEqual((0, PageSize), (va, size)); // Should protect the exact region all the operations use. + Assert.Equal((0ul, (ulong)PageSize), (va, size)); // Should protect the exact region all the operations use. protection = newProtection; }; RegionHandle handle = _tracking.BeginTracking(0, PageSize, 0); // After creating the handle, there is no protection yet. - Assert.AreEqual(MemoryPermission.ReadAndWrite, protection); + Assert.Equal(MemoryPermission.ReadAndWrite, protection); bool dirtyInitial = handle.Dirty; Assert.True(dirtyInitial); // Handle starts dirty. @@ -412,7 +418,7 @@ namespace Ryujinx.Tests.Memory handle.Reprotect(); // After a reprotect, there is write protection, which will set a dirty flag when any write happens. - Assert.AreEqual(MemoryPermission.Read, protection); + Assert.Equal(MemoryPermission.Read, protection); (ulong address, ulong size)? readTrackingTriggered = null; handle.RegisterAction((address, size) => @@ -421,7 +427,7 @@ namespace Ryujinx.Tests.Memory }); // Registering an action adds read/write protection. - Assert.AreEqual(MemoryPermission.None, protection); + Assert.Equal(MemoryPermission.None, protection); bool dirtyAfterReprotect = handle.Dirty; Assert.False(dirtyAfterReprotect); // Handle is no longer dirty. @@ -433,9 +439,9 @@ namespace Ryujinx.Tests.Memory bool dirtyAfterRead = handle.Dirty; Assert.False(dirtyAfterRead); // Not dirtied, as this was a read. - Assert.AreEqual(readTrackingTriggered, (0UL, 4UL)); // Read action was triggered. + Assert.Equal(readTrackingTriggered, (0UL, 4UL)); // Read action was triggered. - Assert.AreEqual(MemoryPermission.Read, protection); // Write protection is still present. + Assert.Equal(MemoryPermission.Read, protection); // Write protection is still present. readTrackingTriggered = null; @@ -446,14 +452,14 @@ namespace Ryujinx.Tests.Memory bool dirtyAfterWriteAfterRead = handle.Dirty; Assert.True(dirtyAfterWriteAfterRead); // Should be dirty. - Assert.AreEqual(MemoryPermission.ReadAndWrite, protection); // All protection is now be removed from the memory. + Assert.Equal(MemoryPermission.ReadAndWrite, protection); // All protection is now be removed from the memory. - Assert.IsNull(readTrackingTriggered); // Read tracking was removed when the action fired, as it can only fire once. + Assert.Null(readTrackingTriggered); // Read tracking was removed when the action fired, as it can only fire once. handle.Dispose(); } - [Test] + [Fact] public void PreciseAction() { RegionHandle handle = _tracking.BeginTracking(0, PageSize, 0); @@ -476,22 +482,22 @@ namespace Ryujinx.Tests.Memory _tracking.VirtualMemoryEvent(0, 4, false, precise: true); - Assert.IsNull(readTrackingTriggered); // Hasn't been triggered - precise action returned true. - Assert.AreEqual(preciseTriggered, (0UL, 4UL, false)); // Precise action was triggered. + Assert.Null(readTrackingTriggered); // Hasn't been triggered - precise action returned true. + Assert.Equal(preciseTriggered, (0UL, 4UL, false)); // Precise action was triggered. _tracking.VirtualMemoryEvent(0, 4, true, precise: true); - Assert.IsNull(readTrackingTriggered); // Still hasn't been triggered. + Assert.Null(readTrackingTriggered); // Still hasn't been triggered. bool dirtyAfterPreciseActionTrue = handle.Dirty; Assert.False(dirtyAfterPreciseActionTrue); // Not dirtied - precise action returned true. - Assert.AreEqual(preciseTriggered, (0UL, 4UL, true)); // Precise action was triggered. + Assert.Equal(preciseTriggered, (0UL, 4UL, true)); // Precise action was triggered. // Handle is now dirty. handle.Reprotect(true); preciseTriggered = null; _tracking.VirtualMemoryEvent(4, 4, true, precise: true); - Assert.AreEqual(preciseTriggered, (4UL, 4UL, true)); // Precise action was triggered even though handle was dirty. + Assert.Equal(preciseTriggered, (4UL, 4UL, true)); // Precise action was triggered even though handle was dirty. handle.Reprotect(); handle.RegisterPreciseAction((address, size, write) => @@ -503,10 +509,10 @@ namespace Ryujinx.Tests.Memory _tracking.VirtualMemoryEvent(8, 4, true, precise: true); - Assert.AreEqual(readTrackingTriggered, (8UL, 4UL)); // Read action triggered, as precise action returned false. + Assert.Equal(readTrackingTriggered, (8UL, 4UL)); // Read action triggered, as precise action returned false. bool dirtyAfterPreciseActionFalse = handle.Dirty; Assert.True(dirtyAfterPreciseActionFalse); // Dirtied, as precise action returned false. - Assert.AreEqual(preciseTriggered, (8UL, 4UL, true)); // Precise action was triggered. + Assert.Equal(preciseTriggered, (8UL, 4UL, true)); // Precise action was triggered. } } }