Sunday, June 12, 2005

I have created a project on http://projectdistributor.net for NSteer and will soon upload a drop to the server. If you are interrested by this project, suscribe to the RSS:

 

posted on Monday, June 13, 2005 1:17:38 AM UTC  #    Comments [0]
 Saturday, June 11, 2005

NSteer 2: Laying down some interfaces

In the previous episode, we laid down the concepts and “lexical” language about autonomous agents. We can start to design interfaces for each concept identified previously.  Here’s a concept summary to get started:

Concept summary

  • Dynamic concepts
    • Agent, the canonical autonomous agent,
    • Behavior, the canonical behavior,
    • Body, an instance defining the kinetic dynamics of the agent,
    • Vision, what the agent sees,
    • Integrators integrate the motion dynamics,
    • Saturators, saturate scalars and vectors,
  • Visualization concepts
    • Visualizable: can be visible/hidden, can be rendered,
    • Sprite: a graphical element with a background and a border
    • Artifact, a dynamic or visual artifact that can be attached to an agent (e.g. smoke trail, hallow, etc…). An artifact is owned by agent.
    • A scene is the graphical layer abstraction.
    • A world provides dimensions and projection methods,
  • Service concepts
    • Agent service, maintains a list of active actions,
    • World service, accesses world instance
    • Integrator service, manages agent movement integration and force resolution,
    • Behavior service, manages local and global behaviors,

On top of those concepts, remember that we are going to work with the System.Components model-container-services interfaces: IComponent, IContainer.

Dynamic concepts

An agent has a body, a behavior, a vision and can be visualized.
public interface IAgent : IComponent, IVisualizable
{
    IBody Body { get;}
    IBehavior Behavior { get;}
    IVision Vision { get;}
}
A behavior computes the steering force and is also considered as an artifact.
public interface IBehavior : IArtifact
{
    PointF ComputeSteering();
}
A body implements the kinetics of the agent and is as well an artifact.
public interface IBody : IArtifact
{
    float Mass { get;}
    PointF Position { get;}
    float Direction { get;}
    Referential Anchor { get;}
    PointF Velocity { get;}
    PointF Acceleration { get;}
    IPointSaturator VelocitySaturator { get; set;}
    IPointSaturator AccelerationSaturator { get; set;}
    void Update(
        PointF acceleration,
        PointF velocity,
        PointF position);
}

There are some comments to do about this interface.
1. IPointSaturator is the interface defining PointF saturator. In fact, it is very important to make sure that the agents have a maximum speed!
2. Referential is the local referential attached to the agent.
3. There is one major lack in this interface, the inertia, the rotation velocity and acceleration. For the sake of simplicity, I decided to leave those aside for now.

A vision determines if an agent can see another, it has a maximum range (and is an artifact)
public interface IVision : IArtifact
{
    float MaxRange { get;}
    bool CanSee(IAgent agent);
}
An integrator integrates the motion dynamics,
public interface IIntegrator
{
    void Integrate(IBody body, PointF steering);
}
A saturator will rescale a vector or a scalar depending on the body state.

It also provides a way to determine the maximum vector norm (norm-2) depending on the “attack” angle.

public interface IScalarSaturator
{
    float Saturate(IBody body, float value);
}
public interface IPointSaturator
{
    PointF Saturate(IBody body, PointF vector);
    float GetMaxNormFromAngle(float value);
}

Visualization concepts


A scene provides the methods to render lines, circles, etc…
public interface IScene : IComponent
{
    void Prepare();
    void Flush();
    void DrawLine(Pen pen, PointF start, PointF end);
    ...  
    void PushTranslateTransform(float dx, float dy);
    ...
    void PopTransform();
}

A visualizable element can be visible/hidden and rendered,
public interface IVisualizable
{
    bool Visible { get;set;}
    void Render(IScene scene);
}
A sprite is a graphical element with a background and a border
public interface ISprite : IVisualizable, IDisposable
{
    string Name { get;}
    Font Font { get;set;}
    Color BackgroundColor { get;set;}
    Color StrokeColor { get;set;}
    float StrokeWidth { get;set;}
}

I’ve added the name for debugging reasons.

An artifact is a sprite attached to an agent (e.g. smoke trail, hallow, etc…).
public interface IArtifact : ISprite, IOwned<IAgent>
{}
public interface IOwned<T>
{
    event EventHandler OwnerChanged;
    T Owner { get;set;}
}
The world contains world dimensions and projection from/to screen.
public interface IWorld
{
    Size WorldSize { get;}
    Size ScreenSize { get;}
    PointF ScreenToWorld(PointF point);
    PointF WorldToScreen(PointF point);
    PointF ToWorldRatio{get;}
   PointF ToScreenRatio {get;}
}

Service concepts

I’ll skip the service concepts for now. They basically provide access to the different instances of neighborhood, obstacle manager, agent list, etc... For now, it’s to time have a break and a well-deserved cool beer.

posted on Saturday, June 11, 2005 7:03:26 AM UTC  #    Comments [0]
 Thursday, June 09, 2005

   Diagnosys: In the background, ngraphviz generates a temporary dot file for each graph that gets rendered and shreds it afterwards. If you are running Ngraphviz from a folder that does not have write support, you get something like the exception below.

   Workaround: Do not run reflector from a share!

