C# Unit Test: How to create test input of COM Interop value? - c#

In my application, there is a method which accepts an Object, then performs some operations on it to return a C# long value. At runtime, the Object received from Active Directory is an IADSLargeInteger.
In writing a unit test for this code, I am unable to create such an object to pass into the method being tested.
How can I create such an object for my unit test?
Are there other ways to verify the logic of my method?
Method to be tested:
public static long ConvertLargeIntegerToLong(object largeInteger)
{
var type = largeInteger.GetType();
var highPart = (int)type.InvokeMember("HighPart", BindingFlags.GetProperty, null, largeInteger, null)!;
var lowPartInt = (int)type.InvokeMember("LowPart", BindingFlags.GetProperty | BindingFlags.Public, null, largeInteger, null)!;
uint lowPartUint;
unchecked
{
lowPartUint = (uint)lowPartInt;
}
return (long)highPart << 32 | (long)lowPartUint;
}
Sample Unit Test
public void ConvertLargeIntegerToLong_ComObjectLargeInt_Long()
{
var expectedValue = 94294967295;
var testValue = ??; // What to put here?
var result = ConvertLargeIntegerToLong(testValue);
Assert.AreEqual(expectedValue, result);
}

After asking the question, I continued hunting around and thought to add the activeds.dll as a COM reference to my test project.
After I did that, I had direct access to the IADSLargeInteger interface. And looking more closely at the Microsoft docs for the interface, saw an example creating such an object for VB.Net.
In the end, I did like this for my code (still maintaining the COM reference):
var testValue = new LargeInteger { HighPart = 1234, LowPart = 4567 };
LargeInteger is also in that DLL and is the concrete class implementing the interface -- as #Hans Passant mentioned in his comment.

Related

When implementing an interface that has a method with 'in' parameter by TypeBuilder.CreateType, TypeLoadException is thrown

