Friday, May 25, 2007

MbUnit 2.4 is out, check it out at

http://weblogs.asp.net/astopford/archive/2007/05/24/mbunit-2-4-rtm.aspx

If you are using MbUnit parameterized tests (i.e. RowTest, CombinatorialTest) then migrating to Pex should be a piece of cake :)

posted on Friday, May 25, 2007 10:25:02 PM UTC  #    Comments [2]
 Sunday, April 22, 2007

3 years after being released on CodeProject, it was about time to dust off QuickGraph and give it generics support.

posted on Sunday, April 22, 2007 3:49:21 PM UTC  #    Comments [2]
 Friday, April 20, 2007

With parameterized unit tests, it is not uncommon to generate a large number of exceptions. An basic exception log usually looks like this: a small message and the stack trace.

Whith this kind of output, a lot of work is still left to the user since he has, *for each frame*,  to manually open the source file and move to the line refered by the trace.

Give me the source context!

In the Pex reports we added a couple lines of code to read the source for each frame and display it in the reports (no rocket science). The cool thing is that you now can get a pretty good idea of what happened without leaving the test report. Multiply that by dozens of exceptions and you've won a loooot of time.

Here are some screenshots to illustrate this: an exception was thrown in some arcane method. The error message is not really useful (as usual).

If we expand the source and actually see the code, things become much clearer...

posted on Friday, April 20, 2007 7:12:40 AM UTC  #    Comments [0]
 Wednesday, April 11, 2007

MbUnit supports different flavors of parameterized unit tests: RowTest, CombinatorialTest, etc... If you are already using those features, it would be very easy for you to 'pexify' them:

namespace MyTest
{
     using MbUnit.Framework;
     using Microsoft.Pex.Framework;

     [TestFixture, PexClass]
     public partial class MyTestFixture
{
[RowTest]
[Row("a", "b")]
[PexTest]

public void Test(string a, string b)
{
...
}


}
}

Isn't this nice? :)

Some little notes:

  • 'partial' is helpfull to emit the generated unit test in the same class... but not the same file. Pex also support another mode where partial is not required.
  • the Pex attributes do not 'interfere' with the MbUnit ones. Your unit tests will still run exactly the same with MbUnit.
posted on Wednesday, April 11, 2007 11:47:27 AM UTC  #    Comments [2]
 Sunday, April 08, 2007

The bank sample is a small example that serves as a quickstart for NUnit. In this post, we will revisit the sample and see how existing unit tests can be refactored into Pex parameterized tests.

The original unit test:

Let's start with the initial implementation of the Account class, and the first unit test case from the sample:

namespace bank
{
  public class Account
  {
    private float balance;
    public void Deposit(float amount)
    {
      balance+=amount;
    }

    public void Withdraw(float amount)
    {
      balance-=amount;
    }

    public void TransferFunds(Account destination, float amount)
    {}

    public float Balance
    {
      get{ return balance;}
    }
  }
}
namespace bank
{
  using NUnit.Framework;

  [TestFixture]
  public class AccountTest
  {
    [Test]
    public void TransferFunds()
    {
      Account source = new Account();
      source.Deposit(200.00F);
      Account destination = new Account();
      destination.Deposit(150.00F);

      source.TransferFunds(destination, 100.00F);
      Assert.AreEqual(250.00F, destination.Balance);
      Assert.AreEqual(100.00F, source.Balance);
	
    }
  }
}

Refactoring the unit test and hooking Pex

An easy oportunity to refactor a unit test into parameterized unit tests is to extract constants as parameters, namely 200F as sourceDeposit, 150F as destinationDeposit, etc... We also add the PexClass and PexTest custom attributes to tell Pex that there are some parameterized tests: 

    using Microsoft.Pex.Framework;
    [TestFixture, PexClass]
    public partial class AccountTest
    {
        [PexTest]
        public void TransferFunds(
            float sourceDeposit,
            float destinationDeposit,
            float transfer)
        {
            Account source = new Account();
            source.Deposit(sourceDeposit);
            Account destination = new Account();
            destination.Deposit(destinationDeposit);
            source.TransferFunds(destination, transfer);
            Assert.AreEqual(destinationDeposit + transfer, destination.Balance);
            Assert.AreEqual(sourceDeposit - transfer, source.Balance);
        }
    }