Access to the path "\\xxxxxxxx\a26d8897-1b11-4f40-8d50-301cc6503ba2.dot" is denied.

System.UnauthorizedAccessException

  at System.IO.__Error.WinIOError(Int32 errorCode, String str)
  at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share,
Int32 bufferSize, Boolean useAsync, String msgPath, Boolean bFromProxy)
  at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share,
Int32 bufferSize)
  at System.IO.StreamWriter.CreateFile(String path, Boolean append)
  at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize)
  at System.IO.StreamWriter..ctor(String path)
  at NGraphviz.Helpers.Dot.Run(GraphvizImageType imageType, String dotCode, String outputFileName)
  at QuickGraph.Algorithms.Graphviz.GraphvizAlgorithm.Write(String outputFileName)
  at Reflector.Graph.Graphs.InstructionGraphRenderer.Render(String fileName)
  at Reflector.Graph.IlGraphControl.Translate()
  at Reflector.Framework.InternetExplorerControl.OnParentChanged(EventArgs e)
  at System.Windows.Forms.Control.AssignParent(Control value)
  at System.Windows.Forms.ControlCollection.Add(Control value)
  at _134._1(IWindow )
  at _121._1(String )
  at _4.set_Visible(Boolean value)
  at Reflector.Framework.PackageBase.commandBar_Click(Object sender, EventArgs args)
  at _78.OnClick(EventArgs e)
  at _78.PerformClick()
  at _1.OnClick(EventArgs e)
  at System.Windows.Forms.MenuItemData.Execute()
  at System.Windows.Forms.Command.Invoke()
  at System.Windows.Forms.Control.WmCommand(Message& m)
  at System.Windows.Forms.Control.WndProc(Message& m)
  at System.Windows.Forms.TreeView .WndProc(Message& m)
  at _2.WndProc(Message& message)
  at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
  at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
  at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

 

posted on Thursday, June 09, 2005 11:11:15 PM UTC  #    Comments [1]
 Wednesday, June 08, 2005

The SVG viewer and NGraphviz can causes some common failure that are easy to workaround, i.e. I don't plan to fix them soon ;)

1.

 Diagnosys: The first time you run the Adobe SVG viewer, a copyright dialog pops up. After that, you will hit this failure.
 Workaround: Close Reflector and rerun. The dialog is gone and everything works fine.

Object reference not set to an instance of an object.

System.NullReferenceException

  at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
  at System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMethods+
IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
  at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
  at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
  at System.Windows.Forms.Application.DoEvents()
  at _121._1(String )
  at _4.set_Visible(Boolean value)
  at Reflector.Framework.PackageBase.commandBar_Click(Object sender, EventArgs args)
  at _78.OnClick(EventArgs e)
  at _78.PerformClick()
  at _1.OnClick(EventArgs e)
  at System.Windows.Forms.MenuItemData.Execute()
  at System.Windows.Forms.Command.Invoke()
  at System.Windows.Forms.Control.WmCommand(Message& m)
  at System.Windows.Forms.Control.WndProc(Message& m)
  at _76.WndProc(Message& message)
  at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
  at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
  at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

2.

    Diagnosys: You don't have the necessary C++ libraries on your machine to run NGraphviz.
    Workaround: make sure msvcp71.dll and msvcr71.dll are available.

The specified module could not be found. (Exception from HRESULT: 0x8007007E)

System.IO.FileNotFoundException

  at NGraphviz.Helpers.Dot.Run(GraphvizImageType imageType, String dotCode, String outputFileName)
  at QuickGraph.Algorithms.Graphviz.GraphvizAlgorithm.Write(String outputFileName)
  at Reflector.Graph.Graphs.StatementGraphRenderer.Render(String fileName)
  at Reflector.Graph.StatementGraphControl.Translate()
  at Reflector.Framework.InternetExplorerControl.OnParentChanged(EventArgs e)
  at System.Windows.Forms.Control.AssignParent(Control value)
  at System.Windows.Forms.Control.ControlCollection.Add(Control value)
  at _134._1(IWindow )
  at _121._1(String )
  at _121._4.set_Visible(Boolean value)
  at Reflector.Framework.PackageBase.commandBar_Click(Object sender, EventArgs args)
  at _78.OnClick(EventArgs e)
  at _78.PerformClick()
  at _83._1.OnClick(EventArgs e)
  at System.Windows.Forms.MenuItem.MenuItemData.Execute()
  at System.Windows.Forms.Command.Invoke()
  at System.Windows.Forms.Command.DispatchID(Int32 id)
  at System.Windows.Forms.Control.WmCommand(Message& m)
  at System.Windows.Forms.Control.WndProc(Message& m)
  at System.Windows.Forms.TreeView.WndProc(Message& m)
  at _2.WndProc(Message& message)
  at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
  at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
posted on Thursday, June 09, 2005 2:41:39 AM UTC  #    Comments [0]
 Monday, June 06, 2005
Just updated to dasBlog...
posted on Monday, June 06, 2005 6:23:26 PM UTC  #    Comments [1]
 Thursday, May 26, 2005