Before beginning, this is my first question on SO. So there might be faults or lack of information about the problem. Please let me know if there's something that I need to correct. Thanks.
Using TypeBuilder, I'm building a class that implements an interface that contains a method. After implementing that method with ILGenerator, then I call TypeBuilder.CreateType() and everything goes well in the normal case.
But if the method contains any parameter with the in modifier, also known as readonly reference for value types, TypeBuilder.CreateType() throws TypeLoadException("Method 'SomeMethod' ... does not have an implementation.").
Unlike the usual case of TypeLoadException that implemented method with the same signature as the one declared in the interface(s) doesn't exist, this problem is raised only when the method contains in parameter(s) even signatures are the same. When I remove or change the in modifier to ref or out, TypeBuilder.CreateType() successfully recognizes the generated method as an implementation of one declared in the interface, and the type is built normally.
Here's a fully compilable example:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace EmitMethodWithInParamTest
{
public struct StructParam
{
public String Data;
}
public interface ISomeInterface
{
Int32 SomeMethod(in StructParam param);
}
static class EmitExtension
{
public static void ReplicateCustomAttributes(this ParameterBuilder paramBuilder, ParameterInfo paramInfo)
{
foreach (var attrData in paramInfo.GetCustomAttributesData())
{
var ctorArgs = attrData.ConstructorArguments.Select(arg => arg.Value).ToArray();
// Handling variable arguments
var ctorParamInfos = attrData.Constructor.GetParameters();
if (ctorParamInfos.Length > 0 &&
ctorParamInfos.Last().IsDefined(typeof(ParamArrayAttribute)) &&
ctorArgs.Last() is IReadOnlyCollection<CustomAttributeTypedArgument> variableArgs)
{
ctorArgs[ctorArgs.Length - 1] = variableArgs.Select(arg => arg.Value).ToArray();
}
var namedPropArgs = attrData.NamedArguments.Where(arg => !arg.IsField);
var namedPropInfos = namedPropArgs.Select(arg => (PropertyInfo)arg.MemberInfo).ToArray();
var namedPropValues = namedPropArgs.Select(arg => arg.TypedValue.Value).ToArray();
var namedFieldArgs = attrData.NamedArguments.Where(arg => arg.IsField);
var namedFieldInfos = namedFieldArgs.Select(arg => (FieldInfo)arg.MemberInfo).ToArray();
var namedFieldValues = namedFieldArgs.Select(arg => arg.TypedValue.Value).ToArray();
var attrBuilder = new CustomAttributeBuilder(attrData.Constructor,
ctorArgs, namedPropInfos, namedPropValues, namedFieldInfos, namedFieldValues);
paramBuilder.SetCustomAttribute(attrBuilder);
}
}
}
class Program
{
static Program()
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-us");
}
static void Main(String[] args)
{
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
var typeBuilder = moduleBuilder.DefineType("SomeClass",
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout,
null /*base class*/,
new[] { typeof(ISomeInterface) });
var methodInfoToImpl = typeof(ISomeInterface).GetMethod(nameof(ISomeInterface.SomeMethod));
var paramInfos = methodInfoToImpl.GetParameters();
var methodBuilder = typeBuilder.DefineMethod(methodInfoToImpl.Name,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final,
CallingConventions.HasThis,
methodInfoToImpl.ReturnType,
paramInfos.Select(pi => pi.ParameterType).ToArray());
foreach (var paramInfo in paramInfos)
{
// paramInfo.Position is zero-based but DefineParameter requires 1-based index.
var paramBuilder = methodBuilder.DefineParameter(paramInfo.Position + 1, paramInfo.Attributes, paramInfo.Name);
if (paramInfo.Attributes.HasFlag(ParameterAttributes.HasDefault))
{
paramBuilder.SetConstant(paramInfo.DefaultValue);
}
paramBuilder.ReplicateCustomAttributes(paramInfo);
}
// Dummy implementation for example. Always throws NotImplementedException.
var ilGen = methodBuilder.GetILGenerator();
ilGen.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Throw);
var builtType = typeBuilder.CreateType(); // <- TypeLoadException("Method 'SomeMethod' in type 'SomeClass' from assembly 'DynamicAssembly, ...' does not have an implementation.") is thrown.
var generatedObj = (ISomeInterface)Activator.CreateInstance(builtType);
var someParam = new StructParam() { Data = "SomeData" };
var result = generatedObj.SomeMethod(in someParam); // <- NotImplementedException expected by dummy implementation if executed.
Console.WriteLine($"Result: {result}");
}
}
}
This code is also uploaded to Pastebin.
While digging down this problem, I found that the in parameter has two custom attributes, InteropServices.InAttribute and CompilerServices.IsReadOnlyAttribute. But when I generate a method without implementing the interface (this succeeds normally because no signature matching required), in parameter of generated method has only one custom attribute, InAttribute. So I replicated all custom attributes of parameters from the interface, but still TypeLoadException is being raised.
I've tested this on .NET Framework 4.6.1 and .NET Core 2.2 with C# 7.2 and 7.3. And all environments gave me the same exception. I'm using Visual Studio 2017 on Windows.
Is there anything that I have missed or are there any workarounds?
Thank you for any help in advance.
After writing the question above, I've been investigated built binary of sample code in IL and source code of CoreCLR for a few days, and now I found the problem and solution.
In short, required and optional custom modifiers of return type and each parameter type take a part of method signature like each types do, and it had to be replicated manually. I thought that it will be done by passing ParameterAttributes.In to MethodBuilder.DefineParameter and replicating the custom attribute InAttribute, but it was wrong.
And, among in, ref and out modifiers, only in emits a required custom modifier to specified parameter. In contrast, ref and out are represented only with their type itself. This is the reason why only in didn't work as expected.
To replicate custom modifiers, call to TypeBuilder.DefineMethod need be modified like this:
var methodBuilder = typeBuilder.DefineMethod(methodInfoToImpl.Name,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final,
CallingConventions.HasThis,
methodInfoToImpl.ReturnType,
methodInfoToImpl.ReturnParameter.GetRequiredCustomModifiers(), // *
methodInfoToImpl.ReturnParameter.GetOptionalCustomModifiers(), // *
paramInfos.Select(pi => pi.ParameterType).ToArray(),
paramInfos.Select(pi => pi.GetRequiredCustomModifiers()).ToArray(), // *
paramInfos.Select(pi => pi.GetOptionalCustomModifiers()).ToArray() // *
);
Marked lines with // * are newly added to replicate custom modifiers of return/parameter types.
Or, we can do this by calling MethodBuilder.SetSignature method after calling DefineMethod without any type and custom modifiers arguments. If we decided to call SetSignature separately, we need to call it before any DefineParameter, SetCustomAttribute, Equals(Object), SetImplementationFlags, getter of property Signature and many other methods that call the internal method MethodBuilder.GetMethodSignature() that cache bytes representing method signature.
Thank you for reading and giving me advice. :)

Calling function from ComImport class doesn't fail as expected

