Additional tests for type equivalence (#21340)
authorAaron Robinson <arobins@microsoft.com>
Wed, 5 Dec 2018 01:59:28 +0000 (17:59 -0800)
committerGitHub <noreply@github.com>
Wed, 5 Dec 2018 01:59:28 +0000 (17:59 -0800)
* Additional tests for type equivalence

tests/src/Interop/StringMarshalling/VBByRefStr/PInvokeDef.cs
tests/src/baseservices/typeequivalence/contracts/Types.cs
tests/src/baseservices/typeequivalence/impl/Impls.cs
tests/src/baseservices/typeequivalence/simple/Simple.cs

index 12d29ed..71759c5 100644 (file)
@@ -6,11 +6,13 @@ using System;
 using System.Text;
 using System.Runtime.InteropServices;
 
+#pragma warning disable 0618 // disable the obsolete warning
+
 class VBByRefStrNative
 {
-    
     [DllImport(nameof(VBByRefStrNative), CharSet = CharSet.Ansi)]
     public static extern bool Marshal_Ansi(string expected, [MarshalAs(UnmanagedType.VBByRefStr)] ref string actual, string newValue);
+
     [DllImport(nameof(VBByRefStrNative), CharSet = CharSet.Unicode)]
     public static extern bool Marshal_Unicode(string expected, [MarshalAs(UnmanagedType.VBByRefStr)] ref string actual, string newValue);
 
@@ -20,3 +22,5 @@ class VBByRefStrNative
     [DllImport(nameof(VBByRefStrNative), EntryPoint = "Marshal_Invalid")]
     public static extern bool Marshal_ByVal([MarshalAs(UnmanagedType.VBByRefStr)]string str);
 }
+
+#pragma warning restore 0618
index 5163a6f..6e29e7a 100644 (file)
@@ -15,4 +15,50 @@ namespace TypeEquivalenceTypes
     public interface IEmptyType
     {
     }
+
+    [ComImport]
+    [Guid("729E8A0A-ECAB-46F3-A151-EB494B92D40D")]
+    public interface IMethodTestType
+    {
+        /// <summary>
+        /// Multiply the input value by the implementation's scale
+        /// e.g. scale = 6, i = 3, result = 18
+        /// </summary>
+        int ScaleInt(int i);
+
+        /// <summary>
+        /// Duplicate the input string by the implementation's scale
+        /// e.g. scale = 3, s = "ab", result = "ababab"
+        /// </summary>
+        string ScaleString(string s);
+    }
+
+    /// <summary>
+    /// Interface used for validating sparse embedded types
+    /// </summary>
+    [ComImport]
+    [Guid("8220DE7C-79FF-40C5-9075-0031514C6930")]
+    public interface ISparseType
+    {
+        int MultiplyBy1(int a);
+        int MultiplyBy2(int a);
+        int MultiplyBy3(int a);
+        int MultiplyBy4(int a);
+        int MultiplyBy5(int a);
+        int MultiplyBy6(int a);
+        int MultiplyBy7(int a);
+        int MultiplyBy8(int a);
+        int MultiplyBy9(int a);
+        int MultiplyBy10(int a);
+        int MultiplyBy11(int a);
+        int MultiplyBy12(int a);
+        int MultiplyBy13(int a);
+        int MultiplyBy14(int a);
+        int MultiplyBy15(int a);
+        int MultiplyBy16(int a);
+        int MultiplyBy17(int a);
+        int MultiplyBy18(int a);
+        int MultiplyBy19(int a);
+        int MultiplyBy20(int a);
+    }
 }
index e9129fe..baf96c0 100644 (file)
@@ -3,6 +3,8 @@
 // See the LICENSE file in the project root for more information.
 
 using System;
+using System.Text;
+using System.Reflection;
 using System.Runtime.InteropServices;
 
 using TypeEquivalenceTypes;
@@ -16,4 +18,94 @@ public class EmptyType : IEmptyType
     {
         return new EmptyType();
     }