Iteration 1: amount should not be negative,

The first (and unique) test case that Pex generates uses float.MinValue for all values, which leads to some interresting floating point issues.

this.TransferFunds(float.MinValue, float.MinValue, float.MinValue);

...

expected: <-Infinity>

but was: <-3.40282347E+38>

at Assert.AreEqual(destinationDeposit + transfer, destination.Balance);

This little test reminds us that floats can have some weird values (infinity, minvalue, etc...).

Iteration 2: amount should not be too big,

It's time to add parameter checking to prevent negative transfer amounts. The ValidateAmount method is added in each transaction method:

        private void ValidateAmount(float amount)
        {
            if (amount < 0)
                throw new ArgumentOutOfRangeException("amount");
        }

Pex now generates 4 test cases. 3 of them pass negative values as amount to cover the argument validation code:

        [Test()]
        [ExpectedException(typeof(System.ArgumentOutOfRangeException)), ...]
        public void TransferFunds_Single_Single_Single_70408_082415_0_01()
        {
            this.TransferFunds(float.MinValue, float.MinValue, float.MinValue);
}
...
            this.TransferFunds(float.MaxValue, float.MinValue, float.MinValue);
            this.TransferFunds(float.MaxValue, float.MaxValue, float.MinValue);

The 4-th test finds another overflow by passing all float.MaxValue.

Iteration 3: NaN handling

We add a MaximumAmount field to bound the amount of money that can be transfered.


private float maximumAmount = 1000.00F;
public float MaximumAmount
{
 get{ return maximumAmount;}
}

private void ValidateAmount(float amount)
{
if (amount <= 0)
     throw new ArgumentOutOfRangeException("amount");
    if (amount > this.MaximumAmount)
      throw new ArgumentOutOfRangeException("amount");
}

We run Pex. The test still does not fail and to our surprise it generates the following passing test: 

      this.TransferFunds(float.NaN, float.NaN, float.NaN);

Oops, NaN is a very special number. Did you know that (float.NaN == float.Nan) == false? In our case, float.NaN passes the parameter validation and assertions!

Iteration 4: The test fails!

Again, we beef up the 'amount' validation to rule out NaN:

        private void ValidateAmount(float amount)
        {
            if (float.IsNaN(amount))
                throw new ArgumentOutOfRangeException("amount");
            if (amount <= 0)
                throw new ArgumentOutOfRangeException("amount");
            if (amount > this.MaximumAmount)
                throw new ArgumentOutOfRangeException("amount");
        }

We run Pex again and, at last, we find an input to fail the test:

            this.TransferFunds(float.Epsilon, float.Epsilon, float.Epsilon);
        ...
        [test] TransferFunds_Single_Single_Single_70408_113456_0_05, AssertionException:
 expected: <2.80259693E-45>
  but was: <1.40129846E-45>

Iteration 5: Implementing TransferFunds

Now that we found an input that fails the test, we can actually add some code to TransferFunds (as in the QuickStart):

        public void TransferFunds(Account destination, float amount)
        {
            this.ValidateAmount(amount);
            destination.Deposit(amount);
            Withdraw(amount);
        }

So we run Pex again and all the tests passes. Next time, we'll take look at the implementation of the 'MinimumDeposit' feature.

posted on Sunday, April 08, 2007 2:09:48 PM UTC  #    Comments [2]
 Sunday, April 01, 2007

This is the first post about Pex and how to use it. Since Pex is a fairly large project, I'll probably stretch the content of a large number of entries. Stay tunned...

Pex gives you Parameterized Unit Tests

Data-driven tests are not something new. They exist under different forms such as MbUnit's RowTest or CombinatorialTest, VSTS's DataSource, etc... So what's so special about Pex? The major difference is that Pex finds the parameter inputs for you (and generates a unit test out of it).

Whereas the user had to (smartly) guess a set of input for the data-driven tests, Pex tries to compute the relevant inputs to those tests automatically (and may also suggest fixes).

Note: The way Pex finds the input will be covered in more details later. In a couple words, Pex performs a systematic white box analysis of the program behavior. It tries to generate a minimal test suite with maximum coverage.

