csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
453 lines
14 KiB
453 lines
14 KiB
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
|
|
using System;
|
|
using System.Reactive.Linq;
|
|
using Avalonia.Controls.Presenters;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Controls.Templates;
|
|
using Avalonia.Data;
|
|
using Avalonia.Input;
|
|
using Avalonia.Media;
|
|
using Avalonia.Platform;
|
|
using Avalonia.UnitTests;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace Avalonia.Controls.UnitTests
|
|
{
|
|
public class TextBoxTests
|
|
{
|
|
[Fact]
|
|
public void DefaultBindingMode_Should_Be_TwoWay()
|
|
{
|
|
Assert.Equal(
|
|
BindingMode.TwoWay,
|
|
TextBox.TextProperty.GetMetadata(typeof(TextBox)).DefaultBindingMode);
|
|
}
|
|
|
|
[Fact]
|
|
public void CaretIndex_Can_Moved_To_Position_After_The_End_Of_Text_With_Arrow_Key()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
Text = "1234"
|
|
};
|
|
|
|
target.CaretIndex = 3;
|
|
RaiseKeyEvent(target, Key.Right, 0);
|
|
|
|
Assert.Equal(4, target.CaretIndex);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Press_Ctrl_A_Select_All_Text()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
Text = "1234"
|
|
};
|
|
|
|
RaiseKeyEvent(target, Key.A, InputModifiers.Control);
|
|
|
|
Assert.Equal(0, target.SelectionStart);
|
|
Assert.Equal(4, target.SelectionEnd);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Press_Ctrl_A_Select_All_Null_Text()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate()
|
|
};
|
|
|
|
RaiseKeyEvent(target, Key.A, InputModifiers.Control);
|
|
|
|
Assert.Equal(0, target.SelectionStart);
|
|
Assert.Equal(0, target.SelectionEnd);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Press_Ctrl_Z_Will_Not_Modify_Text()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
Text = "1234"
|
|
};
|
|
|
|
RaiseKeyEvent(target, Key.Z, InputModifiers.Control);
|
|
|
|
Assert.Equal("1234", target.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Typing_Beginning_With_0_Should_Not_Modify_Text_When_Bound_To_Int()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var source = new Class1();
|
|
var target = new TextBox
|
|
{
|
|
DataContext = source,
|
|
Template = CreateTemplate(),
|
|
};
|
|
|
|
target.ApplyTemplate();
|
|
target.Bind(TextBox.TextProperty, new Binding(nameof(Class1.Foo), BindingMode.TwoWay));
|
|
|
|
Assert.Equal("0", target.Text);
|
|
|
|
target.CaretIndex = 1;
|
|
target.RaiseEvent(new TextInputEventArgs
|
|
{
|
|
RoutedEvent = InputElement.TextInputEvent,
|
|
Text = "2",
|
|
});
|
|
|
|
Assert.Equal("02", target.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Control_Backspace_Should_Remove_The_Word_Before_The_Caret_If_There_Is_No_Selection()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
TextBox textBox = new TextBox
|
|
{
|
|
Text = "First Second Third Fourth",
|
|
CaretIndex = 5
|
|
};
|
|
|
|
// (First| Second Third Fourth)
|
|
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control);
|
|
Assert.Equal(" Second Third Fourth", textBox.Text);
|
|
|
|
// ( Second |Third Fourth)
|
|
textBox.CaretIndex = 8;
|
|
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control);
|
|
Assert.Equal(" Third Fourth", textBox.Text);
|
|
|
|
// ( Thi|rd Fourth)
|
|
textBox.CaretIndex = 4;
|
|
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control);
|
|
Assert.Equal(" rd Fourth", textBox.Text);
|
|
|
|
// ( rd F[ou]rth)
|
|
textBox.SelectionStart = 5;
|
|
textBox.SelectionEnd = 7;
|
|
|
|
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control);
|
|
Assert.Equal(" rd Frth", textBox.Text);
|
|
|
|
// ( |rd Frth)
|
|
textBox.CaretIndex = 1;
|
|
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control);
|
|
Assert.Equal("rd Frth", textBox.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Control_Delete_Should_Remove_The_Word_After_The_Caret_If_There_Is_No_Selection()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
TextBox textBox = new TextBox
|
|
{
|
|
Text = "First Second Third Fourth",
|
|
CaretIndex = 19
|
|
};
|
|
|
|
// (First Second Third |Fourth)
|
|
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control);
|
|
Assert.Equal("First Second Third ", textBox.Text);
|
|
|
|
// (First Second |Third )
|
|
textBox.CaretIndex = 13;
|
|
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control);
|
|
Assert.Equal("First Second ", textBox.Text);
|
|
|
|
// (First Sec|ond )
|
|
textBox.CaretIndex = 9;
|
|
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control);
|
|
Assert.Equal("First Sec", textBox.Text);
|
|
|
|
// (Fi[rs]t Sec )
|
|
textBox.SelectionStart = 2;
|
|
textBox.SelectionEnd = 4;
|
|
|
|
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control);
|
|
Assert.Equal("Fit Sec", textBox.Text);
|
|
|
|
// (Fit Sec| )
|
|
textBox.Text += " ";
|
|
textBox.CaretIndex = 7;
|
|
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control);
|
|
Assert.Equal("Fit Sec", textBox.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Setting_SelectionStart_To_SelectionEnd_Sets_CaretPosition_To_SelectionStart()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var textBox = new TextBox
|
|
{
|
|
Text = "0123456789"
|
|
};
|
|
|
|
textBox.SelectionStart = 2;
|
|
textBox.SelectionEnd = 2;
|
|
Assert.Equal(2, textBox.CaretIndex);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Setting_Text_Updates_CaretPosition()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Text = "Initial Text",
|
|
CaretIndex = 11
|
|
};
|
|
|
|
var invoked = false;
|
|
|
|
target.GetObservable(TextBox.TextProperty).Skip(1).Subscribe(_ =>
|
|
{
|
|
// Caret index should be set before Text changed notification, as we don't want
|
|
// to notify with an invalid CaretIndex.
|
|
Assert.Equal(7, target.CaretIndex);
|
|
invoked = true;
|
|
});
|
|
|
|
target.Text = "Changed";
|
|
|
|
Assert.True(invoked);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Press_Enter_Does_Not_Accept_Return()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
AcceptsReturn = false,
|
|
Text = "1234"
|
|
};
|
|
|
|
RaiseKeyEvent(target, Key.Enter, 0);
|
|
|
|
Assert.Equal("1234", target.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Press_Enter_Add_Default_Newline()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
AcceptsReturn = true
|
|
};
|
|
|
|
RaiseKeyEvent(target, Key.Enter, 0);
|
|
|
|
Assert.Equal(Environment.NewLine, target.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Press_Enter_Add_Custom_Newline()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
AcceptsReturn = true,
|
|
NewLine = "Test"
|
|
};
|
|
|
|
RaiseKeyEvent(target, Key.Enter, 0);
|
|
|
|
Assert.Equal("Test", target.Text);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(new object[] { false, TextWrapping.NoWrap, ScrollBarVisibility.Hidden })]
|
|
[InlineData(new object[] { false, TextWrapping.Wrap, ScrollBarVisibility.Hidden })]
|
|
[InlineData(new object[] { true, TextWrapping.NoWrap, ScrollBarVisibility.Auto })]
|
|
[InlineData(new object[] { true, TextWrapping.Wrap, ScrollBarVisibility.Disabled })]
|
|
public void Has_Correct_Horizontal_ScrollBar_Visibility(
|
|
bool acceptsReturn,
|
|
TextWrapping wrapping,
|
|
ScrollBarVisibility expected)
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
AcceptsReturn = acceptsReturn,
|
|
TextWrapping = wrapping,
|
|
};
|
|
|
|
Assert.Equal(expected, ScrollViewer.GetHorizontalScrollBarVisibility(target));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SelectionEnd_Doesnt_Cause_Exception()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
Text = "0123456789"
|
|
};
|
|
|
|
target.SelectionStart = 0;
|
|
target.SelectionEnd = 9;
|
|
|
|
target.Text = "123";
|
|
|
|
RaiseTextEvent(target, "456");
|
|
|
|
Assert.True(true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SelectionStart_Doesnt_Cause_Exception()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
Text = "0123456789"
|
|
};
|
|
|
|
target.SelectionStart = 8;
|
|
target.SelectionEnd = 9;
|
|
|
|
target.Text = "123";
|
|
|
|
RaiseTextEvent(target, "456");
|
|
|
|
Assert.True(true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SelectionStartEnd_Are_Valid_AterTextChange()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
Text = "0123456789"
|
|
};
|
|
|
|
target.SelectionStart = 8;
|
|
target.SelectionEnd = 9;
|
|
|
|
target.Text = "123";
|
|
|
|
Assert.True(target.SelectionStart <= "123".Length);
|
|
Assert.True(target.SelectionEnd <= "123".Length);
|
|
}
|
|
}
|
|
[Fact]
|
|
public void CoerceCaretIndex_Doesnt_Cause_Exception_with_malformed_line_ending()
|
|
{
|
|
using (UnitTestApplication.Start(Services))
|
|
{
|
|
var target = new TextBox
|
|
{
|
|
Template = CreateTemplate(),
|
|
Text = "0123456789\r"
|
|
};
|
|
target.CaretIndex = 11;
|
|
|
|
Assert.True(true);
|
|
}
|
|
}
|
|
|
|
private static TestServices Services => TestServices.MockThreadingInterface.With(
|
|
standardCursorFactory: Mock.Of<IStandardCursorFactory>());
|
|
|
|
private IControlTemplate CreateTemplate()
|
|
{
|
|
return new FuncControlTemplate<TextBox>(control =>
|
|
new TextPresenter
|
|
{
|
|
Name = "PART_TextPresenter",
|
|
[!!TextPresenter.TextProperty] = new Binding
|
|
{
|
|
Path = "Text",
|
|
Mode = BindingMode.TwoWay,
|
|
Priority = BindingPriority.TemplatedParent,
|
|
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
|
|
},
|
|
});
|
|
}
|
|
|
|
private void RaiseKeyEvent(TextBox textBox, Key key, InputModifiers inputModifiers)
|
|
{
|
|
textBox.RaiseEvent(new KeyEventArgs
|
|
{
|
|
RoutedEvent = InputElement.KeyDownEvent,
|
|
Modifiers = inputModifiers,
|
|
Key = key
|
|
});
|
|
}
|
|
|
|
private void RaiseTextEvent(TextBox textBox, string text)
|
|
{
|
|
textBox.RaiseEvent(new TextInputEventArgs
|
|
{
|
|
RoutedEvent = InputElement.TextInputEvent,
|
|
Text = text
|
|
});
|
|
}
|
|
|
|
private class Class1 : NotifyingBase
|
|
{
|
|
private int _foo;
|
|
|
|
public int Foo
|
|
{
|
|
get { return _foo; }
|
|
set { _foo = value; RaisePropertyChanged(); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|