A while ago, I mentioned I was planning to build an autonomous agent framework on .NET (this was in fact a long time ago). It’s time to wake this project up with a shiny description:

NSteer is a framework for simulating of autonomous agents for .NET.

Until we get down to the code, here is a little snapshot to get you hooked:

 

A bit of history: boids, flocks, herds, etc…

In 1986, Craig Reynolds wrote a little application that simulated bird group behaviors. The term Boids was born. The beauty of his approach was that the “bird” behavior was not created from some complicated mathematical equation, it all boiled down to 3 simple rules that each agent would follow:

  1. Separation: avoid neighbors,
  2. Cohesion: go towards the group center,
  3. Alignment: align with group velocity.

Since then there has been a lot action in this field and you can see applications of this approach in a lot of the blockbuster hits. Check out Craig’s web site for an impressive list of links to papers (I love this one), samples, frameworks and movies…. It was about time to bring .NET into the play.

Laying down concepts

Let’s start by identifying the concepts in our problem that we can later translate into interfaces:

  • An Agent describes an independent entity that lives in a World. An Agent has a Vision, a Body and a Behavior
  • A Body defines the cinematic properties of the agent (position, acceleration, etc…)
  • A Vision defines the region where the Agent can “see” obstacles or neighbors
  • The Behavior of the Agent will yield a steering force that will move the Agent. This is the “brain” of the agent.
  • Agents are confined in a World.
  • A Simulator that uses an Integrator to integrate the dynamics of the system.

We will also need ways to access the list of Agents, Obstacles, etc… To do so, I chose to use the Service – Component – Container pattern where different services give access to the agents, obstacles, etc...

In .Net, this pattern is already part of the framework. The IComponent, IContainer interfaces are defined in System.ComponentModel and there already exists base class such as Container, Component, ServiceContainer to get started.

For a start, we will define the following services:

  • AgentService, gives access to the Agents,
  • WorldService, gives access to the world dimension and properties,
  • ObstacleService, gives access to the obstacles in the world,
  • NeighorhoodService, let agent query about neighboring agents

At last, we need some concepts for visualization:

  • A Sprite is a 2D drawing with background color, foreground color, etc… It can be hidden or made visible.
  • A Scene is an abstraction of GDI+,(just in case I had the courage to implement the framework using DirectX or XAML).

There might be a couple more going down the road, but this looks like a good starting point. I’ll see on the next post how we lay down the interface and maybe get ready for testing.

posted on Thursday, May 26, 2005 10:35:00 AM UTC  #    Comments [0]
 Monday, May 23, 2005

All downloads recompiled against Reflector 4.1.52.0 available at http://www.projectdistributor.net/Groups/Group.aspx?groupId=34 .

Enjoy :)

posted on Monday, May 23, 2005 9:49:00 AM UTC  #    Comments [2]
 Friday, April 22, 2005

Andrew Stopford has agreed to take over the MbUnit and keep it running. This is a very good news for the project. Hopefully, MbUnit can recover a short bug fix cycle and shape up its integration with CruiseControl.NET or Draco.

Good luck Andrew !

 

posted on Saturday, April 23, 2005 1:25:00 AM UTC  #    Comments [2]
 Friday, April 15, 2005

To whom it may concern:


As many of you probably know, I am now working at Microsoft in the CLR JIT testing team.  As my job load and duties are filling up more and more, I am unable to continue to contribute at a rate that best serves this project.  From this point forward please consider Jamie Cansdale (www.testdriven.net) as the sole owner (work/responsibilities/fun) for the MbUnit project.  I’ll of course be around occasionally.


Cheers,
Peli

posted on Friday, April 15, 2005 11:30:00 PM UTC  #    Comments [15]
 Monday, January 10, 2005

This is a rather funny application of unit testing. Let me state the problem:

We need to write a wrapper for every type that inherits from C. To make sure we don't miss any, we start by writing a combinatorial test that makes sure every type is mapped with a wrapper type*.

[TestFixture]
public class WrapperTest
{
    // get all the types assignable to C, from the assembly SomeAssembly
    [Factory(typeof(Type))]
    public IEnumerable<Type> Types()
    {
        foreach(Type type in SomeAssembly.GetExportedTypes())
        { 
            if (typeof(C).IsAssignableFrom(type))
               yield return type;
        }
    } 

    // tests that all types have a wrapper
    [CombinatorialTest]
    public void EnsureWrapper(
        [UsingFactories("Types")]Type type
    )
    {
        Assert.IsTrue( IsWrapped(type) );
    }
    
    // returns true of the wrapper exists
    private bool IsWrapped(Type type)
    {...}
}

Ok, we can run this test and see a lot of failures. So now we know wich wrapper has to be written.... but wait, why not making the test generate the wrapper as well.

    [CombinatorialTest]
    public void EnsureWrapper(
        [UsingFactories("Types")]Type type
    )
    {
        if (IsWrapped(type))
            return;

        // wrapper not found, 
        // generating the code and dumping it to Console.Out
        ...

        Assert.Fail("Wrapper not found");
    }

Now, we have test cases that give us the fix in case of a failure :)

