This commit is contained in:
Eli Arbel 2019-03-22 12:46:22 +02:00 коммит произвёл GitHub
Родитель e21a08982f
Коммит 2caf1679fa
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
28 изменённых файлов: 3862 добавлений и 1 удалений

Просмотреть файл

@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaEdit", "src\Avaloni
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaEdit.Demo", "src\AvaloniaEdit.Demo\AvaloniaEdit.Demo.csproj", "{03763F37-9BD9-4D1D-ADC9-1050F6F8C062}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaEdit.Tests", "test\AvaloniaEdit.Tests\AvaloniaEdit.Tests.csproj", "{9E5D4372-D362-44A2-984D-578288870AB8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -31,6 +33,14 @@ Global
{03763F37-9BD9-4D1D-ADC9-1050F6F8C062}.Release|Any CPU.Build.0 = Release|Any CPU
{03763F37-9BD9-4D1D-ADC9-1050F6F8C062}.Release|x64.ActiveCfg = Release|Any CPU
{03763F37-9BD9-4D1D-ADC9-1050F6F8C062}.Release|x64.Build.0 = Release|Any CPU
{9E5D4372-D362-44A2-984D-578288870AB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E5D4372-D362-44A2-984D-578288870AB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E5D4372-D362-44A2-984D-578288870AB8}.Debug|x64.ActiveCfg = Debug|Any CPU
{9E5D4372-D362-44A2-984D-578288870AB8}.Debug|x64.Build.0 = Debug|Any CPU
{9E5D4372-D362-44A2-984D-578288870AB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E5D4372-D362-44A2-984D-578288870AB8}.Release|Any CPU.Build.0 = Release|Any CPU
{9E5D4372-D362-44A2-984D-578288870AB8}.Release|x64.ActiveCfg = Release|Any CPU
{9E5D4372-D362-44A2-984D-578288870AB8}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

Просмотреть файл

@ -1,7 +1,11 @@
using Avalonia.Metadata;
using System.Runtime.CompilerServices;
using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui/avaloniaedit", "AvaloniaEdit")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui/avaloniaedit", "AvaloniaEdit.Editing")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui/avaloniaedit", "AvaloniaEdit.Rendering")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui/avaloniaedit", "AvaloniaEdit.Highlighting")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui/avaloniaedit", "AvaloniaEdit.Search")]
[assembly: InternalsVisibleTo("AvaloniaEdit.Tests")]

