using System;
using System.Text;
using Glass.Editing;
using Glass.Typesetting;
using Glass.UnitTests.Editing;
using UnitTestSharp;
namespace Glass.UnitTests.Typesetting
{
public class SplicedRowsTests : TestFixture
{
// Short lines, wrapped lines, empty lines and a CR LF, long enough to take several blocks of 16 chars.
public static readonly string[] Bases =
{
"ab cd\nef gh ij kl mn op qr st uv\n\nwx\r\nyz aaaa bbbb cccc\nd",
"aaaa bbbb cccc dddd eeee ffff\r\ngggg\rhhhh\n",
"x",
"",
};
public static readonly string[] Replacements = { "", "x", "\n", "\r", "\r\n", "pq rs\ntu vw xy zz" };
///
/// Describes every question a spliced text's rows answer differently from a full layout of the spliced string.
///
public static string Differences(string baseText, int start, int end, string replacement, int fitWidth = 100,
int indexStep = 1)
{
PagedText paged = PagedTextTests.Paged(baseText);
VisualLineIndex index = VisualLineIndexTests.NewIndex(fitWidth);
var spliced = new SplicedText();
spliced.Set(paged, start, end, replacement);
var rows = new SplicedRows(index);
string whole = baseText.Remove(start, end - start).Insert(start, replacement);
var layout = new VisualLineIndexTests.FullLayout(whole, fitWidth);
var returnMe = new StringBuilder();
int total = layout.TotalRows;
if (rows.TotalRows(spliced) != total)
{
returnMe.Append($"TotalRows {rows.TotalRows(spliced)} not {total}; ");
}
for (int i = 0; i <= whole.Length; i += indexStep)
{
if (layout.IsInsideCrLf(i))
{
continue;
}
foreach (bool atLineEnd in new[] { false, true })
{
if (rows.RowOf(spliced, i, atLineEnd) != layout.RowOf(i, atLineEnd))
{
returnMe.Append($"RowOf({i},{atLineEnd}) {rows.RowOf(spliced, i, atLineEnd)} not ")
.Append($"{layout.RowOf(i, atLineEnd)}; ");
}
}
}
for (int row = 0; row < total; ++row)
{
if (rows.IndexOfRow(spliced, row) != layout.IndexOfRow(row))
{
returnMe.Append($"IndexOfRow({row}) {rows.IndexOfRow(spliced, row)} not ")
.Append($"{layout.IndexOfRow(row)}; ");
}
}
return returnMe.Length == 0 ? "" : $"splice({start},{end},{replacement.Length}): {returnMe}";
}
public static readonly string Token = VisualLineIndexTests.Repeat("abcdefghij", 40);
public static readonly string Prose = VisualLineIndexTests.Repeat("abcd efgh ", 40);
// A splice that changes the length by a multiple of this keeps the rows after it where they were.
public const int RowChars = 10;
///
/// Describes how the rows of a spliced text, with a chunked line the splice is in, differ from a full layout.
/// The rows through the end of the replacement must match it. The rows after it must too when exactBelow is
/// set, and otherwise are within a row of it.
///
public static string ChunkedDifferences(string baseText, int start, int end, string replacement,
bool exactBelow, int fitWidth = 100, int indexStep = 1)
{
PagedText paged = PagedTextTests.Paged(baseText);
VisualLineIndex index = VisualLineIndexTests.NewIndex(fitWidth, blockChars: 16, longLineChars: 48);
VisualLineIndexTests.CountAll(index, paged);
var spliced = new SplicedText();
spliced.Set(paged, start, end, replacement);
var rows = new SplicedRows(index);
string whole = baseText.Remove(start, end - start).Insert(start, replacement);
var layout = new VisualLineIndexTests.FullLayout(whole, fitWidth);
int after = start + replacement.Length;
var returnMe = new StringBuilder();
int total = rows.TotalRows(spliced);
if (total != layout.TotalRows && (exactBelow || Math.Abs(total - layout.TotalRows) > 1))
{
returnMe.Append($"TotalRows {total} not {layout.TotalRows}; ");
}
for (int i = 0; i <= whole.Length; i += indexStep)
{
if (layout.IsInsideCrLf(i))
{
continue;
}
foreach (bool atLineEnd in new[] { false, true })
{
int expected = layout.RowOf(i, atLineEnd);
int actual = rows.RowOf(spliced, i, atLineEnd);
bool allowed = actual == expected || (i > after && !exactBelow && Math.Abs(actual - expected) <= 1);
if (!allowed)
{
returnMe.Append($"RowOf({i},{atLineEnd}) {actual} not {expected}; ");
}
}
}
int exactRows = layout.RowOf(after, atLineEnd: false);
for (int row = 0; row < layout.TotalRows && row < total; ++row)
{
int expected = layout.IndexOfRow(row);
int actual = rows.IndexOfRow(spliced, row);
bool allowed = actual == expected
|| (row > exactRows && !exactBelow && Math.Abs(actual - expected) <= 2 * RowChars);
if (!allowed)
{
returnMe.Append($"IndexOfRow({row}) {actual} not {expected}; ");
}
}
return returnMe.Length == 0 ? "" : $"splice({start},{end},{replacement.Length}): {returnMe}";
}
///
/// Describes how the distances across the lines of a spliced text, for lines that don't wrap, differ from those
/// of an index that counted the text with the splice in it.
///
public static string WidthDifferences(string baseText, int start, int end, string replacement,
SpriteFontDefinition font = null, TrailingSpaceMode trailingSpaces = TrailingSpaceMode.Hang,
bool widestIsExact = true)
{
PagedText paged = PagedTextTests.Paged(baseText);
VisualLineIndex index = VisualLineIndexTests.NewIndex(int.MaxValue, measureWidths: true, blockChars: 16,
longLineChars: 48, trailingSpaces: trailingSpaces, font: font);
VisualLineIndexTests.CountAll(index, paged);
var spliced = new SplicedText();
spliced.Set(paged, start, end, replacement);
var rows = new SplicedRows(index);
string composed = baseText.Remove(start, end - start).Insert(start, replacement);
PagedText reference = PagedTextTests.Paged(composed);
VisualLineIndex referenceIndex = VisualLineIndexTests.NewIndex(int.MaxValue, measureWidths: true,
blockChars: 16, longLineChars: 48, trailingSpaces: trailingSpaces, font: font);
VisualLineIndexTests.CountAll(referenceIndex, reference);
var returnMe = new StringBuilder();
if (rows.TotalRows(spliced) != referenceIndex.TotalRows(reference))
{
returnMe.Append($"TotalRows {rows.TotalRows(spliced)} not {referenceIndex.TotalRows(reference)}; ");
}
if (widestIsExact && rows.EstimatedWidestLine(spliced) != referenceIndex.EstimatedWidestLine(reference))
{
returnMe.Append($"EstimatedWidestLine {rows.EstimatedWidestLine(spliced)} not ")
.Append($"{referenceIndex.EstimatedWidestLine(reference)}; ");
}
for (int row = 0; row < referenceIndex.TotalRows(reference); ++row)
{
if (rows.IndexOfRow(spliced, row) != referenceIndex.IndexOfRow(reference, row))
{
returnMe.Append($"IndexOfRow({row}) {rows.IndexOfRow(spliced, row)} not ")
.Append($"{referenceIndex.IndexOfRow(reference, row)}; ");
}
}
for (int i = 0; i <= composed.Length; ++i)
{
if (i > 0 && i < composed.Length && composed[i - 1] == '\r' && composed[i] == '\n')
{
continue;
}
long expected = referenceIndex.WidthBefore(reference, i);
if (rows.WidthBefore(spliced, i) != expected)
{
returnMe.Append($"WidthBefore({i}) {rows.WidthBefore(spliced, i)} not {expected}; ");
}
if (rows.RowOf(spliced, i, atLineEnd: false) != referenceIndex.RowOf(reference, i, atLineEnd: false))
{
returnMe.Append($"RowOf({i}) {rows.RowOf(spliced, i, atLineEnd: false)} not ")
.Append($"{referenceIndex.RowOf(reference, i, atLineEnd: false)}; ");
}
if (i == 0 || composed[i - 1] == '\n' || composed[i - 1] == '\r')
{
long lineWidth = referenceIndex.EstimatedLineWidth(reference, i);
if (rows.EstimatedLineWidth(spliced, i) != lineWidth)
{
returnMe.Append($"EstimatedLineWidth({i}) {rows.EstimatedLineWidth(spliced, i)} not ")
.Append($"{lineWidth}; ");
}
}
}
for (int line = 0; line < reference.HardLineCount; ++line)
{
int lineStart = reference.StartOfLineNumber(line);
long lineWidth = referenceIndex.EstimatedLineWidth(reference, lineStart);
for (long x = 0; x <= lineWidth + 20; x += 7)
{
int expected = referenceIndex.IndexAtWidth(reference, lineStart, x);
int actual = rows.IndexAtWidth(spliced, lineStart, x);
long expectedAway = Math.Abs(referenceIndex.WidthBefore(reference, expected) - x);
long actualAway = Math.Abs(referenceIndex.WidthBefore(reference, actual) - x);
if (actual != expected && actualAway != expectedAway)
{
returnMe.Append($"IndexAtWidth({lineStart}, {x}) {actual} not {expected}; ");
}
}
}
return returnMe.Length == 0 ? "" : $"splice({start},{end},{replacement.Length}): {returnMe}";
}
public static string DifferencesForEverySplice(string replacement, int startStep, int indexStep)
{
var returnMe = new StringBuilder();
foreach (string baseText in Bases)
{
for (int start = 0; start <= baseText.Length; start += startStep)
{
foreach (int length in new[] { 0, 1, 4, 20, 1000 })
{
int end = Math.Min(baseText.Length, start + length);
returnMe.Append(Differences(baseText, start, end, replacement, indexStep: indexStep));
}
}
}
return returnMe.ToString();
}
public class CtorTests : TestFixture
{
public void RejectsNoIndex()
{
CheckThrow(typeof(ArgumentNullException));
new SplicedRows(null);
}
}
public class TotalRowsTests : TestFixture
{
public void MatchesAFullLayout_WhenNothingIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[0], startStep: 3, indexStep: 100));
}
public void MatchesAFullLayout_WhenACharIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[1], startStep: 3, indexStep: 100));
}
public void MatchesAFullLayout_WhenALineFeedIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[2], startStep: 3, indexStep: 100));
}
public void MatchesAFullLayout_WhenACarriageReturnIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[3], startStep: 3, indexStep: 100));
}
public void MatchesAFullLayout_WhenACrLfIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[4], startStep: 3, indexStep: 100));
}
public void MatchesAFullLayout_WhenWrappedLinesAreInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[5], startStep: 3, indexStep: 100));
}
public void WhenAnInsertedCarriageReturnJoinsALineFeed_CountsOneBreak()
{
CheckEqual("", Differences("ab\ncd", 1, 2, "x\r", indexStep: 1));
}
public void OnAChunkedLine_WhenARowOfCharsIsInserted_MatchesAFullLayout()
{
CheckEqual("", ChunkedDifferences(Token, 205, 205, "klmnopqrst", exactBelow: true));
}
public void OnAChunkedLine_WhenARowOfCharsIsDeleted_MatchesAFullLayout()
{
CheckEqual("", ChunkedDifferences(Token, 205, 215, "", exactBelow: true));
}
public void OnAChunkedLine_WhenCharsAreReplacedByAsManyChars_MatchesAFullLayout()
{
CheckEqual("", ChunkedDifferences(Token, 205, 208, "xyz", exactBelow: true));
}
[Thorough]
public void OnAChunkedLine_WhenTheRowsAfterAreShifted_IsWithinARowOfAFullLayout()
{
var returnMe = new StringBuilder();
foreach (int start in new[] { 0, 1, 16, 103, 205, 399, 400 })
{
returnMe.Append(ChunkedDifferences(Token, start, start, "xyz", exactBelow: false));
returnMe.Append(ChunkedDifferences(Token, start, Math.Min(400, start + 30), "xy",
exactBelow: false));
}
CheckEqual("", returnMe.ToString());
}
public void OnAChunkedLineOfProse_WhenTheRowsAfterAreShifted_IsWithinARowOfAFullLayout()
{
var returnMe = new StringBuilder();
foreach (int start in new[] { 0, 7, 103, 205, 399 })
{
returnMe.Append(ChunkedDifferences(Prose, start, start, "wxyz", exactBelow: false));
returnMe.Append(ChunkedDifferences(Prose, start, Math.Min(400, start + 15), "x",
exactBelow: false));
}
CheckEqual("", returnMe.ToString());
}
public void OnAChunkedLine_WhenALineBreakIsInserted_IsWithinARowOfAFullLayout()
{
CheckEqual("", ChunkedDifferences(Token, 205, 205, "xy\nz", exactBelow: false));
}
[Thorough]
public void OnAChunkedLine_AmongShortOnes_IsWithinARowOfAFullLayout()
{
string text = "ab\ncd\n" + Token + "\nef\n" + Prose + "\ngh";
var returnMe = new StringBuilder();
foreach (int start in new[] { 3, 200, 420 })
{
returnMe.Append(ChunkedDifferences(text, start, start + 2, "xyz", exactBelow: false));
}
CheckEqual("", returnMe.ToString());
}
}
public class RowOfTests : TestFixture
{
[Thorough]
public void MatchesAFullLayoutAtEveryIndex_WhenNothingIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[0], startStep: 5, indexStep: 1));
}
public void MatchesAFullLayoutAtEveryIndex_WhenACharIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[1], startStep: 5, indexStep: 1));
}
[Thorough]
public void MatchesAFullLayoutAtEveryIndex_WhenALineFeedIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[2], startStep: 5, indexStep: 1));
}
[Thorough]
public void MatchesAFullLayoutAtEveryIndex_WhenACarriageReturnIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[3], startStep: 5, indexStep: 1));
}
[Thorough]
public void MatchesAFullLayoutAtEveryIndex_WhenACrLfIsInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[4], startStep: 5, indexStep: 1));
}
public void MatchesAFullLayoutAtEveryIndex_WhenWrappedLinesAreInserted()
{
CheckEqual("", DifferencesForEverySplice(Replacements[5], startStep: 5, indexStep: 1));
}
public void MatchesAFullLayoutAtEveryIndex_AtOtherWidths()
{
var returnMe = new StringBuilder();
foreach (int width in new[] { 15, 45, 250 })
{
returnMe.Append(Differences(Bases[0], 8, 30, Replacements[5], width));
returnMe.Append(Differences(Bases[1], 0, 0, Replacements[2], width));
returnMe.Append(Differences(Bases[1], 20, 38, Replacements[0], width));
}
CheckEqual("", returnMe.ToString());
}
}
public class CheckpointAtOrBeforeTests : TestFixture
{
public static SplicedText Spliced(out PagedText paged, out VisualLineIndex index,
out SplicedRows rows)
{
paged = PagedTextTests.Paged(Token);
index = VisualLineIndexTests.NewIndex(blockChars: 16, longLineChars: 48);
VisualLineIndexTests.CountAll(index, paged);
rows = new SplicedRows(index);
var returnMe = new SplicedText();
returnMe.Set(paged, 205, 205, "xyz");
return returnMe;
}
public void BeforeTheSplice_IsTheChunkStartUnderneath()
{
SplicedText spliced = Spliced(out PagedText paged, out VisualLineIndex index, out SplicedRows rows);
CheckEqual(index.CheckpointAtOrBefore(paged, 100), rows.CheckpointAtOrBefore(spliced, 100));
}
public void InTheStretchTheSpliceTouches_IsTheStartOfTheStretch()
{
SplicedText spliced = Spliced(out PagedText paged, out VisualLineIndex index, out SplicedRows rows);
int stretchStart = index.CheckpointAtOrBefore(paged, 205);
CheckEqual(stretchStart, rows.CheckpointAtOrBefore(spliced, 206));
CheckEqual(stretchStart, rows.CheckpointAtOrBefore(spliced, 208));
CheckTrue(stretchStart <= 205 && stretchStart > 205 - CheckpointAtOrBeforeTests.ChunkBound);
}
public const int ChunkBound = VisualLineIndexTests.CheckpointAtOrBeforeTests.ChunkBound;
public void AfterTheStretch_IsTheChunkStartUnderneathMovedWithTheText()
{
SplicedText spliced = Spliced(out PagedText paged, out VisualLineIndex index, out SplicedRows rows);
CheckEqual(index.CheckpointAtOrBefore(paged, 300) + 3, rows.CheckpointAtOrBefore(spliced, 303));
}
public void ShortAfterTheStretch_IsNotBeforeTheStretchEnds()
{
SplicedText spliced = Spliced(out _, out _, out SplicedRows rows);
CheckTrue(rows.CheckpointAtOrBefore(spliced, 209) <= 209);
CheckTrue(rows.CheckpointAtOrBefore(spliced, 209) >= 205 - ChunkBound);
}
public void OnAShortLine_IsTheStartOfTheLine()
{
PagedText paged = PagedTextTests.Paged("ab cd\nef gh ij");
var spliced = new SplicedText();
spliced.Set(paged, 8, 9, "xyz");
var rows = new SplicedRows(VisualLineIndexTests.NewIndex(longLineChars: 48));
CheckEqual(6, rows.CheckpointAtOrBefore(spliced, 11));
CheckEqual(0, rows.CheckpointAtOrBefore(spliced, 3));
}
}
public class IndexOfRowTests : TestFixture
{
public void ARowAfterTheStretchOfAChunkedLine_KeepsTheStartItHadUnderneathMovedWithTheText()
{
PagedText paged = PagedTextTests.Paged(Token);
VisualLineIndex index = VisualLineIndexTests.NewIndex(blockChars: 16, longLineChars: 48);
VisualLineIndexTests.CountAll(index, paged);
var spliced = new SplicedText();
spliced.Set(paged, 205, 205, "xyz");
var rows = new SplicedRows(index);
CheckEqual(rows.IndexOfRow(spliced, 31), rows.IndexOfRow(spliced, 30) + RowChars);
CheckTrue(rows.IndexOfRow(spliced, 30) % RowChars == 3);
}
public void AFarRow_LeadsToTheLastRowsStart()
{
PagedText paged = PagedTextTests.Paged("ab\ncd");
var spliced = new SplicedText();
spliced.Set(paged, 1, 2, "x\ny");
var rows = new SplicedRows(VisualLineIndexTests.NewIndex());
CheckEqual(5, rows.IndexOfRow(spliced, 500));
}
public void ANegativeRow_LeadsToTheStart()
{
PagedText paged = PagedTextTests.Paged("ab\ncd");
var spliced = new SplicedText();
spliced.Set(paged, 1, 2, "x\ny");
var rows = new SplicedRows(VisualLineIndexTests.NewIndex());
CheckEqual(0, rows.IndexOfRow(spliced, -3));
}
}
// A line past the long length with a short one either side, and spaces in it to hang or to break on.
public static readonly string WideLines = "ab\n" + VisualLineIndexTests.Repeat("abcd efgh ", 20) + "\ncd";
public static readonly string KernedLines = "ab\n" + VisualLineIndexTests.Repeat("AVAWTa ", 40) + "\ncd";
public static readonly string SpacedLines = "ab\n" + VisualLineIndexTests.Repeat("abcd efgh ", 20) + " \ncd";
public class WidthBeforeTests : TestFixture
{
public void InALineCountedInChunks_AfterACharIsInserted_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(WideLines, 100, 100, "xy"));
}
public void InALineCountedInChunks_AfterCharsAreReplaced_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(WideLines, 100, 140, "wxyz!"));
}
public void InALineCountedInChunks_AfterCharsAreDeleted_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(WideLines, 30, 180, ""));
}
public void InALineCountedInChunks_AtTheStartOfTheLine_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(WideLines, 3, 3, "xy"));
}
public void InALineCountedInChunks_AtTheEndOfTheLine_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(WideLines, 203, 203, "xy"));
}
public void InALineCountedInChunks_AtEveryCharOfTheLine_IsWhereTheSplicedTextPutsIt()
{
var returnMe = new StringBuilder();
for (int start = 3; start <= 203; start += 7)
{
returnMe.Append(WidthDifferences(WideLines, start, Math.Min(203, start + 2), "q"));
}
CheckEqual("", returnMe.ToString());
}
public void InALineCountedInChunks_WithKerning_IsWhereTheSplicedTextPutsIt()
{
SpriteFontDefinition kerned = VisualLineIndexTests.WidthChunkedLinesTests.Kerned;
var returnMe = new StringBuilder();
foreach (int start in new[] { 3, 20, 21, 100, 283 })
{
returnMe.Append(WidthDifferences(KernedLines, start, start, "AVT", kerned));
returnMe.Append(WidthDifferences(KernedLines, start, Math.Min(283, start + 3), "WA", kerned));
}
CheckEqual("", returnMe.ToString());
}
public void InALineCountedInChunks_WithSpacesAtItsEnd_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(SpacedLines, 100, 100, "xy"));
CheckEqual("", WidthDifferences(SpacedLines, 203, 205, "q"));
CheckEqual("", WidthDifferences(SpacedLines, 207, 207, " "));
}
public void InALineCountedInChunks_WhenSpacesWrap_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(SpacedLines, 100, 100, "xy", trailingSpaces: TrailingSpaceMode.Wrap));
CheckEqual("", WidthDifferences(SpacedLines, 203, 205, "q", trailingSpaces: TrailingSpaceMode.Wrap));
}
public void InAShortLine_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(WideLines, 1, 1, "xy", widestIsExact: false));
CheckEqual("", WidthDifferences(WideLines, 206, 206, "xy"));
}
public void WhenTheSpliceHasABreak_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(WideLines, 100, 100, "x\ny"));
}
public void WhenTheSpliceJoinsLines_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(WideLines, 1, 206, "zz", widestIsExact: false));
CheckEqual("", WidthDifferences(WideLines, 200, 206, "zz"));
}
public void AtTheEndOfTheText_IsWhereTheSplicedTextPutsIt()
{
CheckEqual("", WidthDifferences(WideLines, 283 - 100, 283 - 100, "xy"));
CheckEqual("", WidthDifferences(WideLines, WideLines.Length, WideLines.Length, "xy"));
CheckEqual("", WidthDifferences(WideLines, 100, WideLines.Length, "xy"));
}
}
public class IndexAtWidthTests : TestFixture
{
public void InALineCountedInChunks_IsTheStopNearestInTheSplicedText()
{
var returnMe = new StringBuilder();
foreach (int start in new[] { 3, 50, 120, 203 })
{
returnMe.Append(WidthDifferences(WideLines, start, Math.Min(203, start + 5), "xyz"));
}
CheckEqual("", returnMe.ToString());
}
public void InALineCountedInChunks_WithAWiderReplacement_IsTheStopNearestInTheSplicedText()
{
CheckEqual("", WidthDifferences(WideLines, 60, 61, VisualLineIndexTests.Repeat("W", 30)));
}
}
public class EstimatedLineWidthTests : TestFixture
{
public void OfALineCountedInChunks_IsTheWidthOfTheSplicedLine()
{
CheckEqual("", WidthDifferences(WideLines, 100, 110, "xy"));
}
public void OfALineCountedInChunks_WhenTheSpliceChangesTheHangingSpaces_IsTheWidthOfTheSplicedLine()
{
CheckEqual("", WidthDifferences(SpacedLines, 203, 207, "q"));
CheckEqual("", WidthDifferences(SpacedLines, 190, 207, ""));
}
public void OfALineBeforeAndAfterTheSplice_IsTheWidthUnderneath()
{
CheckEqual("", WidthDifferences(WideLines, 206, 206, "xyz"));
CheckEqual("", WidthDifferences("ab\n" + WideLines, 100, 100, "x"));
}
}
public class EstimatedWidestLineTests : TestFixture
{
public void WhenTheSpliceNarrowsTheWidestLine_IsTheSplicedLinesWidth()
{
CheckEqual("", WidthDifferences(WideLines, 20, 190, "q"));
}
public void WhenTheSpliceWidensTheWidestLine_IsTheSplicedLinesWidth()
{
CheckEqual("", WidthDifferences(WideLines, 100, 100, VisualLineIndexTests.Repeat("W", 40)));
}
public void WhenAnotherLineIsWider_IsThatLinesWidth()
{
string text = WideLines + "\n" + VisualLineIndexTests.Repeat("WWWW ", 60);
CheckEqual("", WidthDifferences(text, 100, 150, "q"));
}
}
public class WidestLineTests : TestFixture
{
public void WhenTheSpliceNarrowsALineCountedInChunks_IsTheSplicedLinesWidth()
{
PagedText paged = PagedTextTests.Paged(WideLines);
VisualLineIndex index = VisualLineIndexTests.NewIndex(int.MaxValue, measureWidths: true,
blockChars: 16, longLineChars: 48);
VisualLineIndexTests.CountAll(index, paged);
var spliced = new SplicedText();
spliced.Set(paged, 20, 190, "q");
var rows = new SplicedRows(index);
long expected = index.WidthBefore(paged, 20) + 10 + index.WidestLine(paged)
- index.WidthBefore(paged, 190);
CheckEqual(expected, rows.WidestLine(spliced));
}
public static VisualLineIndex NoWrapIndex()
{
return VisualLineIndexTests.NewIndex(int.MaxValue, measureWidths: true);
}
public void CountsAWiderLineTheSpliceBrings()
{
PagedText paged = PagedTextTests.Paged("ab\ncd\nef");
var spliced = new SplicedText();
spliced.Set(paged, 3, 3, "abcdefgh");
var rows = new SplicedRows(NoWrapIndex());
CheckEqual(100, rows.WidestLine(spliced));
}
public void StillCountsALineTheSpliceReplaced()
{
PagedText paged = PagedTextTests.Paged("ab\nabcdefgh\nef");
var spliced = new SplicedText();
spliced.Set(paged, 3, 11, "x");
var rows = new SplicedRows(NoWrapIndex());
CheckEqual(80, rows.WidestLine(spliced));
}
public void IsTheTextUnderneathsWidestLine_WhenTheSpliceIsNarrower()
{
PagedText paged = PagedTextTests.Paged("ab\ncdefg\nef");
var spliced = new SplicedText();
spliced.Set(paged, 0, 0, "x");
var rows = new SplicedRows(NoWrapIndex());
CheckEqual(50, rows.WidestLine(spliced));
}
}
}
}