Skip to content

Commit

Permalink
Test fill-in (#535)
Browse files Browse the repository at this point in the history
- array: out byref, return/out with element marshalling
- bool: in by ref, default marshalling
- char: in by ref
- SafeHandle: out by ref
  • Loading branch information
elinor-fung authored Jan 11, 2021
1 parent 54321e3 commit a072658
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,21 @@ public partial class Arrays
[return:MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
public static partial int[] CreateRange(int start, int end, out int numValues);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "create_range_array_out")]
public static partial void CreateRange_Out(int start, int end, out int numValues, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] out int[] res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "sum_string_lengths")]
public static partial int SumStringLengths([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] strArray);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings")]
public static partial void ReverseStrings([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] ref string[] strArray, out int numElements);
[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_replace")]
public static partial void ReverseStrings_Ref([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] ref string[] strArray, out int numElements);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_return")]
[return: MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)]
public static partial string[] ReverseStrings_Return([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] strArray, out int numElements);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "reverse_strings_out")]
public static partial void ReverseStrings_Out([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] strArray, out int numElements, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] out string[] res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes")]
[return:MarshalAs(UnmanagedType.LPArray, SizeConst = sizeof(long))]
Expand Down Expand Up @@ -88,16 +98,24 @@ public void IntArrayRefParameter()
public void ArraysReturnedFromNative()
{
int start = 5;

int end = 20;

Assert.Equal(Enumerable.Range(start, end - start), NativeExportsNE.Arrays.CreateRange(start, end, out _));
IEnumerable<int> expected = Enumerable.Range(start, end - start);
Assert.Equal(expected, NativeExportsNE.Arrays.CreateRange(start, end, out _));

int[] res;
NativeExportsNE.Arrays.CreateRange_Out(start, end, out _, out res);
Assert.Equal(expected, res);
}

[Fact]
public void NullArrayReturnedFromNative()
{
Assert.Null(NativeExportsNE.Arrays.CreateRange(1, 0, out _));

int[] res;
NativeExportsNE.Arrays.CreateRange_Out(1, 0, out _, out res);
Assert.Null(res);
}

private static string[] GetStringArray()
Expand Down Expand Up @@ -131,20 +149,43 @@ public void ByRefArrayWithElementMarshalling()
{
var strings = GetStringArray();
var expectedStrings = strings.Select(s => ReverseChars(s)).ToArray();
NativeExportsNE.Arrays.ReverseStrings(ref strings, out _);
NativeExportsNE.Arrays.ReverseStrings_Ref(ref strings, out _);

Assert.Equal((IEnumerable<string>)expectedStrings, strings);
}

[Fact]
public void ReturnArrayWithElementMarshalling()
{
var strings = GetStringArray();
var expectedStrings = strings.Select(s => ReverseChars(s)).ToArray();
Assert.Equal(expectedStrings, NativeExportsNE.Arrays.ReverseStrings_Return(strings, out _));

string[] res;
NativeExportsNE.Arrays.ReverseStrings_Out(strings, out _, out res);
Assert.Equal(expectedStrings, res);
}

[Fact]
public void ByRefNullArrayWithElementMarshalling()
{
string[] strings = null;
NativeExportsNE.Arrays.ReverseStrings(ref strings, out _);
NativeExportsNE.Arrays.ReverseStrings_Ref(ref strings, out _);

Assert.Null(strings);
}

[Fact]
public void ReturnNullArrayWithElementMarshalling()
{
string[] strings = null;
Assert.Null(NativeExportsNE.Arrays.ReverseStrings_Return(strings, out _));

string[] res;
NativeExportsNE.Arrays.ReverseStrings_Out(strings, out _, out res);
Assert.Null(res);
}

[Fact]
public void ConstantSizeArray()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ partial class NativeExportsNE
[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "blittablestructs_double_intfields_byref")]
public static partial void DoubleIntFieldsByRef(ref IntFields result);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "blittablestructs_double_intfields_byref")]
public static partial void DoubleIntFieldsByRefIn(in IntFields result);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "blittablestructs_double_intfields_refreturn")]
public static partial void DoubleIntFieldsRefReturn(
IntFields input,
Expand Down Expand Up @@ -61,6 +64,12 @@ public void ValidateBlittableStruct()
NativeExportsNE.DoubleIntFieldsByRef(ref input);
Assert.Equal(expected, input);
}

