XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Runtime.CompilerServices;
using XFESystem.Desktop;
using Xunit;

namespace XFESystem.Desktop.Tests;

public sealed class EditorReadbackTrackerTests
{
    [Theory]
    [InlineData("Large.cs")]
    [InlineData("Large.md")]
    public void TenThousandUnchangedLargeReadbacksAllocateNothing(string path)
    {
        var tracker = new EditorReadbackTracker();
        string content = new('x', 128 * 1024);
        Assert.True(tracker.TryUpdate(7, path, content, out string prefix));
        Assert.Equal(EditorReadbackTracker.MaximumPrefixCharacters, prefix.Length);
        for (int index = 0; index < 100; index++) tracker.TryUpdate(7, path, content, out _);

        bool unchanged = true;
        long before = GC.GetAllocatedBytesForCurrentThread();
        for (int index = 0; index < 10_000; index++)
            unchanged &= !tracker.TryUpdate(7, path, content, out _);
        long allocated = GC.GetAllocatedBytesForCurrentThread() - before;

        Assert.True(unchanged);
        Assert.Equal(0, allocated);
        GC.KeepAlive(tracker);
    }

    [Fact]
    public void ObservedPrefixLengthPathAndWindowChangesEachReportOnce()
    {
        var tracker = new EditorReadbackTracker();
        string original = new('a', 128 * 1024);
        AssertChangeOnce(tracker, 1, "Sample.cs", original);
        string prefixChanged = "b" + original[1..];
        AssertChangeOnce(tracker, 1, "Sample.cs", prefixChanged);
        AssertChangeOnce(tracker, 1, "Sample.cs", prefixChanged + "x");
        AssertChangeOnce(tracker, 1, "Moved.cs", prefixChanged + "x");
        AssertChangeOnce(tracker, 2, "Moved.cs", prefixChanged + "x");
    }

    [Fact]
    public void EqualLengthChangesBeyondThePrefixKeepTheExistingTruncationSemantics()
    {
        var tracker = new EditorReadbackTracker();
        string content = new('a', 128 * 1024);
        Assert.True(tracker.TryUpdate(1, "Large.md", content, out string originalPrefix));
        string changedOutsidePrefix = content[..EditorReadbackTracker.MaximumPrefixCharacters] +
            new string('z', content.Length - EditorReadbackTracker.MaximumPrefixCharacters);

        Assert.False(tracker.TryUpdate(1, "Large.md", changedOutsidePrefix, out string prefix));
        Assert.Same(originalPrefix, prefix);
        Assert.Equal(content[..EditorReadbackTracker.MaximumPrefixCharacters], prefix);
    }

    [Theory]
    [InlineData(0)]
    [InlineData(8191)]
    [InlineData(8192)]
    [InlineData(8193)]
    public void PrefixBoundaryAndResetPreserveExactSourceCharacters(int characters)
    {
        var tracker = new EditorReadbackTracker();
        string content = new('\u4E2D', characters);
        Assert.True(tracker.TryUpdate(0, "Boundary.md", content, out string prefix));
        Assert.Equal(content[..Math.Min(characters, EditorReadbackTracker.MaximumPrefixCharacters)], prefix);
        Assert.False(tracker.TryUpdate(0, "Boundary.md", content, out _));

        tracker.Reset();
        tracker.Reset();
        Assert.True(tracker.TryUpdate(0, "Boundary.md", content, out string afterReset));
        Assert.Equal(prefix, afterReset);
    }

    [Fact]
    public void AStillLiveTrackerDoesNotKeepTheOriginalLargeSourceAlive()
    {
        var tracker = new EditorReadbackTracker();
        var source = TrackLargeSource(tracker, out string prefix);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        Assert.False(source.TryGetTarget(out _));
        Assert.Equal(EditorReadbackTracker.MaximumPrefixCharacters, prefix.Length);
        Assert.Equal(new string('q', EditorReadbackTracker.MaximumPrefixCharacters), prefix);
        GC.KeepAlive(prefix);
        GC.KeepAlive(tracker);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static WeakReference<string> TrackLargeSource(EditorReadbackTracker tracker, out string prefix)
    {
        string content = new('q', 128 * 1024);
        Assert.True(tracker.TryUpdate(1, "Closed.cs", content, out prefix));
        Assert.NotSame(content, prefix);
        return new(content);
    }

    private static void AssertChangeOnce(EditorReadbackTracker tracker, int id, string path, string content)
    {
        Assert.True(tracker.TryUpdate(id, path, content, out string prefix));
        Assert.Equal(content[..EditorReadbackTracker.MaximumPrefixCharacters], prefix);
        Assert.False(tracker.TryUpdate(id, path, content, out string unchanged));
        Assert.Same(prefix, unchanged);
    }
}