White box unit testing with AspectDNG 5

Posted by jbevain Thu, 13 Jan 2005 00:16:21 GMT


Last time, Tom was kidding me (softly) about the fact that we can do almost everything we want with AspectDNG. I begin to think he wasn’t wrong…

Once again, here is a very, very complex system that should be hard tested:

<!- code formatted by http://manoli.net/csharpformat/ ->

<span class="rem">// Main.cs</span>

<span class="kwrd">using</span> System;

<span class="kwrd">public</span> <span class="kwrd">class</span> ComplexSystem {

    <span class="kwrd">private</span> <span class="kwrd">int</span> m_secret;

    <span class="kwrd">public</span> ComplexSystem() {
        m_secret = 0;
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> SecretOperation(<span class="kwrd">int</span> oper) {
        m_secret += oper;
    }

    <span class="rem">// should always return a multiple of 2</span>
    <span class="kwrd">public</span> <span class="kwrd">int</span> PublicOperation() {
        <span class="kwrd">if</span> ((m_secret % 2) != 0) {
            SecretOperation(1);
        }
        <span class="kwrd">return</span> m_secret;
    }
}

This can be safely compiled to a Main.dll.
Ok, this ComplexSystem is the central point of your next application, you NEED to test it. What can be better than NUnit ? But here is the problem, you would like to be sure that the secret operation have a correct behaviour, and that the m_secret field is well setted… Two way to do that, first you use boring Reflection, or you can even take a look behind your back, you ensure that you’re alone, you change the visibility of all this, but you promise yourself that you’ll change it as soon as tests passed. Also you may note that somewhere not to forgot, this is a SECRET operation.

What about introducing a new way of testing this ? Using AspectDNG ? Something I may call white box unit testing ? Here is one aspect to do that :

<!- code formatted by http://manoli.net/csharpformat/ ->
<span class="rem">// Tests.cs</span>

<span class="kwrd">using</span> System;
<span class="kwrd">using</span> NUnit.Framework;

<span class="rem">// dummy complex system, may have been generated</span>
<span class="kwrd">public</span> <span class="kwrd">class</span> ComplexSystem {
    <span class="kwrd">public</span> <span class="kwrd">int</span> m_secret;
    <span class="kwrd">public</span> <span class="kwrd">void</span> SecretOperation(<span class="kwrd">int</span> oper) {}
    <span class="kwrd">public</span> <span class="kwrd">int</span> PublicOperation() { <span class="kwrd">return</span> 0; }
}

[TestFixture]
<span class="kwrd">public</span> <span class="kwrd">class</span> TestComplexSystem {

    <span class="kwrd">private</span> ComplexSystem m_complexSystem;

    [SetUp]
    <span class="kwrd">public</span> <span class="kwrd">void</span> SetUp() {
        m_complexSystem = <span class="kwrd">new</span> ComplexSystem();
    }

    [Test]
    <span class="kwrd">public</span> <span class="kwrd">void</span> TestPublicOperation() {
        Assert.AreEqual(0, m_complexSystem.PublicOperation() % 2);
        m_complexSystem.SecretOperation(1);
        m_complexSystem.SecretOperation(1);
        m_complexSystem.SecretOperation(1);
        Assert.AreEqual(0, m_complexSystem.PublicOperation() % 2);
        Assert.AreEqual(4, m_complexSystem.PublicOperation());
    }

    [Test]
    <span class="kwrd">public</span> <span class="kwrd">void</span> TestFieldSecret() {
        Assert.AreEqual(0, m_complexSystem.m_secret);
        m_complexSystem.SecretOperation(1);
        Assert.AreEqual(1, m_complexSystem.m_secret);
    }

    [Test]
    <span class="kwrd">public</span> <span class="kwrd">void</span> TestSecretOperation() {
        <span class="kwrd">int</span> cursor = m_complexSystem.m_secret;
        m_complexSystem.SecretOperation(12);
        Assert.AreEqual(12, m_complexSystem.m_secret - cursor);
    }
}

What can we see there ? I use a dummy ComplexSystem, that looks like really close to the real one no ? It is just a trick, with that, I’ll be able to compile this single file into a Tests.dll assembly. Once this is done, all I have to do it to inject the content of my TestComplexSystem into the real ComplexSystem. This can be done with the standard MetaAspect Insert from AspectDNG.
When weaving is done, after using a simple insert advice, here is the result :



“Et voila”, the ComplexSystem is now a test fixture itself. Pretty simple no ?
And this sample works with Mono. Of course it is a very lightweight one, but hey, it looks good !

UPDATE: You can download the sources of the example here. Just compile as described in the post, and run AspectDNG -w on the AspectDNG.xml provided.

So, what do you think about this kind of unit testing ? I’m curious about you opinion !

Cecil Feed 3

Posted by jbevain Mon, 10 Jan 2005 00:45:36 GMT


I’ve promised, here are some news of Mono.Cecil :

Mono.Cecil is now a top level module of Mono’s Subversion repository. It may be accessible from here, once the module will be mirrored to the anonymous SVN.

Included in the module is a little Gtk# Application, Cecil Feed, that for now, is just a modification of one of the samples bundled with Gtk#. The old sample was simply looking into assemblies, and diplayed some of their contents in a TreeView. I’ve juste adapted the sample and here is a screen shot of the beast :



And for curious peoples, here is the source of this sample application :

<span class="rem">// TreeView.cs - Fun TreeView demo</span>
<span class="rem">//</span>
<span class="rem">// Author: Kristian Rietveld &lt;kris@gtk.org&gt;</span>
<span class="rem">//</span>
<span class="rem">// (c) 2002 Kristian Rietveld</span>

<span class="rem">// A rewrite of the TreeView demo using Cecil</span>
<span class="rem">// Author: Jb Evain &lt;jb@evain.net&gt;</span>

<span class="kwrd">namespace</span> Cecil.Feed {    

    <span class="kwrd">using</span> System;
    <span class="kwrd">using</span> Gtk;

    <span class="kwrd">using</span> Mono.Cecil;

    <span class="kwrd">public</span> <span class="kwrd">class</span> TreeViewDemo : IReflectionStructureVisitor {

        <span class="kwrd">private</span> <span class="kwrd">string</span> m_file;
        <span class="kwrd">private</span> TreeStore m_store = <span class="kwrd">null</span>;
        <span class="kwrd">private</span> <span class="kwrd">int</span> m_count = 0;

        <span class="kwrd">private</span> TreeIter m_cursor;
        <span class="kwrd">private</span> <span class="kwrd">bool</span> m_newBranch = <span class="kwrd">false</span>;
        <span class="kwrd">private</span> <span class="kwrd">bool</span> m_root = <span class="kwrd">true</span>;

        <span class="kwrd">public</span> TreeViewDemo(<span class="kwrd">string</span> file) {

            m_file = file;

            DateTime start = DateTime.Now;

            Application.Init ();

            PopulateStore ();

            Window win = <span class="kwrd">new</span> Window(<span class="str">"Cecil ~ Feed"</span>);
            win.DeleteEvent += <span class="kwrd">new</span> DeleteEventHandler(<span class="kwrd">this</span>.DeleteCB);
            win.SetDefaultSize(640,480);

            ScrolledWindow sw = <span class="kwrd">new</span> ScrolledWindow ();
            win.Add (sw);

            TreeView tv = <span class="kwrd">new</span> TreeView(m_store);
            tv.HeadersVisible = <span class="kwrd">true</span>;
            tv.EnableSearch = <span class="kwrd">false</span>;
            tv.AppendColumn (<span class="str">"Name"</span>, <span class="kwrd">new</span> CellRendererText (), <span class="str">"text"</span>, 0);
            tv.AppendColumn (<span class="str">"Type"</span>, <span class="kwrd">new</span> CellRendererText (), <span class="str">"text"</span>, 1);

            sw.Add (tv);

            win.ShowAll ();            

            Console.WriteLine (m_count + <span class="str">" nodes added."</span>);
            Console.WriteLine (<span class="str">"Startup time: "</span> + DateTime.Now.Subtract (start));

            Application.Run ();
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IAssemblyDefinition asm) {
            AddToTree(m_file, <span class="str">"AssemblyDefinition"</span>);
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IAssemblyName name) {
            AddToTree(name.FullName, <span class="str">"AssemblyName"</span>);
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IAssemblyNameReferenceCollection names) {
            m_newBranch = <span class="kwrd">false</span>;
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IAssemblyNameReference name) {
            AddToTree(name.FullName, <span class="str">"AssemblyNameReference"</span>);
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IResourceCollection resources) {
            m_newBranch = <span class="kwrd">false</span>;
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IEmbeddedResource res) {
            AddToTree(res.Name, <span class="str">"EmbeddedResource"</span>);
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(ILinkedResource res) {
            AddToTree(res.Name, <span class="str">"LinkedResource"</span>);
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IModuleDefinition module) {
            AddToTree(module.Name, <span class="str">"ModuleDefinition"</span>);
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IModuleDefinitionCollection modules) {
            m_newBranch = <span class="kwrd">true</span>;
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IModuleReference module) {
            AddToTree(module.Name, <span class="str">"ModuleReference"</span>);
        }

        <span class="kwrd">public</span> <span class="kwrd">void</span> Visit(IModuleReferenceCollection modules) {
            m_newBranch = <span class="kwrd">false</span>;
        }

        <span class="kwrd">private</span> <span class="kwrd">void</span> PopulateStore () {
            m_store = <span class="kwrd">new</span> TreeStore (<span class="kwrd">typeof</span> (<span class="kwrd">string</span>), <span class="kwrd">typeof</span> (<span class="kwrd">string</span>));

            IAssemblyDefinition asm = AssemblyFactory.GetAssembly(m_file);
            asm.Accept(<span class="kwrd">this</span>);
        }

        <span class="kwrd">private</span> <span class="kwrd">void</span> AddToTree(<span class="kwrd">string</span> name, <span class="kwrd">string</span> type) {
            <span class="kwrd">if</span> (m_newBranch) {
                m_cursor = m_store.AppendValues(m_cursor, name, type);
                m_newBranch = <span class="kwrd">false</span>;
            } <span class="kwrd">else</span> {
                m_store.AppendValues(m_cursor, name, type);
            }
            <span class="kwrd">if</span> (m_root) {
                m_cursor = m_store.AppendValues(name, type);
                m_root = <span class="kwrd">false</span>;
            }
            m_count++;
        }

        <span class="kwrd">private</span> <span class="kwrd">void</span> DeleteCB(<span class="kwrd">object</span> o, DeleteEventArgs args) {
            Application.Quit ();
        }

        <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> Main (<span class="kwrd">string</span>[] args) {
            <span class="kwrd">if</span> (args.Length == 0) {
                Console.WriteLine(<span class="str">"usage: cecil-feed.exe assembly"</span>);
                <span class="kwrd">return</span>;
            }
            <span class="kwrd">try</span> {
                TreeViewDemo tvd = <span class="kwrd">new</span> TreeViewDemo(args[0]);
            } <span class="kwrd">catch</span> (Exception e) {
                Console.WriteLine(e);
            }
        }
    }
}

Ok, it is very simple, but once I’ll work on Cecil a bit more, we can imagine to have here on the first Open Source ildasm clone. By the way, this example shows how it is simple with the design pattern visitor to walk through Cecil’s objects. Using this, it should be very easy to write some little tools like peverify, or even write optimizers.

What do you think you would do with a library to manipulate CIL files ?

DotNetGuru contributes to Mono, or the contrary 5

Posted by jbevain Fri, 07 Jan 2005 08:09:49 GMT


<span class="kwrd">using</span> Mono.Cecil;

Tonight, Cecil will leave SourceForge’s CVS to a better place, in the sun.

Cecil’s development will now be supported by Mono’s SVN. By the way, its name change a little bit. It is now Mono.Cecil, hey, sounds good no ?

Thanks to Miguel De Icaza, I have received a write access to Mono’s SVN last night. Cecil will be a top module until it is mature enough to be bundled with others Mono’s assemblies.

I’m proud, but a lot of work remains, Cecil isn’t really usable, but I hope that its new status will improve the speed of the devel, and will bring more feedbacks and bugs reports.

Last but not least, this blog may be syndicated within the Monologue, by this way the world may discovers AspectDNG, and others DNG activities I’ll blog on.

I’ll post as soon as migration is ended, to give you instructions to access Cecil’s repository. I may blog later on some screen shots of a little Gtk# application, using Cecil, that mimics ildasm, but it is really simple and limited to Cecil progress.

Isn’t the year 2005 beginning very well ?

DNG, Cecil, X-develop 1

Posted by jbevain Mon, 03 Jan 2005 22:18:15 GMT


Nom de zeus !

J'ai toujours un onglet FireFox pointant sur DotNetGuru, et quand l'envie m'en prend, j'y fait un petit F5. J'ai cru que que mon renard partait en vrille, mais non, DNG a bel et bien changé.

Bon, mon premier réflexe fut de plisser les yeux et de faire berk. Bon c'est pas ma faute, il faut croire que j'aime les couleurs tristes. En ce sens il m'allait bien l'ancien DNGn de toute façon, faut pas m'écouter, je suis pire que les vieux. Mais bon, à force de naviguer dessus depuis dix bonnes minutes, on s'y fait plutôt pas mal. Les polices sont plus smooth, et globalement on s'y retrouve. Seul manque à l'appel les anciens messages du forum, et surtout, la page sur AspectDNG. Crime ! Donc au final, je m'y fait plutôt bien, et bravo pour le switch éclair sans anicroches.

Ce post allant surement croiser ceux d'autres gens sur le même sujet, je passe à autre chose.

Cecil ma fille


J'ai mis à disposition des curieux un snapshot fraichement tiré du CVS de sourceforge, de ma petite librairie Cecil. Petite librairie, qui n'a pour ambition que de fournir une alternative complètement managée à System.Reflection, et System.Reflection.Emit. Je vous laisse regarder ici :

Alors où en suis-je ? La partie lecture des meta données est pratiquement terminée, et la partie Reflection ne va que jusqu'aux modules, mais ça laisse quand même appercevoir à quoi la librairie pourra ressembler au final. Je remercie d'avance tous les curieux et les courageux, qui mettront ici leurs commentaires sur ce petit bout de code. Petit conseil final, allez voir dans les tests pour non seulement admirer comment je debug avec des Console.WriteLine dans NUnit, mais surtout pour voir comment manipuler le "point d'entrée" de la librairie.

Au passage, je suis passé à X-develop pour développer cette librairie, et le fait est, que c'est vraiment un IDE très orienté source, et que pour mon usage, il est vraiment bien. Ma version d'évaluation se fini au cours du mois, ils ont intérêt à rallonger la licence de test si ils veulent que je continue à écrire des bugs reports.

EDIT :
La page AspectDNG est de retour, joie.
L'ancien site sera disponible à une autre adresse, joie. Que demande le peuple ?

Older posts: 1 ... 29 30 31 32 33