Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/test/unit/System.Windows.Forms/ResourceStrings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.RegularExpressions;

namespace System.Windows.Forms.Tests;

internal static partial class ResourceStrings
{
[GeneratedRegex(@"{[0-9]}")]
private static partial Regex PlaceholdersPattern();

internal static string InvalidTypeFormatCombinationMessage =>
PlaceholdersPattern().Replace(SR.ClipboardOrDragDrop_InvalidFormatTypeCombination, "*");
internal static string TypeRequiresResolver => PlaceholdersPattern().Replace(SR.ClipboardOrDragDrop_InvalidType, "*");
internal static string UseTryGetDataWithResolver => PlaceholdersPattern().Replace(SR.ClipboardOrDragDrop_UseTypedAPI, "*");
internal static string TypedInterfaceNotImplemented => PlaceholdersPattern().Replace(SR.ITypeDataObject_Not_Implemented, "*");
}
Original file line number Diff line number Diff line change
Expand Up @@ -566,13 +566,13 @@ public unsafe void GetReturnsProxy()
PInvokeCore.OleGetClipboard(proxy).Succeeded.Should().BeTrue();
((nint)proxy.Value).Should().NotBe((nint)dataScope.Value);

using var dataUnknown = dataScope.Query<Com.IUnknown>();
using var proxyUnknown = proxy.Query<Com.IUnknown>();
using var dataUnknown = dataScope.Query<IUnknown>();
using var proxyUnknown = proxy.Query<IUnknown>();
((nint)proxyUnknown.Value).Should().NotBe((nint)dataUnknown.Value);

// The proxy does not know about this interface, it should give back the real pointer.
using var realDataPointer = proxy.Query<Com.IComCallableWrapper>();
using var realDataPointerUnknown = realDataPointer.Query<Com.IUnknown>();
using var realDataPointer = proxy.Query<IComCallableWrapper>();
using var realDataPointerUnknown = realDataPointer.Query<IUnknown>();
((nint)proxyUnknown.Value).Should().NotBe((nint)realDataPointerUnknown.Value);
((nint)dataUnknown.Value).Should().Be((nint)realDataPointerUnknown.Value);
}
Expand Down Expand Up @@ -1311,52 +1311,19 @@ public void RoundTrip_TypedDataObject_SupportsTypedInterface(bool copy) =>

[WinFormsTheory]
[BoolData]
public void RoundTrip_ManagedDataObject_SupportsTypedInterface(bool copy) =>
CustomDataObject_RoundTrip_SupportsTypedInterface<ManagedDataObject>(copy);

[WinFormsTheory]
[BoolData]
public void RoundTrip_Object_SupportsTypedInterface(bool copy)
{
SerializableTestData data = new();
string format = typeof(SerializableTestData).FullName!;

// Opt-in into access to the binary formatted stream.
using BinaryFormatterInClipboardDragDropScope clipboardScope = new(enable: copy);

// We need the BinaryFormatter to flush the data from the managed object to the HGLOBAL
// and to write data to HGLOBAL as a binary formatted stream now if it hadn't been flushed.
using BinaryFormatterScope scope = new(enable: copy);

Clipboard.SetDataObject(data, copy);

DataObject received = Clipboard.GetDataObject().Should().BeAssignableTo<DataObject>().Subject;

received.TryGetData(
format,
name => name.FullName == typeof(SerializableTestData).FullName ? typeof(SerializableTestData) : null,
autoConvert: false,
out SerializableTestData? result).Should().BeTrue();

result.Should().BeEquivalentTo(data);

Clipboard.TryGetData(
format,
(TypeName name) => name.FullName == typeof(SerializableTestData).FullName ? typeof(SerializableTestData) : null,
out result).Should().BeTrue();

result.Should().BeEquivalentTo(data);
}
public void RoundTrip_UntypedDataObject_SupportsTypedInterface(bool copy) =>
CustomDataObject_RoundTrip_SupportsTypedInterface<UntypedDataObject>(copy);