*: this could be done by a FxCop rule as well since it is pure static analysis.

posted on Monday, January 10, 2005 8:13:00 AM UTC  #    Comments [5]
 Saturday, January 08, 2005

Updated Reflector.Framework for Reflector 4.1.27.0.

This version has an automatic *non-intrusive* checking for available updates... based on ProjectDistributor web services :) 

Download it here

posted on Sunday, January 09, 2005 12:44:00 AM UTC  #    Comments [3]
 Friday, January 07, 2005

ProjectDistributor is a new actor on the scene of inline project managment (thanks for Darren). It provides a simple web site for publishing your little cool applications that have been sleeping on your desktop.

Unlike the big guns like sourceforge, tigris or gotdotnet, ProjectDistributor is simple simple simple. With RSS and webservices, it has the vitual but no more features, anyway who uses all the feature from sf or tigris ?

I've decided to use ProjectDistributor to publish my snippets and other useless samples. Currently, the following applciations are already there:

ps: ProjectDistributor.AutoUpdate is a micro autoupdate framework for your application based on projectdistributor. The next release of the addins with support that .... and have their “Check for Addin update” button :)

posted on Friday, January 07, 2005 9:57:00 PM UTC  #    Comments [4]
 Tuesday, January 04, 2005

Mike Gunderloy has posted a nice introductory article on using TD.NET and MbUnit in Visual Studio. Check it out at http://www.developer.com/net/net/article.php/3453121

This article is really about TD.NET as Mike emphasis on one of the zillions of feature of TD.NET. There are a lot of very nice feature in TD.NET, just take a moment to discover them.

Going beyond Mike sample with MbUnit

Mike illustrates the article with a little class that stores an integer and returns information such as IsPositive, etc... In the article, Mike uses the canonical fixture. Let's if we can do better. (disclaimer: my VB is really bad)

RowFixture

Typically, you want to test this for 'interresting' values such 0,-1,1,MaxInt,etc... This example really fits well into the example of the RowFixture:

Imports System
Imports MbUnit.Core.Framework
Imports MbUnit.Framework

<TestFixture()> _
Public Class NumberTests
    ...

    <RowTest()> _
    <Row(5,FALSE)> _
    <Row(8,TRUE)> _
    Public Sub TestIsEven(int value, Boolean isEven)
        ' Make sure even numbers are property identified
        Dim num As New Number
        num.Value = value;
        Assert.AreEqual(isEven, num.IsEven)
    End Sub

End Class

This will create a test case for each RowAttribute. Better readibabilty, better test separation. Now can we do better ?

Combinatorial test

Let's try another approach. We could create a table of 'interresting' number with their properties (is positive, is even). Once this is done, we can feed this table to combinatorial tests.

<TestFixture()> _
Public Class NumberTests

    Public Class NumberRow
        Public int Value
        Public bool IsPositive
        Public bool IsEven

        Public New(int value, bool isPositive, bool isEven)
            Me.Value = value
            Me.IsPositive = IsPositive
            Me.IsEven = isEven
        End New
    End Class

    <Factory()> _    
    Public Function Numbers() as Array Of NumberRow
        Dim numbers As New Array Of NumberRow[4];

        numbers[0] = New NumberRow(-1, False, False)
        numbers[1] = New NumberRow(0, False, True)
        numbers[2] = New NumberRow(1, True, False)
        numbers[3] = New NumberRow(2, True, True)

        Return numbers
    End Function
    
    <CombinatorialTest()> _
    Public Sub TestIsEven(<UsingFactories("NUMBERS")> _ NumberRow row)
        ' Make sure even numbers are property identified
        Dim num As New Number
        num.Value = row.Value;
        Assert.AreEqual(row.IsEven, num.IsEven)
    End Sub

End Class

This will create 4 test cases, one per element of the array returned by Numbers. Moreover, we could reuse Numbers in another test to verify IsPositive.

[Update]
If you plan to reuse the factory, you can extract it into a separate class and pass the facotry type of the UsingFactories parameter.

Public Class NumberRow
    Public int Value
    Public bool IsPositive
    Public bool IsEven

    Public New(int value, bool isPositive, bool isEven)
        Me.Value = value
        Me.IsPositive = IsPositive
        Me.IsEven = isEven
    End New
End Class

Public Class NumberFactory
    <Factory()> _    
    Public Function Numbers() as Array Of NumberRow
        Dim numbers As New Array Of NumberRow[4];

        numbers[0] = New NumberRow(-1, False, False)
        numbers[1] = New NumberRow(0, False, True)
        numbers[2] = New NumberRow(1, True, False)
        numbers[3] = New NumberRow(2, True, True)

        Return numbers
    End Function
End Class

<TestFixture()> _
Public Class NumberTests
    
    <CombinatorialTest()> _
    Public Sub TestIsEven(<UsingFactories(CType(NumberFactory))> _ NumberRow row)
        ' Make sure even numbers are property identified
        Dim num As New Number
        num.Value = row.Value;
        Assert.AreEqual(row.IsEven, num.IsEven)
    End Sub

End Class
posted on Tuesday, January 04, 2005 2:48:00 PM UTC  #    Comments [11]

The Reflector addin download have been down for a long time and I apologize for that (vacations).