Просмотреть файл

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="Moq" Version="4.10.1" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\AvaloniaEdit\AvaloniaEdit.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.IO;
using Avalonia;
using Avalonia.Media;
using Avalonia.Platform;
using Moq;
namespace AvaloniaEdit.AvaloniaMocks
{
public class MockPlatformRenderInterface : IPlatformRenderInterface
{
public IEnumerable<string> InstalledFontNames => throw new NotImplementedException();
public IFormattedTextImpl CreateFormattedText(
string text,
Typeface typeface,
TextAlignment textAlignment,
TextWrapping wrapping,
Size constraint,
IReadOnlyList<FormattedTextStyleSpan> spans)
{
return Mock.Of<IFormattedTextImpl>();
}
public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{
return Mock.Of<IRenderTarget>();
}
public IRenderTargetBitmapImpl CreateRenderTargetBitmap(
int width,
int height,
double dpiX,
double dpiY)
{
return Mock.Of<IRenderTargetBitmapImpl>();
}
public IRenderTargetBitmapImpl CreateRenderTargetBitmap(PixelSize size, Vector dpi)
{
throw new NotImplementedException();
}
public IStreamGeometryImpl CreateStreamGeometry()
{
return new MockStreamGeometryImpl();
}
public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null)
{
throw new NotImplementedException();
}
public IBitmapImpl LoadBitmap(Stream stream)
{
return Mock.Of<IBitmapImpl>();
}
public IBitmapImpl LoadBitmap(string fileName)
{
return Mock.Of<IBitmapImpl>();
}
public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using Avalonia;
using Avalonia.Media;
using Avalonia.Platform;
namespace AvaloniaEdit.AvaloniaMocks
{
public class MockStreamGeometryImpl : IStreamGeometryImpl, ITransformedGeometryImpl
{
private MockStreamGeometryContext _context;
public MockStreamGeometryImpl()
{
Transform = Matrix.Identity;
_context = new MockStreamGeometryContext();
}
public MockStreamGeometryImpl(Matrix transform)
{
Transform = transform;
_context = new MockStreamGeometryContext();
}
private MockStreamGeometryImpl(Matrix transform, MockStreamGeometryContext context)
{
Transform = transform;
_context = context;
}
public IGeometryImpl SourceGeometry { get; }
public Rect Bounds => _context.CalculateBounds();
public Matrix Transform { get; }
public IStreamGeometryImpl Clone()
{
return this;
}
public void Dispose()
{
}
public bool FillContains(Point point)
{
return _context.FillContains(point);
}
public bool StrokeContains(Pen pen, Point point)
{
return false;
}
public Rect GetRenderBounds(Pen pen) => Bounds;
public IGeometryImpl Intersect(IGeometryImpl geometry)
{
return new MockStreamGeometryImpl(Transform);
}
public IStreamGeometryContextImpl Open()
{
return _context;
}
public ITransformedGeometryImpl WithTransform(Matrix transform)
{
return new MockStreamGeometryImpl(transform, _context);
}
class MockStreamGeometryContext : IStreamGeometryContextImpl
{
private List<Point> points = new List<Point>();
public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
{
}
public void BeginFigure(Point startPoint, bool isFilled)
{
points.Add(startPoint);
}
public Rect CalculateBounds()
{
var left = double.MaxValue;
var right = double.MinValue;
var top = double.MaxValue;
var bottom = double.MinValue;
foreach (var p in points)
{
left = Math.Min(p.X, left);
right = Math.Max(p.X, right);
top = Math.Min(p.Y, top);
bottom = Math.Max(p.Y, bottom);
}
return new Rect(new Point(left, top), new Point(right, bottom));
}
public void CubicBezierTo(Point point1, Point point2, Point point3)
{
}
public void Dispose()
{
}
public void EndFigure(bool isClosed)
{
}
public void LineTo(Point point)
{
points.Add(point);
}
public void QuadraticBezierTo(Point control, Point endPoint)
{
throw new NotImplementedException();
}
public void SetFillRule(FillRule fillRule)
{
}
public bool FillContains(Point point)
{
// Use the algorithm from http://www.blackpawn.com/texts/pointinpoly/default.html
// to determine if the point is in the geometry (since it will always be convex in this situation)
for (int i = 0; i < points.Count; i++)
{
var a = points[i];
var b = points[(i + 1) % points.Count];
var c = points[(i + 2) % points.Count];
Vector v0 = c - a;
Vector v1 = b - a;
Vector v2 = point - a;
var dot00 = v0 * v0;
var dot01 = v0 * v1;
var dot02 = v0 * v2;
var dot11 = v1 * v1;
var dot12 = v1 * v2;
var invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
if ((u >= 0) && (v >= 0) && (u + v < 1)) return true;
}
return false;
}
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
using System;
using Avalonia.Platform;
using Moq;
namespace AvaloniaEdit.AvaloniaMocks
{
public class MockWindowingPlatform : IWindowingPlatform
{
private readonly Func<IWindowImpl> _windowImpl;
private readonly Func<IPopupImpl> _popupImpl;
public MockWindowingPlatform(Func<IWindowImpl> windowImpl = null, Func<IPopupImpl> popupImpl = null)
{
_windowImpl = windowImpl;
_popupImpl = popupImpl;
}
public IWindowImpl CreateWindow()
{
return _windowImpl?.Invoke() ?? Mock.Of<IWindowImpl>(x => x.Scaling == 1);
}
public IEmbeddableWindowImpl CreateEmbeddableWindow()
{
throw new NotImplementedException();
}
public IPopupImpl CreatePopup() => _popupImpl?.Invoke() ?? Mock.Of<IPopupImpl>(x => x.Scaling == 1);
}
}

Просмотреть файл

@ -0,0 +1,179 @@
using System;
using System.Collections.Generic;
using System.Reactive.Concurrency;
using Avalonia;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Shared.PlatformSupport;
using Avalonia.Styling;
using Avalonia.Themes.Default;
using Moq;
namespace AvaloniaEdit.AvaloniaMocks
{
public class TestServices
{
public static readonly TestServices StyledWindow = new TestServices(
assetLoader: new AssetLoader(),
layoutManager: new LayoutManager(),
platform: new AppBuilder().RuntimePlatform,
renderInterface: new MockPlatformRenderInterface(),
standardCursorFactory: Mock.Of<IStandardCursorFactory>(),
styler: new Styler(),
theme: () => CreateDefaultTheme(),
threadingInterface: Mock.Of<IPlatformThreadingInterface>(x => x.CurrentThreadIsLoopThread == true),
windowingPlatform: new MockWindowingPlatform());
public static readonly TestServices MockPlatformRenderInterface = new TestServices(
renderInterface: new MockPlatformRenderInterface());
public static readonly TestServices MockPlatformWrapper = new TestServices(
platform: Mock.Of<IRuntimePlatform>());
public static readonly TestServices MockStyler = new TestServices(
styler: Mock.Of<IStyler>());
public static readonly TestServices MockThreadingInterface = new TestServices(
threadingInterface: Mock.Of<IPlatformThreadingInterface>(x => x.CurrentThreadIsLoopThread == true));
public static readonly TestServices MockWindowingPlatform = new TestServices(
windowingPlatform: new MockWindowingPlatform());
public static readonly TestServices RealFocus = new TestServices(
focusManager: new FocusManager(),
keyboardDevice: () => new KeyboardDevice(),
keyboardNavigation: new KeyboardNavigationHandler(),
inputManager: new InputManager());
public static readonly TestServices RealLayoutManager = new TestServices(
layoutManager: new LayoutManager());
public static readonly TestServices RealStyler = new TestServices(
styler: new Styler());
public TestServices(
IAssetLoader assetLoader = null,
IFocusManager focusManager = null,
IInputManager inputManager = null,
Func<IKeyboardDevice> keyboardDevice = null,
IKeyboardNavigationHandler keyboardNavigation = null,
ILayoutManager layoutManager = null,
Func<IMouseDevice> mouseDevice = null,
IRuntimePlatform platform = null,
IPlatformRenderInterface renderInterface = null,
IRenderLoop renderLoop = null,
IScheduler scheduler = null,
IStandardCursorFactory standardCursorFactory = null,
IStyler styler = null,
Func<Styles> theme = null,
IPlatformThreadingInterface threadingInterface = null,
IWindowImpl windowImpl = null,
IWindowingPlatform windowingPlatform = null)
{
AssetLoader = assetLoader;
FocusManager = focusManager;
InputManager = inputManager;
KeyboardDevice = keyboardDevice;
KeyboardNavigation = keyboardNavigation;
LayoutManager = layoutManager;
MouseDevice = mouseDevice;
Platform = platform;
RenderInterface = renderInterface;
Scheduler = scheduler;
StandardCursorFactory = standardCursorFactory;
Styler = styler;
Theme = theme;
ThreadingInterface = threadingInterface;
WindowImpl = windowImpl;
WindowingPlatform = windowingPlatform;
}
public IAssetLoader AssetLoader { get; }
public IInputManager InputManager { get; }
public IFocusManager FocusManager { get; }
public Func<IKeyboardDevice> KeyboardDevice { get; }
public IKeyboardNavigationHandler KeyboardNavigation { get; }
public ILayoutManager LayoutManager { get; }
public Func<IMouseDevice> MouseDevice { get; }
public IRuntimePlatform Platform { get; }
public IPlatformRenderInterface RenderInterface { get; }
public IScheduler Scheduler { get; }
public IStandardCursorFactory StandardCursorFactory { get; }
public IStyler Styler { get; }
public Func<Styles> Theme { get; }
public IPlatformThreadingInterface ThreadingInterface { get; }
public IWindowImpl WindowImpl { get; }
public IWindowingPlatform WindowingPlatform { get; }
public TestServices With(
IAssetLoader assetLoader = null,
IFocusManager focusManager = null,
IInputManager inputManager = null,
Func<IKeyboardDevice> keyboardDevice = null,
IKeyboardNavigationHandler keyboardNavigation = null,
ILayoutManager layoutManager = null,
Func<IMouseDevice> mouseDevice = null,
IRuntimePlatform platform = null,
IPlatformRenderInterface renderInterface = null,
IRenderLoop renderLoop = null,
IScheduler scheduler = null,
IStandardCursorFactory standardCursorFactory = null,
IStyler styler = null,
Func<Styles> theme = null,
IPlatformThreadingInterface threadingInterface = null,
IWindowImpl windowImpl = null,
IWindowingPlatform windowingPlatform = null)
{
return new TestServices(
assetLoader: assetLoader ?? AssetLoader,
focusManager: focusManager ?? FocusManager,
inputManager: inputManager ?? InputManager,
keyboardDevice: keyboardDevice ?? KeyboardDevice,
keyboardNavigation: keyboardNavigation ?? KeyboardNavigation,
layoutManager: layoutManager ?? LayoutManager,
mouseDevice: mouseDevice ?? MouseDevice,
platform: platform ?? Platform,
renderInterface: renderInterface ?? RenderInterface,
scheduler: scheduler ?? Scheduler,
standardCursorFactory: standardCursorFactory ?? StandardCursorFactory,
styler: styler ?? Styler,
theme: theme ?? Theme,
threadingInterface: threadingInterface ?? ThreadingInterface,
windowingPlatform: windowingPlatform ?? WindowingPlatform,
windowImpl: windowImpl ?? WindowImpl);
}
private static Styles CreateDefaultTheme()
{
var result = new Styles
{
new DefaultTheme(),
};
var loader = new AvaloniaXamlLoader();
var baseLight = (IStyle)loader.Load(
new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"));
result.Add(baseLight);
return result;
}
private static IPlatformRenderInterface CreateRenderInterfaceMock()
{
return Mock.Of<IPlatformRenderInterface>(x =>
x.CreateFormattedText(
It.IsAny<string>(),
It.IsAny<Typeface>(),
It.IsAny<TextAlignment>(),
It.IsAny<TextWrapping>(),
It.IsAny<Size>(),
It.IsAny<IReadOnlyList<FormattedTextStyleSpan>>()) == Mock.Of<IFormattedTextImpl>() &&
x.CreateStreamGeometry() == Mock.Of<IStreamGeometryImpl>(
y => y.Open() == Mock.Of<IStreamGeometryContextImpl>()));
}
}
}

Просмотреть файл

@ -0,0 +1,67 @@
using System;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reflection;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.Threading;
namespace AvaloniaEdit.AvaloniaMocks
{
public class UnitTestApplication : Application
{
public UnitTestApplication(TestServices services)
{
Services = services ?? new TestServices();
RegisterServices();
}
public TestServices Services { get; }
public static IDisposable Start(TestServices services = null)
{
AvaloniaLocator.Current = (AvaloniaLocator.CurrentMutable = new AvaloniaLocator());
var app = new UnitTestApplication(services);
AvaloniaLocator.CurrentMutable.BindToSelf<Application>(app);
var updateServices = Dispatcher.UIThread.GetType().GetMethod("UpdateServices", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
updateServices?.Invoke(Dispatcher.UIThread, null);
return Disposable.Create(() =>
{
updateServices?.Invoke(Dispatcher.UIThread, null);
AvaloniaLocator.CurrentMutable = null;
AvaloniaLocator.Current = null;
});
}
public override void RegisterServices()
{
AvaloniaLocator.CurrentMutable
.Bind<IAssetLoader>().ToConstant(Services.AssetLoader)
.Bind<IFocusManager>().ToConstant(Services.FocusManager)
.BindToSelf<IGlobalStyles>(this)
.Bind<IInputManager>().ToConstant(Services.InputManager)
.Bind<IKeyboardDevice>().ToConstant(Services.KeyboardDevice?.Invoke())
.Bind<IKeyboardNavigationHandler>().ToConstant(Services.KeyboardNavigation)
.Bind<ILayoutManager>().ToConstant(Services.LayoutManager)
.Bind<IMouseDevice>().ToConstant(Services.MouseDevice?.Invoke())
.Bind<IRuntimePlatform>().ToConstant(Services.Platform)
.Bind<IPlatformRenderInterface>().ToConstant(Services.RenderInterface)
.Bind<IPlatformThreadingInterface>().ToConstant(Services.ThreadingInterface)
.Bind<IScheduler>().ToConstant(Services.Scheduler)
.Bind<IStandardCursorFactory>().ToConstant(Services.StandardCursorFactory)
.Bind<IStyler>().ToConstant(Services.Styler)
.Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform)
.Bind<IApplicationLifecycle>().ToConstant(this);
var styles = Services.Theme?.Invoke();
if (styles != null)
{
Styles.AddRange(styles);
}
}
}
}

Просмотреть файл

@ -0,0 +1,75 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Linq;
using NUnit.Framework;
namespace AvaloniaEdit.Document
{
[TestFixture]
public class ChangeTrackingTest
{
[Test]
public void NoChanges()
{
TextDocument document = new TextDocument("initial text");
ITextSource snapshot1 = document.CreateSnapshot();
ITextSource snapshot2 = document.CreateSnapshot();
Assert.AreEqual(0, snapshot1.Version.CompareAge(snapshot2.Version));
Assert.AreEqual(0, snapshot1.Version.GetChangesTo(snapshot2.Version).Count());
Assert.AreEqual(document.Text, snapshot1.Text);
Assert.AreEqual(document.Text, snapshot2.Text);
}
[Test]
public void ForwardChanges()
{
TextDocument document = new TextDocument("initial text");
ITextSource snapshot1 = document.CreateSnapshot();
document.Replace(0, 7, "nw");
document.Insert(1, "e");
ITextSource snapshot2 = document.CreateSnapshot();
Assert.AreEqual(-1, snapshot1.Version.CompareAge(snapshot2.Version));
TextChangeEventArgs[] arr = snapshot1.Version.GetChangesTo(snapshot2.Version).ToArray();
Assert.AreEqual(2, arr.Length);
Assert.AreEqual("nw", arr[0].InsertedText.Text);
Assert.AreEqual("e", arr[1].InsertedText.Text);
Assert.AreEqual("initial text", snapshot1.Text);
Assert.AreEqual("new text", snapshot2.Text);
}
[Test]
public void BackwardChanges()
{
TextDocument document = new TextDocument("initial text");
ITextSource snapshot1 = document.CreateSnapshot();
document.Replace(0, 7, "nw");
document.Insert(1, "e");
ITextSource snapshot2 = document.CreateSnapshot();
Assert.AreEqual(1, snapshot2.Version.CompareAge(snapshot1.Version));
TextChangeEventArgs[] arr = snapshot2.Version.GetChangesTo(snapshot1.Version).ToArray();
Assert.AreEqual(2, arr.Length);
Assert.AreEqual("", arr[0].InsertedText.Text);
Assert.AreEqual("initial", arr[1].InsertedText.Text);
Assert.AreEqual("initial text", snapshot1.Text);
Assert.AreEqual("new text", snapshot2.Text);
}
}
}

Просмотреть файл

@ -0,0 +1,170 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using AvaloniaEdit.Rendering;
using NUnit.Framework;
namespace AvaloniaEdit.Document
{
[TestFixture]
public class CollapsingTests
{
TextDocument document;
HeightTree heightTree;
[SetUp]
public void Setup()
{
document = new TextDocument();
document.Text = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10";
heightTree = new HeightTree(document, 10);
foreach (DocumentLine line in document.Lines) {
heightTree.SetHeight(line, line.LineNumber);
}
}
CollapsedLineSection SimpleCheck(int from, int to)
{
CollapsedLineSection sec1 = heightTree.CollapseText(document.GetLineByNumber(from), document.GetLineByNumber(to));
for (int i = 1; i < from; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
for (int i = from; i <= to; i++) {
Assert.IsTrue(heightTree.GetIsCollapsed(i));
}
for (int i = to + 1; i <= 10; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
CheckHeights();
return sec1;
}
[Test]
public void SimpleCheck()
{
SimpleCheck(4, 6);
}
[Test]
public void SimpleUncollapse()
{
CollapsedLineSection sec1 = heightTree.CollapseText(document.GetLineByNumber(4), document.GetLineByNumber(6));
sec1.Uncollapse();
for (int i = 1; i <= 10; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
CheckHeights();
}
[Test]
public void FullCheck()
{
for (int from = 1; from <= 10; from++) {
for (int to = from; to <= 10; to++) {
try {
SimpleCheck(from, to).Uncollapse();
for (int i = 1; i <= 10; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
CheckHeights();
} catch {
Console.WriteLine("from = " + from + ", to = " + to);
throw;
}
}
}
}
[Test]
public void InsertInCollapsedSection()
{
CollapsedLineSection sec1 = heightTree.CollapseText(document.GetLineByNumber(4), document.GetLineByNumber(6));
document.Insert(document.GetLineByNumber(5).Offset, "a\nb\nc");
for (int i = 1; i < 4; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
for (int i = 4; i <= 8; i++) {
Assert.IsTrue(heightTree.GetIsCollapsed(i));
}
for (int i = 9; i <= 12; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
CheckHeights();
}
[Test]
public void RemoveInCollapsedSection()
{
CollapsedLineSection sec1 = heightTree.CollapseText(document.GetLineByNumber(3), document.GetLineByNumber(7));
int line4Offset = document.GetLineByNumber(4).Offset;
int line6Offset = document.GetLineByNumber(6).Offset;
document.Remove(line4Offset, line6Offset - line4Offset);
for (int i = 1; i < 3; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
for (int i = 3; i <= 5; i++) {
Assert.IsTrue(heightTree.GetIsCollapsed(i));
}
for (int i = 6; i <= 8; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
CheckHeights();
}
[Test]
public void RemoveEndOfCollapsedSection()
{
CollapsedLineSection sec1 = heightTree.CollapseText(document.GetLineByNumber(3), document.GetLineByNumber(6));
int line5Offset = document.GetLineByNumber(5).Offset;
int line8Offset = document.GetLineByNumber(8).Offset;
document.Remove(line5Offset, line8Offset - line5Offset);
for (int i = 1; i < 3; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
for (int i = 3; i <= 5; i++) {
Assert.IsTrue(heightTree.GetIsCollapsed(i));
}
for (int i = 6; i <= 7; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
CheckHeights();
}
[Test]
public void RemoveCollapsedSection()
{
CollapsedLineSection sec1 = heightTree.CollapseText(document.GetLineByNumber(3), document.GetLineByNumber(3));
int line3Offset = document.GetLineByNumber(3).Offset;
document.Remove(line3Offset - 1, 1);
for (int i = 1; i <= 9; i++) {
Assert.IsFalse(heightTree.GetIsCollapsed(i));
}
CheckHeights();
Assert.AreSame(null, sec1.Start);
Assert.AreSame(null, sec1.End);
// section gets uncollapsed when it is removed
Assert.IsFalse(sec1.IsCollapsed);
}
void CheckHeights()
{
HeightTests.CheckHeights(document, heightTree);
}
}
}

Просмотреть файл

@ -0,0 +1,91 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using AvaloniaEdit.Rendering;
using NUnit.Framework;
namespace AvaloniaEdit.Document
{
[TestFixture]
public class HeightTests
{
TextDocument document;
HeightTree heightTree;
[SetUp]
public void Setup()
{
document = new TextDocument();
document.Text = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10";
heightTree = new HeightTree(document, 10);
foreach (DocumentLine line in document.Lines) {
heightTree.SetHeight(line, line.LineNumber);
}
}
[Test]
public void SimpleCheck()
{
CheckHeights();
}
[Test]
public void TestLinesRemoved()
{
document.Remove(5, 4);
CheckHeights();
}
[Test]
public void TestHeightChanged()
{
heightTree.SetHeight(document.GetLineByNumber(4), 100);
CheckHeights();
}
[Test]
public void TestLinesInserted()
{
document.Insert(0, "x\ny\n");
heightTree.SetHeight(document.Lines[0], 100);
heightTree.SetHeight(document.Lines[1], 1000);
heightTree.SetHeight(document.Lines[2], 10000);
CheckHeights();
}
void CheckHeights()
{
CheckHeights(document, heightTree);
}
internal static void CheckHeights(TextDocument document, HeightTree heightTree)
{
double[] heights = document.Lines.Select(l => heightTree.GetIsCollapsed(l.LineNumber) ? 0 : heightTree.GetHeight(l)).ToArray();
double[] visualPositions = new double[document.LineCount+1];
for (int i = 0; i < heights.Length; i++) {
visualPositions[i+1]=visualPositions[i]+heights[i];
}
foreach (DocumentLine ls in document.Lines) {
Assert.AreEqual(visualPositions[ls.LineNumber-1], heightTree.GetVisualPosition(ls));
}
Assert.AreEqual(visualPositions[document.LineCount], heightTree.TotalHeight);
}
}
}

Просмотреть файл

@ -0,0 +1,585 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace AvaloniaEdit.Document
{
[TestFixture]
public class LineManagerTests
{
TextDocument document;
[SetUp]
public void SetUp()
{
document = new TextDocument();
}
[Test]
public void CheckEmptyDocument()
{
Assert.AreEqual("", document.Text);
Assert.AreEqual(0, document.TextLength);
Assert.AreEqual(1, document.LineCount);
}
[Test]
public void CheckClearingDocument()
{
document.Text = "Hello,\nWorld!";
Assert.AreEqual(2, document.LineCount);
var oldLines = document.Lines.ToArray();
document.Text = "";
Assert.AreEqual("", document.Text);
Assert.AreEqual(0, document.TextLength);
Assert.AreEqual(1, document.LineCount);
Assert.AreSame(oldLines[0], document.Lines.Single());
Assert.IsFalse(oldLines[0].IsDeleted);
Assert.IsTrue(oldLines[1].IsDeleted);
Assert.IsNull(oldLines[0].NextLine);
Assert.IsNull(oldLines[1].PreviousLine);
}
[Test]
public void CheckGetLineInEmptyDocument()
{
Assert.AreEqual(1, document.Lines.Count);
List<DocumentLine> lines = new List<DocumentLine>(document.Lines);
Assert.AreEqual(1, lines.Count);
DocumentLine line = document.Lines[0];
Assert.AreSame(line, lines[0]);
Assert.AreSame(line, document.GetLineByNumber(1));
Assert.AreSame(line, document.GetLineByOffset(0));
}
[Test]
public void CheckLineSegmentInEmptyDocument()
{
DocumentLine line = document.GetLineByNumber(1);
Assert.AreEqual(1, line.LineNumber);
Assert.AreEqual(0, line.Offset);
Assert.IsFalse(line.IsDeleted);
Assert.AreEqual(0, line.Length);
Assert.AreEqual(0, line.TotalLength);
Assert.AreEqual(0, line.DelimiterLength);
}
[Test]
public void LineIndexOfTest()
{
DocumentLine line = document.GetLineByNumber(1);
Assert.AreEqual(0, document.Lines.IndexOf(line));
DocumentLine lineFromOtherDocument = new TextDocument().GetLineByNumber(1);
Assert.AreEqual(-1, document.Lines.IndexOf(lineFromOtherDocument));
document.Text = "a\nb\nc";
DocumentLine middleLine = document.GetLineByNumber(2);
Assert.AreEqual(1, document.Lines.IndexOf(middleLine));
document.Remove(1, 3);
Assert.IsTrue(middleLine.IsDeleted);
Assert.AreEqual(-1, document.Lines.IndexOf(middleLine));
}
[Test]
public void InsertInEmptyDocument()
{
document.Insert(0, "a");
Assert.AreEqual(document.LineCount, 1);
DocumentLine line = document.GetLineByNumber(1);
Assert.AreEqual("a", document.GetText(line));
}
[Test]
public void SetText()
{
document.Text = "a";
Assert.AreEqual(document.LineCount, 1);
DocumentLine line = document.GetLineByNumber(1);
Assert.AreEqual("a", document.GetText(line));
}
[Test]
public void InsertNothing()
{
document.Insert(0, "");
Assert.AreEqual(document.LineCount, 1);
Assert.AreEqual(document.TextLength, 0);
}
[Test]
public void InsertNull()
{
Assert.Throws<ArgumentNullException>(() => document.Insert(0, (string)null));
}
[Test]
public void SetTextNull()
{
Assert.Throws<ArgumentNullException>(() => document.Text = null);
}
[Test]
public void RemoveNothing()
{
document.Remove(0, 0);
Assert.AreEqual(document.LineCount, 1);
Assert.AreEqual(document.TextLength, 0);
}
[Test]
public void GetCharAt0EmptyDocument()
{
Assert.Throws<ArgumentOutOfRangeException>(() => document.GetCharAt(0));
}
[Test]
public void GetCharAtNegativeOffset()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "a\nb";
document.GetCharAt(-1);
});
}
[Test]
public void GetCharAtEndOffset()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "a\nb";
document.GetCharAt(document.TextLength);
});
}
[Test]
public void InsertAtNegativeOffset()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "a\nb";
document.Insert(-1, "text");
});
}
[Test]
public void InsertAfterEndOffset()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "a\nb";
document.Insert(4, "text");
});
}
[Test]
public void RemoveNegativeAmount()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "abcd";
document.Remove(2, -1);
});
}
[Test]
public void RemoveTooMuch()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "abcd";
document.Remove(2, 10);
});
}
[Test]
public void GetLineByNumberNegative()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "a\nb";
document.GetLineByNumber(-1);
});
}
[Test]
public void GetLineByNumberTooHigh()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "a\nb";
document.GetLineByNumber(3);
});
}
[Test]
public void GetLineByOffsetNegative()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "a\nb";
document.GetLineByOffset(-1);
});
}
[Test]
public void GetLineByOffsetToHigh()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
document.Text = "a\nb";
document.GetLineByOffset(10);
});
}
[Test]
public void InsertAtEndOffset()
{
document.Text = "a\nb";
CheckDocumentLines("a",
"b");
document.Insert(3, "text");
CheckDocumentLines("a",
"btext");
}
[Test]
public void GetCharAt()
{
document.Text = "a\r\nb";
Assert.AreEqual('a', document.GetCharAt(0));
Assert.AreEqual('\r', document.GetCharAt(1));
Assert.AreEqual('\n', document.GetCharAt(2));
Assert.AreEqual('b', document.GetCharAt(3));
}
[Test]
public void CheckMixedNewLineTest()
{
const string mixedNewlineText = "line 1\nline 2\r\nline 3\rline 4";
document.Text = mixedNewlineText;
Assert.AreEqual(mixedNewlineText, document.Text);
Assert.AreEqual(4, document.LineCount);
for (int i = 1; i < 4; i++)
{
DocumentLine line = document.GetLineByNumber(i);
Assert.AreEqual(i, line.LineNumber);
Assert.AreEqual("line " + i, document.GetText(line));
}
Assert.AreEqual(1, document.GetLineByNumber(1).DelimiterLength);
Assert.AreEqual(2, document.GetLineByNumber(2).DelimiterLength);
Assert.AreEqual(1, document.GetLineByNumber(3).DelimiterLength);
Assert.AreEqual(0, document.GetLineByNumber(4).DelimiterLength);
}
[Test]
public void LfCrIsTwoNewLinesTest()
{
document.Text = "a\n\rb";
Assert.AreEqual("a\n\rb", document.Text);
CheckDocumentLines("a",
"",
"b");
}
[Test]
public void RemoveFirstPartOfDelimiter()
{
document.Text = "a\r\nb";
document.Remove(1, 1);
Assert.AreEqual("a\nb", document.Text);
CheckDocumentLines("a",
"b");
}
[Test]
public void RemoveLineContentAndJoinDelimiters()
{
document.Text = "a\rb\nc";
document.Remove(2, 1);
Assert.AreEqual("a\r\nc", document.Text);
CheckDocumentLines("a",
"c");
}
[Test]
public void RemoveLineContentAndJoinDelimiters2()
{
document.Text = "a\rb\nc\nd";
document.Remove(2, 3);
Assert.AreEqual("a\r\nd", document.Text);
CheckDocumentLines("a",
"d");
}
[Test]
public void RemoveLineContentAndJoinDelimiters3()
{
document.Text = "a\rb\r\nc";
document.Remove(2, 2);
Assert.AreEqual("a\r\nc", document.Text);
CheckDocumentLines("a",
"c");
}
[Test]
public void RemoveLineContentAndJoinNonMatchingDelimiters()
{
document.Text = "a\nb\nc";
document.Remove(2, 1);
Assert.AreEqual("a\n\nc", document.Text);
CheckDocumentLines("a",
"",
"c");
}
[Test]
public void RemoveLineContentAndJoinNonMatchingDelimiters2()
{
document.Text = "a\nb\rc";
document.Remove(2, 1);
Assert.AreEqual("a\n\rc", document.Text);
CheckDocumentLines("a",
"",
"c");
}
[Test]
public void RemoveMultilineUpToFirstPartOfDelimiter()
{
document.Text = "0\n1\r\n2";
document.Remove(1, 3);
Assert.AreEqual("0\n2", document.Text);
CheckDocumentLines("0",
"2");
}
[Test]
public void RemoveSecondPartOfDelimiter()
{
document.Text = "a\r\nb";
document.Remove(2, 1);
Assert.AreEqual("a\rb", document.Text);
CheckDocumentLines("a",
"b");
}
[Test]
public void RemoveFromSecondPartOfDelimiter()
{
document.Text = "a\r\nb\nc";
document.Remove(2, 3);
Assert.AreEqual("a\rc", document.Text);
CheckDocumentLines("a",
"c");
}
[Test]
public void RemoveFromSecondPartOfDelimiterToDocumentEnd()
{
document.Text = "a\r\nb";
document.Remove(2, 2);
Assert.AreEqual("a\r", document.Text);
CheckDocumentLines("a",
"");
}
[Test]
public void RemoveUpToMatchingDelimiter1()
{
document.Text = "a\r\nb\nc";
document.Remove(2, 2);
Assert.AreEqual("a\r\nc", document.Text);
CheckDocumentLines("a",
"c");
}
[Test]
public void RemoveUpToMatchingDelimiter2()
{
document.Text = "a\r\nb\r\nc";
document.Remove(2, 3);
Assert.AreEqual("a\r\nc", document.Text);
CheckDocumentLines("a",
"c");
}
[Test]
public void RemoveUpToNonMatchingDelimiter()
{
document.Text = "a\r\nb\rc";
document.Remove(2, 2);
Assert.AreEqual("a\r\rc", document.Text);
CheckDocumentLines("a",
"",
"c");
}
[Test]
public void RemoveTwoCharDelimiter()
{
document.Text = "a\r\nb";
document.Remove(1, 2);
Assert.AreEqual("ab", document.Text);
CheckDocumentLines("ab");
}
[Test]
public void RemoveOneCharDelimiter()
{
document.Text = "a\nb";
document.Remove(1, 1);
Assert.AreEqual("ab", document.Text);
CheckDocumentLines("ab");
}
void CheckDocumentLines(params string[] lines)
{
Assert.AreEqual(lines.Length, document.LineCount, "LineCount");
for (int i = 0; i < lines.Length; i++)
{
Assert.AreEqual(lines[i], document.GetText(document.Lines[i]), "Text of line " + (i + 1));
}
}
[Test]
public void FixUpFirstPartOfDelimiter()
{
document.Text = "a\n\nb";
document.Replace(1, 1, "\r");
Assert.AreEqual("a\r\nb", document.Text);
CheckDocumentLines("a",
"b");
}
[Test]
public void FixUpSecondPartOfDelimiter()
{
document.Text = "a\r\rb";
document.Replace(2, 1, "\n");
Assert.AreEqual("a\r\nb", document.Text);
CheckDocumentLines("a",
"b");
}
[Test]
public void InsertInsideDelimiter()
{
document.Text = "a\r\nc";
document.Insert(2, "b");
Assert.AreEqual("a\rb\nc", document.Text);
CheckDocumentLines("a",
"b",
"c");
}
[Test]
public void InsertInsideDelimiter2()
{
document.Text = "a\r\nd";
document.Insert(2, "b\nc");
Assert.AreEqual("a\rb\nc\nd", document.Text);
CheckDocumentLines("a",
"b",
"c",
"d");
}
[Test]
public void InsertInsideDelimiter3()
{
document.Text = "a\r\nc";
document.Insert(2, "b\r");
Assert.AreEqual("a\rb\r\nc", document.Text);
CheckDocumentLines("a",
"b",
"c");
}
[Test]
public void ExtendDelimiter1()
{
document.Text = "a\nc";
document.Insert(1, "b\r");
Assert.AreEqual("ab\r\nc", document.Text);
CheckDocumentLines("ab",
"c");
}
[Test]
public void ExtendDelimiter2()
{
document.Text = "a\rc";
document.Insert(2, "\nb");
Assert.AreEqual("a\r\nbc", document.Text);
CheckDocumentLines("a",
"bc");
}
[Test]
public void ReplaceLineContentBetweenMatchingDelimiters()
{
document.Text = "a\rb\nc";
document.Replace(2, 1, "x");
Assert.AreEqual("a\rx\nc", document.Text);
CheckDocumentLines("a",
"x",
"c");
}
[Test]
public void GetOffset()
{
document.Text = "Hello,\nWorld!";
Assert.AreEqual(0, document.GetOffset(1, 1));
Assert.AreEqual(1, document.GetOffset(1, 2));
Assert.AreEqual(5, document.GetOffset(1, 6));
Assert.AreEqual(6, document.GetOffset(1, 7));
Assert.AreEqual(7, document.GetOffset(2, 1));
Assert.AreEqual(8, document.GetOffset(2, 2));
Assert.AreEqual(12, document.GetOffset(2, 6));
Assert.AreEqual(13, document.GetOffset(2, 7));
}
[Test]
public void GetOffsetIgnoreNegativeColumns()
{
document.Text = "Hello,\nWorld!";
Assert.AreEqual(0, document.GetOffset(1, -1));
Assert.AreEqual(0, document.GetOffset(1, -100));
Assert.AreEqual(0, document.GetOffset(1, 0));
Assert.AreEqual(7, document.GetOffset(2, -1));
Assert.AreEqual(7, document.GetOffset(2, -100));
Assert.AreEqual(7, document.GetOffset(2, 0));
}
[Test]
public void GetOffsetIgnoreTooHighColumns()
{
document.Text = "Hello,\nWorld!";
Assert.AreEqual(6, document.GetOffset(1, 8));
Assert.AreEqual(6, document.GetOffset(1, 100));
Assert.AreEqual(13, document.GetOffset(2, 8));
Assert.AreEqual(13, document.GetOffset(2, 100));
}
}
}