private static void CustomDataObject_RoundTrip_SupportsTypedInterface<T>(bool copy) where T : IDataObject, new()
{
SerializableTestData data = new();
T testDataObject = new();
string format = ManagedDataObject.s_format;
string format = UntypedDataObject.s_format;
testDataObject.SetData(format, data);

// Opt-in into access the binary formatted stream.
using BinaryFormatterInClipboardDragDropScope clipboardScope = new(enable: copy);

// We need the BinaryFormatter to flush the data from the managed object to the HGLOBAL.
using (BinaryFormatterScope scope = new(enable: copy))
{
Expand All @@ -1371,7 +1338,7 @@ public void RoundTrip_Object_SupportsTypedInterface(bool copy)
using BinaryFormatterScope scope = new(enable: copy);
ITypedDataObject received = Clipboard.GetDataObject().Should().BeAssignableTo<ITypedDataObject>().Subject;

// Need an explict resolver to hit the BinaryFormatter path if the data was copied out.
// Need an explicit resolver to hit the BinaryFormatter path if the data was copied out.
received.TryGetData(format, out SerializableTestData? result).Should().Be(!copy);
if (copy)
{
Expand All @@ -1384,7 +1351,7 @@ public void RoundTrip_Object_SupportsTypedInterface(bool copy)

received.TryGetData(
format,
(TypeName name) => name.FullName == typeof(SerializableTestData).FullName ? typeof(SerializableTestData) : null,
name => name.FullName == typeof(SerializableTestData).FullName ? typeof(SerializableTestData) : null,
autoConvert: false,
out result).Should().BeTrue();

Expand All @@ -1402,7 +1369,7 @@ public void RoundTrip_Object_SupportsTypedInterface(bool copy)

Clipboard.TryGetData(
format,
(TypeName name) => name.FullName == typeof(SerializableTestData).FullName ? typeof(SerializableTestData) : null,
name => name.FullName == typeof(SerializableTestData).FullName ? typeof(SerializableTestData) : null,
out result).Should().BeTrue();

result.Should().BeEquivalentTo(data);
Expand All @@ -1411,12 +1378,47 @@ public void RoundTrip_Object_SupportsTypedInterface(bool copy)
{
T received = Clipboard.GetDataObject().Should().BeOfType<T>().Subject;
received.Should().Be(testDataObject);
// When we are not flushing the data to the HGLOBAL, we are reading from our DataStore or the managed test data object.
// When we are not flushing the data to the HGLOBAL, we are reading from our managed test data object,
// which might not support the types interface.
Action tryGetData = () => received.TryGetData(format, out SerializableTestData? result);
tryGetData.Should().Throw<NotSupportedException>();
tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: ResourceStrings.TypedInterfaceNotImplemented);
}
}

[WinFormsTheory]
[BoolData]
public void RoundTrip_Object_SupportsTypedInterface(bool copy)
{
SerializableTestData data = new();
string format = typeof(SerializableTestData).FullName!;

// Opt-in into access to the binary formatted stream.
using BinaryFormatterInClipboardDragDropScope clipboardScope = new(enable: copy);

// We need the BinaryFormatter to flush the data from the managed object to the HGLOBAL.
using BinaryFormatterScope scope = new(enable: copy);

Clipboard.SetDataObject(data, copy);

DataObject received = Clipboard.GetDataObject().Should().BeAssignableTo<DataObject>().Subject;

received.TryGetData(
format,
name => name.FullName == typeof(SerializableTestData).FullName ? typeof(SerializableTestData) : null,
autoConvert: false,
out SerializableTestData? result).Should().BeTrue();

result.Should().BeEquivalentTo(data);

Clipboard.TryGetData(
format,
name => name.FullName == typeof(SerializableTestData).FullName ? typeof(SerializableTestData) : null,
out result).Should().BeTrue();

result.Should().BeEquivalentTo(data);
}

[WinFormsFact]
public unsafe void OleGetClipboard_ProxyBehavior()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Drawing;
using System.Reflection.Metadata;
using System.Text.RegularExpressions;
using System.Windows.Forms.TestUtilities;
using Com = Windows.Win32.System.Com;

namespace System.Windows.Forms.Tests;

public unsafe partial class NativeToWinFormsAdapterTests
{
[GeneratedRegex(@"{[0-9]}")]
private static partial Regex PlaceholdersPattern();

private static string InvalidTypeFormatCombinationMessage =>
PlaceholdersPattern().Replace(SR.ClipboardOrDragDrop_InvalidFormatTypeCombination, "*");
private static string TypeRequiresResolverMessage => PlaceholdersPattern().Replace(SR.ClipboardOrDragDrop_InvalidType, "*");
private static string UseTryGetDataWithResolver => PlaceholdersPattern().Replace(SR.ClipboardOrDragDrop_UseTypedAPI, "*");

private const string FormatterDisabledMessage =
"BinaryFormatter serialization and deserialization are disabled within this application. See https://aka.ms/binaryformatter for more information.";

Expand Down Expand Up @@ -58,7 +49,7 @@ public void TryGetData_AsObject_Primitive_RequiresResolver(string format)
DataObject dataObject = new(comDataObject.Value);

Action tryGetData = () => dataObject.TryGetData(format, out object? value);
tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: TypeRequiresResolverMessage);
tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: ResourceStrings.TypeRequiresResolver);