Released in 3 flavors

There has been a significant refactoring of the addins so stay tuned: the addins are now separated in 3 assemblies: Reflector.CodeMetrics, Reflector.Graph and Reflector.Framework

  • Reflector.CodeMetrics has no dependency on NGraphviz,
  • Reflector.Graph contains graph stuff only, dependency on NGraphviz
  • Reflector.Framework contains CodeMetrics, Graph, and the all the rest. It is compiled against 1.1
  • you should not mix those 3 builds. Pick the one you want but don't mix them!

New project web site

The addins are now hosted on the excellent http://projectdistributor.net/Groups/Group.aspx?groupId=34. Make sure you monitor the rss to be notified for the updates.

posted on Tuesday, January 04, 2005 9:06:00 AM UTC  #    Comments [3]
 Thursday, December 16, 2004

MSN Desktop search (or other search engine) is definitely the new must-have tool for developers, specially if you work with a laaaaaaarge code base. The title is self-explaining:

  •  install MSN Desktop search,
  • set up the indexing to point the source code folders
  • wait a few hours for indexing depending on the size of your project
  • pick any class or method and write it in the search bar...

The results are just lovely! It is easy to browse, relevant and fast! 

posted on Friday, December 17, 2004 5:24:00 AM UTC  #    Comments [9]
 Friday, December 10, 2004

I have finally deciced to merge MbUnit.Core.dll into MbUnit.Framework.dll. This will be a minor breaking change in the next release because you will have to remove the reference to MbUnit.Core.dll.

All the attributes also have moved to MbUnit.Framework, so you don't need to use MbUnit.Core.Framework. I did this change mainly to simplify the morphing NUnitForms or NUnitAsp to MbUnit: a Replace All in Files will be sufficient to move them to MbUnit.

 

posted on Friday, December 10, 2004 1:30:00 PM UTC  #    Comments [12]
 Sunday, December 05, 2004

Reflector.CodeMetrics dynamically loads code metrics tabs at runtime by using Reflection. This means that anybody can write his own metric whithout recompiling CodeMetrics.... an Addin API inside another AddIn api :)

Here's a quick review of the steps to get your new cool code metric started. In this example, we will display the number of arguments per method (simple example).

Setting up the project

Start a new assembly project, add references to Reflector.exe, Reflector.CodeMetrics.dll and Reflector.Helpers.dll

Creating a new CodeMetric

All code metrics implement the ICodeMetric interface (this what the CodeMetricManager looks for):

public interface ICodeMetric : IServiceComponent

{

string Name { get;}

string FullName { get;}

ComputationState State { get;}

DataTable Result { get;}

Object FindItem(DataRow row);

bool Enabled { get;set;}

CodeMetricLevel Level { get;}

event ComputationProgressEventHandler Progress;

void Compute();

void Abort();

}

Of course, you don't have to implement it from scratch. You can use the abstract base class CodeMetricBase to get started:

public class ArgumentCountCodeMetric : CodeMetricBase
{
    // setting up name, full name and level of metric
    public ArgumentCountCodeMetric()
    :base("AC","Argument Count",CodeMetricLevel.Method)
    {}

    // adding columns
    protected void AddColumns()
    {
       this.AddColumn("Argument Count");
    }

    ...
}

It is important to note that we specify that the metrics target Method (can also target Type, Module). The AddColumns method is used to all the columns you want to show in the grid.

Add the metric computation

Time to get to the real fun, computing the metric... First, we provide a method GetTestCount that returns the number of steps. This number is used to scale the progress bar:

private int GetStepCount()
{
    int count = 0;
    foreach (IAssembly assembly in this.Services.AssemblyLoader.Assemblies)
    {
       if (this.Services.CodeMetricManager.IsIgnored(assembly))
           continue;
       foreach (IModule module in assembly.Modules)
            count += module.Types.Count;    
    }
    return count;
}

It is important to note that we check for each IAssembly if it has to be ignored. This is directly linked to the checkbox control on the CodeMetrics page. Note that we coun the types only, if you show progress on methods, almost all the CPU time is spent to update the controls. Next, we write the method that create a row in the grid from a IMethodDeclaration:

private void ComputeMethod(IMethodDeclaration method)
{
    IMethodBody body = method as IMethodBody;
    if (body == null)
        return;
    this.AddRow(
        method,
        body.Parameters.Count 
        );
}

The AddRow methods will add a row in the underlying DataTable, etc...

Implementing Compute

We have all the pieces, we just need to implement Compute:

public override void Compute()
{
    base.Compute();
    int stepCount = GetStepCount();
    int count = 0;
    foreach (IAssembly assembly in this.Services.AssemblyLoader.Assemblies)
    {
        if (this.Services.CodeMetricManager.IsIgnored(assembly))
            continue;
        foreach (IModule module in assembly.Modules)
        {
            foreach (ITypeDeclaration type in module.Types)
            {
                this.OnProgress(
                    new ComputationProgressEventArgs(
                        count++,
                        stepCount,
                        "Analysing {0}",
                        type
                        )
                     );
                foreach (IMethodDeclaration method in type.Methods)
                {
                    if (this.CheckForAbort())
                        return;
                    ComputeMethod(method);
                }
            }
        }
    }
    this.Finished();
}