Просмотреть файл

@ -0,0 +1,183 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using AvaloniaEdit.Rendering;
using NUnit.Framework;
namespace AvaloniaEdit.Document
{
/// <summary>
/// A randomized test for the line manager.
/// </summary>
[TestFixture]
public class RandomizedLineManagerTest
{
TextDocument document;
Random rnd;
[OneTimeSetUp]
public void FixtureSetup()
{
int seed = Environment.TickCount;
Console.WriteLine("RandomizedLineManagerTest Seed: " + seed);
rnd = new Random(seed);
}
[SetUp]
public void Setup()
{
document = new TextDocument();
}
[Test]
public void ShortReplacements()
{
char[] chars = { 'a', 'b', '\r', '\n' };
char[] buffer = new char[20];
for (int i = 0; i < 2500; i++) {
int offset = rnd.Next(0, document.TextLength);
int length = rnd.Next(0, document.TextLength - offset);
int newTextLength = rnd.Next(0, 20);
for (int j = 0; j < newTextLength; j++) {
buffer[j] = chars[rnd.Next(0, chars.Length)];
}
document.Replace(offset, length, new string(buffer, 0, newTextLength));
CheckLines();
}
}
[Test]
public void LargeReplacements()
{
char[] chars = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', '\r', '\n' };
char[] buffer = new char[1000];
for (int i = 0; i < 20; i++) {
int offset = rnd.Next(0, document.TextLength);
int length = rnd.Next(0, (document.TextLength - offset) / 4);
int newTextLength = rnd.Next(0, 1000);
for (int j = 0; j < newTextLength; j++) {
buffer[j] = chars[rnd.Next(0, chars.Length)];
}
string newText = new string(buffer, 0, newTextLength);
string expectedText = document.Text.Remove(offset, length).Insert(offset, newText);
document.Replace(offset, length, newText);
Assert.AreEqual(expectedText, document.Text);
CheckLines();
}
}
void CheckLines()
{
string text = document.Text;
int lineNumber = 1;
int lineStart = 0;
for (int i = 0; i < text.Length; i++) {
char c = text[i];
if (c == '\r' && i + 1 < text.Length && text[i + 1] == '\n') {
DocumentLine line = document.GetLineByNumber(lineNumber);
Assert.AreEqual(lineNumber, line.LineNumber);
Assert.AreEqual(2, line.DelimiterLength);
Assert.AreEqual(lineStart, line.Offset);
Assert.AreEqual(i - lineStart, line.Length);
i++; // consume \n
lineNumber++;
lineStart = i+1;
} else if (c == '\r' || c == '\n') {
DocumentLine line = document.GetLineByNumber(lineNumber);
Assert.AreEqual(lineNumber, line.LineNumber);
Assert.AreEqual(1, line.DelimiterLength);
Assert.AreEqual(lineStart, line.Offset);
Assert.AreEqual(i - lineStart, line.Length);
lineNumber++;
lineStart = i+1;
}
}
Assert.AreEqual(lineNumber, document.LineCount);
}
[Test]
public void CollapsingTest()
{
char[] chars = { 'a', 'b', '\r', '\n' };
char[] buffer = new char[20];
HeightTree heightTree = new HeightTree(document, 10);
List<CollapsedLineSection> collapsedSections = new List<CollapsedLineSection>();
for (int i = 0; i < 2500; i++) {
// Console.WriteLine("Iteration " + i);
// Console.WriteLine(heightTree.GetTreeAsString());
// foreach (CollapsedLineSection cs in collapsedSections) {
// Console.WriteLine(cs);
// }
switch (rnd.Next(0, 10)) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
int offset = rnd.Next(0, document.TextLength);
int length = rnd.Next(0, document.TextLength - offset);
int newTextLength = rnd.Next(0, 20);
for (int j = 0; j < newTextLength; j++) {
buffer[j] = chars[rnd.Next(0, chars.Length)];
}
document.Replace(offset, length, new string(buffer, 0, newTextLength));
break;
case 6:
case 7:
int startLine = rnd.Next(1, document.LineCount + 1);
int endLine = rnd.Next(startLine, document.LineCount + 1);
collapsedSections.Add(heightTree.CollapseText(document.GetLineByNumber(startLine), document.GetLineByNumber(endLine)));
break;
case 8:
if (collapsedSections.Count > 0) {
CollapsedLineSection cs = collapsedSections[rnd.Next(0, collapsedSections.Count)];
// unless the text section containing the CollapsedSection was deleted:
if (cs.Start != null) {
cs.Uncollapse();
}
collapsedSections.Remove(cs);
}
break;
case 9:
foreach (DocumentLine ls in document.Lines) {
heightTree.SetHeight(ls, ls.LineNumber);
}
break;
}
var treeSections = new HashSet<CollapsedLineSection>(heightTree.GetAllCollapsedSections());
int expectedCount = 0;
foreach (CollapsedLineSection cs in collapsedSections) {
if (cs.Start != null) {
expectedCount++;
Assert.IsTrue(treeSections.Contains(cs));
}
}
Assert.AreEqual(expectedCount, treeSections.Count);
CheckLines();
HeightTests.CheckHeights(document, heightTree);
}
}
}
}