I'm trying to verify that the class I'm trying to use via COM works as expected. Unfortunately it seems to succeed on a call which should fail:
enum X509CertificateEnrollmentContext
{
ContextUser = 0x1,
ContextMachine = 0x2,
ContextAdministratorForceMachine = 0x3
}
[ComImport(), Guid("884e2045-217d-11da-b2a4-000e7bbb2b09")]
class Cenroll { }
[Guid("728ab35d-217d-11da-b2a4-000e7bbb2b09")]
interface IX509CertificateRequestCmc2
{
void InitializeFromTemplate(
[In] X509CertificateEnrollmentContext Context,
[In] IX509EnrollmentPolicyServer pPolicyServer,
[In] IX509CertificateTemplate pTemplate);
}
static void Main(string[] args)
{
var cr = new Cenroll();
var cmc2 = (IX509CertificateRequestCmc2)cr;
cmc2.InitializeFromTemplate(X509CertificateEnrollmentContext.ContextUser, null, null);
}
Casting from Cenroll to the interface works, which indicates that the guids are ok. (and it fails casting to other guids, so it's not random success)
But when I call InitializeFromTemplate, with both parameters set to null, it succeeds. The documentation says that the result should be an E_POINTER error:
Return code - Description
E_POINTER - The pPolicyServer and pTemplate parameters cannot be NULL.
So why don't I see an exception?
The problem is that you are redeclaring the interface, and the new definition is different from the original.
Guids are OK, but underneath, QueryInterface implementation checks GUID, and returns the pointer to the implementation - this is the interface vtable and method addresses are calculated relative to this address (when a call to the method is compiled, offset of the method is added to this address to get the actuall address).
In your implementation, InitializeFromTemplate is the first method and generated client code calls the method at the beginning of vtable.
However, in the original interface, there are 56 other methods before InitializeFromTemplate because there is an inheritance chain:
IX509CertificateRequest (25 methods)
|
+-> IX509CertificateRequestPkcs7 (8 methods)
|
+-> IX509CertificateRequestCmc (23 methods)
|
+-> IX509CertificateRequestCmc2
Function addresses in the certenroll.dll adhere to this layout, so when you call InitializeFromTemplate as declared in your interface, you are calling the first method in chain which is actually IX509CertificateRequest::Initialize.
As an experiment, if you add 56 dummy methods before InitializeFromTemplate in your IX509CertificateRequestCmc2 you will correctly receive an exception:
[Guid("728ab35d-217d-11da-b2a4-000e7bbb2b09")]
interface IX509CertificateRequestCmc
{
void fn1();
void fn2();
...
void fn56();
void InitializeFromTemplate(...);
}
The call will throw: CertEnroll::CX509CertificateRequestCmc::InitializeFromTemplate: Invalid pointer 0x80004003 (-2147467261)
Of course, the solution is not to add the dummy methods :) You should use the generated interop types instead of providing your own. As you are referencing the certenroll assembly, I don't understand why don't you simply use those generated interop classes. Here's the full example which behaves as expected:
using CERTENROLLLib;
namespace comcerttest
{
class Program
{
static void Main(string[] args)
{
// If you are embedding the interop types, note that you must
// remove the `Class` suffix from generated type name in order
// to instantiate it. See link at the bottom for explanation:
var cr = new CX509CertificateRequestCmc();
var cmc2 = (IX509CertificateRequestCmc2)cr;
cmc2.InitializeFromTemplate(X509CertificateEnrollmentContext.ContextUser, null, null);
}
}
}
The issue with using class vs interface type is explained here:
Using embedded interop types

C# mutantion testing - change method runtime with il code

You can skip to my approach if you don't mind what I'm actually trying to do.
What I'm trying to do
Hey I'm trying to make mutant testing,
inspired by the talk
http://www.infoq.com/presentations/kill-better-test
But I'm using c# and the best mutant libraries are made in java such as
http://pitest.org/
There are some frameworks for c# such as ninjaturtles and visualmutator,
but they both doesn't work in my computer for some reason(I get a weird error).
and also I thought it would be interesting creating my own.
About mutant testing
For those who doesn't know what is mutant testing,
it's a testing for the tests, most people use
code coverage to check that their test cover all the scenarios,
but it's not enough,
cause just because it gets to a piece of code doesn't mean it tests it.
It changes a piece of code, and if the tests still pass
it means you didn't tested the piece of code.
My approach
So I've tried starting with a simple code
that gets the il codes of a method.
var classType = typeof(MethodClass);
var methodInfo = classType.GetMethod("ExecuteMethod", BindingFlags.NonPublic | BindingFlags.Static);
byte[] ilCodes = methodInfo.GetMethodBody().GetILAsByteArray();
this is the MethodClass I'm trying to change:
public class MethodClass
{
private static int ExecuteMethod()
{
var i = 0;
i += 5;
if (i >= 5)
{
i = 2;
}
return i;
}
}
now I'm trying to replace the ils
for (int i = 0; i < ilCodes.Length; i++)
{
if (ilCodes[i] == OpCodes.Add.Value)
{
ilCodes[i] = (byte)OpCodes.Sub.Value;
}
}
but then I'm not sure how to update my function to work with the new il codes.
I've tried using
var dynamicFunction = new DynamicMethod("newmethod", typeof(int), null);
var ilGenerator = dynamicFunction.GetILGenerator();
and then the il generator has a function emit, that gets operator and value, so I could use this. but I don't have the value to put in the emit..
Does anybody know how to do it?