+}
+
+/// <summary>
+/// Implementation of interfaces that have no impact on inputs.
+/// </summary>
+public class IdempotentImpl : IMethodTestType
+{
+    public int ScaleInt(int i)
+    {
+        return i;
+    }
+
+    public string ScaleString(string s)
+    {
+        return s;
+    }
+}
+
+public class MethodTestBase : IMethodTestType
+{
+    private readonly int scaleValue;
+
+    /// <summary>
+    /// Create an instance of <see cref="MethodTestBase" />
+    /// </summary>
+    public static object Create(int scaleValue)
+    {
+        return new MethodTestBase(scaleValue);
+    }
+
+    protected MethodTestBase(int scaleValue)
+    {
+        this.scaleValue = scaleValue;
+    }
+
+    public virtual int ScaleInt(int i)
+    {
+        return this.scaleValue * i;
+    }
+
+    public virtual string ScaleString(string s)
+    {
+        var sb = new StringBuilder(this.scaleValue * s.Length);
+        for (int i = 0; i < this.scaleValue; ++i)
+        {
+            sb.Append(s);
+        }
+
+        return sb.ToString();
+    }
+}
+
+public class SparseTest : ISparseType
+{
+    /// <summary>
+    /// Create an instance of <see cref="SparseTest" />
+    /// </summary>
+    public static object Create()
+    {
+        return new SparseTest();
+    }
+
+    /// <summary>
+    /// Get the number of methods on the <see cref="ISparseType" /> interface
+    /// </summary>
+    public static int GetSparseInterfaceMethodCount()
+    {
+        return typeof(ISparseType).GetMethods(BindingFlags.Public | BindingFlags.Instance).Length;
+    }
+
+    public int MultiplyBy1(int a) { return a * 1; }
+    public int MultiplyBy2(int a) { return a * 2; }
+    public int MultiplyBy3(int a) { return a * 3; }
+    public int MultiplyBy4(int a) { return a * 4; }
+    public int MultiplyBy5(int a) { return a * 5; }
+    public int MultiplyBy6(int a) { return a * 6; }
+    public int MultiplyBy7(int a) { return a * 7; }
+    public int MultiplyBy8(int a) { return a * 8; }
+    public int MultiplyBy9(int a) { return a * 9; }
+    public int MultiplyBy10(int a) { return a * 10; }
+    public int MultiplyBy11(int a) { return a * 11; }
+    public int MultiplyBy12(int a) { return a * 12; }
+    public int MultiplyBy13(int a) { return a * 13; }
+    public int MultiplyBy14(int a) { return a * 14; }
+    public int MultiplyBy15(int a) { return a * 15; }
+    public int MultiplyBy16(int a) { return a * 16; }
+    public int MultiplyBy17(int a) { return a * 17; }
+    public int MultiplyBy18(int a) { return a * 18; }
+    public int MultiplyBy19(int a) { return a * 19; }
+    public int MultiplyBy20(int a) { return a * 20; }
 }
\ No newline at end of file
index dd42ddd..0b6a54d 100644 (file)
@@ -3,6 +3,9 @@
 // See the LICENSE file in the project root for more information.
 
 using System;
+using System.Linq;
+using System.Text;
+using System.Reflection;
 using System.Runtime.InteropServices;
 
 using TestLibrary;
@@ -21,26 +24,111 @@ public class Simple
         }
     }
 