Parameterized Unit Tests, what does it feel like?

Parameterized unit tests are methods with parameters. There's nothing magic about that. Pex provides a set of custom attributes so that you can author them side-by-side with classic unit tests:

[TestClass, PexClass] // VSTS fixture containing parameterized tests
public class AccountTest
{
    // parameterized unit test
    // account money should never be negative, for any 'money', 'withdraw'
    [PexTest]
    public void TransferFunds(int money, int withdraw) {...}
}

When Pex finds interresting data to feed the parameterized unit test, it generates a unit test method that calls the parameterized unit test. This also means that once the unit test has been generated, you do not need Pex anymore to run the repro.

[TestClass, PexClass] // VSTS fixture containing parameterized tests
public class AccountTest
{
    [PexTest]
    public void TransferFunds(int money, int withdraw) {...}
    ...
    [TestMethod, GeneratedBy("Pex", "1.0.0.0")]
    public void TransferFunds_12345() { this.TransferFunds(12, 13); }

}

Why do I need parameterized unit tests anyway?

A parameterized unit tests generally captures more program behaviors than a single unit test which is like a micro-scenario. This will become more apparent when we start looking at some examples. 

If you were already using [RowTest] or [DataSource] as part of your testing, then you will definitely like Pex.

posted on Monday, April 02, 2007 5:52:37 AM UTC  #    Comments [2]
 Monday, March 19, 2007

Reflector.CodeMetrics swallowed the treemap coolaid ...

posted on Monday, March 19, 2007 11:01:41 AM UTC  #    Comments [0]
 Tuesday, March 13, 2007

The Pex screencast was a bit mysterious without sound and comments. I've added a 'storyboard' to help you understand it:

   http://research.microsoft.com/pex/screencast.aspx


 

posted on Tuesday, March 13, 2007 7:31:29 AM UTC  #    Comments [1]
 Thursday, March 08, 2007

Pex

I'm thrilled to present the project I joined last October: 'Pex' (for Program EXploration). Pex is a powerfull plugin for unit test frameworks that let the user write parameterized unit tests**. Pex does the hard work of computing the relevant values for those parameters, and serializing them as classic unit tests.

Here's a short screencast where we test and implement a string chunker. In the screencast, we use a parameterized unit test to express that for *any* string input and *any* chunk length, the concatenation of the chunks should be equal to the original sting.

http://research.microsoft.com/pex/screencast.aspx

More info on Pex is available at http://research.microsoft.com/pex/.

** It's actually much more than that... but let's keep that for later :)

posted on Friday, March 09, 2007 1:58:36 AM UTC  #    Comments [5]
 Saturday, February 24, 2007
 Tuesday, February 20, 2007

All my Reflector addins have a new home:

http://www.codeplex.com/reflectoraddins

Please use the codeplex issue tracking to log bugs.

 

posted on Tuesday, February 20, 2007 12:04:29 PM UTC  #    Comments [2]
 Sunday, November 19, 2006

Getting this dusty blog back to life....

posted on Sunday, November 19, 2006 10:08:28 AM UTC  #    Comments [0]
 Tuesday, September 12, 2006

GLEE, a graph layout engine developed in Microsoft Research. It is now available for downloading at http://research.microsoft.com/research/downloads/download.aspx?FUID=c927728f-8872-4826-80ee-ecb842d10371.

 

posted on Tuesday, September 12, 2006 7:13:07 AM UTC  #    Comments [1]
 Saturday, September 09, 2006

After 2 years in the CLR, I'm moving job (and building) to Microsoft Research. I will be working on Parametrized Unit Testing.

 

posted on Sunday, September 10, 2006 1:21:39 AM UTC  #    Comments [3]
 Sunday, March 12, 2006

I've refreshed the Reflector Addins and fixed a couple bugs:

  • CodeMetrics: fixed data serialization problem. Now dumping xml.
  • IL graph: back to life
  • IronPython: upgrade to beta4

Download the latest binaries as usual at http://projectdistributor.net/Projects/Project.aspx?projectId=43 

posted on Sunday, March 12, 2006 10:18:03 AM UTC  #    Comments [1]
 Wednesday, February 01, 2006

 Looks like there are some big changes ahead for me... Elliott, born sunday, loves milk and keeping his parents awake all night.  