I am not able to test Application Variables in my Test Project

I was trying to do some POC on Test Drven Development. In my project I am using Application State Variables, So I need to fake them as HttpContext is not available during TDD execution.
I have search and found some code to fake the Application variable. The code looks like this:
[TestMethod()]
public void StartReportService_ApplicationStateShouldContainMyIndex()
{
//No HttpApplicationBase in System.Web.Abstractions, must use Real Object
var application = new Mock<HttpApplication>();
//Real object does not have a property of type HttpApplicationStateBase so must use real one?
//var applicationStateBase = new Mock<HttpApplicationStateBase>();
//real one not creable so HACK get private constructor
var ctor = typeof(HttpApplicationState).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { }, new ParameterModifier[] { });
var applicationState = (HttpApplicationState)ctor.Invoke(new Object[] { });
//fails here, HttpApplication.Application not overridable
application.SetupProperty(x => x.Application, applicationState);
var plugin = HttpApplicationPlugin.HttpApplicationPluginInstance;
plugin.Application_Start(application.Object,null);
}
I am not able to find the HttpApplicationPlugin class. Could anyone please help?

Library to generate class that has inline constructor in another assembly with random data?

I'm receiving event notifications from web services that trigger event handlers with data regarding what triggered the event. I'm trying to test that once an event handler is called that a, b and c are all called with the proper values. This isn't possible without relying on the web service
My solution is to create converters that convert the EventArgs that are returned to my via the services library (Exchange Web Services) to something my dumb objects can understand without relying on third part services. My issue is that the EventArgs class given to my by the EWS library has an internal constructor so there's no easy way to generate an instance of it with random property values without much work with reflection.
For example, I have a simply interface:
public interface IConverter<TFrom, TTo>
{
TTo Convert(TFrom from);
}
and a simple implementation:
public class NotificationEventArgsConverter : IConverter<NotificationEventArgs, NewNotification>
{
public NewNotification Convert(NotificationEventArgs from)
{
return new NewNotification
{
ItemIds = from.Events.Cast<ItemEvent>().Select(x => x.ItemId.ToString())
};
}
}
Question is how can I generate an instance of NotificationEventArgs with random values. Is there a library for this that I missed in my searches?
The entire goal of this is to emulate if I receive an instance of NotificationEventArgs with the following values then NewNotification should resemble x.
Edit
In the meantime I will simply use typeof(T).GetConstructor().
You might want to take a look at AutoFixture:
AutoFixture makes it easier for developers to do Test-Driven Development by automating non-relevant Test Fixture Setup, allowing the Test Developer to focus on the essentials of each test case.
After doing some decompilation of Microsoft.Exchange.WebServices and playing bit with reflection, you can do it for example like this:
var fixture = new Fixture();
// retrieve internal FolderEvent(EventType, DateTime) ctor
// using FolderEvent class as NotificationEvent is abstract
var notificationEventCtor = typeof(FolderEvent).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new Type[] { typeof(EventType), typeof(DateTime) },
null
);
// generate 10 random events with some help of LINQ and AutoFixture
var trashData = Enumerable
.Range(1, 10)
.Select(i => new object[]
{
fixture.CreateAnonymous<EventType>(),
fixture.CreateAnonymous<DateTime>()
})
.Select(p => notificationEventCtor.Invoke(p))
.Cast<NotificationEvent>()
.ToList();
Code above will generate 10 FolderEvents in a list, ready to pass to NotificationEventArgs constructor (which is internal again, so same code applies):
var notificationEventArgsCtor = typeof(NotificationEventArgs).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new Type[]
{
typeof(StreamingSubscription),
typeof(IEnumerable<NotificationEvent>)
},
null
);
var instance = notificationEventArgsCtor
.Invoke(new object[] { null, trashData });
Take a look at the PrivateObject class (specifically these constructor overloads). It wraps all the reflection work for you and allows you to create objects with non-public constructors, as well as access non-public methods and properties of those objects. You can get the underlying objects via the Target property.

Categories