dataObject.TryGetData(format, Resolver, autoConvert: false, out object? value).Should().BeTrue();
value.Should().Be(1);
Expand All @@ -79,7 +70,7 @@ public void TryGetData_AsObject_Primitive_InvalidTypeFormatCombination(string fo
// Throw when validating arguments, as these formats allow exactly strings or bitmaps only.
Action tryGetData = () => dataObject.TryGetData(format, out object? _);
tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: InvalidTypeFormatCombinationMessage);
.WithMessage(expectedWildcardPattern: ResourceStrings.InvalidTypeFormatCombinationMessage);
}

private static (DataObject dataObject, TestData value) SetDataObject(string format)
Expand All @@ -101,7 +92,7 @@ public void TryGetData_AsObject_Custom_RequiresResolver(string format)
(DataObject dataObject, TestData _) = SetDataObject(format);
Action tryGetData = () => dataObject.TryGetData(format, out object? _);

tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: TypeRequiresResolverMessage);
tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: ResourceStrings.TypeRequiresResolver);
}

[WinFormsTheory]
Expand All @@ -114,7 +105,7 @@ public void TryGetData_AsObject_Custom_FormatterEnabled_RequiresResolver(string
using BinaryFormatterScope scope = new(enable: true);
using BinaryFormatterInClipboardDragDropScope clipboardScope = new(enable: true);

tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: TypeRequiresResolverMessage);
tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: ResourceStrings.TypeRequiresResolver);
}

[WinFormsTheory]
Expand All @@ -127,7 +118,7 @@ public void TryGetData_AsObject_Custom_InvalidTypeFormatCombination(string forma

// Type-Format combination is validated before the we attempt to serialize data.
tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: InvalidTypeFormatCombinationMessage);
.WithMessage(expectedWildcardPattern: ResourceStrings.InvalidTypeFormatCombinationMessage);
}

[WinFormsTheory]
Expand Down Expand Up @@ -180,7 +171,7 @@ public void TryGetData_AsInterface_ListOfPrimitives_RequiresResolver(string form
// Theoretically we don't require a resolver here, but this is an exception. In the more common cases resolver
// is required to instantiate non-concrete types.
Action tryGetData = () => dataObject.TryGetData(format, out IList<int>? _);
tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: TypeRequiresResolverMessage);
tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: ResourceStrings.TypeRequiresResolver);
}

[WinFormsTheory]
Expand All @@ -196,7 +187,7 @@ public void TryGetData_AsInterface_ListOfPrimitives_InvalidTypeFormatCombination

Action tryGetData = () => dataObject.TryGetData(format, out IList<int>? _);
tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: InvalidTypeFormatCombinationMessage);
.WithMessage(expectedWildcardPattern: ResourceStrings.InvalidTypeFormatCombinationMessage);
}

[WinFormsTheory]
Expand Down Expand Up @@ -227,7 +218,7 @@ public void TryGetData_AsConcreteType_ListOfPrimitives_InvalidTypeFormatCombinat

Action tryGetData = () => dataObject.TryGetData(format, out List<int>? _);
tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: InvalidTypeFormatCombinationMessage);
.WithMessage(expectedWildcardPattern: ResourceStrings.InvalidTypeFormatCombinationMessage);
}

[WinFormsTheory]
Expand Down Expand Up @@ -277,7 +268,7 @@ public void TryGetData_AsConcreteType_Custom_InvalidTypeFormatCombination(string

Action tryGetData = () => dataObject.TryGetData(format, out TestData? _);
tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: InvalidTypeFormatCombinationMessage);
.WithMessage(expectedWildcardPattern: ResourceStrings.InvalidTypeFormatCombinationMessage);
}