Просмотреть файл

@ -0,0 +1,328 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using NUnit.Framework;
namespace AvaloniaEdit.Document
{
[TestFixture]
public class TextAnchorTest
{
TextDocument document;
[SetUp]
public void SetUp()
{
document = new TextDocument();
}
[Test]
public void AnchorInEmptyDocument()
{
TextAnchor a1 = document.CreateAnchor(0);
TextAnchor a2 = document.CreateAnchor(0);
a1.MovementType = AnchorMovementType.BeforeInsertion;
a2.MovementType = AnchorMovementType.AfterInsertion;
Assert.AreEqual(0, a1.Offset);
Assert.AreEqual(0, a2.Offset);
document.Insert(0, "x");
Assert.AreEqual(0, a1.Offset);
Assert.AreEqual(1, a2.Offset);
}
[Test]
public void AnchorsSurviveDeletion()
{
document.Text = new string(' ', 10);
TextAnchor[] a1 = new TextAnchor[11];
TextAnchor[] a2 = new TextAnchor[11];
for (int i = 0; i < 11; i++) {
//Console.WriteLine("Insert first at i = " + i);
a1[i] = document.CreateAnchor(i);
a1[i].SurviveDeletion = true;
//Console.WriteLine(document.GetTextAnchorTreeAsString());
//Console.WriteLine("Insert second at i = " + i);
a2[i] = document.CreateAnchor(i);
a2[i].SurviveDeletion = false;
//Console.WriteLine(document.GetTextAnchorTreeAsString());
}
for (int i = 0; i < 11; i++) {
Assert.AreEqual(i, a1[i].Offset);
Assert.AreEqual(i, a2[i].Offset);
}
document.Remove(1, 8);
for (int i = 0; i < 11; i++) {
if (i <= 1) {
Assert.IsFalse(a1[i].IsDeleted);
Assert.IsFalse(a2[i].IsDeleted);
Assert.AreEqual(i, a1[i].Offset);
Assert.AreEqual(i, a2[i].Offset);
} else if (i <= 8) {
Assert.IsFalse(a1[i].IsDeleted);
Assert.IsTrue(a2[i].IsDeleted);
Assert.AreEqual(1, a1[i].Offset);
} else {
Assert.IsFalse(a1[i].IsDeleted);
Assert.IsFalse(a2[i].IsDeleted);
Assert.AreEqual(i - 8, a1[i].Offset);
Assert.AreEqual(i - 8, a2[i].Offset);
}
}
}
Random rnd;
[OneTimeSetUp]
public void FixtureSetup()
{
int seed = Environment.TickCount;
Console.WriteLine("TextAnchorTest Seed: " + seed);
rnd = new Random(seed);
}
[Test]
public void CreateAnchors()
{
List<TextAnchor> anchors = new List<TextAnchor>();
List<int> expectedOffsets = new List<int>();
document.Text = new string(' ', 1000);
for (int i = 0; i < 1000; i++) {
int offset = rnd.Next(1000);
anchors.Add(document.CreateAnchor(offset));
expectedOffsets.Add(offset);
}
for (int i = 0; i < anchors.Count; i++) {
Assert.AreEqual(expectedOffsets[i], anchors[i].Offset);
}
GC.KeepAlive(anchors);
}
[Test]
public void CreateAndGCAnchors()
{
List<TextAnchor> anchors = new List<TextAnchor>();
List<int> expectedOffsets = new List<int>();
document.Text = new string(' ', 1000);
for (int t = 0; t < 250; t++) {
int c = rnd.Next(50);
if (rnd.Next(2) == 0) {
for (int i = 0; i < c; i++) {
int offset = rnd.Next(1000);
anchors.Add(document.CreateAnchor(offset));
expectedOffsets.Add(offset);
}
} else if (c <= anchors.Count) {
anchors.RemoveRange(0, c);
expectedOffsets.RemoveRange(0, c);
GC.Collect();
}
for (int j = 0; j < anchors.Count; j++) {
Assert.AreEqual(expectedOffsets[j], anchors[j].Offset);
}
}
GC.KeepAlive(anchors);
}
[Test]
public void MoveAnchorsDuringReplace()
{
document.Text = "abcd";
TextAnchor start = document.CreateAnchor(1);
TextAnchor middleDeletable = document.CreateAnchor(2);
TextAnchor middleSurvivorLeft = document.CreateAnchor(2);
middleSurvivorLeft.SurviveDeletion = true;
middleSurvivorLeft.MovementType = AnchorMovementType.BeforeInsertion;
TextAnchor middleSurvivorRight = document.CreateAnchor(2);
middleSurvivorRight.SurviveDeletion = true;
middleSurvivorRight.MovementType = AnchorMovementType.AfterInsertion;
TextAnchor end = document.CreateAnchor(3);
document.Replace(1, 2, "BxC");
Assert.AreEqual(1, start.Offset);
Assert.IsTrue(middleDeletable.IsDeleted);
Assert.AreEqual(1, middleSurvivorLeft.Offset);
Assert.AreEqual(4, middleSurvivorRight.Offset);
Assert.AreEqual(4, end.Offset);
}
[Test]
public void CreateAndMoveAnchors()
{
List<TextAnchor> anchors = new List<TextAnchor>();
List<int> expectedOffsets = new List<int>();
document.Text = new string(' ', 1000);
for (int t = 0; t < 250; t++) {
//Console.Write("t = " + t + " ");
int c = rnd.Next(50);
switch (rnd.Next(5)) {
case 0:
//Console.WriteLine("Add c=" + c + " anchors");
for (int i = 0; i < c; i++) {
int offset = rnd.Next(document.TextLength);
TextAnchor anchor = document.CreateAnchor(offset);
if (rnd.Next(2) == 0)
anchor.MovementType = AnchorMovementType.BeforeInsertion;
else
anchor.MovementType = AnchorMovementType.AfterInsertion;
anchor.SurviveDeletion = rnd.Next(2) == 0;
anchors.Add(anchor);
expectedOffsets.Add(offset);
}
break;
case 1:
if (c <= anchors.Count) {
//Console.WriteLine("Remove c=" + c + " anchors");
anchors.RemoveRange(0, c);
expectedOffsets.RemoveRange(0, c);
GC.Collect();
}
break;
case 2:
int insertOffset = rnd.Next(document.TextLength);
int insertLength = rnd.Next(1000);
//Console.WriteLine("insertOffset=" + insertOffset + " insertLength="+insertLength);
document.Insert(insertOffset, new string(' ', insertLength));
for (int i = 0; i < anchors.Count; i++) {
if (anchors[i].MovementType == AnchorMovementType.BeforeInsertion) {
if (expectedOffsets[i] > insertOffset)
expectedOffsets[i] += insertLength;
} else {
if (expectedOffsets[i] >= insertOffset)
expectedOffsets[i] += insertLength;
}
}
break;
case 3:
int removalOffset = rnd.Next(document.TextLength);
int removalLength = rnd.Next(document.TextLength - removalOffset);
//Console.WriteLine("RemovalOffset=" + removalOffset + " RemovalLength="+removalLength);
document.Remove(removalOffset, removalLength);
for (int i = anchors.Count - 1; i >= 0; i--) {
if (expectedOffsets[i] > removalOffset && expectedOffsets[i] < removalOffset + removalLength) {
if (anchors[i].SurviveDeletion) {
expectedOffsets[i] = removalOffset;
} else {
Assert.IsTrue(anchors[i].IsDeleted);
anchors.RemoveAt(i);
expectedOffsets.RemoveAt(i);
}
} else if (expectedOffsets[i] > removalOffset) {
expectedOffsets[i] -= removalLength;
}
}
break;
case 4:
int replaceOffset = rnd.Next(document.TextLength);
int replaceRemovalLength = rnd.Next(document.TextLength - replaceOffset);
int replaceInsertLength = rnd.Next(1000);
//Console.WriteLine("ReplaceOffset=" + replaceOffset + " RemovalLength="+replaceRemovalLength + " InsertLength=" + replaceInsertLength);
document.Replace(replaceOffset, replaceRemovalLength, new string(' ', replaceInsertLength));
for (int i = anchors.Count - 1; i >= 0; i--) {
if (expectedOffsets[i] > replaceOffset && expectedOffsets[i] < replaceOffset + replaceRemovalLength) {
if (anchors[i].SurviveDeletion) {
if (anchors[i].MovementType == AnchorMovementType.AfterInsertion)
expectedOffsets[i] = replaceOffset + replaceInsertLength;
else
expectedOffsets[i] = replaceOffset;
} else {
Assert.IsTrue(anchors[i].IsDeleted);
anchors.RemoveAt(i);
expectedOffsets.RemoveAt(i);
}
} else if (expectedOffsets[i] > replaceOffset) {
expectedOffsets[i] += replaceInsertLength - replaceRemovalLength;
} else if (expectedOffsets[i] == replaceOffset && replaceRemovalLength == 0 && anchors[i].MovementType == AnchorMovementType.AfterInsertion) {
expectedOffsets[i] += replaceInsertLength - replaceRemovalLength;
}
}
break;
}
Assert.AreEqual(anchors.Count, expectedOffsets.Count);
for (int j = 0; j < anchors.Count; j++) {
Assert.AreEqual(expectedOffsets[j], anchors[j].Offset);
}
}
GC.KeepAlive(anchors);
}
[Test]
public void RepeatedTextDragDrop()
{
document.Text = new string(' ', 1000);
for (int i = 0; i < 20; i++) {
TextAnchor a = document.CreateAnchor(144);
TextAnchor b = document.CreateAnchor(157);
document.Insert(128, new string('a', 13));
document.Remove(157, 13);
a = document.CreateAnchor(128);
b = document.CreateAnchor(141);
document.Insert(157, new string('b', 13));
document.Remove(128, 13);
a = null;
b = null;
if ((i % 5) == 0)
GC.Collect();
}
}
[Test]
public void ReplaceSpacesWithTab()
{
document.Text = "a b";
TextAnchor before = document.CreateAnchor(1);
before.MovementType = AnchorMovementType.AfterInsertion;
TextAnchor after = document.CreateAnchor(5);
TextAnchor survivingMiddle = document.CreateAnchor(2);
TextAnchor deletedMiddle = document.CreateAnchor(3);
document.Replace(1, 4, "\t", OffsetChangeMappingType.CharacterReplace);
Assert.AreEqual("a\tb", document.Text);
// yes, the movement is a bit strange; but that's how CharacterReplace works when the text gets shorter
Assert.AreEqual(1, before.Offset);
Assert.AreEqual(2, after.Offset);
Assert.AreEqual(2, survivingMiddle.Offset);
Assert.AreEqual(2, deletedMiddle.Offset);
}
[Test]
public void ReplaceTwoCharactersWithThree()
{
document.Text = "a12b";
TextAnchor before = document.CreateAnchor(1);
before.MovementType = AnchorMovementType.AfterInsertion;
TextAnchor after = document.CreateAnchor(3);
before.MovementType = AnchorMovementType.BeforeInsertion;
TextAnchor middleB = document.CreateAnchor(2);
before.MovementType = AnchorMovementType.BeforeInsertion;
TextAnchor middleA = document.CreateAnchor(2);
before.MovementType = AnchorMovementType.AfterInsertion;
document.Replace(1, 2, "123", OffsetChangeMappingType.CharacterReplace);
Assert.AreEqual("a123b", document.Text);
Assert.AreEqual(1, before.Offset);
Assert.AreEqual(4, after.Offset);
Assert.AreEqual(2, middleA.Offset);
Assert.AreEqual(2, middleB.Offset);
}
}
}