The metric is ready, we just need to register it to the manager when the Addin is loaded.

Setting up a package and registering CodeMetrics

Reflector looks for IPackage class when loading Addins. Reflector.Helpers contains a smart implementation of that addin that will automatically load the code metrics the assembly contains, so all you have to do is to inherit from PackagePage (well almost):

namespace Reflector.CodeMetrics
{
    public sealed class CodeMetricPackage : PackageBase
    {
        [ReflectorWindow(
        Name = "Dummy control to make Reflector happy",
        Caption = "Dummy control to make Reflector happy"
        )]
       [ReflectorCommandBar(CommandBarTarget.Tools)]
       private UserControl dummy = new UserControl();
    }
}

If you do not actually load a new window, Reflector gets pissed and unload the addin. Therefore, just add a dummy window. At this point, recompile (makes sure you target the right .Net framework), load and enjoy.

Debugging

To debug, just start Reflector as external process and break point on your code.

posted on Monday, December 06, 2004 6:48:00 AM UTC  #    Comments [11]
 Tuesday, November 30, 2004

TestDriven.NET 1.0 is released on www.testdriven.net (MbUnit ships with TD.NET). Check out the brand new web site!   

You are a TD.NET user ? Use the link builder and add a cool image like this one on your blog or web site...TestDriven.NET

posted on Tuesday, November 30, 2004 8:49:00 AM UTC  #    Comments [14]
 Monday, November 29, 2004

The next version (greater than 1.0.903d) contains a bunch of decorators that will deny access to file, file dialog, sql client, oracle client, etc... The decorators are located in the MbUnit.Framework.1.1.dll in the MbUnit.Framework.Security namespace.

For example you can deny access to the SqlClient using the following:

using MbUnit.Core.Framework;
using MbUnit.Framework;
using MbUnit.Framework.Security;
[TestFixture]
public class MyFixture
{
    [Test]
    [DenySqlClient]
    public void AccessDatabase()
    {
        // access to SQL client will fail in this method.
    }
}
posted on Monday, November 29, 2004 8:49:00 AM UTC  #    Comments [11]

I have added 2 new improvements to MbUnit to avoid having tests blocked by assertions or timeouts:

  • Assertion dialog caused by Debug.Assert are automatically swallowed (by removing the default debug trace)
  • TimeOut (in minutes) can be set at the fixture level:
[TestFixture(TimeOut = 1)]
public class MyFixture{...}

Those changes will be available in release greater than 1.0.903

posted on Monday, November 29, 2004 8:24:00 AM UTC  #    Comments [3]
 Friday, November 26, 2004

Question: So you are using files in your application, how do you test easily how it behaves if the file access is denied ?
Answer: Use declarative permissions to deny all access on the files

Ok that's a rough introduction, let me develop the idea. When your application relies on using resources such as files, TcpChannels, registry, etc... you should test how it behaves when the access to those resources is refused. The resource denial can be caused by a lot of external factors (loss of connectivity, etc...), lack of physical resources, .... or by denied security permissions. In other words, security permissions is an easy way to simulate various situations such as file access error, etc... 

Let me illustrate this by implementing a test decorator for MbUnit that makes all file access diened.

Creating DenyFileIOAccess decorator

As all test decorators, we derive a new attribute class from MbUnit.Core.DecoratorPatternAttribute and a new IRunInvoker from DecoratorRunInvoker:

using System;
using System.Security.Permissions;
using System.Collections;
using MbUnit.Core.Invokers;
using MbUnit.Core.Framework;
namespace MbUnit.Framework.Security
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple  = false, Inherited =true)]
    public sealed class DenyFileIOAccessAttribute : DecoratorPatternAttribute
    {
        public override IRunInvoker GetInvoker(IRunInvoker invoker)
        {
            return new DenyFileIOAccessRunInvoker(invoker, this);
        }
        private sealed class DenyFileIOAccessRunInvoker : DecoratorRunInvoker
        {
            private DenyFileIOAccessAttribute attribute;
            public DenyFileIOAccessRunInvoker(
                IRunInvoker invoker,
                DenyFileIOAccessAttribute attribute)
                :base(invoker)
            {
                this.attribute = attribute;
            }
            [FileIOPermission(SecurityAction.Deny, AllFiles = FileIOPermissionAccess.AllAccess)]
            public override object Execute(Object o, IList args)
            {
                return this.Invoker.Execute(o, args);
            }
        }
    }
}

The important thing to notice in the snippet is the FileIOPermission attribute that tags the execute method. All the code executed inside that method will have file IO denied. So since Invoker.Execute calls the test method, we have what we are looking for.

DenyFileIOAccessAttribute in action

Let put the new decorator in action. The following snippet shows a simple test that tries to create a new file. The execution log using TestDriven.NET is outputed below. As one can see, a SecurityException was raised by the framework when trying to open the file.... it's magic.

