using Amphora;
using Glass.Editing;
using System;
using System.Collections.Generic;
using UnitTestSharp;
namespace Glass.UnitTests.Editing
{
public class ReplacementReaderTests : TestFixture
{
public const string Grin = "\U0001F600";
///
/// Hands out a text in chunks of a fixed size and remembers where each was asked for.
///
public class ScriptedChunks : IChunkedText
{
private readonly string text;
private readonly int chunkSize;
public List Asked { get; } = new List();
public ScriptedChunks(string text, int chunkSize)
{
this.text = text;
this.chunkSize = chunkSize;
}
public int Length => text.Length;
public StringView GetChunk(int start)
{
Asked.Add(start);
return new StringView(text, start, Math.Min(text.Length, start + chunkSize));
}
}
public static ReplacementReader ReaderWithRoom(int room, IEditLimit limit = null)
{
return new ReplacementReader(new StringSource(""), start: 0, length: 0, room, limit, pageSize: 8);
}
public static string Digits(int count)
{
return SourceChunksTests.Digits(count);
}
public class CtorTests : TestFixture
{
public void NullText_Throws()
{
CheckThrow(typeof(ArgumentNullException));
new ReplacementReader(null, start: 0, length: 0, room: 5, limit: null, pageSize: 8);
}
public void StartsWithNothingCut()
{
CheckFalse(ReaderWithRoom(5).WasTruncated);
}
}
public class ReadTests : TestFixture
{
public void NullSource_Throws()
{
CheckThrow(typeof(ArgumentNullException));
ReaderWithRoom(5).Read(null);
}
public void AnEmptyChunk_Throws()
{
var chunks = new EditBufferTests.BrokenChunks(4, "");
CheckThrow(typeof(InvalidOperationException));
ReaderWithRoom(100).Read(chunks);
}
public void AChunkPastTheLength_Throws()
{
var chunks = new EditBufferTests.BrokenChunks(4, "toolong");
CheckThrow(typeof(InvalidOperationException));
ReaderWithRoom(100).Read(chunks);
}
public void EmptySource_GivesNoText()
{
var chunks = new ScriptedChunks("", 3);
PagedText pages = ReaderWithRoom(5).Read(chunks);
CheckEqual(0, pages.Length);
CheckEqual(0, chunks.Asked.Count);
}
public void JoinsTheChunks()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks("hello, world", 5));
CheckEqual("hello, world", pages.ToString());
}
public void AsksForEachChunkWhereTheLastEnded()
{
var chunks = new ScriptedChunks("hello, world", 5);
ReaderWithRoom(100).Read(chunks);
CheckEqual(new[] { 0, 5, 10 }, chunks.Asked.ToArray());
}
public void BuildsPagesOfTheGivenSize()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks(Digits(40), 40));
CheckEqual(8, pages.PageSize);
}
public void DropsControlCharsInEveryChunk()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks("a\u0001b\u0002c\u0003d", 2));
CheckEqual("abcd", pages.ToString());
}
public void KeepsHardBreaks()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks("a\nb\r\nc", 2));
CheckEqual("a\nb\r\nc", pages.ToString());
}
public void ACrLfSplitAcrossChunks_StaysTogether()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks("ab\r\ncd", 3));
CheckEqual("ab\r\ncd", pages.ToString());
}
public void APairSplitAcrossChunks_IsKept()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks("ab" + Grin + "cd", 3));
CheckEqual("ab" + Grin + "cd", pages.ToString());
}
public void APairSplitAcrossChunks_WhoseChunkIsOneChar_IsKept()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks("a" + Grin + "b", 1));
CheckEqual("a" + Grin + "b", pages.ToString());
}
public void AHighSurrogateAtAChunkEndWithNoLowAfter_IsDropped()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks("ab\uD83Dcd", 3));
CheckEqual("abcd", pages.ToString());
}
public void AHighSurrogateAtTheEndOfTheText_IsDropped()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks("ab\uD83D", 3));
CheckEqual("ab", pages.ToString());
}
public void ALoneLowSurrogate_IsDropped()
{
PagedText pages = ReaderWithRoom(100).Read(new ScriptedChunks("ab\uDE00cd", 3));
CheckEqual("abcd", pages.ToString());
}
public void TextThatFitsExactly_IsNotCut()
{
var reader = ReaderWithRoom(5);
PagedText pages = reader.Read(new ScriptedChunks("hello", 2));
CheckEqual("hello", pages.ToString());
CheckFalse(reader.WasTruncated);
}
public void TextPastTheRoom_IsCutThere()
{
var reader = ReaderWithRoom(7);
PagedText pages = reader.Read(new ScriptedChunks("hello, world", 5));
CheckEqual("hello, ", pages.ToString());
CheckTrue(reader.WasTruncated);
}
public void StopsAskingOnceTheRoomIsFull()
{
var chunks = new ScriptedChunks(Digits(60), 3);
ReaderWithRoom(5).Read(chunks);
CheckEqual(new[] { 0, 3 }, chunks.Asked.ToArray());
}
public void ARoomOfNone_ReadsOneChunkAndTakesNothing()
{
var reader = ReaderWithRoom(0);
var chunks = new ScriptedChunks("hello", 3);
PagedText pages = reader.Read(chunks);
CheckEqual(0, pages.Length);
CheckTrue(reader.WasTruncated);
CheckEqual(new[] { 0 }, chunks.Asked.ToArray());
}
public void ARoomOfNone_WithALineFeedFirst_TakesNothing()
{
PagedText pages = ReaderWithRoom(0).Read(new ScriptedChunks("\nabc", 4));
CheckEqual(0, pages.Length);
}
public void ACutThroughAPair_DropsTheWholePair()
{
var reader = ReaderWithRoom(3);
PagedText pages = reader.Read(new ScriptedChunks("ab" + Grin + "cd", 10));
CheckEqual("ab", pages.ToString());
CheckTrue(reader.WasTruncated);
}
public void ACutThroughAPairSplitAcrossChunks_DropsTheWholePair()
{
var reader = ReaderWithRoom(3);
PagedText pages = reader.Read(new ScriptedChunks("ab" + Grin + "cd", 3));
CheckEqual("ab", pages.ToString());
CheckTrue(reader.WasTruncated);
}
public void ACutThroughACrLf_DropsTheWholeBreak()
{
var reader = ReaderWithRoom(2);
PagedText pages = reader.Read(new ScriptedChunks("a\r\nb", 10));
CheckEqual("a", pages.ToString());
}
public void ACutBetweenTheCrAndLfOfTwoChunks_DropsTheWholeBreak()
{
var reader = ReaderWithRoom(2);
PagedText pages = reader.Read(new ScriptedChunks("a\r\nb", 2));
CheckEqual("a", pages.ToString());
CheckTrue(reader.WasTruncated);
}
public void ACutAfterALoneCr_KeepsIt()
{
var reader = ReaderWithRoom(2);
PagedText pages = reader.Read(new ScriptedChunks("a\rb", 2));
CheckEqual("a\r", pages.ToString());
}
public void TheRoomCountsCleanedText()
{
var reader = ReaderWithRoom(3);
PagedText pages = reader.Read(new ScriptedChunks("a\u0001b\u0001c\u0001d", 2));
CheckEqual("abc", pages.ToString());
CheckTrue(reader.WasTruncated);
}
public void ATextEndingInDroppedCharsAfterAFullRoom_IsNotCut()
{
var reader = ReaderWithRoom(3);
PagedText pages = reader.Read(new ScriptedChunks("abc\u0001\u0001", 3));
CheckEqual("abc", pages.ToString());
CheckFalse(reader.WasTruncated);
}
}
public class WithALimitTests : TestFixture
{
public void ALimitThatAllowsAll_KeepsTheText()
{
var limit = new EditBufferTests.FixedLimit(int.MaxValue);
var reader = ReaderWithRoom(100, limit);
PagedText pages = reader.Read(new ScriptedChunks("hello, world", 5));
CheckEqual("hello, world", pages.ToString());
CheckFalse(reader.WasTruncated);
}
public void ALimitIsAskedAboutShortTextOnce_WithAllOfIt()
{
var limit = new EditBufferTests.FixedLimit(int.MaxValue);
ReaderWithRoom(100, limit).Read(new ScriptedChunks("hello, world", 5));
CheckEqual(1, limit.Asked);
CheckEqual("hello, world", limit.ReplacementSeen);
}
public void ALimitIsAskedWhereTheReplacementGoes()
{
var limit = new EditBufferTests.FixedLimit(int.MaxValue);
var reader = new ReplacementReader(new StringSource("0123456789"), start: 2, length: 3, room: 100,
limit, pageSize: 8);
reader.Read(new ScriptedChunks("ab", 5));
CheckEqual("0123456789", limit.TextSeen);
CheckEqual(2, limit.StartSeen);
CheckEqual(3, limit.LengthSeen);
}
public void AnEmptyReplacement_DoesNotAskTheLimit()
{
var limit = new EditBufferTests.FixedLimit(int.MaxValue);
ReaderWithRoom(100, limit).Read(new ScriptedChunks("\u0001\u0002", 1));
CheckEqual(0, limit.Asked);
}
public void ALimitThatCuts_KeepsWhatFits()
{
var limit = new EditBufferTests.FixedLimit(4);
var reader = ReaderWithRoom(100, limit);
PagedText pages = reader.Read(new ScriptedChunks("hello, world", 5));
CheckEqual("hell", pages.ToString());
CheckTrue(reader.WasTruncated);
}
public void ALimitThatAllowsNone_GivesNoText()
{
var limit = new EditBufferTests.FixedLimit(0);
var reader = ReaderWithRoom(100, limit);
PagedText pages = reader.Read(new ScriptedChunks("hello", 5));
CheckEqual(0, pages.Length);
CheckTrue(reader.WasTruncated);
}
public void ALimitThatCutsThroughAPair_DropsTheWholePair()
{
var limit = new EditBufferTests.FixedLimit(3);
PagedText pages = ReaderWithRoom(100, limit).Read(new ScriptedChunks("ab" + Grin + "cd", 10));
CheckEqual("ab", pages.ToString());
}
public void AskedAtDoublingSizes_OverALongText()
{
var limit = new EditBufferTests.FixedLimit(int.MaxValue);
int chunk = 1 << 14;
ReaderWithRoom(int.MaxValue, limit).Read(new ScriptedChunks(Digits(chunk * 3), chunk));
CheckEqual(3, limit.Asked);
}
public void ALimitThatCutsEarly_StopsAskingForChunks()
{
var limit = new EditBufferTests.FixedLimit(100);
var chunks = new ScriptedChunks(Digits((1 << 14) * 5), 1 << 14);
PagedText pages = ReaderWithRoom(int.MaxValue, limit).Read(chunks);
CheckEqual(100, pages.Length);
CheckEqual(new[] { 0 }, chunks.Asked.ToArray());
}
public void ARoomOfNone_WithALineFeedFirst_TakesNothing()
{
var limit = new EditBufferTests.FixedLimit(int.MaxValue);
PagedText pages = ReaderWithRoom(0, limit).Read(new ScriptedChunks("\nabc", 4));
CheckEqual(0, pages.Length);
}
public void ALimitTighterThanTheRoom_CutsWhatTheRoomLetsIn()
{
var limit = new EditBufferTests.FixedLimit(2);
var reader = ReaderWithRoom(5, limit);
PagedText pages = reader.Read(new ScriptedChunks("hello, world", 10));
CheckEqual("he", pages.ToString());
CheckTrue(reader.WasTruncated);
}
public void TheRoomAndALimit_BothApply()
{
var limit = new EditBufferTests.FixedLimit(4);
var reader = ReaderWithRoom(3, limit);
PagedText pages = reader.Read(new ScriptedChunks("hello", 5));
CheckEqual("hel", pages.ToString());
CheckTrue(reader.WasTruncated);
}
public void ACrCutOffByTheRoomBeforeItsLf_IsDropped()
{
var limit = new EditBufferTests.FixedLimit(int.MaxValue);
var reader = ReaderWithRoom(2, limit);
PagedText pages = reader.Read(new ScriptedChunks("a\r\nb", 2));
CheckEqual("a", pages.ToString());
}
}
}
}