net comments edit

Typemock Isolator 5.3.1 was released today, and with it the ability to mock base class constructors using a syntax like this:

Isolate.Fake.Instance<Derived>(Members.CallOriginal, ConstructorWillBe.Called, BaseConstructorWillBe.Ignored);

That’s pretty cool. But something I uncovered in working through a complex test scenario (and getting a little help from good old Typemock Support) is that you can mock a constructor N-levels deep using a slightly different syntax. The caveat is that it only works on types that have generic type parameters.

Let’s say you have a three-level-deep class hierarchy like this:

public class Level1<T>
{
  public Level1()
  {
    throw new NotSupportedException();
  }
}

public class Level2<T> : Level1<T>
{
  public bool Level2WasCalled { get; set; }
  public Level2()
  {
    this.Level2WasCalled = true;
  }
}

public class Level3<T> : Level2<T>
{
  public bool Level3WasCalled { get; set; }
  public Level3()
  {
    this.Level3WasCalled = true;
  }
}

You want to instantiate a Level3<T> object, and you want to run the Level2<T> constructor, but the Level1<T> constructor throws an exception so you want to stop running the real constructors there. It’s a little more complex setup, but you can do this:

[Test]
[Isolated]
public void SkipLevel1Constructor()
{
  var fakeBase = Isolate.Fake.Instance<Level1<string>>();
  Isolate.Swap.AllInstances<Level1<string>>().With(fakeBase);
  var fake = Isolate.Fake.Instance<Level3<string>>(Members.CallOriginal);
  Assert.IsTrue(fake.Level2WasCalled);
  Assert.IsTrue(fake.Level3WasCalled);
}

This test will pass. Now, granted, if you’re doing something more fancy, the Isolate.Swap.AllInstances call may have some unintended side effects since it’ll also intercept new instances of Level2<T> and so forth, but if you’re doing something reasonably simple where the Isolate.Swap.AllInstances is OK, here’s one way to skip an n-level deep constructor.

UPDATE: It appears you can use Isolate.Swap.NextInstance instead of Isolate.Swap.AllInstances, and that’s actually recommended so you have fewer potential side effects. No need to mock all instances if you don’t have to.

All of this, of course, gets the “Works On My Box” seal of approval, and the standard “if it totally hoses you or doesn’t work for you, sooooooorrrryyyyy” style disclaimer. Also, while I found this during sorting an issue out with Typemock Support, I can’t say they “officially support” doing what I’m telling you about here. It just happens to work. Whether it’s functioning as designed or whether we’re inadvertently exploiting something in the product that will be patched up later is yet to be seen.

I have a copy of the [older version of] Electronic Battleship: Advanced Mission game. We played it a bit, but we got really frustrated because the holes in the vertical grid were too big for the pegs to fit in well - a minor bump and the pegs would fall out, causing you to basically start the game over.

We shelved it for a while, but I found that Hasbro has replacement parts order forms, so I ordered a new set of pegs (in case it was actually the pegs that were too small) and a new set of grids (in case the grid holes were too big). I figured, like $7 total to fix the thing would be worth it since it was a $40 game anyway.

I got the parts and the pegs didn’t fit into the grid holes any better, so I figured it was definitely the grids. I looked at the replacement grids they sent… and the grids were too small. The regular Electronic Battleship grids apparently are 10 by 10 while Advanced Mission grids are 14 by 14.

I contacted their support department explaining the problem in detail and asking if they could send me some new Advanced Mission grids. They did me one better: They sent me a whole new game.

That, my friends, is customer service. Hasbro, you rock. Thanks a million!

Jenn and I played last night and it was a fantastic game. Came down to the very last turn - if I missed shooting down Jenn’s last ship, she was going to shoot my last ship down. I made the right guess and got her, but just by that one turn. Great game.

net comments edit

OK, so not really a contest so much as a very short “first come, first serve.” Typemock launched their ASP.NET bundle with Typemock Isolator and Ivonna, an ASP.NET testing tool, and they’ve given me a license to hand out to a lucky reader.

First person to leave a comment on this post wins. Make sure you fill in the “email address” field so I can contact you back. (Your address won’t actually appear on the blog, and I won’t use it for anything other than getting you your license, so don’t worry about spam.)

Good luck!

[UPDATE: The prize has been claimed!]

gists, dotnet, build, csharp comments edit

I’m working on an application where we wanted to be able to provide some config or command line parameters that would specify a particular set of files for processing. What might be considered the “standard” set of .NET framework libraries comes with System.IO.Directory.GetFiles(), but the wildcard support is pretty weak. I don’t want to find *.dll recursively, I want support like “recursively search folders under this tree for *.dll but exclude Foo.dll” or something.

So I started thinking - what has that sort of include/exclude support and robust wildcard matching?

MSBuild.

When you use the CreateItem task, you can specify all nature of wildcards, like this:

<CreateItem
 Include="**/bin/**/*.dll"
 Exclude="**/Foo.dll">
   <Output
    TaskParameter="Include"
    ItemName="MyItemName" />
</CreateItem>

The ** will be expanded to mean “any number of folders” and the filename wildcards will work to properly include/exclude files. Way, way better than GetFiles(). But how do you harness that power for your own use outside of a build system?

Actually, it turns out to be super easy. Basically:

  1. Add references to the Microsoft.Build.Framework, Microsoft.Build.Tasks, and Microsoft.Build.Utilities assemblies. They should be in the GAC.
  2. Instantiate a Microsoft.Build.Tasks.CreateItem task object.
  3. Add items to the Include/Exclude list.
  4. Execute the task and ensure the operation was successful.
  5. Read the results out of the “Include” property on the task object. Read the metadata off of the items using the “GetMetadata” method. The metadata items available are the MSBuild Well-Known Item Metadata values.

Here’s a code snippet showing a simple example:

// Instantiate the task
CreateItem task = new CreateItem();

// Add paths/wildcards to include
task.Include = new ITaskItem[]
{
  new TaskItem(@"C:\path\**\*.txt")
};

// Add paths/wildcards to exclude
task.Exclude = new ITaskItem[]
{
  new TaskItem(@"C:\path\bin\**\*.*"),
  new TaskItem(@"**\_svn\**\*.*"),
};

// Execute the task, check for success
bool success = task.Execute();
Console.WriteLine("Success: {0}", success);
if(!success)
{
  return;
}

// Get the list of matching items from "Include"
// and use the "GetMetadata" property to find out the path.
foreach(ITaskItem include in task.Include)
{
  Console.WriteLine("* {0}", include.GetMetadata("FullPath"));
}

Awesome! Now I don’t have to write that file finding code myself!