Просмотреть файл

@ -0,0 +1,365 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using NUnit.Framework;
namespace AvaloniaEdit.Document
{
[TestFixture]
public class TextSegmentTreeTest
{
Random rnd;
[OneTimeSetUp]
public void FixtureSetup()
{
int seed = Environment.TickCount;
Console.WriteLine("TextSegmentTreeTest Seed: " + seed);
rnd = new Random(seed);
}
class TestTextSegment : TextSegment
{
internal int ExpectedOffset, ExpectedLength;
public TestTextSegment(int expectedOffset, int expectedLength)
{
this.ExpectedOffset = expectedOffset;
this.ExpectedLength = expectedLength;
this.StartOffset = expectedOffset;
this.Length = expectedLength;
}
}
TextSegmentCollection<TestTextSegment> tree;
List<TestTextSegment> expectedSegments;
[SetUp]
public void SetUp()
{
tree = new TextSegmentCollection<TestTextSegment>();
expectedSegments = new List<TestTextSegment>();
}
[Test]
public void FindInEmptyTree()
{
Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(0));
Assert.AreEqual(0, tree.FindSegmentsContaining(0).Count);
Assert.AreEqual(0, tree.FindOverlappingSegments(10, 20).Count);
}
[Test]
public void FindFirstSegmentWithStartAfter()
{
var s1 = new TestTextSegment(5, 10);
var s2 = new TestTextSegment(10, 10);
tree.Add(s1);
tree.Add(s2);
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(-100));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(0));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(4));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(5));
Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(6));
Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(9));
Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(10));
Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(11));
Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(100));
}
[Test]
public void FindFirstSegmentWithStartAfterWithDuplicates()
{
var s1 = new TestTextSegment(5, 10);
var s1b = new TestTextSegment(5, 7);
var s2 = new TestTextSegment(10, 10);
var s2b = new TestTextSegment(10, 7);
tree.Add(s1);
tree.Add(s1b);
tree.Add(s2);
tree.Add(s2b);
Assert.AreSame(s1b, tree.GetNextSegment(s1));
Assert.AreSame(s2b, tree.GetNextSegment(s2));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(-100));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(0));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(4));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(5));
Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(6));
Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(9));
Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(10));
Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(11));
Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(100));
}
[Test]
public void FindFirstSegmentWithStartAfterWithDuplicates2()
{
var s1 = new TestTextSegment(5, 1);
var s2 = new TestTextSegment(5, 2);
var s3 = new TestTextSegment(5, 3);
var s4 = new TestTextSegment(5, 4);
tree.Add(s1);
tree.Add(s2);
tree.Add(s3);
tree.Add(s4);
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(0));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(1));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(4));
Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(5));
Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(6));
}
TestTextSegment AddSegment(int offset, int length)
{
// Console.WriteLine("Add " + offset + ", " + length);
TestTextSegment s = new TestTextSegment(offset, length);
tree.Add(s);
expectedSegments.Add(s);
return s;
}
void RemoveSegment(TestTextSegment s)
{
// Console.WriteLine("Remove " + s);
expectedSegments.Remove(s);
tree.Remove(s);
}
void TestRetrieval(int offset, int length)
{
HashSet<TestTextSegment> actual = new HashSet<TestTextSegment>(tree.FindOverlappingSegments(offset, length));
HashSet<TestTextSegment> expected = new HashSet<TestTextSegment>();
foreach (TestTextSegment e in expectedSegments) {
if (e.ExpectedOffset + e.ExpectedLength < offset)
continue;
if (e.ExpectedOffset > offset + length)
continue;
expected.Add(e);
}
Assert.IsTrue(actual.IsSubsetOf(expected));
Assert.IsTrue(expected.IsSubsetOf(actual));
}
void CheckSegments()
{
Assert.AreEqual(expectedSegments.Count, tree.Count);
foreach (TestTextSegment s in expectedSegments) {
Assert.AreEqual(s.ExpectedOffset, s.StartOffset /*, "startoffset for " + s*/);
Assert.AreEqual(s.ExpectedLength, s.Length /*, "length for " + s*/);
}
}
[Test]
public void AddSegments()
{
TestTextSegment s1 = AddSegment(10, 20);
TestTextSegment s2 = AddSegment(15, 10);
CheckSegments();
}
void ChangeDocument(OffsetChangeMapEntry change)
{
tree.UpdateOffsets(change);
foreach (TestTextSegment s in expectedSegments) {
int endOffset = s.ExpectedOffset + s.ExpectedLength;
s.ExpectedOffset = change.GetNewOffset(s.ExpectedOffset, AnchorMovementType.AfterInsertion);
s.ExpectedLength = Math.Max(0, change.GetNewOffset(endOffset, AnchorMovementType.BeforeInsertion) - s.ExpectedOffset);
}
}
[Test]
public void InsertionBeforeAllSegments()
{
TestTextSegment s1 = AddSegment(10, 20);
TestTextSegment s2 = AddSegment(15, 10);
ChangeDocument(new OffsetChangeMapEntry(5, 0, 2));
CheckSegments();
}
[Test]
public void ReplacementBeforeAllSegmentsTouchingFirstSegment()
{
TestTextSegment s1 = AddSegment(10, 20);
TestTextSegment s2 = AddSegment(15, 10);
ChangeDocument(new OffsetChangeMapEntry(5, 5, 2));
CheckSegments();
}
[Test]
public void InsertionAfterAllSegments()
{
TestTextSegment s1 = AddSegment(10, 20);
TestTextSegment s2 = AddSegment(15, 10);
ChangeDocument(new OffsetChangeMapEntry(45, 0, 2));
CheckSegments();
}
[Test]
public void ReplacementOverlappingWithStartOfSegment()
{
TestTextSegment s1 = AddSegment(10, 20);
TestTextSegment s2 = AddSegment(15, 10);
ChangeDocument(new OffsetChangeMapEntry(9, 7, 2));
CheckSegments();
}
[Test]
public void ReplacementOfWholeSegment()
{
TestTextSegment s1 = AddSegment(10, 20);
TestTextSegment s2 = AddSegment(15, 10);
ChangeDocument(new OffsetChangeMapEntry(10, 20, 30));
CheckSegments();
}
[Test]
public void ReplacementAtEndOfSegment()
{
TestTextSegment s1 = AddSegment(10, 20);
TestTextSegment s2 = AddSegment(15, 10);
ChangeDocument(new OffsetChangeMapEntry(24, 6, 10));
CheckSegments();
}
[Test]
public void RandomizedNoDocumentChanges()
{
for (int i = 0; i < 1000; i++) {
// Console.WriteLine(tree.GetTreeAsString());
// Console.WriteLine("Iteration " + i);
switch (rnd.Next(3)) {
case 0:
AddSegment(rnd.Next(500), rnd.Next(30));
break;
case 1:
AddSegment(rnd.Next(500), rnd.Next(300));
break;
case 2:
if (tree.Count > 0) {
RemoveSegment(expectedSegments[rnd.Next(tree.Count)]);
}
break;
}
CheckSegments();
}
}
[Test]
public void RandomizedCloseNoDocumentChanges()
{
// Lots of segments in a short document. Tests how the tree copes with multiple identical segments.
for (int i = 0; i < 1000; i++) {
switch (rnd.Next(3)) {
case 0:
AddSegment(rnd.Next(20), rnd.Next(10));
break;
case 1:
AddSegment(rnd.Next(20), rnd.Next(20));
break;
case 2:
if (tree.Count > 0) {
RemoveSegment(expectedSegments[rnd.Next(tree.Count)]);
}
break;
}
CheckSegments();
}
}
[Test]
public void RandomizedRetrievalTest()
{
for (int i = 0; i < 1000; i++) {
AddSegment(rnd.Next(500), rnd.Next(300));
}
CheckSegments();
for (int i = 0; i < 1000; i++) {
TestRetrieval(rnd.Next(1000) - 100, rnd.Next(500));
}
}
[Test]
public void RandomizedWithDocumentChanges()
{
for (int i = 0; i < 500; i++) {
// Console.WriteLine(tree.GetTreeAsString());
// Console.WriteLine("Iteration " + i);
switch (rnd.Next(6)) {
case 0:
AddSegment(rnd.Next(500), rnd.Next(30));
break;
case 1:
AddSegment(rnd.Next(500), rnd.Next(300));
break;
case 2:
if (tree.Count > 0) {
RemoveSegment(expectedSegments[rnd.Next(tree.Count)]);
}
break;
case 3:
ChangeDocument(new OffsetChangeMapEntry(rnd.Next(800), rnd.Next(50), rnd.Next(50)));
break;
case 4:
ChangeDocument(new OffsetChangeMapEntry(rnd.Next(800), 0, rnd.Next(50)));
break;
case 5:
ChangeDocument(new OffsetChangeMapEntry(rnd.Next(800), rnd.Next(50), 0));
break;
}
CheckSegments();
}
}
[Test]
public void RandomizedWithDocumentChangesClose()
{
for (int i = 0; i < 500; i++) {
// Console.WriteLine(tree.GetTreeAsString());
// Console.WriteLine("Iteration " + i);
switch (rnd.Next(6)) {
case 0:
AddSegment(rnd.Next(50), rnd.Next(30));
break;
case 1:
AddSegment(rnd.Next(50), rnd.Next(3));
break;
case 2:
if (tree.Count > 0) {
RemoveSegment(expectedSegments[rnd.Next(tree.Count)]);
}
break;
case 3:
ChangeDocument(new OffsetChangeMapEntry(rnd.Next(80), rnd.Next(10), rnd.Next(10)));
break;
case 4:
ChangeDocument(new OffsetChangeMapEntry(rnd.Next(80), 0, rnd.Next(10)));
break;
case 5:
ChangeDocument(new OffsetChangeMapEntry(rnd.Next(80), rnd.Next(10), 0));
break;
}
CheckSegments();
}
}
}
}

Просмотреть файл

