4

I want to automate some test to check the ability of a programmer to write efficient algorithm. In this sample, the algorithm is to perform a simple binary search in an array of int.

public class ComplexityPractice
{
    public bool BinarySearch(int [] sortedArray, int value)
    {
        // to be implement 
    }
}

Note : This code is loaded by reflection in a restricted domain.

The easist way to implement this method is of course Array.BinarySearch(sortedArray, value) from the .NET library. But my goal is to check the ability of the programmer to produce the code himself, so the question is :

How could I prevent the programmer from using function from Array class?

Perfect28
  • 11,089
  • 3
  • 25
  • 45
  • 2
    You man other than reading the code? – D Stanley Mar 12 '15 at 13:17
  • Do a string search, use a simple C# parser and check for the call (eg using ANTLR), use Roslyn to parse the code then check for the call – Panagiotis Kanavos Mar 12 '15 at 13:17
  • You could go through a number of contrivances, including replacing the .NET assembly on the target machine, a compiler build step, a SonarQube style parser on your build system. Really, you should just read the code. – Jeff Watkins Mar 12 '15 at 13:18
  • 1
    The OP is asking how to create a certification-style test to check a student's code, not how to write a unit test or perform code analysis. I think the question needs clarification – Panagiotis Kanavos Mar 12 '15 at 13:19
  • 1
    You'd need some sort of static analysis tool that allows you to define custom rules, and then figure out how to force them to _use_ the rule. – D Stanley Mar 12 '15 at 13:20
  • 1
    If I search "C# Binary Search" the first page of results has 4 implementations. Restricting Array.BinarySearch won't stop students from being lazy. – RossFabricant Mar 12 '15 at 13:26
  • Simply specify on the test that the student must write his own implementation of the binary search and cannot use predefined functions as Array.BinarySearch or he'll get a 0 – Mathieu Bourgoin Mar 12 '15 at 13:28
  • 2
    If this is for testing programmers in a job interview and not for students learing algorithms I would actually rather fail everyone that _didnt_ use Array.BinarySearch :) That's much easier to check! – wasatz Mar 12 '15 at 13:29
  • @RossFabricant : You'r right, but the test is made in a closed space with no internet connection. – Perfect28 Mar 12 '15 at 13:29
  • A bit more context on what you are trying to accomplish/test would help. Then we're not loophole-searching as much. – ryanyuyu Mar 12 '15 at 13:30
  • 1
    I believe, you can adapt my answer from [Count of function execution in method on code compilation](http://stackoverflow.com/questions/25189214/count-of-function-execution-in-method-on-code-compilation) thread for your purposes. – DmitryG Mar 12 '15 at 13:43

2 Answers2

-1

Method 1:

Check if code is valid and then test if it contains method calls that are not allowed but you have to ignore string literals.
However, this will not stop the user to invoke methods by name if Reflection is available.

bool validCode = true;
string[] unallowedMethods = new string[] 
{
  "Array.BinarySearch",
  ...
};
string sourceCode = ...;
ICodeCompiler codeCompiler = ...;
CompilerResults results = codeCompiler.CompileAssemblyFromSource(parameters, sourceCode);
validCode = result.Errors.Count == 0;
if (validCode)
 foreach (method in unallowedMethods)
   if (sourceCode.Contains(method)))
   //improve this by checking if occurrence is not a string literal in program 
   {
      validCode = false;
      break;
   }

Method 2:

Test if a method calls another method using Mono Cecil:
Take a look at this answer

static class MethodDefinitionExtensions
{
    public static bool CallsMethod(this MethodDefinition caller, 
        MethodDefinition callee)
    {
        return caller.Body.Instructions.Any(x => 
            x.OpCode == OpCodes.Call && x.Operand == callee);
    }
}

class Program
{
    private static AssemblyDefinition _assembly = AssemblyDefinition.ReadAssembly(
        System.Reflection.Assembly.GetExecutingAssembly().Location);

    private static void Method1()
    {
        Method2();
    }

    private static void Method2()
    {
        Method1();
        Method3();
    }

    private static void Method3()
    {
        Method1();
    }

    private static IEnumerable<MethodDefinition> GetMethodsCalled(
        MethodDefinition caller)
    {
        return caller.Body.Instructions
            .Where(x => x.OpCode == OpCodes.Call)
            .Select(x => (MethodDefinition)x.Operand);
    }

    private static MethodDefinition GetMethod(string name)
    {
        TypeDefinition programType = _assembly.MainModule.Types
            .FirstOrDefault(x => x.Name == "Program");
        return programType.Methods.First(x => x.Name == name);
    }

    public static void Main(string[] args)
    {
        MethodDefinition method1 = GetMethod("Method1");
        MethodDefinition method2 = GetMethod("Method2");
        MethodDefinition method3 = GetMethod("Method3");

        Debug.Assert(method1.CallsMethod(method3) == false);
        Debug.Assert(method1.CallsMethod(method2) == true);
        Debug.Assert(method3.CallsMethod(method1) == true);

        Debug.Assert(GetMethodsCalled(method2).SequenceEqual(
            new List<MethodDefinition> { method1, method3 }));
    }
}
Community
  • 1
  • 1
B0Andrew
  • 1,725
  • 13
  • 19
-1

I would consider using Aspect Oriented Programming.

Specifically, I would checkout PostSharp.

PostSharp provides method boundaries that allow you to cancel the execution of a method prior to entering it.

Here's an example:

•OnEntry - Before the execution of the method body

•OnExit - Always called when a method is done executing even if there was an error

•OnSuccess - Called only when a method is done executing and there were no exceptions

•OnException - Called only when a method has stopped executing due to an unhandled exception

http://www.postsharp.net/blog/post/Day-4-OnMethodBoundaryAspect

Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118