using System;
using System.IO;
using MbUnit.Framework;
using MbUnit.Framework.Security;
namespace MbUnit.Demo
{
    [TestFixture]
    public class SecurityTest
    {
        [Test]
        [DenyFileIOAccess]
        public void SecureMethod()
        {
            using (StreamWriter writer = new StreamWriter("test.txt"))
            {
                writer.Write("we should not be here");
            }
        }
    }
}

-- output

------ Test started: Assembly: MbUnit.Tests.1.1.dll ------
Info: Test Execution
Info: Exploring MbUnit.Tests.1.1, Version=1.0.1791.9801, Culture=neutral, PublicKeyToken=null
Info: MbUnit 2.22.0.0 Addin
Info: Found 1 tests
Info: [failure] SecurityTest.SecureMethod
TestCase 'SecurityTest.SecureMethod' failed: Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
 System.Security.SecurityException
 Message: Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
 Source: mscorlib
 StackTrace:
 at System.Security.CodeAccessSecurityEngine.Check(PermissionToken permToken, CodeAccessPermission demand, StackCrawlMark& stackMark, Int32 checkFrames, Int32 unrestrictedOverride)
 at System.Security.CodeAccessSecurityEngine.Check(CodeAccessPermission cap, StackCrawlMark& stackMark)
 at System.Security.CodeAccessPermission.Demand()
 at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
 at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
 at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
 at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize)
 at System.IO.StreamWriter..ctor(String path)
 \securitytest.cs(22,0): at MbUnit.Demo.SecurityTest.SecureMethod()
0 succeeded, 1 failed, 0 skipped, took 0.00 seconds.

---------------------- Done ----------------------

This methodology applies to the other types of permissions that can be found in the System.Security namespace.

Where can I get those ?

MbUnit will soon contain a few other of those attributes. Since it is a .Net 1.1 feature, they will be enclosed in the MbUnit.Framework.1.1.dll under the MbUnit.Security namespace.

posted on Friday, November 26, 2004 7:07:00 PM UTC  #    Comments [3]
 Tuesday, November 23, 2004

Reflector.CodeMetrics is a new Addin for Reflector that analyses and computes several code quality metrics on your assemblies. This addin uses the excellent Reflector API to compute classic metrics such as the cyclomatic complexity or more straightforward such as the number of local variables in a method. All results can be dumped to file (using DataSet.Save)

Download Reflector.CodeMetrics (look for Reflector.CodeMetrics.zip) For installation and usage instructions, please read the Readme.txt enclosed in the zip file.

Tip: when you explore the result, you can doubleclick on the border of the row to show the item in the decompiler

 

posted on Wednesday, November 24, 2004 4:21:00 AM UTC  #    Comments [14]
 Thursday, November 18, 2004

This is a preview of a new Reflector Addin that computes various CodeMetrics on .Net assemblies. The excellent Reflector API makes it very easy to do this kind of things. Here are the metrics that I plan to implement :

  • Counting metrics: Module/Assembly, Type/Module, Method/Type, etc...
  • IL counting metrics: IL/Method, LocalVariables/Method, ExceptionHandlers/Method, etc...
  • IL flow graph metrics: components, cyclomatic complexity,
  • Method graph: methodrank, callers, callees, components, distance from entry point,
  • Type graph: type rank, inherance level, etc...

I have not done an extensive research on the subject so I might forget a lot of them, suggestions and links welcome.

Note that this uses a plugin architecture so that anyone can write and use his own metric.

Screenshot:

posted on Thursday, November 18, 2004 10:50:00 AM UTC  #    Comments [18]
 Wednesday, November 17, 2004
posted on Thursday, November 18, 2004 6:55:00 AM UTC  #    Comments [0]
 Monday, November 15, 2004
 Wednesday, October 20, 2004

This new functionality enables you to specify a tabular list of test cases that are to be feeded to the test method. Let me illustrate that with the floating point division testing (as in the FIT framework Simple Example ):

numerator denominator quotient()
1000 10 100.0000
-1000 10 -100.0000
1000 7 142.85715
1000 .00001 100000000
4195835 3145729 1.3338196

You can now translate this directly to C# in MbUnit using the RowTestAttribute and the RowAttribute:

[TestFixture]
public class DivisionFixture
{
    [RowTest]
    [Row(1000,10,100.0000)]
    [Row(-1000,10,-100.0000)]
    [Row(1000,7,142.85715)]
    [Row(1000,0.00001,100000000)]
    [Row(4195835,3145729,1.3338196)]
    public void DivTest(double numerator, double denominator, double result)
    {
        Assert.AreEqual(result, numerator / denominator, 0.00001 );
    }
}

Of course, these tests are not very well targeted because we do not test the “special” floating point values such as 1,0,double.MaxValue, double.MinValue, NaN but you get the picture.

What if a test should throw ? In that case, you can specify the exception type as an additional parameter in the RowAttribute constructor:

    [Row(1,0,0, ExpectedException = typeof(ArithmeticException))]
    public void DivTest(double numerator, double denominator, double result)
    {...}

The final output of the tests is as follows where you can see that 5 tests (one per row) were generated and executed.

