diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Richedit/Interop.EDITSTREAM.cs b/src/System.Windows.Forms.Primitives/src/Interop/Richedit/Interop.EDITSTREAM.cs new file mode 100644 index 00000000000..b15cf71481f --- /dev/null +++ b/src/System.Windows.Forms.Primitives/src/Interop/Richedit/Interop.EDITSTREAM.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal static partial class Richedit + { + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct EDITSTREAM + { + public UIntPtr dwCookie; + public uint dwError; + public IntPtr pfnCallback; + } + } +} diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Richedit/Interop.EDITSTREAMCALLBACK.cs b/src/System.Windows.Forms.Primitives/src/Interop/Richedit/Interop.EDITSTREAMCALLBACK.cs new file mode 100644 index 00000000000..15bf8c6b998 --- /dev/null +++ b/src/System.Windows.Forms.Primitives/src/Interop/Richedit/Interop.EDITSTREAMCALLBACK.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +internal partial class Interop +{ + internal static partial class Richedit + { + public delegate int EDITSTREAMCALLBACK(IntPtr dwCookie, IntPtr pbBuff, int cb, out int pcb); + } +} diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Richedit/Interop.SF.cs b/src/System.Windows.Forms.Primitives/src/Interop/Richedit/Interop.SF.cs new file mode 100644 index 00000000000..f9f02d88b32 --- /dev/null +++ b/src/System.Windows.Forms.Primitives/src/Interop/Richedit/Interop.SF.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +internal partial class Interop +{ + internal static partial class Richedit + { + [Flags] + public enum SF : uint + { + TEXT = 0x0001, + RTF = 0x0002, + RTFNOOBJS = 0x0003, + TEXTIZED = 0x0004, + UNICODE = 0x0010, + USECODEPAGE = 0x0020, + NCRFORNONASCII = 0x0040, + RTFVAL = 0x0700, + F_PWD = 0x0800, + F_KEEPDOCINFO = 0x1000, + F_PERSISTVIEWSCALE = 0x2000, + F_PLAINRTF = 0x4000, + F_SELECTION = 0x8000, + } + } +} diff --git a/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/NativeMethods.cs b/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/NativeMethods.cs index c46d8491aa3..217c8e218ac 100644 --- a/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/NativeMethods.cs +++ b/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/NativeMethods.cs @@ -181,23 +181,6 @@ public class HH_FTS_QUERY internal string pszWindow = null; } - public delegate int EditStreamCallback(IntPtr dwCookie, IntPtr buf, int cb, out int transferred); - - [StructLayout(LayoutKind.Sequential)] - public class EDITSTREAM - { - public IntPtr dwCookie = IntPtr.Zero; - public int dwError = 0; - public EditStreamCallback pfnCallback = null; - } - - [StructLayout(LayoutKind.Sequential)] - public class EDITSTREAM64 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public byte[] contents = new byte[20]; - } - public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); public delegate int ListViewCompareCallback(IntPtr lParam1, IntPtr lParam2, IntPtr lParamSort); diff --git a/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/UnsafeNativeMethods.cs b/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/UnsafeNativeMethods.cs index 3649a7f6f2d..44ddab7d58f 100644 --- a/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/UnsafeNativeMethods.cs +++ b/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/UnsafeNativeMethods.cs @@ -83,12 +83,6 @@ public static StringBuilder GetModuleFileNameLongPath(HandleRef hModule) [DllImport(ExternDll.User32, CharSet = CharSet.Auto)] public static extern int SendMessage(HandleRef hWnd, int msg, int wParam, [Out, MarshalAs(UnmanagedType.IUnknown)]out object editOle); - [DllImport(ExternDll.User32, CharSet = CharSet.Auto)] - public static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, NativeMethods.EDITSTREAM lParam); - - [DllImport(ExternDll.User32, CharSet = CharSet.Auto)] - public static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, NativeMethods.EDITSTREAM64 lParam); - [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)] public static extern int GetDlgItemInt(IntPtr hWnd, int nIDDlgItem, bool[] err, bool signed); diff --git a/src/System.Windows.Forms.Primitives/tests/Interop/Richedit/EDITSTREAMTests.cs b/src/System.Windows.Forms.Primitives/tests/Interop/Richedit/EDITSTREAMTests.cs new file mode 100644 index 00000000000..deeb232417c --- /dev/null +++ b/src/System.Windows.Forms.Primitives/tests/Interop/Richedit/EDITSTREAMTests.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; +using static Interop.Richedit; + +namespace System.Windows.Forms.Tests.Interop.Richedit +{ + public class EDITSTREAMTests : IClassFixture + { + [WinFormsFact] + public unsafe void EditStream_Size_Get_ReturnsExpected() + { + if (IntPtr.Size == 4) + { + Assert.Equal(12, sizeof(EDITSTREAM)); + } + else + { + Assert.Equal(20, sizeof(EDITSTREAM)); + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBox.cs b/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBox.cs index 4595cbd106b..4729fe936a5 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBox.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBox.cs @@ -703,12 +703,12 @@ public string Rtf { if (IsHandleCreated) { - return StreamOut(RichTextBoxConstants.SF_RTF); + return StreamOut(SF.RTF); } else if (textPlain != null) { ForceHandleCreate(); - return StreamOut(RichTextBoxConstants.SF_RTF); + return StreamOut(SF.RTF); } else { @@ -729,7 +729,7 @@ public string Rtf ForceHandleCreate(); textRtf = value; - StreamIn(value, RichTextBoxConstants.SF_RTF); + StreamIn(value, SF.RTF); if (CanRaiseTextChangedEvent) { OnTextChanged(EventArgs.Empty); @@ -1267,7 +1267,7 @@ public string SelectedRtf get { ForceHandleCreate(); - return StreamOut(RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_RTF); + return StreamOut(SF.F_SELECTION | SF.RTF); } set { @@ -1277,7 +1277,7 @@ public string SelectedRtf value = string.Empty; } - StreamIn(value, RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_RTF); + StreamIn(value, SF.F_SELECTION | SF.RTF); } } @@ -1417,13 +1417,13 @@ public override string SelectedText { ForceHandleCreate(); - string text = StreamOut(RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE); + string text = StreamOut(SF.F_SELECTION | SF.TEXT | SF.UNICODE); return text; } set { ForceHandleCreate(); - StreamIn(value, RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE); + StreamIn(value, SF.F_SELECTION | SF.TEXT | SF.UNICODE); } } @@ -1522,7 +1522,7 @@ public override string Text // ForceHandleCreate(); - return StreamOut(RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE); + return StreamOut(SF.TEXT | SF.UNICODE); } } set @@ -1541,7 +1541,7 @@ public override string Text { value = string.Empty; } - StreamIn(value, RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE); + StreamIn(value, SF.TEXT | SF.UNICODE); // reset Modified User32.SendMessageW(this, (User32.WM)User32.EM.SETMODIFY); } @@ -2501,24 +2501,27 @@ public void LoadFile(string path, RichTextBoxStreamType fileType) /// public void LoadFile(Stream data, RichTextBoxStreamType fileType) { - //valid values are 0x0 to 0x4 + if (data == null) + { + throw new ArgumentNullException(nameof(data)); + } if (!ClientUtils.IsEnumValid(fileType, (int)fileType, (int)RichTextBoxStreamType.RichText, (int)RichTextBoxStreamType.UnicodePlainText)) { throw new InvalidEnumArgumentException(nameof(fileType), (int)fileType, typeof(RichTextBoxStreamType)); } - int flags; + SF flags; switch (fileType) { case RichTextBoxStreamType.RichText: - flags = RichTextBoxConstants.SF_RTF; + flags = SF.RTF; break; case RichTextBoxStreamType.PlainText: Rtf = string.Empty; - flags = RichTextBoxConstants.SF_TEXT; + flags = SF.TEXT; break; case RichTextBoxStreamType.UnicodePlainText: - flags = RichTextBoxConstants.SF_UNICODE | RichTextBoxConstants.SF_TEXT; + flags = SF.UNICODE | SF.TEXT; break; default: throw new ArgumentException(SR.InvalidFileType); @@ -2816,23 +2819,23 @@ public void SaveFile(string path, RichTextBoxStreamType fileType) /// public void SaveFile(Stream data, RichTextBoxStreamType fileType) { - int flags; + SF flags; switch (fileType) { case RichTextBoxStreamType.RichText: - flags = RichTextBoxConstants.SF_RTF; + flags = SF.RTF; break; case RichTextBoxStreamType.PlainText: - flags = RichTextBoxConstants.SF_TEXT; + flags = SF.TEXT; break; case RichTextBoxStreamType.UnicodePlainText: - flags = RichTextBoxConstants.SF_UNICODE | RichTextBoxConstants.SF_TEXT; + flags = SF.UNICODE | SF.TEXT; break; case RichTextBoxStreamType.RichNoOleObjs: - flags = RichTextBoxConstants.SF_RTFNOOBJS; + flags = SF.RTFNOOBJS; break; case RichTextBoxStreamType.TextTextOleObjs: - flags = RichTextBoxConstants.SF_TEXTIZED; + flags = SF.TEXTIZED; break; default: throw new InvalidEnumArgumentException(nameof(fileType), (int)fileType, typeof(RichTextBoxStreamType)); @@ -2984,12 +2987,12 @@ private static int Twip2Pixel(IntPtr hDC, int v, bool xDirection) return (int)(((((double)v) / 20.0) / 72.0) * logP); } - private void StreamIn(string str, int flags) + private void StreamIn(string str, SF flags) { if (str.Length == 0) { // Destroy the selection if callers was setting selection text - if ((RichTextBoxConstants.SFF_SELECTION & flags) != 0) + if ((SF.F_SELECTION & flags) != 0) { User32.SendMessageW(this, User32.WM.CLEAR); ProtectedError = false; @@ -3011,7 +3014,7 @@ private void StreamIn(string str, int flags) // get the string into a byte array byte[] encodedBytes; - if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) + if ((flags & SF.UNICODE) != 0) { encodedBytes = Encoding.Unicode.GetBytes(str); } @@ -3025,10 +3028,10 @@ private void StreamIn(string str, int flags) StreamIn(editStream, flags); } - private void StreamIn(Stream data, int flags) + private void StreamIn(Stream data, SF flags) { // clear out the selection only if we are replacing all the text - if ((flags & RichTextBoxConstants.SFF_SELECTION) == 0) + if ((flags & SF.F_SELECTION) == 0) { var cr = new Richedit.CHARRANGE(); User32.SendMessageW(this, (User32.WM)RichEditMessages.EM_EXSETSEL, IntPtr.Zero, ref cr); @@ -3042,7 +3045,7 @@ private void StreamIn(Stream data, int flags) // If SF_RTF is requested then check for the RTF tag at the start // of the file. We don't load if the tag is not there // - if ((flags & RichTextBoxConstants.SF_RTF) != 0) + if ((flags & SF.RTF) != 0) { long streamStart = editStream.Position; byte[] bytes = new byte[SZ_RTF_TAG.Length]; @@ -3059,8 +3062,8 @@ private void StreamIn(Stream data, int flags) int cookieVal = 0; // set up structure to do stream operation - NativeMethods.EDITSTREAM es = new NativeMethods.EDITSTREAM(); - if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) + var es = new EDITSTREAM(); + if ((flags & SF.UNICODE) != 0) { cookieVal = INPUT | UNICODE; } @@ -3068,7 +3071,7 @@ private void StreamIn(Stream data, int flags) { cookieVal = INPUT | ANSI; } - if ((flags & RichTextBoxConstants.SF_RTF) != 0) + if ((flags & SF.RTF) != 0) { cookieVal |= RTF; } @@ -3076,27 +3079,17 @@ private void StreamIn(Stream data, int flags) { cookieVal |= TEXTLF; } - es.dwCookie = (IntPtr)cookieVal; - es.pfnCallback = new NativeMethods.EditStreamCallback(EditStreamProc); + es.dwCookie = (UIntPtr)cookieVal; + var callback = new EDITSTREAMCALLBACK(EditStreamProc); + es.pfnCallback = Marshal.GetFunctionPointerForDelegate(callback); // gives us TextBox compatible behavior, programatic text change shouldn't // be limited... User32.SendMessageW(this, (User32.WM)RichEditMessages.EM_EXLIMITTEXT, IntPtr.Zero, (IntPtr)int.MaxValue); // go get the text for the control - // Needed for 64-bit - if (IntPtr.Size == 8) - { - NativeMethods.EDITSTREAM64 es64 = ConvertToEDITSTREAM64(es); - UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichEditMessages.EM_STREAMIN, flags, es64); - - //Assign back dwError value - es.dwError = GetErrorValue64(es64); - } - else - { - UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichEditMessages.EM_STREAMIN, flags, es); - } + User32.SendMessageW(this, (User32.WM)RichEditMessages.EM_STREAMIN, (IntPtr)flags, ref es); + GC.KeepAlive(callback); UpdateMaxLength(); @@ -3126,7 +3119,7 @@ private void StreamIn(Stream data, int flags) } } - private string StreamOut(int flags) + private string StreamOut(SF flags) { Stream stream = new MemoryStream(); StreamOut(stream, flags, false); @@ -3139,7 +3132,7 @@ private string StreamOut(int flags) byte[] bytes = new byte[streamLength]; stream.Read(bytes, 0, streamLength); - if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) + if ((flags & SF.UNICODE) != 0) { result = Encoding.Unicode.GetString(bytes, 0, bytes.Length); } @@ -3158,17 +3151,16 @@ private string StreamOut(int flags) return result; } - private void StreamOut(Stream data, int flags, bool includeCrLfs) + private void StreamOut(Stream data, SF flags, bool includeCrLfs) { // set up the EDITSTREAM structure for the callback. - Debug.Assert(data != null, "StreamOut passed a null stream"); editStream = data; try { int cookieVal = 0; - NativeMethods.EDITSTREAM es = new NativeMethods.EDITSTREAM(); - if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) + var es = new EDITSTREAM(); + if ((flags & SF.UNICODE) != 0) { cookieVal = OUTPUT | UNICODE; } @@ -3176,7 +3168,7 @@ private void StreamOut(Stream data, int flags, bool includeCrLfs) { cookieVal = OUTPUT | ANSI; } - if ((flags & RichTextBoxConstants.SF_RTF) != 0) + if ((flags & SF.RTF) != 0) { cookieVal |= RTF; } @@ -3191,23 +3183,13 @@ private void StreamOut(Stream data, int flags, bool includeCrLfs) cookieVal |= TEXTLF; } } - es.dwCookie = (IntPtr)cookieVal; - es.pfnCallback = new NativeMethods.EditStreamCallback(EditStreamProc); + es.dwCookie = (UIntPtr)cookieVal; + var callback = new EDITSTREAMCALLBACK(EditStreamProc); + es.pfnCallback = Marshal.GetFunctionPointerForDelegate(callback); // Get Text - // Needed for 64-bit - if (IntPtr.Size == 8) - { - NativeMethods.EDITSTREAM64 es64 = ConvertToEDITSTREAM64(es); - UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichEditMessages.EM_STREAMOUT, flags, es64); - - //Assign back dwError value - es.dwError = GetErrorValue64(es64); - } - else - { - UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichEditMessages.EM_STREAMOUT, flags, es); - } + User32.SendMessageW(this, (User32.WM)RichEditMessages.EM_STREAMOUT, (IntPtr)flags, ref es); + GC.KeepAlive(callback); // check to make sure things went well if (es.dwError != 0) @@ -3222,41 +3204,6 @@ private void StreamOut(Stream data, int flags, bool includeCrLfs) } } - private unsafe NativeMethods.EDITSTREAM64 ConvertToEDITSTREAM64(NativeMethods.EDITSTREAM es) - { - NativeMethods.EDITSTREAM64 es64 = new NativeMethods.EDITSTREAM64(); - - fixed (byte* es64p = &es64.contents[0]) - { - byte* bp; - long l; - - *((long*)es64p) = (long)es.dwCookie; - *((int*)(es64p + 8)) = es.dwError; - - l = (long)Marshal.GetFunctionPointerForDelegate(es.pfnCallback); - bp = (byte*)&l; - for (int i = 0; i < sizeof(long); i++) - { - es64.contents[i + 12] = bp[i]; - } - } - - return es64; - } - - private unsafe int GetErrorValue64(NativeMethods.EDITSTREAM64 es64) - { - int errorVal; - - fixed (byte* es64p = &es64.contents[0]) - { - errorVal = *((int*)(es64p + 8)); - } - - return errorVal; - } - private void UpdateOleCallback() { Debug.WriteLineIf(RichTextDbg.TraceVerbose, "update ole callback (" + AllowDrop + ")"); @@ -3528,8 +3475,7 @@ internal unsafe void WmReflectNotify(ref Message m) case RichEditMessages.EM_STREAMIN: // Don't allow STREAMIN to replace protected selection - // - if ((unchecked((int)(long)enprotected.wParam) & RichTextBoxConstants.SFF_SELECTION) != 0) + if ((unchecked((SF)(long)enprotected.wParam) & SF.F_SELECTION) != 0) { break; } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBoxConstants.cs b/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBoxConstants.cs index 5264e60a72a..f999f476d61 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBoxConstants.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBoxConstants.cs @@ -208,23 +208,6 @@ internal static class RichTextBoxConstants internal const int cchTextLimitDefault = 32767; - /* stream formats */ - internal const int SF_TEXT = 0x0001; - internal const int SF_RTF = 0x0002; - internal const int SF_RTFNOOBJS = 0x0003; /* outbound only */ - internal const int SF_TEXTIZED = 0x0004; /* outbound only */ - internal const int SF_UNICODE = 0x0010; /* Unicode file of some kind */ - - /* Flag telling stream operations to operate on the selection only */ - /* EM_STREAMIN will replace the current selection */ - /* EM_STREAMOUT will stream out the current selection */ - internal const int SFF_SELECTION = 0x8000; - - /* Flag telling stream operations to operate on the common RTF keyword only */ - /* EM_STREAMIN will accept the only common RTF keyword */ - /* EM_STREAMOUT will stream out the only common RTF keyword */ - internal const int SFF_PLAINRTF = 0x4000; - /* all paragraph measurements are in twips */ internal const int lDefaultTab = 720; diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs index 3edd54c7b23..4ba64c02b54 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; +using System.IO; +using System.Text; using WinForms.Common.Tests; using Xunit; using static Interop; @@ -987,21 +989,57 @@ public void RichTextBox_RightMargin_SetNegative_ThrowsArgumentOutOfRangeExceptio } [WinFormsFact] - public void RichTextBox_SelectedText_GetWithoutHandle_ReturnsExpected() + public void RichTextBox_Rtf_GetWithHandle_ReturnsExpected() { using var control = new RichTextBox(); - Assert.Empty(control.SelectedText); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + string rtf1 = control.Rtf; + Assert.StartsWith("{\\rtf", rtf1); Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); // Get again. - Assert.Empty(control.SelectedText); + string rtf2 = control.Rtf; + Assert.Equal(rtf1, rtf2); + Assert.NotSame(rtf1, rtf2); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_SelectedText_GetWithHandle_ReturnsExpected() + public void RichTextBox_Rtf_GetWithPlainText_ReturnsExpected() { - using var control = new RichTextBox(); + using var control = new RichTextBox + { + Text = "Text" + }; + string rtf1 = control.Rtf; + Assert.Contains("Text", rtf1); + Assert.StartsWith("{\\rtf", rtf1); + Assert.True(control.IsHandleCreated); + + // Get again. + string rtf2 = control.Rtf; + Assert.Equal(rtf1, rtf2); + Assert.NotSame(rtf1, rtf2); + Assert.True(control.IsHandleCreated); + } + + [WinFormsFact] + public void RichTextBox_Rtf_GetWithPlainTextWithHandle_ReturnsExpected() + { + using var control = new RichTextBox + { + Text = "Text" + }; Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -1010,34 +1048,49 @@ public void RichTextBox_SelectedText_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Empty(control.SelectedText); + string rtf1 = control.Rtf; + Assert.Contains("Text", rtf1); + Assert.StartsWith("{\\rtf", rtf1); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); // Get again. - Assert.Empty(control.SelectedText); + string rtf2 = control.Rtf; + Assert.Equal(rtf1, rtf2); + Assert.NotSame(rtf1, rtf2); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsFact] - public void RichTextBox_SelectedRtf_GetWithoutHandle_ReturnsExpected() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetNullOrEmptyStringTheoryData))] + public void RichTextBox_Rtf_Set_GetReturnsExpected(string nullOrEmpty) { - using var control = new RichTextBox(); - Assert.NotNull(control.SelectedRtf); + using var control = new RichTextBox + { + Rtf = "{\\rtf1Hello World}" + }; + + string rtf = control.Rtf; + Assert.StartsWith("{\\rtf", rtf); + Assert.NotSame(rtf, control.Rtf); + Assert.Equal("Hello World", control.Text); Assert.True(control.IsHandleCreated); - // Call again. - Assert.NotNull(control.SelectedRtf); + control.Rtf = nullOrEmpty; + rtf = control.Rtf; + Assert.StartsWith("{\\rtf", rtf); + Assert.Empty(control.Text); Assert.True(control.IsHandleCreated); } - [WinFormsFact] - public void RichTextBox_SelectedRtf_GetWithHandle_ReturnsExpected() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetNullOrEmptyStringTheoryData))] + public void RichTextBox_Rtf_SetWithHandle_GetReturnsExpected(string nullOrEmpty) { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1048,14 +1101,20 @@ public void RichTextBox_SelectedRtf_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.NotNull(control.SelectedRtf); + control.Rtf = "{\\rtf1Hello World}"; + string rtf = control.Rtf; + Assert.StartsWith("{\\rtf", rtf); + Assert.NotSame(rtf, control.Rtf); + Assert.Equal("Hello World", control.Text); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Call again. - Assert.NotNull(control.SelectedRtf); + control.Rtf = nullOrEmpty; + rtf = control.Rtf; + Assert.StartsWith("{\\rtf", rtf); + Assert.Empty(control.Text); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -1063,19 +1122,42 @@ public void RichTextBox_SelectedRtf_GetWithHandle_ReturnsExpected() } [WinFormsFact] - public void RichTextBox_SelectionAlignment_GetWithoutHandle_ReturnsExpected() + public void RichTextBox_Rtf_SetWithHandler_CallsTextChanged() { using var control = new RichTextBox(); - Assert.Equal(HorizontalAlignment.Left, control.SelectionAlignment); - Assert.True(control.IsHandleCreated); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Equal(EventArgs.Empty, e); + callCount++; + }; + control.TextChanged += handler; - // Call again. - Assert.Equal(HorizontalAlignment.Left, control.SelectionAlignment); - Assert.True(control.IsHandleCreated); + // Set different. + control.Rtf = "{\\rtf1text}"; + Assert.Equal("text", control.Text); + Assert.Equal(2, callCount); + + // Set same. + control.Rtf = "{\\rtf1text}"; + Assert.Equal("text", control.Text); + Assert.Equal(4, callCount); + + // Set different. + control.Text = null; + Assert.Empty(control.Text); + Assert.Equal(5, callCount); + + // Remove handler. + control.TextChanged -= handler; + control.Rtf = "{\\rtf1text}"; + Assert.Equal("text", control.Text); + Assert.Equal(5, callCount); } [WinFormsFact] - public void RichTextBox_SelectionAlignment_GetWithHandle_ReturnsExpected() + public void RichTextBox_Rtf_SetWithHandlerWithHandle_CallsTextChanged() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1086,14 +1168,47 @@ public void RichTextBox_SelectionAlignment_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(HorizontalAlignment.Left, control.SelectionAlignment); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Equal(EventArgs.Empty, e); + callCount++; + }; + control.TextChanged += handler; + + // Set different. + control.Rtf = "{\\rtf1text}"; + Assert.Equal("text", control.Text); + Assert.Equal(2, callCount); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Call again. - Assert.Equal(HorizontalAlignment.Left, control.SelectionAlignment); + // Set same. + control.Rtf = "{\\rtf1text}"; + Assert.Equal("text", control.Text); + Assert.Equal(4, callCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set different. + control.Rtf = null; + Assert.Empty(control.Text); + Assert.Equal(6, callCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Remove handler. + control.TextChanged -= handler; + control.Rtf = "{\\rtf1text}"; + Assert.Equal("text", control.Text); + Assert.Equal(6, callCount); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -1101,19 +1216,31 @@ public void RichTextBox_SelectionAlignment_GetWithHandle_ReturnsExpected() } [WinFormsFact] - public void RichTextBox_SelectionBullet_GetWithoutHandle_ReturnsExpected() + public void RichTextBox_Rtf_SetInvalidValue_ThrowsArgumentException() { using var control = new RichTextBox(); - Assert.False(control.SelectionBullet); + Assert.Throws(null, () => control.Rtf = "text"); Assert.True(control.IsHandleCreated); + Assert.DoesNotContain("text", control.Rtf); + Assert.Empty(control.Text); + } - // Call again. - Assert.False(control.SelectionBullet); + [WinFormsFact] + public void RichTextBox_SelectedRtf_Get_ReturnsExpected() + { + using var control = new RichTextBox(); + string rtf1 = control.SelectedRtf; + Assert.Empty(rtf1); + Assert.True(control.IsHandleCreated); + + // Get again. + string rtf2 = control.SelectedRtf; + Assert.Equal(rtf1, rtf2); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_SelectionBullet_GetWithHandle_ReturnsExpected() + public void RichTextBox_SelectedRtf_GetWithHandle_ReturnsExpected() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1124,14 +1251,16 @@ public void RichTextBox_SelectionBullet_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.False(control.SelectionBullet); + string rtf1 = control.SelectedRtf; + Assert.Empty(rtf1); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Call again. - Assert.False(control.SelectionBullet); + // Get again. + string rtf2 = control.SelectedRtf; + Assert.Equal(rtf1, rtf2); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -1139,21 +1268,31 @@ public void RichTextBox_SelectionBullet_GetWithHandle_ReturnsExpected() } [WinFormsFact] - public void RichTextBox_SelectionCharOffset_GetWithoutHandle_ReturnsExpected() + public void RichTextBox_SelectedRtf_GetWithPlainText_ReturnsExpected() { - using var control = new RichTextBox(); - Assert.Equal(0, control.SelectionCharOffset); + using var control = new RichTextBox + { + Text = "Text", + SelectedText = "ex" + }; + string rtf1 = control.SelectedRtf; + Assert.Empty(rtf1); Assert.True(control.IsHandleCreated); - // Call again. - Assert.Equal(0, control.SelectionCharOffset); + // Get again. + string rtf2 = control.SelectedRtf; + Assert.Equal(rtf1, rtf2); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_SelectionCharOffset_GetWithHandle_ReturnsExpected() + public void RichTextBox_SelectedRtf_GetWithPlainTextWithHandle_ReturnsExpected() { - using var control = new RichTextBox(); + using var control = new RichTextBox + { + Text = "Text", + SelectedText = "ex" + }; Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -1162,84 +1301,106 @@ public void RichTextBox_SelectionCharOffset_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(0, control.SelectionCharOffset); + string rtf1 = control.SelectedRtf; + Assert.Empty(rtf1); + Assert.DoesNotContain("ex", rtf1); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Call again. - Assert.Equal(0, control.SelectionCharOffset); + // Get again. + string rtf2 = control.SelectedRtf; + Assert.Equal(rtf1, rtf2); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable SelectionCharOffset_CustomGetCharFormat_TestData() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetNullOrEmptyStringTheoryData))] + public void RichTextBox_SelectedRtf_Set_GetReturnsExpected(string nullOrEmpty) { - yield return new object[] { CFM.OFFSET, 0, 0 }; - yield return new object[] { CFM.OFFSET, 900, 60 }; - yield return new object[] { CFM.OFFSET, 30000, 2000 }; - yield return new object[] { CFM.OFFSET, 60000, 4000 }; - yield return new object[] { CFM.OFFSET, -900, -60 }; + using var control = new RichTextBox + { + SelectedRtf = "{\\rtf1Hell}" + }; - yield return new object[] { 0, 0, 0 }; - yield return new object[] { 0, 900, 60 }; - yield return new object[] { 0, 30000, 2000 }; - yield return new object[] { 0, 60000, 4000 }; - yield return new object[] { 0, -900, -60 }; + string rtf = control.SelectedRtf; + Assert.Empty(rtf); + Assert.Empty(control.SelectedText); + Assert.True(control.IsHandleCreated); + + control.SelectedRtf = nullOrEmpty; + rtf = control.SelectedRtf; + Assert.Empty(rtf); + Assert.Empty(control.SelectedText); + Assert.True(control.IsHandleCreated); } [WinFormsTheory] - [MemberData(nameof(SelectionCharOffset_CustomGetCharFormat_TestData))] - public void RichTextBox_SelectionCharOffset_CustomGetCharFormat_Success(uint mask, int yOffset, int expected) + [CommonMemberData(nameof(CommonTestHelper.GetNullOrEmptyStringTheoryData))] + public void RichTextBox_SelectedRtf_SetWithHandle_GetReturnsExpected(string nullOrEmpty) { - using var control = new CustomGetCharFormatRichTextBox - { - ExpectedWParam = (IntPtr)SCF.SELECTION, - GetCharFormatResult = new CHARFORMATW - { - dwMask = (CFM)mask, - yOffset = yOffset - } - }; - + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); - control.MakeCustom = true; - Assert.Equal(expected, control.SelectionCharOffset); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.SelectedRtf = "{\\rtf1Hell}"; + string rtf = control.SelectedRtf; + Assert.Empty(rtf); + Assert.Empty(control.SelectedText); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + control.SelectedRtf = nullOrEmpty; + rtf = control.SelectedRtf; + Assert.Empty(rtf); + Assert.Empty(control.SelectedText); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } [WinFormsTheory] - [InlineData(2000)] - [InlineData(10)] - [InlineData(0)] - [InlineData(-10)] - [InlineData(-2000)] - public void RichTextBox_SelectionCharOffset_Set_GetReturnsExpected(int value) + [CommonMemberData(nameof(CommonTestHelper.GetNullOrEmptyStringTheoryData))] + public void RichTextBox_SelectedRtf_SetWithRtf_GetReturnsExpected(string nullOrEmpty) { using var control = new RichTextBox { - SelectionCharOffset = value + Rtf = "{\\rtf1Hello World}", + SelectedRtf = "{\\rtf1Hell}" }; - Assert.Equal(value, control.SelectionCharOffset); + + string rtf = control.SelectedRtf; + Assert.Empty(rtf); + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); - // Set same. - control.SelectionCharOffset = value; - Assert.Equal(value, control.SelectionCharOffset); + control.SelectedRtf = nullOrEmpty; + rtf = control.SelectedRtf; + Assert.Empty(rtf); + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); } [WinFormsTheory] - [InlineData(2000)] - [InlineData(10)] - [InlineData(0)] - [InlineData(-10)] - [InlineData(-2000)] - public void RichTextBox_SelectionCharOffset_SetWithHandle_GetReturnsExpected(int value) + [CommonMemberData(nameof(CommonTestHelper.GetNullOrEmptyStringTheoryData))] + public void RichTextBox_SelectedRtf_SetWithRtfWithHandle_GetReturnsExpected(string nullOrEmpty) { - using var control = new RichTextBox(); + using var control = new RichTextBox + { + Rtf = "{\\rtf1Hello World}" + }; Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -1248,16 +1409,19 @@ public void RichTextBox_SelectionCharOffset_SetWithHandle_GetReturnsExpected(int int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - control.SelectionCharOffset = value; - Assert.Equal(value, control.SelectionCharOffset); + control.SelectedRtf = "{\\rtf1Hell}"; + string rtf = control.SelectedRtf; + Assert.Empty(rtf); + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Set same. - control.SelectionCharOffset = value; - Assert.Equal(value, control.SelectionCharOffset); + control.SelectedRtf = nullOrEmpty; + rtf = control.SelectedRtf; + Assert.Empty(rtf); + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -1265,43 +1429,31 @@ public void RichTextBox_SelectionCharOffset_SetWithHandle_GetReturnsExpected(int } [WinFormsFact] - public unsafe void RichTextBox_SelectionCharOffset_GetCharFormat_Success() - { - using var control = new RichTextBox(); - - Assert.NotEqual(IntPtr.Zero, control.Handle); - control.SelectionCharOffset = 60; - var format = new CHARFORMATW - { - cbSize = (uint)sizeof(CHARFORMATW) - }; - Assert.NotEqual(IntPtr.Zero, User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_GETCHARFORMAT, (IntPtr)SCF.SELECTION, ref format)); - Assert.Equal(900, format.yOffset); - } - - [WinFormsTheory] - [InlineData(2001)] - [InlineData(-20001)] - public void RichTextBox_SelectionCharOffset_SetInvalidValue_ThrowsArgumentOutOfRangeException(int value) + public void RichTextBox_SelectedRtf_SetInvalidValue_ThrowsArgumentException() { using var control = new RichTextBox(); - Assert.Throws("value", () => control.SelectionCharOffset = value); + Assert.Throws(null, () => control.SelectedRtf = "text"); + Assert.True(control.IsHandleCreated); + Assert.DoesNotContain("text", control.Rtf); + Assert.Empty(control.Text); } [WinFormsFact] - public void RichTextBox_SelectionColor_GetWithoutHandle_ReturnsExpected() + public void RichTextBox_SelectedText_Get_ReturnsExpected() { using var control = new RichTextBox(); - Assert.Equal(Color.Black, control.SelectionColor); + string text1 = control.SelectedText; + Assert.Empty(text1); Assert.True(control.IsHandleCreated); - // Call again. - Assert.Equal(Color.Black, control.SelectionColor); + // Get again. + string text2 = control.SelectedText; + Assert.Equal(text1, text2); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_SelectionColor_GetWithHandle_ReturnsExpected() + public void RichTextBox_SelectedText_GetWithHandle_ReturnsExpected() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1312,79 +1464,48 @@ public void RichTextBox_SelectionColor_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(Color.Black, control.SelectionColor); + string text1 = control.SelectedText; + Assert.Empty(text1); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Call again. - Assert.Equal(Color.Black, control.SelectionColor); + // Get again. + string text2 = control.SelectedText; + Assert.Equal(text1, text2); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable SelectionColor_CustomGetCharFormat_TestData() - { - yield return new object[] { CFM.COLOR, 0x785634, Color.FromArgb(0xFF, 0x34, 0x56, 0x78) }; - yield return new object[] { CFM.COLOR, 0x78563412, Color.FromArgb(0xFF, 0x12, 0x34, 0x56) }; - yield return new object[] { CFM.COLOR, 0, Color.Black }; - - yield return new object[] { 0, 0x785634, Color.Empty }; - yield return new object[] { 0, 0x78563412, Color.Empty }; - yield return new object[] { 0, 0, Color.Empty }; - } - - [WinFormsTheory] - [MemberData(nameof(SelectionColor_CustomGetCharFormat_TestData))] - public void RichTextBox_SelectionColor_CustomGetCharFormat_Success(uint mask, int textColor, Color expected) - { - using var control = new CustomGetCharFormatRichTextBox - { - ExpectedWParam = (IntPtr)SCF.SELECTION, - GetCharFormatResult = new CHARFORMATW - { - dwMask = (CFM)mask, - crTextColor = textColor - } - }; - - Assert.NotEqual(IntPtr.Zero, control.Handle); - control.MakeCustom = true; - Assert.Equal(expected, control.SelectionColor); - } - - public static IEnumerable SelectionColor_Set_TestData() - { - yield return new object[] { Color.Empty, Color.Black }; - yield return new object[] { Color.Red, Color.Red }; - yield return new object[] { Color.FromArgb(0x12, 0x34, 0x56, 0x78), Color.FromArgb(0xFF, 0x34, 0x56, 0x78) }; - } - - [WinFormsTheory] - [MemberData(nameof(SelectionColor_Set_TestData))] - public void RichTextBox_SelectionColor_Set_GetReturnsExpected(Color value, Color expected) + [WinFormsFact] + public void RichTextBox_SelectedText_GetWithPlainText_ReturnsExpected() { using var control = new RichTextBox { - SelectionColor = value + Text = "Text", + SelectedText = "ex" }; - Assert.Equal(expected, control.SelectionColor); + string text1 = control.SelectedText; + Assert.Empty(text1); Assert.True(control.IsHandleCreated); - // Set same. - control.SelectionColor = value; - Assert.Equal(expected, control.SelectionColor); + // Get again. + string text2 = control.SelectedText; + Assert.Equal(text1, text2); Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(SelectionColor_Set_TestData))] - public void RichTextBox_SelectionColor_SetWithHandle_GetReturnsExpected(Color value, Color expected) + [WinFormsFact] + public void RichTextBox_SelectedText_GetWithPlainTextWithHandle_ReturnsExpected() { - using var control = new RichTextBox(); + using var control = new RichTextBox + { + Text = "Text", + SelectedText = "ex" + }; Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -1393,54 +1514,42 @@ public void RichTextBox_SelectionColor_SetWithHandle_GetReturnsExpected(Color va int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - control.SelectionColor = value; - Assert.Equal(expected, control.SelectionColor); + string text1 = control.SelectedText; + Assert.Empty(text1); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Set same. - control.SelectionColor = value; - Assert.Equal(expected, control.SelectionColor); + // Get again. + string text2 = control.SelectedText; + Assert.Equal(text1, text2); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsFact] - public unsafe void RichTextBox_SelectionColor_GetCharFormat_Success() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetStringTheoryData))] + public void RichTextBox_SelectedText_Set_GetReturnsExpected(string value) { - using var control = new RichTextBox(); - - Assert.NotEqual(IntPtr.Zero, control.Handle); - control.SelectionColor = Color.FromArgb(0x12, 0x34, 0x56, 0x78); - var format = new CHARFORMATW + using var control = new RichTextBox { - cbSize = (uint)sizeof(CHARFORMATW) + SelectedText = value }; - Assert.NotEqual(IntPtr.Zero, User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_GETCHARFORMAT, (IntPtr)SCF.SELECTION, ref format)); - Assert.Equal(0x785634, format.crTextColor); - } - - [WinFormsFact] - public void RichTextBox_SelectionFont_GetWithoutHandle_ReturnsExpected() - { - using var control = new RichTextBox(); - Font result1 = control.SelectionFont; - Assert.NotNull(result1); + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); - // Call again. - Font result2 = control.SelectionFont; - Assert.NotNull(result2); - Assert.NotSame(result1, result2); + // Set same. + control.SelectedText = value; + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); } - [WinFormsFact] - public void RichTextBox_SelectionFont_GetWithHandle_ReturnsExpected() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetStringTheoryData))] + public void RichTextBox_SelectedText_SetWithHandle_GetReturnsExpected(string value) { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1451,116 +1560,66 @@ public void RichTextBox_SelectionFont_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Font result1 = control.SelectionFont; - Assert.NotNull(result1); + control.SelectedText = value; + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Call again. - Font result2 = control.SelectionFont; - Assert.NotNull(result2); - Assert.NotSame(result1, result2); + // Set same. + control.SelectedText = value; + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable SelectionFont_Set_TestData() - { - yield return new object[] { new Font("Arial", 8.25f), 1 }; - yield return new object[] { new Font("Arial", 8.25f, FontStyle.Bold | FontStyle.Italic | FontStyle.Regular | FontStyle.Strikeout | FontStyle.Underline, GraphicsUnit.Point, 10), 1 }; - } - [WinFormsTheory] - [MemberData(nameof(SelectionFont_Set_TestData))] - public void RichTextBox_SelectionFont_Set_GetReturnsExpected(Font value, byte expectedGdiCharset) + [CommonMemberData(nameof(CommonTestHelper.GetStringTheoryData))] + public void RichTextBox_SelectedText_SetWithRtf_GetReturnsExpected(string value) { using var control = new RichTextBox { - SelectionFont = value + Rtf = "{\\rtf1Hello World}", + SelectedText = value }; - Font result1 = control.SelectionFont; - Assert.NotSame(result1, value); - Assert.Equal(value?.Name, result1.Name); - Assert.Equal(value?.Size, result1.Size); - Assert.Equal(value?.Style, result1.Style); - Assert.Equal(expectedGdiCharset, result1.GdiCharSet); + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); // Set same. - control.SelectionFont = value; - Font result2 = control.SelectionFont; - Assert.Equal(value?.Name, result2.Name); - Assert.Equal(value?.Size, result2.Size); - Assert.Equal(value?.Style, result2.Style); - Assert.Equal(expectedGdiCharset, result2.GdiCharSet); + control.SelectedText = value; + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); } [WinFormsTheory] - [MemberData(nameof(SelectionFont_Set_TestData))] - public void RichTextBox_SelectionFont_SetWithHandle_GetReturnsExpected(Font value, byte expectedGdiCharset) + [CommonMemberData(nameof(CommonTestHelper.GetStringTheoryData))] + public void RichTextBox_SelectedText_SetWithText_GetReturnsExpected(string value) { - using var control = new RichTextBox(); - Assert.NotEqual(IntPtr.Zero, control.Handle); - int invalidatedCallCount = 0; - control.Invalidated += (sender, e) => invalidatedCallCount++; - int styleChangedCallCount = 0; - control.StyleChanged += (sender, e) => styleChangedCallCount++; - int createdCallCount = 0; - control.HandleCreated += (sender, e) => createdCallCount++; - - control.SelectionFont = value; - Font result1 = control.SelectionFont; - Assert.NotSame(result1, value); - Assert.Equal(value?.Name, result1.Name); - Assert.Equal(value?.Size, result1.Size); - Assert.Equal(value?.Style, result1.Style); - Assert.Equal(expectedGdiCharset, result1.GdiCharSet); + using var control = new RichTextBox + { + Text = "Hello World", + SelectedText = value + }; + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); // Set same. - control.SelectionFont = value; - Font result2 = control.SelectionFont; - Assert.Equal(value?.Name, result2.Name); - Assert.Equal(value?.Size, result2.Size); - Assert.Equal(value?.Style, result2.Style); - Assert.Equal(expectedGdiCharset, result2.GdiCharSet); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); - } - - [WinFormsFact] - public void RichTextBox_SelectionFont_SetNull_ThrowsNullReferenceException() - { - using var control = new RichTextBox(); - Assert.Throws(() => control.SelectionFont = null); - } - - [WinFormsFact] - public void RichTextBox_SelectionHangingIndent_GetWithoutHandle_ReturnsExpected() - { - using var control = new RichTextBox(); - Assert.Equal(0, control.SelectionHangingIndent); - Assert.True(control.IsHandleCreated); - - // Call again. - Assert.Equal(0, control.SelectionHangingIndent); + control.SelectedText = value; + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); } - [WinFormsFact] - public void RichTextBox_SelectionHangingIndent_GetWithHandle_ReturnsExpected() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetStringTheoryData))] + public void RichTextBox_SelectedText_SetWithTextWithHandle_GetReturnsExpected(string value) { - using var control = new RichTextBox(); + using var control = new RichTextBox + { + Text = "Hello World" + }; Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -1569,14 +1628,16 @@ public void RichTextBox_SelectionHangingIndent_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(0, control.SelectionHangingIndent); + control.SelectedText = value; + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Call again. - Assert.Equal(0, control.SelectionHangingIndent); + // Set same. + control.SelectedText = value; + Assert.Empty(control.SelectedText); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -1584,19 +1645,19 @@ public void RichTextBox_SelectionHangingIndent_GetWithHandle_ReturnsExpected() } [WinFormsFact] - public void RichTextBox_SelectionIndent_GetWithoutHandle_ReturnsExpected() + public void RichTextBox_SelectionAlignment_GetWithoutHandle_ReturnsExpected() { using var control = new RichTextBox(); - Assert.Equal(0, control.SelectionIndent); + Assert.Equal(HorizontalAlignment.Left, control.SelectionAlignment); Assert.True(control.IsHandleCreated); // Call again. - Assert.Equal(0, control.SelectionIndent); + Assert.Equal(HorizontalAlignment.Left, control.SelectionAlignment); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_SelectionIndent_GetWithHandle_ReturnsExpected() + public void RichTextBox_SelectionAlignment_GetWithHandle_ReturnsExpected() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1607,14 +1668,14 @@ public void RichTextBox_SelectionIndent_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(0, control.SelectionIndent); + Assert.Equal(HorizontalAlignment.Left, control.SelectionAlignment); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); // Call again. - Assert.Equal(0, control.SelectionIndent); + Assert.Equal(HorizontalAlignment.Left, control.SelectionAlignment); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -1622,19 +1683,19 @@ public void RichTextBox_SelectionIndent_GetWithHandle_ReturnsExpected() } [WinFormsFact] - public void RichTextBox_SelectionLength_GetWithoutHandle_ReturnsExpected() + public void RichTextBox_SelectionBullet_GetWithoutHandle_ReturnsExpected() { using var control = new RichTextBox(); - Assert.Equal(0, control.SelectionLength); + Assert.False(control.SelectionBullet); Assert.True(control.IsHandleCreated); - // Get again. - Assert.Equal(0, control.SelectionLength); + // Call again. + Assert.False(control.SelectionBullet); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_SelectionLength_GetWithHandle_ReturnsExpected() + public void RichTextBox_SelectionBullet_GetWithHandle_ReturnsExpected() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1645,14 +1706,14 @@ public void RichTextBox_SelectionLength_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(0, control.SelectionLength); + Assert.False(control.SelectionBullet); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Get again. - Assert.Equal(0, control.SelectionLength); + // Call again. + Assert.False(control.SelectionBullet); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -1660,19 +1721,19 @@ public void RichTextBox_SelectionLength_GetWithHandle_ReturnsExpected() } [WinFormsFact] - public void RichTextBox_SelectionProtected_GetWithoutHandle_ReturnsExpected() + public void RichTextBox_SelectionCharOffset_GetWithoutHandle_ReturnsExpected() { using var control = new RichTextBox(); - Assert.False(control.SelectionProtected); + Assert.Equal(0, control.SelectionCharOffset); Assert.True(control.IsHandleCreated); // Call again. - Assert.False(control.SelectionProtected); + Assert.Equal(0, control.SelectionCharOffset); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_SelectionProtected_GetWithHandle_ReturnsExpected() + public void RichTextBox_SelectionCharOffset_GetWithHandle_ReturnsExpected() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1683,72 +1744,82 @@ public void RichTextBox_SelectionProtected_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.False(control.SelectionProtected); + Assert.Equal(0, control.SelectionCharOffset); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); // Call again. - Assert.False(control.SelectionProtected); + Assert.Equal(0, control.SelectionCharOffset); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsFact] - public void RichTextBox_SelectionRightIndent_GetWithoutHandle_ReturnsExpected() + public static IEnumerable SelectionCharOffset_CustomGetCharFormat_TestData() { - using var control = new RichTextBox(); - Assert.Equal(0, control.SelectionRightIndent); - Assert.True(control.IsHandleCreated); + yield return new object[] { CFM.OFFSET, 0, 0 }; + yield return new object[] { CFM.OFFSET, 900, 60 }; + yield return new object[] { CFM.OFFSET, 30000, 2000 }; + yield return new object[] { CFM.OFFSET, 60000, 4000 }; + yield return new object[] { CFM.OFFSET, -900, -60 }; - // Call again. - Assert.Equal(0, control.SelectionRightIndent); - Assert.True(control.IsHandleCreated); + yield return new object[] { 0, 0, 0 }; + yield return new object[] { 0, 900, 60 }; + yield return new object[] { 0, 30000, 2000 }; + yield return new object[] { 0, 60000, 4000 }; + yield return new object[] { 0, -900, -60 }; } - [WinFormsFact] - public void RichTextBox_SelectionRightIndent_GetWithHandle_ReturnsExpected() + [WinFormsTheory] + [MemberData(nameof(SelectionCharOffset_CustomGetCharFormat_TestData))] + public void RichTextBox_SelectionCharOffset_CustomGetCharFormat_Success(uint mask, int yOffset, int expected) { - using var control = new RichTextBox(); - Assert.NotEqual(IntPtr.Zero, control.Handle); - int invalidatedCallCount = 0; - control.Invalidated += (sender, e) => invalidatedCallCount++; - int styleChangedCallCount = 0; - control.StyleChanged += (sender, e) => styleChangedCallCount++; - int createdCallCount = 0; - control.HandleCreated += (sender, e) => createdCallCount++; - - Assert.Equal(0, control.SelectionRightIndent); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + using var control = new CustomGetCharFormatRichTextBox + { + ExpectedWParam = (IntPtr)SCF.SELECTION, + GetCharFormatResult = new CHARFORMATW + { + dwMask = (CFM)mask, + yOffset = yOffset + } + }; - // Call again. - Assert.Equal(0, control.SelectionRightIndent); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.MakeCustom = true; + Assert.Equal(expected, control.SelectionCharOffset); } - [WinFormsFact] - public void RichTextBox_SelectionStart_GetWithoutHandle_ReturnsExpected() + [WinFormsTheory] + [InlineData(2000)] + [InlineData(10)] + [InlineData(0)] + [InlineData(-10)] + [InlineData(-2000)] + public void RichTextBox_SelectionCharOffset_Set_GetReturnsExpected(int value) { - using var control = new RichTextBox(); - Assert.Equal(0, control.SelectionStart); + using var control = new RichTextBox + { + SelectionCharOffset = value + }; + Assert.Equal(value, control.SelectionCharOffset); Assert.True(control.IsHandleCreated); - // Get again. - Assert.Equal(0, control.SelectionStart); + // Set same. + control.SelectionCharOffset = value; + Assert.Equal(value, control.SelectionCharOffset); Assert.True(control.IsHandleCreated); } - [WinFormsFact] - public void RichTextBox_SelectionStart_GetWithHandle_ReturnsExpected() + [WinFormsTheory] + [InlineData(2000)] + [InlineData(10)] + [InlineData(0)] + [InlineData(-10)] + [InlineData(-2000)] + public void RichTextBox_SelectionCharOffset_SetWithHandle_GetReturnsExpected(int value) { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1759,14 +1830,16 @@ public void RichTextBox_SelectionStart_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(0, control.SelectionStart); + control.SelectionCharOffset = value; + Assert.Equal(value, control.SelectionCharOffset); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Get again. - Assert.Equal(0, control.SelectionStart); + // Set same. + control.SelectionCharOffset = value; + Assert.Equal(value, control.SelectionCharOffset); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -1774,57 +1847,43 @@ public void RichTextBox_SelectionStart_GetWithHandle_ReturnsExpected() } [WinFormsFact] - public void RichTextBox_SelectionTabs_GetWithoutHandle_ReturnsExpected() + public unsafe void RichTextBox_SelectionCharOffset_GetCharFormat_Success() { using var control = new RichTextBox(); - Assert.Empty(control.SelectionTabs); - Assert.True(control.IsHandleCreated); - // Call again. - Assert.Empty(control.SelectionTabs); - Assert.True(control.IsHandleCreated); + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.SelectionCharOffset = 60; + var format = new CHARFORMATW + { + cbSize = (uint)sizeof(CHARFORMATW) + }; + Assert.NotEqual(IntPtr.Zero, User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_GETCHARFORMAT, (IntPtr)SCF.SELECTION, ref format)); + Assert.Equal(900, format.yOffset); } - [WinFormsFact] - public void RichTextBox_SelectionTabs_GetWithHandle_ReturnsExpected() + [WinFormsTheory] + [InlineData(2001)] + [InlineData(-20001)] + public void RichTextBox_SelectionCharOffset_SetInvalidValue_ThrowsArgumentOutOfRangeException(int value) { using var control = new RichTextBox(); - Assert.NotEqual(IntPtr.Zero, control.Handle); - int invalidatedCallCount = 0; - control.Invalidated += (sender, e) => invalidatedCallCount++; - int styleChangedCallCount = 0; - control.StyleChanged += (sender, e) => styleChangedCallCount++; - int createdCallCount = 0; - control.HandleCreated += (sender, e) => createdCallCount++; - - Assert.Empty(control.SelectionTabs); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); - - // Call again. - Assert.Empty(control.SelectionTabs); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + Assert.Throws("value", () => control.SelectionCharOffset = value); } [WinFormsFact] - public void RichTextBox_SelectionType_GetWithoutHandle_ReturnsExpected() + public void RichTextBox_SelectionColor_GetWithoutHandle_ReturnsExpected() { using var control = new RichTextBox(); - Assert.Equal(RichTextBoxSelectionTypes.Empty, control.SelectionType); + Assert.Equal(Color.Black, control.SelectionColor); Assert.True(control.IsHandleCreated); // Call again. - Assert.Equal(RichTextBoxSelectionTypes.Empty, control.SelectionType); + Assert.Equal(Color.Black, control.SelectionColor); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_SelectionType_GetWithHandle_ReturnsExpected() + public void RichTextBox_SelectionColor_GetWithHandle_ReturnsExpected() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1835,72 +1894,77 @@ public void RichTextBox_SelectionType_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(RichTextBoxSelectionTypes.Empty, control.SelectionType); + Assert.Equal(Color.Black, control.SelectionColor); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); // Call again. - Assert.Equal(RichTextBoxSelectionTypes.Empty, control.SelectionType); + Assert.Equal(Color.Black, control.SelectionColor); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsFact] - public void RichTextBox_ShowSelectionMargin_GetWithHandle_ReturnsExpected() + public static IEnumerable SelectionColor_CustomGetCharFormat_TestData() { - using var control = new RichTextBox(); - Assert.NotEqual(IntPtr.Zero, control.Handle); - int invalidatedCallCount = 0; - control.Invalidated += (sender, e) => invalidatedCallCount++; - int styleChangedCallCount = 0; - control.StyleChanged += (sender, e) => styleChangedCallCount++; - int createdCallCount = 0; - control.HandleCreated += (sender, e) => createdCallCount++; + yield return new object[] { CFM.COLOR, 0x785634, Color.FromArgb(0xFF, 0x34, 0x56, 0x78) }; + yield return new object[] { CFM.COLOR, 0x78563412, Color.FromArgb(0xFF, 0x12, 0x34, 0x56) }; + yield return new object[] { CFM.COLOR, 0, Color.Black }; - Assert.False(control.ShowSelectionMargin); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + yield return new object[] { 0, 0x785634, Color.Empty }; + yield return new object[] { 0, 0x78563412, Color.Empty }; + yield return new object[] { 0, 0, Color.Empty }; + } - // Call EM_SETOPTIONS. - User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_SETOPTIONS, (IntPtr)RichTextBoxConstants.ECOOP_OR, (IntPtr)RichTextBoxConstants.ECO_SELECTIONBAR); - Assert.False(control.ShowSelectionMargin); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + [WinFormsTheory] + [MemberData(nameof(SelectionColor_CustomGetCharFormat_TestData))] + public void RichTextBox_SelectionColor_CustomGetCharFormat_Success(uint mask, int textColor, Color expected) + { + using var control = new CustomGetCharFormatRichTextBox + { + ExpectedWParam = (IntPtr)SCF.SELECTION, + GetCharFormatResult = new CHARFORMATW + { + dwMask = (CFM)mask, + crTextColor = textColor + } + }; + + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.MakeCustom = true; + Assert.Equal(expected, control.SelectionColor); + } + + public static IEnumerable SelectionColor_Set_TestData() + { + yield return new object[] { Color.Empty, Color.Black }; + yield return new object[] { Color.Red, Color.Red }; + yield return new object[] { Color.FromArgb(0x12, 0x34, 0x56, 0x78), Color.FromArgb(0xFF, 0x34, 0x56, 0x78) }; } [WinFormsTheory] - [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] - public void RichTextBox_ShowSelectionMargin_Set_GetReturnsExpected(bool value) + [MemberData(nameof(SelectionColor_Set_TestData))] + public void RichTextBox_SelectionColor_Set_GetReturnsExpected(Color value, Color expected) { using var control = new RichTextBox { - ShowSelectionMargin = value + SelectionColor = value }; - Assert.Equal(value, control.ShowSelectionMargin); - Assert.False(control.IsHandleCreated); + Assert.Equal(expected, control.SelectionColor); + Assert.True(control.IsHandleCreated); // Set same. - control.ShowSelectionMargin = value; - Assert.Equal(value, control.ShowSelectionMargin); - Assert.False(control.IsHandleCreated); - - // Set different. - control.ShowSelectionMargin = !value; - Assert.Equal(!value, control.ShowSelectionMargin); - Assert.False(control.IsHandleCreated); + control.SelectionColor = value; + Assert.Equal(expected, control.SelectionColor); + Assert.True(control.IsHandleCreated); } [WinFormsTheory] - [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] - public void RichTextBox_ShowSelectionMargin_SetWithHandle_GetReturnsExpected(bool value) + [MemberData(nameof(SelectionColor_Set_TestData))] + public void RichTextBox_SelectionColor_SetWithHandle_GetReturnsExpected(Color value, Color expected) { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1911,56 +1975,54 @@ public void RichTextBox_ShowSelectionMargin_SetWithHandle_GetReturnsExpected(boo int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - control.ShowSelectionMargin = value; - Assert.Equal(value, control.ShowSelectionMargin); + control.SelectionColor = value; + Assert.Equal(expected, control.SelectionColor); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); // Set same. - control.ShowSelectionMargin = value; - Assert.Equal(value, control.ShowSelectionMargin); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); - - // Set different. - control.ShowSelectionMargin = !value; - Assert.Equal(!value, control.ShowSelectionMargin); + control.SelectionColor = value; + Assert.Equal(expected, control.SelectionColor); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [InlineData(true, 0x1000041)] - [InlineData(false, 0x41)] - public void RichTextBox_ShowSelectionMargin_GetOptions_Success(bool value, int expected) + [WinFormsFact] + public unsafe void RichTextBox_SelectionColor_GetCharFormat_Success() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); - control.ShowSelectionMargin = value; - Assert.Equal((IntPtr)expected, User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_GETOPTIONS)); + control.SelectionColor = Color.FromArgb(0x12, 0x34, 0x56, 0x78); + var format = new CHARFORMATW + { + cbSize = (uint)sizeof(CHARFORMATW) + }; + Assert.NotEqual(IntPtr.Zero, User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_GETCHARFORMAT, (IntPtr)SCF.SELECTION, ref format)); + Assert.Equal(0x785634, format.crTextColor); } [WinFormsFact] - public void RichTextBox_TextLength_GetDefaultWithoutHandle_Success() + public void RichTextBox_SelectionFont_GetWithoutHandle_ReturnsExpected() { using var control = new RichTextBox(); - Assert.Equal(0, control.TextLength); + Font result1 = control.SelectionFont; + Assert.NotNull(result1); Assert.True(control.IsHandleCreated); // Call again. - Assert.Equal(0, control.TextLength); + Font result2 = control.SelectionFont; + Assert.NotNull(result2); + Assert.NotSame(result1, result2); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_TextLength_GetDefaultWithHandle_ReturnsExpected() + public void RichTextBox_SelectionFont_GetWithHandle_ReturnsExpected() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -1971,41 +2033,58 @@ public void RichTextBox_TextLength_GetDefaultWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(0, control.TextLength); + Font result1 = control.SelectionFont; + Assert.NotNull(result1); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); // Call again. - Assert.Equal(0, control.TextLength); + Font result2 = control.SelectionFont; + Assert.NotNull(result2); + Assert.NotSame(result1, result2); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } + public static IEnumerable SelectionFont_Set_TestData() + { + yield return new object[] { new Font("Arial", 8.25f), 1 }; + yield return new object[] { new Font("Arial", 8.25f, FontStyle.Bold | FontStyle.Italic | FontStyle.Regular | FontStyle.Strikeout | FontStyle.Underline, GraphicsUnit.Point, 10), 1 }; + } + [WinFormsTheory] - [InlineData("", 0)] - [InlineData("a\0b", 1)] - [InlineData("a", 1)] - [InlineData("\ud83c\udf09", 2)] - public void RichTextBox_TextLength_GetSetWithHandle_Success(string text, int expected) + [MemberData(nameof(SelectionFont_Set_TestData))] + public void RichTextBox_SelectionFont_Set_GetReturnsExpected(Font value, byte expectedGdiCharset) { using var control = new RichTextBox { - Text = text + SelectionFont = value }; - Assert.Equal(expected, control.TextLength); + Font result1 = control.SelectionFont; + Assert.NotSame(result1, value); + Assert.Equal(value?.Name, result1.Name); + Assert.Equal(value?.Size, result1.Size); + Assert.Equal(value?.Style, result1.Style); + Assert.Equal(expectedGdiCharset, result1.GdiCharSet); + Assert.True(control.IsHandleCreated); + + // Set same. + control.SelectionFont = value; + Font result2 = control.SelectionFont; + Assert.Equal(value?.Name, result2.Name); + Assert.Equal(value?.Size, result2.Size); + Assert.Equal(value?.Style, result2.Style); + Assert.Equal(expectedGdiCharset, result2.GdiCharSet); Assert.True(control.IsHandleCreated); } [WinFormsTheory] - [InlineData("", 0)] - [InlineData("a\0b", 1)] - [InlineData("a", 1)] - [InlineData("\ud83c\udf09", 2)] - public void RichTextBox_TextLength_GetWithHandle_ReturnsExpected(string text, int expected) + [MemberData(nameof(SelectionFont_Set_TestData))] + public void RichTextBox_SelectionFont_SetWithHandle_GetReturnsExpected(Font value, byte expectedGdiCharset) { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -2016,275 +2095,244 @@ public void RichTextBox_TextLength_GetWithHandle_ReturnsExpected(string text, in int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - control.Text = text; - Assert.Equal(expected, control.TextLength); + control.SelectionFont = value; + Font result1 = control.SelectionFont; + Assert.NotSame(result1, value); + Assert.Equal(value?.Name, result1.Name); + Assert.Equal(value?.Size, result1.Size); + Assert.Equal(value?.Style, result1.Style); + Assert.Equal(expectedGdiCharset, result1.GdiCharSet); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.SelectionFont = value; + Font result2 = control.SelectionFont; + Assert.Equal(value?.Name, result2.Name); + Assert.Equal(value?.Size, result2.Size); + Assert.Equal(value?.Style, result2.Style); + Assert.Equal(expectedGdiCharset, result2.GdiCharSet); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable TextLength_GetCustomGetTextLengthEx_TestData() + [WinFormsFact] + public void RichTextBox_SelectionFont_SetNull_ThrowsNullReferenceException() { - yield return new object[] { IntPtr.Zero, 0 }; - yield return new object[] { (IntPtr)(-1), -1 }; - yield return new object[] { (IntPtr)1, 1 }; + using var control = new RichTextBox(); + Assert.Throws(() => control.SelectionFont = null); } - [WinFormsTheory] - [MemberData(nameof(TextLength_GetCustomGetTextLengthEx_TestData))] - public void RichTextBox_TextLength_GetCustomGetTextLengthEx_Success(IntPtr result, int expected) + [WinFormsFact] + public void RichTextBox_SelectionHangingIndent_GetWithoutHandle_ReturnsExpected() { - using var control = new CustomGetTextLengthExRichTextBox - { - GetTextLengthExResult = result - }; - Assert.Equal(expected, control.TextLength); + using var control = new RichTextBox(); + Assert.Equal(0, control.SelectionHangingIndent); + Assert.True(control.IsHandleCreated); + + // Call again. + Assert.Equal(0, control.SelectionHangingIndent); + Assert.True(control.IsHandleCreated); } - private class CustomGetTextLengthExRichTextBox : RichTextBox + [WinFormsFact] + public void RichTextBox_SelectionHangingIndent_GetWithHandle_ReturnsExpected() { - public IntPtr GetTextLengthExResult { get; set; } + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - protected unsafe override void WndProc(ref Message m) - { - if (m.Msg == RichEditMessages.EM_GETTEXTLENGTHEX) - { - GETTEXTLENGTHEX* gtl = (GETTEXTLENGTHEX*)m.WParam; - Assert.Equal(GTL.NUMCHARS, gtl->flags); - Assert.Equal(1200u, gtl->codepage); - Assert.Equal(IntPtr.Zero, m.LParam); - m.Result = GetTextLengthExResult; - return; - } + Assert.Equal(0, control.SelectionHangingIndent); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); - base.WndProc(ref m); - } + // Call again. + Assert.Equal(0, control.SelectionHangingIndent); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - public static IEnumerable Text_Set_TestData() + [WinFormsFact] + public void RichTextBox_SelectionIndent_GetWithoutHandle_ReturnsExpected() { - foreach (bool autoSize in new bool[] { true, false }) - { - yield return new object[] { autoSize, null, string.Empty }; - yield return new object[] { autoSize, string.Empty, string.Empty }; - yield return new object[] { autoSize, "text", "text" }; - } + using var control = new RichTextBox(); + Assert.Equal(0, control.SelectionIndent); + Assert.True(control.IsHandleCreated); + + // Call again. + Assert.Equal(0, control.SelectionIndent); + Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(Text_Set_TestData))] - public void RichTextBox_Text_Set_GetReturnsExpected(bool autoSize, string value, string expected) + [WinFormsFact] + public void RichTextBox_SelectionIndent_GetWithHandle_ReturnsExpected() { - using var control = new RichTextBox - { - AutoSize = autoSize - }; - int layoutCallCount = 0; - control.Layout += (control, e) => layoutCallCount++; + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.False(control.Modified); - Assert.False(control.CanUndo); - Assert.Equal(0, layoutCallCount); - Assert.False(control.IsHandleCreated); + Assert.Equal(0, control.SelectionIndent); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); - // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.False(control.Modified); - Assert.False(control.CanUndo); - Assert.Equal(0, layoutCallCount); - Assert.False(control.IsHandleCreated); + // Call again. + Assert.Equal(0, control.SelectionIndent); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))] - public void RichTextBox_Text_SetWithRtfText_GetReturnsExpected(string value, string expected) + [WinFormsFact] + public void RichTextBox_SelectionLength_GetWithoutHandle_ReturnsExpected() { - using var control = new RichTextBox - { - Rtf = "{\\rtf Hello World}", - Text = value - }; - Assert.Equal(expected, control.Text); - Assert.Contains(expected, control.Rtf); - Assert.DoesNotContain("Hello World", control.Rtf); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); + using var control = new RichTextBox(); Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.False(control.CanUndo); Assert.True(control.IsHandleCreated); - // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Contains(expected, control.Rtf); - Assert.DoesNotContain("Hello World", control.Rtf); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); + // Get again. Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.False(control.CanUndo); Assert.True(control.IsHandleCreated); } - public static IEnumerable Text_SetWithParent_TestData() + [WinFormsFact] + public void RichTextBox_SelectionLength_GetWithHandle_ReturnsExpected() { - yield return new object[] { true, null, string.Empty, 1 }; - yield return new object[] { true, string.Empty, string.Empty, 1 }; - yield return new object[] { true, "text", "text", 1 }; + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - yield return new object[] { false, null, string.Empty, 0 }; - yield return new object[] { false, string.Empty, string.Empty, 0 }; - yield return new object[] { false, "text", "text", 0 }; + Assert.Equal(0, control.SelectionLength); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Get again. + Assert.Equal(0, control.SelectionLength); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [MemberData(nameof(Text_SetWithParent_TestData))] - public void RichTextBox_Text_SetWithParent_GetReturnsExpected(bool autoSize, string value, string expected, int expectedParentLayoutCallCount) + [WinFormsFact] + public void RichTextBox_SelectionProtected_GetWithoutHandle_ReturnsExpected() { - using var parent = new Control(); - using var control = new RichTextBox - { - Parent = parent, - AutoSize = autoSize - }; - int layoutCallCount = 0; - control.Layout += (control, e) => layoutCallCount++; - int parentLayoutCallCount = 0; - void parentHandler(object sender, LayoutEventArgs e) - { - Assert.Same(parent, sender); - Assert.Same(control, e.AffectedControl); - Assert.Equal("Text", e.AffectedProperty); - parentLayoutCallCount++; - }; - parent.Layout += parentHandler; - - try - { - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.False(control.Modified); - Assert.False(control.CanUndo); - Assert.Equal(0, layoutCallCount); - Assert.Equal(expectedParentLayoutCallCount, parentLayoutCallCount); - Assert.False(control.IsHandleCreated); + using var control = new RichTextBox(); + Assert.False(control.SelectionProtected); + Assert.True(control.IsHandleCreated); - // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.False(control.Modified); - Assert.False(control.CanUndo); - Assert.Equal(0, layoutCallCount); - Assert.Equal(expectedParentLayoutCallCount * 2, parentLayoutCallCount); - Assert.False(control.IsHandleCreated); - } - finally - { - parent.Layout -= parentHandler; - } + // Call again. + Assert.False(control.SelectionProtected); + Assert.True(control.IsHandleCreated); } - public static IEnumerable Text_SetWithSelection_TestData() + [WinFormsFact] + public void RichTextBox_SelectionProtected_GetWithHandle_ReturnsExpected() { - yield return new object[] { string.Empty, 0, 2, null, string.Empty }; - yield return new object[] { string.Empty, 0, 2, "t", "t" }; - yield return new object[] { string.Empty, 0, 2, "text", "text" }; + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - yield return new object[] { string.Empty, 1, 2, null, string.Empty }; - yield return new object[] { string.Empty, 1, 2, "t", "t" }; - yield return new object[] { string.Empty, 1, 2, "text", "text" }; + Assert.False(control.SelectionProtected); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); - yield return new object[] { "text", 0, 2, null, string.Empty }; - yield return new object[] { "text", 0, 2, "t", "t" }; - yield return new object[] { "text", 0, 2, "te", "te" }; - yield return new object[] { "text", 0, 2, "tex", "tex" }; + // Call again. + Assert.False(control.SelectionProtected); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } - yield return new object[] { "text", 1, 2, null, string.Empty }; - yield return new object[] { "text", 1, 2, "t", "t" }; - yield return new object[] { "text", 1, 2, "te", "te" }; - yield return new object[] { "text", 1, 2, "tex", "tex" }; + [WinFormsFact] + public void RichTextBox_SelectionRightIndent_GetWithoutHandle_ReturnsExpected() + { + using var control = new RichTextBox(); + Assert.Equal(0, control.SelectionRightIndent); + Assert.True(control.IsHandleCreated); + + // Call again. + Assert.Equal(0, control.SelectionRightIndent); + Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(Text_SetWithSelection_TestData))] - public void RichTextBox_Text_SetWithSelection_GetReturnsExpected(string oldValue, int selectionStart, int selectionLength, string value, string expected) + [WinFormsFact] + public void RichTextBox_SelectionRightIndent_GetWithHandle_ReturnsExpected() { - using var control = new RichTextBox - { - Text = oldValue, - SelectionStart = selectionStart, - SelectionLength = selectionLength, - }; + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.False(control.CanUndo); + Assert.Equal(0, control.SelectionRightIndent); Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); - // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.False(control.CanUndo); + // Call again. + Assert.Equal(0, control.SelectionRightIndent); Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [InlineData(null, "", true)] - [InlineData("", "", false)] - [InlineData("text", "text", false)] - public void RichTextBox_Text_SetModified_GetReturnsExpected(string value, string expected, bool expectedModified) + [WinFormsFact] + public void RichTextBox_SelectionStart_GetWithoutHandle_ReturnsExpected() { - using var control = new RichTextBox - { - Modified = true, - Text = value - }; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); + using var control = new RichTextBox(); Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.Equal(expectedModified, control.Modified); - Assert.False(control.CanUndo); Assert.True(control.IsHandleCreated); - // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); + // Get again. Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.False(control.CanUndo); Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(Text_Set_TestData))] - public void RichTextBox_Text_SetWithHandle_GetReturnsExpected(bool autoSize, string value, string expected) + [WinFormsFact] + public void RichTextBox_SelectionStart_GetWithHandle_ReturnsExpected() { - using var control = new RichTextBox - { - AutoSize = autoSize - }; + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -2292,45 +2340,37 @@ public void RichTextBox_Text_SetWithHandle_GetReturnsExpected(bool autoSize, str control.StyleChanged += (sender, e) => styleChangedCallCount++; int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - int layoutCallCount = 0; - control.Layout += (control, e) => layoutCallCount++; - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.Equal(0, layoutCallCount); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); + // Get again. Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.Equal(0, layoutCallCount); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))] - public void RichTextBox_Text_SetWithRtfTextWithHandle_GetReturnsExpected(string value, string expected) + [WinFormsFact] + public void RichTextBox_SelectionTabs_GetWithoutHandle_ReturnsExpected() { - using var control = new RichTextBox - { - Rtf = "{\\rtf Hello World}" - }; + using var control = new RichTextBox(); + Assert.Empty(control.SelectionTabs); + Assert.True(control.IsHandleCreated); + + // Call again. + Assert.Empty(control.SelectionTabs); + Assert.True(control.IsHandleCreated); + } + + [WinFormsFact] + public void RichTextBox_SelectionTabs_GetWithHandle_ReturnsExpected() + { + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -2339,48 +2379,36 @@ public void RichTextBox_Text_SetWithRtfTextWithHandle_GetReturnsExpected(string int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Contains(expected, control.Rtf); - Assert.DoesNotContain("Hello World", control.Rtf); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.False(control.CanUndo); + Assert.Empty(control.SelectionTabs); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Contains(expected, control.Rtf); - Assert.DoesNotContain("Hello World", control.Rtf); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.False(control.CanUndo); + // Call again. + Assert.Empty(control.SelectionTabs); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [MemberData(nameof(Text_SetWithParent_TestData))] - public void RichTextBox_Text_SetWithParentWithHandle_GetReturnsExpected(bool autoSize, string value, string expected, int expectedParentLayoutCallCount) + [WinFormsFact] + public void RichTextBox_SelectionType_GetWithoutHandle_ReturnsExpected() { - using var parent = new Control(); - using var control = new RichTextBox - { - Parent = parent, - AutoSize = autoSize - }; + using var control = new RichTextBox(); + Assert.Equal(RichTextBoxSelectionTypes.Empty, control.SelectionType); + Assert.True(control.IsHandleCreated); + + // Call again. + Assert.Equal(RichTextBoxSelectionTypes.Empty, control.SelectionType); + Assert.True(control.IsHandleCreated); + } + + [WinFormsFact] + public void RichTextBox_SelectionType_GetWithHandle_ReturnsExpected() + { + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -2388,59 +2416,25 @@ public void RichTextBox_Text_SetWithParentWithHandle_GetReturnsExpected(bool aut control.StyleChanged += (sender, e) => styleChangedCallCount++; int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - int layoutCallCount = 0; - control.Layout += (control, e) => layoutCallCount++; - int parentLayoutCallCount = 0; - void parentHandler(object sender, LayoutEventArgs e) - { - Assert.Same(parent, sender); - Assert.Same(control, e.AffectedControl); - Assert.Equal("Text", e.AffectedProperty); - parentLayoutCallCount++; - }; - parent.Layout += parentHandler; - try - { - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.False(control.Modified); - Assert.False(control.CanUndo); - Assert.Equal(0, layoutCallCount); - Assert.Equal(expectedParentLayoutCallCount, parentLayoutCallCount); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + Assert.Equal(RichTextBoxSelectionTypes.Empty, control.SelectionType); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); - // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.False(control.Modified); - Assert.False(control.CanUndo); - Assert.Equal(0, layoutCallCount); - Assert.Equal(expectedParentLayoutCallCount * 2, parentLayoutCallCount); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); - } - finally - { - parent.Layout -= parentHandler; - } + // Call again. + Assert.Equal(RichTextBoxSelectionTypes.Empty, control.SelectionType); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [InlineData(null, "")] - [InlineData("", "")] - [InlineData("text", "text")] - public void RichTextBox_Text_SetModifiedWithHandle_GetReturnsExpected(string value, string expected) + [WinFormsFact] + public void RichTextBox_ShowSelectionMargin_GetWithHandle_ReturnsExpected() { - using var control = new RichTextBox - { - Modified = true - }; + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -2449,63 +2443,48 @@ public void RichTextBox_Text_SetModifiedWithHandle_GetReturnsExpected(string val int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); + Assert.False(control.ShowSelectionMargin); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); + // Call EM_SETOPTIONS. + User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_SETOPTIONS, (IntPtr)RichTextBoxConstants.ECOOP_OR, (IntPtr)RichTextBoxConstants.ECO_SELECTIONBAR); + Assert.False(control.ShowSelectionMargin); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable Text_SetWithSelectionWithHandle_TestData() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void RichTextBox_ShowSelectionMargin_Set_GetReturnsExpected(bool value) { - yield return new object[] { string.Empty, 0, 2, null, string.Empty }; - yield return new object[] { string.Empty, 0, 2, "t", "t" }; - yield return new object[] { string.Empty, 0, 2, "text", "text" }; - - yield return new object[] { string.Empty, 1, 2, null, string.Empty }; - yield return new object[] { string.Empty, 1, 2, "t", "t" }; - yield return new object[] { string.Empty, 1, 2, "text", "text" }; + using var control = new RichTextBox + { + ShowSelectionMargin = value + }; + Assert.Equal(value, control.ShowSelectionMargin); + Assert.False(control.IsHandleCreated); - yield return new object[] { "text", 0, 2, null, string.Empty }; - yield return new object[] { "text", 0, 2, "t", "t" }; - yield return new object[] { "text", 0, 2, "te", "te" }; - yield return new object[] { "text", 0, 2, "tex", "tex" }; + // Set same. + control.ShowSelectionMargin = value; + Assert.Equal(value, control.ShowSelectionMargin); + Assert.False(control.IsHandleCreated); - yield return new object[] { "text", 1, 2, null, string.Empty }; - yield return new object[] { "text", 1, 2, "t", "t" }; - yield return new object[] { "text", 1, 2, "te", "te" }; - yield return new object[] { "text", 1, 2, "tex", "tex" }; + // Set different. + control.ShowSelectionMargin = !value; + Assert.Equal(!value, control.ShowSelectionMargin); + Assert.False(control.IsHandleCreated); } [WinFormsTheory] - [MemberData(nameof(Text_SetWithSelectionWithHandle_TestData))] - public void RichTextBox_Text_SetWithSelectionWith_GetReturnsExpected(string oldValue, int selectionStart, int selectionLength, string value, string expected) + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void RichTextBox_ShowSelectionMargin_SetWithHandle_GetReturnsExpected(bool value) { - using var control = new RichTextBox - { - Text = oldValue, - SelectionStart = selectionStart, - SelectionLength = selectionLength, - }; + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -2514,71 +2493,56 @@ public void RichTextBox_Text_SetWithSelectionWith_GetReturnsExpected(string oldV int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.False(control.CanUndo); + control.ShowSelectionMargin = value; + Assert.Equal(value, control.ShowSelectionMargin); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); // Set same. - control.Text = value; - Assert.Equal(expected, control.Text); - Assert.Equal(expected.Length, control.TextLength); - Assert.Equal(0, control.SelectionStart); - Assert.Equal(0, control.SelectionLength); - Assert.Empty(control.SelectedText); - Assert.False(control.Modified); - Assert.False(control.CanUndo); + control.ShowSelectionMargin = value; + Assert.Equal(value, control.ShowSelectionMargin); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set different. + control.ShowSelectionMargin = !value; + Assert.Equal(!value, control.ShowSelectionMargin); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsFact] - public void RichTextBox_Text_SetWithHandler_CallsTextChanged() + [WinFormsTheory] + [InlineData(true, 0x1000041)] + [InlineData(false, 0x41)] + public void RichTextBox_ShowSelectionMargin_GetOptions_Success(bool value, int expected) { using var control = new RichTextBox(); - int callCount = 0; - EventHandler handler = (sender, e) => - { - Assert.Same(control, sender); - Assert.Equal(EventArgs.Empty, e); - callCount++; - }; - control.TextChanged += handler; - - // Set different. - control.Text = "text"; - Assert.Equal("text", control.Text); - Assert.Equal(0, callCount); - // Set same. - control.Text = "text"; - Assert.Equal("text", control.Text); - Assert.Equal(0, callCount); + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.ShowSelectionMargin = value; + Assert.Equal((IntPtr)expected, User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_GETOPTIONS)); + } - // Set different. - control.Text = null; - Assert.Empty(control.Text); - Assert.Equal(0, callCount); + [WinFormsFact] + public void RichTextBox_TextLength_GetDefaultWithoutHandle_Success() + { + using var control = new RichTextBox(); + Assert.Equal(0, control.TextLength); + Assert.True(control.IsHandleCreated); - // Remove handler. - control.TextChanged -= handler; - control.Text = "text"; - Assert.Equal("text", control.Text); - Assert.Equal(0, callCount); + // Call again. + Assert.Equal(0, control.TextLength); + Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_Text_SetWithHandlerWithHandle_CallsTextChanged() + public void RichTextBox_TextLength_GetDefaultWithHandle_ReturnsExpected() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -2589,55 +2553,41 @@ public void RichTextBox_Text_SetWithHandlerWithHandle_CallsTextChanged() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - int callCount = 0; - EventHandler handler = (sender, e) => - { - Assert.Same(control, sender); - Assert.Equal(EventArgs.Empty, e); - callCount++; - }; - control.TextChanged += handler; - - // Set different. - control.Text = "text"; - Assert.Equal("text", control.Text); - Assert.Equal(1, callCount); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); - - // Set same. - control.Text = "text"; - Assert.Equal("text", control.Text); - Assert.Equal(2, callCount); + Assert.Equal(0, control.TextLength); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - // Set different. - control.Text = null; - Assert.Empty(control.Text); - Assert.Equal(3, callCount); + // Call again. + Assert.Equal(0, control.TextLength); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); + } - // Remove handler. - control.TextChanged -= handler; - control.Text = "text"; - Assert.Equal("text", control.Text); - Assert.Equal(3, callCount); + [WinFormsTheory] + [InlineData("", 0)] + [InlineData("a\0b", 1)] + [InlineData("a", 1)] + [InlineData("\ud83c\udf09", 2)] + public void RichTextBox_TextLength_GetSetWithHandle_Success(string text, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.Equal(expected, control.TextLength); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); } - [WinFormsFact] - public void RichTextBox_UndoActionName_GetWithHandle_ReturnsExpected() + [WinFormsTheory] + [InlineData("", 0)] + [InlineData("a\0b", 1)] + [InlineData("a", 1)] + [InlineData("\ud83c\udf09", 2)] + public void RichTextBox_TextLength_GetWithHandle_ReturnsExpected(string text, int expected) { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -2648,66 +2598,1387 @@ public void RichTextBox_UndoActionName_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Empty(control.UndoActionName); + control.Text = text; + Assert.Equal(expected, control.TextLength); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + public static IEnumerable TextLength_GetCustomGetTextLengthEx_TestData() + { + yield return new object[] { IntPtr.Zero, 0 }; + yield return new object[] { (IntPtr)(-1), -1 }; + yield return new object[] { (IntPtr)1, 1 }; + } + + [WinFormsTheory] + [MemberData(nameof(TextLength_GetCustomGetTextLengthEx_TestData))] + public void RichTextBox_TextLength_GetCustomGetTextLengthEx_Success(IntPtr result, int expected) + { + using var control = new CustomGetTextLengthExRichTextBox + { + GetTextLengthExResult = result + }; + Assert.Equal(expected, control.TextLength); + } + + private class CustomGetTextLengthExRichTextBox : RichTextBox + { + public IntPtr GetTextLengthExResult { get; set; } + + protected unsafe override void WndProc(ref Message m) + { + if (m.Msg == RichEditMessages.EM_GETTEXTLENGTHEX) + { + GETTEXTLENGTHEX* gtl = (GETTEXTLENGTHEX*)m.WParam; + Assert.Equal(GTL.NUMCHARS, gtl->flags); + Assert.Equal(1200u, gtl->codepage); + Assert.Equal(IntPtr.Zero, m.LParam); + m.Result = GetTextLengthExResult; + return; + } + + base.WndProc(ref m); + } + } + + public static IEnumerable Text_Set_TestData() + { + foreach (bool autoSize in new bool[] { true, false }) + { + yield return new object[] { autoSize, null, string.Empty }; + yield return new object[] { autoSize, string.Empty, string.Empty }; + yield return new object[] { autoSize, "text", "text" }; + } + } + + [WinFormsTheory] + [MemberData(nameof(Text_Set_TestData))] + public void RichTextBox_Text_Set_GetReturnsExpected(bool autoSize, string value, string expected) + { + using var control = new RichTextBox + { + AutoSize = autoSize + }; + int layoutCallCount = 0; + control.Layout += (control, e) => layoutCallCount++; + + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.Equal(0, layoutCallCount); + Assert.False(control.IsHandleCreated); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.Equal(0, layoutCallCount); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))] + public void RichTextBox_Text_SetWithRtfText_GetReturnsExpected(string value, string expected) + { + using var control = new RichTextBox + { + Rtf = "{\\rtf Hello World}", + Text = value + }; + Assert.Equal(expected, control.Text); + Assert.Contains(expected, control.Rtf); + Assert.DoesNotContain("Hello World", control.Rtf); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Contains(expected, control.Rtf); + Assert.DoesNotContain("Hello World", control.Rtf); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + } + + public static IEnumerable Text_SetWithParent_TestData() + { + yield return new object[] { true, null, string.Empty, 1 }; + yield return new object[] { true, string.Empty, string.Empty, 1 }; + yield return new object[] { true, "text", "text", 1 }; + + yield return new object[] { false, null, string.Empty, 0 }; + yield return new object[] { false, string.Empty, string.Empty, 0 }; + yield return new object[] { false, "text", "text", 0 }; + } + + [WinFormsTheory] + [MemberData(nameof(Text_SetWithParent_TestData))] + public void RichTextBox_Text_SetWithParent_GetReturnsExpected(bool autoSize, string value, string expected, int expectedParentLayoutCallCount) + { + using var parent = new Control(); + using var control = new RichTextBox + { + Parent = parent, + AutoSize = autoSize + }; + int layoutCallCount = 0; + control.Layout += (control, e) => layoutCallCount++; + int parentLayoutCallCount = 0; + void parentHandler(object sender, LayoutEventArgs e) + { + Assert.Same(parent, sender); + Assert.Same(control, e.AffectedControl); + Assert.Equal("Text", e.AffectedProperty); + parentLayoutCallCount++; + }; + parent.Layout += parentHandler; + + try + { + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.Equal(0, layoutCallCount); + Assert.Equal(expectedParentLayoutCallCount, parentLayoutCallCount); + Assert.False(control.IsHandleCreated); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.Equal(0, layoutCallCount); + Assert.Equal(expectedParentLayoutCallCount * 2, parentLayoutCallCount); + Assert.False(control.IsHandleCreated); + } + finally + { + parent.Layout -= parentHandler; + } + } + + public static IEnumerable Text_SetWithSelection_TestData() + { + yield return new object[] { string.Empty, 0, 2, null, string.Empty }; + yield return new object[] { string.Empty, 0, 2, "t", "t" }; + yield return new object[] { string.Empty, 0, 2, "text", "text" }; + + yield return new object[] { string.Empty, 1, 2, null, string.Empty }; + yield return new object[] { string.Empty, 1, 2, "t", "t" }; + yield return new object[] { string.Empty, 1, 2, "text", "text" }; + + yield return new object[] { "text", 0, 2, null, string.Empty }; + yield return new object[] { "text", 0, 2, "t", "t" }; + yield return new object[] { "text", 0, 2, "te", "te" }; + yield return new object[] { "text", 0, 2, "tex", "tex" }; + + yield return new object[] { "text", 1, 2, null, string.Empty }; + yield return new object[] { "text", 1, 2, "t", "t" }; + yield return new object[] { "text", 1, 2, "te", "te" }; + yield return new object[] { "text", 1, 2, "tex", "tex" }; + } + + [WinFormsTheory] + [MemberData(nameof(Text_SetWithSelection_TestData))] + public void RichTextBox_Text_SetWithSelection_GetReturnsExpected(string oldValue, int selectionStart, int selectionLength, string value, string expected) + { + using var control = new RichTextBox + { + Text = oldValue, + SelectionStart = selectionStart, + SelectionLength = selectionLength, + }; + + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(null, "", true)] + [InlineData("", "", false)] + [InlineData("text", "text", false)] + public void RichTextBox_Text_SetModified_GetReturnsExpected(string value, string expected, bool expectedModified) + { + using var control = new RichTextBox + { + Modified = true, + Text = value + }; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.Equal(expectedModified, control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + } + + [WinFormsTheory] + [MemberData(nameof(Text_Set_TestData))] + public void RichTextBox_Text_SetWithHandle_GetReturnsExpected(bool autoSize, string value, string expected) + { + using var control = new RichTextBox + { + AutoSize = autoSize + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + int layoutCallCount = 0; + control.Layout += (control, e) => layoutCallCount++; + + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.Equal(0, layoutCallCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.Equal(0, layoutCallCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))] + public void RichTextBox_Text_SetWithRtfTextWithHandle_GetReturnsExpected(string value, string expected) + { + using var control = new RichTextBox + { + Rtf = "{\\rtf Hello World}" + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Contains(expected, control.Rtf); + Assert.DoesNotContain("Hello World", control.Rtf); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Contains(expected, control.Rtf); + Assert.DoesNotContain("Hello World", control.Rtf); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [MemberData(nameof(Text_SetWithParent_TestData))] + public void RichTextBox_Text_SetWithParentWithHandle_GetReturnsExpected(bool autoSize, string value, string expected, int expectedParentLayoutCallCount) + { + using var parent = new Control(); + using var control = new RichTextBox + { + Parent = parent, + AutoSize = autoSize + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + int layoutCallCount = 0; + control.Layout += (control, e) => layoutCallCount++; + int parentLayoutCallCount = 0; + void parentHandler(object sender, LayoutEventArgs e) + { + Assert.Same(parent, sender); + Assert.Same(control, e.AffectedControl); + Assert.Equal("Text", e.AffectedProperty); + parentLayoutCallCount++; + }; + parent.Layout += parentHandler; + + try + { + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.Equal(0, layoutCallCount); + Assert.Equal(expectedParentLayoutCallCount, parentLayoutCallCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.Equal(0, layoutCallCount); + Assert.Equal(expectedParentLayoutCallCount * 2, parentLayoutCallCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + finally + { + parent.Layout -= parentHandler; + } + } + + [WinFormsTheory] + [InlineData(null, "")] + [InlineData("", "")] + [InlineData("text", "text")] + public void RichTextBox_Text_SetModifiedWithHandle_GetReturnsExpected(string value, string expected) + { + using var control = new RichTextBox + { + Modified = true + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + public static IEnumerable Text_SetWithSelectionWithHandle_TestData() + { + yield return new object[] { string.Empty, 0, 2, null, string.Empty }; + yield return new object[] { string.Empty, 0, 2, "t", "t" }; + yield return new object[] { string.Empty, 0, 2, "text", "text" }; + + yield return new object[] { string.Empty, 1, 2, null, string.Empty }; + yield return new object[] { string.Empty, 1, 2, "t", "t" }; + yield return new object[] { string.Empty, 1, 2, "text", "text" }; + + yield return new object[] { "text", 0, 2, null, string.Empty }; + yield return new object[] { "text", 0, 2, "t", "t" }; + yield return new object[] { "text", 0, 2, "te", "te" }; + yield return new object[] { "text", 0, 2, "tex", "tex" }; + + yield return new object[] { "text", 1, 2, null, string.Empty }; + yield return new object[] { "text", 1, 2, "t", "t" }; + yield return new object[] { "text", 1, 2, "te", "te" }; + yield return new object[] { "text", 1, 2, "tex", "tex" }; + } + + [WinFormsTheory] + [MemberData(nameof(Text_SetWithSelectionWithHandle_TestData))] + public void RichTextBox_Text_SetWithSelectionWith_GetReturnsExpected(string oldValue, int selectionStart, int selectionLength, string value, string expected) + { + using var control = new RichTextBox + { + Text = oldValue, + SelectionStart = selectionStart, + SelectionLength = selectionLength, + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expected.Length, control.TextLength); + Assert.Equal(0, control.SelectionStart); + Assert.Equal(0, control.SelectionLength); + Assert.Empty(control.SelectedText); + Assert.False(control.Modified); + Assert.False(control.CanUndo); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void RichTextBox_Text_SetWithHandler_CallsTextChanged() + { + using var control = new RichTextBox(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Equal(EventArgs.Empty, e); + callCount++; + }; + control.TextChanged += handler; + + // Set different. + control.Text = "text"; + Assert.Equal("text", control.Text); + Assert.Equal(0, callCount); + + // Set same. + control.Text = "text"; + Assert.Equal("text", control.Text); + Assert.Equal(0, callCount); + + // Set different. + control.Text = null; + Assert.Empty(control.Text); + Assert.Equal(0, callCount); + + // Remove handler. + control.TextChanged -= handler; + control.Text = "text"; + Assert.Equal("text", control.Text); + Assert.Equal(0, callCount); + } + + [WinFormsFact] + public void RichTextBox_Text_SetWithHandlerWithHandle_CallsTextChanged() + { + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Equal(EventArgs.Empty, e); + callCount++; + }; + control.TextChanged += handler; + + // Set different. + control.Text = "text"; + Assert.Equal("text", control.Text); + Assert.Equal(1, callCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Text = "text"; + Assert.Equal("text", control.Text); + Assert.Equal(2, callCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set different. + control.Text = null; + Assert.Empty(control.Text); + Assert.Equal(3, callCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Remove handler. + control.TextChanged -= handler; + control.Text = "text"; + Assert.Equal("text", control.Text); + Assert.Equal(3, callCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void RichTextBox_UndoActionName_GetWithHandle_ReturnsExpected() + { + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.Empty(control.UndoActionName); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + public static IEnumerable UndoActionName_CustomGetUndoName_TestData() + { + yield return new object[] { IntPtr.Zero, IntPtr.Zero, string.Empty }; + yield return new object[] { (IntPtr)1, IntPtr.Zero, "Unknown" }; + yield return new object[] { (IntPtr)1, (IntPtr)1, "Typing" }; + yield return new object[] { (IntPtr)1, (IntPtr)2, "Delete" }; + yield return new object[] { (IntPtr)1, (IntPtr)3, "Drag and Drop" }; + yield return new object[] { (IntPtr)1, (IntPtr)4, "Cut" }; + yield return new object[] { (IntPtr)1, (IntPtr)5, "Paste" }; + yield return new object[] { (IntPtr)1, (IntPtr)6, "Unknown" }; + yield return new object[] { (IntPtr)1, (IntPtr)7, "Unknown" }; + } + + [WinFormsTheory] + [MemberData(nameof(UndoActionName_CustomGetUndoName_TestData))] + public void RichTextBox_UndoActionName_CustomGetUndoName_ReturnsExpected(IntPtr canUndoResult, IntPtr getUndoNameResult, string expected) + { + using var control = new CustomGetUndoNameRichTextBox + { + CanUndoResult = canUndoResult, + GetUndoNameResult = getUndoNameResult + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + Assert.Equal(expected, control.UndoActionName); + } + + private class CustomGetUndoNameRichTextBox : RichTextBox + { + public IntPtr CanUndoResult { get; set; } + public IntPtr GetUndoNameResult { get; set; } + + protected unsafe override void WndProc(ref Message m) + { + if (m.Msg == (int)User32.EM.CANUNDO) + { + m.Result = CanUndoResult; + return; + } + else if (m.Msg == RichEditMessages.EM_GETUNDONAME) + { + m.Result = GetUndoNameResult; + return; + } + + base.WndProc(ref m); + } + } + + [WinFormsFact] + public void RichTextBox_ZoomFactor_GetWithHandle_ReturnsExpected() + { + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.Equal(1, control.ZoomFactor); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Call EM_SETZOOM. + User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_SETZOOM, (IntPtr)2, (IntPtr)10); + Assert.Equal(0.2f, control.ZoomFactor); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [InlineData(1, 1, 1.0f)] + [InlineData(10, 1, 10.0f)] + [InlineData(10, 2, 5.0f)] + [InlineData(1, 10, 0.1f)] + [InlineData(1, 0, 1f)] + [InlineData(0, 1, 1f)] + [InlineData(0, 0, 1f)] + public void RichTextBox_ZoomFactor_CustomGetZoom_ReturnsExpected(int numerator, int denominator, float expected) + { + using var control = new CustomGetZoomRichTextBox + { + NumeratorResult = numerator, + DenominatorResult = denominator + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + Assert.Equal(expected, control.ZoomFactor); + } + + private class CustomGetZoomRichTextBox : RichTextBox + { + public int NumeratorResult { get; set; } + public int DenominatorResult { get; set; } + + protected unsafe override void WndProc(ref Message m) + { + if (m.Msg == RichEditMessages.EM_GETZOOM) + { + int* pNumerator = (int*)m.WParam; + int* pDenominator = (int*)m.LParam; + + *pNumerator = NumeratorResult; + *pDenominator = DenominatorResult; + return; + } + + base.WndProc(ref m); + } + } + + [WinFormsTheory] + [InlineData(0.015626f, 0.016f)] + [InlineData(63.9f, 63.9f)] + [InlineData(1.0f, 1.0f)] + [InlineData(2.0f, 2.0f)] + [InlineData(float.NaN, -2147483.75f)] + public void RichTextBox_ZoomFactor_Set_GetReturnsExpected(float value, float expected) + { + using var control = new RichTextBox + { + ZoomFactor = value + }; + Assert.Equal(expected, control.ZoomFactor, 2); + Assert.False(control.IsHandleCreated); + + // Set same. + control.ZoomFactor = value; + Assert.Equal(expected, control.ZoomFactor, 2); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(0.015626f, 0.016f)] + [InlineData(63.9f, 63.9f)] + [InlineData(1.0f, 1.0f)] + [InlineData(2.0f, 2.0f)] + [InlineData(float.NaN, 1.0f)] + public void RichTextBox_ZoomFactor_SetWithHandle_GetReturnsExpected(float value, float expected) + { + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.ZoomFactor = value; + Assert.Equal(expected, control.ZoomFactor); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.ZoomFactor = value; + Assert.Equal(expected, control.ZoomFactor); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [InlineData(0.015624f)] + [InlineData(0.015625f)] + [InlineData(64.0f)] + [InlineData(64.1f)] + [InlineData(float.PositiveInfinity)] + [InlineData(float.NegativeInfinity)] + public void RichTextBox_ZoomFactor_SetInvalidValue_ThrowsArgumentOutOfRangeException(float value) + { + using var control = new RichTextBox(); + Assert.Throws("value", () => control.ZoomFactor = value); + } + + public static IEnumerable CanPaste_TestData() + { + yield return new object[] { DataFormats.GetFormat(DataFormats.Palette), false }; + yield return new object[] { new DataFormats.Format("UnknownName", int.MaxValue), false }; + } + + [WinFormsTheory] + [MemberData(nameof(CanPaste_TestData))] + public void RichTextBox_CanPaste_Invoke_ReturnsExpected(DataFormats.Format format, bool expected) + { + using var control = new RichTextBox(); + Assert.Equal(expected, control.CanPaste(format)); + Assert.True(control.IsHandleCreated); + } + + [WinFormsTheory] + [MemberData(nameof(CanPaste_TestData))] + public void RichTextBox_CanPaste_InvokeWithHandle_ReturnsExpected(DataFormats.Format format, bool expected) + { + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.Equal(expected, control.CanPaste(format)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + public static IEnumerable CanPaste_CustomCanPaste_TestData() + { + yield return new object[] { IntPtr.Zero, false }; + yield return new object[] { (IntPtr)1, true }; + } + + [WinFormsTheory] + [MemberData(nameof(CanPaste_CustomCanPaste_TestData))] + public void RichTextBox_CanPaste_CustomCanPaste_ReturnsExpected(IntPtr result, bool expected) + { + using var control = new CustomCanPasteRichTextBox + { + Result = result + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + Assert.Equal(expected, control.CanPaste(DataFormats.GetFormat(DataFormats.Text))); + } + + private class CustomCanPasteRichTextBox : RichTextBox + { + public IntPtr Result { get; set; } + + protected unsafe override void WndProc(ref Message m) + { + if (m.Msg == RichEditMessages.EM_CANPASTE) + { + m.Result = Result; + return; + } + + base.WndProc(ref m); + } + } + + [WinFormsFact] + public void RichTextBox_CanPaste_NullFormat_ThrowsNullReferenceException() + { + using var control = new RichTextBox(); + Assert.Throws(() => control.CanPaste(null)); + } + + public static IEnumerable Find_String_TestData() + { + yield return new object[] { string.Empty, string.Empty, -1 }; + yield return new object[] { string.Empty, "abc", -1 }; + + yield return new object[] { "abc", string.Empty, -1 }; + yield return new object[] { "abc", "a", 0 }; + yield return new object[] { "abc", "ab", 0 }; + yield return new object[] { "abc", "abc", 0 }; + yield return new object[] { "abc", "abcd", -1 }; + yield return new object[] { "abc", "b", 1 }; + yield return new object[] { "abc", "d", -1 }; + yield return new object[] { "abc", "ABC", 0 }; + + yield return new object[] { "aa", "a", 0 }; + yield return new object[] { "abc def", "ef", 5 }; + yield return new object[] { "abc def", "def", 4 }; + yield return new object[] { "abc def", " ", 3 }; + + yield return new object[] { "ab\u0640cd", "abcd", 0 }; + yield return new object[] { "ab\u0640cd", "\u0640", 2 }; + yield return new object[] { "ab\u0640cd", "bc", 1 }; + } + + [WinFormsTheory] + [MemberData(nameof(Find_String_TestData))] + public void RichTextBox_Find_String_ReturnsExpected(string text, string str, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.Equal(expected, control.Find(str)); + Assert.True(control.IsHandleCreated); + } + + public static IEnumerable Find_String_RichTextBoxFinds_TestData() + { + yield return new object[] { string.Empty, string.Empty, RichTextBoxFinds.None, -1 }; + yield return new object[] { string.Empty, "abc", RichTextBoxFinds.None, -1 }; + yield return new object[] { string.Empty, string.Empty, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { string.Empty, "abc", RichTextBoxFinds.Reverse, -1 }; + + yield return new object[] { "abc", string.Empty, RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "a", RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "a", RichTextBoxFinds.Reverse, 0 }; + yield return new object[] { "abc", "ab", RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "abc", RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "abcd", RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "b", RichTextBoxFinds.None, 1 }; + yield return new object[] { "abc", "d", RichTextBoxFinds.None, -1 }; + + yield return new object[] { "abc", "ABC", RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "abc", RichTextBoxFinds.MatchCase, 0 }; + yield return new object[] { "abc", "ABC", RichTextBoxFinds.MatchCase, -1 }; + + yield return new object[] { "aa", "a", RichTextBoxFinds.None, 0 }; + yield return new object[] { "aa", "a", RichTextBoxFinds.Reverse, 1 }; + yield return new object[] { "aa", string.Empty, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { "abc def", "ef", RichTextBoxFinds.None, 5 }; + yield return new object[] { "abc def", "def", RichTextBoxFinds.None, 4 }; + yield return new object[] { "abc def", " ", RichTextBoxFinds.None, 3 }; + yield return new object[] { "abc def", "ef", RichTextBoxFinds.WholeWord, -1 }; + yield return new object[] { "abc def", "def", RichTextBoxFinds.WholeWord, 4 }; + yield return new object[] { "abc def", " ", RichTextBoxFinds.WholeWord, -1 }; + + yield return new object[] { "ab\u0640cd", "abcd", RichTextBoxFinds.None, 0 }; + yield return new object[] { "ab\u0640cd", "\u0640", RichTextBoxFinds.None, 2 }; + yield return new object[] { "ab\u0640cd", "bc", RichTextBoxFinds.None, 1 }; + yield return new object[] { "ab\u0640cd", "abcd", RichTextBoxFinds.NoHighlight, 0 }; + yield return new object[] { "ab\u0640cd", "\u0640", RichTextBoxFinds.NoHighlight, 2 }; + yield return new object[] { "ab\u0640cd", "bc", RichTextBoxFinds.NoHighlight, 1 }; + yield return new object[] { "abcd", "abcd", RichTextBoxFinds.NoHighlight, 0 }; + } + + [WinFormsTheory] + [MemberData(nameof(Find_String_RichTextBoxFinds_TestData))] + public void RichTextBox_Find_StringRichTextBoxFinds_ReturnsExpected(string text, string str, RichTextBoxFinds options, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.Equal(expected, control.Find(str, options)); + Assert.True(control.IsHandleCreated); + } + + public static IEnumerable Find_String_Int_RichTextBoxFinds_TestData() + { + yield return new object[] { string.Empty, string.Empty, 0, RichTextBoxFinds.None, -1 }; + yield return new object[] { string.Empty, "abc", 0, RichTextBoxFinds.None, -1 }; + yield return new object[] { string.Empty, string.Empty, 0, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { string.Empty, "abc", 0, RichTextBoxFinds.Reverse, -1 }; + + yield return new object[] { "abc", string.Empty, 0, RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "a", 0, RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "a", 0, RichTextBoxFinds.Reverse, 0 }; + yield return new object[] { "abc", "ab", 0, RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "abc", 0, RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "abcd", 0, RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "b", 0, RichTextBoxFinds.None, 1 }; + yield return new object[] { "abc", "d", 0, RichTextBoxFinds.None, -1 }; + + yield return new object[] { "abc", "ABC", 0, RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "abc", 0, RichTextBoxFinds.MatchCase, 0 }; + yield return new object[] { "abc", "ABC", 0, RichTextBoxFinds.MatchCase, -1 }; + + yield return new object[] { "aa", "a", 0, RichTextBoxFinds.None, 0 }; + yield return new object[] { "aa", "a", 0, RichTextBoxFinds.Reverse, 1 }; + yield return new object[] { "aa", string.Empty, 0, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { "abc def", "ef", 0, RichTextBoxFinds.None, 5 }; + yield return new object[] { "abc def", "def", 0, RichTextBoxFinds.None, 4 }; + yield return new object[] { "abc def", " ", 0, RichTextBoxFinds.None, 3 }; + yield return new object[] { "abc def", "ef", 0, RichTextBoxFinds.WholeWord, -1 }; + yield return new object[] { "abc def", "def", 0, RichTextBoxFinds.WholeWord, 4 }; + yield return new object[] { "abc def", " ", 0, RichTextBoxFinds.WholeWord, -1 }; + + yield return new object[] { "abc", "a", 1, RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "a", 2, RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "c", 2, RichTextBoxFinds.None, 2 }; + yield return new object[] { "abc", "a", 1, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { "abc", "a", 2, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { "abc", "c", 2, RichTextBoxFinds.Reverse, 2 }; + + yield return new object[] { "ab\u0640cd", "abcd", 0, RichTextBoxFinds.None, 0 }; + yield return new object[] { "ab\u0640cd", "\u0640", 0, RichTextBoxFinds.None, 2 }; + yield return new object[] { "ab\u0640cd", "bc", 0, RichTextBoxFinds.None, 1 }; + yield return new object[] { "ab\u0640cd", "abcd", 0, RichTextBoxFinds.NoHighlight, 0 }; + yield return new object[] { "ab\u0640cd", "\u0640", 0, RichTextBoxFinds.NoHighlight, 2 }; + yield return new object[] { "ab\u0640cd", "bc", 0, RichTextBoxFinds.NoHighlight, 1 }; + yield return new object[] { "abcd", "abcd", 0, RichTextBoxFinds.NoHighlight, 0 }; + } + + [WinFormsTheory] + [MemberData(nameof(Find_String_Int_RichTextBoxFinds_TestData))] + public void RichTextBox_Find_StringIntRichTextBoxFinds_ReturnsExpected(string text, string str, int start, RichTextBoxFinds options, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.Equal(expected, control.Find(str, start, options)); + Assert.True(control.IsHandleCreated); + } + + public static IEnumerable Find_String_Int_Int_RichTextBoxFinds_TestData() + { + foreach (int end in new int[] { -1, 0 }) + { + yield return new object[] { string.Empty, string.Empty, 0, end, RichTextBoxFinds.None, -1 }; + yield return new object[] { string.Empty, "abc", 0, end, RichTextBoxFinds.None, -1 }; + yield return new object[] { string.Empty, string.Empty, 0, end, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { string.Empty, "abc", 0, end, RichTextBoxFinds.Reverse, -1 }; + + yield return new object[] { "abc", string.Empty, 0, end, RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "a", 0, end, RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "a", 0, end, RichTextBoxFinds.Reverse, 0 }; + yield return new object[] { "abc", "ab", 0, end, RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "abc", 0, end, RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "abcd", 0, end, RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "b", 0, end, RichTextBoxFinds.None, 1 }; + yield return new object[] { "abc", "d", 0, end, RichTextBoxFinds.None, -1 }; + + yield return new object[] { "abc", "ABC", 0, end, RichTextBoxFinds.None, 0 }; + yield return new object[] { "abc", "abc", 0, end, RichTextBoxFinds.MatchCase, 0 }; + yield return new object[] { "abc", "ABC", 0, end, RichTextBoxFinds.MatchCase, -1 }; + + yield return new object[] { "aa", "a", 0, end, RichTextBoxFinds.None, 0 }; + yield return new object[] { "aa", "a", 0, end, RichTextBoxFinds.Reverse, 1 }; + yield return new object[] { "abc", string.Empty, 0, end, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { "abc def", "ef", 0, end, RichTextBoxFinds.None, 5 }; + yield return new object[] { "abc def", "def", 0, end, RichTextBoxFinds.None, 4 }; + yield return new object[] { "abc def", " ", 0, end, RichTextBoxFinds.None, 3 }; + yield return new object[] { "abc def", "ef", 0, end, RichTextBoxFinds.WholeWord, -1 }; + yield return new object[] { "abc def", "def", 0, end, RichTextBoxFinds.WholeWord, 4 }; + yield return new object[] { "abc def", " ", 0, end, RichTextBoxFinds.WholeWord, -1 }; + + yield return new object[] { "ab\u0640cd", "abcd", 0, end, RichTextBoxFinds.None, 0 }; + yield return new object[] { "ab\u0640cd", "\u0640", 0, end, RichTextBoxFinds.None, 2 }; + yield return new object[] { "ab\u0640cd", "bc", 0, end, RichTextBoxFinds.None, 1 }; + yield return new object[] { "ab\u0640cd", "abcd", 0, end, RichTextBoxFinds.NoHighlight, 0 }; + yield return new object[] { "ab\u0640cd", "\u0640", 0, end, RichTextBoxFinds.NoHighlight, 2 }; + yield return new object[] { "ab\u0640cd", "bc", 0, end, RichTextBoxFinds.NoHighlight, 1 }; + yield return new object[] { "abcd", "abcd", 0, end, RichTextBoxFinds.NoHighlight, 0 }; + } + + yield return new object[] { "abc", "a", 1, 3, RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "a", 2, 3, RichTextBoxFinds.None, -1 }; + yield return new object[] { "abc", "c", 2, 3, RichTextBoxFinds.None, 2 }; + yield return new object[] { "abc", "a", 1, 3, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { "abc", "a", 2, 3, RichTextBoxFinds.Reverse, -1 }; + yield return new object[] { "abc", "c", 2, 3, RichTextBoxFinds.Reverse, 2 }; + + yield return new object[] { "abc", "c", 0, 5, RichTextBoxFinds.None, 2 }; + yield return new object[] { "abc", "c", 0, 2, RichTextBoxFinds.None, -1 }; + } + + [WinFormsTheory] + [MemberData(nameof(Find_String_Int_Int_RichTextBoxFinds_TestData))] + public void RichTextBox_Find_StringIntIntRichTextBoxFinds_ReturnsExpected(string text, string str, int start, int end, RichTextBoxFinds options, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.Equal(expected, control.Find(str, start, end, options)); + Assert.True(control.IsHandleCreated); + } + + [WinFormsTheory] + [MemberData(nameof(Find_String_TestData))] + public void RichTextBox_Find_StringWithHandle_ReturnsExpectedd(string text, string str, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.Equal(expected, control.Find(str)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [MemberData(nameof(Find_String_RichTextBoxFinds_TestData))] + public void RichTextBox_Find_StringRichTextBoxFindsWithHandle_ReturnsExpectedd(string text, string str, RichTextBoxFinds options, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.Equal(expected, control.Find(str, options)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [MemberData(nameof(Find_String_Int_RichTextBoxFinds_TestData))] + public void RichTextBox_Find_StringIntRichTextBoxFindsWithHandle_ReturnsExpectedd(string text, string str, int start, RichTextBoxFinds options, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.Equal(expected, control.Find(str, start, options)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [MemberData(nameof(Find_String_Int_Int_RichTextBoxFinds_TestData))] + public void RichTextBox_Find_StringIntIntRichTextBoxFindsWithHandle_ReturnsExpectedd(string text, string str, int start, int end, RichTextBoxFinds options, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.Equal(expected, control.Find(str, start, end, options)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + public static IEnumerable Find_CharArray_TestData() + { + yield return new object[] { string.Empty, new char[0], -1 }; + yield return new object[] { string.Empty, new char[] { 'a', 'b', 'c' }, -1 }; + + yield return new object[] { "abc", new char[0], -1 }; + yield return new object[] { "abc", new char[] { 'a' }, 0 }; + yield return new object[] { "abc", new char[] { 'a', 'b' }, 0 }; + yield return new object[] { "abc", new char[] { 'a', 'b', 'c' }, 0 }; + yield return new object[] { "abc", new char[] { 'a', 'b', 'c', 'd' }, 0 }; + yield return new object[] { "abc", new char[] { 'c', 'b', 'a' }, 0 }; + yield return new object[] { "abc", new char[] { 'c', 'b' }, 1 }; + yield return new object[] { "abc", new char[] { 'b' }, 1 }; + yield return new object[] { "abc", new char[] { 'd' }, -1 }; + yield return new object[] { "abc", new char[] { 'A', 'B', 'C' }, -1 }; + + yield return new object[] { "aa", new char[] { 'a' }, 0 }; + yield return new object[] { "abc def", new char[] { 'e', 'f' }, 5 }; + yield return new object[] { "abc def", new char[] { 'd', 'e', 'f' }, 4 }; + yield return new object[] { "abc def", new char[] { ' ' }, 3 }; + + yield return new object[] { "ab\u0640cd", new char[] { 'a', 'b', 'c', 'd' }, 0 }; + yield return new object[] { "ab\u0640cd", new char[] { '\u0640' }, 2 }; + yield return new object[] { "ab\u0640cd", new char[] { 'b', 'c' }, 1 }; + } + + [WinFormsTheory] + [MemberData(nameof(Find_CharArray_TestData))] + public void RichTextBox_Find_CharArray_ReturnsExpected(string text, char[] characterSet, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.Equal(expected, control.Find(characterSet)); + Assert.True(control.IsHandleCreated); + } + + public static IEnumerable Find_CharArray_Int_TestData() + { + yield return new object[] { string.Empty, new char[0], 0, -1 }; + yield return new object[] { string.Empty, new char[] { 'a', 'b', 'c' }, 0, -1 }; + + yield return new object[] { "abc", new char[0], 0, -1 }; + yield return new object[] { "abc", new char[] { 'a' },0, 0 }; + yield return new object[] { "abc", new char[] { 'a', 'b' },0, 0 }; + yield return new object[] { "abc", new char[] { 'a', 'b', 'c' },0, 0 }; + yield return new object[] { "abc", new char[] { 'a', 'b', 'c', 'd' },0, 0 }; + yield return new object[] { "abc", new char[] { 'c', 'b', 'a' },0, 0 }; + yield return new object[] { "abc", new char[] { 'c', 'b' },0, 1 }; + yield return new object[] { "abc", new char[] { 'b' },0, 1 }; + yield return new object[] { "abc", new char[] { 'd' }, 0, -1 }; + yield return new object[] { "abc", new char[] { 'A', 'B', 'C' }, 0, -1 }; + + yield return new object[] { "aa", new char[] { 'a' }, 0, 0 }; + yield return new object[] { "abc def", new char[] { 'e', 'f' }, 0, 5 }; + yield return new object[] { "abc def", new char[] { 'd', 'e', 'f' }, 0, 4 }; + yield return new object[] { "abc def", new char[] { ' ' }, 0, 3 }; + + yield return new object[] { "ab\u0640cd", new char[] { 'a', 'b', 'c', 'd' }, 0, 0 }; + yield return new object[] { "ab\u0640cd", new char[] { '\u0640' }, 0, 2 }; + yield return new object[] { "ab\u0640cd", new char[] { 'b', 'c' }, 0, 1 }; + + yield return new object[] { "abc", new char[] { 'a' }, 1, -1 }; + yield return new object[] { "abc", new char[] { 'a' }, 2, -1 }; + yield return new object[] { "abc", new char[] { 'c' }, 2, 2 }; + } + + [WinFormsTheory] + [MemberData(nameof(Find_CharArray_Int_TestData))] + public void RichTextBox_Find_CharArrayInt_ReturnsExpected(string text, char[] characterSet, int start, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.Equal(expected, control.Find(characterSet, start)); + Assert.True(control.IsHandleCreated); + } + + public static IEnumerable Find_CharArray_Int_Int_TestData() + { + foreach (int end in new int[] { -1, 0 }) + { + yield return new object[] { string.Empty, new char[0], 0, end, -1 }; + yield return new object[] { string.Empty, new char[] { 'a', 'b', 'c' }, 0, end, -1 }; + + yield return new object[] { "abc", new char[0], 0, end, -1 }; + yield return new object[] { "abc", new char[] { 'a' },0, end, 0 }; + yield return new object[] { "abc", new char[] { 'a', 'b' },0, end, 0 }; + yield return new object[] { "abc", new char[] { 'a', 'b', 'c' },0, end, 0 }; + yield return new object[] { "abc", new char[] { 'a', 'b', 'c', 'd' },0, end, 0 }; + yield return new object[] { "abc", new char[] { 'c', 'b', 'a' },0, end, 0 }; + yield return new object[] { "abc", new char[] { 'c', 'b' },0, end, 1 }; + yield return new object[] { "abc", new char[] { 'b' },0, end, 1 }; + yield return new object[] { "abc", new char[] { 'd' }, 0, end, -1 }; + yield return new object[] { "abc", new char[] { 'A', 'B', 'C' }, 0, end, -1 }; + + yield return new object[] { "aa", new char[] { 'a' }, 0, end, 0 }; + yield return new object[] { "abc def", new char[] { 'e', 'f' }, 0, end, 5 }; + yield return new object[] { "abc def", new char[] { 'd', 'e', 'f' }, 0, end, 4 }; + yield return new object[] { "abc def", new char[] { ' ' }, 0, end, 3 }; + + yield return new object[] { "ab\u0640cd", new char[] { 'a', 'b', 'c', 'd' }, 0, end, 0 }; + yield return new object[] { "ab\u0640cd", new char[] { '\u0640' }, 0, end, 2 }; + yield return new object[] { "ab\u0640cd", new char[] { 'b', 'c' }, 0, end, 1 }; + } + + yield return new object[] { "abc", new char[] { 'a' }, 1, 3, -1 }; + yield return new object[] { "abc", new char[] { 'a' }, 2, 3, -1 }; + yield return new object[] { "abc", new char[] { 'c' }, 2, 3, 2 }; + + yield return new object[] { "abc", new char[] { 'c' }, 0, 5, 2 }; + yield return new object[] { "abc", new char[] { 'c' }, 0, 2, -1 }; + } + + [WinFormsTheory] + [MemberData(nameof(Find_CharArray_Int_Int_TestData))] + public void RichTextBox_Find_CharArrayIntInt_ReturnsExpected(string text, char[] characterSet, int start, int end, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.Equal(expected, control.Find(characterSet, start, end)); + Assert.True(control.IsHandleCreated); + } + + [WinFormsTheory] + [MemberData(nameof(Find_CharArray_TestData))] + public void RichTextBox_Find_CharArrayWithHandle_ReturnsExpected(string text, char[] characterSet, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.Equal(expected, control.Find(characterSet)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [MemberData(nameof(Find_CharArray_Int_TestData))] + public void RichTextBox_Find_CharArrayIntWithHandle_ReturnsExpected(string text, char[] characterSet, int start, int expected) + { + using var control = new RichTextBox + { + Text = text + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.Equal(expected, control.Find(characterSet, start)); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable UndoActionName_CustomGetUndoName_TestData() - { - yield return new object[] { IntPtr.Zero, IntPtr.Zero, string.Empty }; - yield return new object[] { (IntPtr)1, IntPtr.Zero, "Unknown" }; - yield return new object[] { (IntPtr)1, (IntPtr)1, "Typing" }; - yield return new object[] { (IntPtr)1, (IntPtr)2, "Delete" }; - yield return new object[] { (IntPtr)1, (IntPtr)3, "Drag and Drop" }; - yield return new object[] { (IntPtr)1, (IntPtr)4, "Cut" }; - yield return new object[] { (IntPtr)1, (IntPtr)5, "Paste" }; - yield return new object[] { (IntPtr)1, (IntPtr)6, "Unknown" }; - yield return new object[] { (IntPtr)1, (IntPtr)7, "Unknown" }; - } - [WinFormsTheory] - [MemberData(nameof(UndoActionName_CustomGetUndoName_TestData))] - public void RichTextBox_UndoActionName_CustomGetUndoName_ReturnsExpected(IntPtr canUndoResult, IntPtr getUndoNameResult, string expected) + [MemberData(nameof(Find_CharArray_Int_Int_TestData))] + public void RichTextBox_Find_CharArrayIntIntWithHandle_ReturnsExpected(string text, char[] characterSet, int start, int end, int expected) { - using var control = new CustomGetUndoNameRichTextBox + using var control = new RichTextBox { - CanUndoResult = canUndoResult, - GetUndoNameResult = getUndoNameResult + Text = text }; Assert.NotEqual(IntPtr.Zero, control.Handle); - Assert.Equal(expected, control.UndoActionName); - } - - private class CustomGetUndoNameRichTextBox : RichTextBox - { - public IntPtr CanUndoResult { get; set; } - public IntPtr GetUndoNameResult { get; set; } - - protected unsafe override void WndProc(ref Message m) - { - if (m.Msg == (int)User32.EM.CANUNDO) - { - m.Result = CanUndoResult; - return; - } - else if (m.Msg == RichEditMessages.EM_GETUNDONAME) - { - m.Result = GetUndoNameResult; - return; - } - - base.WndProc(ref m); - } - } - - [WinFormsFact] - public void RichTextBox_ZoomFactor_GetWithHandle_ReturnsExpected() - { - using var control = new RichTextBox(); - Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; int styleChangedCallCount = 0; @@ -2715,146 +3986,162 @@ public void RichTextBox_ZoomFactor_GetWithHandle_ReturnsExpected() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(1, control.ZoomFactor); + Assert.Equal(expected, control.Find(characterSet, start, end)); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); + } - // Call EM_SETZOOM. - User32.SendMessageW(control.Handle, (User32.WM)RichEditMessages.EM_SETZOOM, (IntPtr)2, (IntPtr)10); - Assert.Equal(0.2f, control.ZoomFactor); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + [WinFormsFact] + public void RichTextBox_Find_NullStrEmpty_ThrowsArgumentNullException() + { + using var control = new RichTextBox(); + Assert.Throws("str", () => control.Find((string)null)); + Assert.Throws("str", () => control.Find(null, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 0, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, -1, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 1, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 0, 0, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, -1, 0, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 1, 0, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 0, -2, RichTextBoxFinds.None)); } - [WinFormsTheory] - [InlineData(1, 1, 1.0f)] - [InlineData(10, 1, 10.0f)] - [InlineData(10, 2, 5.0f)] - [InlineData(1, 10, 0.1f)] - [InlineData(1, 0, 1f)] - [InlineData(0, 1, 1f)] - [InlineData(0, 0, 1f)] - public void RichTextBox_ZoomFactor_CustomGetZoom_ReturnsExpected(int numerator, int denominator, float expected) + [WinFormsFact] + public void RichTextBox_Find_NullStrNotEmpty_ThrowsArgumentNullException() { - using var control = new CustomGetZoomRichTextBox + using var control = new RichTextBox { - NumeratorResult = numerator, - DenominatorResult = denominator + Text = "t" }; - Assert.NotEqual(IntPtr.Zero, control.Handle); - Assert.Equal(expected, control.ZoomFactor); + Assert.Throws("str", () => control.Find((string)null)); + Assert.Throws("str", () => control.Find(null, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 0, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, -1, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 2, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 0, 0, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, -1, 0, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 2, 0, RichTextBoxFinds.None)); + Assert.Throws("str", () => control.Find(null, 0, -2, RichTextBoxFinds.None)); } - private class CustomGetZoomRichTextBox : RichTextBox + [WinFormsFact] + public void RichTextBox_Find_NullCharacterSetEmpty_ThrowsArgumentNullException() { - public int NumeratorResult { get; set; } - public int DenominatorResult { get; set; } + using var control = new RichTextBox(); + Assert.Throws("characterSet", () => control.Find((char[])null)); + Assert.Throws("characterSet", () => control.Find(null, 0)); + Assert.Throws("characterSet", () => control.Find(null, -1)); + Assert.Throws("characterSet", () => control.Find(null, 1)); + Assert.Throws("characterSet", () => control.Find(null, 0, 0)); + Assert.Throws("characterSet", () => control.Find(null, -1, 0)); + Assert.Throws("characterSet", () => control.Find(null, 1, 0)); + Assert.Throws("characterSet", () => control.Find(null, 0, -2)); + } - protected unsafe override void WndProc(ref Message m) + [WinFormsFact] + public void RichTextBox_Find_NullCharacterSetNotEmpty_ThrowsArgumentNullException() + { + using var control = new RichTextBox { - if (m.Msg == RichEditMessages.EM_GETZOOM) - { - int* pNumerator = (int*)m.WParam; - int* pDenominator = (int*)m.LParam; - - *pNumerator = NumeratorResult; - *pDenominator = DenominatorResult; - return; - } + Text = "t" + }; + Assert.Throws("characterSet", () => control.Find((char[])null)); + Assert.Throws("characterSet", () => control.Find(null, 0)); + Assert.Throws("characterSet", () => control.Find(null, -1)); + Assert.Throws("characterSet", () => control.Find(null, 2)); + Assert.Throws("characterSet", () => control.Find(null, 0, 0)); + Assert.Throws("characterSet", () => control.Find(null, -1, 0)); + Assert.Throws("characterSet", () => control.Find(null, 2, 0)); + Assert.Throws("characterSet", () => control.Find(null, 0, -2)); + } - base.WndProc(ref m); - } + [WinFormsTheory] + [InlineData(-1)] + [InlineData(1)] + public void RichTextBox_Find_InvalidStartEmpty_ThrowsArgumentOutOfRangeException(int start) + { + using var control = new RichTextBox(); + Assert.Throws("start", () => control.Find("s", start, RichTextBoxFinds.NoHighlight)); + Assert.Throws("start", () => control.Find("s", start, 0, RichTextBoxFinds.NoHighlight)); + Assert.Throws("start", () => control.Find(new char[] { 's' }, start)); + Assert.Throws("start", () => control.Find(new char[] { 's' }, start, 0)); } [WinFormsTheory] - [InlineData(0.015626f, 0.016f)] - [InlineData(63.9f, 63.9f)] - [InlineData(1.0f, 1.0f)] - [InlineData(2.0f, 2.0f)] - [InlineData(float.NaN, -2147483.75f)] - public void RichTextBox_ZoomFactor_Set_GetReturnsExpected(float value, float expected) + [InlineData(-1)] + [InlineData(2)] + public void RichTextBox_Find_InvalidStartNotEmpty_ThrowsArgumentOutOfRangeException(int start) { using var control = new RichTextBox { - ZoomFactor = value + Text = "t" }; - Assert.Equal(expected, control.ZoomFactor, 2); - Assert.False(control.IsHandleCreated); - - // Set same. - control.ZoomFactor = value; - Assert.Equal(expected, control.ZoomFactor, 2); - Assert.False(control.IsHandleCreated); + Assert.Throws("start", () => control.Find("s", start, RichTextBoxFinds.NoHighlight)); + Assert.Throws("start", () => control.Find("s", start, 0, RichTextBoxFinds.NoHighlight)); + Assert.Throws("start", () => control.Find(new char[] { 's' }, start)); + Assert.Throws("start", () => control.Find(new char[] { 's' }, start, 0)); } - [WinFormsTheory] - [InlineData(0.015626f, 0.016f)] - [InlineData(63.9f, 63.9f)] - [InlineData(1.0f, 1.0f)] - [InlineData(2.0f, 2.0f)] - [InlineData(float.NaN, 1.0f)] - public void RichTextBox_ZoomFactor_SetWithHandle_GetReturnsExpected(float value, float expected) + [WinFormsFact] + public void RichTextBox_Find_InvalidEndEmpty_ThrowsArgumentOutOfRangeException() { using var control = new RichTextBox(); - Assert.NotEqual(IntPtr.Zero, control.Handle); - int invalidatedCallCount = 0; - control.Invalidated += (sender, e) => invalidatedCallCount++; - int styleChangedCallCount = 0; - control.StyleChanged += (sender, e) => styleChangedCallCount++; - int createdCallCount = 0; - control.HandleCreated += (sender, e) => createdCallCount++; - - control.ZoomFactor = value; - Assert.Equal(expected, control.ZoomFactor); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + Assert.Throws("end", () => control.Find("s", 0, -2, RichTextBoxFinds.NoHighlight)); + Assert.Throws("end", () => control.Find(new char[] { 's' }, 0, -2)); + } - // Set same. - control.ZoomFactor = value; - Assert.Equal(expected, control.ZoomFactor); - Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + [WinFormsFact] + public void RichTextBox_Find_InvalidEndNotEmpty_ThrowsArgumentOutOfRangeException() + { + using var control = new RichTextBox + { + Text = "t" + }; + Assert.Throws("end", () => control.Find("s", 0, -2, RichTextBoxFinds.NoHighlight)); + Assert.Throws("end", () => control.Find(new char[] { 's' }, 0, -2)); } - [WinFormsTheory] - [InlineData(0.015624f)] - [InlineData(0.015625f)] - [InlineData(64.0f)] - [InlineData(64.1f)] - [InlineData(float.PositiveInfinity)] - [InlineData(float.NegativeInfinity)] - public void RichTextBox_ZoomFactor_SetInvalidValue_ThrowsArgumentOutOfRangeException(float value) + [WinFormsFact] + public void RichTextBox_Find_StartGreaterThanEnd_ThrowsArgumentOutOfRangeException() { - using var control = new RichTextBox(); - Assert.Throws("value", () => control.ZoomFactor = value); + using var control = new RichTextBox + { + Text = "t" + }; + Assert.Throws(null, () => control.Find("s", 1, 0, RichTextBoxFinds.None)); + Assert.Throws(null, () => control.Find("s", 1, 0, RichTextBoxFinds.Reverse)); + Assert.Throws("end", () => control.Find(new char[] { 's' }, 1, 0)); + Assert.Throws("end", () => control.Find(new char[] { 's' }, 1, 0)); } - public static IEnumerable CanPaste_TestData() + [WinFormsFact] + public void RichTextBox_LoadFile_InvokePlainTextEmpty_Success() { - yield return new object[] { DataFormats.GetFormat(DataFormats.Palette), false }; - yield return new object[] { new DataFormats.Format("UnknownName", int.MaxValue), false }; + using var control = new RichTextBox(); + using var stream = new MemoryStream(); + control.LoadFile(stream, RichTextBoxStreamType.PlainText); + Assert.Empty(control.Text); + Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(CanPaste_TestData))] - public void RichTextBox_CanPaste_Invoke_ReturnsExpected(DataFormats.Format format, bool expected) + [WinFormsFact] + public void RichTextBox_LoadFile_InvokePlainTextNotEmpty_Success() { using var control = new RichTextBox(); - Assert.Equal(expected, control.CanPaste(format)); + using var stream = new MemoryStream(); + byte[] buffer = Encoding.ASCII.GetBytes("Hello World"); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; + + control.LoadFile(stream, RichTextBoxStreamType.PlainText); + Assert.Equal("Hello World", control.Text); Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(CanPaste_TestData))] - public void RichTextBox_CanPaste_InvokeWithHandle_ReturnsExpected(DataFormats.Format format, bool expected) + [WinFormsFact] + public void RichTextBox_LoadFile_InvokePlainTextEmptyWithHandle_Success() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -2865,317 +4152,267 @@ public void RichTextBox_CanPaste_InvokeWithHandle_ReturnsExpected(DataFormats.Fo int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(expected, control.CanPaste(format)); + using var stream = new MemoryStream(); + control.LoadFile(stream, RichTextBoxStreamType.PlainText); + Assert.Empty(control.Text); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable CanPaste_CustomCanPaste_TestData() - { - yield return new object[] { IntPtr.Zero, false }; - yield return new object[] { (IntPtr)1, true }; - } - - [WinFormsTheory] - [MemberData(nameof(CanPaste_CustomCanPaste_TestData))] - public void RichTextBox_CanPaste_CustomCanPaste_ReturnsExpected(IntPtr result, bool expected) + [WinFormsFact] + public void RichTextBox_LoadFile_InvokePlainTextNotEmptyWithHandle_Success() { - using var control = new CustomCanPasteRichTextBox - { - Result = result - }; + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); - Assert.Equal(expected, control.CanPaste(DataFormats.GetFormat(DataFormats.Text))); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + using var stream = new MemoryStream(); + byte[] buffer = Encoding.ASCII.GetBytes("Hello World"); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; + control.LoadFile(stream, RichTextBoxStreamType.PlainText); + Assert.Equal("Hello World", control.Text); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - private class CustomCanPasteRichTextBox : RichTextBox + [WinFormsFact] + public void RichTextBox_LoadFile_InvokePlainTextWithRtf_Success() { - public IntPtr Result { get; set; } - - protected unsafe override void WndProc(ref Message m) + using var control = new RichTextBox { - if (m.Msg == RichEditMessages.EM_CANPASTE) - { - m.Result = Result; - return; - } + Rtf = "{\\rtf1OldText}" + }; + using var stream = new MemoryStream(); + byte[] buffer = Encoding.ASCII.GetBytes("Hello World"); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; - base.WndProc(ref m); - } + control.LoadFile(stream, RichTextBoxStreamType.PlainText); + Assert.Equal("Hello World", control.Text); + Assert.DoesNotContain("OldText", control.Rtf); + Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_CanPaste_NullFormat_ThrowsNullReferenceException() + public void RichTextBox_LoadFile_InvokeUnicodeTextEmpty_Success() { using var control = new RichTextBox(); - Assert.Throws(() => control.CanPaste(null)); + using var stream = new MemoryStream(); + control.LoadFile(stream, RichTextBoxStreamType.UnicodePlainText); + Assert.Empty(control.Text); + Assert.True(control.IsHandleCreated); } - public static IEnumerable Find_String_TestData() + [WinFormsFact] + public void RichTextBox_LoadFile_InvokeUnicodeTextNotEmpty_Success() { - yield return new object[] { string.Empty, string.Empty, -1 }; - yield return new object[] { string.Empty, "abc", -1 }; - - yield return new object[] { "abc", string.Empty, -1 }; - yield return new object[] { "abc", "a", 0 }; - yield return new object[] { "abc", "ab", 0 }; - yield return new object[] { "abc", "abc", 0 }; - yield return new object[] { "abc", "abcd", -1 }; - yield return new object[] { "abc", "b", 1 }; - yield return new object[] { "abc", "d", -1 }; - yield return new object[] { "abc", "ABC", 0 }; - - yield return new object[] { "aa", "a", 0 }; - yield return new object[] { "abc def", "ef", 5 }; - yield return new object[] { "abc def", "def", 4 }; - yield return new object[] { "abc def", " ", 3 }; + using var control = new RichTextBox(); + using var stream = new MemoryStream(); + byte[] buffer = Encoding.Unicode.GetBytes("Hello World"); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; - yield return new object[] { "ab\u0640cd", "abcd", 0 }; - yield return new object[] { "ab\u0640cd", "\u0640", 2 }; - yield return new object[] { "ab\u0640cd", "bc", 1 }; + control.LoadFile(stream, RichTextBoxStreamType.UnicodePlainText); + Assert.Equal("Hello World", control.Text); + Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(Find_String_TestData))] - public void RichTextBox_Find_String_ReturnsExpected(string text, string str, int expected) + [WinFormsFact] + public void RichTextBox_LoadFile_InvokeUnicodeTextEmptyWithHandle_Success() { - using var control = new RichTextBox - { - Text = text - }; - Assert.Equal(expected, control.Find(str)); + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + using var stream = new MemoryStream(); + control.LoadFile(stream, RichTextBoxStreamType.UnicodePlainText); + Assert.Empty(control.Text); Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - public static IEnumerable Find_String_RichTextBoxFinds_TestData() + [WinFormsFact] + public void RichTextBox_LoadFile_InvokeUnicodeTextNotEmptyWithHandle_Success() { - yield return new object[] { string.Empty, string.Empty, RichTextBoxFinds.None, -1 }; - yield return new object[] { string.Empty, "abc", RichTextBoxFinds.None, -1 }; - yield return new object[] { string.Empty, string.Empty, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { string.Empty, "abc", RichTextBoxFinds.Reverse, -1 }; - - yield return new object[] { "abc", string.Empty, RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "a", RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "a", RichTextBoxFinds.Reverse, 0 }; - yield return new object[] { "abc", "ab", RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "abc", RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "abcd", RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "b", RichTextBoxFinds.None, 1 }; - yield return new object[] { "abc", "d", RichTextBoxFinds.None, -1 }; - - yield return new object[] { "abc", "ABC", RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "abc", RichTextBoxFinds.MatchCase, 0 }; - yield return new object[] { "abc", "ABC", RichTextBoxFinds.MatchCase, -1 }; - - yield return new object[] { "aa", "a", RichTextBoxFinds.None, 0 }; - yield return new object[] { "aa", "a", RichTextBoxFinds.Reverse, 1 }; - yield return new object[] { "aa", string.Empty, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { "abc def", "ef", RichTextBoxFinds.None, 5 }; - yield return new object[] { "abc def", "def", RichTextBoxFinds.None, 4 }; - yield return new object[] { "abc def", " ", RichTextBoxFinds.None, 3 }; - yield return new object[] { "abc def", "ef", RichTextBoxFinds.WholeWord, -1 }; - yield return new object[] { "abc def", "def", RichTextBoxFinds.WholeWord, 4 }; - yield return new object[] { "abc def", " ", RichTextBoxFinds.WholeWord, -1 }; + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - yield return new object[] { "ab\u0640cd", "abcd", RichTextBoxFinds.None, 0 }; - yield return new object[] { "ab\u0640cd", "\u0640", RichTextBoxFinds.None, 2 }; - yield return new object[] { "ab\u0640cd", "bc", RichTextBoxFinds.None, 1 }; - yield return new object[] { "ab\u0640cd", "abcd", RichTextBoxFinds.NoHighlight, 0 }; - yield return new object[] { "ab\u0640cd", "\u0640", RichTextBoxFinds.NoHighlight, 2 }; - yield return new object[] { "ab\u0640cd", "bc", RichTextBoxFinds.NoHighlight, 1 }; - yield return new object[] { "abcd", "abcd", RichTextBoxFinds.NoHighlight, 0 }; + using var stream = new MemoryStream(); + byte[] buffer = Encoding.Unicode.GetBytes("Hello World"); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; + control.LoadFile(stream, RichTextBoxStreamType.UnicodePlainText); + Assert.Equal("Hello World", control.Text); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [MemberData(nameof(Find_String_RichTextBoxFinds_TestData))] - public void RichTextBox_Find_StringRichTextBoxFinds_ReturnsExpected(string text, string str, RichTextBoxFinds options, int expected) + [WinFormsFact] + public void RichTextBox_LoadFile_InvokeUnicodeTextWithRtf_Success() { using var control = new RichTextBox { - Text = text + Rtf = "{\\rtf1OldText}" }; - Assert.Equal(expected, control.Find(str, options)); + using var stream = new MemoryStream(); + byte[] buffer = Encoding.Unicode.GetBytes("Hello World"); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; + + control.LoadFile(stream, RichTextBoxStreamType.UnicodePlainText); + Assert.Equal("Hello World", control.Text); + Assert.DoesNotContain("OldText", control.Rtf); Assert.True(control.IsHandleCreated); } - public static IEnumerable Find_String_Int_RichTextBoxFinds_TestData() + [WinFormsFact] + public void RichTextBox_LoadFile_InvokeRichTextNotEmpty_Success() { - yield return new object[] { string.Empty, string.Empty, 0, RichTextBoxFinds.None, -1 }; - yield return new object[] { string.Empty, "abc", 0, RichTextBoxFinds.None, -1 }; - yield return new object[] { string.Empty, string.Empty, 0, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { string.Empty, "abc", 0, RichTextBoxFinds.Reverse, -1 }; - - yield return new object[] { "abc", string.Empty, 0, RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "a", 0, RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "a", 0, RichTextBoxFinds.Reverse, 0 }; - yield return new object[] { "abc", "ab", 0, RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "abc", 0, RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "abcd", 0, RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "b", 0, RichTextBoxFinds.None, 1 }; - yield return new object[] { "abc", "d", 0, RichTextBoxFinds.None, -1 }; - - yield return new object[] { "abc", "ABC", 0, RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "abc", 0, RichTextBoxFinds.MatchCase, 0 }; - yield return new object[] { "abc", "ABC", 0, RichTextBoxFinds.MatchCase, -1 }; - - yield return new object[] { "aa", "a", 0, RichTextBoxFinds.None, 0 }; - yield return new object[] { "aa", "a", 0, RichTextBoxFinds.Reverse, 1 }; - yield return new object[] { "aa", string.Empty, 0, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { "abc def", "ef", 0, RichTextBoxFinds.None, 5 }; - yield return new object[] { "abc def", "def", 0, RichTextBoxFinds.None, 4 }; - yield return new object[] { "abc def", " ", 0, RichTextBoxFinds.None, 3 }; - yield return new object[] { "abc def", "ef", 0, RichTextBoxFinds.WholeWord, -1 }; - yield return new object[] { "abc def", "def", 0, RichTextBoxFinds.WholeWord, 4 }; - yield return new object[] { "abc def", " ", 0, RichTextBoxFinds.WholeWord, -1 }; - - yield return new object[] { "abc", "a", 1, RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "a", 2, RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "c", 2, RichTextBoxFinds.None, 2 }; - yield return new object[] { "abc", "a", 1, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { "abc", "a", 2, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { "abc", "c", 2, RichTextBoxFinds.Reverse, 2 }; + using var control = new RichTextBox(); + using var stream = new MemoryStream(); + byte[] buffer = Encoding.ASCII.GetBytes("{\\rtf1Hello World}"); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; - yield return new object[] { "ab\u0640cd", "abcd", 0, RichTextBoxFinds.None, 0 }; - yield return new object[] { "ab\u0640cd", "\u0640", 0, RichTextBoxFinds.None, 2 }; - yield return new object[] { "ab\u0640cd", "bc", 0, RichTextBoxFinds.None, 1 }; - yield return new object[] { "ab\u0640cd", "abcd", 0, RichTextBoxFinds.NoHighlight, 0 }; - yield return new object[] { "ab\u0640cd", "\u0640", 0, RichTextBoxFinds.NoHighlight, 2 }; - yield return new object[] { "ab\u0640cd", "bc", 0, RichTextBoxFinds.NoHighlight, 1 }; - yield return new object[] { "abcd", "abcd", 0, RichTextBoxFinds.NoHighlight, 0 }; + control.LoadFile(stream, RichTextBoxStreamType.RichText); + Assert.Equal("Hello World", control.Text); + Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(Find_String_Int_RichTextBoxFinds_TestData))] - public void RichTextBox_Find_StringIntRichTextBoxFinds_ReturnsExpected(string text, string str, int start, RichTextBoxFinds options, int expected) + [WinFormsFact] + public void RichTextBox_LoadFile_InvokeRichTextWithRtf_Success() { using var control = new RichTextBox { - Text = text + Rtf = "{\\rtf1OldText}" }; - Assert.Equal(expected, control.Find(str, start, options)); + using var stream = new MemoryStream(); + byte[] buffer = Encoding.ASCII.GetBytes("{\\rtf1Hello World}"); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; + + control.LoadFile(stream, RichTextBoxStreamType.RichText); + Assert.Equal("Hello World", control.Text); + Assert.DoesNotContain("OldText", control.Rtf); Assert.True(control.IsHandleCreated); } - public static IEnumerable Find_String_Int_Int_RichTextBoxFinds_TestData() + [WinFormsFact] + public void RichTextBox_LoadFile_NullData_ThrowsArgumentNullException() { - foreach (int end in new int[] { -1, 0 }) - { - yield return new object[] { string.Empty, string.Empty, 0, end, RichTextBoxFinds.None, -1 }; - yield return new object[] { string.Empty, "abc", 0, end, RichTextBoxFinds.None, -1 }; - yield return new object[] { string.Empty, string.Empty, 0, end, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { string.Empty, "abc", 0, end, RichTextBoxFinds.Reverse, -1 }; - - yield return new object[] { "abc", string.Empty, 0, end, RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "a", 0, end, RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "a", 0, end, RichTextBoxFinds.Reverse, 0 }; - yield return new object[] { "abc", "ab", 0, end, RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "abc", 0, end, RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "abcd", 0, end, RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "b", 0, end, RichTextBoxFinds.None, 1 }; - yield return new object[] { "abc", "d", 0, end, RichTextBoxFinds.None, -1 }; - - yield return new object[] { "abc", "ABC", 0, end, RichTextBoxFinds.None, 0 }; - yield return new object[] { "abc", "abc", 0, end, RichTextBoxFinds.MatchCase, 0 }; - yield return new object[] { "abc", "ABC", 0, end, RichTextBoxFinds.MatchCase, -1 }; - - yield return new object[] { "aa", "a", 0, end, RichTextBoxFinds.None, 0 }; - yield return new object[] { "aa", "a", 0, end, RichTextBoxFinds.Reverse, 1 }; - yield return new object[] { "abc", string.Empty, 0, end, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { "abc def", "ef", 0, end, RichTextBoxFinds.None, 5 }; - yield return new object[] { "abc def", "def", 0, end, RichTextBoxFinds.None, 4 }; - yield return new object[] { "abc def", " ", 0, end, RichTextBoxFinds.None, 3 }; - yield return new object[] { "abc def", "ef", 0, end, RichTextBoxFinds.WholeWord, -1 }; - yield return new object[] { "abc def", "def", 0, end, RichTextBoxFinds.WholeWord, 4 }; - yield return new object[] { "abc def", " ", 0, end, RichTextBoxFinds.WholeWord, -1 }; - - yield return new object[] { "ab\u0640cd", "abcd", 0, end, RichTextBoxFinds.None, 0 }; - yield return new object[] { "ab\u0640cd", "\u0640", 0, end, RichTextBoxFinds.None, 2 }; - yield return new object[] { "ab\u0640cd", "bc", 0, end, RichTextBoxFinds.None, 1 }; - yield return new object[] { "ab\u0640cd", "abcd", 0, end, RichTextBoxFinds.NoHighlight, 0 }; - yield return new object[] { "ab\u0640cd", "\u0640", 0, end, RichTextBoxFinds.NoHighlight, 2 }; - yield return new object[] { "ab\u0640cd", "bc", 0, end, RichTextBoxFinds.NoHighlight, 1 }; - yield return new object[] { "abcd", "abcd", 0, end, RichTextBoxFinds.NoHighlight, 0 }; - } - - yield return new object[] { "abc", "a", 1, 3, RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "a", 2, 3, RichTextBoxFinds.None, -1 }; - yield return new object[] { "abc", "c", 2, 3, RichTextBoxFinds.None, 2 }; - yield return new object[] { "abc", "a", 1, 3, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { "abc", "a", 2, 3, RichTextBoxFinds.Reverse, -1 }; - yield return new object[] { "abc", "c", 2, 3, RichTextBoxFinds.Reverse, 2 }; + using var control = new RichTextBox(); + Assert.Throws("data", () => control.LoadFile((Stream)null, RichTextBoxStreamType.RichText)); + } - yield return new object[] { "abc", "c", 0, 5, RichTextBoxFinds.None, 2 }; - yield return new object[] { "abc", "c", 0, 2, RichTextBoxFinds.None, -1 }; + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(RichTextBoxStreamType))] + public void RichTextBox_LoadFile_InvalidFileType_ThrowsInvalidEnumArgumentException(RichTextBoxStreamType fileType) + { + using var control = new RichTextBox(); + using var stream = new MemoryStream(); + Assert.Throws("fileType", () => control.LoadFile(stream, fileType)); + Assert.False(control.IsHandleCreated); } [WinFormsTheory] - [MemberData(nameof(Find_String_Int_Int_RichTextBoxFinds_TestData))] - public void RichTextBox_Find_StringIntIntRichTextBoxFinds_ReturnsExpected(string text, string str, int start, int end, RichTextBoxFinds options, int expected) + [InlineData(RichTextBoxStreamType.RichNoOleObjs)] + [InlineData(RichTextBoxStreamType.TextTextOleObjs)] + public void RichTextBox_LoadFile_UnprocessableFileType_ThrowsArgumentException(RichTextBoxStreamType fileType) { - using var control = new RichTextBox - { - Text = text - }; - Assert.Equal(expected, control.Find(str, start, end, options)); + using var control = new RichTextBox(); + using var stream = new MemoryStream(); + Assert.Throws(null, () => control.LoadFile(stream, fileType)); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void RichTextBox_LoadFile_RichTextEmpty_ThrowsArgumentException() + { + using var control = new RichTextBox(); + using var stream = new MemoryStream(); + Assert.Throws(null, () => control.LoadFile(stream, RichTextBoxStreamType.RichText)); + Assert.Empty(control.Text); Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(Find_String_TestData))] - public void RichTextBox_Find_StringWithHandle_ReturnsExpectedd(string text, string str, int expected) + [WinFormsFact] + public void RichTextBox_LoadFile_InvalidRtf_ThrowsArgumentException() { - using var control = new RichTextBox - { - Text = text - }; - Assert.NotEqual(IntPtr.Zero, control.Handle); - int invalidatedCallCount = 0; - control.Invalidated += (sender, e) => invalidatedCallCount++; - int styleChangedCallCount = 0; - control.StyleChanged += (sender, e) => styleChangedCallCount++; - int createdCallCount = 0; - control.HandleCreated += (sender, e) => createdCallCount++; + using var control = new RichTextBox(); + using var stream = new MemoryStream(); + byte[] buffer = Encoding.ASCII.GetBytes("Hello World"); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; - Assert.Equal(expected, control.Find(str)); + Assert.Throws(null, () => control.LoadFile(stream, RichTextBoxStreamType.RichText)); + } + + [WinFormsFact] + public void RichTextBox_GetAutoSizeMode_Invoke_ReturnsExpected() + { + using var control = new SubRichTextBox(); + Assert.Equal(AutoSizeMode.GrowOnly, control.GetAutoSizeMode()); + } + + [WinFormsTheory] + [InlineData(-1)] + [InlineData(0)] + [InlineData(1)] + public void RichTextBox_GetLineFromCharIndex_InvokeEmpty_Success(int index) + { + using var control = new RichTextBox(); + Assert.Equal(0, control.GetLineFromCharIndex(index)); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); } [WinFormsTheory] - [MemberData(nameof(Find_String_RichTextBoxFinds_TestData))] - public void RichTextBox_Find_StringRichTextBoxFindsWithHandle_ReturnsExpectedd(string text, string str, RichTextBoxFinds options, int expected) + [InlineData(-1)] + [InlineData(0)] + [InlineData(1)] + [InlineData(4)] + [InlineData(5)] + public void RichTextBox_GetLineFromCharIndex_InvokeNotEmpty_Success(int index) { using var control = new RichTextBox { - Text = text + Text = "text" }; - Assert.NotEqual(IntPtr.Zero, control.Handle); - int invalidatedCallCount = 0; - control.Invalidated += (sender, e) => invalidatedCallCount++; - int styleChangedCallCount = 0; - control.StyleChanged += (sender, e) => styleChangedCallCount++; - int createdCallCount = 0; - control.HandleCreated += (sender, e) => createdCallCount++; - - Assert.Equal(expected, control.Find(str, options)); + Assert.Equal(0, control.GetLineFromCharIndex(index)); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); } [WinFormsTheory] - [MemberData(nameof(Find_String_Int_RichTextBoxFinds_TestData))] - public void RichTextBox_Find_StringIntRichTextBoxFindsWithHandle_ReturnsExpectedd(string text, string str, int start, RichTextBoxFinds options, int expected) + [InlineData(-1)] + [InlineData(0)] + [InlineData(1)] + public void RichTextBox_GetLineFromCharIndex_InvokeEmptyWithHandle_Success(int index) { - using var control = new RichTextBox - { - Text = text - }; + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -3184,7 +4421,7 @@ public void RichTextBox_Find_StringIntRichTextBoxFindsWithHandle_ReturnsExpected int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(expected, control.Find(str, start, options)); + Assert.Equal(0, control.GetLineFromCharIndex(index)); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -3192,12 +4429,16 @@ public void RichTextBox_Find_StringIntRichTextBoxFindsWithHandle_ReturnsExpected } [WinFormsTheory] - [MemberData(nameof(Find_String_Int_Int_RichTextBoxFinds_TestData))] - public void RichTextBox_Find_StringIntIntRichTextBoxFindsWithHandle_ReturnsExpectedd(string text, string str, int start, int end, RichTextBoxFinds options, int expected) + [InlineData(-1)] + [InlineData(0)] + [InlineData(1)] + [InlineData(4)] + [InlineData(5)] + public void RichTextBox_GetLineFromCharIndex_InvokeNotEmptyWithHandle_Success(int index) { using var control = new RichTextBox { - Text = text + Text = "text" }; Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; @@ -3207,149 +4448,154 @@ public void RichTextBox_Find_StringIntIntRichTextBoxFindsWithHandle_ReturnsExpec int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(expected, control.Find(str, start, end, options)); + Assert.Equal(0, control.GetLineFromCharIndex(index)); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable Find_CharArray_TestData() + public static IEnumerable GetLineFromCharIndex_CustomLineFromChar_TestData() { - yield return new object[] { string.Empty, new char[0], -1 }; - yield return new object[] { string.Empty, new char[] { 'a', 'b', 'c' }, -1 }; - - yield return new object[] { "abc", new char[0], -1 }; - yield return new object[] { "abc", new char[] { 'a' }, 0 }; - yield return new object[] { "abc", new char[] { 'a', 'b' }, 0 }; - yield return new object[] { "abc", new char[] { 'a', 'b', 'c' }, 0 }; - yield return new object[] { "abc", new char[] { 'a', 'b', 'c', 'd' }, 0 }; - yield return new object[] { "abc", new char[] { 'c', 'b', 'a' }, 0 }; - yield return new object[] { "abc", new char[] { 'c', 'b' }, 1 }; - yield return new object[] { "abc", new char[] { 'b' }, 1 }; - yield return new object[] { "abc", new char[] { 'd' }, -1 }; - yield return new object[] { "abc", new char[] { 'A', 'B', 'C' }, -1 }; - - yield return new object[] { "aa", new char[] { 'a' }, 0 }; - yield return new object[] { "abc def", new char[] { 'e', 'f' }, 5 }; - yield return new object[] { "abc def", new char[] { 'd', 'e', 'f' }, 4 }; - yield return new object[] { "abc def", new char[] { ' ' }, 3 }; - - yield return new object[] { "ab\u0640cd", new char[] { 'a', 'b', 'c', 'd' }, 0 }; - yield return new object[] { "ab\u0640cd", new char[] { '\u0640' }, 2 }; - yield return new object[] { "ab\u0640cd", new char[] { 'b', 'c' }, 1 }; + yield return new object[] { (IntPtr)(-1) }; + yield return new object[] { IntPtr.Zero }; + yield return new object[] { (IntPtr)1 }; + yield return new object[] { (IntPtr)int.MaxValue }; + yield return new object[] { PARAM.FromLowHigh(1, 2) }; + yield return new object[] { PARAM.FromLowHigh(int.MaxValue, int.MaxValue) }; } [WinFormsTheory] - [MemberData(nameof(Find_CharArray_TestData))] - public void RichTextBox_Find_CharArray_ReturnsExpected(string text, char[] characterSet, int expected) + [MemberData(nameof(GetLineFromCharIndex_CustomLineFromChar_TestData))] + public void RichTextBox_GetLineFromCharIndex_CustomLineFromChar_Success(IntPtr result) { - using var control = new RichTextBox + using var control = new CustomLineFromCharRichTextBox { - Text = text + LineFromCharResult = (IntPtr)result }; - Assert.Equal(expected, control.Find(characterSet)); - Assert.True(control.IsHandleCreated); + Assert.NotEqual(IntPtr.Zero, control.Handle); + Assert.Equal(0, control.GetLineFromCharIndex(1)); } - public static IEnumerable Find_CharArray_Int_TestData() + private class CustomLineFromCharRichTextBox : RichTextBox { - yield return new object[] { string.Empty, new char[0], 0, -1 }; - yield return new object[] { string.Empty, new char[] { 'a', 'b', 'c' }, 0, -1 }; - - yield return new object[] { "abc", new char[0], 0, -1 }; - yield return new object[] { "abc", new char[] { 'a' },0, 0 }; - yield return new object[] { "abc", new char[] { 'a', 'b' },0, 0 }; - yield return new object[] { "abc", new char[] { 'a', 'b', 'c' },0, 0 }; - yield return new object[] { "abc", new char[] { 'a', 'b', 'c', 'd' },0, 0 }; - yield return new object[] { "abc", new char[] { 'c', 'b', 'a' },0, 0 }; - yield return new object[] { "abc", new char[] { 'c', 'b' },0, 1 }; - yield return new object[] { "abc", new char[] { 'b' },0, 1 }; - yield return new object[] { "abc", new char[] { 'd' }, 0, -1 }; - yield return new object[] { "abc", new char[] { 'A', 'B', 'C' }, 0, -1 }; + public IntPtr LineFromCharResult { get; set; } - yield return new object[] { "aa", new char[] { 'a' }, 0, 0 }; - yield return new object[] { "abc def", new char[] { 'e', 'f' }, 0, 5 }; - yield return new object[] { "abc def", new char[] { 'd', 'e', 'f' }, 0, 4 }; - yield return new object[] { "abc def", new char[] { ' ' }, 0, 3 }; + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)User32.EM.LINEFROMCHAR) + { + Assert.Equal((IntPtr)1, m.WParam); + Assert.Equal(IntPtr.Zero, m.LParam); + m.Result = LineFromCharResult; + return; + } - yield return new object[] { "ab\u0640cd", new char[] { 'a', 'b', 'c', 'd' }, 0, 0 }; - yield return new object[] { "ab\u0640cd", new char[] { '\u0640' }, 0, 2 }; - yield return new object[] { "ab\u0640cd", new char[] { 'b', 'c' }, 0, 1 }; + base.WndProc(ref m); + } + } - yield return new object[] { "abc", new char[] { 'a' }, 1, -1 }; - yield return new object[] { "abc", new char[] { 'a' }, 2, -1 }; - yield return new object[] { "abc", new char[] { 'c' }, 2, 2 }; + public static IEnumerable GetLineFromCharIndex_CustomExLineFromChar_TestData() + { + yield return new object[] { (IntPtr)(-1), -1 }; + yield return new object[] { IntPtr.Zero, 0 }; + yield return new object[] { (IntPtr)1, 1 }; + yield return new object[] { (IntPtr)int.MaxValue, 0x7FFFFFFF }; + yield return new object[] { PARAM.FromLowHigh(1, 2), 0x20001 }; + yield return new object[] { PARAM.FromLowHigh(int.MaxValue, int.MaxValue), -1 }; } [WinFormsTheory] - [MemberData(nameof(Find_CharArray_Int_TestData))] - public void RichTextBox_Find_CharArrayInt_ReturnsExpected(string text, char[] characterSet, int start, int expected) + [MemberData(nameof(GetLineFromCharIndex_CustomExLineFromChar_TestData))] + public void RichTextBox_GetLineFromCharIndex_CustomExLineFromChar_Success(IntPtr result, int expected) { - using var control = new RichTextBox + using var control = new CustomExLineFromCharRichTextBox { - Text = text + ExLineFromCharResult = (IntPtr)result }; - Assert.Equal(expected, control.Find(characterSet, start)); - Assert.True(control.IsHandleCreated); + Assert.NotEqual(IntPtr.Zero, control.Handle); + Assert.Equal(expected, control.GetLineFromCharIndex(1)); } - public static IEnumerable Find_CharArray_Int_Int_TestData() + private class CustomExLineFromCharRichTextBox : RichTextBox { - foreach (int end in new int[] { -1, 0 }) - { - yield return new object[] { string.Empty, new char[0], 0, end, -1 }; - yield return new object[] { string.Empty, new char[] { 'a', 'b', 'c' }, 0, end, -1 }; - - yield return new object[] { "abc", new char[0], 0, end, -1 }; - yield return new object[] { "abc", new char[] { 'a' },0, end, 0 }; - yield return new object[] { "abc", new char[] { 'a', 'b' },0, end, 0 }; - yield return new object[] { "abc", new char[] { 'a', 'b', 'c' },0, end, 0 }; - yield return new object[] { "abc", new char[] { 'a', 'b', 'c', 'd' },0, end, 0 }; - yield return new object[] { "abc", new char[] { 'c', 'b', 'a' },0, end, 0 }; - yield return new object[] { "abc", new char[] { 'c', 'b' },0, end, 1 }; - yield return new object[] { "abc", new char[] { 'b' },0, end, 1 }; - yield return new object[] { "abc", new char[] { 'd' }, 0, end, -1 }; - yield return new object[] { "abc", new char[] { 'A', 'B', 'C' }, 0, end, -1 }; + public IntPtr ExLineFromCharResult { get; set; } - yield return new object[] { "aa", new char[] { 'a' }, 0, end, 0 }; - yield return new object[] { "abc def", new char[] { 'e', 'f' }, 0, end, 5 }; - yield return new object[] { "abc def", new char[] { 'd', 'e', 'f' }, 0, end, 4 }; - yield return new object[] { "abc def", new char[] { ' ' }, 0, end, 3 }; + protected override void WndProc(ref Message m) + { + if (m.Msg == RichEditMessages.EM_EXLINEFROMCHAR) + { + Assert.Equal(IntPtr.Zero, m.WParam); + Assert.Equal((IntPtr)1, m.LParam); + m.Result = ExLineFromCharResult; + return; + } - yield return new object[] { "ab\u0640cd", new char[] { 'a', 'b', 'c', 'd' }, 0, end, 0 }; - yield return new object[] { "ab\u0640cd", new char[] { '\u0640' }, 0, end, 2 }; - yield return new object[] { "ab\u0640cd", new char[] { 'b', 'c' }, 0, end, 1 }; + base.WndProc(ref m); } + } - yield return new object[] { "abc", new char[] { 'a' }, 1, 3, -1 }; - yield return new object[] { "abc", new char[] { 'a' }, 2, 3, -1 }; - yield return new object[] { "abc", new char[] { 'c' }, 2, 3, 2 }; + [WinFormsTheory] + [InlineData(ControlStyles.ContainerControl, false)] + [InlineData(ControlStyles.UserPaint, false)] + [InlineData(ControlStyles.Opaque, false)] + [InlineData(ControlStyles.ResizeRedraw, false)] + [InlineData(ControlStyles.FixedWidth, false)] + [InlineData(ControlStyles.FixedHeight, false)] + [InlineData(ControlStyles.StandardClick, false)] + [InlineData(ControlStyles.Selectable, true)] + [InlineData(ControlStyles.UserMouse, false)] + [InlineData(ControlStyles.SupportsTransparentBackColor, false)] + [InlineData(ControlStyles.StandardDoubleClick, false)] + [InlineData(ControlStyles.AllPaintingInWmPaint, true)] + [InlineData(ControlStyles.CacheText, false)] + [InlineData(ControlStyles.EnableNotifyMessage, false)] + [InlineData(ControlStyles.DoubleBuffer, false)] + [InlineData(ControlStyles.OptimizedDoubleBuffer, false)] + [InlineData(ControlStyles.UseTextForAccessibility, false)] + [InlineData((ControlStyles)0, true)] + [InlineData((ControlStyles)int.MaxValue, false)] + [InlineData((ControlStyles)(-1), false)] + public void RichTextBox_GetStyle_Invoke_ReturnsExpected(ControlStyles flag, bool expected) + { + using var control = new SubRichTextBox(); + Assert.Equal(expected, control.GetStyle(flag)); - yield return new object[] { "abc", new char[] { 'c' }, 0, 5, 2 }; - yield return new object[] { "abc", new char[] { 'c' }, 0, 2, -1 }; + // Call again to test caching. + Assert.Equal(expected, control.GetStyle(flag)); } [WinFormsTheory] - [MemberData(nameof(Find_CharArray_Int_Int_TestData))] - public void RichTextBox_Find_CharArrayIntInt_ReturnsExpected(string text, char[] characterSet, int start, int end, int expected) + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void RichTextBox_OnBackColorChanged_Invoke_CallsBackColorChanged(EventArgs eventArgs) { - using var control = new RichTextBox + using var control = new SubRichTextBox(); + int callCount = 0; + EventHandler handler = (sender, e) => { - Text = text + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; }; - Assert.Equal(expected, control.Find(characterSet, start, end)); - Assert.True(control.IsHandleCreated); + + // Call with handler. + control.BackColorChanged += handler; + control.OnBackColorChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.False(control.IsHandleCreated); + + // Remove handler. + control.BackColorChanged -= handler; + control.OnBackColorChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.False(control.IsHandleCreated); } [WinFormsTheory] - [MemberData(nameof(Find_CharArray_TestData))] - public void RichTextBox_Find_CharArrayWithHandle_ReturnsExpected(string text, char[] characterSet, int expected) + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void RichTextBox_OnBackColorChanged_InvokeWithHandle_CallsBackColorChanged(EventArgs eventArgs) { - using var control = new RichTextBox - { - Text = text - }; + using var control = new SubRichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -3358,44 +4604,49 @@ public void RichTextBox_Find_CharArrayWithHandle_ReturnsExpected(string text, ch int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(expected, control.Find(characterSet)); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; + }; + + // Call with handler. + control.BackColorChanged += handler; + control.OnBackColorChanged(eventArgs); + Assert.Equal(1, callCount); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); + Assert.Equal(1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Remove handler. + control.BackColorChanged -= handler; + control.OnBackColorChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(2, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [MemberData(nameof(Find_CharArray_Int_TestData))] - public void RichTextBox_Find_CharArrayIntWithHandle_ReturnsExpected(string text, char[] characterSet, int start, int expected) + [WinFormsFact] + public void RichTextBox_Redo_Invoke_Success() { - using var control = new RichTextBox - { - Text = text - }; - Assert.NotEqual(IntPtr.Zero, control.Handle); - int invalidatedCallCount = 0; - control.Invalidated += (sender, e) => invalidatedCallCount++; - int styleChangedCallCount = 0; - control.StyleChanged += (sender, e) => styleChangedCallCount++; - int createdCallCount = 0; - control.HandleCreated += (sender, e) => createdCallCount++; + using var control = new RichTextBox(); + control.Redo(); + Assert.True(control.IsHandleCreated); - Assert.Equal(expected, control.Find(characterSet, start)); + // Call again. + control.Redo(); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [MemberData(nameof(Find_CharArray_Int_Int_TestData))] - public void RichTextBox_Find_CharArrayIntIntWithHandle_ReturnsExpected(string text, char[] characterSet, int start, int end, int expected) + [WinFormsFact] + public void RichTextBox_Redo_InvokeWithHandle_Success() { - using var control = new RichTextBox - { - Text = text - }; + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -3404,7 +4655,14 @@ public void RichTextBox_Find_CharArrayIntIntWithHandle_ReturnsExpected(string te int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(expected, control.Find(characterSet, start, end)); + control.Redo(); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Call again. + control.Redo(); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); @@ -3412,167 +4670,170 @@ public void RichTextBox_Find_CharArrayIntIntWithHandle_ReturnsExpected(string te } [WinFormsFact] - public void RichTextBox_Find_NullStrEmpty_ThrowsArgumentNullException() + public void RichTextBox_SaveFile_InvokePlainTextEmpty_Success() { using var control = new RichTextBox(); - Assert.Throws("str", () => control.Find((string)null)); - Assert.Throws("str", () => control.Find(null, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 0, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, -1, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 1, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 0, 0, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, -1, 0, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 1, 0, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 0, -2, RichTextBoxFinds.None)); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.PlainText); + Assert.Empty(Encoding.ASCII.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_Find_NullStrNotEmpty_ThrowsArgumentNullException() + public void RichTextBox_SaveFile_InvokePlainTextNotEmpty_Success() { using var control = new RichTextBox { - Text = "t" + Text = "Hello World" }; - Assert.Throws("str", () => control.Find((string)null)); - Assert.Throws("str", () => control.Find(null, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 0, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, -1, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 2, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 0, 0, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, -1, 0, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 2, 0, RichTextBoxFinds.None)); - Assert.Throws("str", () => control.Find(null, 0, -2, RichTextBoxFinds.None)); + + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.PlainText); + Assert.Empty(Encoding.ASCII.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_Find_NullCharacterSetEmpty_ThrowsArgumentNullException() + public void RichTextBox_SaveFile_InvokePlainTextEmptyWithHandle_Success() { using var control = new RichTextBox(); - Assert.Throws("characterSet", () => control.Find((char[])null)); - Assert.Throws("characterSet", () => control.Find(null, 0)); - Assert.Throws("characterSet", () => control.Find(null, -1)); - Assert.Throws("characterSet", () => control.Find(null, 1)); - Assert.Throws("characterSet", () => control.Find(null, 0, 0)); - Assert.Throws("characterSet", () => control.Find(null, -1, 0)); - Assert.Throws("characterSet", () => control.Find(null, 1, 0)); - Assert.Throws("characterSet", () => control.Find(null, 0, -2)); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.PlainText); + Assert.Empty(Encoding.ASCII.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } [WinFormsFact] - public void RichTextBox_Find_NullCharacterSetNotEmpty_ThrowsArgumentNullException() + public void RichTextBox_SaveFile_InvokePlainTextNotEmptyWithHandle_Success() { using var control = new RichTextBox { - Text = "t" + Text = "Hello World" }; - Assert.Throws("characterSet", () => control.Find((char[])null)); - Assert.Throws("characterSet", () => control.Find(null, 0)); - Assert.Throws("characterSet", () => control.Find(null, -1)); - Assert.Throws("characterSet", () => control.Find(null, 2)); - Assert.Throws("characterSet", () => control.Find(null, 0, 0)); - Assert.Throws("characterSet", () => control.Find(null, -1, 0)); - Assert.Throws("characterSet", () => control.Find(null, 2, 0)); - Assert.Throws("characterSet", () => control.Find(null, 0, -2)); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.PlainText); + Assert.Equal("Hello World", Encoding.ASCII.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [InlineData(-1)] - [InlineData(1)] - public void RichTextBox_Find_InvalidStartEmpty_ThrowsArgumentOutOfRangeException(int start) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeUnicodeTextEmpty_Success() { using var control = new RichTextBox(); - Assert.Throws("start", () => control.Find("s", start, RichTextBoxFinds.NoHighlight)); - Assert.Throws("start", () => control.Find("s", start, 0, RichTextBoxFinds.NoHighlight)); - Assert.Throws("start", () => control.Find(new char[] { 's' }, start)); - Assert.Throws("start", () => control.Find(new char[] { 's' }, start, 0)); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.PlainText); + Assert.Empty(Encoding.Unicode.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [InlineData(-1)] - [InlineData(2)] - public void RichTextBox_Find_InvalidStartNotEmpty_ThrowsArgumentOutOfRangeException(int start) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeUnicodeTextNotEmpty_Success() { using var control = new RichTextBox { - Text = "t" + Text = "Hello World" }; - Assert.Throws("start", () => control.Find("s", start, RichTextBoxFinds.NoHighlight)); - Assert.Throws("start", () => control.Find("s", start, 0, RichTextBoxFinds.NoHighlight)); - Assert.Throws("start", () => control.Find(new char[] { 's' }, start)); - Assert.Throws("start", () => control.Find(new char[] { 's' }, start, 0)); + + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.PlainText); + Assert.Empty(Encoding.Unicode.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_Find_InvalidEndEmpty_ThrowsArgumentOutOfRangeException() + public void RichTextBox_SaveFile_InvokeUnicodePlainTextEmptyWithHandle_Success() { using var control = new RichTextBox(); - Assert.Throws("end", () => control.Find("s", 0, -2, RichTextBoxFinds.NoHighlight)); - Assert.Throws("end", () => control.Find(new char[] { 's' }, 0, -2)); - } + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - [WinFormsFact] - public void RichTextBox_Find_InvalidEndNotEmpty_ThrowsArgumentOutOfRangeException() - { - using var control = new RichTextBox - { - Text = "t" - }; - Assert.Throws("end", () => control.Find("s", 0, -2, RichTextBoxFinds.NoHighlight)); - Assert.Throws("end", () => control.Find(new char[] { 's' }, 0, -2)); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.UnicodePlainText); + Assert.Empty(Encoding.Unicode.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } [WinFormsFact] - public void RichTextBox_Find_StartGreaterThanEnd_ThrowsArgumentOutOfRangeException() + public void RichTextBox_SaveFile_InvokeUnicodePlainTextNotEmptyWithHandle_Success() { using var control = new RichTextBox { - Text = "t" + Text = "Hello World" }; - Assert.Throws(null, () => control.Find("s", 1, 0, RichTextBoxFinds.None)); - Assert.Throws(null, () => control.Find("s", 1, 0, RichTextBoxFinds.Reverse)); - Assert.Throws("end", () => control.Find(new char[] { 's' }, 1, 0)); - Assert.Throws("end", () => control.Find(new char[] { 's' }, 1, 0)); - } + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - [WinFormsFact] - public void RichTextBox_GetAutoSizeMode_Invoke_ReturnsExpected() - { - using var control = new SubRichTextBox(); - Assert.Equal(AutoSizeMode.GrowOnly, control.GetAutoSizeMode()); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.UnicodePlainText); + Assert.Equal("Hello World", Encoding.Unicode.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [InlineData(-1)] - [InlineData(0)] - [InlineData(1)] - public void RichTextBox_GetLineFromCharIndex_InvokeEmpty_Success(int index) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeRichTextEmpty_Success() { using var control = new RichTextBox(); - Assert.Equal(0, control.GetLineFromCharIndex(index)); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.RichText); + string text = Encoding.ASCII.GetString(stream.ToArray()); + Assert.StartsWith("{\\rtf", text); Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [InlineData(-1)] - [InlineData(0)] - [InlineData(1)] - [InlineData(4)] - [InlineData(5)] - public void RichTextBox_GetLineFromCharIndex_InvokeNotEmpty_Success(int index) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeRichTextNotEmpty_Success() { using var control = new RichTextBox { - Text = "text" + Text = "Hello World" }; - Assert.Equal(0, control.GetLineFromCharIndex(index)); + + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.RichText); + Assert.Empty(Encoding.ASCII.GetString(stream.ToArray())); Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [InlineData(-1)] - [InlineData(0)] - [InlineData(1)] - public void RichTextBox_GetLineFromCharIndex_InvokeEmptyWithHandle_Success(int index) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeRichTextEmptyWithHandle_Success() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -3583,24 +4844,22 @@ public void RichTextBox_GetLineFromCharIndex_InvokeEmptyWithHandle_Success(int i int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(0, control.GetLineFromCharIndex(index)); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.RichText); + string text = Encoding.ASCII.GetString(stream.ToArray()); + Assert.StartsWith("{\\rtf", text); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [InlineData(-1)] - [InlineData(0)] - [InlineData(1)] - [InlineData(4)] - [InlineData(5)] - public void RichTextBox_GetLineFromCharIndex_InvokeNotEmptyWithHandle_Success(int index) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeRichTextNotEmptyWithHandle_Success() { using var control = new RichTextBox { - Text = "text" + Text = "Hello World" }; Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; @@ -3610,154 +4869,104 @@ public void RichTextBox_GetLineFromCharIndex_InvokeNotEmptyWithHandle_Success(in int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - Assert.Equal(0, control.GetLineFromCharIndex(index)); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.RichText); + string text = Encoding.ASCII.GetString(stream.ToArray()); + Assert.StartsWith("{\\rtf", text); + Assert.Contains("Hello World", text); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable GetLineFromCharIndex_CustomLineFromChar_TestData() + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeTextTextOleObjsEmpty_Success() { - yield return new object[] { (IntPtr)(-1) }; - yield return new object[] { IntPtr.Zero }; - yield return new object[] { (IntPtr)1 }; - yield return new object[] { (IntPtr)int.MaxValue }; - yield return new object[] { PARAM.FromLowHigh(1, 2) }; - yield return new object[] { PARAM.FromLowHigh(int.MaxValue, int.MaxValue) }; + using var control = new RichTextBox(); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.TextTextOleObjs); + Assert.Empty(Encoding.ASCII.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [MemberData(nameof(GetLineFromCharIndex_CustomLineFromChar_TestData))] - public void RichTextBox_GetLineFromCharIndex_CustomLineFromChar_Success(IntPtr result) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeTextTextOleObjsNotEmpty_Success() { - using var control = new CustomLineFromCharRichTextBox + using var control = new RichTextBox { - LineFromCharResult = (IntPtr)result + Text = "Hello World" }; - Assert.NotEqual(IntPtr.Zero, control.Handle); - Assert.Equal(0, control.GetLineFromCharIndex(1)); - } - - private class CustomLineFromCharRichTextBox : RichTextBox - { - public IntPtr LineFromCharResult { get; set; } - - protected override void WndProc(ref Message m) - { - if (m.Msg == (int)User32.EM.LINEFROMCHAR) - { - Assert.Equal((IntPtr)1, m.WParam); - Assert.Equal(IntPtr.Zero, m.LParam); - m.Result = LineFromCharResult; - return; - } - base.WndProc(ref m); - } + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.TextTextOleObjs); + Assert.Empty(Encoding.ASCII.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); } - public static IEnumerable GetLineFromCharIndex_CustomExLineFromChar_TestData() + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeTextTextOleObjsEmptyWithHandle_Success() { - yield return new object[] { (IntPtr)(-1), -1 }; - yield return new object[] { IntPtr.Zero, 0 }; - yield return new object[] { (IntPtr)1, 1 }; - yield return new object[] { (IntPtr)int.MaxValue, 0x7FFFFFFF }; - yield return new object[] { PARAM.FromLowHigh(1, 2), 0x20001 }; - yield return new object[] { PARAM.FromLowHigh(int.MaxValue, int.MaxValue), -1 }; + using var control = new RichTextBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.TextTextOleObjs); + Assert.Empty(Encoding.ASCII.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [MemberData(nameof(GetLineFromCharIndex_CustomExLineFromChar_TestData))] - public void RichTextBox_GetLineFromCharIndex_CustomExLineFromChar_Success(IntPtr result, int expected) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeTextTextOleObjsNotEmptyWithHandle_Success() { - using var control = new CustomExLineFromCharRichTextBox + using var control = new RichTextBox { - ExLineFromCharResult = (IntPtr)result + Text = "Hello World" }; Assert.NotEqual(IntPtr.Zero, control.Handle); - Assert.Equal(expected, control.GetLineFromCharIndex(1)); - } - - private class CustomExLineFromCharRichTextBox : RichTextBox - { - public IntPtr ExLineFromCharResult { get; set; } - - protected override void WndProc(ref Message m) - { - if (m.Msg == RichEditMessages.EM_EXLINEFROMCHAR) - { - Assert.Equal(IntPtr.Zero, m.WParam); - Assert.Equal((IntPtr)1, m.LParam); - m.Result = ExLineFromCharResult; - return; - } - - base.WndProc(ref m); - } - } - - [WinFormsTheory] - [InlineData(ControlStyles.ContainerControl, false)] - [InlineData(ControlStyles.UserPaint, false)] - [InlineData(ControlStyles.Opaque, false)] - [InlineData(ControlStyles.ResizeRedraw, false)] - [InlineData(ControlStyles.FixedWidth, false)] - [InlineData(ControlStyles.FixedHeight, false)] - [InlineData(ControlStyles.StandardClick, false)] - [InlineData(ControlStyles.Selectable, true)] - [InlineData(ControlStyles.UserMouse, false)] - [InlineData(ControlStyles.SupportsTransparentBackColor, false)] - [InlineData(ControlStyles.StandardDoubleClick, false)] - [InlineData(ControlStyles.AllPaintingInWmPaint, true)] - [InlineData(ControlStyles.CacheText, false)] - [InlineData(ControlStyles.EnableNotifyMessage, false)] - [InlineData(ControlStyles.DoubleBuffer, false)] - [InlineData(ControlStyles.OptimizedDoubleBuffer, false)] - [InlineData(ControlStyles.UseTextForAccessibility, false)] - [InlineData((ControlStyles)0, true)] - [InlineData((ControlStyles)int.MaxValue, false)] - [InlineData((ControlStyles)(-1), false)] - public void RichTextBox_GetStyle_Invoke_ReturnsExpected(ControlStyles flag, bool expected) - { - using var control = new SubRichTextBox(); - Assert.Equal(expected, control.GetStyle(flag)); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - // Call again to test caching. - Assert.Equal(expected, control.GetStyle(flag)); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.TextTextOleObjs); + Assert.Equal("Hello World", Encoding.ASCII.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [WinFormsTheory] - [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] - public void RichTextBox_OnBackColorChanged_Invoke_CallsBackColorChanged(EventArgs eventArgs) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeRichNoOleObjsNotEmpty_Success() { - using var control = new SubRichTextBox(); - int callCount = 0; - EventHandler handler = (sender, e) => + using var control = new RichTextBox { - Assert.Same(control, sender); - Assert.Same(eventArgs, e); - callCount++; + Text = "Hello World" }; - // Call with handler. - control.BackColorChanged += handler; - control.OnBackColorChanged(eventArgs); - Assert.Equal(1, callCount); - Assert.False(control.IsHandleCreated); - - // Remove handler. - control.BackColorChanged -= handler; - control.OnBackColorChanged(eventArgs); - Assert.Equal(1, callCount); - Assert.False(control.IsHandleCreated); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.RichNoOleObjs); + Assert.Empty(Encoding.ASCII.GetString(stream.ToArray())); + Assert.True(control.IsHandleCreated); } - [WinFormsTheory] - [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] - public void RichTextBox_OnBackColorChanged_InvokeWithHandle_CallsBackColorChanged(EventArgs eventArgs) + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeRichNoOleObjsEmptyWithHandle_Success() { - using var control = new SubRichTextBox(); + using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -3766,47 +4975,63 @@ public void RichTextBox_OnBackColorChanged_InvokeWithHandle_CallsBackColorChange int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - int callCount = 0; - EventHandler handler = (sender, e) => - { - Assert.Same(control, sender); - Assert.Same(eventArgs, e); - callCount++; - }; - - // Call with handler. - control.BackColorChanged += handler; - control.OnBackColorChanged(eventArgs); - Assert.Equal(1, callCount); + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.RichNoOleObjs); + string text = Encoding.ASCII.GetString(stream.ToArray()); + Assert.StartsWith("{\\rtf", text); Assert.True(control.IsHandleCreated); - Assert.Equal(1, invalidatedCallCount); + Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); + } - // Remove handler. - control.BackColorChanged -= handler; - control.OnBackColorChanged(eventArgs); - Assert.Equal(1, callCount); + [WinFormsFact] + public void RichTextBox_SaveFile_InvokeRichNoOleObjsNotEmptyWithHandle_Success() + { + using var control = new RichTextBox + { + Text = "Hello World" + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + using var stream = new MemoryStream(); + control.SaveFile(stream, RichTextBoxStreamType.RichNoOleObjs); + string text = Encoding.ASCII.GetString(stream.ToArray()); + Assert.StartsWith("{\\rtf", text); + Assert.Contains("Hello World", text); Assert.True(control.IsHandleCreated); - Assert.Equal(2, invalidatedCallCount); + Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } [WinFormsFact] - public void RichTextBox_Redo_Invoke_Success() + public void RichTextBox_SaveFile_NullData_Nop() { using var control = new RichTextBox(); - control.Redo(); + control.SaveFile((Stream)null, RichTextBoxStreamType.RichText); Assert.True(control.IsHandleCreated); + } - // Call again. - control.Redo(); + [WinFormsFact] + public void RichTextBox_SaveFile_NullDataWithText_Nop() + { + using var control = new RichTextBox + { + Text = "Text" + }; + control.SaveFile((Stream)null, RichTextBoxStreamType.RichText); Assert.True(control.IsHandleCreated); } [WinFormsFact] - public void RichTextBox_Redo_InvokeWithHandle_Success() + public void RichTextBox_SaveFile_NullDataWithHandle_Nop() { using var control = new RichTextBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); @@ -3817,18 +5042,37 @@ public void RichTextBox_Redo_InvokeWithHandle_Success() int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - control.Redo(); + control.SaveFile((Stream)null, RichTextBoxStreamType.RichText); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + } - // Call again. - control.Redo(); + [WinFormsFact] + public void RichTextBox_SaveFile_NullDataWithTextWithHandle_Nop() + { + using var control = new RichTextBox + { + Text = "Text" + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.SaveFile((Stream)null, RichTextBoxStreamType.RichText); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); - Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(RichTextBoxStreamType))] + public void RichTextBox_SaveFile_InvalidFileType_ThrowsInvalidEnumArgumentException(RichTextBoxStreamType fileType) + { + using var control = new RichTextBox(); + using var stream = new MemoryStream(); + Assert.Throws("fileType", () => control.SaveFile(stream, fileType)); + Assert.False(control.IsHandleCreated); } private class CustomGetCharFormatRichTextBox : RichTextBox