# 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 Thursday, December 16, 2004 1:24:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [9]
# Thursday, December 09, 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 Thursday, December 09, 2004 9:30:00 PM (Pacific Standard Time, UTC-08:00)  #    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 Sunday, December 05, 2004 2:48:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [11]
# Monday, November 29, 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 Monday, November 29, 2004 4:49:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [14]
# Sunday, November 28, 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 Sunday, November 28, 2004 4:49:00 PM (Pacific Standard Time, UTC-08:00)  #    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 Sunday, November 28, 2004 4:24:00 PM (Pacific Standard Time, UTC-08:00)  #    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 3:07:00 AM (Pacific Standard Time, UTC-08:00)  #    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 Tuesday, November 23, 2004 12:21:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [14]
# Wednesday, November 17, 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 Wednesday, November 17, 2004 6:50:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [18]
posted on Wednesday, November 17, 2004 2:55:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]