{
input = initial;
NativeExportsNE.DoubleIntFieldsByRefIn(in input);
Assert.Equal(expected, input); // Updated even when passed with in keyword (matches built-in system)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ partial class NativeExportsNE
[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_uint")]
public static partial uint ReturnWinBoolAsUInt([MarshalAs(UnmanagedType.Bool)] bool input);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_uint")]
public static partial uint ReturnDefaultBoolAsUInt(bool input);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_uint")]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool ReturnUIntAsByteBool(uint input);
Expand All @@ -37,23 +40,44 @@ partial class NativeExportsNE
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool ReturnUIntAsWinBool(uint input);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_uint")]
public static partial bool ReturnUIntAsDefaultBool(uint input);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsByteBool_Ref(uint input, [MarshalAs(UnmanagedType.U1)] ref bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsByteBool_Out(uint input, [MarshalAs(UnmanagedType.U1)] out bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsByteBool_In(uint input, [MarshalAs(UnmanagedType.U1)] in bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsRefByteBool(uint input, [MarshalAs(UnmanagedType.U1)] ref bool res);
public static partial void ReturnUIntAsVariantBool_Ref(uint input, [MarshalAs(UnmanagedType.VariantBool)] ref bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsOutByteBool(uint input, [MarshalAs(UnmanagedType.U1)] out bool res);
public static partial void ReturnUIntAsVariantBool_Out(uint input, [MarshalAs(UnmanagedType.VariantBool)] out bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsRefVariantBool(uint input, [MarshalAs(UnmanagedType.VariantBool)] ref bool res);
public static partial void ReturnUIntAsVariantBool_In(uint input, [MarshalAs(UnmanagedType.VariantBool)] in bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsOutVariantBool(uint input, [MarshalAs(UnmanagedType.VariantBool)] out bool res);
public static partial void ReturnUIntAsWinBool_Ref(uint input, [MarshalAs(UnmanagedType.Bool)] ref bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsRefWinBool(uint input, [MarshalAs(UnmanagedType.Bool)] ref bool res);
public static partial void ReturnUIntAsWinBool_Out(uint input, [MarshalAs(UnmanagedType.Bool)] out bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsOutWinBool(uint input, [MarshalAs(UnmanagedType.Bool)] out bool res);
public static partial void ReturnUIntAsWinBool_In(uint input, [MarshalAs(UnmanagedType.Bool)] in bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsDefaultBool_Ref(uint input, ref bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsDefaultBool_Out(uint input, out bool res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "bool_return_as_refuint")]
public static partial void ReturnUIntAsDefaultBool_In(uint input, in bool res);
}

public class BooleanTests
Expand All @@ -77,6 +101,8 @@ public void ValidateBoolIsMarshalledAsExpected()
Assert.Equal((uint)0, NativeExportsNE.ReturnUIntBoolAsUInt(false));
Assert.Equal((uint)1, NativeExportsNE.ReturnWinBoolAsUInt(true));
Assert.Equal((uint)0, NativeExportsNE.ReturnWinBoolAsUInt(false));
Assert.Equal((uint)1, NativeExportsNE.ReturnDefaultBoolAsUInt(true));
Assert.Equal((uint)0, NativeExportsNE.ReturnDefaultBoolAsUInt(false));
}

[Theory]
Expand All @@ -90,12 +116,16 @@ public void ValidateByteBoolReturns(uint value, bool expected)
Assert.Equal(expected, NativeExportsNE.ReturnUIntAsByteBool(value));

bool result = !expected;
NativeExportsNE.ReturnUIntAsRefByteBool(value, ref result);
NativeExportsNE.ReturnUIntAsByteBool_Ref(value, ref result);
Assert.Equal(expected, result);

result = !expected;
NativeExportsNE.ReturnUIntAsOutByteBool(value, out result);
NativeExportsNE.ReturnUIntAsByteBool_Out(value, out result);
Assert.Equal(expected, result);

result = !expected;
NativeExportsNE.ReturnUIntAsByteBool_In(value, in result);
Assert.Equal(!expected, result); // Should not be updated when using 'in'
}

[Theory]
Expand All @@ -110,12 +140,16 @@ public void ValidateVariantBoolReturns(uint value, bool expected)
Assert.Equal(expected, NativeExportsNE.ReturnUIntAsVariantBool(value));

bool result = !expected;
NativeExportsNE.ReturnUIntAsRefVariantBool(value, ref result);
NativeExportsNE.ReturnUIntAsVariantBool_Ref(value, ref result);
Assert.Equal(expected, result);

result = !expected;
NativeExportsNE.ReturnUIntAsOutVariantBool(value, out result);
NativeExportsNE.ReturnUIntAsVariantBool_Out(value, out result);
Assert.Equal(expected, result);

result = !expected;
NativeExportsNE.ReturnUIntAsVariantBool_In(value, in result);
Assert.Equal(!expected, result); // Should not be updated when using 'in'
}

[Theory]
Expand All @@ -129,12 +163,39 @@ public void ValidateWinBoolReturns(uint value, bool expected)
Assert.Equal(expected, NativeExportsNE.ReturnUIntAsWinBool(value));

bool result = !expected;
NativeExportsNE.ReturnUIntAsRefWinBool(value, ref result);
NativeExportsNE.ReturnUIntAsWinBool_Ref(value, ref result);
Assert.Equal(expected, result);

result = !expected;
NativeExportsNE.ReturnUIntAsOutWinBool(value, out result);
NativeExportsNE.ReturnUIntAsWinBool_Out(value, out result);
Assert.Equal(expected, result);

result = !expected;
NativeExportsNE.ReturnUIntAsWinBool_In(value, in result);
Assert.Equal(!expected, result); // Should not be updated when using 'in'
}

[Theory]
[InlineData(new object[] { 0, false })]
[InlineData(new object[] { 1, true })]
[InlineData(new object[] { 37, true })]
[InlineData(new object[] { 0xffffffff, true })]
[InlineData(new object[] { 0x80000000, true })]
public void ValidateDefaultBoolReturns(uint value, bool expected)
{
Assert.Equal(expected, NativeExportsNE.ReturnUIntAsDefaultBool(value));

bool result = !expected;
NativeExportsNE.ReturnUIntAsDefaultBool_Ref(value, ref result);
Assert.Equal(expected, result);

result = !expected;
NativeExportsNE.ReturnUIntAsDefaultBool_Out(value, out result);
Assert.Equal(expected, result);

result = !expected;
NativeExportsNE.ReturnUIntAsDefaultBool_In(value, in result);
Assert.Equal(!expected, result); // Should not be updated when using 'in'
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ partial class NativeExportsNE
public static partial char ReturnUIntAsUnicode(uint input);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "char_return_as_refuint", CharSet = CharSet.Unicode)]
public static partial void ReturnUIntAsRefUnicode(uint input, ref char res);
public static partial void ReturnUIntAsUnicode_Ref(uint input, ref char res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "char_return_as_refuint", CharSet = CharSet.Unicode)]
public static partial void ReturnUIntAsOutUnicode(uint input, out char res);
public static partial void ReturnUIntAsUnicode_Out(uint input, out char res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "char_return_as_refuint", CharSet = CharSet.Unicode)]
public static partial void ReturnUIntAsUnicode_In(uint input, in char res);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "char_return_as_uint", CharSet = CharSet.None)]
[return: MarshalAs(UnmanagedType.U2)]
Expand Down Expand Up @@ -53,13 +56,18 @@ public void ValidateUnicodeReturns(char expected, uint value)
{
Assert.Equal(expected, NativeExportsNE.ReturnUIntAsUnicode(value));

char result = '\u0000';
NativeExportsNE.ReturnUIntAsRefUnicode(value, ref result);
char initial = '\u0000';
char result = initial;
NativeExportsNE.ReturnUIntAsUnicode_Ref(value, ref result);
Assert.Equal(expected, result);

result = '\u0000';
NativeExportsNE.ReturnUIntAsOutUnicode(value, out result);
result = initial;
NativeExportsNE.ReturnUIntAsUnicode_Out(value, out result);
Assert.Equal(expected, result);

result = initial;
NativeExportsNE.ReturnUIntAsUnicode_In(value, in result);
Assert.Equal(initial, result); // Should not be updated when using 'in'
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ protected override bool ReleaseHandle()
[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "alloc_handle")]
public static partial NativeExportsSafeHandle AllocateHandle();

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "alloc_handle_out")]
public static partial void AllocateHandle(out NativeExportsSafeHandle handle);

[GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "release_handle")]
[return:MarshalAs(UnmanagedType.I1)]
private static partial bool ReleaseHandle(nint handle);
Expand Down Expand Up @@ -52,6 +55,16 @@ public void ByValue_CorrectlyUnwrapsHandle()
Assert.True(NativeExportsNE.IsHandleAlive(handle));
}

[Fact]
public void ByRefOut_CreatesSafeHandle()
{
NativeExportsNE.NativeExportsSafeHandle handle;
NativeExportsNE.AllocateHandle(out handle);
Assert.False(handle.IsClosed);
Assert.False(handle.IsInvalid);
handle.Dispose();
}

[Fact]
public void ByRefSameValue_UsesSameHandleInstance()
{
Expand Down
Loading

0 comments on commit a072658

Please sign in to comment.