-    private static void InterfaceTypesFromDifferentAssembliesAreEqual()
+    private static void InterfaceTypesFromDifferentAssembliesAreEquivalent()
     {
-        Console.WriteLine("Interfaces are the same");
+        Console.WriteLine($"{nameof(InterfaceTypesFromDifferentAssembliesAreEquivalent)}");
         var inAsm = EmptyType.Create();
-        DisplayType((IEmptyType)inAsm);
-
         var otherAsm = EmptyType2.Create();
-        DisplayType((IEmptyType)otherAsm);
 
-        void DisplayType(IEmptyType i)
+        AreNotSameObject((IEmptyType)inAsm, (IEmptyType)otherAsm);
+
+        void AreNotSameObject(IEmptyType a, IEmptyType b)
+        {
+            Assert.AreNotEqual(a, b);
+        }
+    }
+
+    private class MethodTestDerived : MethodTestBase
+    {
+        private readonly int scaleValue;
+
+        private IMethodTestType inner;
+
+        /// <summary>
+        /// Create an instance of <see cref="MethodTestDerived" />
+        /// </summary>
+        public static object Create(int scaleValue, int baseScaleValue)
+        {
+            return new MethodTestDerived(scaleValue, baseScaleValue);
+        }
+
+        private MethodTestDerived(int scaleValue, int baseScaleValue)
+            : base(baseScaleValue)
+        {
+            this.scaleValue = scaleValue;
+        }
+
+        public override int ScaleInt(int i)
+        {
+            return base.ScaleInt(i) * this.scaleValue;
+        }
+
+        public override string ScaleString(string s)
         {
-            Console.WriteLine(i.GetType());
+            string baseValue = base.ScaleString(s);
+            var sb = new StringBuilder(this.scaleValue * baseValue.Length);
+            for (int i = 0; i < this.scaleValue; ++i)
+            {
+                sb.Append(baseValue);
+            }
+
+            return sb.ToString();
+        }
+    }
+
+    private static void InterfaceTypesMethodOperations()
+    {
+        Console.WriteLine($"{nameof(InterfaceTypesMethodOperations)}");
+
+        int baseScale = 2;
+        int derivedScale = 3;
+        object baseInst = MethodTestBase.Create(baseScale);
+        object derivedInst = MethodTestDerived.Create(derivedScale, baseScaleValue: baseScale);
+
+        var baseInterface = (IMethodTestType)baseInst;
+        var derivedBase = (MethodTestBase)derivedInst;
+
+        {
+            int input = 67;
+            int expectedBaseValue = input * baseScale;
+            int expectedDerivedValue = expectedBaseValue * derivedScale;
+
+            Assert.AreEqual(expectedBaseValue, baseInterface.ScaleInt(input));
+            Assert.AreEqual(expectedDerivedValue, derivedBase.ScaleInt(input));
         }
+
+        {
+            string input = "stringToScale";
+            string expectedBaseValue = string.Concat(Enumerable.Repeat(input, baseScale));
+            string expectedDerivedValue = string.Concat(Enumerable.Repeat(expectedBaseValue, derivedScale));
+
+            Assert.AreEqual(expectedBaseValue, baseInterface.ScaleString(input));
+            Assert.AreEqual(expectedDerivedValue, derivedBase.ScaleString(input));
+        }
+    }
+
+    private static void CallSparseInterface()
+    {
+        Console.WriteLine($"{nameof(CallSparseInterface)}");
+
+        int sparseTypeMethodCount = typeof(ISparseType).GetMethods(BindingFlags.Public | BindingFlags.Instance).Length;
+        Assert.AreEqual(2, sparseTypeMethodCount, "Should have limited method metadata");
+
+        var sparseType = (ISparseType)SparseTest.Create();
+        Assert.AreEqual(20, SparseTest.GetSparseInterfaceMethodCount(), "Should have all method metadata");
+
+        int input = 63;
+        Assert.AreEqual(input * 7, sparseType.MultiplyBy7(input));
+        Assert.AreEqual(input * 18, sparseType.MultiplyBy18(input));
     }
 
     public static int Main(string[] noArgs)
     {
         try
         {
-            InterfaceTypesFromDifferentAssembliesAreEqual();
+            InterfaceTypesFromDifferentAssembliesAreEquivalent();
+            InterfaceTypesMethodOperations();
+            CallSparseInterface();
         }
         catch (Exception e)
         {