@ -0,0 +1,90 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using NUnit.Framework;
namespace AvaloniaEdit.Document
{
[TestFixture]
public class TextUtilitiesTests
{
#region GetWhitespaceAfter
[Test]
public void TestGetWhitespaceAfter()
{
Assert.AreEqual(new SimpleSegment(2, 3), TextUtilities.GetWhitespaceAfter(new StringTextSource("a \t \tb"), 2));
}
[Test]
public void TestGetWhitespaceAfterDoesNotSkipNewLine()
{
Assert.AreEqual(new SimpleSegment(2, 3), TextUtilities.GetWhitespaceAfter(new StringTextSource("a \t \tb"), 2));
}
[Test]
public void TestGetWhitespaceAfterEmptyResult()
{
Assert.AreEqual(new SimpleSegment(2, 0), TextUtilities.GetWhitespaceAfter(new StringTextSource("a b"), 2));
}
[Test]
public void TestGetWhitespaceAfterEndOfString()
{
Assert.AreEqual(new SimpleSegment(2, 0), TextUtilities.GetWhitespaceAfter(new StringTextSource("a "), 2));
}
[Test]
public void TestGetWhitespaceAfterUntilEndOfString()
{
Assert.AreEqual(new SimpleSegment(2, 3), TextUtilities.GetWhitespaceAfter(new StringTextSource("a \t \t"), 2));
}
#endregion
#region GetWhitespaceBefore
[Test]
public void TestGetWhitespaceBefore()
{
Assert.AreEqual(new SimpleSegment(1, 3), TextUtilities.GetWhitespaceBefore(new StringTextSource("a\t \t b"), 4));
}
[Test]
public void TestGetWhitespaceBeforeDoesNotSkipNewLine()
{
Assert.AreEqual(new SimpleSegment(2, 1), TextUtilities.GetWhitespaceBefore(new StringTextSource("a\n b"), 3));
}
[Test]
public void TestGetWhitespaceBeforeEmptyResult()
{
Assert.AreEqual(new SimpleSegment(2, 0), TextUtilities.GetWhitespaceBefore(new StringTextSource(" a b"), 2));
}
[Test]
public void TestGetWhitespaceBeforeStartOfString()
{
Assert.AreEqual(new SimpleSegment(0, 0), TextUtilities.GetWhitespaceBefore(new StringTextSource(" a"), 0));
}
[Test]
public void TestGetWhitespaceBeforeUntilStartOfString()
{
Assert.AreEqual(new SimpleSegment(0, 2), TextUtilities.GetWhitespaceBefore(new StringTextSource(" \t a"), 2));
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,92 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using NUnit.Framework;
namespace AvaloniaEdit.Document
{
public class UndoStackTests
{
[Test]
public void ContinueUndoGroup()
{
var doc = new TextDocument();
doc.Insert(0, "a");
doc.UndoStack.StartContinuedUndoGroup();
doc.Insert(1, "b");
doc.UndoStack.EndUndoGroup();
doc.UndoStack.Undo();
Assert.AreEqual("", doc.Text);
}
[Test]
public void ContinueEmptyUndoGroup()
{
var doc = new TextDocument();
doc.Insert(0, "a");
doc.UndoStack.StartUndoGroup();
doc.UndoStack.EndUndoGroup();
doc.UndoStack.StartContinuedUndoGroup();
doc.Insert(1, "b");
doc.UndoStack.EndUndoGroup();
doc.UndoStack.Undo();
Assert.AreEqual("a", doc.Text);
}
[Test]
public void ContinueEmptyUndoGroup_WithOptionalEntries()
{
var doc = new TextDocument();
doc.Insert(0, "a");
doc.UndoStack.StartUndoGroup();
doc.UndoStack.PushOptional(new StubUndoableAction());
doc.UndoStack.EndUndoGroup();
doc.UndoStack.StartContinuedUndoGroup();
doc.Insert(1, "b");
doc.UndoStack.EndUndoGroup();
doc.UndoStack.Undo();
Assert.AreEqual("a", doc.Text);
}
[Test]
public void EmptyContinuationGroup()
{
var doc = new TextDocument();
doc.Insert(0, "a");
doc.UndoStack.StartContinuedUndoGroup();
doc.UndoStack.EndUndoGroup();
doc.UndoStack.StartContinuedUndoGroup();
doc.Insert(1, "b");
doc.UndoStack.EndUndoGroup();
doc.UndoStack.Undo();
Assert.AreEqual("", doc.Text);
}
class StubUndoableAction : IUndoableOperation
{
public void Undo()
{
}
public void Redo()
{
}
}
}
}

Просмотреть файл

@ -0,0 +1,86 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Text;
using AvaloniaEdit.AvaloniaMocks;
using AvaloniaEdit.Document;
using NUnit.Framework;
namespace AvaloniaEdit.Editing
{
[TestFixture]
public class ChangeDocumentTests
{
[Test]
public void ClearCaretAndSelectionOnDocumentChange()
{
using (UnitTestApplication.Start(new TestServices(renderInterface: new MockPlatformRenderInterface())))
{
TextArea textArea = new TextArea();
textArea.Document = new TextDocument("1\n2\n3\n4th line");
textArea.Caret.Offset = 6;
textArea.Selection = Selection.Create(textArea, 3, 6);
textArea.Document = new TextDocument("1\n2nd");
Assert.AreEqual(0, textArea.Caret.Offset);
Assert.AreEqual(new TextLocation(1, 1), textArea.Caret.Location);
Assert.IsTrue(textArea.Selection.IsEmpty);
}
}
[Test]
public void SetDocumentToNull()
{
using (UnitTestApplication.Start(new TestServices(renderInterface: new MockPlatformRenderInterface())))
{
TextArea textArea = new TextArea();
textArea.Document = new TextDocument("1\n2\n3\n4th line");
textArea.Caret.Offset = 6;
textArea.Selection = Selection.Create(textArea, 3, 6);
textArea.Document = null;
Assert.AreEqual(0, textArea.Caret.Offset);
Assert.AreEqual(new TextLocation(1, 1), textArea.Caret.Location);
Assert.IsTrue(textArea.Selection.IsEmpty);
}
}
[Test]
public void CheckEventOrderOnDocumentChange()
{
using (UnitTestApplication.Start(new TestServices(renderInterface: new MockPlatformRenderInterface())))
{
TextArea textArea = new TextArea();
TextDocument newDocument = new TextDocument();
StringBuilder b = new StringBuilder();
textArea.TextView.DocumentChanged += delegate
{
b.Append("TextView.DocumentChanged;");
Assert.AreSame(newDocument, textArea.TextView.Document);
Assert.AreSame(newDocument, textArea.Document);
};
textArea.DocumentChanged += delegate
{
b.Append("TextArea.DocumentChanged;");
Assert.AreSame(newDocument, textArea.TextView.Document);
Assert.AreSame(newDocument, textArea.Document);
};
textArea.Document = newDocument;
Assert.AreEqual("TextView.DocumentChanged;TextArea.DocumentChanged;", b.ToString());
}
}
}
}

Просмотреть файл

@ -0,0 +1,183 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using AvaloniaEdit.Document;
using System;
using System.Linq;
using NUnit.Framework;
namespace AvaloniaEdit.Editing
{
[TestFixture]
public class TextSegmentReadOnlySectionTests
{
TextSegmentCollection<TextSegment> segments;
TextSegmentReadOnlySectionProvider<TextSegment> provider;
[SetUp]
public void SetUp()
{
segments = new TextSegmentCollection<TextSegment>();
provider = new TextSegmentReadOnlySectionProvider<TextSegment>(segments);
}
[Test]
public void InsertionPossibleWhenNothingIsReadOnly()
{
Assert.IsTrue(provider.CanInsert(0));
Assert.IsTrue(provider.CanInsert(100));
}
[Test]
public void DeletionPossibleWhenNothingIsReadOnly()
{
var result = provider.GetDeletableSegments(new SimpleSegment(10, 20)).ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual(10, result[0].Offset);
Assert.AreEqual(20, result[0].Length);
}
[Test]
public void EmptyDeletionPossibleWhenNothingIsReadOnly()
{
var result = provider.GetDeletableSegments(new SimpleSegment(10, 0)).ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual(10, result[0].Offset);
Assert.AreEqual(0, result[0].Length);
}
[Test]
public void InsertionPossibleBeforeReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, EndOffset = 15 });
Assert.IsTrue(provider.CanInsert(5));
}
[Test]
public void InsertionPossibleAtStartOfReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, EndOffset = 15 });
Assert.IsTrue(provider.CanInsert(10));
}
[Test]
public void InsertionImpossibleInsideReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, EndOffset = 15 });
Assert.IsFalse(provider.CanInsert(11));
Assert.IsFalse(provider.CanInsert(12));
Assert.IsFalse(provider.CanInsert(13));
Assert.IsFalse(provider.CanInsert(14));
}
[Test]
public void InsertionPossibleAtEndOfReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, EndOffset = 15 });
Assert.IsTrue(provider.CanInsert(15));
}
[Test]
public void InsertionPossibleBetweenReadOnlySegments()
{
segments.Add(new TextSegment { StartOffset = 10, EndOffset = 15 });
segments.Add(new TextSegment { StartOffset = 15, EndOffset = 20 });
Assert.IsTrue(provider.CanInsert(15));
}
[Test]
public void DeletionImpossibleInReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(11, 2)).ToList();
Assert.AreEqual(0, result.Count);
}
[Test]
public void EmptyDeletionImpossibleInReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(11, 0)).ToList();
Assert.AreEqual(0, result.Count);
}
[Test]
public void EmptyDeletionPossibleAtStartOfReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(10, 0)).ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual(10, result[0].Offset);
Assert.AreEqual(0, result[0].Length);
}
[Test]
public void EmptyDeletionPossibleAtEndOfReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(15, 0)).ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual(15, result[0].Offset);
Assert.AreEqual(0, result[0].Length);
}
[Test]
public void DeletionAroundReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 20, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(15, 16)).ToList();
Assert.AreEqual(2, result.Count);
Assert.AreEqual(15, result[0].Offset);
Assert.AreEqual(5, result[0].Length);
Assert.AreEqual(25, result[1].Offset);
Assert.AreEqual(6, result[1].Length);
}
[Test]
public void DeleteLastCharacterInReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 20, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(24, 1)).ToList();
Assert.AreEqual(0, result.Count);
/* // we would need this result for the old Backspace code so that the last character doesn't get selected:
Assert.AreEqual(1, result.Count);
Assert.AreEqual(25, result[0].Offset);
Assert.AreEqual(0, result[0].Length);*/
}
[Test]
public void DeleteFirstCharacterInReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 20, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(20, 1)).ToList();
Assert.AreEqual(0, result.Count);
/* // we would need this result for the old Delete code so that the first character doesn't get selected:
Assert.AreEqual(1, result.Count);
Assert.AreEqual(2, result[0].Offset);
Assert.AreEqual(0, result[0].Length);*/
}
[Test]
public void DeleteWholeReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 20, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(20, 5)).ToList();
Assert.AreEqual(0, result.Count);
}
}
}

Просмотреть файл

@ -0,0 +1,179 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Collections.Generic;
using AvaloniaEdit.Document;
using NUnit.Framework;
namespace AvaloniaEdit.Highlighting
{
[TestFixture]
public class HighlightedLineMergeTests
{
IDocument document = new TextDocument(new string(' ', 20));
[Test]
public void SimpleMerge1()
{
HighlightedLine baseLine = new HighlightedLine(document, document.GetLineByNumber(1));
baseLine.Sections.Add(MakeSection(0, 1, "B"));
HighlightedLine additionalLine = new HighlightedLine(document, document.GetLineByNumber(1));
additionalLine.Sections.Add(MakeSection(0, 2, "A"));
baseLine.MergeWith(additionalLine);
// The additional section gets split up so that it fits into the tree structure
Assert.That(baseLine.Sections, Is.EqualTo(
new[] {
MakeSection(0, 1, "B"),
MakeSection(0, 1, "A"),
MakeSection(1, 2, "A")
}).Using(new SectionComparer()));
}
[Test]
public void SimpleMerge2()
{
HighlightedLine baseLine = new HighlightedLine(document, document.GetLineByNumber(1));
baseLine.Sections.Add(MakeSection(0, 1, "B"));
baseLine.Sections.Add(MakeSection(0, 1, "BN"));
HighlightedLine additionalLine = new HighlightedLine(document, document.GetLineByNumber(1));
additionalLine.Sections.Add(MakeSection(0, 2, "A"));
baseLine.MergeWith(additionalLine);
// The additional section gets split up so that it fits into the tree structure
Assert.That(baseLine.Sections, Is.EqualTo(
new[] {
MakeSection(0, 1, "B"),
MakeSection(0, 1, "BN"),
MakeSection(0, 1, "A"),
MakeSection(1, 2, "A")
}).Using(new SectionComparer()));
}
HighlightedSection MakeSection(int start, int end, string name)
{
return new HighlightedSection { Offset = start, Length = end - start, Color = new HighlightingColor { Name = name }};
}
class SectionComparer : IEqualityComparer<HighlightedSection>
{
public bool Equals(HighlightedSection a, HighlightedSection b)
{
return a.Offset == b.Offset && a.Length == b.Length && a.Color.Name == b.Color.Name;
}
public int GetHashCode(HighlightedSection obj)
{
return obj.Offset;
}
}
#region Automatic Test
/*
const int combinations = 6 * 3 * 4 * 3 * 3 * 4;
HighlightingColor[] baseLineColors = {
new HighlightingColor { Name = "Base-A" },
new HighlightingColor { Name = "Base-B" },
new HighlightingColor { Name = "Base-N" },
new HighlightingColor { Name = "Base-C" }
};
HighlightingColor[] additionalLineColors = {
new HighlightingColor { Name = "Add-A" },
new HighlightingColor { Name = "Add-B" },
new HighlightingColor { Name = "Add-N" },
new HighlightingColor { Name = "Add-C" }
};
HighlightedLine BuildHighlightedLine(int num, HighlightingColor[] colors)
{
// We are build a HighlightedLine with 4 segments:
// A B C (top-level) and N nested within B.
// These are the integers controlling the generating process:
int aStart = GetNum(ref num, 5); // start offset of A
int aLength = GetNum(ref num, 2); // length of A
int bDistance = GetNum(ref num, 3); // distance from start of B to end of A
int bStart = aStart + aLength + bDistance;
int nDistance = GetNum(ref num, 2); // distance from start of B to start of N, range 0-2
int nLength = GetNum(ref num, 2); // length of N
int bEndDistance = GetNum(ref num, 2); // distance from end of N to end of B
int bLength = nDistance + nLength + bEndDistance;
int cDistance = GetNum(ref num, 3); // distance from end of B to start of C
int cStart = bStart + bLength + cDistance;
int cLength = 1;
Assert.AreEqual(0, num);
var documentLine = document.GetLineByNumber(1);
HighlightedLine line = new HighlightedLine(document, documentLine);
line.Sections.Add(new HighlightedSection { Offset = aStart, Length = aLength, Color = colors[0] });
line.Sections.Add(new HighlightedSection { Offset = bStart, Length = bLength, Color = colors[1] });
line.Sections.Add(new HighlightedSection { Offset = bStart + nDistance, Length = nLength, Color = colors[2] });
line.Sections.Add(new HighlightedSection { Offset = cStart, Length = cLength, Color = colors[3] });
return line;
}
/// <summary>
/// Gets a number between 0 and max (inclusive)
/// </summary>
int GetNum(ref int num, int max)
{
int result = num % (max+1);
num = num / (max + 1);
return result;
}
[Test]
public void TestAll()
{
for (int c1 = 0; c1 < combinations; c1++) {
HighlightedLine line1 = BuildHighlightedLine(c1, additionalLineColors);
for (int c2 = 0; c2 < combinations; c2++) {
HighlightedLine line2 = BuildHighlightedLine(c2, baseLineColors);
HighlightingColor[] expectedPerCharColors = new HighlightingColor[document.TextLength];
ApplyColors(expectedPerCharColors, line2);
ApplyColors(expectedPerCharColors, line1);
try {
line2.MergeWith(line1);
} catch (InvalidOperationException ex) {
throw new InvalidOperationException(string.Format("Error for c1 = {0}, c2 = {1}", c1, c2), ex);
}
HighlightingColor[] actualPerCharColors = new HighlightingColor[document.TextLength];
ApplyColors(actualPerCharColors, line2);
Assert.AreEqual(expectedPerCharColors, actualPerCharColors, string.Format("c1 = {0}, c2 = {1}", c1, c2));
}
}
}
void ApplyColors(HighlightingColor[] perCharColors, HighlightedLine line)
{
foreach (var section in line.Sections) {
for (int i = 0; i < section.Length; i++) {
perCharColors[section.Offset + i] = section.Color;
}
}
}
*/
#endregion
}
}