[WinFormsTheory]
Expand All @@ -302,7 +293,7 @@ public void TryGetData_WithResolver_AsConcreteType_Custom_InvalidTypeFormatCombi
Action tryGetData = () => dataObject.TryGetData(format, TestData.Resolver, autoConvert: true, out TestData? _);

tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: InvalidTypeFormatCombinationMessage);
.WithMessage(expectedWildcardPattern: ResourceStrings.InvalidTypeFormatCombinationMessage);
}

[WinFormsTheory]
Expand All @@ -317,7 +308,7 @@ public void TryGetData_WithResolver_AsConcreteType_Custom_FormatterEnabled_Inval
using BinaryFormatterInClipboardDragDropScope clipboardScope = new(enable: true);

tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: InvalidTypeFormatCombinationMessage);
.WithMessage(expectedWildcardPattern: ResourceStrings.InvalidTypeFormatCombinationMessage);
}

[WinFormsTheory]
Expand Down Expand Up @@ -354,7 +345,7 @@ public void TryGetData_AsAbstract_Custom_InvalidTypeFormatCombination(string for

Action tryGetData = () => dataObject.TryGetData(format, out AbstractBase? _);
tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: InvalidTypeFormatCombinationMessage);
.WithMessage(expectedWildcardPattern: ResourceStrings.InvalidTypeFormatCombinationMessage);
}

[WinFormsTheory]
Expand All @@ -364,7 +355,7 @@ public void TryGetData_AsAbstract_Custom_RequiresResolver(string format)
(DataObject dataObject, TestData _) = SetDataObject(format);
Action tryGetData = () => dataObject.TryGetData(format, out AbstractBase? _);

tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: TypeRequiresResolverMessage);
tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: ResourceStrings.TypeRequiresResolver);

dataObject.TryGetData(format, out NotSupportedException? ex).Should().BeTrue();
ex.Should().BeOfType<NotSupportedException>().Which.Message.Should().Be(FormatterDisabledMessage);
Expand All @@ -380,7 +371,7 @@ public void TryGetData_AsAbstract_Custom_FormatterEnabled_RequiresResolver(strin
using BinaryFormatterScope scope = new(enable: true);
using BinaryFormatterInClipboardDragDropScope clipboardScope = new(enable: true);

tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: TypeRequiresResolverMessage);
tryGetData.Should().Throw<NotSupportedException>().WithMessage(expectedWildcardPattern: ResourceStrings.TypeRequiresResolver);
}

[WinFormsTheory]
Expand Down Expand Up @@ -420,7 +411,7 @@ public void TryGetData_WithResolver_AsAbstract_Custom_InvalidTypeFormatCombinati
// Nothing is written to HGLOBAL in this test because format-type combination is invalid.
Action tryGetData = () => dataObject.TryGetData(format, TestData.Resolver, autoConvert: true, out AbstractBase? _);
tryGetData.Should().Throw<NotSupportedException>()
.WithMessage(expectedWildcardPattern: InvalidTypeFormatCombinationMessage);
.WithMessage(expectedWildcardPattern: ResourceStrings.InvalidTypeFormatCombinationMessage);
}

[WinFormsTheory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace System.Windows.Forms.TestUtilities;

internal class ManagedAndRuntimeDataObject : ManagedDataObject, ComTypes.IDataObject
internal class ManagedAndRuntimeDataObject : UntypedDataObject, ComTypes.IDataObject
{
public int DAdvise(ref ComTypes.FORMATETC pFormatetc, ComTypes.ADVF advf, ComTypes.IAdviseSink adviseSink, out int connection) => throw new NotImplementedException();
public void DUnadvise(int connection) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace System.Windows.Forms.TestUtilities;

internal class TypedDataObject : ManagedDataObject, ITypedDataObject
internal class TypedDataObject : UntypedDataObject, ITypedDataObject
{
public bool TryGetData<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>([MaybeNullWhen(false), NotNullWhen(true)] out T data) =>
throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace System.Windows.Forms.TestUtilities;

internal class ManagedDataObject : IDataObject
internal class UntypedDataObject : IDataObject
{
public static string s_format = nameof(SerializableTestData);
protected SerializableTestData? _data;
Expand Down