Info: Found 5 tests
Info: [assembly-setup] success
Info: [success] RowTestDemo.DivTest(0)
Info: [success] RowTestDemo.DivTest(1)
Info: [success] RowTestDemo.DivTest(2)
Info: [success] RowTestDemo.DivTest(3)
Info: [success] RowTestDemo.DivTest(4)
Info: [assembly-teardown] success
Info: [reports] generating HTML report
posted on Wednesday, October 20, 2004 9:30:00 PM UTC  #    Comments [7]
 Monday, October 18, 2004

I'm slowly catching up with putting some order in the MbUnit documentation. Therefore, MbUnit has now a Wiki (FlexWiki powered) part of the TestDriven.NET wiki. Feel free to contribute...

http://www.testdriven.net/wiki/default.aspx/MyWiki.MbUnit

posted on Monday, October 18, 2004 7:36:00 PM UTC  #    Comments [12]
 Sunday, October 17, 2004

MbUnit has now a basic support for loading fixture and tests based on their names, such fixture are called Naked Fixtures . Although this may look like a step backward in functionality, this can be handy in particular situations. For example, if you don't want to reference any test framework, this is a good solution because it does not require any type or attribute.

Naming rules

  • class name must end with “Fixture“
  • fixture setup method must be named “TestFixtureSetUp“
  • fixture teardown method must be name “TestFixtureTearDown“
  • setup method must be named “SetUp”
  • teardown method must be named “TearDown”
  • test methods must end with “Test”
  • all rules are case sensitive

Limitations

  • [Update: decorators are supported].
  • no combinatorial tests

QuickStart

 Below are two fixture. The first uses attributes and should be familiar to you. The second is it's naked equivalent:

[TestFixture]
public class ClassicFixture
{
    [TestFixtureSetUp]
    public void TestFixtureSetUp()
    {
        Console.WriteLine("TestFixtureSetUp");
    }
    [SetUp]
    public void SetUp()
    {
        Console.WriteLine("SetUp");
    }
    [Test]
    public void First()
    {
        Console.WriteLine("Test1");
    }
    [Test]
    public void SecondTest()
    {
        Console.WriteLine("Test1");
    }
    [TearDown]
    public void TearDown()
    {
        Console.WriteLine("TearDown");
    } 
    [TestFixtureTearDown]
    public void TestFixtureTearDown()
    {
        Console.WriteLine("TestFixtureTearDown");
    }
}

Naked version:

public class NakedFixture
{
    public void TestFixtureSetUp()
    {
        Console.WriteLine("TestFixtureSetUp");
    }
    public void SetUp()
    {
        Console.WriteLine("SetUp");
    }
    public void FirstTest()
    {
        Console.WriteLine("Test1");
    }
    public void SecondTest()
    {
        Console.WriteLine("Test1");
    }
    public void TearDown()
    {
        Console.WriteLine("TearDown");
    }
    public void TestFixtureTearDown()
    {
        Console.WriteLine("TestFixtureTearDown");
    }
}
posted on Sunday, October 17, 2004 12:43:00 PM UTC  #    Comments [1]
 Friday, October 15, 2004

TestDrivent.NET, which contains MbUnit, QuickGraph, TestFu and Refly, has gone RC2 .

See http://www.testdriven.net/wiki/default.aspx/MyWiki.DownLoad

 

posted on Friday, October 15, 2004 4:37:00 PM UTC  #    Comments [4]

Check out this new Reflector addin that creates diffs. Very cool...

http://codingsanity.blogspot.com/2004/10/reflector-diff.html

posted on Friday, October 15, 2004 7:14:00 AM UTC  #    Comments [7]
 Saturday, October 09, 2004

PDFizer: A XHTML to PDF converter: with this library, you can transform simple XHTML pages to nice and printable PDF files. This project is based on the excellent webzine article "Pdfizer, a dumb HTML to PDF converter, in C#" written by Jonathan de Halleux.

Cool, my PDFizer project has been resurected. If you are looking for an easy way to convert HTML pages into PDF, you might well be interrested by that one.

posted on Saturday, October 09, 2004 11:12:00 AM UTC  #    Comments [3]
 Tuesday, October 05, 2004

MutantBuild is the back bone behind TestDriven.NET / MbUnit compilation. Jamie Cansdale has published an installer that will let you play with it. Anybody automating VS.NET solution should have a look at this.

posted on Wednesday, October 06, 2004 3:14:00 AM UTC  #    Comments [4]
 Monday, October 04, 2004

Sometimes, a unit test does not fail but does not succeed entirely: making it fail is too extreme and on the other hand, letting him succeed would make you miss the issue. Therefore, MbUnit now supports warnings:

  • A warning can be emited in any test case using Assert.Warning methods,
  • A warning does not make test fail,
  • Warnings are recorded in the test report (in the Html report, they are displayed right after the fixture summary),
  • Multiple warnings can be outputed per test

QuickStart

This fixture shows 2 tests with warnings:

using System;

using MbUnit.Core.Framework;

using MbUnit.Framework;

namespace MbUnit.Demo

{

[TestFixture]

public class WarningTest

{

[Test]

public void Warning()

{

Assert.Warning("Be wary");

}

[Test]

public void Warning2()

{

Assert.Warning("Something weird happened");

}

}

}

The corresponding html report looks like this:

posted on Tuesday, October 05, 2004 12:42:00 AM UTC  #    Comments [3]