Просмотреть файл

@ -0,0 +1,56 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
using AvaloniaEdit.Document;
using NUnit.Framework;
namespace AvaloniaEdit.Highlighting
{
[TestFixture]
public class HtmlClipboardTests
{
TextDocument document;
DocumentHighlighter highlighter;
public HtmlClipboardTests()
{
document = new TextDocument("using System.Text;\n\tstring text = SomeMethod();");
highlighter = new DocumentHighlighter(document, HighlightingManager.Instance.GetDefinition("C#"));
}
[Test, Ignore("")]
public void FullDocumentTest()
{
var segment = new TextSegment { StartOffset = 0, Length = document.TextLength };
string html = HtmlClipboard.CreateHtmlFragment(document, highlighter, segment, new HtmlOptions());
Assert.AreEqual("<span style=\"color: #008000; font-weight: bold; \">using</span> System.Text;<br>" + Environment.NewLine +
"&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color: #ff0000; \">string</span> " +
"text = <span style=\"color: #191970; font-weight: bold; \">SomeMethod</span>();", html);
}
[Test, Ignore("")]
public void PartOfHighlightedWordTest()
{
var segment = new TextSegment { StartOffset = 1, Length = 3 };
string html = HtmlClipboard.CreateHtmlFragment(document, highlighter, segment, new HtmlOptions());
Assert.AreEqual("<span style=\"color: #008000; font-weight: bold; \">sin</span>", html);
}
}
}

Просмотреть файл

@ -0,0 +1,129 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using AvaloniaEdit.Document;
using NUnit.Framework;
namespace AvaloniaEdit.Search
{
//[TestFixture]
//public class FindTests
//{
// [Test]
// public void SkipWordBorderSimple()
// {
// var strategy = SearchStrategyFactory.Create("All", false, true, SearchMode.Normal);
// var text = new StringTextSource(" FindAllTests ");
// var results = strategy.FindAll(text, 0, text.TextLength).ToArray();
// Assert.IsEmpty(results, "No results should be found!");
// }
// [Test]
// public void SkipWordBorder()
// {
// var strategy = SearchStrategyFactory.Create("AllTests", false, true, SearchMode.Normal);
// var text = new StringTextSource("name=\"{FindAllTests}\"");
// var results = strategy.FindAll(text, 0, text.TextLength).ToArray();
// Assert.IsEmpty(results, "No results should be found!");
// }
// [Test]
// public void SkipWordBorder2()
// {
// var strategy = SearchStrategyFactory.Create("AllTests", false, true, SearchMode.Normal);
// var text = new StringTextSource("name=\"FindAllTests ");
// var results = strategy.FindAll(text, 0, text.TextLength).ToArray();
// Assert.IsEmpty(results, "No results should be found!");
// }
// [Test]
// public void SkipWordBorder3()
// {
// var strategy = SearchStrategyFactory.Create("// find", false, true, SearchMode.Normal);
// var text = new StringTextSource(" // findtest");
// var results = strategy.FindAll(text, 0, text.TextLength).ToArray();
// Assert.IsEmpty(results, "No results should be found!");
// }
// [Test]
// public void WordBorderTest()
// {
// var strategy = SearchStrategyFactory.Create("// find", false, true, SearchMode.Normal);
// var text = new StringTextSource(" // find me");
// var results = strategy.FindAll(text, 0, text.TextLength).ToArray();
// Assert.AreEqual(1, results.Length, "One result should be found!");
// Assert.AreEqual(" ".Length, results[0].Offset);
// Assert.AreEqual("// find".Length, results[0].Length);
// }
// [Test]
// public void ResultAtStart()
// {
// var strategy = SearchStrategyFactory.Create("result", false, true, SearchMode.Normal);
// var text = new StringTextSource("result // find me");
// var results = strategy.FindAll(text, 0, text.TextLength).ToArray();
// Assert.AreEqual(1, results.Length, "One result should be found!");
// Assert.AreEqual(0, results[0].Offset);
// Assert.AreEqual("result".Length, results[0].Length);
// }
// [Test]
// public void ResultAtEnd()
// {
// var strategy = SearchStrategyFactory.Create("me", false, true, SearchMode.Normal);
// var text = new StringTextSource("result // find me");
// var results = strategy.FindAll(text, 0, text.TextLength).ToArray();
// Assert.AreEqual(1, results.Length, "One result should be found!");
// Assert.AreEqual("result // find ".Length, results[0].Offset);
// Assert.AreEqual("me".Length, results[0].Length);
// }
// [Test]
// public void TextWithDots()
// {
// var strategy = SearchStrategyFactory.Create("Text", false, true, SearchMode.Normal);
// var text = new StringTextSource(".Text.");
// var results = strategy.FindAll(text, 0, text.TextLength).ToArray();
// Assert.AreEqual(1, results.Length, "One result should be found!");
// Assert.AreEqual(".".Length, results[0].Offset);
// Assert.AreEqual("Text".Length, results[0].Length);
// }
// [Test]
// public void SimpleTest()
// {
// var strategy = SearchStrategyFactory.Create("AllTests", false, false, SearchMode.Normal);
// var text = new StringTextSource("name=\"FindAllTests ");
// var results = strategy.FindAll(text, 0, text.TextLength).ToArray();
// Assert.AreEqual(1, results.Length, "One result should be found!");
// Assert.AreEqual("name=\"Find".Length, results[0].Offset);
// Assert.AreEqual("AllTests".Length, results[0].Length);
// }
//}
}

Просмотреть файл

@ -0,0 +1,153 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using AvaloniaEdit.Document;
using NUnit.Framework;
namespace AvaloniaEdit.Utils
{
[TestFixture]
public class CaretNavigationTests
{
int GetNextCaretStop(string text, int offset, CaretPositioningMode mode)
{
return TextUtilities.GetNextCaretPosition(new StringTextSource(text), offset, LogicalDirection.Forward, mode);
}
int GetPrevCaretStop(string text, int offset, CaretPositioningMode mode)
{
return TextUtilities.GetNextCaretPosition(new StringTextSource(text), offset, LogicalDirection.Backward, mode);
}
[Test]
public void CaretStopInEmptyString()
{
Assert.AreEqual(0, GetNextCaretStop("", -1, CaretPositioningMode.Normal));
Assert.AreEqual(-1, GetNextCaretStop("", 0, CaretPositioningMode.Normal));
Assert.AreEqual(-1, GetPrevCaretStop("", 0, CaretPositioningMode.Normal));
Assert.AreEqual(0, GetPrevCaretStop("", 1, CaretPositioningMode.Normal));
Assert.AreEqual(-1, GetNextCaretStop("", -1, CaretPositioningMode.WordStart));
Assert.AreEqual(-1, GetNextCaretStop("", -1, CaretPositioningMode.WordBorder));
Assert.AreEqual(-1, GetPrevCaretStop("", 1, CaretPositioningMode.WordStart));
Assert.AreEqual(-1, GetPrevCaretStop("", 1, CaretPositioningMode.WordBorder));
}
[Test]
public void StartOfDocumentWithWordStart()
{
Assert.AreEqual(0, GetNextCaretStop("word", -1, CaretPositioningMode.Normal));
Assert.AreEqual(0, GetNextCaretStop("word", -1, CaretPositioningMode.WordStart));
Assert.AreEqual(0, GetNextCaretStop("word", -1, CaretPositioningMode.WordBorder));
Assert.AreEqual(0, GetPrevCaretStop("word", 1, CaretPositioningMode.Normal));
Assert.AreEqual(0, GetPrevCaretStop("word", 1, CaretPositioningMode.WordStart));
Assert.AreEqual(0, GetPrevCaretStop("word", 1, CaretPositioningMode.WordBorder));
}
[Test]
public void StartOfDocumentNoWordStart()
{
Assert.AreEqual(0, GetNextCaretStop(" word", -1, CaretPositioningMode.Normal));
Assert.AreEqual(1, GetNextCaretStop(" word", -1, CaretPositioningMode.WordStart));
Assert.AreEqual(1, GetNextCaretStop(" word", -1, CaretPositioningMode.WordBorder));
Assert.AreEqual(0, GetPrevCaretStop(" word", 1, CaretPositioningMode.Normal));
Assert.AreEqual(-1, GetPrevCaretStop(" word", 1, CaretPositioningMode.WordStart));
Assert.AreEqual(-1, GetPrevCaretStop(" word", 1, CaretPositioningMode.WordBorder));
}
[Test]
public void EndOfDocumentWordBorder()
{
Assert.AreEqual(4, GetNextCaretStop("word", 3, CaretPositioningMode.Normal));
Assert.AreEqual(-1, GetNextCaretStop("word", 3, CaretPositioningMode.WordStart));
Assert.AreEqual(4, GetNextCaretStop("word", 3, CaretPositioningMode.WordBorder));
Assert.AreEqual(4, GetPrevCaretStop("word", 5, CaretPositioningMode.Normal));
Assert.AreEqual(0, GetPrevCaretStop("word", 5, CaretPositioningMode.WordStart));
Assert.AreEqual(4, GetPrevCaretStop("word", 5, CaretPositioningMode.WordBorder));
}
[Test]
public void EndOfDocumentNoWordBorder()
{
Assert.AreEqual(4, GetNextCaretStop("txt ", 3, CaretPositioningMode.Normal));
Assert.AreEqual(-1, GetNextCaretStop("txt ", 3, CaretPositioningMode.WordStart));
Assert.AreEqual(-1, GetNextCaretStop("txt ", 3, CaretPositioningMode.WordBorder));
Assert.AreEqual(4, GetPrevCaretStop("txt ", 5, CaretPositioningMode.Normal));
Assert.AreEqual(0, GetPrevCaretStop("txt ", 5, CaretPositioningMode.WordStart));
Assert.AreEqual(3, GetPrevCaretStop("txt ", 5, CaretPositioningMode.WordBorder));
}
[Test]
public void SingleCharacterOutsideBMP()
{
string c = "\U0001D49E";
Assert.AreEqual(2, GetNextCaretStop(c, 0, CaretPositioningMode.Normal));
Assert.AreEqual(0, GetPrevCaretStop(c, 2, CaretPositioningMode.Normal));
}
[Test]
public void DetectWordBordersOutsideBMP()
{
string c = " a\U0001D49Eb ";
Assert.AreEqual(1, GetNextCaretStop(c, 0, CaretPositioningMode.WordBorder));
Assert.AreEqual(5, GetNextCaretStop(c, 1, CaretPositioningMode.WordBorder));
Assert.AreEqual(5, GetPrevCaretStop(c, 6, CaretPositioningMode.WordBorder));
Assert.AreEqual(1, GetPrevCaretStop(c, 5, CaretPositioningMode.WordBorder));
}
[Test]
public void DetectWordBordersOutsideBMP2()
{
string c = " \U0001D49E\U0001D4AA ";
Assert.AreEqual(1, GetNextCaretStop(c, 0, CaretPositioningMode.WordBorder));
Assert.AreEqual(5, GetNextCaretStop(c, 1, CaretPositioningMode.WordBorder));
Assert.AreEqual(5, GetPrevCaretStop(c, 6, CaretPositioningMode.WordBorder));
Assert.AreEqual(1, GetPrevCaretStop(c, 5, CaretPositioningMode.WordBorder));
}
[Test]
public void CombiningMark()
{
string str = " x͆ ";
Assert.AreEqual(3, GetNextCaretStop(str, 1, CaretPositioningMode.Normal));
Assert.AreEqual(1, GetPrevCaretStop(str, 3, CaretPositioningMode.Normal));
}
[Test]
public void StackedCombiningMark()
{
string str = " x͆͆͆͆ ";
Assert.AreEqual(6, GetNextCaretStop(str, 1, CaretPositioningMode.Normal));
Assert.AreEqual(1, GetPrevCaretStop(str, 6, CaretPositioningMode.Normal));
}
[Test]
public void SingleClosingBraceAtLineEnd()
{
string str = "\t\t}";
Assert.AreEqual(2, GetNextCaretStop(str, 1, CaretPositioningMode.WordStart));
Assert.AreEqual(-1, GetPrevCaretStop(str, 1, CaretPositioningMode.WordStart));
}
}
}

Просмотреть файл