posted on Thursday, February 02, 2006 3:14:40 AM UTC  #    Comments [0]
 Thursday, January 26, 2006

Update for Reflector 4.2.0.0

   Download at http://www.projectdistributor.net/Releases/Release.aspx?releaseId=304

.net 1.1 addins:

  • Reflector.CodeMetrics.dll (CodeMetrics)
  • Reflector.Rules.dll (Rules)
  • Reflector.ComViewer.dll (COM viewer)
  • Reflector.DesignViewer.dll (PropertyGrid, Control, XmlSerializer)
  • Reflector.TreeMap.dll (Type Tree Map)
  • Reflector.Graph.dll (Assembly Graph, IL Graph, Statement Graph)

.net 2.0 addins:

  • Reflector.IronPython.dll (IronPython console. Requires IronPython assemblies in path!)
  • Reflector.Coverage.dll (Coverage visualization)

 

posted on Thursday, January 26, 2006 3:25:12 PM UTC  #    Comments [0]
 Monday, November 21, 2005

I have updated my Reflector Addins (download available at http://projectdistributor.net/Releases/Release.aspx?releaseId=274 ).

  1. The big change is that I have splitted the addins into many assemblies which let you load more selectively which one you want.
  2. The second change is that most of the addins are now compiled against .Net 1.1. All the 1.1 addins are in the root directory, while the ones requiring 2.0 are in the 2.0 folder (which also contains a config file)!

.net 1.1 addins:

  • Reflector.CodeMetrics.dll (CodeMetrics)
  • Reflector.Rules.dll (Rules)
  • Reflector.ComViewer.dll (COM viewer)
  • Reflector.DesignViewer.dll (PropertyGrid, Control, XmlSerializer)
  • Reflector.TreeMap.dll (Type Tree Map)

.net 2.0 addins:

  • Reflector.Graph.dll (Assembly Graph, IL Graph, Statement Graph)
  • Reflector.CodeGeneration.dll (Code Generators)
  • Reflector.IronPython.dll (IronPython console. Requires IronPython assemblies in path!)
  • Reflector.Languages.dll (Reflection.Emit language)
  • Reflector.Coverage.dll (Coverage visualization)

Enjoy.

posted on Monday, November 21, 2005 11:24:45 AM UTC  #    Comments [3]
 Tuesday, November 01, 2005

There's a new addin in Reflector.Framework that let's you load COM typelib in Reflector (i.e. it generates the assembly and loads it for your).

posted on Tuesday, November 01, 2005 10:37:10 PM UTC  #    Comments [0]

There are 3 different builds for my addins, depending on the kind of depencies they require. *This is list depicts the features of the next drop 4.1.85.2*. All projects can be found on projectdistributor.net.

Each flavor is mutually exclusive! Pick your flavor depending on the dependencies and features that your are looking for!

Dependencies:

  • Common requirements:
    • Reflector 4.1.85.0 (or higher)
    • .Net 2.0 Redist

 

  • Reflector.CodeMetrics:
    • Nothing else
  • Reflector.Graph:
    • Dependency on NGraphviz (unmanaged assembly)
    • SVG viewer
  • Reflector.Framework:
    • Dependency on NGraphviz (unmanaged assembly)
    • SVG viewer

Features:

  • Reflector.CodeMetrics
    • CodeMetrics
    • Coverage datagrid
  • Reflector.Graph
    • Assembly Graph
    • IL graph (not bullet proof)
    • Statement Graph (not bullet proof)
    • Class diagram (alpha)
    • Method invocation graph (alpha)
    • Typed Dataset (alpha)
  • Reflector.Framework
    • All the addins from Reflector.CodeMetrics + Reflector.Graph
    • XmlSerializer viewer (see your object as if it was "XmlSerialized") *locks the assembly*
    • Control viewer (see your winforms control) *locks the assembly*
    • PropertyGrid viewer (see your object as if it was in a PropertyGrid control) *locks the assembly*
    • COM loader (compiles assembly for COM type libraries)  *New*
    • Reflector.Emit language
    • Type TreeMap (supports coverage)
    • IronPython console

 

 

 

posted on Tuesday, November 01, 2005 2:03:14 PM UTC  #    Comments [1]

Ever wondered what would it take to generate your code on the fly using Reflector.Emit....
The meaning of the following screenshot is left as a quiz...

posted on Tuesday, November 01, 2005 11:11:27 AM UTC  #    Comments [2]
 Saturday, October 29, 2005

I've update Reflector.Framework, Reflector.CodeMetrics and Reflector.Graph against the latest version of Reflector.

  • They all require .Net 2.0
  • Compiled against Reflector 4.1.85.0
  • Reflector.Framework requires IronPython assemblies!!!!
posted on Sunday, October 30, 2005 4:03:37 AM UTC  #    Comments [0]

It's alive!

posted on Sunday, October 30, 2005 4:00:01 AM UTC  #    Comments [0]
 Wednesday, October 26, 2005

A while ago I hooked up Haibo's ILReader to make a rustic Debugger Visualizer for DynamicMethod (Lightweight Code Generation). Haibo did the hard work and made it very interresting tool for debugging those strange .net citizens.

I'm a big fan of custom debugger visualizers. Not only they are very useful but they also very well documented and easily testable! There are already many implementations of those for datasets, xml, etc... but usually it worth investing a little time to build your own customized visualizers.

For example, if your data organized as a tree, you might be continuously drilling down this tree. You could consider a visializer that would render the tree to a certain depth. This will save you a *lot* of "expand node" time.

 

posted on Wednesday, October 26, 2005 2:00:48 PM UTC  #    Comments [0]
 Sunday, September 04, 2005

I have uploaded a updated build of the Reflector addins for Reflector. 4.1.80.0.

This build is done against Whidbey (.Net 2.0) Beta2!

posted on Monday, September 05, 2005 5:01:46 AM UTC  #    Comments [3]
 Tuesday, July 26, 2005

In this post, I’ll show how to build an MsBuild (msdn2) task will automatically generate XSD schemas for your custom tasks. The post is separated in two sections: if you are interested to see how the task works, continue on reading. If you don’t care and want to get straight down to the beef, scroll down until you see TaskSchema reference.

What is MsBuild? Why do we want to generate schemas?

MsBuild is the new .Net build system. It is based on XML files containing the projects, targets and tasks (see also Ant, NAnt). The framework comes with a set of tasks that allows easy compilation of solutions or projects and doing a couple more actions. Of course, everybody has different needs and you will probably end up writing your own specialized task to solve your problems.

When editing a MsBuild script, it is *very* convenient to take advantage of the “built-in intellisense” of XML by attaching it to the MsBuild schema file. You can do this in VS2005 in two mouse clicks (see below How to setup intellisense for msbuild). Unfortunately, this is not true for your custom tasks where you need to create yourself a XSD schema.

I’ll assume you have a basic knowledge of custom msbuild tasks in the following.

Note that NAnt has had this feature (nantschema) for a while now.

What are we looking for?

Before diving into the coding details, let’s see what our “final products” looks like. Let’s build a simple task to use it as our example during the article: the sleep tasks makes msbuild sleep x seconds (note that this implementation is very very poor):

using System;
using System.Threading;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Foo
{
public sealed Sleep : Task
{
private int seconds;

[Required]
public int Seconds
{
get { return this.seconds;}
set { this.seconds = value;}
}
public override bool Execute()
{
this.Log.LogMessage(“Sleeping {0} seconds”, this.Seconds);
Thread.Sleep(this.Seconds * 1000);
}
}
}

The sleep task has a single (required) parameter “seconds”. We expect the schema for this task to look as follows:

<xs:schema
    xmlns:msb=http://schemas.microsoft.com/developer/msbuild/2003
    elementFormDefault="qualified" 
    targetNamespace="http://schemas.microsoft.com/developer/msbuild/2003"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <
xs:include schemaLocation=" Microsoft.Build.Commontypes.xsd" />
    <
xs:element name="Sleep" substitutionGroup="msb:Task">
    <
xs:complexType>
        <
xs:complexContent mixed="false">
            <
xs:extension base="msb:TaskType">
                <
xs:attribute name="Seconds" type="msb:non_empty_string" />
            </
xs:extension>
        </
xs:complexContent>
   
</xs:complexType>
</xs:element>
</xs:schema>

There’s a couple things to say about this schema:

  1. we include the MsBuild schema so we get all the type that are already defined for msbuild,
  2. Sleep is in the substitutionGroup msb:Task,
  3. the extension has “msb:TaskType” as base class to inherit the Task properties,
  4. Since Seconds is an int, we restrict the attribute to msb:non_empty_string. We cannot restrict it to xs:integer to handle cases where the users pases a property, e.g. $(Property).
  5. Latter on, we could add information from the xml documentation into the schema as well.

Now that we know kind of output we are looking for, let’s see what “ingredients” we need.

Recipe ingredients

Here’s a little summary of tools and techniques that we will use to generate the schemas:

  • System.Reflection: we’ll use reflection to enumerate types, find custom attributes, etc…
  • System.Xml.Schema: this namespace contains the object model to create schemas (what a surprise!)
  • System.Xml: to integrate document parts (if available) in the output
  • Microsoft.Build.Utilities: this namespace contains the Task base class,

Building TaskSchema

The TaskSchema has the following properties (it actually has more properties but I’ll skip them for simplicity):

[Required]
ITaskItem[] Assemblies {get;set}
[Output]
ITaskItem[] Schemas {get;}

Assemblies is a list of assemblies containing the tasks to “schematize”. Schemas is an output parameter that will contain the path of each schema, as we will generate one schema per assembly.

This is the high level “factored” Execute method (almost pseudo-code):

CreateAndInitializeSchema(); // (add namespace, includes, etc...)

foreach(string assemblyName in Assemblies)
{
// load error handling comes here
Assembly assembly = LoadAssembly(assemblyName);
// iterating exported types
foreach(Type type in assembly.GetExportedTypes())
{
//if (type is not a task) continue;
if(!typeof(ITask).IsAssignableFrom(type)) continue;
// create a new schema element and name it after the type
// create a simpleType + extension
XmlSchemaElement element = CreateElement(type);
foreach(PropertyInfo property in type.GetProperties())
{
// if (property is defined in some base class) continue;
if (property.DeclaringType != type) continue;
// create schema attribute and name it after property name
// create a simpleType that
XmlSchemaAttribute attribute = CreateAttribute(property);
// add attribute to current element
AddAttribute(element, attribute);
}
}
// saving to disk
SaveSchema(schema);

There are a lot of interesting details to go through to implement this pseudo-code.
I won’t go through all of them. I will rather focus on some parts:

Translating enums into XSD

An enumeration can be represented in XSD by simple type restriction. For example,

[C#]

public enum HelloWorld
{
Hello,
World
}

[XSD]

<xs:simpleType name="HelloWorldType" base="msb:non_empty_integer">
    <
xs:restriction base="xs:string">
        <
xs:enumeration value="Hello" />
        <
xs:enumeration value="World" />
    </
xs:restriction>
</
xs:simpleType>

Getting custom attributes, the generic way

This is a well know (and very handy trick) that add a generic type parameter to a method to “strongly type” it.

T GetAttribute<T>(ICustomAttributeProvider t) where T : Attribute
{
object[] attributes = t.GetCustomAttributes(typeof(T), true);
if (attributes != null && attributes.Length > 0)
return (T)attributes[0];
else
return null;
}

 

Finding and adding documentation to the schema

Adding documention to the schema is straightforward, it is a matter of adding a annotation containing a document element:

<xs:attribute name="Assemblies" use="required">
    <
xs:annotation>
        <
xs:documentation>
            Gets or sets the list of path to analyse.
        </xs:documentation>
    </
xs:annotation>
</
xs:attribute>

The real trouble is to find what kind of documentation we are going to put there. We cannot rely solely on Reflection for this task because MsBuild custom attributes does not store any “documentation” data. Therefore, the best source of documentation is the XML documentation that is generated by the C# compiler (don’t forget to turn it on in Projects -> Properties -> Build). By default, the compiler dumps that file along side of the assembly so it is easy to find. Here’s a sample of how that file looks like:

<?xml version="1.0"?>
<
doc>
    <
assembly>
        <
name>TaskFoo</name>
    </
assembly>
    <
members>
        <
member name="T:TaskFoo.TaskSchema">
            <
summary>
                A Task that generates a XSD schema of the tasks in an assembly.
            </summary>
        </
member>
...

That is sweet. We can access the summary of each member very easily using XPath. For example:

//member[@name=”T:taskType.FullName”]/summary

This expression will return me the summary of the taskType type. Similar constructs can be mode for the property summary.

TaskSchema task reference

A Task that generates the XSD schemas for assemblies containing tasks.

Download: See Task on project distributor. Compiled against .Net 2.0 Beta 2.

Features:
  • Generates ready-to-use XSD schemas. No edition needed.
  • Generates task lists, i.e. the UsingTask sequence, to integrate easily your tasks into MsBuild,
  • If documentation is available, automatically adds documentation to the schema,
  • Task attribute are strongly typed,
  • Generates specific types for enumerations
  • It’s a MsBuild task! It will fit in your automation!
Attributes:
  • Assemblies: Required ITaskItem[] expression. The list of assemblies to analyse.
  • OutputPath: Optional string expression. The desired schemas output path.
  • Schemas: Output ITaskItem[] expression. For each assembly, the corresponding schema path.
  • CreateTaskList: Optional Boolean expression. A value that indicates if TaskList (see below) should be generated as well.
  • TaskLists: Output ITaskItem[] expression. For each assembly, the corresponding task list path. This output is null if CreateTaskList is false.

There are a couple more options. Run TaskSchema to have the full schema!

Examples:

This little msbuild project applies TaskSchema to itself (it is part of Churn.Tasks.dll):

<?xml version="1.0" encoding="utf-8" ?>
<
Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="CreateSchema">

    <
UsingTask AssemblyFile="Churn.Tasks\bin\Debug\Churn.Tasks.dll" TaskName="Churn.Tasks.TaskSchema" />

    <
ItemGroup>
        <
Assemblies Include="bin\Debug\TaskFoo.dll" />
    </
ItemGroup>

    <
Target Name="CreateSchema">
        <
TaskSchema
            Assemblies="@(Assemblies)" 
            OutputPath="Churn.Tasks\bin\Schemas" 
            />
    </
Target>
</
Project>

[Output]

Microsoft (R) Build Engine Version 2.0.50215.44
[Microsoft .NET Framework, Version 2.0.50215.44]
Copyright (C) Microsoft Corporation 2005. All rights reserved.
Build started 5/26/2005 8:19:51 PM.
__________________________________________________
Project "D:\Projects\Churn.NET\Churn.Tasks\taskschema.self.xml" (default targets):
Target CreateSchema:
Analysing bin\Debug\Churn.Tasks.dll
Found documentation file at Debug\Churn.Tasks.xml
Analyzing Churn.Tasks.TaskSchema
Creating Schema bin\Schemas\Churn.Tasks.Tasks.xsd
Create Task list bin\Schemas\Churn.Tasks.Tasks
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.93

[Schema: TaskFoo.xsd]

Execute the sample and see for yourself!

posted on Tuesday, July 26, 2005 12:27:33 PM UTC  #    Comments [5]
 Tuesday, July 19, 2005

Andrew and Jay have been working hard lately and published the following article:

Unit Testing with NUnit, MbUnit and VSTS 

posted on Tuesday, July 19, 2005 11:45:30 PM UTC  #    Comments [0]
 Friday, July 01, 2005

MbUnit gets a new wiki and issue tracking!

   http://www.mertner.com/confluence/display/MbUnit/Home

 

posted on Saturday, July 02, 2005 6:55:29 AM UTC  #    Comments [0]
 Wednesday, June 29, 2005
CruiseControl 0.9.2 has now MbUnit stylesheets... Congratulation to the CruiseControl team and Andrew to get this done. :)
posted on Wednesday, June 29, 2005 10:02:06 AM UTC  #    Comments [0]
 Wednesday, June 15, 2005
posted on Wednesday, June 15, 2005 10:00:40 AM UTC  #    Comments [0]
 Monday, June 13, 2005

I've uploaded the first demo on the project site. Have fun...

http://projectdistributor.net/Projects/Project.aspx?projectId=124

posted on Monday, June 13, 2005 12:43:12 PM UTC  #    Comments [0]
 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]