@ -0,0 +1,146 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using NUnit.Framework;
namespace AvaloniaEdit.Utils
{
[TestFixture]
public class CompressingTreeListTests
{
[Test]
public void EmptyTreeList()
{
CompressingTreeList<string> list = new CompressingTreeList<string>(string.Equals);
Assert.AreEqual(0, list.Count);
foreach (string v in list) {
Assert.Fail();
}
string[] arr = new string[0];
list.CopyTo(arr, 0);
}
[Test]
public void CheckAdd10BillionElements()
{
const int billion = 1000000000;
CompressingTreeList<string> list = new CompressingTreeList<string>(string.Equals);
list.InsertRange(0, billion, "A");
list.InsertRange(1, billion, "B");
Assert.AreEqual(2 * billion, list.Count);
Assert.Throws<OverflowException>(delegate { list.InsertRange(2, billion, "C"); });
}
[Test]
public void AddRepeated()
{
CompressingTreeList<int> list = new CompressingTreeList<int>((a, b) => a == b);
list.Add(42);
list.Add(42);
list.Add(42);
list.Insert(0, 42);
list.Insert(1, 42);
Assert.AreEqual(new[] { 42, 42, 42, 42, 42 }, list.ToArray());
}
[Test]
public void RemoveRange()
{
CompressingTreeList<int> list = new CompressingTreeList<int>((a, b) => a == b);
for (int i = 1; i <= 3; i++) {
list.InsertRange(list.Count, 2, i);
}
Assert.AreEqual(new[] { 1, 1, 2, 2, 3, 3 }, list.ToArray());
list.RemoveRange(1, 4);
Assert.AreEqual(new[] { 1, 3 }, list.ToArray());
list.Insert(1, 1);
list.InsertRange(2, 2, 2);
list.Insert(4, 1);
Assert.AreEqual(new[] { 1, 1, 2, 2, 1, 3 }, list.ToArray());
list.RemoveRange(2, 2);
Assert.AreEqual(new[] { 1, 1, 1, 3 }, list.ToArray());
}
[Test]
public void RemoveAtEnd()
{
CompressingTreeList<int> list = new CompressingTreeList<int>((a, b) => a == b);
for (int i = 1; i <= 3; i++) {
list.InsertRange(list.Count, 2, i);
}
Assert.AreEqual(new[] { 1, 1, 2, 2, 3, 3 }, list.ToArray());
list.RemoveRange(3, 3);
Assert.AreEqual(new[] { 1, 1, 2 }, list.ToArray());
}
[Test]
public void RemoveAtStart()
{
CompressingTreeList<int> list = new CompressingTreeList<int>((a, b) => a == b);
for (int i = 1; i <= 3; i++) {
list.InsertRange(list.Count, 2, i);
}
Assert.AreEqual(new[] { 1, 1, 2, 2, 3, 3 }, list.ToArray());
list.RemoveRange(0, 1);
Assert.AreEqual(new[] { 1, 2, 2, 3, 3 }, list.ToArray());
}
[Test]
public void RemoveAtStart2()
{
CompressingTreeList<int> list = new CompressingTreeList<int>((a, b) => a == b);
for (int i = 1; i <= 3; i++) {
list.InsertRange(list.Count, 2, i);
}
Assert.AreEqual(new[] { 1, 1, 2, 2, 3, 3 }, list.ToArray());
list.RemoveRange(0, 3);
Assert.AreEqual(new[] { 2, 3, 3 }, list.ToArray());
}
[Test]
public void Transform()
{
CompressingTreeList<int> list = new CompressingTreeList<int>((a, b) => a == b);
list.AddRange(new[] { 0, 1, 1, 0 });
int calls = 0;
list.Transform(i => { calls++; return i + 1; });
Assert.AreEqual(3, calls);
Assert.AreEqual(new[] { 1, 2, 2, 1 }, list.ToArray());
}
[Test]
public void TransformToZero()
{
CompressingTreeList<int> list = new CompressingTreeList<int>((a, b) => a == b);
list.AddRange(new[] { 0, 1, 1, 0 });
list.Transform(i => 0);
Assert.AreEqual(new[] { 0, 0, 0, 0 }, list.ToArray());
}
[Test]
public void TransformRange()
{
CompressingTreeList<int> list = new CompressingTreeList<int>((a, b) => a == b);
list.AddRange(new[] { 0, 1, 1, 1, 0, 0 });
list.TransformRange(2, 3, i => 0);
Assert.AreEqual(new[] { 0, 1, 0, 0, 0, 0 }, list.ToArray());
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using NUnit.Framework;
namespace AvaloniaEdit.Utils
{
[TestFixture]
public class ExtensionMethodsTests
{
[Test]
public void ZeroIsNotCloseToOne()
{
Assert.IsFalse(0.0.IsClose(1));
}
[Test]
public void ZeroIsCloseToZero()
{
Assert.IsTrue(0.0.IsClose(0));
}
[Test]
public void InfinityIsCloseToInfinity()
{
Assert.IsTrue(double.PositiveInfinity.IsClose(double.PositiveInfinity));
}
[Test]
public void NaNIsNotCloseToNaN()
{
Assert.IsFalse(double.NaN.IsClose(double.NaN));
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using NUnit.Framework;
namespace AvaloniaEdit.Utils
{
[TestFixture]
public class IndentationStringTests
{
[Test]
public void IndentWithSingleTab()
{
var options = new TextEditorOptions { IndentationSize = 4, ConvertTabsToSpaces = false };
Assert.AreEqual("\t", options.IndentationString);
Assert.AreEqual("\t", options.GetIndentationString(2));
Assert.AreEqual("\t", options.GetIndentationString(3));
Assert.AreEqual("\t", options.GetIndentationString(4));
Assert.AreEqual("\t", options.GetIndentationString(5));
Assert.AreEqual("\t", options.GetIndentationString(6));
}
[Test]
public void IndentWith4Spaces()
{
var options = new TextEditorOptions { IndentationSize = 4, ConvertTabsToSpaces = true };
Assert.AreEqual(" ", options.IndentationString);
Assert.AreEqual(" ", options.GetIndentationString(2));
Assert.AreEqual(" ", options.GetIndentationString(3));
Assert.AreEqual(" ", options.GetIndentationString(4));
Assert.AreEqual(" ", options.GetIndentationString(5));
Assert.AreEqual(" ", options.GetIndentationString(6));
}
}
}

Просмотреть файл

@ -0,0 +1,195 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
using NUnit.Framework;
using System.Text;
namespace AvaloniaEdit.Utils
{
[TestFixture]
public class RopeTests
{
[Test]
public void EmptyRope()
{
Rope<char> empty = new Rope<char>();
Assert.AreEqual(0, empty.Length);
Assert.AreEqual("", empty.ToString());
}
[Test]
public void EmptyRopeFromString()
{
Rope<char> empty = new Rope<char>(string.Empty);
Assert.AreEqual(0, empty.Length);
Assert.AreEqual("", empty.ToString());
}
[Test]
public void InitializeRopeFromShortString()
{
Rope<char> rope = new Rope<char>("Hello, World");
Assert.AreEqual(12, rope.Length);
Assert.AreEqual("Hello, World", rope.ToString());
}
string BuildLongString(int lines)
{
StringWriter w = new StringWriter();
w.NewLine = "\n";
for (int i = 1; i <= lines; i++) {
w.WriteLine(i.ToString());
}
return w.ToString();
}
[Test]
public void InitializeRopeFromLongString()
{
string text = BuildLongString(1000);
Rope<char> rope = new Rope<char>(text);
Assert.AreEqual(text.Length, rope.Length);
Assert.AreEqual(text, rope.ToString());
Assert.AreEqual(text.ToCharArray(), rope.ToArray());
}
[Test]
public void TestToArrayAndToStringWithParts()
{
string text = BuildLongString(1000);
Rope<char> rope = new Rope<char>(text);
string textPart = text.Substring(1200, 600);
char[] arrayPart = textPart.ToCharArray();
Assert.AreEqual(textPart, rope.ToString(1200, 600));
Assert.AreEqual(arrayPart, rope.ToArray(1200, 600));
Rope<char> partialRope = rope.GetRange(1200, 600);
Assert.AreEqual(textPart, partialRope.ToString());
Assert.AreEqual(arrayPart, partialRope.ToArray());
}
[Test]
public void ConcatenateStringToRope()
{
StringBuilder b = new StringBuilder();
Rope<char> rope = new Rope<char>();
for (int i = 1; i <= 1000; i++) {
b.Append(i.ToString());
rope.AddText(i.ToString());
b.Append(' ');
rope.Add(' ');
}
Assert.AreEqual(b.ToString(), rope.ToString());
}
[Test]
public void ConcatenateSmallRopesToRope()
{
StringBuilder b = new StringBuilder();
Rope<char> rope = new Rope<char>();
for (int i = 1; i <= 1000; i++) {
b.Append(i.ToString());
b.Append(' ');
rope.AddRange(CharRope.Create(i.ToString() + " "));
}
Assert.AreEqual(b.ToString(), rope.ToString());
}
[Test]
public void AppendLongTextToEmptyRope()
{
string text = BuildLongString(1000);
Rope<char> rope = new Rope<char>();
rope.AddText(text);
Assert.AreEqual(text, rope.ToString());
}
[Test]
public void ConcatenateStringToRopeBackwards()
{
StringBuilder b = new StringBuilder();
Rope<char> rope = new Rope<char>();
for (int i = 1; i <= 1000; i++) {
b.Append(i.ToString());
b.Append(' ');
}
for (int i = 1000; i >= 1; i--) {
rope.Insert(0, ' ');
rope.InsertText(0, i.ToString());
}
Assert.AreEqual(b.ToString(), rope.ToString());
}
[Test]
public void ConcatenateSmallRopesToRopeBackwards()
{
StringBuilder b = new StringBuilder();
Rope<char> rope = new Rope<char>();
for (int i = 1; i <= 1000; i++) {
b.Append(i.ToString());
b.Append(' ');
}
for (int i = 1000; i >= 1; i--) {
rope.InsertRange(0, CharRope.Create(i.ToString() + " "));
}
Assert.AreEqual(b.ToString(), rope.ToString());
}
[Test]
public void ConcatenateStringToRopeByInsertionInMiddle()
{
StringBuilder b = new StringBuilder();
Rope<char> rope = new Rope<char>();
for (int i = 1; i <= 998; i++) {
b.Append(i.ToString("d3"));
b.Append(' ');
}
int middle = 0;
for (int i = 1; i <= 499; i++) {
rope.InsertText(middle, i.ToString("d3"));
middle += 3;
rope.Insert(middle, ' ');
middle++;
rope.InsertText(middle, (999-i).ToString("d3"));
rope.Insert(middle + 3, ' ');
}
Assert.AreEqual(b.ToString(), rope.ToString());
}
[Test]
public void ConcatenateSmallRopesByInsertionInMiddle()
{
StringBuilder b = new StringBuilder();
Rope<char> rope = new Rope<char>();
for (int i = 1; i <= 1000; i++) {
b.Append(i.ToString("d3"));
b.Append(' ');
}
int middle = 0;
for (int i = 1; i <= 500; i++) {
rope.InsertRange(middle, CharRope.Create(i.ToString("d3") + " "));
middle += 4;
rope.InsertRange(middle, CharRope.Create((1001-i).ToString("d3") + " "));
}
Assert.AreEqual(b.ToString(), rope.ToString());
}
}
}

Просмотреть файл

@ -0,0 +1,116 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Runtime.CompilerServices;
using AvaloniaEdit.AvaloniaMocks;
using AvaloniaEdit.Document;
using AvaloniaEdit.Editing;
using AvaloniaEdit.Rendering;
using NUnit.Framework;
namespace AvaloniaEdit
{
[TestFixture]
public class WeakReferenceTests
{
[MethodImpl(MethodImplOptions.NoInlining)]
private static WeakReference CreateControl<T>(Action<T> action = null)
where T : class, new()
{
WeakReference wr;
using (UnitTestApplication.Start(new TestServices(renderInterface: new MockPlatformRenderInterface())))
{
var control = new T();
wr = new WeakReference(control);
action?.Invoke(control);
control = null;
}
GarbageCollect();
return wr;
}
[Test]
public void TextViewCanBeCollectedTest()
{
var wr = CreateControl<TextView>();
Assert.IsFalse(wr.IsAlive);
}
[Test]
public void DocumentDoesNotHoldReferenceToTextView()
{
TextDocument textDocument = new TextDocument();
Assert.AreEqual(0, textDocument.LineTrackers.Count);
var wr = CreateControl<TextView>(t => t.Document = textDocument);
Assert.IsFalse(wr.IsAlive);
// document cannot immediately clear the line tracker
Assert.AreEqual(1, textDocument.LineTrackers.Count);
// but it should clear it on the next change
textDocument.Insert(0, "a");
Assert.AreEqual(0, textDocument.LineTrackers.Count);
}
//[Test] // currently fails due to some Avalonia static
void DocumentDoesNotHoldReferenceToTextArea()
{
var textDocument = new TextDocument();
var wr = CreateControl<TextArea>(t => t.Document = textDocument);
Assert.IsFalse(wr.IsAlive);
GC.KeepAlive(textDocument);
}
//[Test] // currently fails due to some Avalonia static
void DocumentDoesNotHoldReferenceToTextEditor()
{
var textDocument = new TextDocument();
var wr = CreateControl<TextEditor>(t => t.Document = textDocument);
Assert.IsFalse(wr.IsAlive);
GC.KeepAlive(textDocument);
}
[Test]
public void DocumentDoesNotHoldReferenceToLineMargin()
{
TextDocument textDocument = new TextDocument();
var wr = CreateControl<TextView>(t =>
{
t.Document = textDocument;
new LineNumberMargin { TextView = t };
});
Assert.IsFalse(wr.IsAlive);
GC.KeepAlive(textDocument);
}
static void GarbageCollect()
{
for (int i = 0; i < 3; i++)
{
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
}
}
}
}