<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-5841632161546703012</atom:id><lastBuildDate>Mon, 16 Sep 2024 01:43:17 +0000</lastBuildDate><category>VS2012</category><category>Visual Studio</category><category>.NET</category><category>VS2010</category><category>Unit Testing</category><category>VS2013</category><category>Visual Studio Extensions</category><category>introduction</category><category>TDD</category><category>microformats</category><category>ContinuousTests</category><category>Mighty Moose</category><category>book</category><category>books</category><category>gripe</category><category>proposal</category><category>rant</category><category>title</category><category>titles</category><category>AMD</category><category>ATI Catalyst 9.4</category><category>AllMargins</category><category>AllMargins 2012</category><category>C#</category><category>Code Contracts</category><category>Firefox 3</category><category>Generics</category><category>IE8</category><category>Regular Expressions</category><category>UTF-16</category><category>Unicode</category><category>XML</category><category>book reviews</category><category>computers</category><category>history</category><category>musings</category><category>nostalgia</category><category>retro</category><category>semantics</category><category>unattended install</category><category>web design</category><title>Discovering Code</title><description>A blog about programming, computers, science, and anything else I feel like writing about.</description><link>http://discoveringcode.blogspot.com/</link><managingEditor>noreply@blogger.com (Craig S.)</managingEditor><generator>Blogger</generator><openSearch:totalResults>22</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-7969714671855419602</guid><pubDate>Fri, 07 Mar 2014 04:44:00 +0000</pubDate><atom:updated>2014-03-07T18:10:45.306-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">Code Contracts</category><category domain="http://www.blogger.com/atom/ns#">TDD</category><category domain="http://www.blogger.com/atom/ns#">Unit Testing</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio</category><category domain="http://www.blogger.com/atom/ns#">VS2010</category><category domain="http://www.blogger.com/atom/ns#">VS2012</category><category domain="http://www.blogger.com/atom/ns#">VS2013</category><title>Code Contracts and Test-Driven Development</title><description>&lt;h3&gt;Introduction&lt;/h3&gt; &lt;p&gt;This post will be mostly about Microsoft’s Research in Software Engineering (RiSE) group’s &lt;a href=&quot;http://research.microsoft.com/en-us/projects/contracts/&quot; target=&quot;_blank&quot;&gt;Code Contracts&lt;/a&gt;. I’ll also cover the role of code contracts in conjunction with test-driven development. There seems to be a debate over the role of test-driven development when using code contracts. I’m going to weigh in on that debate.&lt;/p&gt; &lt;p&gt;In order to demonstrate code contracts, I’m going to return to the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class that I used as an example in my blog post &lt;a href=&quot;http://discoveringcode.blogspot.com/2014/02/advanced-test-driven-development.html&quot; target=&quot;_blank&quot;&gt;Advanced Test-Driven Development&lt;/a&gt;. This post may also be a little on the longer side.&lt;/p&gt; &lt;h3&gt;An Introduction to Code Contracts&lt;/h3&gt; &lt;p&gt;What are code contracts? Where did they come from? Why should I care?&lt;/p&gt; &lt;p&gt;The term ‘code contract’ was coined by Bertrand Meyer while he was developing the Eiffel programming language around 1986. In fact, code contracts are a core part of the Eiffel programming language to this day.&lt;/p&gt; &lt;p&gt;Code contracts are a way of specifying pre-conditions, post-conditions for methods and invariants for objects. Pre-conditions are predicates that specify conditions that must be met in order for a method to be in a state that can result in successful execution. Post-conditions are predicates that must be met upon any exit from a method. Invariants are predicates that validate state that must hold at all throughout the lifetime of an object.&lt;/p&gt; &lt;h3&gt;Microsoft &amp;amp; Code Contracts&lt;/h3&gt; &lt;p&gt;Microsoft’s RiSE team first introduced code contracts to .NET as an extension to the C# language known as Spec#. Spec# was basically a &lt;abbr title=&quot;Domain Specific Language&quot;&gt;DSL&lt;/abbr&gt; especially for defining code contracts when programming in C#. Fast forward a few years, and shortly after the release of the .NET Framework 3.5, the RiSE team released the successor to Spec#, Code Contracts, in the form of an assembly that you can reference from your project. This assembly replaced the DSL with a native C# language implementation. For the first time in .NET (aside from the Spec# augmented language), programmers could employ code contracts (and not just simple guard conditions at method entry and rudimentary forms of post-conditions). With the release of the .NET Framework 4.0, Code Contracts have found their way into the base class library (BCL) itself. Code contracts can be found in the &lt;code class=&quot;csharp identifier&quot;&gt;System&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;Diagnostics&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;Contracts&lt;/code&gt; namespace. You no longer need to reference an external assembly to employ code contracts.&lt;/p&gt; &lt;p&gt;In order to make full use of code contracts in your .NET projects, you will need to install the necessary tooling from &lt;a href=&quot;http://research.microsoft.com/en-us/projects/contracts/&quot; target=&quot;_blank&quot;&gt;Microsoft’s RiSE Code Contracts site&lt;/a&gt;. Installing this tooling installs a new project properties tab for controlling how contracts are incorporated into your assemblies, whether contracts will be enforced at runtime, and/or whether or not the static analyzer will perform an analysis of your code. For the full details, check out the &lt;a href=&quot;http://research.microsoft.com/en-us/projects/contracts/userdoc.pdf&quot; target=&quot;_blank&quot;&gt;Code Contracts documentation&lt;/a&gt;. Furthermore, the tooling installs a code contracts re-writer. The re-writer is the component responsible for weaving the necessary &lt;abbr title=&quot;Intermediate Language&quot;&gt;IL&lt;/abbr&gt; into your assemblies in order to enforce the contracts according to the options specified. OK, enough of the history lesson. Let’s get to the fun part: the code.&lt;/p&gt; &lt;h3&gt;Using Code Contracts with the Category Class&lt;/h3&gt; &lt;p&gt;As I stated in the introduction to this post, I’m going to be reusing the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class example I went through in my post on advanced TDD. This class represents a category that you might find in some online e-commerce product catalog. I&#39;m going to highlight just a few areas of the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class as it pertains to implementing code contracts. The first part of the class we’re going to look at is instantiating the class given a name, since the pre- and post-conditions are pretty easy to follow. Also, because of this easiness, it will be easier to introduce how to incorporate unit testing when using Code Contracts.&lt;/p&gt; &lt;p&gt;So, starting with the a category&#39;s name: it cannot be null; it must not be the empty string; and it must not consist solely of whitespace. In my advanced TDD post, we enforced these requirements with the following code:&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;public class Category
{
    private string name;

    public Category(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new InvalidCategoryNameException();

        this.name = SanitizeName(name);
    }
}
&lt;/pre&gt;
&lt;p&gt;The guard clause is known as a pre-condition. This particular form of pre-condition is considered a &lt;i&gt;defensive programming&lt;/i&gt; style. If the &lt;code class=&quot;csharp identifier&quot;&gt;name&lt;/code&gt; parameter is null, the empty string, or only whitespace, an &lt;code class=&quot;csharp userType&quot;&gt;InvalidCategoryNameException&lt;/code&gt; exception is thrown. Notice that the constructor has no post-conditions&amp;mdash;there is no code to ensure that the private class field &lt;code class=&quot;csharp identifier&quot;&gt;name&lt;/code&gt; also satisfies these conditions. (In all honesty, it&#39;s hard to think of a reason why, if the &lt;code class=&quot;csharp identifier&quot;&gt;name&lt;/code&gt; parameter meets the pre-conditions, the corresponding class field would not end up being assigned.) Let&#39;s see what this same constructor would look like using Code Contracts.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;using System;
using System.Diagnostics.CodeContracts;

namespace DDDSportsStore.Domain
{
    public class Category
    {
        private string name;

        public Category(string name)
        {
            Contract.Requires&amp;lt;InvalidCategoryNameException&amp;gt;(
                !string.IsNullOrWhiteSpace(name)
            );
            Contract.Ensures(!string.IsNullOrWhiteSpace(this.name));

            this.name = SanitizeName(name);
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;As you can see, the guard clause was replaced with a call to &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Requires&lt;/span&gt;&amp;lt;&lt;span class=&quot;csharp typeParam&quot;&gt;T&lt;/span&gt;&amp;gt;(&lt;span class=&quot;csharp keyword&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;csharp identifier&quot;&gt;precondition&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;. (&lt;span style=&quot;font-variant: small-caps&quot;&gt;Important&lt;/span&gt;: read the documentation before using the generic form of the &lt;code class=&quot;csharp identifier&quot;&gt;Requires&lt;/code&gt; method in your release code.) This line of code guarantees that if the &lt;code class=&quot;csharp identifier&quot;&gt;name&lt;/code&gt; parameter does not meet the specified pre-condition, the specified exception will be thrown. Similarly, we have stated a post-condition: namely that when this constructor exits, the class&#39;s &lt;code class=&quot;csharp identifier&quot;&gt;name&lt;/code&gt; field will also not be null, an empty string, or whitespace. In my advanced TDD post, the constructor ended up having a lot more guard clauses in it for other properties of the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class. Don&#39;t worry, we&#39;ll come to those soon.&lt;/p&gt;
&lt;h3&gt;Code Contract Violations&lt;/h3&gt;
&lt;p&gt;When a pre-condition, post-condition, or invariant condition is violated, an exception is thrown. The exception is the &lt;code class=&quot;csharp identifier&quot;&gt;System&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;Diagnostics&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;Contracts&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;csharp userType&quot;&gt;ContractException&lt;/span&gt;&lt;/code&gt;. The catch is, this exception’s access modifier is &lt;code class=&quot;csharp keyword&quot;&gt;internal&lt;/code&gt;; so you can’t catch this exception directly. This is actually a very good design decision on the part of the RiSE team, even thought it causes headaches for us developers&amp;mdash;especially when it comes to unit testing. Programmers should not be able to circumvent contract violations by catching these exceptions and “handling” them. Contracts are guarantees. Pre-conditions guarantee that, given parameters that satisfy the stated pre-conditions, the method can perform its duties. Similarly, post-conditions guarantee to the caller that upon exit from the method, certain conditions will be true. And invariants guarantee that certain conditions hold throughout the lifetime of the object before and after each method call. So while this is a bit of a pain when it comes to unit testing, this was a very good decision.&lt;/p&gt;
&lt;h3&gt;Code Contracts and Test-Driven Development&lt;/h3&gt;
&lt;p&gt;As I alluded to in the introduction to this post, there is a debate that’s been going on in Internet land regarding the roles of code contracts and test-driven development and when and how they are used together. I’ve seen many people giving bad advice in regards to these development practices and I wish to argue the case for my opinion in the next few paragraphs.&lt;/p&gt;
&lt;p&gt;What, traditionally, has been the purpose of unit tests (especially those unit tests written as part of a test-driven development effort)? Traditionally, they’re written to ensure that a method does what it’s supposed to do. In fact, there’s a whole style of test-driven development known as behavior driven development (BDD). BDD’s main focus is tests that are named after the behavior that the function is performing. BDD tests strive to be as human readable as possible in an effort to be somewhat of a requirements document for the code base. (I’m over simplifying a bit&amp;mdash;I urge you to become familiar with it, as the style has many merits over regular TDD.) But no matter the testing style you use, tests are written to verify that: 1) method parameters are checked to ensure successful execution of a method; 2) the method executes successfully and the proper outputs are returned; and 3) that the state of the object is valid when the method has finished executing (not all tests require this last point to be checked). The first point sounds a lot like pre-conditions&amp;mdash;and in a sense, that’s exactly what’s being checked. The second point sounds exactly like post-conditions&amp;mdash;and it is. The third point, if part of the test, might be an object invariant (I say might, because what’s being tested in the third point may only be true for that particular case and not a true invariant.)&lt;/p&gt;
&lt;p&gt;So now the question is, if I use code contracts, do I need to test pre-conditions and post-conditions? Emphatically, I say YES!! You will find many who disagree with me. Let’s examine the two main arguments against writing tests that exercise code contracts.&lt;/p&gt;
&lt;h4&gt;You Don’t Write Unit Tests that Exercise Debug Asserts—Why Write Tests That Exercise Your Contracts?&lt;/h4&gt;
&lt;p&gt;First, I would like to say that this is an invalid statement to begin with. Of course you don’t exercise debug asserts. There’s nothing you can do with them in the testing framework. Your test will fail if a debug assert fails because the program aborts (and therefore, your test runner aborts, too)! So that’s just a ridiculous comparison to make. Furthermore, pre-conditions are not debug asserts. I think this argument comes about because there is a &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Assert&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; method in Code Contracts. But this method is not used as a pre- or post-condition. The &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Assert&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; method is used as a hint to the static analyzer that, at some point in your code, some condition should hold. That’s it. It’s just a hint to the static analyzer&amp;mdash;not a contract. These hints are sometimes needed in order to give the static analyzer a little bit of help when it can’t quite figure out what should hold or not.&lt;/p&gt;
&lt;h4&gt;Testing Code Contracts Pre-Conditions is Akin to Testing the BCL&lt;/h4&gt;
&lt;p&gt;This argument is almost plausible; but ultimately, it is flawed. First, it is true that Code Contracts are now a part of the .NET base class library. That’s what makes this argument so plausible. However, when you write tests to test your pre-conditions, the goal is not to test that Code Contracts “does the right thing” when a contract is violated. Indeed, that would be silly. It’s 3rd party code that I have no control over, so why test it? No, what I am testing is that I didn’t accidentally mistype the condition that is checked as part of the pre-condition contract!&lt;/p&gt;
&lt;p&gt;Seriously, you must write unit tests for your pre-conditions. While adding code contracts to the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class used in this blog post, I did mistype a pre-condition specification. The specification was supposed to ensure that when adding a subcategory to a category, the category being added as a subcategory is not null and was not the &lt;code class=&quot;csharp userType&quot;&gt;NullCategory&lt;/code&gt;. So when I ran my unit tests and two of them failed (again, I had added the contracts after I had already written the majority of the class in this instance using the standard defensive coding practice of guard clauses at method entry), I was surprised. What happened is that I had accidentally used an &lt;code class=&quot;csharp literal&quot;&gt;||&lt;/code&gt; instead of an &lt;code class=&quot;csharp literal&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; in the pre-condition (I probably had copied the guard clause condition; pre-conditions are often the opposite of traditional guard clauses—guard clauses check that something isn’t true, pre-conditions check that something is true). So again I say, YES, you must test your pre-conditions to ensure, not that Code Contracts is behaving, but that you didn’t mistype your pre-condition!&lt;/p&gt;
&lt;p&gt;I do find, however, that it’s not practical to test your post-conditions, even though the same possibility of mistyping the post-condition exists. This is because 1) it’s really hard to make your method fail a post-condition on purpose, and 2) chances are, if your post-condition is wrong, a &lt;code class=&quot;csharp userType&quot;&gt;ContractException&lt;/code&gt; exception will be thrown. Again, this argument is not water tight—but it is difficult to test post-conditions, and therefore I believe, not worth the effort.&lt;/p&gt;
&lt;p&gt;I think that these two arguments are the most frequent reasons given for not testing your code contracts; and I think I have demonstrated why these arguments don’t hold water.&lt;/p&gt;
&lt;h3&gt;Test-Driven Development with Code Contracts&lt;/h3&gt;
&lt;p&gt;Now that we have that out of the way, I want to share with you how you can perform test-driven development while using code contracts. This did take me quite a bit of time to figure out. So let’s re-introduce unit tests for the constructor as it&#39;s currently implemented above.&lt;/p&gt;
&lt;p&gt;The first thing we need to take care of is the fact that when a contract is violated, a private &lt;code class=&quot;csharp userType&quot;&gt;ContractException&lt;/code&gt; exception is thrown, and since it’s private, it cannot be caught. So how can we test our pre-conditions? Code contracts provides an event on the static &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;/code&gt; class called &lt;code class=&quot;csharp identifier&quot;&gt;ContractFailed&lt;/code&gt;. You can subscribe to this event to get access to the contract exception that was thrown. You can also flag the exception as handled from within this event. (So apparently, even thought you can’t catch the exception, you can subscribe to this event and effectively handle it there. Why any good developer would do this is beyond me, after all, why use code contracts in the first place, then? But for unit testing, this is just the hook we need for testing our contracts&amp;mdash;but this is the only place where you should ever write this code.)&lt;/p&gt;
&lt;p&gt;Now if you remember back to our constructor example, I was using the generic form of the &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Requires&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; method that allowed me to specify the exception that is thrown. How this works is, upon a contract violation, code contracts will still throw the &lt;code class=&quot;csharp identifier&quot;&gt;System&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;Diagnostics&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;Contracts&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;csharp userType&quot;&gt;ContractException&lt;/span&gt;&lt;/code&gt; exception. But there is a class that is emitted as part of the code contracts re-writer that is able to catch this exception. When the exception is caught, the exception’s &lt;code class=&quot;csharp identifier&quot;&gt;InnerException&lt;/code&gt; property contains an instance of the exception specified for the generic type parameter. This inner exception is then thrown back to the application. (Read the documentation before using the generic version of &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Requires&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;Shown below, I have written a class that subscribes to the &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;ContractFailed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; event,&amp;nbsp; which is meant to serve as a base class for all test classes that will be testing objects written with code contracts.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;using System;
using System.Diagnostics.Contracts;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DDDSportsStore.Domain.Tests
{
    // Probably not the best named class for this purpose...
    // but good enough.
    [TestClass]
    public abstract class UnitTestBase
    {
        private EventHandler&amp;lt;ContractFailedEventArgs&amp;gt; ContractFailedHandler = 
            new EventHandler&amp;lt;ContractFailedEventArgs&amp;gt;((s, e) =&amp;gt; e.SetHandled());

        [TestInitialize]
        public void HookContractFailed()
        {
            Contract.ContractFailed += ContractFailedHandler;
        }

        [TestCleanup]
        public void UnhookContractFailed()
        {
            Contract.ContractFailed -= ContractFailedHandler;
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;This class has both a setup and a teardown method. It hooks and unhooks an event handler to handle the &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;ContractFailed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; event. In the official documentation, the RiSE team show that you should call &lt;code class=&quot;csharp identifier&quot;&gt;e&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;SetUnwind&lt;span class=&quot;csharp literal&quot;&gt;()&lt;/span&gt;&lt;/code&gt;. If you call that method, your unit tests will stop running the moment a contract is violated. That’s because that method causes another exception to be thrown. Any exception thrown from the &lt;code class=&quot;csharp identifier&quot;&gt;ContractFailed&lt;/code&gt; event handler winds up causing the application to terminate&amp;mdash;which means no other tests will run because the test runner will be terminated. But in this case, we want the exception to be thrown because it verifies that when we pass invalid parameters to the method under test, that the pre-condition contract was specified correctly, and therefore, the correct exception is thrown. So now you can use your test framework’s method for asserting thrown exceptions and the tests will pass. Let’s look at an example test that tests our &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; constructor by passing a &lt;code class=&quot;csharp keyword&quot;&gt;null&lt;/code&gt; name, an empty string name, and a name consisting entirely of whitespace.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;[TestClass]
public CategoryTests : UnitTestBase
{
    private void AssertCannotCreateCategoryWithName(string name)
    {
        ExceptionAssert.Throws&amp;lt;InvalidCategoryNameException&amp;gt;(
            () =&amp;gt; new Category(name)
        );
    }

    [TestMethod]
    When_creating_a_category_with_an_invalid_name_then_an_InvalidCategoryNameException_is_thrown()
    {
        AssertCannotCreateCategoryWithName(null);
        AssertCannotCreateCategoryWithName(string.Empty);
        AssertCannotCreateCategoryWithName(&quot;\n&quot;);
    }
}
&lt;/pre&gt;
&lt;p&gt;If you look back to my previous post, you will see my implementation of the &lt;code class=&quot;csharp userType&quot;&gt;ExceptionAssert&lt;/code&gt; class that I created to handle testing for thrown exceptions. I prefer using this utility class to using the &lt;code class=&quot;csharp userType&quot;&gt;ExpectedExceptionAttribute&lt;/code&gt; attribute. Pretty much, that&#39;s all there is to incorporating unit tests with code that uses code contracts and maintaining the ability to test that you typed your pre-conditions correctly. If you don&#39;t want to use the generic form of the &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Requires&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; method (and there may be good reasons for you to do so, see the code contracts documentation for details), then you may need to modify how you test your pre-conditions. But the basic elements remain the same. I&#39;ll leave that as an exercise for you.&lt;/p&gt;
&lt;p&gt;For the remainder of this blog post, I&#39;m going to skip showing unit tests. As, apart from what I showed above, there&#39;s nothing different about my unit tests than what I demonstrated in my previous blog post. For the rest of this post, I want to focus on Code Contracts and incorporating more of its features into your classes.&lt;/p&gt;
&lt;h3&gt;Code Contracts and Inheritance&lt;/h3&gt;
&lt;p&gt;The great thing about Code Contracts is that you don’t need to redefine them on all of your sub-types. Once you define them on a base class, they’re defined for all sub-types. In this way, using Code Contracts can help ensure that your code follows the Liskov Substitution Principle (LSP). Because code contracts are inherited, all derived types can be used in place of their base types and clients are guaranteed that all pre-conditions, post-conditions, and invariants of the base type will still hold on all derived types.&lt;/p&gt;
&lt;p&gt;This does have some implications for derived types however. Derived types are not allowed to define pre-conditions that are stronger than their base types (in fact, doing so would most likely be a direct violation of the LSP to begin with). It is interesting to note, that while weaker pre-conditions should be allowed, they are not. The RiSE team, in their work with Spec#, found that allowing weaker pre-conditions often provided little value but added a large amount of complexity to the analyzer. So in effect, you cannot even add any pre-conditions to derived types. This is even true for interfaces (after all, interfaces are nothing more than pure, abstract classes for which C# has simply provided syntactic sugar (and built-in compiler constraints) in the form of the &lt;code class=&quot;csharp keyword&quot;&gt;interface&lt;/code&gt; keyword). It should also be noted that if you don’t specify any pre-condition on a method in a base class, then that method is considered to have the weakest of all pre-conditions: &lt;code class=&quot;csharp keyword&quot;&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These same rules, however, do not apply to post-conditions. You are allowed to specify stronger post-conditions on derived types. This just provides further guarantees for clients that call those methods on derived types compared to their base class method counterparts.&lt;/p&gt;
&lt;h3&gt;Code Contracts and Abstract Class Methods and Interfaces&lt;/h3&gt;
&lt;p&gt;Naturally, the question should arise: how can I implement contracts on abstract class methods and interfaces, neither of which are permitted to have method bodies? The answer is to create a special class that overrides the abstract class methods or implements the interface. Code Contracts provides two attributes, one that adorns the abstract class or interface (&lt;code class=&quot;csharp userType&quot;&gt;ContractClassAttribute&lt;/code&gt;), and the other that adorns the contract class itself (&lt;code class=&quot;csharp userType&quot;&gt;ContractClassForAttribute&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;Keeping Your Contracts DRY&lt;/h3&gt;
&lt;p&gt;If you find yourself repeating many contracts over and over again in various methods throughout your objects, you can group them together into methods adorned with the &lt;code class=&quot;csharp userType&quot;&gt;ContractAbbreviatorAttribute&lt;/code&gt; attribute and call them directly from methods that require the contracts. Let me show you an example. For any &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; that is created, it must have a non-null list of subcategories. It’s parent category must also not be null (if a category has no parent, it should have the &lt;code class=&quot;csharp userType&quot;&gt;NullCategory&lt;/code&gt; &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;None&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; assigned as its property value). And of course, a category should not have a null, empty string, or whitespace only name after it’s been instantiated. Here’s how I can “group” my contracts together:&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;public class Category
{
    public static readonly Category None = new NullCategory();

    private string name;
    private Category parentCategory;
    private List&amp;lt;Category&amp;gt; subCategories;

    protected Category()
    {
        subCategories = new List&amp;lt;Category&amp;gt;();
    }

    public Category(string name) : this(name, None) { }

    public Category(string name, Category parent) : this()
    {
        Contract.Requires&amp;lt;InvalidCategoryNameException&amp;gt;(
            !string.IsNullOrWhiteSpace(name)
        );
        Contract.Requires(parent != null);
        EnsureThisCategoryIsValid();

        this.name = SanitizeName(name);
        if (parentCategory == null)
            parentCategory = parent;
        else
            SetParentCategory(parent);
    }

    [ContractAbbreviator]
    private void EnsureThisCategoryIsValid()
    {
        // Obviously, separate calls to Ensures or Requires are ANDed together...
        Contract.Ensures(subCategories != null);
        Contract.Ensures(
            this == None || 
            !(string.IsNullOrWhiteSpace(name) || parentCategory == null)
        );
    }
}
&lt;/pre&gt;
&lt;p&gt;Again, while this example is trivial, if you have a lot of methods with the same pre- and/or post-conditions, this can be a valuable tool in keeping your code contracts code &lt;abbr title=&quot;Don&#39;t Repeat Yourself&quot;&gt;DRY&lt;/abbr&gt;.&lt;/p&gt;
&lt;p&gt;Specifying Object Invariants&lt;/p&gt;
&lt;p&gt;Code contracts has a way of telling the analyzer the various invariants of your objects. Invariants are conditions that must be met by your object after each public method call. In the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class, for example, the following invariants are true: a category’s name is not null, a category’s parent is not null, and a category’s list of subcategories is not null. These conditions can be checked by placing them within calls to &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Invariant&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; inside of a method adorned with the &lt;code class=&quot;csharp userType&quot;&gt;ContractInvariantMethodAttribute&lt;/code&gt; attribute as shown below:&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;[ContractInvariantMethod]
public void CategoryInvariants()
{
    Contract.Invariant(Name != null);
    Contract.Invariant(Parent != null);
    Contract.Invariant(Subcategories != null);
}
&lt;/pre&gt;
&lt;p&gt;Invariants can be especially useful with automatic properties (properties that don&#39;t have explicit backing fields that are retrieved/assigned from the property&#39;s getters/setters).&lt;/p&gt;
&lt;h3&gt;Code Contract Helper Methods&lt;/h3&gt;
&lt;p&gt;Let&#39;s say you have some helper method to help you in determining whether certain conditions hold (either for pre- or post-conditions on a method) due to some complex logic. You don&#39;t really want all that complex logic in the &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Requires&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; or &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Ensures&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; method call. So instead, you&#39;ll have something like &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Ensures&lt;/span&gt;(&lt;span class=&quot;csharp identifier&quot;&gt;ThisMethodsResultsAreVaild&lt;/span&gt;());&lt;/span&gt;&lt;/code&gt;. In order to use this method without code contracts emitting an error at compile time, you should mark the method as pure using the &lt;code class=&quot;csharp userType&quot;&gt;PureAttribute&lt;/code&gt; attribute. This tells code contracts that this method has no visible side-effects and will remove the compiler error. The effects of the &lt;code class=&quot;csharp userType&quot;&gt;PureAttribute&lt;/code&gt; attribute are also inherited by derived classes.&lt;/p&gt;
&lt;h3&gt;Giving the Analyzer a Helping Hand&lt;/h3&gt;
&lt;p&gt;Determining the various states that the source code could leave the object in at any particular time is a fairly difficult task. You’ll see this is true when you start to use Code Contracts because it will slow down your build times a bit (static analysis runs as a post-build activity). For this reason, Microsoft does suggest that you only run contract checking for a custom build configuration that you would create in addition to your normal Debug and Release builds (e.g., Checked).&lt;/p&gt;
&lt;p&gt;Due to the complexity involved in analyzing the source code, sometimes the static analyzer will ask for your help. It does this by writing informational messages to the Error Output window in Visual Studio. Sometimes it tells you exactly what it’s looking for in the form of suggesting appropriate &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Requires&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; or &lt;code class=&quot;csharp userType&quot;&gt;Contract&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Ensures&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; statements. Other times, it tells you that it’s assuming one thing or another (and suggests that you specify these assumptions for next time).&lt;/p&gt;
&lt;p&gt;Code Contracts has two other static methods on the Contract class called &lt;code class=&quot;csharp identifier&quot;&gt;Assume&lt;/code&gt; and &lt;code class=&quot;csharp identifier&quot;&gt;Assert&lt;/code&gt;. These are not pre- or post-conditions or even object invariants. In the case of &lt;code class=&quot;csharp identifier&quot;&gt;Assume&lt;/code&gt;, you’re informing the static analyzer that it should &lt;em&gt;&lt;b&gt;assume&lt;/b&gt;&lt;/em&gt; the condition specified for the argument to the method is true at that point in the execution of the code. It is merely a hint to the analyzer. On the other hand, &lt;code class=&quot;csharp identifier&quot;&gt;Assert&lt;/code&gt; tells the static analyzer that some condition &lt;em&gt;&lt;b&gt;must&lt;/b&gt;&lt;/em&gt; be true at that point in code execution in order for successful execution to continue. If at runtime (for builds where asserts are left in the code, such as your Checked build confiuration) an assertion is violated, your program will terminate.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;I&#39;ve touched upon many of the features of Microsoft&#39;s RiSE Code Contracts in this blog post along with a few code illustrations. If you find Code Contracts interesting and an acceptable way of practicing Design by Contract, I encourage you to check out the &lt;a href=&quot;http://research.microsoft.com/en-us/projects/contracts/&quot; target=&quot;_blank&quot;&gt;Code Contracts&lt;/a&gt; website and the corresponding &lt;a href=&quot;http://research.microsoft.com/en-us/projects/contracts/userdoc.pdf&quot; target=&quot;_blank&quot;&gt;documentation&lt;/a&gt;. Below, find the complete &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class re-written to include all Code Contracts. Except for having to hook the &lt;code class=&quot;csharp identifier&quot;&gt;ContractFailed&lt;/code&gt; event in a base class for all my unit tests in order to test that expected exceptions where thrown, the unit tests did not need to change in any other way, and so I have not repeated them here. Until next time, take care.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Text.RegularExpressions;

namespace DDDSportsStore.Domain
{
    [DebuggerDisplay(&quot;[Name: {Name}]&quot;)]
    public partial class Category
    {
        public static readonly Category None = new NullCategory();
        private string name;
        private Category parentCategory;
        private List&lt;Category&gt; subCategories;

        protected Category() 
        {
            subCategories = new List&lt;category&gt;();
        }

        public Category(string name) : this(name, None) { }

        private Category(string name, Category parent) : this()
        {
            Contract.Requires&amp;lt;InvalidCategoryNameException&amp;gt;(
                !string.IsNullOrWhiteSpace(name)
            );
            RequiresCategoryIsNotNull(parent);
            EnsureThisCategoryIsValid();

            this.name = SanitizeName(name);

            if (parentCategory == null)
                parentCategory = parent;
            else
                SetParentCategory(parent);
        }

        protected virtual int Id { get; set; }

        public virtual string Name
        {
            get { return name; }
            set 
            {
                RequiresValidName(value);
                name = SanitizeName(value); 
            }
        }

        public virtual Category Parent 
        {
            get { return parentCategory; }
            set 
            {
                RequiresCategoryIsNotNull(value);
                Contract.Assume(parentCategory != null);
                SetParentCategory(value); 
            }
        }

        public IReadOnlyCollection&lt;category&gt; Subcategories 
        {
            get 
            {
                Contract.Ensures(
                    Contract.ForAll(
                        Contract.Result&amp;lt;IReadOnlyCollection&amp;lt;Category&amp;gt;&amp;gt;(), 
                        c =&amp;gt; c != null &amp;amp;&amp;amp; c != Category.None
                    )
                );
                Contract.Assume(subCategories != null);

                return subCategories; 
            } 
        }

        /// &amp;lt;summary&amp;gt;
        ///     Creates a new &amp;lt;see cref=&quot;Category&quot;/&amp;gt; as a subcategory of the
        ///     current instance.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;name&quot;&amp;gt;The name of the new category.&amp;lt;/param&amp;gt;
        /// &amp;lt;exception cref=&quot;InvalidOperationException&quot;&amp;gt;
        ///     Thrown if the current instance is &amp;lt;see cref=&quot;Category.None&quot;/&amp;gt;
        /// &amp;lt;/exception&amp;gt;
        /// &amp;lt;exception cref=&quot;InvalidCategoryNameException&quot;&amp;gt;
        ///     Thrown if the &amp;lt;paramref name=&quot;name&quot;/&amp;gt; is &amp;lt;c&amp;gt;null&amp;lt;/c&amp;gt;, 
        ///     the empty string, or consists entirely of whitespace.
        /// &amp;lt;/exception&amp;gt;
        public virtual Category AddSubcategory(string name)
        {
            RequiresValidName(name);

            Category subCategory = new Category(name, this);
            AddSubcategory(subCategory);
            return subCategory;
        }

        private void AddSubcategory(Category c)
        {
            Contract.Requires&amp;lt;InvalidOperationException&amp;gt;(
                this != Category.None &amp;amp;&amp;amp; !(c == None || c == null)
            );
            Contract.Requires&amp;lt;InvalidOperationException&amp;gt;(
                !(
                      Contract.Exists&amp;lt;Category&amp;gt;(
                          subCategories, sc =&amp;gt; sc.Name == c.Name
                      )
                 )
            );

            this.subCategories.Add(c);
        }

        public bool Equals(Category other)
        {
            if ((object)other == null)
                return false;

            return this.ToString() == other.ToString();
        }

        private string SanitizeName(string proposedName)
        {
            Contract.Assume(!string.IsNullOrWhiteSpace(proposedName));
            return Regex.Replace(proposedName, @&quot;\s+&quot;, &quot; &quot;);
        }

        private void SetParentCategory(Category c)
        {
            RequiresCategoryIsNotNull(c);
            RequiresCategoryIsNotNull(parentCategory);
            Contract.Requires&amp;lt;InvalidOperationException&amp;gt;(
                c == Category.None || !this.HasDescendant(c), 
                &quot;Attempted to set the parent of this category to &quot; +
                &quot;one of this category&#39;s descendants.&quot;
            );

            parentCategory = c;
            if (parentCategory != None)
                parentCategory.AddSubcategory(this);
        }

        #region System.Object Overrides

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            Category c = obj as Category;
            if ((object)c == null)
                return false;

            return this.ToString() == c.ToString();
        }

        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }

        public override string ToString()
        {
            return Parent == Category.None ?
                Name : string.Concat(Parent.ToString(), &quot;/&quot;, Name);
        }

        #endregion

        #region Operator Overrides

        public static bool operator ==(Category a, Category b)
        {
            if (object.ReferenceEquals(a, b))
                return true;

            if ((object)a == null || (object)b == null)
                return false;

            return a.ToString() == b.ToString();
        }

        public static bool operator !=(Category a, Category b)
        {
            return !(a == b);
        }

        #endregion

        #region Code Contracts Helper Methods

        [ContractInvariantMethod]
        private void CategoryInvariants()
        {
            Contract.Invariant(Name != null);
            Contract.Invariant(Parent != null);
            Contract.Invariant(Subcategories != null);
        }

        [Pure]
        private bool HasDescendant(Category c)
        {
            RequiresCategoryIsNotNull(c);

            bool result = false;

            if (this == c)
                result = true;
            else if (c.Parent != None)
                result = this.HasDescendant(c.Parent);

            return result;
        }

        [ContractAbbreviator]
        private void EnsureThisCategoryIsValid()
        {
            Contract.Ensures(subCategories != null);
            Contract.Ensures(this == None || 
               !(string.IsNullOrWhiteSpace(name) || parentCategory == null));
        }

        [ContractAbbreviator]
        private void RequiresValidName(string name)
        {
            Contract.Requires&amp;lt;InvalidCategoryNameException&amp;gt;(
                this == None || !string.IsNullOrWhiteSpace(name)
            );
        }

        [ContractAbbreviator]
        private void RequiresCategoryIsNotNull(Category c)
        {
            Contract.Requires(c != null);
        }

        #endregion
    }
}
&lt;/pre&gt;  </description><link>http://discoveringcode.blogspot.com/2014/03/code-contracts-and-test-driven.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-3332449415849609554</guid><pubDate>Sun, 02 Mar 2014 03:19:00 +0000</pubDate><atom:updated>2014-05-28T08:49:19.167-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">ContinuousTests</category><category domain="http://www.blogger.com/atom/ns#">Mighty Moose</category><category domain="http://www.blogger.com/atom/ns#">TDD</category><category domain="http://www.blogger.com/atom/ns#">Unit Testing</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio</category><category domain="http://www.blogger.com/atom/ns#">VS2010</category><category domain="http://www.blogger.com/atom/ns#">VS2012</category><category domain="http://www.blogger.com/atom/ns#">VS2013</category><title>Mighty Moose and Contextual (a/k/a Hierarchical) TDD</title><description>&lt;h3&gt;Introduction&lt;/h3&gt; &lt;p&gt;In my last few blog posts, I introduced &lt;a href=&quot;http://continuoustests.com/&quot; target=&quot;_blank&quot;&gt;Mighty Moose&lt;/a&gt; and advanced TDD using nested, hierarchical context classes. If you have started using Mighty Moose and tried your hand at contextual &lt;abbr title=&quot;Test-Driven Development&quot;&gt;TDD&lt;/abbr&gt; (that’s my new name for it, it seems to fit), also known as hierarchical testing, you may have noticed a problem.&lt;/p&gt; &lt;h3&gt;The Test Runner Behind Mighty Moose&lt;/h3&gt; &lt;p&gt;Mighty Moose is compatible with the following testing frameworks:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;MS Test  &lt;li&gt;NUnit  &lt;li&gt;xUnit  &lt;li&gt;MbUnit  &lt;li&gt;SimpleTest  &lt;li&gt;MSpec&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;What may be surprising is that Mighty Moose does not necessarily use the native test runners for these frameworks. Mighty Moose has its own test runner called AutoTest.Net. From what I can tell, it appears that Mighty Moose implements a bunch of &lt;span style=&quot;font-variant: small-caps&quot;&gt;Adapter&lt;/span&gt;s that it uses to interact with the various testing frameworks it supports. The &lt;span style=&quot;font-variant: small-caps&quot;&gt;Adapter&lt;/span&gt;s don’t make use of the native test framework engines themselves. The &lt;span style=&quot;font-variant: small-caps&quot;&gt;Adapter&lt;/span&gt;s contain their own implementation. Unfortunately, it appears the execution of the &lt;span style=&quot;font-variant: small-caps&quot;&gt;Adapter&lt;/span&gt;s may not be 100% compatible with the test framework you’re using to write your tests.&lt;/p&gt; &lt;p&gt;So, imagine my surprise when I refactored all of my tests to use nested, hierarchical classes in order to constrain the boundaries of the various setups I would need (see my &lt;a title=&quot;Advanced Test-Driven Development&quot; href=&quot;http://discoveringcode.blogspot.com/2014/02/advanced-test-driven-development.html&quot; target=&quot;_blank&quot;&gt;last blog post on advanced TDD&lt;/a&gt;). Mighty Moose started reporting that all of my abstract base class tests were broken! (The actual error was that AutoTest.Net was unable to instantiate an abstract class. No, really?) I ran my tests in Visual Studio using the &lt;kbd&gt;&lt;abbr title=&quot;Control&quot;&gt;CTRL&lt;/abbr&gt;+R, T&lt;/kbd&gt; shortcut. This invokes the native MS Test test runner. I pop on over to the Test Explorer window, and what do I find? All of my tests pass. &lt;/p&gt; &lt;p&gt;On the one hand, having these &lt;span style=&quot;font-variant: small-caps&quot;&gt;Adapter&lt;/span&gt;s are great; you don’t have to learn a different testing framework &lt;abbr title=&quot;Application Programming Interface&quot;&gt;API&lt;/abbr&gt; in order to use Mighty Moose. On the other hand, my confidence in Mighty Moose is now lower than I would otherwise like because the output is not 100% compatible with the native test runner. How can I be sure that in all instances the tests are actually passing or failing (or even that AutoTest.Net is reporting the right result, for that matter)?&lt;/p&gt; &lt;h3&gt;AutoTest.Net is Broken&lt;/h3&gt; &lt;p&gt;So obviously, there’s a bug in AutoTest.Net, which is what Mighty Moose uses to run your tests; and it’s a pretty big one. AutoTest.Net recognizes that you have various test classes (a là the &lt;code class=&quot;csharp userType&quot;&gt;TestClassAttribute&lt;/code&gt; attribute). And so it tries to instantiate any class decorated with that attribute without checking if it’s valid to instantiate said class. But wait, it gets worse. It finds the nested inner class (which derives from the abstract base classes) and only runs the tests found in the concrete derived class (none of the inherited base class tests run with the derived class).&lt;/p&gt; &lt;p&gt;Is there a way around this? Well, yes, but you should be careful. The way to avoid this problem with Mighty Moose is to not make the base classes &lt;code class=&quot;csharp keyword&quot;&gt;abstract&lt;/code&gt;. However, this will lead to the base class tests executing for every class which derives from that base class. And this won’t be true just for AutoTest.Net, but also for MS Test. (I don’t know about NUnit and xUnit since I’ve never used them.)&lt;/p&gt; &lt;p&gt;So what, you say? That’s ok, as long as Mighty Moose works. Well, consider this. You have 100 tests in your base class, and 100 tests in a derived class. How many tests will get executed? 300 tests. 100 for the base class, 100 for the derived class’s inherited base class methods, and 100 tests contained in the derived class itself. OK, so you don’t have 100 tests in a single test class. However, in a production system, you may have upwards of 5000 tests. (And that’s just when they’re running once!) So now multiply a good chunk of those tests and pretty soon you’re pushing 15000 tests. (And keep in mind that that&#39;s assuming that you&#39;re only nesting one level. If you nest two levels deep, now you have an explosion of the possible number of tests that will execute.) It’s wasteful of time and computing resources.&lt;/p&gt; &lt;h3&gt;Conclusion&lt;/h3&gt; &lt;p&gt;If you have a really small project and don’t mind tests being executed more than once, by all means, go for it. But it’s really not a good of a solution. AutoTest.Net should take into account whether or not a class is abstract and ignore it if it’s marked with the &lt;code class=&quot;csharp userType&quot;&gt;TestClassAttribute&lt;/code&gt; attribute. Furthermore, AutoTest.Net should look to see if a test class is a derived class and ensure that the derived class’s base class hierarchy is properly instantiated and that all inherited members are executed as part of the derived class.&lt;/p&gt; &lt;p&gt;Hopefully the authors of AutoTest.Net will fix this bug soon. Until then, if you have a small project, go for it. Otherwise, it’s probably best not to use Mighty Moose. If you really need a continuous test runner, check out &lt;a href=&quot;http://www.ncrunch.net/&quot; target=&quot;_blank&quot;&gt;NCrunch&lt;/a&gt;. I’ve been using it at work and I really like that continuous test runner, too. (Oh, and as far as the cost for NCrunch, while I don’t want to pay for it for personal use at this time, it’s really not that expensive; and if things were different as far as the level of development I do personally, I’d definitely pay for it.)&lt;abbr title=&quot;Behavioral Driven Design&quot;&gt;&lt;abbr&gt;&lt;/p&gt;  </description><link>http://discoveringcode.blogspot.com/2014/03/mighty-moose-and-contextual-tdd.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-4032311661841832724</guid><pubDate>Wed, 26 Feb 2014 02:29:00 +0000</pubDate><atom:updated>2014-03-07T18:11:26.525-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">C#</category><category domain="http://www.blogger.com/atom/ns#">TDD</category><category domain="http://www.blogger.com/atom/ns#">Unit Testing</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio</category><category domain="http://www.blogger.com/atom/ns#">VS2012</category><category domain="http://www.blogger.com/atom/ns#">VS2013</category><title>Advanced Test-Driven Development</title><description>&lt;h3&gt;Introduction&lt;/h3&gt;&lt;p&gt;At my current place of employment, I was recently introduced to the “Uncle Bob” series of videos, more properly titled &lt;a href=&quot;http://cleancoders.com/&quot; target=&quot;_blank&quot;&gt;Clean Coders&lt;/a&gt;. In episodes 19 through 23, Robert Martin begins a series on advanced test-driven development.&lt;/p&gt;&lt;p&gt;One of the things that was mentioned in that series is about how your tests should be treated no differently than production code. That means that your tests should also follow the SOLID principles: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation/Separation, and the Dependency Inversion principles (see the videos for clarifications surrounding applying these principles in relation to unit tests, however). Also, another good coding principle is DRY—don’t repeat yourself.&lt;/p&gt;&lt;h3&gt;Traditional TDD&lt;/h3&gt;&lt;p&gt;In .NET, I use the standard MS Test test framework. I know, it’s not great, and I should use NUnit or xUnit, right? But really, I don’t like NUnit (or xUnit). Actually, MS Test isn’t great either (too many attributes), but I like it better than NUnit or xUnit. Feel free to disagree with me. I&#39;m not writing this blog post to argue about the best testing framework. See &lt;a href=&quot;http://osherove.com/blog/&quot; target=&quot;_blank&quot;&gt;Roy Osherove&#39;s blog&lt;/a&gt; for a more in-depth discussion regarding the merits (or lack thereof) of various testing frameworks. (Hint: he has a very low opinion of MS Test—but that&#39;s OK, he&#39;s entitled to his opinion.)&lt;/p&gt;&lt;p&gt;Anyway, the point is, the MS Test framework does not support the notion of setup &lt;i&gt;contexts&lt;/i&gt; (nor does NUnit or xUnit, for that matter). Yes, yes, there is a &lt;code class=&quot;csharp userType&quot;&gt;TestInitializeAttribute&lt;/code&gt; that you can adorn a method with to provide a test class with a setup method (and NUnit’s corresponding &lt;code class=&quot;csharp userType&quot;&gt;SetupAttribute&lt;/code&gt; attribute), but that’s not what I’m talking about.&lt;/p&gt;&lt;p&gt;Usually when we create tests, we create one test class for each class under test (CUT). Invariably, one of two things can take place when it comes to common data needed for tests (though, maybe not needed for each test):&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Create private test class fields and initialize them in the setup method adorned with the &lt;code class=&quot;csharp userType&quot;&gt;TestInitializeAttribute&lt;/code&gt; attribute&lt;br /&gt;
&lt;li&gt;Just re-create all test setup information within each test method in the Arrange section of the test&lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/ol&gt;&lt;p&gt;I usually follow number 2, but I was always bothered by it. After all, it violates &lt;abbr title=&quot;Don&#39;t Repeat Yourself&quot;&gt;DRY&lt;/abbr&gt;. I just hate it. But option 1 is no better! You end up instantiating a lot of fields and data for &lt;em&gt;each and every&lt;/em&gt; test method in the class, regardless of whether the currently executing test needs &lt;em&gt;all&lt;/em&gt; of the data. This can be terribly inefficient, especially if your tests involve creating expensive objects.&lt;/p&gt;&lt;p&gt;So how can we get small setup methods &lt;em&gt;and&lt;/em&gt; small tests?&lt;/p&gt;&lt;h3&gt;Advanced &lt;abbr title=&quot;Test-Driven Development&quot;&gt;TDD&lt;/abbr&gt; with Context Classes&lt;/h3&gt;&lt;p&gt;The solution to this problem is recognizing that there are various &lt;i&gt;contexts&lt;/i&gt; under which your tests are running. Some contexts may be completely separate from others, while other contexts need to use data that also appears in a different context. The real trick is determining how to arrange the contexts so that you don’t violate the &lt;abbr title=&quot;Don&#39;t Repeat Yourself&quot;&gt;DRY&lt;/abbr&gt; principle and are able to promote re-use in order to keep setup methods small, all the while keeping your tests really small. I got the idea for this concept directly from the Clean Coders video series. (Please, if you hate this idea, don’t misconstrue the fact that because I got this idea from the Clean Coders video series that the series must be junk. It’s not. I just might have a bad idea here. I don’t think so; but hey, I’m entitled to my opinion. :) Of course, I’m always interested in feedback and open discussion.)&lt;/p&gt;&lt;p&gt;I first tried this concept out on some code at my place of employment. But of course, I can’t show you that code. So, the rest of this article is going to demonstrate this concept using a class called &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt;. While this class is really simple, and you may disagree with my implementation, this is not about the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class implementation. It’s about how you can structure your tests to keep them SOLID, DRY, and focused.&lt;/p&gt;&lt;p&gt;&lt;b&gt;It should be noted that the method outlined here may not work on Visual Studio 2010. It will work with Visual Studio 2012 and 2013, however. If anyone finds that the methods outlined here work on Visual Studio 2010, too, I’ll update this post accordingly.&lt;/b&gt;&lt;/p&gt;&lt;h3&gt;Introducing the Category Class&lt;/h3&gt;&lt;p&gt;In order to demonstrate the concept, I’m going to build up the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class incrementally, practicing &lt;abbr title=&quot;Test-Driven Development&quot;&gt;TDD&lt;/abbr&gt; as I go along. So, without further delay, let’s get started.&lt;/p&gt;&lt;p&gt;First, I want to outline some invariants of the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A category name cannot be null or the empty string and it cannot be a whitespace only string. If any of these conditions are true, throw an &lt;code class=&quot;csharp userType&quot;&gt;InvalidCategoryNameException&lt;/code&gt; exception.&lt;br /&gt;
&lt;li&gt;A category can have a single parent. The parent cannot be null—the parent property must always return an object.&lt;br /&gt;
&lt;li&gt;A category can have sub-categories. You cannot add a &lt;code class=&quot;csharp keyword&quot;&gt;null&lt;/code&gt; sub-category. Adding a sub-category must not result in a cycle, e.g. A -&amp;gt; B -&amp;gt; C -&amp;gt; A, where the first and last category A are the same exact category object.&lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;As I go along, I’ll introduce other business rules and/or requirements. So, what test should I write first? Well, I think I&#39;ll write a test to make sure that I can create a &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DDDSportsStore.Domain.Tests
{
    [TestClass]
    public class CategoryTests
    {
        [TestMethod]
        public void Can_create_a_category()
        {
            Category c = new Category();
        }
    }
}
&lt;/pre&gt;&lt;p&gt;Now, of course this test won’t compile because I haven&#39;t yet written the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class. So I&#39;m going to go ahead and create that now.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;using System;
using System.Collections.Generic;
using System.Linq;

namespace DDDSportsStore.Domain
{
    public class Category
    {
    
    }
}
&lt;/pre&gt;&lt;p&gt;There, that&#39;s all that&#39;s needed in order to make the test above pass. If you haven’t guessed, this category class is implementing a product category that you might find as part of an online e-commerce catalog. I’m trying to practice domain-driven design (DDD) with an example used in the &lt;a href=&quot;http://www.amazon.com/Pro-ASP-NET-MVC-Adam-Freeman/dp/1430242361&quot; target=&quot;_blank&quot;&gt;Pro ASP.NET MVC4&lt;/a&gt; book published by APress. Enough about DDD; that’s another story and another blog post (or 10).&lt;/p&gt;&lt;p&gt;Now that I have a passing test and I can indeed create a category object, I&#39;m going to get rid of that first test and replace it with a test that ensures that I cannot create a category with a null name. It would be really hard in a blog format to show the incremental building up of the category class in order to satisfy the test (see episode 24 of Clean Coders on the Transformation Priority Premise), so I&#39;m just going to show you the final implementation of this particular constructor that will pass the test.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;[TestMethod]
[ExpectedException(typeof(InvalidCategoryNameException))]
public void Cannot_create_a_Category_with_a_null_string_for_a_name()
{
    Category c = new Category(null);
}
&lt;/pre&gt;&lt;p&gt;Pay no attention to the &lt;code class=&quot;csharp userType&quot;&gt;ExpectedExceptionAttribute&lt;/code&gt; attribute. I&#39;ll be replacing that soon enough. Just know that that attribute is a real code smell and could be causing your tests to pass when they shouldn&#39;t be. OK, with that said, of course this test should also fail because I have no constructor that takes a parameter. I&#39;m going to implement that constructor now.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;public class Category
{
    private string name;

    public Category(string name)
    {
        if (name == null)
            throw new InvalidCategoryNameException();

        Name = name;
    }

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}
&lt;/pre&gt;&lt;p&gt;Ok, the next part of the first invariant is that the string cannot be empty. I&#39;ll write another test to test this invariant.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;[TestMethod]
[ExpectedException(typeof(InvalidCategoryNameException))]
public void Cannot_create_a_Category_with_an_empty_string_for_a_name()
{
    Category c = new Category(string.Empty);
}
&lt;/pre&gt;&lt;p&gt;Again of course, this test fails because in the constructor, I only checked to see if &lt;code class=&quot;csharp identifier&quot;&gt;name&lt;/code&gt; is &lt;code class=&quot;csharp keyword&quot;&gt;null&lt;/code&gt;. So now I&#39;ll update the constructor to make this test pass.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;public Category(string name)
{
    if (string.IsNullOrEmpty(name))
        throw new InvalidCategoryNameException();

    Name = name;
}
&lt;/pre&gt;&lt;p&gt;There, that should be enough to make the above test pass. The final invariant regarding a category&#39;s name is that it cannot consist entirely of white space. The test for this invariant will closely resemble the other two tests. So I think it&#39;s time to refactor these tests to remove code duplication and use &lt;i&gt;composable assertions&lt;/i&gt; (again, see the Clean Coders videos). The first thing you&#39;ll notice about the tests is that I attempt to assign the newly created category to a variable named &lt;code class=&quot;csharp identifier&quot;&gt;c&lt;/code&gt;. This isn&#39;t strictly necessary—I merely need to call the constructor with an invalid category name and the execption should be thrown. So I&#39;ll eliminate that duplication in this refactoring. I&#39;ll also create a helper method to carry out the assertion. Finally, I&#39;m testing 3 components of a single &lt;i&gt;logical&lt;/i&gt; invariant concerning the name of a category. So I could really check all 3 components in a single test and I would not be violating the &quot;single assertion per test&quot; rule. The new tests are shown below.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;[TestClass]
public class CategoryTests
{
    [TestMethod]
    public void Cannot_create_a_Category_with_an_invalid_name()
    {
        AssertCannotCreateCategoryWithName(null);
        AssertCannotCreateCategoryWithName(string.Empty);
        AssertCannotCreateCategoryWithName(&quot;\n&quot;);
    }

    public void AssertCannotCreateCategoryWithName(string name)
    {
        ExceptionAssert.Throws&amp;lt;InvalidCategoryNameException&amp;gt;(
            () =&amp;gt; new Category(name)
        );
    }
}

public static class ExceptionAssert
{
    public static void Throws&amp;lt;T&amp;gt;(Action action) where T : Exception
    {
        try
        {
            action();
            Assert.Fail(
                &quot;Expected &#39;{0}&#39; to be thrown but no exception was thrown.&quot;,
                typeof(T).FullName
            );
        }
        catch (T)
        {
            return;
        }
        catch (AssertFailedException)
        {
            throw;
        }
        catch (Exception e)
        {
            Assert.Fail(&quot;Expected &#39;{0}&#39; to be thrown, but &#39;{1}&#39; was thrown instead.&quot;, 
                        typeof(T).FullName,
                        e.GetType().FullName
            );
        }
    }
}
&lt;/pre&gt;&lt;p&gt;Remember I told you that I&#39;d be taking care of that &lt;code class=&quot;csharp userType&quot;&gt;ExpectedExceptionAttribute&lt;/code&gt; attribute. This is one instance where NUnit and xUnit really has something on MS Test (syntactically), namely the &lt;code&gt;&lt;span class=&quot;csharp userType&quot;&gt;Assert&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;Throws&lt;/span&gt;&amp;lt;&lt;span class=&quot;csharp typeParam&quot;&gt;T&lt;/span&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;csharp identifier&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;csharp literal&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; method. I hate the &lt;code class=&quot;csharp userType&quot;&gt;ExpectedExceptionAttribute&lt;/code&gt; now because it messes with the Arrange, Act, and Assert pattern of TDD. Plus, it can mask other problems with your code. So instead, I get rid of the attribute and use a custom static class modeled after the &lt;code class=&quot;csharp userType&quot;&gt;Assert&lt;/code&gt; and &lt;code class=&quot;csharp userType&quot;&gt;CollectionAssert&lt;/code&gt; classes in the standard MS Test test framework. So, in my test above, I added a call to my new assertion method trying to create a category with a whitespace only name. The constructor currently only looks for &lt;code class=&quot;csharp keyword&quot;&gt;null&lt;/code&gt; and the empty string, so this test will fail. It&#39;s a simple matter of updating the guard clause in the constructor to make this test pass:&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;public Category(string name)
{
    if (string.IsNullOrWhiteSpace(name))
        throw new InvalidCategoryNameException();

    Name = name;
}
&lt;/pre&gt;&lt;p&gt;That&#39;s it. The test above should now pass and I&#39;ve ensured that the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class is enforcing all of the invariants on its name. There are a few more tests I need to write before I get to the concept of creating context classes. I&#39;m going to skip the step-by-step, but I will show you the final tests that I created to enforce some of the category&#39;s &lt;code class=&quot;csharp identifier&quot;&gt;Subcategory&lt;/code&gt; property invariants (the ones that I don&#39;t enforce will be enforced later, as I continue to develop this class). I additionally included a test that ensures that any whitespace that appears in a category name is replaced with a single space character. I&#39;ll also show you the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class as it stands after having written the tests.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;[TestClass]
public class CategoryTests
{
    private string PARENT;
    private Category parent;

    [TestInitialize]
    public void CategoryTestsSetup()
    {
        // It&#39;s important to initialize test state here, because if a test 
        // (in-)advertently changes the variable&#39;s state, it could affect 
        // other tests.
        PARENT = &quot;Parent&quot;;
        parent = new Category(PARENT);
    }

    // ...

    // Our other tests we wrote previously are up above.

    [TestMethod]
    public void
    A_category_name_is_sanitized_to_contain_only_1_space_character_between_words()
    {
        AssertCategoryNameWhitespaceIsCollapsed(
            &quot;A  category  with  extraneous  whitespace&quot;, 
            &quot;A category with extraneous whitespace&quot;
        );
        AssertCategoryNameWhitespaceIsCollapsed(
            &quot;A\r\ncategory\twith\vother\fwhitespace characters&quot;, 
            &quot;A category with other whitespace characters&quot;
        );
        AssertCategoryNameWhitespaceIsCollapsed(
            &quot;This category name is ok&quot;, 
            &quot;This category name is ok&quot;
        );
    }

    private void
    AssertCategoryNameWhitespaceIsCollapsed(string name, string expectedName)
    {
        Assert.AreEqual(new Category(name).Name, expectedName);
    }

    [TestMethod]
    public void A_top_level_category_returns_its_name_when_ToString_is_called()
    {
        Assert.AreEqual(PARENT, parent.ToString());
    }
}
&lt;/pre&gt;&lt;p&gt;Now for the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class as it stands now.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;public class Category
{
    public static readonly Category None = new NullCategory();
    private string name;
    private List&amp;lt;Category&amp;gt; subCategories;

    protected Category()
    {
        subCategories = new List&amp;lt;Category&amp;gt;();
    }

    public Category(string name) : this()
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new InvalidCategoryNameException();

        this.name = SanitizeName(name);
    }

    public virtual string Name
    {
        get { return name; }
        set { name = SanitizeName(value); }
    }

    public IReadOnlyCollection&amp;lt;Category&amp;gt; Subcategories 
    {
        get { return subCategories.AsReadOnly(); }
    }

    public virtual void AddSubcategory(Category c) 
    {
        if (this == Category.None)
            throw new InvalidOperationException(
                &quot;Unable to add a subcategory to the &#39;None&#39; category.&quot;
            );

        if (c == null || c == Category.None)
            throw new InvalidSubcategoryException();

        if (subCategories.Any(sc =&amp;gt; sc.Name == c.Name))
            throw new DuplicateSubcategoryException();

        subCategories.Add(c);
    }

    private string SanitizeName(string proposedName)
    {
        return Regex.Replace(proposedName, @&quot;\s+&quot;, &quot; &quot;);
    }

    #region System.Object overrides

    public override string ToString()
    {
        return Name;
    }

    #endregion

    /// &amp;lt;summary&amp;gt;
    /// This class represents an implementation of the Null Object pattern 
    /// (a/k/a Special Case pattern) and is meant to be used anywhere
    /// where you might otherwise return null.
    /// &amp;lt;/summary&amp;gt;
    private sealed class NullCategory : Category
    {
        public override Name
        {
            get { return string.Empty; }
            set { }
        }
    }
}
&lt;/pre&gt;&lt;p&gt;So ordinarily, I would have written two unit tests for each of the invalid subcategory conditions asserted in the tests above; but instead, I chose to use a custom assertion method and perform one logical assert. You can also see that I have two new private member variables in the test class which are initialized before each test. But only two of the three tests need these private members. Now, ordinarily, this isn&#39;t all that bad and I wouldn&#39;t bother with factoring out a context class. But what if the tests were much more involved in the setups that are needed? For instance, at my place of employment, I recently had 7 tests, 2 of which required the same 20 or 30 lines of setup code, the other 5 of which required at least another 10 common lines of setup code between them. All of this code would have been repeated in the methods requiring the code. Or worse, all 50 or so lines would have been in a single setup method, with all of that setup occurring before each test, even if a particular test didn&#39;t require all that was setup.&lt;/p&gt;&lt;p&gt;You can also see more fleshed out versions of the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class. I also created a nested, private category class that is an implementation of the Null Object (a/k/a &lt;a title=&quot;Special Case Pattern&quot; href=&quot;http://martinfowler.com/eaaCatalog/specialCase.html&quot; target=&quot;_blank&quot;&gt;Special Case&lt;/a&gt;) Pattern to represent the null category. Implementing this pattern allows programmers to not have to check for &lt;code class=&quot;csharp keyword&quot;&gt;null&lt;/code&gt; all the time before accessing properties and fields of objects. Because it&#39;s a nested, private class, it cannot be instantiated by anything except the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class. This allows the &lt;code class=&quot;csharp userType&quot;&gt;NullCategory&lt;/code&gt; to be exposed as a public static field on the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class as a &lt;span style=&quot;font-variant: small-caps&quot;&gt;Singleton&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;Now, I have not addressed setting the parent category of a category. By default, a category&#39;s parent is set to the &lt;span style=&quot;font-variant: small-caps&quot;&gt;Singleton&lt;/span&gt; &lt;code class=&quot;csharp userType&quot;&gt;NullCategory&lt;/code&gt;. But before I tackle that, I want to override the &lt;code&gt;&lt;span class=&quot;csharp identifier&quot;&gt;System&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp userType&quot;&gt;Object&lt;/span&gt;.&lt;/span&gt;Equals&lt;/span&gt;&lt;/code&gt; method. And when I override this method, I also need to override the &lt;code&gt;&lt;span class=&quot;csharp identifier&quot;&gt;System&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp userType&quot;&gt;Object&lt;/span&gt;.&lt;/span&gt;GetHashCode&lt;/span&gt;&lt;/code&gt; method and the equality and inequality operators.&lt;/p&gt;&lt;h3&gt;The Equality Context Test Class&lt;/h3&gt;&lt;p&gt;My motivation for overriding the &lt;code class=&quot;csharp identifier&quot;&gt;Equals&lt;/code&gt; method and the (in)equality operators is for easy comparison of two categories in order to determine whether or not they are the same. Also, the implementation I have in mind will prevent two subcategories with the same name being added to the same parent. I think you&#39;ll see how I accomplish this very easily without much further explanation, so let&#39;s hop to it.&lt;/p&gt;&lt;p&gt;Of course, before I can write any code to implement equality testing, I&#39;ll need to write the tests. In order to test equality, I&#39;ll need two categories. But I&#39;ll only need them for this set of tests. I don&#39;t want to drag these categories around for each and every other test I might have surrounding categories. So, I think it&#39;s best at this point to create a context class for testing category equality. (Again, this example is very simplistic and contrived, and probably not worthy of this level of breakdown; but keep in mind the real-life scenario I mentioned above with 50 lines of code needed by some of the various tests throughout a single &lt;abbr title=&quot;Class Under Test&quot;&gt;CUT&lt;/abbr&gt;. The benefits are potentially huge: smaller test setups; faster tests; smaller, easier to read, and maintainable tests.)&lt;/p&gt;&lt;p&gt;Ok, so below are the tests for the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class I&#39;ve been working with (somewhat abbreviated), showing the new context class. I&#39;ll also show you my implementation of the equality method and operators in the abstract category class.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;[TestClass]
public abstract class CategoryTests
{
    private string PARENT;
    private Category parent;

    [TestInitialize]
    public void CategoryTestsSetup()
    {
        // It&#39;s important to initialize test state here, because if a test 
        // (in-)advertently changes the variable&#39;s state, it could affect 
        // other tests.
        PARENT = &quot;Parent&quot;;
        parent = new Category(PARENT);
    }

    // ...

    // Our other tests we wrote previously are up above.
    [TestClass]
    public class CategoryEqualityContext : CategoryTests
    {
        Category categoryA;
        Category categoryB;

        [TestInitialize]
        public void CategoryEqualityContextSetup()
        {
            categoryA = new Category(&quot;A&quot;);
            categoryB = new Category(&quot;B&quot;);
        }

        // This method was moved from the outer context because ToString is 
        // used in determining equality, so it makes sense to move it to this
        // context.
        [TestMethod]
        public void A_top_level_category_returns_its_name_when_ToString_is_called()
        {
            Assert.AreEqual(&quot;A&quot;, categoryA.ToString());
        }

        [TestMethod]
        public void
        Can_determine_whether_or_not_two_categories_are_equal_to_one_another()
        {
            Assert.AreEqual(categoryA, categoryA);
            Assert.IsTrue(categoryA.Equals(categoryA));
            Assert.IsTrue(((object)catgeoryA).Equals((object)categoryA));
            Assert.IsTrue(categoryA.Equals(new Category(&quot;A&quot;)));
        }

        [TestMethod]
        public void
        Can_use_the_equality_operator_to_determine_whether_two_categories_are_equal_to_one_another()
        {
            Category c = new Category(&quot;A&quot;);
            Assert.IsTrue(c == categoryA);
        }

        [TestMethod]
        public void
        Can_use_the_inequality_operator_to_determine_whether_two_categories_are_not_equal_to_one_another()
        {
            Assert.IsTrue(categoryA != categoryB);
        }
    }
}
&lt;/pre&gt;&lt;p&gt;So let&#39;s go over these tests before we get to the implementation in &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt;. The way MS Test works with nested classes like this is that the outer class is instantiated first, then the inner class, just like any other nested class structure in C#. But in addition to that, the outer class&#39;s method marked with the &lt;code class=&quot;csharp userType&quot;&gt;TestInitializeAttribute&lt;/code&gt; attribute is also run prior to the nested class&#39;s method marked with the same attribute. If the nested class doesn&#39;t define such a method, the outer class&#39;s method still runs before each and every test in the inner class. So what does that mean for these tests? Well, in this instance, it means that the &lt;code class=&quot;csharp identifier&quot;&gt;PARENT&lt;/code&gt; string and &lt;code class=&quot;csharp identifier&quot;&gt;parent&lt;/code&gt; category are carried along into the &lt;code class=&quot;csharp userType&quot;&gt;CategoryEqualityContext&lt;/code&gt;. While in this trivial example this isn&#39;t a big deal, this is not ideal in a situation where you have a lot of setups occurring in the outer class which the inner class methods don&#39;t need. Actually, we&#39;re going to refactor our tests to remove the outer class setups in just a bit. But I wanted to show you this so I could explain how the nested context classes work.&lt;/p&gt;&lt;p&gt;Secondly, notice that I&#39;ve made the &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; class &lt;code class=&quot;csharp keyword&quot;&gt;abstract&lt;/code&gt;. This is very important. The &lt;code class=&quot;csharp userType&quot;&gt;CategoryEqualityContext&lt;/code&gt; class inherits from the &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; class. This also means that it inherits all the methods of its base class. So, let&#39;s assume that the &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; class isn&#39;t abstract and follow the flow of execution. The &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; class is marked with the &lt;code class=&quot;csharp userType&quot;&gt;TestClassAttribute&lt;/code&gt; attribute, so MS Test looks for all the test methods in that class and executes them. Then MS Test sees a public, nested class called &lt;code class=&quot;csharp userType&quot;&gt;CategoryEqualityContext&lt;/code&gt; and finds all of its test methods and executes them. But because the &lt;code class=&quot;csharp userType&quot;&gt;CategoryEqualityContext&lt;/code&gt; class inherits from &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; class, the tests in &lt;code class=&quot;csharp userType&quot;&gt;CatgoryTests&lt;/code&gt; run again as part of &lt;code class=&quot;csharp userType&quot;&gt;CategoryEqualityContext&lt;/code&gt;. Now you can see why it&#39;s very important to make the &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; class &lt;code class=&quot;csharp keyword&quot;&gt;abstract&lt;/code&gt;. The general rule of thumb, then, is the following:  &lt;blockquote&gt;&lt;b&gt;If you have nested context test classes, make all test classes &lt;code class=&quot;csharp keyword&quot;&gt;abstract&lt;/code&gt; except the inner-most context class; leave that class concrete. This ensures that your tests execute only once.&lt;/b&gt;&lt;/blockquote&gt;There is one more caveat to using nested context classes for scoping your test setups; I&#39;ll get to that later in this blog post.  &lt;p&gt;OK, now that you know how nested context classes work, I&#39;m going to show you how I implemented equality checking in the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class to make the above tests pass.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;public class Category
{
    // ...
    // All other methods previously shown are ansumed to exist above.

    public bool Equals(Category other)
    {
        if ((object)other == null)
            return false;

        return this.ToString() == other.ToString();
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        Category c = obj as Category;
        if ((object)c == nul)
            return false;

        return this.ToString() == c.ToString();
    }

    public override int GetHashCode()
    {
        return this.ToString().GetHashCode();
    }

    public static bool operator ==(Category a, Category b)
    {
        if (object.ReferenceEquals(a, b))
            return true;

        if ((object)a == null || (object)b == null)
            return false;

        return a.ToString() == b.ToString();
    }

    public static bool operator !=(Categoriy a, Category b)
    {
        return !(a == b);
    }
}
&lt;/pre&gt;&lt;p&gt;So there&#39;s not too much to be said about my implementation above. It pretty much follows the standard suggested implementation. Equality merely consists of checking whether or not 1) the acutal objects are the same object reference, or 2) the &lt;code class=&quot;csharp identifier&quot;&gt;ToString&lt;/code&gt; method returns the same string. The only thing to note is that I have no concept of a parent category yet. When I finally add the ability to set a parent category, this will change my implementation of &lt;code class=&quot;csharp identifier&quot;&gt;ToString&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;Even More Nested Context Classes&lt;/h3&gt;&lt;p&gt;So now you have an idea of how to use nested context classes in order to organize your test setups. While the simple example above gave you an at a glance view, let&#39;s make this a bit more concrete by implementing the rest of the functionality. To do that, let me tell you some other rules surrounding categories. First, you cannot have two subcategories of a single category that have the same name. You cannot add the &lt;code class=&quot;csharp identifier&quot;&gt;None&lt;/code&gt; category as a subcategory (we already covered that). A category&#39;s parent cannot be &lt;code class=&quot;csharp keyword&quot;&gt;null&lt;/code&gt;, but it can be &lt;code class=&quot;csharp identifier&quot;&gt;None&lt;/code&gt;, meaning it&#39;s a &quot;top-level&quot; category. In order to make checking for duplicate subcategories really quick and easy, we&#39;re going to change the implementation of &lt;code class=&quot;csharp identifier&quot;&gt;ToString&lt;/code&gt;. The implementation I have in mind will afford a couple of benefits:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Allows very quick determination of whether or not a category can be added as a subcategory&lt;br /&gt;
&lt;li&gt;Allows very quick determination of whether or not two categories are the same by checking their path&lt;br /&gt;
&lt;li&gt;Disallows cycles, e.g. A -&amp;gt; B -&amp;gt; C -&amp;gt; A does not form a cycle. &lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;A note about the cycle point above: we&#39;ll have a method that ensures that the new parent isn&#39;t already a descendant of the current category. The method that&#39;s used is recursive. Technically, if you have extremely many levels of nested categories (e.g. A -&amp;gt; B -&amp;gt; C -&amp;gt; D -&amp;gt; ... etc.), it&#39;s possible to blow out the stack. But generally speaking, a product catalog for instance, will usually only have 2 - 5 levels of nesting; and that&#39;s being generous on the high-end. I guess a way to avoid a potential &lt;code class=&quot;csharp userType&quot;&gt;StackOverflowException&lt;/code&gt; would be to limit the allowable amount of nesting. But given the general use-case for this object—and mostly because this is just an example for this blog article and not something I&#39;d use in production code—I&#39;m not inclined to do so. I&#39;ll leave it to you as an exercise. Also, my current implementation of &lt;code class=&quot;csharp identifier&quot;&gt;AddSubcategory&lt;/code&gt; will need to change. We&#39;ll also add a new constructor to the class.&lt;/p&gt;&lt;p&gt;Again, even though I told you what I&#39;m going to implement in the class, all of the implementation was based on the tests that I wrote. So here are the new (and final) set of tests.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;[TestClass]
public class CategoryTests
{
    // ...
    // All the other tests in the outer context are above.
    // The original setup method was moved to another nested 
    // context to be shown below, along with the test that
    // required the setups.

    [TestClass]
    public abstract class CategoryEqualityContext : CategoryTests
    {
        // ...
        // Nothing has changed in this test class from above.
    }

    [TestClass]
    public abstract class ParentCategoryContext : CategoryTests
    {
        // These variables and the setup method were moved from
        // the outer CategoryTests context class
        private string PARENT;
        private Category parent;

        [TestInitialize]
        public void ParentCategoryContextSetup()
        {
            PARENT = &quot;Parent&quot;;
            parent = new Category(PARENT);
        }

        [TestMethod]
        public void Can_add_a_subcategory_to_a_category()
        {
            parent.AddSubcategory(&quot;subcategory&quot;);
            Assert.AreEqual(1, parent.Subcategories.Count);
        }

        [TestMethod]
        public void Cannot_add_a_duplicate_subcategory_to_a_category()
        {
            parent.AddSubcategory(&quot;subcategory&quot;);
            ExceptionAssert.Throws&amp;lt;DuplicateSubcategoryException&amp;gt;(
                () =&amp;gt; parent.AddSubcategory(&quot;subcategory&quot;)
            );
        }

        [TestMethod]
        public void A_top_level_category_returns_its_name_when_ToString_is_called()
        {
            Assert.AreEqual(PARENT, parent.ToString());
        }

        [TestClass]
        public class ChildCategoryContext : ParentCategoryContext
        {
            private string CHILD;
            privte Category child;

            [TestInitialize]
            public void ChildCategoryContextSetup()
            {
                CHILD = &quot;Child&quot;;
                child = parent.AddSubcategory(CHILD);
            }
    
            [TestMethod]
            public void
            A_subcategory_returns_its_parents_name_with_a_path_separator_and_its_own_name_when_ToString_is_called()
            {
                Assert.IsTrue(string.Concat(PARENT, &quot;/&quot;, CHILD) == child.ToString(), 
                    string.Format(&quot;Expected &#39;{0}/{1}&#39; but got &#39;{2}&#39;&quot;, PARENT, CHILD, child.ToString()
                );
            }

            [TestMethod]
            public void
            Cannot_set_category_parent_if_new_parent_is_a_descendant_of_the_category()
            {
                Category grandchild = child.AddSubcategory(&quot;Grandchild&quot;);

                // Attempt parent/child/grandchild/parent where &#39;parent&#39; 
                // at both the head and tail of the list are the same object.
                ExceptionAssert.Throws&amp;lt;invalidoperationexception&amp;gt;(() =&amp;gt; parent.Parent = grandchild);
            }
        }
    }
}
&lt;/pre&gt;&lt;p&gt;After implementing the code that ought to make these tests pass, one of the tests above will actually fail. Can you spot which test will fail? Don&#39;t try too long to find it. It&#39;s really subtle, and is one of a small list of cons when using this style of testing. The test that will fail is &lt;code class=&quot;csharp identifier&quot;&gt;A_top_level_category_returns_its_name_when_ToString_is_called&lt;span class=&quot;csharp literal&quot;&gt;()&lt;/span&gt;&lt;/code&gt;. But why should that fail? It looks just fine. Again, it&#39;s really subtle. The good news is that the test fails and doesn&#39;t produce a false positive (e.g. a passing test that should fail). Remember the rule I stated above concerning derived test classes. The most derived test class should be concrete while all lesser derived test classes and the base class must be abstract. In the concrete test class in the &lt;code class=&quot;csharp identifier&quot;&gt;ChildCategoryContextSetup&lt;span class=&quot;csharp literal&quot;&gt;()&lt;/span&gt;&lt;/code&gt; method, I call &lt;code class=&quot;csharp identifier&quot;&gt;parent&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;AddSubcategory&lt;span class=&quot;csharp literal&quot;&gt;(&lt;/span&gt;CHILD&lt;span class=&quot;csharp literal&quot;&gt;);&lt;/span&gt;&lt;/code&gt;. So a new subcategory is added to the &lt;code class=&quot;csharp identifier&quot;&gt;parent&lt;/code&gt; category. So the &lt;code class=&quot;csharp identifier&quot;&gt;parent&lt;/code&gt; category now contains 1 subcategory (because the setup runs prior to any tests executing). So now when I execute the &lt;code class=&quot;csharp identifier&quot;&gt;A_top_level_category_return_its_name_when_ToString_is_called&lt;span class=&quot;csharp literal&quot;&gt;()&lt;/span&gt;&lt;/code&gt;, an additional subcategory is added to the &lt;code class=&quot;csharp identifier&quot;&gt;parent&lt;/code&gt; category (for a total of 2 subcategories) and the assertion fails. There are two ways to fix this:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Move the test to the &lt;code class=&quot;csharp userType&quot;&gt;ChildCategoryContext&lt;/code&gt; class.&lt;/b&gt; I don&#39;t like this option because to me, it seems like since it&#39;s only using the &lt;code class=&quot;csharp identifier&quot;&gt;parent&lt;/code&gt; category, it should reside in the &lt;code class=&quot;csharp userType&quot;&gt;ParentCategoryContext&lt;/code&gt; class.&lt;br /&gt;
&lt;li&gt;&lt;b&gt;Obtain the count of subcategories of the &lt;code class=&quot;csharp identifier&quot;&gt;parent&lt;/code&gt; category prior to adding a subcategory. Then assert that the count of subcategories is equal to one plus the count obtained before acting on the CUT.&lt;/b&gt; To me, this is a much better option. The test is still straight-forward; the class resides where you&#39;d expect it to reside; the test is less fragile.&lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/ol&gt;&lt;p&gt;I think I&#39;ll go with option number two and re-write the test as follows:&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;[TestMethod]
public void A_top_level_category_returns_its_name_when_ToString_is_called()
{
    int numSubcategories = parent.subCategories.Count;
    parent.AddSubcategory(&quot;subcategory&quot;);
    Assert.AreEqual(numSubcategories + 1, parent.Subcategories.Count);
}
&lt;/pre&gt;&lt;p&gt;With that done, that&#39;s it for the tests. Now for the implementation in the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;public class Category
{
    // ...
    // All the old fields are above

    private Category parentCategory;

    // The constructors are have changed a bit.

    protected Category()
    {
        subCategories = new List&amp;lt;Category&amp;gt;();
    }

    public Category(string name) : this(name, None) { }

    // This constructor is private so that we can enforce not allowing
    // cycles to occur in parent/child/grandchild relationships.
    private Category(string name, Category parent) : this()
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new InvalidCategoryNameException();
        
        // You shouldn&#39;t call virtual properties and methods from your constructors,
        // so use the fields directly.
        this.name = SanitizeName(name);

        if (parentCategory == null)
            parentCategory = parent;
        else // Use SetParentCategory(...) to prevent cyclic relationships.
            SetParentCategory(parent);
    }

    // ...
    // The other properties listed before remain the same.

    public virtual Category Parent
    {
        get { return parentCategory; }
        set 
        {
            // Since on creation parentCategory is never left null, 
            // always call this method when setting the parent.
            SetParentCategory(value);
        }
    }

    // The original implementation of AddSubcategory was made private so
    // that external users can no longer pass in an arbitrary category.
    // This prevents cycles in the hierarchy.
    // 
    // The new public method is now a sort of factory method that creates
    // a new category, adding it as a subcategory to the current instance,
    // and returning the newly creatd category.

    private void AddSubcategory(Category c)
    {
        // ...
        // The original method stays the same...it&#39;s just private now.
    }

    /// &amp;lt;summary&amp;gt;
    /// Creates a new Category as a subcategory of the current instance.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&quot;name&quot;&amp;gt;The name of the new subcategory.&amp;lt;/param&amp;gt;
    /// &amp;lt;exception cref=&quot;InvalidOperationException&quot;&amp;gt;
    ///     Thrown if the current instance is &amp;lt;see cref=&quot;Category.None&quot;/&amp;gt;.
    /// &amp;lt;/exception&amp;gt;
    /// &amp;lt;exception cref=&quot;InvalidCategoryNameException&quot;&amp;gt;
    ///     Thrown if the &amp;lt;paramref name=&quot;name&quot;/&amp;gt; is &amp;lt;c&amp;gt;null&amp;lt;/c&amp;gt;,
    ///     the empty string, or consists entirely of whitespace.
    /// &amp;lt;/exception&amp;gt;
    public virtual Category AddSubcategory(string name)
    {
        if (this == None)
            throw new InvalidOperationException();
        
        Category subcategory = new Category(name, this);
        AddSubcategory(subcategory);
        return subcategory;
    }

    private void SetParentCategory(Category c)
    {
        if (c != Category.None &amp;amp;&amp;amp; this.HasDescendant(c))
            throw new InvalidOperationException();

        parentCategory = c;
        if (parentCategory == Category.None)
            parentCategory.AddSubcategory(this);
    }

    // This method determines whether or not the new parent passed to
    // SetParentCategory is a descendant of the category on which
    // SetParentCategory was called. If so, this method returns true.
    // This prevents cycles in the hierarchy.
    // Again, limiting hierarchy depth can prevent possible stack overflows
    // due to the recursive nature of this function.
    private bool HasDescendant(Category c)
    {
        bool result = false;

        if (this == c)
            result = true;
        else if (c.Parent != Category.None)
            result = this.HasDescendant(c.Parent);

        return result;
    }

    // The implementation of this method changed. Instead of simply returning
    // the name of the category, it returns the category&#39;s path from the root:
    // e.g. A/B/C, or Parent/Child/Grandchild.
    public override string ToString()
    {
        return Parent == Category.None ?
            Name : string.Concat(Parent.ToString(), &quot;/&quot;, Name);
    }
}
&lt;/pre&gt;&lt;p&gt;There you go, that wraps up all of the code for the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class. Let&#39;s just take a few seconds to review it. We finally added a &lt;code class=&quot;csharp identifier&quot;&gt;Parent&lt;/code&gt; property. In addition, we added a private constructor that creates a new category and sets its parent. This constructor is private so that I have control over preventing cycles in the hierarchy. The original constructor that takes a category name defers to this new constructor, setting the parent category to &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;None&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;. We made the original implementation of &lt;code class=&quot;csharp identifier&quot;&gt;AddSubcategory&lt;/code&gt; private. The original implementation allowed you to pass in any &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; instance, which could allow cycles to occur. So a new method was added that acts as a &lt;span style=&quot;font-variant: small-caps&quot;&gt;Factory Method&lt;/span&gt;, adding the newly created category as a subcategory of the instance on which it was called and returning the newly created subcategory. The &lt;code class=&quot;csharp identifier&quot;&gt;SetParentCategory&lt;/code&gt; method is also interesting. It checks that if the category passed into it is not &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;span class=&quot;csharp literal&quot;&gt;.&lt;span class=&quot;csharp identifier&quot;&gt;None&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;, then that the category is also not a descendant of the current instance—again, preventing cycles in the hierarchy. Finally, the &lt;code class=&quot;csharp identifier&quot;&gt;ToString&lt;/code&gt; implementation changed to return the full path of the category from the root of its hierarchy, e.g. &lt;code&gt;Parent/Child/Grandchild&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;Again, the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class is fairly small. Having said that, this ended up being a very long blog article. But I think that because of its relative simplicity, it made a good example of how using nested test classes to provide &lt;i&gt;context boundaries&lt;/i&gt; for test setup methods can help you keep your setup methods small. Using context classes and setup methods, and keeping your setup methods small promotes the following benefits:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Small setups&lt;/b&gt;: Smaller setups mean that less data is being instantiated and configured; and only the data required for the tests in the current context is setup. This has additional benefits:  &lt;ul&gt;&lt;li&gt;Faster execution times (OK, this could be anywhere from negligible to very noticeable)&lt;br /&gt;
&lt;li&gt;Less chance for contamination to occur between tests, e.g. mutated state affecting downstream tests (though with the caveat seen earlier in this post)&lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/ul&gt;&lt;li&gt;Using setup methods allows you to keep your tests &lt;abbr title=&quot;Don&#39;t Repeat Yourself&quot;&gt;DRY&lt;/abbr&gt;&lt;br /&gt;
&lt;li&gt;Using context classes in addition to setup methods keeps your tests small and easy to read&lt;br /&gt;
&lt;li&gt;Small tests are focused, and usually adhere to the &lt;abbr title=&quot;Single Responsibility Principle&quot;&gt;SRP&lt;/abbr&gt;. This means your tests are:  &lt;ul&gt;&lt;li&gt;easy to maintain&lt;br /&gt;
&lt;li&gt;flexible (read, not fragile) &lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/ul&gt;&lt;li&gt;By going one step further and using &lt;i&gt;composable assertions&lt;/i&gt;, you make your tests even more understandable, easier to maintain, and less fragile. &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;There is a corresponding list of cons when it comes to using this style of testing, so to be fair, I&#39;ll list out the ones that I can immediately see.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Deep nested classes and the indenting could be annoying&lt;br /&gt;
&lt;li&gt;Tests might be hard to find (heck, there&#39;s always &lt;kbd&gt;CTRL+F&lt;/kbd&gt;)&lt;br /&gt;
&lt;li&gt;If you&#39;re not careful with your assumptions, derived class setups can interfere with base class tests  &lt;ul&gt;&lt;li&gt;This is why it&#39;s even more important to not just start writing your tests in this style, but after you&#39;ve written a few and refactored a bit, you can be more confident about the arrangement of your contexts.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;You have to remember to mark all base-class tests &lt;code class=&quot;csharp keyword&quot;&gt;abstract&lt;/code&gt; and leave the inner-most class concrete.&lt;br /&gt;
&lt;li&gt;Not all test runners support abstract base classes (AutoTest.Net for one) &lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;I&#39;m sure you might be able to think of some other pros or cons. Hopefully, though, you&#39;ll agree that the benefits listed above may be worth the little bit of extra effort. Before leaving you, I want to touch a little more on the effort that went into making these tests &lt;i&gt;hierarchical&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;The effort to make these hierarchical test classes was very small. Granted, this example class is not that complex and not that large. At my current place of employment, I had already used this concept. It did take me a bit of time. But that was the &lt;i&gt;first time ever&lt;/i&gt; that I attempted this. This example in this article was the second time I attempted this, and it went much much faster. Why? Because I now know what to look for. There are a few things I want you to keep in mind if you want to try this style of testing:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Don&#39;t attempt to start creating context test classes right off the bat. You will most likely fail.&lt;br /&gt;
&lt;li&gt;As Robert Martin says, treat your test code as you would your production code.  &lt;ul&gt;&lt;li&gt;This means that you will refactor your tests as you go along in your development effort.&lt;br /&gt;
&lt;li&gt;It&#39;s during this refactoring that you will begin to see patterns in usage in the data required for your tests.&lt;br /&gt;
&lt;li&gt;Begin refactoring by simply extracting methods. &lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/ul&gt;&lt;li&gt;Once you begin to see common &lt;i&gt;groupings&lt;/i&gt; of functionality, e.g. the same methods being called from various tests or the same data needed by a group of tests, and what not, that&#39;s when the creation of context classes will payoff.&lt;br /&gt;
&lt;li&gt;Keep these other thoughts in mind when determining the contexts you may need:  &lt;ul&gt;&lt;li&gt;If tests require the same setup, they belong in a single test class&lt;br /&gt;
&lt;li&gt;If tests require the same setup as other tests, and also need a few more things (say, more than two..otherwise, just arrange the items in your tests), consider placing them in a nested context class. Remember to make all base classes abstract and the inner-most derived class concrete.&lt;br /&gt;
&lt;li&gt;If tests require the same setup as other tests, but have additional needed setups different from another nested context classes, create a sibling context class.&lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;I just want to take a minute and explain the last bullet point about sibling contexts. The last point is talking about the same situation we saw even in the small example presented in this post. We had a &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; class that had two nested, sibling context classes: the first nested sibling context class, &lt;code class=&quot;csharp userType&quot;&gt;CategoryEqualityContext&lt;/code&gt; required additional setup that &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; did not provide; the second nested sibling context class, &lt;code class=&quot;csharp userType&quot;&gt;ParentCategoryContext&lt;/code&gt;, also shared the same setup as &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; but needed additional, yet, different setup than &lt;code class=&quot;csharp userType&quot;&gt;CategoryEqualityContext&lt;/code&gt;. Furthermore, the &lt;code class=&quot;csharp userType&quot;&gt;ParentCategoryContext&lt;/code&gt; contained yet another nested context class within which required the setups of both &lt;code class=&quot;csharp userType&quot;&gt;CategoryTests&lt;/code&gt; and &lt;code class=&quot;csharp userType&quot;&gt;ParentCategoryTest&lt;/code&gt; plus additional setup.&lt;/p&gt;&lt;p&gt;Finally, we&#39;ve come to the end of this very long blog post. I hope that you enjoyed it and that you learned something. If you have a question, feel free to drop me a line and I&#39;ll try to get back to you.&lt;/p&gt;&lt;p&gt;Below, find the full, uninterrupted code of the &lt;code class=&quot;csharp userType&quot;&gt;Category&lt;/code&gt; class and its corresponding test class(es). Until next time, take care.&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;using System;
using System.Collections.Generic;
using System.Diagnostices;
using System.Linq;
using System.Text.RegularExpressions;

namespace DDDSportsStore.Domain
{
    [DebuggerDisplay(&quot;[Name: {Name}]&quot;)]
    public class Category
    {
        private static readonly Category None = new NullCategory();

        private string name;
        private Category parentCategory;
        private List&amp;lt;Category&amp;gt; subCategories;

        protected Category()
        {
            subCategories = new List&amp;lt;Category&amp;gt;();
        }

        public Category(string name) : this(name, Category.None) { }

        private Category(string name Category parent) : this()
        {
            if (string.IsNullOrWhiteSpace(name))
               throw new InvalidCategoryNameException();

            this.name = SanitizeName(name);
            if (parentCategory == null)
                parentCategory = parent;
            else
                SetParentCategory(parent);
        }

        public virtual string Name
        {
            get { return name; }
            set { name = SanitizeName(value); }
        }

        private string SanitizeName(string proposedName)
        {
            return Regex.Replace(proposedName, @&quot;\s+&quot;, &quot; &quot;);
        }

        public virtual Category Parent
        {
            get { return parentCategory; }
            set { SetParentCategory(value); }
        }

        private void SetParentCategory(Category c)
        {
            if (c != Category.None &amp;amp;&amp;amp; this.HasDescendant(c))
                throw new InvalidOperationException();

            parentCategory = c;
            if (parentCategory == Category.None)
                parentCategory.AddSubcategory(this);
        }

        private bool HasDescendant(Category c)
        {
            bool result = false;

            if (this == c)
                result = true;
            else if (c.Parent != Category.None)
                result = this.HasDescendant(c.Parent);

            return result;
        }

        public IReadOnlyCollection&amp;lt;Category&amp;gt; Subcategories
        {
            get { return subCategories.AsReadOnly(); }
        }

        /// &amp;lt;summary&amp;gt;
        /// Creates a new Category as a subcategory of the current instance.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;name&quot;&amp;gt;The name of the new subcategory.&amp;lt;/param&amp;gt;
        /// &amp;lt;exception cref=&quot;InvalidOperationException&quot;&amp;gt;
        ///     Thrown if the current instance is &amp;lt;see cref=&quot;Category.None&quot;/&amp;gt;.
        /// &amp;lt;/exception&amp;gt;
        /// &amp;lt;exception cref=&quot;InvalidCategoryNameException&quot;&amp;gt;
        ///     Thrown if the &amp;lt;paramref name=&quot;name&quot;/&amp;gt; is &amp;lt;c&amp;gt;null&amp;lt;/c&amp;gt;,
        ///     the empty string, or consists entirely of whitespace.
        /// &amp;lt;/exception&amp;gt;
        public virtual Category AddSubcategory(string name)
        {
            if (this == None)
                throw new InvalidOperationException();
        
            Category subcategory = new Category(name, this);
            AddSubcategory(subcategory);
            return subcategory;
        }

        private void AddSubcategory(Category c) 
        {
            if (this == Category.None)
                throw new InvalidOperationException(
                    &quot;Unable to add a subcategory to the &#39;None&#39; category.&quot;
                 );

            if (c == null || c == Category.None)
                throw new InvalidSubcategoryException();

            if (subCategories.Any(sc =&amp;gt; sc.Name == c.Name))
                throw new DuplicateSubcategoryException();

            subCategories.Add(c);
        }

        public bool Equals(Category other)
        {
            if ((object)other == null)
                return false;

            return this.ToString() == other.ToString();
        }


        #region System.Object overrides

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            Category c = obj as Category;
            if ((object)c == nul)
                return false;

            return this.ToString() == c.ToString();
        }

        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }

        public override string ToString()
        {
            return Parent == None ?
                Name : string.Concat(Parent.ToString(), &quot;/&quot;, Name);
        }

        #endregion

        #region Operator Overrides

        public static bool operator ==(Category a, Category b)
        {
            if (object.ReferenceEquals(a, b))
                return true;

            if ((object)a == null || (object)b == null)
                return false;

            return a.ToString() == b.ToString();
        }

        public static bool operator !=(Categoriy a, Category b)
        {
            return !(a == b);
        }

        #endregion

        #region NullCategory

        /// &amp;lt;summary&amp;gt;
        /// This class reperesents an implementation of the Null Object
        /// pattern (a/k/a Special Case pattern) and is meant to be used
        /// anywhere where you might otherwise return null.
        /// &amp;lt;/summary&amp;gt;
        private sealed class NullCategory : Category
        {
            public override Name
            {
                get { return string.Empty; }
                set { }
            }
        }
    }

    #endregion
}

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DDDSportsStore.Domain.Tests
{
    [TestClass]
    public class CategoryTests
    {
        [TestMethod]
        public void Cannot_create_a_Category_with_an_invalid_name()
        {
            AssertCannotCreateCategoryWithName(null);
            AssertCannotCreateCategoryWithName(string.Empty);
            AssertCannotCreateCategoryWithName(&quot;\n&quot;);
        }

        [TestMethod]
        public void
        A_category_name_is_sanitized_to_contain_only_1_contiguous_whitespace_character_between_words()
        {
            AssertCategoryNameWhitespaceIsCollapsed(
                &quot;A  category  with  extraneous  whitespace&quot;,
                &quot;A category with extraneous whitespace&quot;
            );
            AssertCategoryNameWhitespaceIsCollapsed(
                &quot;A\r\ncategory\twith\vother\fwhitespace characters&quot;,
                &quot;A category with other whitespace characters&quot;
            );
            AssertCategoryNameWhitespaceIsCollapsed(
                &quot;This category name is ok&quot;, 
                &quot;This category name is ok&quot;
            );
        }

        private void AssertCannotCreateCategoryWithName(string name)
        {
            ExceptionAssert.Throws&amp;lt;InvalidCategoryNameException&amp;gt;(
                () =&amp;gt; new Category(name)
            );
        }

        private void
        AssertCategoryNameWhitespaceIsCollapsed(string name, string expectedName)
        {
            Assert.AreEqual(new Category(name).Name, expectedName);
        }

        public class CategoryEqualityContext : CategoryTests
        {
            Category categoryA;
            Category categoryB;

            [TestInitialize]
            public void CategoryEqualityContextSetup()
            {
                categoryA = new Category(&quot;A&quot;);
                categoryB = new Category(&quot;B&quot;);
            }

            [TestMethod]
            public void
            A_top_level_category_returns_its_name_when_ToString_is_called()
            {
                Assert.AreEqual(&quot;A&quot;, categoryA.ToString());
            }

            [TestMethod]
            public void
            Can_determine_whether_or_not_two_categories_are_equal_to_one_another()
            {
                Assert.AreEqual(categoryA, categoryA);
                Assert.IsTrue(categoryA.Equals(categoryA));
                Assert.IsTrue(((object)catgeoryA).Equals((object)categoryA));
                Assert.IsTrue(categoryA.Equals(new Category(&quot;A&quot;)));
            }

            [TestMethod]
            public void
            Can_use_the_equality_operator_to_determine_whether_two_categories_are_equal_to_one_another()
            {
                Category c = new Category(&quot;A&quot;);
                Assert.IsTrue(c == categoryA);
            }

            [TestMethod]
            public void
            Can_use_the_inequality_operator_to_determine_whether_two_categories_are_not_equal_to_one_another()
            {
                Assert.IsTrue(categoryA != categoryB);
            }
        }

        [TestClass]
        public class ParentCategoryContext : CategoryTests
        {
            private string PARENT;
            private Category parent;

            [TestInitialize]
            public void ParentCategoryContextSetup()
            {
                PARENT = &quot;Parent&quot;;
                parent = new Category(PARENT);
            }

            [TestMethod]
            public void Can_add_a_subcategory_to_a_category()
            {
                int numSubcategories = parent.subCategories.Count;
                parent.AddSubcategory(&quot;subcategory&quot;);
                Assert.AreEqual(numSubcategories + 1, parent.Subcategories.Count);
            }

            [TestMethod]
            public void Cannot_add_a_duplicate_subcategory_to_a_category()
            {
                parent.AddSubcategory(&quot;subcategory&quot;);
                ExceptionAssert.Throws&amp;lt;DuplicateSubcategoryException&amp;gt;(
                    () =&amp;gt; parent.AddSubcategory(&quot;subcategory&quot;)
                );
            }

            [TestClass]
            public class ChildCategoryContext : ParentCategoryContext
            {
                private string CHILD;
                privte Category child;

                [TestInitialize]
                public void ChildCategoryContextSetup()
                {
                    CHILD = &quot;Child&quot;;
                    child = parent.AddSubcategory(CHILD);
                }
    
                [TestMethod]
                public void
                A_subcategory_returns_its_parents_name_with_a_path_separator_and_its_own_name_when_ToString_is_called()
                {
                    Assert.IsTrue(string.Concat(PARENT, &quot;/&quot;, CHILD) == child.ToString(),
                        string.Format(&quot;Expected &#39;{0}/{1}&#39; but got &#39;{2}&#39;&quot;, PARENT, CHILD, child.ToString());
                }

                [TestMethod]
                public void
                Cannot_set_category_parent_if_new_parent_is_a_descendant_of_the_category()
                {
                    Category grandchild = child.AddSubcategory(&quot;Grandchild&quot;);
                    ExceptionAssert.Throws&amp;lt;Invalidoperationexception&amp;gt;(
                        () =&amp;gt; parent.Parent = grandchild
                    );
                }
            }
        }
    }

    public static class ExceptionAssert
    {
        public static void Throws&amp;lt;T&amp;gt;(Action act) where T : Exception
        {
            try
            {
                act();
                Assert.Fail(&quot;Expected &#39;{0}&#39; to be thrown but no exception was thrown.&quot;);
            }
            catch (T)
            {
                return;
            }
            catch (AssertFailedException)
            {
                throw;
            }
            catch (Exception e)
            {
                Assert.Fail(
                    &quot;Expected &#39;{0}&#39; to be thrown, but &#39;{1}&#39; was thrown instead.&quot;,
                    typeof(T).FullName,
                    e.GetType().FullName
                );
            }
        }
    }
}
&lt;/pre&gt;</description><link>http://discoveringcode.blogspot.com/2014/02/advanced-test-driven-development.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-6864667506543079309</guid><pubDate>Sat, 01 Feb 2014 23:45:00 +0000</pubDate><atom:updated>2014-03-05T10:09:06.040-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">ContinuousTests</category><category domain="http://www.blogger.com/atom/ns#">Mighty Moose</category><category domain="http://www.blogger.com/atom/ns#">Unit Testing</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio Extensions</category><category domain="http://www.blogger.com/atom/ns#">VS2010</category><category domain="http://www.blogger.com/atom/ns#">VS2012</category><category domain="http://www.blogger.com/atom/ns#">VS2013</category><title>Mighty Moose a/k/a ContinuousTests</title><description>&lt;h3&gt;Introduction&lt;/h3&gt;&lt;p&gt;At my current place of employment, I was introduced to &lt;a title=&quot;NCrunch&quot; href=&quot;http://www.ncrunch.net/&quot; target=&quot;_blank&quot;&gt;NCrunch&lt;/a&gt;, a continuous testing solution for .NET and Visual Studio. It’s a great tool that I really enjoy using at work. However, for at home use, I can’t justify paying their asking price for a personal license. Don’t get me wrong, I really love the tool, and if I were doing some serious development on my own (i.e. creating products for sale as a side job), I’d probably pay for it, because it’s fast and shows exactly where an exception occurred or a test failed.&lt;/p&gt;&lt;p&gt;So I really like this concept of continuous testing and went on an Internet search to see what was available out there for free. I wanted something that would run in Visual Studio 2012/2013. A lot of the “free” tools use external test runners which display their output in either the browser (as an XML/HTML page) or in a console window. I don’t like those tools because they interrupt my context, having to switch between Visual Studio and, say, a console window. Plus, then I have to go digging for the file and line number when a test fails.&lt;/p&gt;&lt;h3&gt;&lt;/h3&gt;&lt;h3&gt;Enter Mighty Moose a/k/a Continuous Tests&lt;/h3&gt;&lt;p&gt;During my search, I found &lt;a title=&quot;ContinuousTests&quot; href=&quot;http://continuoustests.com/&quot; target=&quot;_blank&quot;&gt;Mighty Moose a/k/a ContinuousTests&lt;/a&gt;, by Greg Young. Mighty Moose has a slightly different philosophy about continuous testing. Instead of a code coverage margin in Visual Studio, they have a &lt;em&gt;risk&lt;/em&gt; margin. The risk margin shows a colored circle next to a method under test with a number inside. The number inside tells you how many tests are covering the method. The color: red, green, or yellow, indicates the risk of changing that method.&lt;/p&gt;&lt;p&gt;How is risk calculated? It’s based on how close the method was called from the test. According to Greg, while code coverage tells you whether or not the code was executed by a test, that information alone is not enough to classify how risky it is to change the code. What if the code that’s “covered” was called from a method 10 frames down the call stack? By changing that code, you could be affecting not just the method under test, but all 8 other methods in the call stack.&lt;/p&gt;&lt;p&gt;In addition to the risk margin, Mighty Moose contains graph “overlay” graphics (for those of us who can’t afford Visual Studio Ultimate ;) ) that show the call graph of all methods called during the test. This can help you gauge “how far away” a method was invoked from the test, and in general, just help you see the entire call graph, which in itself, could be enlightening.&lt;/p&gt;&lt;h3&gt;Getting Mighty Moose to Work with Visual Studio 2013&lt;/h3&gt;&lt;p&gt;Mighty Moose is currently at version 1.0.47. It officially only supports Visual Studio 2008, 2010, and 2012. However, there’s an excellent question over on &lt;a href=&quot;http://stackoverflow.com/questions/20443322/how-to-enable-mighty-moose-continuoustests-in-visual-studio-2013/21583534&quot; target=&quot;_blank&quot;&gt;Stack Overflow&lt;/a&gt; that I contributed to which shows you how to get Mighty Moose to work with Visual Studio 2013.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2014/02/mighty-moose-aka-continuoustests.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-7717748526662041471</guid><pubDate>Thu, 14 Nov 2013 22:52:00 +0000</pubDate><atom:updated>2013-11-14T17:52:22.270-05:00</atom:updated><title>Cool Blog Post Titled &quot;What is a Full Stack Developer?&quot;</title><description>&lt;p&gt;Hey everyone. I just wanted to share a link to a really cool blog post titled &lt;a href=&quot;http://www.laurencegellert.com/2012/08/what-is-a-full-stack-developer/&quot;&gt;What is a Full Stack Developer?&lt;/a&gt;. Hope you enjoy the post.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2013/11/cool-blog-post-titled-what-is-full.html</link><author>noreply@blogger.com (Craig S.)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-8960224625364960875</guid><pubDate>Thu, 24 Oct 2013 23:54:00 +0000</pubDate><atom:updated>2013-10-24T19:54:51.783-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">AllMargins</category><category domain="http://www.blogger.com/atom/ns#">AllMargins 2012</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio Extensions</category><category domain="http://www.blogger.com/atom/ns#">VS2010</category><category domain="http://www.blogger.com/atom/ns#">VS2012</category><category domain="http://www.blogger.com/atom/ns#">VS2013</category><title>AllMargins 2012 v2.8.x Releases</title><description>&lt;p&gt;On 1 September 2013 I released version 2.8 of the &lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/43bc4a3a-0182-4c36-8159-a0a4cdfd04bd&quot;&gt;AllMargins 2012&lt;/a&gt; Visual Studio extension. Since that release, there have been two additional &amp;quot;dot&amp;quot; releases. Briefly, here&#39;s what v2.8.x has to offer:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Visual Studio 2013 RC and RTM support&lt;/li&gt;
&lt;li&gt;All the registry value names for the extension&#39;s settings have been renamed to prevent naming conflicts with the Productivity Power Tools for Visual Studio 2012 and beyond (more on that below)&lt;/li&gt;
&lt;li&gt;Fixed the registry value name for method separator line color&lt;/li&gt;
&lt;li&gt;Fixed the StructureAdornment extension so that method separator lines are drawn using the specified color&lt;/li&gt;
&lt;li&gt;Added C/C++ &lt;code&gt;union&lt;/code&gt; support&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;Extension Option Registry Value Name Clashes&lt;/h4&gt;&lt;p&gt;David Pugh (MSFT) ported a lot (but not all) of the functionality of the original AllMargins extension into the Productivity Power Tools for Visual Studio 2012. The extension option registry value names were left the same. So, when I re-released the AllMargins extension as AllMargins2012, the two extensions would step over each other in terms of their settings for the common extensions. Starting with v2.8, the registry value names have changed to prevent this. As a result, those who installed v2.7 and subsequently customized the extension options by editing the registry, upon installing v2.8, will see that the extension is using the default values for all settings&amp;mdash;it appears as though your customizations were changed. They are not. They are still present in the registry. However, new settings are now used by the AllMargins 2012 extension. You need only copy the setting value from the v2.7 registry value to the new v2.8 registry value. I apologize for the inconvenience.&lt;/p&gt;&lt;p&gt;For more details about what the various registry settings are, and their old and new names, see the description tab for the extension at the &lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/43bc4a3a-0182-4c36-8159-a0a4cdfd04bd&quot;&gt;Visual Studio Gallery&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;What to expect in the next major release&lt;/h3&gt;&lt;p&gt;Many have spoken, including myself, about what you would like to see in the next major release. Work is underway; here is a quick rundown of what to expect (of course, this is subject to change&amp;mdash;nothing is set in stone unless otherwise noted):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The ability to set the extension&#39;s options from the Visual Studio Tools|Options dialog. This is a top priority, non-negotiable item for the next major release. I have been wanting this very feature myself since David Pugh originally wrote this extension. Now that I&#39;m maintaining this code base, this task falls on me.&lt;/li&gt;
&lt;li&gt;The ability to specify the line widths displayed in the editor for the StructureAdornment extension&lt;/li&gt;
&lt;li&gt;Add an option to show/hide the StructureMargin preview tool tip&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The items above are what I can reasonably expect to fit into the next major release, though only the first item is guaranteed to make it through. Whatever doesn&#39;t make it through will be in a follow-up release. One item that is a planned feature for a future release is the availability to select a color theme for the StructureMargin and StructureAdornment extensions. As many have noted, and I agree, the &amp;quot;default&amp;quot; colors don&#39;t work well with Visual Studio 2012&#39;s dark theme. In addition, I plan on changing the default color for the &lt;code&gt;class&lt;/code&gt; structure adornment from black to some other color, because with the Visual Studio light theme the black line can cause exclamation points to appear to not be present in C# and C/C++ preprocessor statements (e.g. &lt;code&gt;#define !SOME_PREPROCESSOR_VAR&lt;/code&gt;), as one user pointed out to me. Black was the original color used by David Pugh&amp;mdash;but due to this potential problem, it&#39;s best if this color is changed.&lt;/p&gt;&lt;p&gt;If there are any other features you&#39;d like to see, please feel free to leave a comment here on my blog or on the Q AND A tab at &lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/43bc4a3a-0182-4c36-8159-a0a4cdfd04bd&quot;&gt;Visual Studio Gallery&lt;/a&gt;. Thanks again for all of your comments, feedback, suggestions, and ratings!&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2013/10/allmargins-2012-v28x-releases.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-1750733349742141917</guid><pubDate>Sun, 20 Jan 2013 03:25:00 +0000</pubDate><atom:updated>2013-01-22T12:34:59.112-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Visual Studio</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio Extensions</category><category domain="http://www.blogger.com/atom/ns#">VS2010</category><category domain="http://www.blogger.com/atom/ns#">VS2012</category><title>Announcing the Release of AllMargins for Visual Studio 2012</title><description>&lt;p&gt;In August of last year, I wrote about &lt;a href=&quot;http://discoveringcode.blogspot.com/2012/08/updating-visual-studio-2010-extension.html&quot;&gt;upgrading Visual Studio 2010 extensions&lt;/a&gt; so that they will work with Visual Studio 2012. In particular, I discussed upgrading the AllMargins Visual Studio extension, which was quite popular.&lt;/p&gt;&lt;p&gt;For some time now, David Pugh of Microsoft has pulled this extension off of Visual Studio Gallery. It is only available if you happened to have downloaded it and saved it to your hard drive or have downloaded the source code (which you can find the link to in the article I wrote back in August). The problem with the source code is that it&#39;s a few versions behind the last release that was available on Visual Studio Gallery and contains a few bugs and is missing support for things like C#&#39;s class initializer syntax.&lt;/p&gt;&lt;p&gt;The extension was pulled because David ported most of the functionality into the Visual Studio Productivity Power Tools. However, I&#39;m not a big fan of the particular implementation of the enhanced scrollbar in &lt;abbr title=&quot;Visual Studio Productivity Power Tools&quot;&gt;VSPPT&lt;/abbr&gt; and prefer the AllMargins scrollbar instead.&lt;br /&gt;
&lt;p&gt;Today, I&#39;m announcing general availability once again of the &lt;b&gt;&lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/43bc4a3a-0182-4c36-8159-a0a4cdfd04bd&quot;&gt;AllMargins 2012&lt;/a&gt;&lt;/b&gt; extension on Visual Studio Gallery. I modified the available source code, bringing it up to parity with version 2.6, the last available release on Visual Studio Gallery. In addition, I modified the extension so that it will install in Visual Studio 2012. The extension is now at version 2.7.&lt;/p&gt;&lt;p&gt;Thanks to David Pugh at Microsoft for giving the Visual Studio community this wonderful extension and releasing the source code for it a while back!&lt;/p&gt;&lt;p&gt;As I have time, I hope to make a few additions to the extension. Some planned enhancements include providing the ability to change various colors used for drawing the lines in code files delineating various code blocks or for drawing various markers in the overview margin (e.g. drawing a mark for all occurrences in a document of a word under the cursor in the overview margin) right from the Visual Studio Options dialog.&lt;/p&gt;&lt;p&gt;A few notes about &lt;b&gt;AllMargins 2012&lt;/b&gt;. First, because the original extension is linked to David Pugh&#39;s Windows Live ID, I had to change the identifier of the extension. (This is good, afterall, you wouldn&#39;t want Microsoft to allow people to hijack author&#39;s extensions possibly replacing them with malicious code, now would you?!) Since the ID, well, identifies the extension, it&#39;s essentially a different extension. So I renamed it &lt;b&gt;AllMargins 2012&lt;/b&gt; while I was at it. What this means is that if you want to use this extension in Visual Studio 2010, you &lt;i&gt;must&lt;/i&gt; uninstall David Pugh&#39;s original AllMargins extension &lt;i&gt;before&lt;/i&gt; installing this extension. I don&#39;t know what would happen if you have both installed (Double overview scrollbars? Crash Visual Studio?) &lt;br /&gt;
&lt;p&gt;I hope that you will continue to find this extension as useful as I have! The Read Me for the top-level &lt;b&gt;AllMargins 2012&lt;/b&gt; extension is presented below.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;pre&gt;AllMargins 2012

Introduction:
    This is a compilation of the OverviewMargin and several other extensions that use the OverviewMargin. The OverviewMargin shows
    a margin on the right side of the editor that logically maps to the entire file (similar the the vertical scroll bar). Unlike
    the scroll bar, it maps to the entire file and can contain other margins that provide more information about the file.


Included extensions:
        CaretMargin
        ErrorsToMarks
        MarkersToMarks
        OverviewMarginImpl
        StructureAdornment
        StructureMargin 

        BlockTagger         The definition of an API to get the structure of a code file.
        BlockTaggerImpl     An implementation of the BlockTaggerAPI for C/C# and VB files.

        OverviewMargin      The definition of an API for creating margins that map to the entire file.

        SettingsStore       The definition of an API to load and save editor options across sessions.
        SettingsStoreImpl   An implementation of the SettingStore API that uses IVsSettingsStore to access the system registry.

Usage:
    See other extensions.

Options:
    None.

Notes:
    &lt;/pre&gt;&lt;del&gt;&lt;pre&gt;The full source for this extension is at http://code.msdn.microsoft.com/OverviewMargin/Release/ProjectReleases.aspx?ReleaseId=3957&lt;/pre&gt;&lt;/del&gt;&lt;pre&gt;The source code is not yet available for download.

History:
    v1.0    David Pugh  2/26/2010
        Initial release
    V1.1    David Pugh  3/4/2010
        Updated included extensions.
    V1.2    David Pugh  4/19/2010
        Updated included extensions.
    V1.3    David Pugh  4/20/2010
        Updated included extensions.
    V1.4    David Pugh  4/22/2010
        Updated included extensions.
    V1.5    David Pugh  4/27/2010
        Updated included extensions.
    V1.6    David Pugh  4/28/2010
        Updated included extensions to fix VB parser error.
    V1.7    David Pugh  4/28/2010
        Updated version number to work around install issue.
    V1.8    David Pugh  4/28/2010
        More VB parse fixes (Public, REM, Interface, Structure).
    V1.9    David Pugh  4/28/2010
        Updated CaretMargin, VB, C# and C parsers.
    V2.0    David Pugh  5/03/2010
        Bumped version number to fix installation problem.
    V2.1    David Pugh  6/10/2010
        Updated OverviewMargin, BlockTagger, StructureAdornment &amp; StructureMargin.
        Changed namespaces and DLL names to Microsoft.VisualStudio.Extensions.....
    V2.2    David Pugh  6/29/2010
        Updated StructureAdornment.
    V2.3    David Pugh  6/30/2010
        Picked up fix for VB parser, tweaks for structure adornment &amp; margin.
    V2.4    David Pugh  7/08/2010
        Updated StructureAdornment.
    V2.5    David Pugh  7/12/2010
        Updated included BlockTaggerImpl to handle C/C# array initializers.
    V2.6    David Pugh  7/31/2010
        Updated included CaretMargin to fix problem with margin not updating correctly.
        Updated included OverviewMarginImpl to fix scrollbar mapping problem.
    V2.7 Craig E. Shea 1/16/2013
        Added Visual Studio 2012 support.
        Removed the attribute MaxVersion=&quot;4.0&quot; on the SupportedFrameworkRuntimeEdition element.
        Changed the author and description to indicate who is now responsible for the extension and that it is a re-release of a previously available extension.
&lt;/pre&gt;</description><link>http://discoveringcode.blogspot.com/2013/01/announcing-release-of-allmargins-for.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-2093359306521434939</guid><pubDate>Sat, 25 Aug 2012 03:53:00 +0000</pubDate><atom:updated>2013-01-17T19:41:15.852-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">Generics</category><category domain="http://www.blogger.com/atom/ns#">Unit Testing</category><title>Generics and Implicit Conversion Operators Create an Identity Crisis</title><description>&lt;div style=&quot;display:none&quot;&gt;&lt;style type=&quot;text/css&quot;&gt;
&lt;!--[if IE]&gt;
.vsCode { margin-right: 2em; }
&lt;![endif]--&gt;
&lt;/style&gt;&lt;br /&gt;
&lt;/div&gt;&lt;p&gt;I keep running into problems with my Unit Tests for a project I&#39;m working on at work, in particular, when I execute &lt;code&gt;&lt;span class=&quot;csharp userType&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;csharp identifier&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;csharp literal&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;csharp identifier&quot;&gt;expected&lt;span class=&quot;csharp literal&quot;&gt;,&lt;/span&gt; actual&lt;/span&gt;&lt;span class=&quot;csharp literal&quot;&gt;)&lt;/span&gt;&lt;/code&gt;.&lt;br /&gt;
&lt;/p&gt;&lt;h3&gt;Some Background Information&lt;/h3&gt;&lt;p&gt;Currently, I&#39;m working on some software that will integrate an accounting system with some online banking web services. This is so that instead of manually entering transactions in both the accounting system and then again up at the bank&#39;s website, firms can enter them once into the accounting system and the integration software I&#39;m writing will handle making the appropriate web service calls to initiate the actual transactions at the bank.&lt;/p&gt;&lt;p&gt;There is a consortium out there known as the Interactive Financial eXchange Forum, usually known simply as &lt;abbr title=&quot;Interactive Financial eXchange&quot;&gt;IFX&lt;/abbr&gt;. They&#39;re an industry group that writes specifications for the transfer of financial data using &lt;abbr title=&quot;eXtensible Markup Language&quot;&gt;XML&lt;/abbr&gt; and web services. Many financial instutions and software packages use specifications from the &lt;abbr title=&quot;Interactive Financial eXchange&quot;&gt;IFX&lt;/abbr&gt;, such as Intuit, the makers of Quicken software.&lt;/p&gt;&lt;p&gt;Some of these specifications are available for download for free. The most recent versions (and the most useful, e.g. &lt;abbr title=&quot;eXtensible Schema Definition&quot;&gt;XSD&lt;/abbr&gt; schemas) are often available to members only (and that pricetag is quite steep). I&#39;m using version 1.7. Within the version 1.7 schemas, there is a type known as &lt;code&gt;NC&lt;/code&gt;, which stands for &amp;quot;narrow-character&amp;quot; string. A narrow-character string is basically all 7-bit &lt;abbr title=&quot;American Symbolic Code for Information Interchange&quot;&gt;ASCII&lt;/abbr&gt; characters below &lt;code&gt;0x7F&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;My first thought was to write an extension method to perform the conversion:&lt;/p&gt;&lt;pre class=&quot;brush: csharp gutter: false&quot;&gt;public static string UTF8ToLatin1(this string value);
&lt;/pre&gt;&lt;p&gt;This worked well until I discovered that I had to constantly remember that if a &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; variable needed to be a narrow-character string, I needed to call that extension method anytime I changed its value. Needless to say, I found occassions where I forgot to call the method. So while cool, this was not a good long-term solution.&lt;/p&gt;&lt;h3&gt;A New Class is Born&lt;/h3&gt;&lt;p&gt;So then I decided to get &amp;quot;cute&amp;quot;; but hopefully not too cute. It turns out that &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; is a &lt;code class=&quot;csharp keyword&quot;&gt;sealed&lt;/code&gt; class. This is unfortunate, but there&#39;s probably a good reason for that. So I decided to write my own wrapper class that wraps a &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; value that provides all the necessary validation while delegating much of its behavior to &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; and all the while making it inheritable (there are several specializations of a narrow-character string used throughout the &lt;abbr title=&quot;Interactive Finacial eXchange&quot;&gt;IFX&lt;/abbr&gt; specification schemas). I called it &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Everything was going pretty well until I realized that I couldn&#39;t just simply assign a &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; to a &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt; object and vice versa without using some sort of property or method accessor. Well I don&#39;t know about you, but that just smelled to me.&lt;/p&gt;&lt;p&gt;I then went researching to see if there was any way to create some sort of overloaded casting operator (sort of like C++&#39;s &lt;code class=&quot;csharp identifier&quot;&gt;static_cast&lt;/code&gt; and &lt;code class=&quot;csharp identifier&quot;&gt;dynamic_cast&lt;/code&gt; operators, and what-not). It turns out, .NET has what they call &lt;i&gt;conversion operators&lt;/i&gt;. I had forgotten all about these, mainly because they look a lot different since &lt;abbr title=&quot;Common Language Runtime&quot;&gt;CLR&lt;/abbr&gt; 2.0 than from &lt;abbr title=&quot;Common Language Runtime&quot;&gt;CLR&lt;/abbr&gt; 1.0, and honestly, I never had the need to implement one before (except for the occasional ToXXXX/FromXXXX methods).&lt;/p&gt;&lt;h3&gt;Conversion Operators&lt;/h3&gt;&lt;p&gt;In &lt;abbr title=&quot;Common Language Runtime&quot;&gt;CLR&lt;/abbr&gt; 1.0, conversion operators were merely method calls in the form of &lt;b&gt;&lt;code class=&quot;csharp identifier&quot;&gt;ToXXX(...)/FromXXX(...)&lt;/code&gt;&lt;/b&gt; for languages that don&#39;t support operator overloading, and named operators called &lt;b&gt;&lt;code class=&quot;csharp identifier&quot;&gt;op_Explicit&lt;/code&gt;&lt;/b&gt; and &lt;b&gt;&lt;code class=&quot;csharp identifier&quot;&gt;op_Implicit&lt;/code&gt;&lt;/b&gt; for those languages that do support operator overloading.&lt;/p&gt;&lt;p&gt;In &lt;abbr title=&quot;Common Language Runtime&quot;&gt;CLR&lt;/abbr&gt; 2.0, conversion operators got some syntactic sugar (at least, in C#). &lt;i&gt;Explicit&lt;/i&gt; conversion operators, when used, look like regular casts from one type to another (much like how you can create a constructor in C++ that takes the type to convert from, which then allows you to use the C++ cast convention instead of calling the constructor directly). &lt;i&gt;Implicit&lt;/i&gt; operators are even cooler in that the syntactic sugar allows you to directly assign the object to convert from directly to the object being converted to, as if both objects were of the same type. Obviously, there&#39;s much room for abuse here, so there are some compiler-enforced rules as well as general guidelines on their (as well as explicit conversion operator&#39;s) use, which can be found &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms229033.aspx&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;http://blogs.msdn.com/b/brada/archive/2003/04/04/49906.aspx&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;So in my &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt; class, I created the required constructors, implemented the requisite &lt;code class=&quot;csharp keyword&quot;&gt;object&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;csharp identifier&quot;&gt;Equals&lt;/span&gt;&lt;/code&gt; methods, overloaded the equality operators, and finally created implicit conversion operators, both to and from &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt;. Now, if you took the time to read the guidelines I linked to above, you will notice that I may have violated one of the guidelines:&lt;/p&gt;&lt;blockquote&gt;&lt;b&gt;Do not provide an implicit conversion operator if the conversion is potentially lossy.&lt;/b&gt;&lt;/blockquote&gt;&lt;p&gt;This is sort of a judgement call. On the one hand, you could consider the conversion from &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; to &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt; as &amp;quot;lossy&amp;quot;, because potentially, a &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; can hold a wider range of characters than what is allowed in a &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt;. However, if you try to assign a &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; with characters that fall outside the allowable range for a &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt;, a &lt;code class=&quot;csharp identifier&quot;&gt;System&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;csharp userType&quot;&gt;ArgumentException&lt;/span&gt;&lt;/code&gt; is thrown&amp;mdash;from the constructor of &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt;, which curiously, is shown as an example in the Framework Design Guidelines documentation, and yet, which also seems to violate the following guideline:&lt;/p&gt;&lt;blockquote&gt;&lt;b&gt;Do not throw exceptions from implicit casts.&lt;/b&gt;&lt;/blockquote&gt;&lt;p&gt;(If anyone has anything to say about the examples shown in the Framework Design Guidelines versus the guidelines themselves, I&#39;d be interested to hear; leave a comment.)&lt;/p&gt;&lt;p&gt;As I was saying, on the one hand, the implicit conversion from &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; to &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt; could be considered lossy. On the other hand, the two are &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt;s, it&#39;s just that one has a more restrictive character set (e.g. it&#39;s not like I&#39;m trying to convert from a &lt;code class=&quot;csharp keyword&quot;&gt;double&lt;/code&gt; to an &lt;code class=&quot;csharp keyword&quot;&gt;int&lt;/code&gt;, the conversion of which could result in actual data loss). So, in light of that, it would make it much simpler to work with the &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt; class if I could convert between instances of &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt; and &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; without needing to explicitly write a cast all the time.&lt;/p&gt;&lt;h3&gt;Unit Testing Problems Begin&lt;/h3&gt;&lt;p&gt;About this time is when some unit testing problems began to rear their ugly head when it came to calls to &lt;code class=&quot;csharp userType&quot;&gt;Assert&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;csharp identifier&quot;&gt;AreEqual&lt;span class=&quot;csharp literal&quot;&gt;(&lt;/span&gt;expected&lt;span class=&quot;csharp literal&quot;&gt;,&lt;/span&gt; actual&lt;/span&gt;&lt;span class=&quot;csharp literal&quot;&gt;)&lt;/span&gt;&lt;/code&gt;. I initially began writing this blog post thinking that the generic version of this method was not properly inferring the parameter types or that the non-generic version was being called instead of the generic version. Well, it turns out to be the latter rather than the former.&lt;/p&gt;&lt;p&gt;When I began writing unit tests, I would have code similar to the following:&lt;/p&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;// Assert
NCString nc = &quot;Hello World&quot;;

// Act
target = new SomeObject(nc);

// Assert
Assert.AreEqual(nc, target.NarrowString);

/* Results of assertion:
 *
 * Assert.AreEqual failed: Expected&amp;lt;MyNamespace.NCString&amp;gt;  Actual&amp;lt;System.String&amp;gt;
 *
 */
&lt;/pre&gt;&lt;h3&gt;Identity Crisis&lt;/h3&gt;&lt;p&gt;I expected that, 1) with the method having a generic method signature overload, 2) .NET&#39;s ability to &lt;em&gt;infer&lt;/em&gt; generic method type parameters, and 3) since the parameters I passed were two different types with conversions from one to another, that &lt;code class=&quot;csharp identifier&quot;&gt;actual&lt;/code&gt; would attempt to be casted into the type of &lt;code class=&quot;csharp identifier&quot;&gt;expected&lt;/code&gt;, after which, they would then be tested for equality.&lt;/p&gt;&lt;p&gt;As I just mentioned above, in .NET, generic methods can most often &lt;i&gt;infer&lt;/i&gt; their generic parameters, so you don&#39;t need to explicitly tell .NET what the type of the generic parameter is. This is precisely what&#39;s causing me issues. I&#39;m used to letting .NET infer my generic parameter types (especially when it comes to &lt;abbr title=&quot;Language Integrated Query&quot;&gt;LINQ&lt;/abbr&gt; statements). But in this case, it&#39;s not being inferred. Why not?&lt;/p&gt;&lt;p&gt;The answer is rather simple; but throw in some implicit conversion operators and the answer becomes more complex. So here&#39;s the not-so-simple answer. What was happening was that the compiler did (probably) attempt to use the generic method. But, because I didn&#39;t specify the type of the generic parameter &lt;code class=&quot;csharp typeParam&quot;&gt;T&lt;/code&gt;, instead, letting .NET (try to) infer the type, .NET was unable to infer the type. Why? Because of the implicit conversion operators. What type should .NET infer for the parameters? &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt;? &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt;? Both parameters are implicitly convertible to one another. Furthermore, even if .NET did choose one type over another, there really isn&#39;t a way to dynamically cast one type to the other through reflection. Indeed, in the end, the compiler had to choose to use the overload that takes two &lt;code class=&quot;csharp keyword&quot;&gt;object&lt;/code&gt; parameters. And, of course, &lt;code class=&quot;csharp keyword&quot;&gt;object&lt;/code&gt; has an &lt;code class=&quot;csharp identifier&quot;&gt;Equals&lt;/code&gt; method that does little more than test for type equality and referential equality.&lt;/p&gt;&lt;h3&gt;Finding Myself&lt;/h3&gt;&lt;p&gt;There are two solutions to this problem. One easy, the other somewhat easy.&lt;/p&gt;&lt;p&gt;First, the somewhat easy one (my first approach, mostly because I didn&#39;t look to see what else was available in the &lt;code class=&quot;csharp userType&quot;&gt;Assert&lt;/code&gt; class). Explicitly tell the compiler what the generic type parameter should be so that the generic method signature is used: &lt;code class=&quot;csharp identifier&quot;&gt;&lt;span class=&quot;csharp userType&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;AreEqual&lt;span class=&quot;csharp literal&quot;&gt;&amp;lt;&lt;span class=&quot;csharp userType&quot;&gt;NCString&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;csharp literal&quot;&gt;(&lt;/span&gt;expected&lt;span class=&quot;csharp literal&quot;&gt;,&lt;/span&gt; actual&lt;span class=&quot;csharp literal&quot;&gt;);&lt;/span&gt;&lt;/code&gt;. Because the two types are implicitly convertible to/from one another, and I&#39;ve explicitly specified the generic type parameter to be a &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt;, the &lt;code class=&quot;csharp identifier&quot;&gt;actual&lt;/code&gt; parameter will be converted to a &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt; and &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt;&#39;s implementation of &lt;code class=&quot;csharp identifier&quot;&gt;Equals&lt;/code&gt; will be used.&lt;/p&gt;&lt;p&gt;The really easy solution (for my case) is to use the overload that takes two &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt; parameters and a &lt;code class=&quot;csharp keyword&quot;&gt;bool&lt;/code&gt; (indicating whether or not the assertion should be handled case-insensitively). Using this overload, I&#39;d have to use the third boolean parameter (in my case, always set to &lt;code class=&quot;csharp keyword&quot;&gt;false&lt;/code&gt;) and no explicit type casting/conversion would need to be performed. (Note however, that an implicit type conversion would still be performed from &lt;code class=&quot;csharp userType&quot;&gt;NCString&lt;/code&gt; to &lt;code class=&quot;csharp keyword&quot;&gt;string&lt;/code&gt;.)&lt;/p&gt;&lt;p&gt;Which is better? Hard to say and it mostly depends on what you&#39;re trying to test for equality. In my case, both types were strings (one more specialized than another), so there&#39;s not much of a diffirence one way or another and not much more in the way of typing for one way or the other.&lt;/p&gt;&lt;h3&gt;Some Final Questions and Concluding Remarks&lt;/h3&gt;&lt;p&gt;So, I wonder, does the .NET Unit Test Framework always use the &lt;code class=&quot;csharp identifier&quot;&gt;&lt;span class=&quot;csharp userType&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;csharp literal&quot;&gt;.&lt;/span&gt;AreEquals&lt;span class=&quot;csharp literal&quot;&gt;(&lt;/span&gt;expected&lt;span class=&quot;csharp literal&quot;&gt;,&lt;/span&gt; actual&lt;span class=&quot;csharp literal&quot;&gt;)&lt;/span&gt;&lt;/code&gt; overload that takes two &lt;code class=&quot;csharp keyword&quot;&gt;object&lt;/code&gt; parameters whenever the two parameters are of different types, or just in the case when the two parameters are not the primitives for which an overload exists and a generic type parameter was not specified?&lt;/p&gt;&lt;p&gt;Anyway, I just wanted to post this, because this has been bothering me for a while. I didn&#39;t expect this behavior, but now that I&#39;ve worked through it, I understand it. I hope that I can save you many hours of troubleshooting your unit tests.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2012/08/generics-and-implicit-conversion.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-8936467719201684418</guid><pubDate>Fri, 24 Aug 2012 21:01:00 +0000</pubDate><atom:updated>2012-09-04T20:48:08.106-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">Regular Expressions</category><category domain="http://www.blogger.com/atom/ns#">Unicode</category><category domain="http://www.blogger.com/atom/ns#">UTF-16</category><category domain="http://www.blogger.com/atom/ns#">XML</category><title>.NET Regular Expressions and XML NAME tokens</title><description>&lt;div style=&quot;display:none&quot;&gt;&lt;style&gt;&lt;!--[if IE]&gt; vsCode { margin-right: 1.5em; } &lt;![endif]--&gt;&lt;/style&gt;&lt;br /&gt;
&lt;/div&gt;&lt;p&gt;Hello everyone. I&#39;m back again. Before we get started, I just kind of wanted to put out a notice. I&#39;m working on my blog template. So if you come here and see that stuff doesn&#39;t look exactly the way it should, well, you&#39;ve been warned. This includes the mobile template (so far, I&#39;m not impressed with blogger&#39;s mobile templates).&lt;/p&gt;&lt;p&gt;Wow, so many articles in such a short amount of time! Yes, I&#39;m being facetious ;). Let&#39;s hope I can continue this pattern. Afterall, I started this blog 3 years ago to start writing down things I learn and which I&#39;d like not to forget.&lt;/p&gt;&lt;p&gt;Well, this blog post certainly fits the bill. I know I&#39;ve done some research on this once before, but I failed to write it down. So I wasted some more time re-researching this problem. What a waste. So, to help you not waste your time, I hope that you find this blog post helpful. Enough already, let&#39;s dive in!&lt;/p&gt;&lt;h3&gt;Extensible Markup Language &lt;samp&gt;NAME&lt;/samp&gt; Tokens&lt;/h3&gt;&lt;p&gt;I first learned eXtensible Markup Language (XML) back in 2000-something-or-other and haven&#39;t used it much. A lot of people use &lt;abbr title=&quot;Extensible Markup Language&quot;&gt;XML&lt;/abbr&gt; everywhere for anything. I&#39;m not a big believer in that, actually. It&#39;s a great tool and it makes sense to use it where and when it needs to be used.&lt;/p&gt;&lt;div style=&quot;background-color: white; float: left; margin-right: 1.5em; padding: 9px 0;&quot;&gt;&lt;a href=&quot;http://www.amazon.com/XML-Primer-Plus-Nicholas-Chase/dp/0672324229/ref=sr_1_1?ie=UTF8&amp;qid=1345831226&amp;sr=8-1&amp;keywords=XML+Primer+Plus&quot; title=&quot;XML Primer Plus on Amazon.com&quot;&gt;&lt;img src=&quot;http://ecx.images-amazon.com/images/I/4198XKEcvuL._SS500_.jpg&quot; style=&quot;width:100px; height: 100px;&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;Having said that, there have been 3 occassions over the last eight months where I had to brush up on my &lt;abbr title=&quot;Extensible Markup Language&quot;&gt;XML&lt;/abbr&gt; skills and really know it well. I&#39;ll put a shameless plug in for a book that, while old, has helped me tremendously (I haven&#39;t seen its equal): &lt;a href=&quot;http://www.amazon.com/XML-Primer-Plus-Nicholas-Chase/dp/0672324229/ref=sr_1_1?ie=UTF8&amp;qid=1345831226&amp;sr=8-1&amp;keywords=XML+Primer+Plus&quot; title=&quot;XML Primer Plus on Amazon.com&quot;&gt;XML Primer Plus by Nicholas Chase&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Like I said, the book is a bit dated now, but it still has very valuable information in it and not much has changed. Having said that, one thing that &lt;em&gt;has&lt;/em&gt; changed are the allowable characters in &lt;samp&gt;NMTOKEN&lt;/samp&gt;s. I recently needed to validate values I read from user input to ensure that they were in fact valid an &lt;code&gt;id&lt;/code&gt; attribute values. I na&amp;iuml;vely assumed the following regular expression:&lt;br /&gt;
&lt;div&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;if ( ... &amp;&amp; Regex.IsMatch(id, @&quot;^\\d.*|\\w*[\\p{P}-[_]]+.*$&quot;) { ... }
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, basically, a &lt;abbr title=&quot;Extensible Markup Language&quot;&gt;XML&lt;/abbr&gt; &lt;samp&gt;NMTOKEN&lt;/samp&gt; can have anything in it except punctuation characters (except for the underscore). I just realized as I&#39;m typing this that I completely forgot to check if the &lt;samp&gt;NMTOKEN&lt;/samp&gt; started with a number, which also isn&#39;t valid.&lt;/p&gt;&lt;p&gt;This &lt;em&gt;might&lt;/em&gt; have been fine back in 1999, but the &lt;abbr title=&quot;Extensible Markup Language&quot;&gt;XML&lt;/abbr&gt; standard has changed since then. It&#39;s still version 1.0 (well, there is a version 1.1, but let&#39;s not go there), but it&#39;s the 5&lt;sup&gt;th&lt;/sup&gt; edition.&lt;/p&gt;&lt;p&gt;The current &lt;abbr title=&quot;Extensible Markup Language&quot;&gt;XML&lt;/abbr&gt; specification &lt;a href=&quot;http://www.w3.org/TR/REC-xml/#NT-Name&quot; title=&quot;XML Name token definition&quot;&gt;defines&lt;/a&gt; a &lt;samp&gt;NAME&lt;/samp&gt; token (to which &lt;samp&gt;ID&lt;/samp&gt; tokens must adhere and which is a specialized form of a &lt;samp&gt;NMTOKEN&lt;/samp&gt; as follows:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;[Definition: A &lt;a href=&quot;http://www.w3.org/TR/REC-xml/#NT-Name&quot;&gt;Name&lt;/a&gt; is an &lt;a href=&quot;http://www.w3.org/TR/REC-xml/#NT-Nmtoken&quot;&gt;Nmtoken&lt;/a&gt; with a restricted set of initial characters.] Disallowed initial characters for &lt;a href=&quot;http://www.w3.org/TR/REC-xml/#NT-Name&quot;&gt;Names&lt;/a&gt; include digits, diacritics, the full stop and the hyphen.&lt;/p&gt;&lt;p&gt;Names beginning with the string &lt;samp&gt;&quot;xml&quot;&lt;/samp&gt;, or with any string which would match &lt;samp&gt;((&#39;X&#39;|&#39;x&#39;) (&#39;M&#39;|&#39;m&#39;) (&#39;L&#39;|&#39;l&#39;))&lt;/samp&gt;, are reserved for standardization in this or future versions of this specification.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/p&gt;&lt;p&gt;The Namespaces in XML Recommendation &lt;a href=&quot;http://www.w3.org/TR/REC-xml/#xml-names&quot;&gt;[XML Names]&lt;/a&gt; assigns a meaning to names containing colon characters. Therefore, authors should not use the colon in XML names except for namespace purposes, but XML processors must accept the colon as a name character.&lt;/p&gt;&lt;p&gt;The first character of a &lt;a href=&quot;http://www.w3.org/TR/REC-xml/#NT-Name&quot;&gt;Name&lt;/a&gt; &lt;span title=&quot;Keyword in RFC2119 context&quot;&gt;MUST&lt;/span&gt; be a &lt;a href=&quot;http://www.w3.org/TR/REC-xml/#NT-NameStartChar&quot;&gt;NameStartChar&lt;/a&gt;, and any other characters &lt;span title=&quot;Keyword in RFC2119 context&quot;&gt;MUST&lt;/span&gt; be &lt;a href=&quot;http://www.w3.org/TR/REC-xml/#NT-NameChar&quot;&gt;NameChars&lt;/a&gt;; this mechanism is used to prevent names from beginning with European (ASCII) digits or with basic combining characters. Almost all characters are permitted in names, except those which either are or reasonably could be used as delimiters. The intention is to be inclusive rather than exclusive, so that writing systems not yet encoded in Unicode can be used in XML names. See &lt;a href=&quot;http://www.w3.org/TR/REC-xml/#sec-suggested-names&quot;&gt;J Suggestions for XML Names&lt;/a&gt; for suggestions on the creation of names.&lt;/p&gt;&lt;p&gt;Document authors are encouraged to use names which are meaningful words or combinations of words in natural languages, and to avoid symbolic or white space characters in names. Note that COLON, HYPHEN-MINUS, FULL STOP (period), LOW LINE (underscore), and MIDDLE DOT are explicitly permitted.&lt;/p&gt;&lt;p&gt;The ASCII symbols and punctuation marks, along with a fairly large group of Unicode symbol characters, are excluded from names because they are more useful as delimiters in contexts where XML names are used outside XML documents; providing this group gives those contexts hard guarantees about what cannot be part of an XML name. The character #x037E, GREEK QUESTION MARK, is excluded because when normalized it becomes a semicolon, which could change the meaning of entity references.&lt;/p&gt;&lt;p&gt;&lt;i&gt;Names and Tokens&lt;/i&gt;&lt;/p&gt;&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Rule&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Production&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr style=&quot;vertical-align:top&quot;&gt;&lt;td&gt;&lt;pre&gt;[4]&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;NameStartChar&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;::=&lt;/pre&gt;&lt;/td&gt;&lt;td style=&quot;width: 20em;&quot;&gt;&lt;samp style=&quot;white-space:wrap-pre&quot;&gt;&quot;:&quot; | [A-Z] | &quot;_&quot; | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]&lt;/samp&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;vertical-align:top&quot;&gt;&lt;td&gt;&lt;pre&gt;[4a]&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;NameChar&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;::=&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;samp style=&quot;white-space:wrap-pre&quot;&gt;NameStartChar | &quot;-&quot; | &quot;.&quot; | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]&lt;/samp&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;vertical-align:top&quot;&gt;&lt;td&gt;&lt;pre&gt;[5]&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;Name&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre&gt;::=&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;samp style=&quot;white-space:wrap-pre&quot;&gt;NameStartChar (NameChar)*&lt;/samp&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/blockquote&gt;&lt;p&gt;At this point, I thought, &quot;No problem,&quot; I&#39;ll just use those productions in a Regular Expression while making sure the token doesn&#39;t start with &lt;samp&gt;xml&lt;/samp&gt; or some form of that thereof and that&#39;ll be that. During unit testing, I discovered that out of 29 invalid sequences that I tried (which were all in the ASCII portion, so this unit test was not comprehensive in any way for the time being), only 7 were flagged. What&#39;s going on here?&lt;/p&gt;&lt;p&gt;Well, I read the &lt;abbr title=&quot;Microsoft Developer Network&quot;&gt;MSDN&lt;/abbr&gt; documentation for .NET Regular Expressions. Here was the expression I used that was failing the unit test:&lt;/p&gt;&lt;div class=&quot;multiline&quot; title=&quot;Double-click to select for copying and pasting.&quot;&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;@&quot;^(?i:(?!xml))(?inx:[a-z]|_|:|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\u10000-\uEFFFF])(?inx:[a-z]|_|:|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\u10000-\uEFFFF]|-|\.|\d|\u00B7|[\u0300-\u036F]|[\u203F-\u2040])*$&quot;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, I must admit, .NET&#39;s Regular Expression syntax is a bit funky. Anyway, the &lt;samp&gt;(?i:(?!xml))&lt;/samp&gt; says if the string case-insensitively starts with &lt;samp&gt;XML&lt;/samp&gt;, then it doesn&#39;t match. Otherwise, use the production rules as shown above from the &lt;abbr title=&quot;World Wide Web Consortium&quot;&gt;W3C&lt;/abbr&gt;.&lt;/p&gt;&lt;p&gt;The catch is, .NET strings are encoded in UTF-16 (and therefore, the escape sequence &lt;samp&gt;\u&lt;/samp&gt; can only be followed by 4 hexadecimal digits), but according to the production  for a &lt;samp&gt;NameStartChar&lt;/samp&gt; I need to detect some characters outside of this range (the &lt;samp&gt;[\u10000-\uEFFFF]&lt;/samp&gt; character class inside of the Regular Expression). Now, I had done some research on internationalization and Unicode, but I never really had to pay much attention to it. I&#39;m the one who&#39;s mostly using my software. However, this is not the case this time. This software may be used by firms doing banking all over the country and aronud the world. So I definitely need to check that the ID string I&#39;m getting is valid. During my research, I came across &lt;a href=&quot;http://www.joelonsoftware.com/articles/Unicode.html&quot;&gt;Joel Spolsky&#39;s blog on Unicode and character encoding&lt;/a&gt;. This was a good start (and you should read this if you haven&#39;t already), but I needed to know more. Specifically, how can I encode a Unicode character that falls outside of the range 0 - 65535 into a 16-bit value?&lt;/p&gt;&lt;h3&gt;UTF-16 Surrogate Pairs&lt;/h3&gt;&lt;p&gt;The answer is UTF-16 surrogate pairs. I had heard of these, but I didn&#39;t know how to generate them. This &lt;a href=&quot;http://www.herongyang.com/Unicode/UTF-16-Paired-Surrogates.html&quot;&gt;article&lt;/a&gt; helped me out. In the UTF-16 character encoding, there are no UTF character code points defined in the range &lt;samp&gt;0xD800 - 0xDFFF&lt;/samp&gt;. This range is used in an algorithm to generate the UTF-16 surrogate pairs that represent Unicode character code points above 65535. The algorithm is really simple and is outlined below..&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Take the hex value of the Unicode character to encode as UTF-16 and subtract &lt;samp&gt;0x10000&lt;/samp&gt; from it.&lt;/li&gt;
&lt;li&gt;Take the result from step 1 above and shift it right 10 bits (&lt;samp&gt;0xA&lt;/samp&gt;).&lt;/li&gt;
&lt;li&gt;Take the result from step 2 and add &lt;samp&gt;0xD800&lt;/samp&gt;. This gives you the first surrogate of the surrogate pair.&lt;/li&gt;
&lt;li&gt;Again, taking the result from step 1, &lt;samp&gt;AND&lt;/samp&gt; the value with &lt;samp&gt;0x3FF&lt;/samp&gt; to mask off the upper 10 bits.&lt;/li&gt;
&lt;li&gt;Add &lt;samp&gt;0xDC00&lt;/samp&gt; to the result from step 4 above. This represents the second surrogate of the UTF-16 surrogate pair.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;The resulting 16-bit surrogates from above properly encode Unicode character code points above 65535 in UTF-16. Let&#39;s run through a quick examlpe.&lt;/p&gt;&lt;h4&gt;Enocding a Unicode Character Code Point Above 65535 into UTF-16&lt;/h4&gt;&lt;p&gt;Let&#39;s start with the Unicode character code point &lt;samp&gt;U+18657&lt;/samp&gt;. (I don&#39;t know what this character is, I just chose something at random.) Following our algorithm above:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;samp&gt;0x18657 - 0x10000 = 0x8657&lt;/samp&gt;&lt;/li&gt;
&lt;li&gt;&lt;samp&gt;0x8657 &gt;&gt; 0xA = 0x21&lt;/samp&gt;&lt;/li&gt;
&lt;li&gt;&lt;samp&gt;0x21 + 0xD800 = 0xD821&lt;/samp&gt; &lt;i&gt;(This is the first surrogate of the surrogate pair.)&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;0x8657 &amp; 0x3FF = 0x257&lt;/samp&gt;&lt;/li&gt;
&lt;li&gt;&lt;samp&gt;0x257 + 0xDC00 = 0xDE57&lt;/samp&gt; &lt;i&gt;(And this is the second surrogate of the surrogate pair.)&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;So, from the algorithm above, the Unicode character code point &lt;samp&gt;U+18657&lt;/samp&gt; can be encoded into UTF-16 using the surrogate pair &lt;samp&gt;U+D821 U+DE57&lt;/samp&gt;.&lt;/p&gt;&lt;h3&gt;Putting it All Together&lt;/h3&gt;&lt;p&gt;Finally, we come to the end. I needed to replace the character class &lt;samp&gt;[\u10000-\uEFFFF]&lt;/samp&gt; with a valid &lt;samp&gt;\u&lt;/samp&gt; escape sequence construct. That involves calculating the range of the surrogate pairs for the character class. I used the algorithm above to calculate the range of surrogate pairs which results in the following pattern that should be used to replace the invalid character class: &lt;code&gt;([\uD800-\uDB7F][\uDC00-\uDFFF])&lt;/code&gt;. This pattern will match all UTF-16 encoded Unicode character code points between the range of &lt;samp&gt;U+10000 - U+EFFFF&lt;/samp&gt;, which is exactly what we want. Here&#39;s the final Regular Expression that will validate an XML &lt;samp&gt;ID&lt;/samp&gt; token:&lt;/p&gt;&lt;p&gt;&lt;div class=&quot;multiline&quot; title=&quot;Double-click to select for copying and pasting.&quot;&gt;&lt;pre class=&quot;brush: csharp&quot;&gt;@&quot;^(?i:(?!xml))(?inx:[a-z]|_|:|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|([\uD800-\uDB7F][\uDC00-\uDFFF]))(?inx:[a-z]|_|:|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|([\uD800-\uDB7F][\UDC00-\uDFFF])|-|\.|\d|\u00B7|[\u0300-\u036F]|[\u203F-\u2040])*$&quot;
&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;h3&gt;A Few Closing Remarks&lt;/h3&gt;&lt;p&gt;Firstly, the second and third Regular Expressions shown in this article could be simplified (e.g. getting rid of all the alternation (&lt;samp&gt;|&lt;/samp&gt;) constructs between character classes and creating one big character class). Second, and most important, this probably isn&#39;t &lt;em&gt;exactly&lt;/em&gt; what you should normally do. The productions given by the &lt;abbr title=&quot;World Wide Web Consortium&quot;&gt;W3C&lt;/abbr&gt; are meant to be inclusive, as they noted for their justification of the productions. But it would probably be more efficient to write a Regular Expression that matches on what &lt;em&gt;should not&lt;/em&gt; be present in a &lt;abbr title=&quot;Extensible Markup Language&quot;&gt;XML&lt;/abbr&gt; &lt;samp&gt;ID&lt;/samp&gt; token (though, the Regular Expression would be almost as long and complex).&lt;/p&gt;&lt;p&gt;I did test my final Regular Expression as shown above, and it did pass (again, my unit test was not comprehensive with regards to characters outside the 7-bit ASCII character set). However, since I used the production shown in the &lt;abbr title=&quot;Extensible Markup Language&quot;&gt;XML&lt;/abbr&gt; specification, I have no reason to think that this Regular Expression would not let an invalid &lt;samp&gt;ID&lt;/samp&gt; token &amp;quot;slip&amp;quot; through.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2012/08/net-regular-expressions-and-xml-name.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-2411390085250644540</guid><pubDate>Wed, 22 Aug 2012 20:13:00 +0000</pubDate><atom:updated>2013-01-19T20:47:07.257-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Visual Studio</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio Extensions</category><category domain="http://www.blogger.com/atom/ns#">VS2010</category><category domain="http://www.blogger.com/atom/ns#">VS2012</category><title>Updating a Visual Studio 2010 Extension for Visual Studio 2012</title><description>&lt;div style=&quot;display:none&quot;&gt;&lt;!--[if IE]&gt;&lt;br /&gt;
&lt;style&gt;.vsCode { margin-right: 1em; }&lt;/style&gt;&lt;br /&gt;
&lt;![endif]--&gt;&lt;br /&gt;
&lt;/div&gt;&lt;h4&gt;UPDATE - 16 January 2013&lt;/h4&gt;&lt;p style=&quot;color:#f0f0f0&quot;&gt;&lt;b&gt;The contents of this article have been updated to correct a problem that existed at the time of publication. In addition, I have uploaded this updated Visual Studio extension to the &lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/43bc4a3a-0182-4c36-8159-a0a4cdfd04bd&quot;&gt;Visual Studio Gallery&lt;/a&gt;.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Hello everyone. It&#39;s been way too long. It seems I&#39;m always doing this and that and never have time to write down anything, anywhere&amp;mdash;whether that be on this blog, or on Facebook. But today, I have something special for those of you who have that favorite Visual Studio 2010 Extension that they just can&#39;t live without, but it hasn&#39;t been updated for Visual Studio 2012.&lt;/p&gt;&lt;p&gt;In order to update the extension, you will need access to the extension&#39;s source code; so these instructions will have limited impact for most of you out there unless you can get your hands on the source code for that favorite extension.&lt;/p&gt;&lt;p&gt;Fortunately for me, the author of my favorite extension, AllMargins, did post his &lt;a href=&quot;http://archive.msdn.microsoft.com/OverviewMargin/Release/ProjectReleases.aspx?ReleaseId=3957&quot; title=&quot;AllMargins source code&quot;&gt;source code&lt;/a&gt;, especially since this extension is no longer available from the &lt;a href=&quot;http://www.visualstudiogallery.com/&quot; title=&quot;Visual Studio Gallery&quot;&gt;Visual Studio Gallery&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Install the Visual Studio 2012 and 2012 &lt;abbr title=&quot;Software Development Kits&quot;&gt;SDKs&lt;/abbr&gt;&lt;/h3&gt;&lt;div style=&quot;float: left&quot;&gt;&lt;a href=&quot;http://www.microsoftstore.com/store/msstore/pd/Visual-Studio-Professional-2012-with-MSDN/productID.252988900/catID.44066800/parentCategoryID.50804600/categoryID.50804700/list.true&quot;&gt;&lt;img alt=&quot;Get Visual Studio Professional 2012 with MSDN from the Microsoft Store&quot; src=&quot;//dri1.img.digitalrivercontent.net/DRHM/Storefront/Company/msstore/images/software/pdp/en-US_Visual_Studio_Pro_2012_MSDN_79D-00276.jpg&quot; style=&quot;width:140px; padding-right: 1em;&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;In order to author extensions for Visual Studio, one must have the Visual Studio &lt;abbr title=&quot;Software Development Kit&quot;&gt;SDK&lt;/abbr&gt; installed. The same is true  for modifying them. If you don&#39;t already have it installed, go out and download it and install it.&lt;br /&gt;
&lt;/p&gt;&lt;h3&gt;Prepare the Source Code for Visual Studio 2012&lt;/h3&gt;&lt;p&gt;If you want to maintain backward compatibility for the extension, it would be best &lt;i&gt;not&lt;/i&gt; to open the original Visual Studio 2010 solution in Visual Studio 2012. That&#39;s because Visual Studio Extension projects for Visual Studio 2010 are not compatible with Visual Studio 2012. Well, that&#39;s not exactly true. The real truth is that the VSIX manifest XML schema has changed between Visual Studio 2010 and Visual Studio 2012. The old schema still works for Visual Studio 2012, but Microsoft would have you use the new schema going forward. The problem is, if you use the new schema, you won&#39;t be able to use the extension in Visual Studio 2010. Don&#39;t worry though, Visual Studio 2012 will &lt;i&gt;not&lt;/i&gt; upgrade the schema, just the project file(s); but in doing so, the projects will no longer open in Visual Studio 2010.&lt;/p&gt;&lt;p&gt;Why should you care? Well, for one, testing. You can&#39;t simply instruct VsixInstaller to install the extension to an experimental instance of Visual Studio, unfortunately. That really makes it hard to test the extension for more than one version of Visual Studio. Even so, you really should be testing your extension on a virtual machine with the installed version of Visual Studio to test it with &lt;i&gt;and&lt;/i&gt; which does &lt;i&gt;not&lt;/i&gt; have the Visual Studio SDK installed. If the Visual Studio SDK is installed on your test machine, your extension will always work but, you may find that it doesn&#39;t work users who don&#39;t have the Visual Studio SDK installed. Your extension should not explicitly require the Visual Studio SDK be installed (unless you&#39;re writing a Visual Studio Extension project template! Lol...).&lt;/p&gt;&lt;p&gt;If you want to be able to develop and test in both Visual Studio 2010 and Visual Studio 2012 on the same machine, here&#39;s my suggestion.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Create a new empty solution called &amp;lt;Your Extension&amp;gt;.2012 in the same place as the original solution.&lt;/li&gt;
&lt;li&gt;Open Windows Explorer to the location of one of the projects that are in the Visual Studio 2010 solution.&lt;ol&gt;&lt;li&gt;Select the project file and copy and paste it into the same folder. The file will be renamed &amp;apos;Copy of &amp;lt;Your Project File&amp;gt;.csproj&amp;apos; (or .vbproj, if you use Visual Basic). Rename the file to &amp;lt;Your Project File&amp;gt;.2012.csproj.&lt;/li&gt;
&lt;li&gt;Back in Visual Studio 2012, add &amp;lt;Your Project File&amp;gt;.csproj to your solution.&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;Add all the files that are part of the Visual Studio 2010 project to the newly created Visual Studio 2012 project.&lt;/li&gt;
&lt;li&gt;Repeat these steps for each of the other projects that were part of the original Visual Studio 2010 solution.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Now you can work on the source code in both Visual Studio 2010 and Visual Studio 2012, opening the respective solution for the version of Visual Studio you&#39;re using to make changes. When you build the Visual Studio 2012 solution, it will be deployed to the Visual Studio 2012 experimental instance. The same is true for 2010, the extension will be deployed to the Visual Studio 2010 experimental instance. Also, it allows you to work on a single code-base that should work in both environments so long as you don&#39;t use features exclusive to Visual Studio 2012.&lt;/p&gt;&lt;p&gt;While upgrading this extension to work with Visual Studio 2012, I discovered that there is an enumeration value in the VSIX XML schema for specifying the Express editions of Visual Studio. However, the only &quot;extensions&quot; that Express SKUs support are project/item template extensions.&lt;/p&gt;&lt;p&gt;We&#39;re now ready to start modifying the various files to make this extension compatible with Visual Studio 2012!&lt;/p&gt;&lt;h3&gt;Update the &lt;samp&gt;*.vsixmanifest&lt;/samp&gt; file&lt;/h3&gt;&lt;p&gt;The first order of business in updating the extension is to modify the &lt;samp&gt;*.vsixmanifest&lt;/samp&gt; file. Here&#39;s an example of one of the files from the AllMargins.vsix extension:&lt;/p&gt;&lt;div title=&quot;Double-click to select code for copying and pasting.&quot;&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&amp;lt;Vsix xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot; Version=&quot;1.0.0&quot; xmlns=&quot;http://schemas.microsoft.com/developer/vsx-schema/2010&quot;&gt;
    &amp;lt;Identifier Id=&quot;SettingsStore.dpugh.ce3ce74a-4966-4a66-b9ad-a3adf4f9e940&quot;&gt;
        &amp;lt;Name&gt;SettingsStore&amp;lt;/Name&gt;
        &amp;lt;Author&gt;dpugh&amp;lt;/Author&gt;
        &amp;lt;Version&gt;1.2&amp;lt;/Version&gt;
        &amp;lt;Description xml:space=&quot;preserve&quot;&gt;This defines an API for persisting IEditorOptions across sessions.&amp;lt;/Description&gt;
        &amp;lt;Locale&gt;1033&amp;lt;/Locale&gt;
        &amp;lt;MoreInfoUrl&gt;http://code.msdn.microsoft.com/OverviewMargin/Release/ProjectReleases.aspx?ReleaseId=3957&amp;lt;/MoreInfoUrl&gt;
        &amp;lt;SupportedProducts&gt;
            &amp;lt;VisualStudio Version=&quot;10.0&quot;&gt;
                &amp;lt;Edition&gt;Ultimate&amp;lt;/Edition&gt;
                &amp;lt;Edition&gt;Premium&amp;lt;/Edition&gt;
                &amp;lt;Edition&gt;Pro&amp;lt;/Edition&gt;
            &amp;lt;/VisualStudio&gt;
        &amp;lt;/SupportedProducts&gt;
        &amp;lt;SupportedFrameworkRuntimeEdition MinVersion=&quot;4.0&quot; MaxVersion=&quot;4.0&quot; /&gt;
    &amp;lt;/Identifier&gt;
    &amp;lt;References /&gt;
    &amp;lt;Content&gt;
        &amp;lt;MefComponent&gt;|%CurrentProject%|&lt;/MefComponent&gt;

    &amp;lt;/Content&gt;
&amp;lt;/Vsix&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You need to update the &lt;code&gt;SupportedProducts&lt;/code&gt; and &lt;code&gt;SupportedFrameworkRuntimeEdition&lt;/code&gt; elements as follows:&lt;/p&gt;&lt;div title=&quot;Double-click to select code for copying and pasting.&quot;&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;SupportedProducts&amp;gt;
  &amp;lt;VisualStudio Version=&quot;10.0&quot;&amp;gt;
    &amp;lt;Edition&amp;gt;Utimate&amp;lt;/Edition&amp;gt;
    &amp;lt;Edition&amp;gt;Premium&amp;lt;/Edition&amp;gt;
    &amp;lt;Edition&amp;gt;Pro&amp;lt;/Edition&amp;gt;
  &amp;lt;/VisualStudio&amp;gt;
  &amp;lt;VisualStudio Version=&quot;11.0&quot;&amp;gt;
    &amp;lt;Edition&amp;gt;Utimate&amp;lt;/Edition&amp;gt;
    &amp;lt;Edition&amp;gt;Premium&amp;lt;/Edition&amp;gt;
    &amp;lt;Edition&amp;gt;Pro&amp;lt;/Edition&amp;gt;
  &amp;lt;/VisualStudio&amp;gt;
&amp;lt;/SupportedProducts&amp;gt;
&amp;lt;SupportedFrameworkRuntimeEdition MinVersion=&quot;4.0&quot; /&amp;gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By removing the &lt;samp&gt;MaxVersion&lt;/samp&gt; attribute for the &lt;samp&gt;SupportedFrameworkRuntimeEdition&lt;/samp&gt; element, we&#39;re telling Visual Studio that so long as the machine supports the .NET Framework 4.0, the extension can be used.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Also for good measure, I updated the &lt;code&gt;Version&lt;/code&gt; value (e.g. 1.3) and updated the &lt;code&gt;Description&lt;/code&gt; element noting that I changed the VSIX package and it is not the original. As an aside, every time you make a change to the extension that you wish to distribute, you must increment the value for the &lt;samp&gt;Version&lt;/samp&gt; element.&lt;/p&gt;&lt;p&gt;Now I ran across a tricky problem with updating the AllMargins extension. This extension has several &quot;sub-extensions&quot; that are contained within the AllMargins extension itself. And some of these &quot;sub-extensions&quot; have yet other &quot;sub-extensions&quot;. The long and short is, during testing, Visual Studio had a problem locating some of the required &lt;abbr title=&quot;Dynamic Link Libraries&quot;&gt;DLLs&lt;/abbr&gt;.&lt;/p&gt;&lt;p&gt;What I found out is that some of the sub-extension projects contained an additional file&amp;mdash;a &lt;samp&gt;*.pkgdef&lt;/samp&gt; file. This is an older file that was used with VSPackages back in the VSI days of Visual Studio 2005/2008. This file is not much unlike a &lt;samp&gt;*.reg&lt;/samp&gt; file, though with a slightly different syntax.&lt;/p&gt;&lt;p&gt;This file for the SettingsStore sub-extension (for which the VSIX manifest file was shown above) looks like this:&lt;/p&gt;&lt;pre&gt;[$RootKey$\BindingPaths\{8ADD56CC-E512-4CB0-AF58-33ECCC0B4912}]
&quot;$PackageFolder$&quot;=&quot;&quot;
&lt;/pre&gt;&lt;p&gt;This creates the &lt;abbr title=&quot;Globally Unique Identifier&quot;&gt;GUID&lt;/abbr&gt; under HKCU\Software\Microsoft\VisualStudio\&amp;lt;Maj. Version Num&amp;gt;_Config\BindingPaths key. &lt;samp&gt;$PackageFolder$&lt;/samp&gt; expands to the folder where the extension was installed by VSIXInstaller.&lt;/p&gt;&lt;p&gt;Apparently, in Visual Studio 2010, just placing this file within your VSIX package was enough for Visual Studio to go ahead and create the requisite registry keys and values. However, this does not work with Visual Studio 2012 and attempts to use extensions relying on this extension result in a &lt;code&gt;System.IO.FileNotFoundException&lt;/code&gt;. In order to resolve this issue, you must place some additional content in your VSIX manifest file as shown below.&lt;/p&gt;&lt;div title=&quot;Double-click to select code for copying and pasting.&quot;&gt;&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;References&amp;gt;
    &amp;lt;Reference Id=&quot;Microsoft.VisualStudio.MPF&quot; MinVersion=&quot;10.0&quot; /&amp;gt;
        &amp;lt;Name&amp;gt;Visual Studio MPF&amp;lt;/Name&amp;gt;
    &amp;lt;/Reference&amp;gt;
    &amp;lt;!-- Any other references you may have --&amp;gt;
&amp;lt;/References&amp;gt;
&amp;lt;Content&amp;gt;
    &amp;lt;MefComponent&amp;gt;|%CurrentProject%|&amp;lt;/MefComponent&amp;gt;&amp;lt;!-- Expands to the assembly name --&amp;gt;
    &amp;lt;VsPackage&amp;gt;SettingsStore.pkgdef&amp;lt;/VsPackage&amp;gt;&amp;lt;!-- Not required by VS2010, but is required by VS2012 in order for the file to be processed --&amp;gt;
&amp;lt;/Content&amp;gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With all of that out of the way, save the file and we&#39;re done with the &lt;samp&gt;*.vsixmanifest&lt;/samp&gt; file. If there are several VSIX extensions that make up the extension you&#39;re updating (as is the case for AllMargins.vsix), you will need to do this for each &lt;samp&gt;*.vsixmanifest&lt;/samp&gt; file in the solution.&lt;/p&gt;&lt;p&gt;At this point, at the original date of publication (22 August 2012), I had you retarget the projects in the solution and replace some DLL references. If you want to maintain compatibility with Visual Studio 2010, this is not necessary. So I have removed that section of the original blog entry.&lt;/p&gt;&lt;h3&gt;Recompile a Debug Build&lt;/h3&gt;&lt;p&gt;You should now recompile the solution using a Debug build. This will automatically install the extension(s) into the Visual Studio experimental instance(i.e. it won&#39;t muck up your Visual Studio that you use for everyday coding). Make sure that everything works correctly. If all is well, you&#39;re ready for the final step.&lt;/p&gt;&lt;h3&gt;Recompile in Release Mode&lt;/h3&gt;&lt;p&gt;If your testing above went OK, then change the build mode from Debug to Release and recompile. Then simply navigate to the &lt;samp&gt;bin\Release&lt;/samp&gt; directory under the project folder for the extension and double-click the VSIX file to install it.&lt;/p&gt;&lt;p&gt;Now, in this case, I was not required to change a single line of code. This may not be the case for every extension you wist to upgrade. &lt;abbr title=&quot;Your mileage may vary.&quot;&gt;YMMV&lt;/abbr&gt;.&lt;/p&gt;&lt;h3&gt;Enjoy using Visual Studio 2012&lt;/h3&gt;&lt;p&gt;That&#39;s it! Enjoy using Visual Studio 2012 with your beloved extension.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2012/08/updating-visual-studio-2010-extension.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-5097712636640402356</guid><pubDate>Wed, 21 Jul 2010 00:34:00 +0000</pubDate><atom:updated>2012-09-04T22:24:57.492-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">book</category><category domain="http://www.blogger.com/atom/ns#">books</category><category domain="http://www.blogger.com/atom/ns#">microformats</category><category domain="http://www.blogger.com/atom/ns#">proposal</category><category domain="http://www.blogger.com/atom/ns#">title</category><category domain="http://www.blogger.com/atom/ns#">titles</category><title>Sample Title Marked up Using x-hTitle Microformat Proposal</title><description>&lt;p&gt;This blog entry will demonstrate using the proposed &lt;tt&gt;x-hTitle&lt;/tt&gt; microformat to mark up a title. Since this is a sample for a microformat proposal, what better title to use than the one that I first read regarding the subject. So, without further adieu, here&#39;s a sample. One other quick note: I may edit this blog entry from time-to-time, adding more samples. Eventually, they will all be moved to the &lt;span class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; rel=&quot;home&quot; href=&quot;http://www.microformats.org&quot;&gt;microformats.org&lt;/a&gt;&lt;/span&gt; site &lt;em&gt;if&lt;/em&gt; this proposal becomes a draft specification.&lt;/p&gt;&lt;h4&gt;Sample &lt;tt&gt;x-hTitle&lt;/tt&gt; Formatted Title&lt;/h4&gt;&lt;div style=&quot;background-color:#303030;border:2px solid black;margin:1em 1.5em;padding:0 1.5em; color: white important;&quot;&gt;  &lt;div class=&quot;x-htitle&quot;&gt;    &lt;h5 class=&quot;fn&quot; 
        style=&quot;font-family:Verdana,Arial,Helvetica,Univers,San-Serif;font-size:1.25em;&quot;&gt;      &lt;a class=&quot;url&quot; 
         href=&quot;http://www.friendsofed.com/book.html?isbn=9781590598146&quot;
         rel=&quot;home&quot;&gt;         Microformats: Empowering Your Markup for Web 2.0       &lt;/a&gt;     &lt;/h5&gt;&lt;div class=&quot;authors&quot;&gt;      &lt;span id=&quot;vcard-JohnAllsopp&quot; class=&quot;contributor vcard&quot;&gt;         &lt;b&gt;&lt;span class=&quot;role&quot;&gt;Author&lt;/span&gt;:&lt;/b&gt;          &lt;a class=&quot;fn url&quot; rel=&quot;home&quot; href=&quot;http://www.microformatique.com&quot;&gt;           John Allsopp         &lt;/a&gt;       &lt;/span&gt;     &lt;/div&gt;&lt;div class=&quot;contributor vcard&quot;&gt;      &lt;b&gt;&lt;span class=&quot;role&quot;&gt;Publisher&lt;/span&gt;:&lt;/b&gt;       &lt;a class=&quot;fn org url&quot; rel=&quot;home&quot; href=&quot;http://www.friendsofed.com&quot;&gt;         friends of ED       &lt;/a&gt;     &lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;font-weight:bold&quot;&gt;Edition:&lt;/span&gt;       &lt;span class=&quot;edition&quot; title=&quot;1&quot;&gt;First Edition&lt;/span&gt;     &lt;/div&gt;&lt;div class=&quot;description&quot;&gt;      &lt;h6&gt;Abstract&lt;/h6&gt;&lt;p&gt;        Microformats burst onto the scene a couple of years ago and are fast         becoming an essential tool for all professional web designers and          developers. Imagine being able to integrate all of yourr web-based contact          details, tagged articles, and geographical information seamlessly in web          and desktop applications, without having to add anything extra to your          websites except a little specialized &lt;abbr title=&quot;Hypertext Markup 
        Language&quot;&gt;HTML&lt;/abbr&gt; markup.       &lt;/p&gt;&lt;p&gt;        Microformats provide a more formalized technology for adding commonly used          semantics (such as contact details, locations, and reviews) to today&#39;s Web.          Unlike &lt;abbr title=&quot;Extensible Markup Language&quot;&gt;XML&lt;/abbr&gt; or the Semantic          Web, microformats use ubiquitous technologies like         &lt;abbr title=&quot;Hypertext Markup Language&quot;&gt;HTML&lt;/abbr&gt; and          &lt;abbr title=&quot;Extensible Hypertext Markup Language&quot;&gt;XHTML&lt;/abbr&gt;, existing         developer skills and current web tools, and, perhaps most important, they          all work in today&#39;s web browsers.       &lt;/p&gt;&lt;p&gt;        This book is a comprehensive guide to microformats. It explores why, in          Bill Gates&#39; words, &lt;q&gt;We need microformats&lt;/q&gt;; how microformats work; and          the kinds of problems microformats help solve. The book covers every          current microformat, with complete details of the syntax, semantics, and          uses of each, along with real-world examples and a comprehensive survey of          the tools available for working with them. The book also features case          studies detailing how major web content publishers such as Yahoo! put          microformats to work in their web applications.       &lt;/p&gt;&lt;p&gt;        Written by one of the Web&#39;s best-known educators,          &lt;a class=&quot;include&quot; href=&quot;#vcard-JohnAllsopp&quot;&gt;John Allsopp&lt;/a&gt;,         &lt;span style=&quot;text-decoration:underline&quot;&gt;           Microformats: Empowering Your Markup for Web 2.0         &lt;/span&gt;         will help you painlessly get up to speed with this exciting technology.       &lt;/p&gt;&lt;h6&gt;In this Book You&#39;ll Learn...&lt;/h6&gt;&lt;ul&gt;&lt;li&gt;           How to take best advantage of the built-in semantics of            &lt;abbr title=&quot;Extensible Hypertext Markup Language&quot;&gt;XHTML&lt;/abbr&gt; and            &lt;abbr title=&quot;Hypertext Markup Language&quot;&gt;HTML&lt;/abbr&gt;.         &lt;/li&gt;
&lt;li&gt;           How to extend the semantics of HTML using microformats and open up a world           of new possibilities with web applications.         &lt;/li&gt;
&lt;li&gt;Every aspect of all the common microformats currently in use.&lt;/li&gt;
&lt;li&gt;           How microformats help your websites and applications easily integrate            with web applications like Google Maps, as well as desktop applications            like iCal, Outlook, and Entourage.         &lt;/li&gt;
&lt;li&gt;           What innovative publishers and services, big and small, are doing right            now with microformats.         &lt;/li&gt;
&lt;/ul&gt;&lt;h6&gt;Summary of Contents&lt;/h6&gt;&lt;ul style=&quot;font-variant:small-caps;&quot;&gt;&lt;li&gt;           Part One: Introducing Microformats           &lt;ul style=&quot;font-variant:normal;font-variant:none;&quot;&gt;&lt;li&gt;Chapter 1: What are Microformats?&lt;/li&gt;
&lt;li&gt;Chapter 2: The State of the Art in Microformats&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li style=&quot;font-variant:small-caps;&quot;&gt;           Part Two: Using Microformats           &lt;ul style=&quot;font-variant:normal;font-variant:none;&quot;&gt;&lt;li&gt;               Chapter 3: Structural and Semantic               &lt;abbr title=&quot;Hypertext Markup Language&quot;&gt;HTML&lt;/abbr&gt;             &lt;/li&gt;
&lt;li&gt;               Chapter 4: Link-Based Microformats: &lt;tt&gt;rel-license&lt;/tt&gt;,               &lt;tt&gt;rel-tag&lt;/tt&gt;, &lt;tt&gt;rel-nofollow&lt;/tt&gt;, and &lt;tt&gt;VoteLinks&lt;/tt&gt;.             &lt;/li&gt;
&lt;li&gt;               Chapter 5: Microformat to Describe Relationships Between People:                &lt;abbr title=&quot;Extensible Hypertext Markup Language Friends Network&quot;&gt;                 XFN               &lt;/abbr&gt;             &lt;/li&gt;
&lt;li&gt;Chapter 6: Location Microformats: &lt;tt&gt;geo&lt;/tt&gt; and &lt;tt&gt;adr&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Chapter 7: Contact Information Microformat: &lt;tt&gt;hCard&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Chapter 8: Event Microformat: &lt;tt&gt;hCalendar&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;               Chapter 9: Review and Resume Microformats: &lt;tt&gt;hReview&lt;/tt&gt; and                &lt;tt&gt;hResume&lt;/tt&gt;             &lt;/li&gt;
&lt;li&gt;Chapter 10: Syndicated Content Microformat: &lt;tt&gt;hAtom&lt;/tt&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li style=&quot;font-variant:small-caps;&quot;&gt;           Part Three: Case Studies           &lt;ul style=&quot;font-variant:normal;font-variant:none;&quot;&gt;&lt;li&gt;Chapter 11: Case Study: Cork&#39;d&lt;/li&gt;
&lt;li&gt;Chapter 12: Case Study: Yahoo!&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;           Part Four: Developing Microformats           &lt;ul style=&quot;font-variant:normal;font-variant:none;&quot;&gt;&lt;li&gt;Chapter 13: The Process of Developing Microformats&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;           Part Five: Appendixes           &lt;ul style=&quot;font-variant:normal;font-variant:none;&quot;&gt;&lt;li&gt;Appendix A: Microformat Specification Reference&lt;/li&gt;
&lt;li&gt;Appendix B: Microformat Design Patterns&lt;/li&gt;
&lt;li&gt;Appendix C: People, Tools, Services, and Publishers&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://discoveringcode.blogspot.com/2010/07/sample-title-marked-up-using-x-htitle.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-5363578285720938393</guid><pubDate>Wed, 21 Jul 2010 00:32:00 +0000</pubDate><atom:updated>2010-07-20T20:32:45.850-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">book</category><category domain="http://www.blogger.com/atom/ns#">books</category><category domain="http://www.blogger.com/atom/ns#">microformats</category><category domain="http://www.blogger.com/atom/ns#">proposal</category><category domain="http://www.blogger.com/atom/ns#">title</category><category domain="http://www.blogger.com/atom/ns#">titles</category><title>A New Microformat Propoal: x-hTitle</title><description>&lt;h4&gt;Comments Regarding the Proposed &lt;tt&gt;x-hTitle&lt;/tt&gt; Pre-Draft Specification&lt;/h4&gt;

&lt;p&gt;This blog post is meant to document my vision of a microformat for semantically marking up information about titles. On the &lt;a href=&quot;http://www.microformats.org/wiki/process&quot;&gt;microformats.org process&lt;/a&gt; page, it is recommended that you not name your new proposed format &lt;tt&gt;h&lt;i&gt;something&lt;/i&gt;&lt;/tt&gt;. But, since this is a proposed pre-draft specification, I need to be able to reference something throughout this specification. Therefore, I am naming this proposed format &lt;tt&gt;x-hTitle&lt;/tt&gt;, where &lt;tt&gt;x&lt;/tt&gt; stands for experimental. If there is interest in developing this microformat further, the &lt;tt&gt;x&lt;/tt&gt; in the name could be removed. In addition, the name of the proposed microformat could change according to community consensus during the specification process.&lt;/p&gt;

&lt;h4&gt;The &lt;tt&gt;x-hTitle&lt;/tt&gt; Proposed Pre-Draft Specification&lt;/h4&gt;

&lt;h5&gt;Editor/Author&lt;/h5&gt;

&lt;ul&gt;&lt;li&gt;Craig S&lt;/li&gt;&lt;/ul&gt;

&lt;h5&gt;Contributors&lt;/h5&gt;

&lt;p&gt;None yet. If you would like to contribute, please register on the &lt;span id=&quot;vcard-microformats&quot; class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; href=&quot;http://www.microformats.org&quot;&gt;microformats.org&lt;/a&gt;&lt;/span&gt;&#39;s microformats-new mailing list and read posts regarding this proposal and contribute your thoughts and suggestions. If this proposal gets the green light to become a draft specification, you can contribute to the specification at the &lt;a class=&quot;include&quot; href=&quot;http://www.blogger.com/post-create.g?blogID=5841632161546703012#vcard-microformats&quot;&gt;microformats.org&lt;/a&gt;&#39;s website and your name will be listed in this section of the specification.&lt;/p&gt;

&lt;h5&gt;Introduction&lt;/h5&gt;

&lt;p&gt;It is difficult for a browser to extract semantic information about a book title described on a web page. Metadata such as author, cover image, and book genres/categories provide relevant content for titles.&lt;/p&gt;

&lt;p&gt;In order to keep this microformat as generic as possible, I want to make a distinction between &lt;em&gt;titles&lt;/em&gt; and &lt;em&gt;books&lt;/em&gt;. A &lt;b&gt;title&lt;/b&gt; is something than an author writes. A &lt;b&gt;book&lt;/b&gt; is a published &lt;em&gt;representation&lt;/em&gt; of a title. There may be more than one book for a given title, for example, a hardcover book, a paperback book, a large-print or illustrated book, etc. Each of these books will have a different &lt;abbr title=&quot;International Standards Book Number&quot;&gt;ISBN&lt;/abbr&gt; even though they are the same title.&lt;/p&gt;

&lt;p&gt;This microformat aims to codify the semantic structured markup of titles. Since a title can describe (possibly) many books, semantically marking up title information has one very important implication: a title which contains reviews (using the &lt;a href=&quot;http://www.microformats.org/wiki/hReview&quot;&gt;hReview&lt;/a&gt; or the &lt;a href=&quot;http://www.microformats.org/wiki/hReview-aggregate&quot;&gt;hReview-aggregate&lt;/a&gt; microformat) may have all reviews for it aggregated in one place. This aggregation may then be used to display this information for several books (e.g. the same reviews would be shown for a hardcover, softcover, or other formats of a title) because they are all for the same title.&lt;/p&gt;

&lt;p&gt;Having such information marked up can provide many benefits to the viewer of such a page. If a web browser understands that a particular web page contains a title, it can provide rich interactions for the user—for example, specific searches for titles via search services such as &lt;span class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; rel=&quot;home&quot; href=&quot;http://www.googe.com/&quot;&gt;Google&lt;/a&gt;&lt;/span&gt;, &lt;span id=&quot;vcard-Amazon&quot; class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; rel=&quot;home&quot; href=&quot;http://www.amazon.com/&quot;&gt;Amazon&lt;/a&gt;&lt;/span&gt;, &lt;span class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; rel=&quot;home&quot; href=&quot;http://www.yahoo.com/&quot;&gt;Yahoo!&lt;/a&gt;&lt;/span&gt;, &lt;span class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; ref=&quot;home&quot; href=&quot;http://www.bing.com/&quot;&gt;Bing&lt;/a&gt;&lt;/span&gt;, etc. While &lt;a class=&quot;include&quot; href=&quot;http://www.blogger.com/post-create.g?blogID=5841632161546703012#vcard-Amazon&quot;&gt;Amazon&lt;/a&gt; already does a good job of returning search results for titles (since that is its primary business) and searches for titles on major search engines usually yield a link to &lt;a class=&quot;include&quot; href=&quot;http://www.blogger.com/post-create.g?blogID=5841632161546703012#vcard-Amazon&quot;&gt;Amazon&lt;/a&gt;, marking up titles using a microformat can make indexing title information easier while making this information more accessible to users. In addition, classification of titles by search engines (and crawlers) can be made more accurate. Also, if a page contains many titles by the same author(s), then the web page is not only a list of titles, but also about a particular author(s).&lt;/p&gt;

&lt;p&gt;In order to enable and encourage the sharing, distribution, syndication, and aggregation of title content and information, the author proposes a pre-draft specification of a &lt;tt&gt;x-hTitle&lt;/tt&gt; microformat, an open standard for distributed metadata about titles. The author has researched numerous sites which contain titles for sale or advertisement and has designed the &lt;tt&gt;x-hTitle&lt;/tt&gt; microformat around a simple, minimal schema for information regarding a particular title. Feedback is encouraged on this blog entry. If there is enough interest in this pre-draft specification to warrant making a sanctioned draft specification of this microformat, future feedback will be moved to the official &lt;a class=&quot;include&quot; href=&quot;http://www.blogger.com/post-create.g?blogID=5841632161546703012#vcard-microformats&quot;&gt;microformats.org&lt;/a&gt; website.&lt;/p&gt;

&lt;h5&gt;Inspiration and Acknowledgements&lt;/h5&gt;

&lt;p&gt;This proposal came about because of reading the book &lt;span class=&quot;x-htitle&quot;&gt;&lt;a class=&quot;fn url&quot; href=&quot;http://www.amazon.com/dp/1590598146&quot;&gt;Microformats: Empowering Your Markup for web 2.0&lt;/a&gt; by &lt;span class=&quot;author vcard&quot;&gt;&lt;a class=&quot;fn url&quot; href=&quot;http://www.microformatique.com/&quot;&gt;John Allsopp&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; (note: the book&#39;s title has been marked up using this very proposed microformat) and my need to create an inventory system for all media that I own, including &lt;abbr title=&quot;Compact Disc&quot;&gt;CD&lt;/abbr&gt;s, &lt;abbr title=&quot;Digital Video Disc&quot;&gt;DVD&lt;/abbr&gt;s, books (again, a specific representation of a title), magazines, and anything else media related. As there already exists a &lt;a href=&quot;http://www.microformats.org/wiki/hAudio&quot;&gt;hAudio&lt;/a&gt; and &lt;a href=&quot;http://www.microformats.org/wiki/hMedia&quot;&gt;hMedia&lt;/a&gt; microformat, titles are notably left out and most likely relegated to another microformat such as &lt;a href=&quot;http://www.microformats.org/wiki/hproduct&quot;&gt;hProduct&lt;/a&gt; or &lt;a href=&quot;http://www.microformats.org/wiki/hlisting&quot;&gt;hListing&lt;/a&gt; which are not the most suitable microformats for this information given the distinction between a title and a particular publication of that title—a book (which is a product and which can be listed, whereas a title in and of itself, is not and can not).&lt;/p&gt;

&lt;h5&gt;Scope&lt;/h5&gt;

&lt;p&gt;Information about titles consistently share several common fields. Where possible, this proposed microformat has been based on this minimum common subset.&lt;/p&gt;

&lt;h5&gt;Out of Scope&lt;/h5&gt;

&lt;p&gt;This microformat does not aim to be a means of publishing a title online (such as the proposed book microformat &lt;a href=&quot;http://www.alistapart.com/articles/boom&quot;&gt;boom&lt;/a&gt;). Instead, it is a means of marking up information about a title suitable for searching, viewing, and aggregating on sites such as &lt;a class=&quot;include&quot; href=&quot;http://www.blogger.com/post-create.g?blogID=5841632161546703012#vcard-Amazon&quot;&gt;Amazon&lt;/a&gt; and Google Books. This microformat, therefore, is not a competitor to &lt;a href=&quot;http://wwww.alistapart.com/articles/boom&quot;&gt;boom&lt;/a&gt;, rather, it serves a much different purpose.&lt;/p&gt;

&lt;h5&gt;Format&lt;/h5&gt;

&lt;h6&gt;Abstract&lt;/h6&gt;

&lt;p&gt;The proposed &lt;tt&gt;x-hTitle&lt;/tt&gt; microformat is based on a set of fields common to many Internet web sites and formats in use today that provide information about titles (in the form of books), whether for sale, advertisement, or promotional or informational purposes. Where possible, field names have been chosen based on those defined by many related microformat standards.&lt;/p&gt;

&lt;h6&gt;Schema Key&lt;/h6&gt;

&lt;table style=&quot;caption-side:bottom&quot;&gt;
  &lt;caption style=&quot;border-top:1px solid #1a1d19;font-size:85%;font-weight:bold;text-align:left;margin-top:.25em;padding-top:.13em&quot;&gt;
    Table 1. Schema Key
  &lt;/caption&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th scope=&quot;col&quot; style=&quot;border-bottom:1px solid #1a1d19;width:10em;&quot;&gt;
        Field Format
      &lt;/th&gt;
      &lt;th scope=&quot;col&quot; style=&quot;border-bottom: 1px solid #1a1d19;&quot;&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;td&gt;&lt;b&gt;bold&lt;/b&gt;{1}&lt;/td&gt;&lt;td&gt;&lt;em&gt;must&lt;/em&gt; be present exactly once.&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;i&gt;italic*&lt;/i&gt;&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;optional&lt;/em&gt;, and &lt;em&gt;may&lt;/em&gt; occur more than once&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;+&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;must&lt;/em&gt; be present, and &lt;em&gt;may&lt;/em&gt; occur more than once.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;?&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;optional&lt;/em&gt;, but &lt;em&gt;must not&lt;/em&gt; occur more than once.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;[square brackets]&lt;/td&gt;&lt;td&gt;A list of common values&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;(paretheses)&lt;/td&gt;&lt;td&gt;Data format&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;#&lt;/td&gt;&lt;td&gt;A comment.&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;!&lt;/td&gt;&lt;td&gt;Awaiting documentation&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h6&gt;Schema&lt;/h6&gt;

&lt;p&gt;The proposed &lt;tt&gt;x-hTitle&lt;/tt&gt; microformat schema consists of the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;b&gt;x-hTitle&lt;/b&gt;{1}.
    &lt;ul&gt;
      &lt;li&gt;version ?. Using text.&lt;/li&gt;
      &lt;li&gt;
        &lt;b&gt;fn&lt;/b&gt;{1}. 
        Reused from &lt;a href=&quot;http://www.microformats.org/wiki/hCard&quot;&gt;hCard&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;edition ?. Using text.&lt;/li&gt;
      &lt;li&gt;volume ?. Using text.&lt;/li&gt;
      &lt;li&gt;
        &lt;i&gt;contributor*&lt;/i&gt;. Reused from 
        &lt;a href=&quot;http://www.microformats.org/wiki/hMedia&quot;&gt;hMedia&lt;/a&gt;.
      &lt;/li&gt;
      &lt;li&gt;
        description ?. Using any valid 
        &lt;abbr title=&quot;Extensible Hypertext Markup Language&quot;&gt;XHTML&lt;/abbr&gt; markup.
      &lt;/li&gt;
      &lt;li&gt;
        &lt;i&gt;review*&lt;/i&gt;. Using 
        &lt;a href=&quot;http://www.microformats.org/wiki/hReview&quot;&gt;hReview&lt;/a&gt; or 
        &lt;a href=&quot;http://www.microformats.org/wiki/hReview-aggregate&quot;&gt;
          hReview-aggregate
        &lt;/a&gt;.
      &lt;/li&gt;
      &lt;li&gt;&lt;i&gt;category*&lt;/i&gt; Using  text.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;Property Details&lt;/h6&gt;

&lt;dl&gt;
  &lt;dt&gt;version&lt;/dt&gt;
  &lt;dd&gt;
    This optional property permits title publishers to specify a particular version of the &lt;tt&gt;x-hTitle&lt;/tt&gt; microformat that their content uses. By omitting this property, the publisher is stating that implementations may interpret titles marked up using this microformat according to the schema version &amp;lt;to be decided&amp;gt; or later. In practice, the author of this specification is committed to maintaining backward compatability with content produced using earlier versions of the specification. This property is syntax compatible with, and thus reuses semantics of &lt;tt&gt;VERSION&lt;/tt&gt; as defined in the &lt;a href=&quot;http://tools.ietf.org/html/rfc2426#section-3.6.9&quot;&gt;vCard RFC2426 section 3.6.9 VERSION Type Definition&lt;/a&gt;. The value of this property for this specification is &amp;lt;to be decided&amp;gt;.
    &lt;ul&gt;
      &lt;li&gt;The element is identified by the class name &lt;tt&gt;version&lt;/tt&gt;&lt;/li&gt;
      &lt;li&gt;
        &lt;tt&gt;x-hTitle&lt;/tt&gt; &lt;em&gt;may&lt;/em&gt; include only one &lt;tt&gt;version&lt;/tt&gt; property.
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/dd&gt;
  &lt;dt&gt;fn&lt;/dt&gt;
  &lt;dd&gt;
    The full name of the title, including any subtitle.
    &lt;ul&gt;
      &lt;li&gt;
        &lt;tt&gt;x-hTitle&lt;/tt&gt; &lt;em&gt;must&lt;/em&gt; include &lt;strong&gt;one&lt;/strong&gt; &lt;tt&gt;fn&lt;/tt&gt; element.
      &lt;/li&gt;
      &lt;li&gt;The element is identified by the class name &lt;tt&gt;fn&lt;/tt&gt;.&lt;/li&gt;
      &lt;li&gt;
        If the title being marked up with this microformat has its own website (for example, for  forum discussions related to the title, source code, or other content), then &lt;a href=&quot;http://www.microformats.org/wiki/hCard&quot;&gt;hCard&lt;/a&gt; &lt;em&gt;may&lt;/em&gt; be used to provide that information with the title.
      &lt;/li&gt;
      &lt;li&gt;
        This element is reused from 
        &lt;a href=&quot;http://www.microformats.org/wiki/hCard&quot;&gt;hCard&lt;/a&gt;.
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/dd&gt;
  &lt;dt&gt;edition&lt;/dt&gt;
  &lt;dd&gt;
    This property specifies the specific edition of a title.
    &lt;ul&gt;
      &lt;li&gt;The element is identified by the class name &lt;tt&gt;edition&lt;/tt&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;x-hTitle&lt;/tt&gt; &lt;em&gt;may&lt;/em&gt; include one instance of this property.&lt;/li&gt;
      &lt;li&gt;
        This property &lt;em&gt;may&lt;/em&gt; use the 
        &lt;a href=&quot;http://www.microformats.org/wiki/abbr-design-pattern&quot;&gt;
          abbr-design-pattern
        &lt;/a&gt;.
      &lt;/li&gt;
      &lt;li&gt;
        Since the content of a title from one edition to a next can differ significantly, this information &lt;em&gt;should&lt;/em&gt; be included if applicable and available.
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/dd&gt;
  &lt;dt&gt;volume&lt;/dt&gt;
  &lt;dd&gt;
    This property specifies that the title is a particular volume of a larger collection of works which share a main title.
    &lt;ul&gt;
      &lt;li&gt;This element is identified by the class name &lt;tt&gt;volume&lt;/tt&gt;.&lt;/li&gt;
      &lt;li&gt;
        &lt;tt&gt;x-hTitle&lt;/tt&gt; &lt;em&gt;may&lt;/em&gt; include &lt;strong&gt;one&lt;/strong&gt; volume element.
      &lt;/li&gt;
      &lt;li&gt;
        This information &lt;em&gt;should&lt;/em&gt; be included if applicable and available.
      &lt;/li&gt;
      &lt;li&gt;
        This property &lt;em&gt;may&lt;/em&gt; use the 
        &lt;a href=&quot;http://www.microformats.org/wiki/abbr-design-pattern&quot;&gt;
          abbr-design-pattern
        &lt;/a&gt;.
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/dd&gt;
  &lt;dt&gt;contributor&lt;/dt&gt;
  &lt;dd&gt;
    A contributor is any entity that takes part in the creation and distribution of a title. Examples include: author, illustrator, publisher, editor, technical reviewer, etc.
    &lt;ul&gt;
      &lt;li&gt;This element is identified by the class name &lt;tt&gt;contributor&lt;/tt&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;x-hTitle&lt;/tt&gt; &lt;em&gt;may&lt;/em&gt; include one or more contributors.&lt;/li&gt;
      &lt;li&gt;
        The contents of the element &lt;em&gt;should&lt;/em&gt; include a valid 
        &lt;a href=&quot;http://www.microformats.org/wiki/hCard&quot;&gt;hCard&lt;/a&gt;.
        &lt;ul&gt;
          &lt;li&gt;
            The &lt;tt&gt;role&lt;/tt&gt; element of 
            &lt;a href=&quot;http://www.microformats.com/wiki/hCard&quot;&gt;hCard&lt;/a&gt; 
            &lt;em&gt;should&lt;/em&gt; be used to specify the contributor&#39;s responsibility related to the title.
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/dd&gt;
  &lt;dt&gt;description&lt;/dt&gt;
  &lt;dd&gt;
    An abstract or explanation of the contents of the title being marked up. for example, this field could be used to contain the text on the back of a technical book that summarizes the content of the title. Or, such as with fiction hardcover books, the content that appears on the inside flaps of the dust jacket.
    &lt;ul&gt;
      &lt;li&gt;This element is identified by the class name &lt;tt&gt;description&lt;/tt&gt;.&lt;/li&gt;
      &lt;li&gt;
        The element&#39;s contents may include any valid 
        &lt;abbr title=&quot;Extensible Hypertext Markup Language&quot;&gt;XHTML&lt;/abbr&gt;.
      &lt;/li&gt;
      &lt;li&gt;
        &lt;tt&gt;x-hTitle&lt;/tt&gt; &lt;em&gt;may&lt;/em&gt; include more than one description.
        &lt;ul&gt;
          &lt;li&gt;
            If more than one description is defined, the full description is the concatenation, in order, of these elements.
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/dd&gt;
  &lt;dt&gt;review&lt;/dt&gt;
  &lt;dd&gt;
    The existence of this property identifies review(s) for the title.
    &lt;ul&gt;
      &lt;li&gt;The element is identified by the class name &lt;tt&gt;review&lt;/tt&gt;.&lt;/li&gt;
      &lt;li&gt;
        Reviews &lt;em&gt;should&lt;/em&gt; use the 
        &lt;a href=&quot;http://www.microformats.org/wiki/hReview&quot;&gt;hReview&lt;/a&gt; microformat.
      &lt;/li&gt;
      &lt;li&gt;
        If many reviews are to be listed for a title, consider using the 
        &lt;a href=&quot;http://www.microformats.org/wiki/hReview-aggregate&quot;&gt;
          hReview-aggregate
        &lt;/a&gt; microformat, instead.
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/dd&gt;
  &lt;dt&gt;category&lt;/dt&gt;
  &lt;dd&gt;
    The category property can be used to classify the genre, style, or keywords and subject matter associated with the title. Examples could include: fiction, horror, mystery, computer, technical, programming, instructional, biography, etc.
    &lt;ul&gt;
      &lt;li&gt;The element is identified by the class name &lt;tt&gt;category&lt;/tt&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;tt&gt;x-hTitle&lt;/tt&gt; &lt;em&gt;may&lt;/em&gt; include one or more category elements.&lt;/li&gt;
      &lt;li&gt;
        This element &lt;em&gt;may&lt;/em&gt; be expressed using the 
        &lt;a href=&quot;http://www.microformats.org/wiki/rel-tag&quot;&gt;rel-tag&lt;/a&gt;
        elemental microformat. When a category is expressed using &lt;tt&gt;rel-tag&lt;/tt&gt;, the content of this element is used as the text for the &lt;tt&gt;category&lt;/tt&gt;. For example: 
        &lt;code&gt;
          &amp;lt;a class=&amp;#34;category&amp;#34; rel=&amp;#34;tag&amp;#34; href=&amp;#34;/tags/romance&amp;#34;&amp;gt;Romance&amp;lt;/a&amp;gt;
        &lt;/code&gt;
        would have &amp;#34;Romance&amp;#34; as the text for the category.
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/dd&gt;
&lt;/dl&gt;</description><link>http://discoveringcode.blogspot.com/2010/07/new-microformat-propoal-x-htitle.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-710073386834114560</guid><pubDate>Sun, 11 Jul 2010 21:30:00 +0000</pubDate><atom:updated>2010-07-11T20:13:18.042-04:00</atom:updated><title>Wow, it&#39;s been a long while!</title><description>&lt;h4&gt;We Thought You Fell Off the Face of the Earth!&lt;/h4&gt;Hello everyone. I&#39;m still around. Well, I warned you, I may not write often. I hope, though, that there are still some readers out there (or new ones will find this blog).&lt;p&gt;First, a very quick update in fast-forward. I moved because my wife got laid off about a year and a quarter ago. She got a new job fairly quickly given the economy, so that&#39;s that. In addition, I&#39;ve completed two more semesters at &lt;span style=&quot;&quot; class=&quot;vcard&quot; id=&quot;vcard-KU&quot;&gt;&lt;a class=&quot;fn org url&quot; rel=&quot;home&quot; href=&quot;http://www.kutztown.edu/&quot;&gt;Kutztown University&lt;/a&gt;&lt;/span&gt; and I will be entering my last semester this Fall. I&#39;ve also been taking two Summer courses.&lt;/p&gt;&lt;p&gt;The main reason for not writing in so long has been three-fold:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;The last two semesters have been extremely difficult—on the flip side, I managed to pull off very good grades; so I&#39;m very pleased about that.&lt;/li&gt;&lt;li&gt;I&#39;ve been trying to work whenever I can to get all those computers installed at &lt;span class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; rel=&quot;home&quot; href=&quot;http://www.tteconline.com/&quot;&gt;Thermocouple Technology, Inc.&lt;/a&gt;&lt;/span&gt;, but it&#39;s been really slow going.&lt;/li&gt;&lt;li&gt;Making things even more slow going at &lt;abbr title=&quot;Thermocouple Technology, Inc.&quot;&gt;TTEC&lt;/abbr&gt; is the fact that I decided to get a different Summer job that would be involved with coding. It is to a certain extent (if you call writing &lt;abbr title=&quot;Structured Query Language&quot;&gt;SQL&lt;/abbr&gt; programming), plus, the job is about an hour away from where I live.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;My coursework at school over the last two semesters included taking Compiler Design I and II using the famous &lt;span class=&quot;hbook htitle hproduct&quot;&gt;&lt;a class=&quot;fn url&quot; href=&quot;http://www.amazon.com/dp/0321486811&quot;&gt;Dragon Book&lt;/a&gt;&lt;/span&gt;. I tried to implement a language that could replace &lt;abbr title=&quot;Structured Query Language&quot;&gt;SQL&lt;/abbr&gt;. Well, being I wrote the language in academia for academia, it didn&#39;t quite turn out the way I would&#39;ve liked. I spent every waking minute last semester writing code for that class. Anyway, the idea is that the language could be used not only for relational databases, but also XML data, structured textual data (e.g. CSV files, tab-delimited files, etc.), or any other structured data (possibly using some kind of schema definition). As the semester wore on, I whittled the language down to just working with relational databases for the start. However, I didn&#39;t have time to learn another database technology with an open API where I could directly access the query engine, so I ended up translating my language to &lt;abbr title=&quot;Structured Query Language&quot;&gt;SQL&lt;/abbr&gt; anyway, which didn&#39;t work out quite so well. Having said that, my ideas are completely valid and workable, given enough time and resources to develop it properly, and it very well could replace &lt;abbr title=&quot;Structured Query Language&quot;&gt;SQL&lt;/abbr&gt; using a much more human-readable/writable syntax. In fact, part of my coursework this Summer is writing a paper on this language and its goals.&lt;/p&gt;&lt;p&gt;Anyway, enough of that. So in a nutshell (which is a first for me, believe me!), that&#39;s what&#39;s happened over the last year and a half or so.&lt;/p&gt;&lt;h4&gt;Why write now?&lt;/h4&gt;&lt;p&gt;Well, I&#39;m glad you asked. As mentioned, it&#39;s my last semester coming up this Fall at &lt;a class=&quot;include&quot; href=&quot;http://www.blogger.com/post-create.g?blogID=5841632161546703012#vcard-KU&quot;&gt;Kutztown University&lt;/a&gt;. As such, I&#39;m required to take a course colloquially called Senior Sem, the cap-stone course that&#39;s supposed to tie together everything we learned into a final project.&lt;/p&gt;&lt;p&gt;Being who I am, I plan on making the best of it. My idea: an inventory system for all the different types of media I own—books, &lt;abbr title=&quot;Compact Disc&quot;&gt;CD&lt;/abbr&gt;s, &lt;abbr title=&quot;Digital Video Disc&quot;&gt;DVD&lt;/abbr&gt;s, magazines, sheet music, etc. It will be web-based using the new &lt;abbr title=&quot;Active Server Pages&quot;&gt;ASP&lt;/abbr&gt;.net &lt;abbr title=&quot;Model-View-Controller&quot;&gt;MVC&lt;/abbr&gt; 2.0 framework. I will also be investigating technologies such as jQuery, and AJAX. In addition, I plan on proposing two new microformats to &lt;span class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; rel=&quot;home&quot; href=&quot;http://www.microformats.org/&quot;&gt;microformats.org&lt;/a&gt;&lt;/span&gt; to use with my project. I will be writing a few more blog posts over the next couple of days/weeks that contain pre-pre-draft specifications of the proposed microformats, as well as samples of  how they could be used alone or along with other existing microformats.&lt;/p&gt;&lt;p&gt;I&#39;m very excited about my project and hope to learn a lot of real-world skills and create a usable application. Whether anyone else would find it useful, I don&#39;t particularly care, I&#39;ve been wanting a comprehensive application like this for years.&lt;/p&gt;&lt;h4&gt;More on Microformats&lt;/h4&gt;&lt;p&gt;If you don&#39;t know what microformats are, I&#39;d encourage you to visit the website I linked to above. In addition, there&#39;s also &lt;abbr title=&quot;Resource Description Framework with Attributes&quot;&gt;RDFa&lt;/abbr&gt;. The two technologies are complementary. &lt;abbr title=&quot;Resource Description Framework with Attributes&quot;&gt;RDFa&lt;/abbr&gt;, as I understand it, is for machines first, whereas microformats are for humans first. Both can be used together to make the web a much more meaningful place for humans and machines.&lt;/p&gt;&lt;p&gt;To make the most of this embedded information, you can use various browser plug-ins to access the information. For example, there is &lt;a rel=&quot;home&quot; href=&quot;http://visitmix.com/labs/oomph/&quot;&gt;Oomph&lt;/a&gt; for Internet Explorer, and &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/4106/&quot;&gt;Operator&lt;/a&gt; for Firefox. When microformats are available on the page, these tools will let you export contact information, calendar events, product information, RSS/Atom feeds, etc. There&#39;s a lot of information that can be encoded in semantic &lt;abbr title=&quot;Extensible Hypertext Markup Language&quot;&gt;XHTML&lt;/abbr&gt;. If you haven&#39;t noticed, this blog post has tons of microformats embedded within it.&lt;/p&gt;&lt;h4&gt;Conclusion&lt;/h4&gt;&lt;p&gt;
So, stay tuned, as I begin &quot;the process&quot; of proposing new microformats. I hope to write again in a few days.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2010/07/wow-its-been-long-while.html</link><author>noreply@blogger.com (Craig S.)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-420472732155819329</guid><pubDate>Sun, 17 May 2009 03:13:00 +0000</pubDate><atom:updated>2009-05-16T23:58:36.041-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">computers</category><category domain="http://www.blogger.com/atom/ns#">history</category><category domain="http://www.blogger.com/atom/ns#">musings</category><category domain="http://www.blogger.com/atom/ns#">nostalgia</category><category domain="http://www.blogger.com/atom/ns#">retro</category><title>The Good Old Days</title><description>&lt;p&gt;Just read an entry on &lt;a href=&quot;http://http://www.hanselman.com/blog/aboutme.aspx&quot; class=&quot;vcard fn url&quot; rel=&quot;contact&quot;&gt;Scott Hanselman&lt;/a&gt;&#39;s blog called &lt;cite&gt;&lt;a href=&quot;http://www.hanselman.com/blog/10AwesomeThingsIRememberAboutComputers.aspx&quot; rev=&quot;vote-for&quot;&gt;10 Awesome Things I Remember About Computers&lt;/a&gt;&lt;/cite&gt;. The comments on the entry closed May 1, so I thought I&#39;d write my own entry and sort of chain off his. Feel free to leave your own memories!&lt;/p&gt;&lt;h4&gt;10 Awesome Things I Remember About Computers (give or take...)&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;Using my S100 CP/M based computer with CP/M DOS&lt;/li&gt;&lt;li&gt;Using the same computer above, typing my school reports in WordStar (how I miss WordStar)&lt;/li&gt;&lt;li&gt;Typing up BASIC (in that day, I used A-Basic, M-Basic, GW-Basic, and in the &#39;90s, QBasic) game listings&lt;/li&gt;&lt;li&gt;Upgraded to an IBM XT with a 40MB HDD (that was HUGE, and the largest available consumer HDD)&lt;/li&gt;&lt;li&gt;DOS 3.x was out, and sub-directories were new. I didn&#39;t know about them/understand them (I was 11!). Anyway, I watched my dad type a command: &lt;code&gt;del *.*&lt;/code&gt; and it deleted some files. Pretty cool. I accidentally wrote a file in the wrong spot. I couldn&#39;t get it deleted, so I tried this (not understanding directories, they didn&#39;t exist in DOS 2.0!): &lt;b&gt;C:\&gt;&lt;/b&gt; &lt;code&gt;del *.*&lt;/code&gt;. Rebooted, nothing happened. Hmmm... &quot;DAD! My computer won&#39;t boot.&quot; He said, &quot;What did you do to it?&quot; To which I said, &quot;I don&#39;t know, it just wouldn&#39;t start.&quot; He wasn&#39;t too happy. ;) Luckily, it was only my computer, so none of his stuff was on it. Whew!&lt;/li&gt;&lt;li&gt;Playing Tie Fighter on my 486 (this is now about 5 years later, about 1992 I&#39;d say).&lt;/li&gt;&lt;li&gt;Using DriveSpace on Windows95 to compress my 810MB HDD to get 2.4GB space. Boy was that a bad idea!&lt;/li&gt;&lt;li&gt;Buying my first computer from scratch and putting it together myself (1997) for $2400: PII 350MHz w/ ABIT BX6 mobo, 256MB RAM, 12GB HDD (yeah baby!) and a LS-120 FDD (that was a total waste).&lt;/li&gt;&lt;li&gt;One year later, bought another computer for $1100: PII 400MHz w/ 512MB RAM, ABIT BX6 Rev 2 mobo, Acer 40x CD-ROM, Yamaha 24/8/4 CD-RW drive and another 12GB HDD&lt;/li&gt;&lt;li&gt;Windows 2000. Finally, a true 32-bit OS that worked well.&lt;/li&gt;&lt;li&gt;Windows XP&amp;mdash;so much better!&lt;/li&gt;&lt;li&gt;One more for good kicks (though this is recent history)&amp;mdash;Microsoft releases their second-most horrible &lt;abbr title=&quot;Operating System&quot;&gt;OS&lt;/abbr&gt; (after &lt;abbr title=&quot;Mellennium Edition&quot;&gt;ME&lt;/abbr&gt;), Vista. Can&#39;t wait for Windows 7!&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Though I have some recent stuff on my list, I&#39;ve been using computers since I was 8 (so just shy 25 years). I&#39;d like to hear from you, too. What are some of your memories?&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2009/05/good-old-days.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-8091339416148295259</guid><pubDate>Thu, 14 May 2009 19:42:00 +0000</pubDate><atom:updated>2009-05-14T20:54:59.087-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">book reviews</category><category domain="http://www.blogger.com/atom/ns#">microformats</category><category domain="http://www.blogger.com/atom/ns#">semantics</category><category domain="http://www.blogger.com/atom/ns#">web design</category><title>Book Review: Microformats: Empowering Your Markup for Web 2.0</title><description>&lt;div class=&quot;hreview&quot;&gt;&lt;h4 class=&quot;summary&quot;&gt;Microformats: giving birth to the semantic web&lt;/h4&gt;&lt;div class=&quot;item description&quot;&gt;&lt;p&gt;I just finished reading &lt;a class=&quot;fn url&quot; href=&quot;http://www.amazon.com/gp/product/1590598148/ref=cm_cr_mts_prod_img&quot;&gt;Microformats: Empowering Your Markup for Web 2.0&lt;/a&gt;. I&#39;ve heard of microformats here and there over the last 3 or 4 years, but until now, I haven&#39;t really looked into them. I saw this book for sale on &lt;a class=&quot;vcard fn org url&quot; href=&quot;http://www.amazon.com&quot;&gt;Amazon.com&lt;/a&gt; at a price I couldn&#39;t resist. It was high about time that I read about what this semantic web thing is all about.&lt;/p&gt;&lt;p&gt;I thought the semantic web was simply about using the appropriate XHTML when creating your web pages and being sure that you were meeting various other standards along the way, such as &lt;abbr title=&quot;Web Content Accessibility Gudielines&quot;&gt;WCAG&lt;/abbr&gt;. The semantic web is that and much more.&lt;/p&gt;&lt;p&gt;Microformats give web content designers and developers a way to use existing XHTML to markup their content so that it can be easily read by humans but also easily read by machines. This has the advantage that, obviously, humans can read it, but that the content can be aggregated by various web services.&lt;/p&gt;&lt;p&gt;This book is one of the best organized books I have ever read and I highly recommend reading this book for a detailed, but quick introduction to microformats. In fact, microformats are so easy to use, an introduction is all you really need to begin using them. If you need more information, just check out &lt;a class=&quot;vcard fn org url&quot; href=&quot;http://www.microformats.org&quot;&gt;microformats.org&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This review is written using the hReview format as discussed in the book. Since this is my first attempt at using this microformat, if there&#39;s anything wrong with it, please leave a comment. In any event, I give this book &lt;span class=&quot;rating&quot;&gt;&lt;span class=&quot;value&quot;&gt;5&lt;/span&gt; stars out of &lt;span class=&quot;best&quot;&gt;5&lt;/span&gt;.&lt;/div&gt;&lt;/div&gt;</description><link>http://discoveringcode.blogspot.com/2009/05/book-review-microformats-empowering.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-1909936719012936977</guid><pubDate>Thu, 14 May 2009 13:30:00 +0000</pubDate><atom:updated>2009-05-14T12:29:03.555-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Firefox 3</category><category domain="http://www.blogger.com/atom/ns#">gripe</category><category domain="http://www.blogger.com/atom/ns#">IE8</category><category domain="http://www.blogger.com/atom/ns#">rant</category><title>FireFox 3.0.10 and IE8</title><description>&lt;p&gt;Time for another, though much shorter, rant.&lt;/p&gt;&lt;h4&gt;My Headaches with Firefox 3&lt;/h4&gt;&lt;p&gt;I&#39;ve had it with Firefox. I was late to jump on the Firefox bandwagon. I jumped on around 2.08 or so and upgraded all the way up to 3.0.10 as recently as two weeks ago. I upgrade Firefox as soon as I can, though I admit, I waited a bit to upgrade to Firefox 3; and it seems for good reason. At first, I was very impressed with Firefox 3. It provided better tab scrolling and seemed much more stable than Firefox 2. That is, until I &quot;upgraded&quot; to Firefox 3.0.9. Then everything came to a screeching halt.&lt;/p&gt;&lt;p&gt;You have to understand that I&#39;m a &lt;strong&gt;power&lt;/strong&gt; browser user. Some would say I&#39;m just crazy. But I have so many things going on that I have a ton of tabs open (at current count, about 344) so that I can quickly get back to whatever else I was doing/researching within the past few weeks (ok, months). As Firefox has continued to release updates, its memory footprint continues to grow, rivaling Internet Explorer with it&#39;s  famed JavaScript memory leak. At first, Firefox was crashing because I actually had 360+ tabs open and during loading all of the tabs, the process size reached 1.5GB, which is apparently the maximum process size on Windows even though each process has 3GB of memory space (go figure?). Ok, so that&#39;s my fault. But since then, I&#39;ve closed unneeded tabs and had gotten as low as 320. My Firefox process size was around 600&lt;abbr title=&quot;megabytes&quot;&gt;MB&lt;/abbr&gt; - 700&lt;abbr title=&quot;megabytes&quot;&gt;MB&lt;/abbr&gt;. However, I experienced browser crashes 2 or 3 times a day.&lt;/p&gt;&lt;p&gt;Yay, Firefox came out with an update, 3.0.10. So I upgraded to that seeing that they fixed (yet another) memory corruption issue (how many of those things do they have??). I hoped that it would solve my problem. Nope. Firefox routinely continues to crash at least once a day, if not twice. I tried things like turning off Google Desktop Search (which is a huge memory waster anyway and should be uninstalled from every computer on earth because it puts its hooks into every single program that&#39;s opened on your computer). But to no avail. I&#39;ve done some searching on this issue and have found that many are experiencing the same problem (I hear it can be much worse on Linux). This leads me into my next segment.&lt;/p&gt;&lt;h4&gt;Enter Internet Explorer 8&lt;/h4&gt;&lt;p&gt;OK, so &lt;a id=&quot;ms&quot; class=&quot;vcard fn org url&quot; href=&quot;http://www.microsoft.com&quot;&gt;Microsoft&lt;/a&gt; copies folks, but so far as I can tell, IE8 was in the works before &lt;a class=&quot;vcard fn org url&quot; href=&quot;http:/www.google.com&quot;&gt;Google&lt;/a&gt; Chrome hit (though, I can&#39;t be absolutely sure about this). Whatever the case may be, Chrome and IE8 use the same &quot;memory model&quot;. Each browser tab is a separate process. This has advantages, and disadvantages. However, today, the disadvantages are smaller than they used to be.&lt;/p&gt;&lt;p&gt;When I first heard that Chrome used separate processes for tabs, I was not impressed. Sure, you have tab isolation, but at what price? Processes are heavy in terms of memory and creation time. However, what I didn&#39;t realize (and I was very surprised I had missed this fact!) was that in Windows 2000, a new type of process was created&amp;mdash;called a job process. A job process is a new process, but it is related to some parent process. It&#39;s almost like a Unix &lt;code&gt;fork&lt;/code&gt;, but not quite. In any event, these processes, while providing isolation, don&#39;t have as steep memory requirements or creation time. IE8 makes heavy use of the job process (as I&#39;m sure Chrome does).&lt;/p&gt;&lt;p&gt;So I started playing around with IE8 last week. I must say I&#39;m pretty impressed. It&#39;s stable, and if a tab crashes, it will attempt to reopen the tab. With IE8, you don&#39;t have to explicitly save your browsing session, just close the browser and all your tabs are remembered. Personally, I don&#39;t care for that. In fact, that&#39;s one thing I&#39;m going to miss from Firefox, the Session Manager plug-in. I think one could be written for IE8, but I haven&#39;t seen one yet and I don&#39;t have time to write one. Anyway, IE8 only lets you save the last browsing session (since it&#39;s explicitly saved). You can&#39;t save multiple browsing sessions to open one up again at some later point. Too bad. That&#39;s a real short-sight. Another plus about IE8 is that it renders much better than it ever used to. I still have to put it through its paces though (and check out how much of ACID2 it passes). Overall, I&#39;m very pleased with it and can&#39;t wait to ditch Firefox.&lt;/p&gt;&lt;h4&gt;An Open Call (and Mind) to Mozilla&lt;/h4&gt;&lt;p&gt;If you&#39;re going to release patches for a browser, especially a build update (e.g. 3.0.xxxx), you better do thorough regression testing to make sure you don&#39;t break the browser. That&#39;s what happened between 3.0.8 and 3.0.9. It just completely broke. 3.0.10 is better, but it&#39;s still broken. I think Firefox needs to get back to its roots as a browser: a low memory footprint, extensibility, and stability, and frankly, more cool features that just kill the browser market (tabbing was definitely a killer feature). I&#39;m going to keep my eye on Firefox, but for now, I need stability, speed, and something that just plain works.&lt;/p&gt;&lt;h4&gt;P.S.&lt;/h4&gt;To the &lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;#ms&quot;&gt;&lt;/a&gt;Microsoft&lt;/span&gt; haters and open source lovers and the passionate (or even fanatic) people out there: this post is meant as an open honest discussion of my findings in regards to the latest Firefox 3.0.10 browser, and not about the quality of FOSS software, in general. This is particular to Firefox. Also, note that I did not say that I hate Firefox, only that it has become unusable to me. I&#39;m disappointed with it. I hope that the next major (or minor, 3.5, is it?) release will resolve many of the issues I and others have been having. I&#39;m willing to give Firefox another shot, but until I can actually use it to work (without it freezing up every 30 seconds for 10 seconds at a time), I will have to stick with IE8.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2009/05/firefox-3010-and-ie8.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-1125264261036970134</guid><pubDate>Thu, 14 May 2009 01:40:00 +0000</pubDate><atom:updated>2009-05-16T19:49:22.200-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">AMD</category><category domain="http://www.blogger.com/atom/ns#">ATI Catalyst 9.4</category><category domain="http://www.blogger.com/atom/ns#">gripe</category><category domain="http://www.blogger.com/atom/ns#">rant</category><category domain="http://www.blogger.com/atom/ns#">unattended install</category><title>ATI Catalyst 9.4 Is No Good for Business</title><description>&lt;p&gt;Today&#39;s post is a bit of a rant. Also, it took me so long to write, that I didn&#39;t want to spend much more time formatting it. So, if it looks a bit messy, I&#39;ll try to get back and clean it up a bit later. If you&#39;ve been reading my blog, you know that I&#39;m in the process of a network deployment. Recently, we qualified for a (basically, free) computer form &lt;abbr class=&quot;vcard&quot; title=&quot;United Parcel Service&quot;&gt;&lt;a class=&quot;fn org url&quot; href=&quot;http://www.ups.com&quot;&gt;UPS&lt;/a&gt;&lt;/abbr&gt;. Unfortunately, all they had to offer were machines with &lt;abbr id=&quot;amd&quot; class=&quot;vcard&quot; title=&quot;Advanced Micro Devices, Inc.&quot;&gt;&lt;a class=&quot;fn org url&quot; href=&quot;http://www.amd.com&quot;&gt;AMD&lt;/a&gt;&lt;/abbr&gt; processors and chipsets. If you haven&#39;t guessed it by now, I&#39;m an &lt;span id=&quot;intel&quot; class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; href=&quot;http://www.intel.com&quot;&gt;Intel&lt;/a&gt;&lt;/span&gt; guy. And now, I know why.&lt;/p&gt;&lt;h4&gt;The Problem with &lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;#amd&quot;&gt;&lt;/a&gt;AMD&lt;/span&gt;&lt;/h4&gt;&lt;p&gt;Apparently, &lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;#amd&quot;&gt;&lt;/a&gt;AMD&lt;/span&gt; doesn&#39;t want to make it easy for (particularly small) business to install their software. This is evidenced by the fact that they have completely non-standard Windows installers. They probably use InstallShield for some of their software (which, arguably, makes horrible installers, in my opinion, after having looked at just a  few InstallShield MSIs with &lt;acronym title=&quot;One Really Cool App&quot;&gt;ORCA&lt;/acronym&gt; from &lt;span class=&quot;vcard&quot;&gt;&lt;a class=&quot;fn org url&quot; href=&quot;http://www.microsoft.com&quot;&gt;Microsoft&lt;/a&gt;&lt;/span&gt;). However, their Catalyst Display Driver package uses something called Monet, which until last week, I&#39;ve never heard of before. And let me say that I hope I never hear of it again, as it caused me nothing but trouble this week.&lt;/p&gt;&lt;p&gt;The idea is that I&#39;m using the Microsoft Deployment Toolkit 2008 to deploy my clients. This driver comes with software that I would like to have installed on the machine, so I decided to go ahead and install the whole package (minus a few items that I really don&#39;t need). But it turned out to be a real chore. To start, there is the lack of documentation. Here&#39;s the help documentation from Setup.exe and InstallManagerApp.exe, which are responsible for the GUI installation:&lt;/p&gt;&lt;div&gt;&lt;textarea cols=&quot;53&quot; rows=&quot;15&quot; wrap=&quot;off&quot;&gt;-INSTALL[-Use /package path] - This will install packages in silent mode.
 -Use /package path is optional.
 E.g.
 1)-INSTALL:will install the whole packages in silent mode.
 2)-INSTALL -Use c:\packages\Drivers\:will install the defined packages in 
                                             silent mode
-UNINSTALL - This will uninstall all packages in silent mode.

/FORCE_FIRST_RUN - forces the first run wizard each time(good if you’re debugging or
                   showing a demo of the initialization wizard and need it to appear 
                   on every run).

/FORCE_HIDE_FIRST_RUN - forces the first run wizard to hide even if it is the first 
                        run.

/INSTALL - run in install mode (this is what a CD autorun could use to run Monet)

/UPDATE - run in uninstall mode (this is what a toolbar or tooltray could use to 
          launch Monet UI)

/UNINSTALL - run in uninstall mode (this is what a toolbar or tooltray could use to 
             launch Monet UI)

/PACKAGE_SELECTION_LISTBOX - a listbox is shown for package selection, instead of 
                             toggling throughicons (this is more useful in debugging 
                             because in the past I have sometimes encountered 
                             multiple installed versions of the same package).

/VERBOSE_TRACE - This is absolutely necessary to always be in command line if you 
                 want tohave &quot;/TRACE_RM&quot; and &quot;/FORCE_CORECOM_TRACE&quot;. The intention 
                 of this option was that we should always trace a minimum on an end 
                 system due to performance issues.... if you&#39;re at all interested in 
                 tracing UI or UI&lt;--&gt;Core commmunication, then make sure this is 
                 always in the command line

/FORCE_CORECOM_TRACE:&amp;lt;path&amp;gt; - Traces all communication between core and UI use this 
                              with a target file e.g. with &lt;path&gt; equal to 
                              &quot;C:\my_directory\core_ui_log.txt&quot;

/TRACE_RM - Trace all messages relevent to risk mitigation.

/DISPLAY_FULL_VERSION - Display the full version and timestamp

/PASS_TO_CORE - Will pass any command line in quotes into the core for processing. 
                Example usage /PASS_TO_CORE:&quot;-a -b -c -d -e -f -g&quot; will pass the 
                command line:&quot;-a -b -c -d -e -f -g&quot; to the core. (Note: if you need 
                to pass &quot; character, then use a &#39; and it willbe converted to &quot; 
                before being passed to the core.

/UNATTENDED_INSTALL&amp;lt;:&amp;gt;&amp;lt;files/path&amp;gt;&amp;lt;;&amp;gt;&amp;lt;file/path&amp;gt; - This puts InstallManagerApp into 
                                                   unattended install mode by using 
                                                   the comma-separated list of 
                                                   files/paths.
 E.g.
 1)/UNATTENDED_INSTALL:&quot;c:\direc1;c:\direc2\filea.msi;c:\direc3&quot;
 2)/UNATTENDED_INSTALL:&quot;c:\drivers&quot;
 3)/UNATTENDED_INSTALL:&quot;c:\drivers\graphics_driver.msi&quot;

/UNATTENDED_UNINSTALL - This will uninstall all packages in unattended mode.

/AUTOACCEPT_ALL - This will autoaccept all legal agreements (for internal use only). 
                  If you don’t use this command line, you’ll have to stick around, 
                  read and accept/deny EULA’s. This option won’t be published.

/ON_REBOOT_MESSAGE:&amp;lt;value&amp;gt; - This takes the answer in advance from the user as to 
                             whether s/he needs to reboot once complete. Valid 
                             &amp;lt;value&amp;gt;s are &quot;YES&quot; or &quot;NO&quot;.

/FORCE_REBOOT - On completion of an install/update/uninstall, force a reboot request 
                to OS. Note that the reboot request will only be issued after the 
                application is closed.

/FORCE_CLOSE_WHEN_DONE - This will automatically close the last wizard page on 
                         completion.

/OEM:&amp;lt;value&amp;gt; - Change the OEM look and feel.  Valid &lt;values&gt; must have an entry in 
               the OEM folder the the same folder name

/NO_CUSTOM_UI:&amp;lt;value&amp;gt; - Ignore UI color setting changes from configuration files.

/HELP - Display this message and exit.
&lt;/textarea&gt;&lt;span class=&quot;caption&quot; style=&quot;font-weight:bold&quot;&gt;Figure 1. Setup.exe/InstalManagerApp.exe command-line switches&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Well, I&#39;m confused already. But here&#39;s what happens. If you use the slash (/) switches, you can get an unattended GUI install. What do I mean? What I mean is, if you use the right combination of switches, you can achieve an unattended install that still shows a GUI. Ok, that&#39;s not so bad. Let&#39;s step through these switches a bit. By specifying &lt;kbd&gt;/UNATTENDED_INSTALL&lt;/kbd&gt;, you would think that would be all I have to do to achieve my goal. Well, you would be wrong. Even when using this switch, the installer stops on the very first wizard page to ask what language you want. Why do I need to choose a language if I&#39;m doing an unattended install? (More precisely, if no language is specified on the command line, English ought to be the default and installation should proceed unattended.) So, in order to get around this, we need to pass the &lt;kbd&gt;/FORCE_HIDE_FIRST_RUN&lt;/kbd&gt; switch, which does just that&amp;mdash;it skips the language selection step. So you run the new command and now the wizard appears to stop in its tracks on the last page and just sits there. That&#39;s because even during an &quot;unattended&quot; install, the setup program expects you to click the Finish button. Stupid. So we need to pass the &lt;kbd&gt;/FORCE_CLOSE_WHEN_DONE&lt;/kbd&gt; switch. Just to be extra cautious, I pass the &lt;kbd&gt;/AUTOACCEPT_ALL&lt;/kbd&gt; switch, which automatically accepts all &lt;abbr title=&quot;End User License Agreement&quot;&gt;EULA&lt;/abbr&gt;s (which according to &lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;#amd&quot;&gt;&lt;/a&gt;AMD&lt;/span&gt; is supposed to be unpublished, hehe). I also pass the &lt;kbd&gt;/ON_REBOOT_MESSAGE:NO&lt;/kbd&gt; switch to make sure the installer doesn&#39;t tell the operating system to reboot, a big no-no when using the Microsoft Deployment Toolkit. So our final command looks like this: &lt;code&gt;setup.exe /UNATTENDED_INSTALL /FORCE_HIDE_FIRST_RUN /FORCE_CLOSE_WHEN_DONE /AUTOACCEPT_ALL /ON_REBOOT_MESSAGE:NO&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Well now there are three problems. In older releases of the Catalyst Display Driver package, HydraVision was installed with everything else and the Windows Vista Experience Index score was also updated so that the Aero user interface would be enabled. This no longer happens in the 9.4 release of the package. It turns out they have a few errors in their new install routine. The lack of installation of HydraVision (a multi-desktop or even desktop spitting application) can be gotten around by replacing &lt;kbd&gt;/UNATTENDED_INSTALL&lt;/kbd&gt; with &lt;kbd&gt;/UNATTENDED_INSTALL:&quot;&lt;driver_folder&gt;\Packaes\Apps\CCC\HydraVision-Full\ccc-hv-full.msi;&amp;lt;driver_folder&amp;gt;\Packgaes&quot;&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;Enabling the Aero user interface (in an unattended manner) is also similarly easy. In previous releases, there was an &lt;abbr title=&quot;Microsoft Installer&quot;&gt;MSI&lt;/abbr&gt; called EnableAero.msi. At first, I was including this in the installation, but I soon realized that all the MSI was doing is running the following command: &lt;del&gt;&lt;code&gt;C:\Windows\System32\WinSat features&lt;/code&gt;&lt;/del&gt; &lt;ins&gt;&lt;code&gt;C:\Windows\System32\WinSAT formal&lt;/code&gt;&lt;/ins&gt;. So, &lt;del&gt;number one&lt;/del&gt;, the EnableAero.msi installer is completely unnecessary. &lt;del&gt;Secondly, the way they are running the command is also unnecessary. Instead, there is a command line switch that enables you to only update the graphics and restart the Display Window Manager: &lt;code&gt;C:\Windows\System32\WinSAT dwm&lt;/code&gt;.&lt;/del&gt;&lt;/p&gt;&lt;p&gt;Now we have achieved the following: an unattended installation (though, still showing a GUI) that installs HydraVision and enables the Aero user interface in Vista. But what if we want a truly silent install? Is this possible? Yes, it is. There are two ways of doing this.&lt;/p&gt;&lt;p&gt;First, there is a file called ATISetup.exe in the &lt;var&gt;Bin{64}&lt;/var&gt; folder of the Catalyst Display Driver package. If you run this file without any command line options, you will see the following command line options (there are more, but for brevity, which it&#39;s already too late for, I&#39;ll omit the unimportant ones):&lt;/p&gt;&lt;dl&gt;&lt;dt&gt;-install&lt;/dt&gt;&lt;dd&gt;Performs a silent install&lt;/dd&gt;&lt;dt&gt;-uninstall [all]&lt;/dt&gt;&lt;dd&gt;Performs a silent uninstall ([all] uninstalls all hidden packages)&lt;/dd&gt;
&lt;dt&gt;-output screen [detail]&lt;/dt&gt;&lt;dd&gt;Screen outputs basic information to the console while including detail will output more verbose information. Useful for debugging.&lt;/dd&gt;&lt;dt&gt;-h #### -v #### -b ## -j ###[ddc]&lt;/dt&gt;&lt;dd&gt;Sets the horizontal resolution, vertical resolution, color depth (or bits per pixel (a/k/a bits per pel)), and vertical refresh rate. Using DDC for the vertical refresh rate tells the driver to get the information from the monitor via DDC or EDID, if the monitor supports it. Most LCDs in use do, as do most CRTs that are left in use. Also, be aware that the documentation for these switches is incorrect: -b only takes 2 digits, and -j can take 3. They have this reversed on their display of the help options (and thus, you can specify 120Hz refresh rate for your CRT if it supports it).&lt;/dd&gt;&lt;/dl&gt;&lt;p&gt;Here&#39;s the kicker: you try to run the following command: &lt;code&gt;ATISetup -install -h 1280 -v 1024 -b 32 -j ddc&lt;/code&gt;, and it doesn&#39;t work. The install occurs, but again, HydraVision is not installed, and when you reboot, the display defaults to a resolution of 800 x 600 @ 32-bits. Again, the problem with HydraVision can be fixed and the installer used, but not the screen resolution. For me, this is back to square one. Why did I go through all of this? To save you the trouble&amp;mdash;and to pick on &lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;#amd&quot;&gt;&lt;/a&gt;AMD&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;So how do I get the driver to install, with all the companion applications, and have the screen resolution set to the desired size and enable the Aero user interface? It comes down to two lowly batch files (or in Vista world, a &lt;kbd&gt;.cmd&lt;/kbd&gt; file).&lt;/p&gt;&lt;p&gt;First, we need to write the batch (or command) file that will install the driver and companion applications. Apparently, what really happens when you run the Setup.exe file in the root driver package with the &lt;kbd&gt;-install&lt;/kbd&gt; switch, it just passes it onto the .\Bin{64}\ATISetup.exe installer. If you use the slash (/) switches, then the GUI installer is used (e.g. the GUI installer is shown, but is unattended if you use the switches I outlined above).&lt;/p&gt;&lt;p&gt;Here&#39;s the install batch file (I named it install.cmd):&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;b&gt;&lt;i&gt;NOTE: You may freely copy and use the batch file source code contained in Figures 2 and 3 of this blog entry without needing to give attribution. I hope someone may find it useful.&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;textarea cols=&quot;53&quot; rows=&quot;15&quot; wrap=&quot;off&quot;&gt;
@ECHO OFF
ECHO Installing ATi Radeon 3100 Graphics drivers...
.\Bin64\ATISetup -install -use ..\Packages\Apps\CCC\HydraVision-Full\ccc-hv-full.msi -use ..\Packages

REM Alternatively, you could use the following commands:
REM 1) Setup -intall -use ..\Packages\Apps\CCC\HydraVision-Full\ccc-hv-full.msi -use ..\Packages
REM 2).\Bin{64}\{Setup.exe|InstallManagerApp.exe} -install -use ..\Packages\Apps\CCC\HydraVision-Full\ccc-hv-full.msi -use ..\Packages
REM 3).\Bin{64}\{Setup.exe|InstallManagerApp.exe} /UNATTENDED_INSTALL:&quot;..\Packages\Apps\CCC\HydraVision-Full\ccc-hv-full.msi;..\Packages&quot; /FORCE_HIDE_FIRST_RUN /FORCE_CLOSE_WHEN_DONE /AUTOACCEPT_ALL /ON_REBOOT_MESSAGE:NO
REM The third command line would be used if you didn&#39;t mind end users seing a GUI during the installation.

ECHO Done.
ECHO.
ECHO ATi Radeon 3100 Graphics drivers have been successfully installed!
EXIT
&lt;/textarea&gt;&lt;span class=&quot;caption&quot; style=&quot;font-weight:bold&quot;&gt;Figure 2. Install.cmd source code.&lt;/span&gt;&lt;/div&gt;&lt;p&gt;This will (more or less) silently install the driver and all accompanying software that you chose. (NOTE: I removed the following folders from the \Packages\Apps directory: CatalystRegistration (a registration nag-ware) and Blizzard (an Internet shortcut to download a trial version of the game World of Warcraft.) Once this batch file has been executed, you need to restart the computer. (NOTE: if you are using the Microsoft Deployment Toolkit to deploy your operating system, you must tell MDT that the application requires a reboot and let MDT reboot the computer or you will mess up the automated deployment.)&lt;/p&gt;&lt;p&gt;Once the computer has rebooted, your video resolution will be 800x600 @ 32-bit. Unfortunately, Windows still does not have a way to &quot;script&quot; the video resolution through an API. No Windows Script interface, no WMI, no PowerShell. So we are left to &quot;hacking&quot; the Windows registry. Please note that the batch file below has only been tested on Windows Vista. For any other operating system, verify the keys that need to be set (perhaps the resolution switches only work for Windows XP and below?).&lt;/p&gt;&lt;div&gt;&lt;textarea cols=&quot;53&quot; rows=&quot;15&quot; wrap=&quot;off&quot;&gt;
@ECHO OFF
ECHO Changing desktop resolution...
FOR /F &quot;tokens=2 delims={}&quot; %%a in (&#39;REG QUERY HKLM\SYSTEM\CurrentControlSet\Control\Video /s /f VolatileSettings&#39;) DO SET VIDEOCARD=%%a
ECHO Video Card GUID is: %VIDEOCARD%
ECHO.

REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v Attach.RelativeX /t REG_DWORD /d 0 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v Attach.RelativeY /t REG_DWORD /d 0 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v DefaultSettings.BitsPerPel /t REG_DWORD /d 32 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v DefaultSettings.FixedOutput /t REG_DWORD /d 0 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v DefaultSettings.Flags /t REG_DWORD /d 0 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v DefaultSettings.Orientation /t REG_DWORD /d 0 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v DefaultSettings.VRefresh /t REG_DWORD /d 75 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v DefaultSettings.XPanning /t REG_DWORD /d 0 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v DefaultSettings.XResolution /t REG_DWORD /d 1280 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v DefaultSettings.YPanning /t REG_DWORD /d 0 &amp;gt; nul
REG ADD &quot;HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\Video\{%VIDEOCARD%}\0000&quot; /v DefaultSettings.YResolution /t REG_DWORD /d 1024 &amp;gt; nul

ECHO Done.
ECHO.
ECHO.
ECHO Enabling Windows Vista Aero User Interface...
REM This command was wrong. It will enable Aero, but will not update the system score.
REM WinSAT dwm &amp;gt; nul
WinSAT formal &amp;gt; nul
ECHO.
ECHO Done.
ECHO.
ECHO.
ECHO ATi Radeon 3100 Graphics card successfully installed and configured!
EXIT
&lt;/textarea&gt;&lt;span class=&quot;caption&quot; style=&quot;font-weight:bold&quot;&gt;Figure 3. SetVideoRes.cmd source code.&lt;/span&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;&amp;gt; nul&lt;/code&gt; makes the batch script not output anything to the screen since REG.exe and WinSAT probably use stdout or stderr bypassing the &lt;code&gt;@ECHO OFF&lt;/code&gt; command in the batch file. I called this batch file SetVideoRes.cmd. It first uses REG QUERY to determine the &lt;acronym title=&quot;Globally Unique Identifier&quot;&gt;GUID&lt;/acronym&gt; of the video card and stores it in a variable. Then it creates several registry entries in the registry pertaining to the display resolution. Finally, it runs the Windows System Assessment Tool to enable the Aero user interface. Once this script has run, the computer needs to be rebooted again so that Windows picks up the new display resolution settings. And finally, there you have it, a completely unattended installation of the Catalyst Display Driver package. Too much work. For &lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;#intel&quot;&gt;&lt;/a&gt;Intel&lt;/span&gt;, this would have been as easy as calling &lt;code&gt;setup /s /v/qn&lt;/code&gt; if it&#39;s an InstallShield installer or &lt;code&gt;&amp;lt;driver_installer&amp;gt;.msi /qn /norestart&lt;/code&gt; if it were an actual Windows MSI.&lt;/p&gt;&lt;p&gt;I hope this helps someone out there. It took me a whole week, installing the operating system about 25 times to figure this all out. What a pain! I did contact &lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;#amd&quot;&gt;&lt;/a&gt;AMD&lt;/span&gt; Customer Care, but they basically told me that they provided limited unattended install support and that they only supported unattended installs on Windows Vista for particular ATi products. Poor business practice, in my opinion. Not everyone is a Hewlett-Packard or a Microsoft.&lt;/p&gt;&lt;p&gt;One final note, I just finished a book on microformats on the web. This blog entry is long enough, so suffice it to say, I&#39;ve tried my hand at a few hCard entries in this post. Not every company mentioned has an hCard entry. I may go back and update this entry later. I mention this only for those who may be looking. I&#39;m going to write more about that in another post.&lt;/p&gt;&lt;p&gt;That&#39;s it for now. Sorry it was so long. Take care.&lt;/p&gt;&lt;h4&gt;Updates&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;2009-05-14&lt;/b&gt; - Fixed code in SetVideoRes.cmd in figure 3: Added quotes around the registry key because the keyname has a space. Also removed the warning about testing on Vista. I have tested the code and it does work. However, it should go without saying that anything you take off the Internet should be tested in a secure, isolated environment before being put into production. Also fixed my SetVideoRes.cmd batch file to call &lt;code&gt;C:\Windows\System32\WinSAT formal&lt;/code&gt; to make sure that the experience score actually gets updated in the System display window.&lt;/li&gt;&lt;/ul&gt;</description><link>http://discoveringcode.blogspot.com/2009/05/ati-catalyst-94-is-no-good-for-business.html</link><author>noreply@blogger.com (Craig S.)</author><thr:total>12</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-1769143688504954536</guid><pubDate>Sat, 09 May 2009 19:55:00 +0000</pubDate><atom:updated>2009-05-09T16:29:49.608-04:00</atom:updated><title>It&#39;s been a while...</title><description>&lt;p&gt;Hello everyone. Well, don&#39;t say I didn&#39;t give you fair warning about the frequency of posting on this blog.&lt;/p&gt;&lt;p&gt;Anyway, call it bad timing, but I started this blog about 8 weeks before the end of the semester. Four weeks later, of course, all the professors are cramming assignments down our throat trying to get in as much as they can because they realized that the semester is nearly over! To their credit, this semester was extremely compressed, partly due to the way the calendar fell this year and partly due to other reasons which I&#39;m not going to expound upon at this time.&lt;/p&gt;&lt;p&gt;So the last five weeks were really busy and this was my first week back at work in a while as well. In addition, I&#39;ve been meaning to continue my series of blog posts on the network infrastructure upgrade at work, but issues with VMware have kept me from making any progress on that front as well. I think I have those issues worked out now so that I can document the process.&lt;/p&gt;&lt;h4&gt;Coming up...&lt;/h4&gt;&lt;p&gt;I don&#39;t know how long it&#39;s going to take me before I post my next entry (hopefully no longer than a week) nor how long it may be in between posts, but, I hope to keep them coming. Here&#39;s what I plan on writing about in the near-term.&lt;/p&gt;&lt;h5&gt;Installation of Windows 2003 &lt;acronym title=&quot;Small Business Server&quot;&gt;SBS&lt;/acronym&gt; &lt;acronym title=&quot;Release 2&quot;&gt;R2&lt;/acronym&gt; Premium with &lt;acronym title=&quot;Service Pack 2&quot;&gt;SP2&lt;/acronym&gt;&lt;/h5&gt;&lt;p&gt;I plan on detailing my implementation of Windows &lt;acronym title=&quot;Small Business Server&quot;&gt;SBS&lt;/acronym&gt; 2003 Premium &lt;acronym title=&quot;Release 2&quot;&gt;R2&lt;/acronym&gt;. Why &lt;acronym title=&quot;Small Business Server&quot;&gt;SBS&lt;/acronym&gt; 2003? Well, a couple of reasons:&lt;ul&gt;&lt;li&gt;This is my first ever ground-up network infrastructure deployment. This means that it&#39;s taking me a lot longer than it would for an experienced network engineer, especially since I&#39;m figuring this stuff out all for myself. However, I have plenty of networking experience and feel confident in my ability. But if you should see anything that I&#39;m doing wrong or feel I should do differently, I would love to hear from you.&lt;/li&gt;&lt;li&gt;I started with Windows 2003 &lt;acronym title=&quot;Small Business Server&quot;&gt;SBS&lt;/acronym&gt; &lt;acronym title=&quot;Release 2&quot;&gt;R2&lt;/acronym&gt; and have it installed in a testing environment right now. I can&#39;t very well just throw everything away to start over with Windows 2008 &lt;acronym title=&quot;Small Business Server&quot;&gt;SBS&lt;/acronym&gt;, even though I would love to. Luckily, my hardware is 64-bit (Pentium D).&lt;/li&gt;&lt;li&gt;I&#39;m writing this blog on a 64-bit Toshiba laptop, but dumb Toshiba only installs 32-bit Vista OSes on their machines (as of late 2008). What gives?? Don&#39;t get me wrong, I love this laptop, I just wish I would have had a choice. In addition, the processor in this laptop does not have Intel&#39;s VMI, so I can&#39;t run a 64-bit guest OS on a 32-bit host. You know how it is, you load up a machine with all your apps (Visual Studio, Office, every other development/networking tool on the planet) and it would take you months to get your machine back to the way it is now if you have to reload (the only way to &quot;upgrade&quot; to a 64-bit OS).&lt;/li&gt;&lt;/ul&gt;
So, I&#39;m stuck with Windows &lt;acronym title=&quot;Small Business Server&quot;&gt;SBS&lt;/acronym&gt; 2003. However, in a later series of posts, I may detail the installation of Windows 2008 &lt;acronym title=&quot;Small Business Server&quot;&gt;SBS&lt;/acronym&gt; when/if I reload. Having said that, at this point, I think I&#39;m going to wait for Windows 7 to come out to upgrade to that. So, then I might as well detail Windows 7 &lt;acronym title=&quot;Small Business Server&quot;&gt;SBS&lt;/acronym&gt;. But that&#39;s at least a year out, and by then, I may not be doing anything regarding networking because I&#39;m more of a coder.&lt;/p&gt;&lt;h5&gt;Installing/Using Microsoft Deployment Toolkit 2008 (or 2010)&lt;/h5&gt;&lt;p&gt;Once I detail my implementation of the core installation of Windows 2003 &lt;acronym title=&quot;Small Business Server&quot;&gt;SBS&lt;/acronym&gt;, I&#39;m going to delve into using the &lt;acronym title=&quot;Microsoft Deployment Toolkit&quot;&gt;MDT&lt;/acronym&gt; 2008 (formerly &lt;acronym title=&quot;Business Desktop Deployment&quot;&gt;BDD&lt;/acronym&gt; 2007) or &lt;acronym title=&quot;Microsoft Deployment Toolkit&quot;&gt;MDT&lt;/acronym&gt; 2010, if it&#39;s out by then, for deploying Microsoft Windows Vista with &lt;acronym title=&quot;Service Pack 1&quot;&gt;SP1&lt;/acronym&gt;.&lt;/p&gt;&lt;p&gt;So that&#39;s it in a nutshell. That&#39;s what you can look forward to over the next few posts.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2009/05/its-been-while.html</link><author>noreply@blogger.com (Craig S.)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-208886340265757582</guid><pubDate>Thu, 05 Mar 2009 01:05:00 +0000</pubDate><atom:updated>2009-03-04T20:05:28.300-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">introduction</category><title>Re-engineering the Network&amp;mdash;from the Ground, Up</title><description>&lt;p&gt;This post is a continuation of my series of posts related to the network re-engineering project I&#39;ve undertaken at work. A lot of work has already been done, but there is still a lot that has yet to be done. If you need to get a quality, professional network in place, but don’t want to spend the money (or don’t have the money) to buy the requisite hardware, &lt;a href=&#39;http://www.ebay.com&#39; title=&#39;eBay&#39;&gt;eBay&lt;/a&gt; is a great place to shop. I found much of the hardware that we required at up to 50% off, or more, most of it brand new.&lt;/p&gt;&lt;p&gt;Here’s the hardware that was bought for this project:&lt;ul&gt;&lt;li&gt;3 Dell Dimension 2400 Desktop Mid-Towers (2004)&lt;/li&gt;&lt;li&gt;2 Dell Inspiron 700 Laptops (2004)&lt;/li&gt;&lt;li&gt;2 Custom PC Towers with FoxConn motherboards (Intel 865A chipset) (2004)&lt;/li&gt;&lt;li&gt;1 Dell PowerEdge 860 1&lt;abbr title=&#39;Rack Unit&#39;&gt;U&lt;/abbr&gt; Rack-mount Server (2006)&lt;/li&gt;&lt;li&gt;1 Dell Dimension E520 Desktop Mid-Tower (2007)&lt;/li&gt;&lt;li&gt;1 25&lt;abbr title=&#39;Rack Unit&#39;&gt;U&lt;/abbr&gt; 19&lt;abbr title=&#39;inch&#39;&gt;in.&lt;/abbr&gt; server rack&lt;/li&gt;&lt;li&gt;1 Dell PowerConnect 5324 1&lt;abbr title=&#39;Rack Unit&#39;&gt;U&lt;/abbr&gt; Rack-mount 24-port Gigabit Managed Ethernet Switch&lt;/li&gt;&lt;li&gt;1 Gruber 48-port &lt;acronym title=&#39;Category&#39;&gt;CAT&lt;/acronym&gt; 6 Patch Panel&lt;/li&gt;&lt;li&gt;1 3&lt;abbr title=&#39;Rack Unit&#39;&gt;U&lt;/abbr&gt; Rack-mount &lt;abbr title=&#39;American Power Conversion Corporation&#39;&gt;APC&lt;/abbr&gt; Smart-&lt;abbr title=&#39;Uninterruptible Power Supply&#39;&gt;UPS&lt;/abbr&gt; 3000R&lt;/li&gt;&lt;li&gt;1 Dell 110T PowerVault &lt;abbr title=&#39;Linear Tape-Open&#39;&gt;LTO&lt;/abbr&gt; Backup Tape Drive&lt;/li&gt;&lt;li&gt;1 1&lt;abbr title=&#39;Rack Unit&#39;&gt;U&lt;/abbr&gt; Rack-mount Belkin 8-Port &lt;abbr title=&#39;Keyboard, Video, Mouse aggregator&#39;&gt;KVM&lt;/abbr&gt;&lt;/li&gt;&lt;li&gt;1 &lt;a href=’http://www.talkswitch.com’&gt;TalkSwitch&lt;/a&gt; &lt;abbr title=&#39;Voice over Internet Protocol&#39;&gt;VoIP&lt;/abbr&gt; &lt;abbr title=&#39;Private Branch Exchange&#39;&gt;PBX&lt;/abbr&gt; Phone System and 12 &lt;abbr title=&#39;Internet Protocol&#39;&gt;IP&lt;/abbr&gt; phones of various models&lt;/li&gt;&lt;li&gt;1 Hewlett-Packard &lt;abbr title=&#39;Advanced Micro Devices, Inc.&#39;&gt;AMD&lt;/abbr&gt;-based x64 &lt;abbr title=&#39;Small Form Factor&#39;&gt;SFF&lt;/abbr&gt; Desktop (2009)&lt;/li&gt;&lt;li&gt;1 Hewlett-Packard 7650n ScanJet Color Network Scanner w/ &lt;abbr title=&#39;Automatic Document Feeder&#39;&gt;ADF&lt;/abbr&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;All of the client computers have been upgraded such that the machines contain no less than 1.5&lt;abbr title=&#39;gigabyte&#39;&gt;GB&lt;/abbr&gt; of &lt;acronym title=&#39;Random Access Memory&#39;&gt;RAM&lt;/acronym&gt; (most of the machine’s video cards are so old that they preclude using the Windows Vista Aero user interface anyway, so we won’t need as much memory). The 64-bit machine, however, was upgraded to have 4&lt;abbr title=&#39;gigabyte&#39;&gt;GB&lt;/abbr&gt; of &lt;acronym title=&#39;Random Access Memory&#39;&gt;RAM&lt;/acronym&gt;, as well as the PowerEdge 860 server (since I only have the 32-bit version of Windows &lt;abbr title=&#39;Small Business Server&#39;&gt;SBS&lt;/abbr&gt; 2003).&lt;/p&gt;&lt;p&gt;The software we’ll be implementing is as follows:&lt;ul&gt;&lt;li&gt;Microsoft Windows Small Business Server (SBS) 2003 R2 Premium, which includes:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Microsoft Windows Server 2003&lt;/li&gt;&lt;li&gt;Microsoft Exchange Server 2003&lt;/li&gt;&lt;li&gt;Internet Security and Acceleration (ISA) Server 2004&lt;/li&gt;&lt;li&gt;Windows SharePoint Services 2.0 (which we&#39;ll be upgrading to 3.0 &lt;abbr title=&#39;Service Pack&#39;&gt;SP&lt;/abbr&gt;1&lt;/li&gt;&lt;li&gt;Windows Software Update Services (WSUS) 2.0 (which we&#39;ll be ugrading to 3.0)&lt;/li&gt;&lt;li&gt;Microsoft &lt;abbr title=&#39;Structured Query Language&#39;&gt;SQL&lt;/abbr&gt; Server 2005, Workgroup Edition (we&#39;ll be upgrading to Standard Edition, courtesy of Microsoft Volume Licensing)&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Microsoft Office 2007 Professional Plus&lt;/li&gt;&lt;li&gt;Microsoft Windows Vista Business/Enterprise (with &lt;abbr title=&#39;Service Pack&#39;&gt;SP&lt;/abbr&gt;1)&lt;/li&gt;&lt;li&gt;Microsoft Desktop Optimization Pack (MDOP, from which we&#39;ll be using:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Microsoft SoftGrid Application Virtualization&lt;/li&gt;&lt;li&gt;Advanced Group Policy Management (AGPM)&lt;/li&gt;&lt;li&gt;Microsoft System Center Desktop Error Monitoring&lt;/li&gt;&lt;li&gt;Asset Inventory Service&lt;/li&gt;&lt;li&gt;Diagnostics and Recovery Toolset&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Trend Micro Worry Free Business Security&lt;/li&gt;&lt;li&gt;Symantec BackupExec 12.5 (soon to be Acronis, too many problems with Symantec, more on that later)&lt;/li&gt;&lt;li&gt;ACT! by Sage 2008&lt;/li&gt;&lt;li&gt;&lt;abbr title=&#39;United Parcel Service&#39;&gt;UPS&lt;/abbr&gt; WorldShip 2009&lt;/li&gt;&lt;li&gt;Possibly Adobe CreativeSuite4&lt;/li&gt;&lt;/ul&gt;There are probably some items I forgot about, but you get the gist.&lt;/p&gt;&lt;h4&gt;Where We’ve Been, Where We Are&lt;/h4&gt;&lt;p&gt;At this point, we have laid down a new cable plant consisting of &lt;acronym title=’Category’&gt;CAT&lt;/acronym&gt; 5e cable. We ran two different sets of wires for each drop location, one for data, one for voice.&lt;/p&gt;&lt;p&gt;This was done for a number of reasons. One, &lt;abbr title=&#39;Voice over Internet Protocol&#39;&gt;VoIP&lt;/abbr&gt; is still not quite there. I can recall on numerous occasions getting a phone call at work from someone who was (most likely) overseas, trying to peddle some wares. The call was so broken up and choppy that I simply told the caller, &quot;Your call is breaking up. Try calling me back on a real landline and we can talk,&quot; at which point, I hung up. I don’t have time to waste constantly telling someone to please repeat themselves when I’m probably not going to be interested to begin with. (Usually it’s people calling trying to get me to outsource our &lt;abbr title=&#39;Information Technology&#39;&gt;IT&lt;/abbr&gt;&amp;mdash;for what? Ten client workstations? Please.) Two, after doing other research, I came to the conclusion that while &lt;abbr title=&#39;Voice over Internet Protocol&#39;&gt;VoIP&lt;/abbr&gt; has made great strides over the last 4 years, it’s not ready for prime time and I don’t want to trust that it’ll work ok over the same network over which data travels. What if someone is downloading a 600&lt;abbr title=&#39;megabyte&#39;&gt;MB&lt;/abbr&gt; &lt;abbr title=’Compact Disc’&gt;CD&lt;/abbr&gt; (which would probably be me)? Will the call be dropped, or broken and chopped up? We can’t afford to have that poor of a level of service for our customers since a majority of our business is still conducted over the phone. So, for all of those reasons, we will have &lt;abbr title=&#39;Voice over Internet Protocol&#39;&gt;VoIP&lt;/abbr&gt; traffic running over its own network, internally. Once the voice traffic leaves the premises, it’ll be traveling over the &lt;acronym title=’Plain Old Telephone System’&gt;POTS&lt;/acronym&gt;.&lt;/p&gt;&lt;p&gt;I’m fortunate that our &lt;span title=&#39;A pet name for our Compaq Proliant 5000 series server.&#39; style=&#39;text-decoration: underline; color: #008000;&#39;&gt;Clydesdale&lt;/span&gt; is still running and functioning. That means that I can mess around with the PowerEdge 860 all I want. I have installed and configured Windows &lt;abbr title=&#39;Small Business Server&#39;&gt;SBS&lt;/abbr&gt; 2003 R2 Premium. Perhaps, in a later post, I’ll go through the configuration process. Right now, this is an &quot;experimental&quot; setup. Basically, because I’m installing and uninstalling software, I plan on reinstalling the server when I’m ready to go to production so it is a clean and error free system. But since I have the process pretty much down, this should only take a few hours.&lt;/p&gt;&lt;p&gt;I had only one desktop computer left which is not in production. I really needed another machine. Here’s the problem: Windows Vista cannot be completely managed from Windows Server 2003. Mostly, this has to do with &lt;abbr title=’Group Policy’&gt;GP&lt;/abbr&gt; administration and management. Luckily, we qualified for a new desktop computer through &lt;abbr title=&#39;United Parcel Service&#39;&gt;UPS&lt;/abbr&gt;&#39;s Customer Technology Program. So we acquired a Hewlett-Packard small form factor (SFF) desktop machine sporting an &lt;abbr title=&#39;Advanced Micro Devices, Inc.&#39;&gt;AMD&lt;/abbr&gt; 64-bit processor (dual core). So this is becoming my management workstation, for now, and the remaining client that is left will be the test production client whose configuration will be that of all desktops in the organization (less specific drivers for each of the different machines we&#39;ll have in use).&lt;/p&gt;&lt;h4&gt;Where We’re Going&lt;/h4&gt;&lt;p&gt;My company is small, but that doesn’t mean that it can’t benefit from automation, especially when it comes to &lt;abbr title=&#39;Information Technology&#39;&gt;IT&lt;/abbr&gt;. So I have set the following goals:&lt;ul&gt;&lt;li&gt;An Active Directory-based domain&lt;/li&gt;&lt;li&gt;An internal e-mail server (Exchange Server 2003). Our &lt;abbr title=&#39;Internet Service Provider&#39;&gt;ISP&lt;/abbr&gt; e-mail is showing its inadequacies.&lt;/li&gt;&lt;li&gt;Central Management and Administration&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Group Policy&lt;/li&gt;&lt;li&gt;Application Virtualization&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Implementation of a Secure, Managed Desktop&lt;/li&gt;&lt;li&gt;A lightweight helpdesk system (included with SharePoint Services)&lt;/li&gt;&lt;li&gt;Implementation of &lt;abbr title=&#39;Virtual Private Network&#39;&gt;VPN&lt;/abbr&gt; access (if needed) and/or remote access via Terminal Services, mainly for remote administration&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;I feel these goals will accomplish a few things for me. I won’t always need to be in my office in order to work. This is important since I am currently only working part time while attending Kutztown University. The users can expect a consistent desktop experience. I can expect a consistent desktop experience&amp;mdash;this means I know exactly what’s installed on the desktop, what the security topology is, and therefore, I know better how to diagnose and repair problems when they arrive.&lt;/p&gt;&lt;h4&gt;Next Steps&lt;/h4&gt;&lt;p&gt;I’ve been using the Microsoft Deployment Toolkit (MDT) 2008 to develop the deployment process. It’s been working quite well. Unfortunately, the documentation is geared more toward large corporate users (even though they say even small corporations will find the tool useful). The toolkit is useful, just there’s not much help. And when you first begin to use it, it’s quite overwhelming. However, over the last few weeks, I’ve really learned the ins and outs of this toolkit, some of which I’ll be sharing over the next few posts. So keep checking back for information on using the &lt;abbr title=&#39;Microsoft Deployment Toolkit&#39;&gt;MDT&lt;/abbr&gt; 2008.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2009/03/re-engineering-network-ground-up.html</link><author>noreply@blogger.com (Craig S.)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-4407491050871351784</guid><pubDate>Wed, 04 Mar 2009 01:37:00 +0000</pubDate><atom:updated>2009-03-04T15:41:39.071-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">introduction</category><title>The State of My Company&#39;s Network Infrastruture</title><description>&lt;p&gt;Ok, so I can’t blame my company for the state of their network. We are a very small company with limited resources. But, our network is getting ridiculously old. Let’s give a quick rundown of what this network is like.&lt;ul&gt;&lt;li&gt;A Compaq Proliant 5000 series server with:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;4 x 200 &lt;abbr title=&#39;megahertz&#39;&gt;MHz&lt;/abbr&gt;, 256&lt;abbr title=&#39;kilobyte&#39;&gt;KB&lt;/abbr&gt; Cache, PentiumPro processors&lt;/li&gt;&lt;li&gt;256&lt;abbr title=&#39;megabyte&#39;&gt;MB&lt;/abbr&gt; &lt;abbr title=&#39;Error Correcting Code&#39;&gt;ECC&lt;/abbr&gt;, Registered, Bufferd &lt;abbr title=&#39;Static, Dynamic&#39;&gt;SD&lt;/abbr&gt;-&lt;acronym title=&#39;Random Access Memory&#39;&gt;RAM&lt;/acronym&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;acronym title=&#39;Category&#39;&gt;CAT&lt;/acronym&gt; 3 cable plant&lt;/li&gt;&lt;li&gt;Microsoft Windows&lt;sup&gt;&amp;reg;&lt;/sup&gt; 2000 Professional clients (one is still running Windows 98&lt;sup&gt;&amp;reg;&lt;/sup&gt;!)&lt;/li&gt;&lt;li&gt;Microsoft Office 2000/2003&lt;/li&gt;&lt;li&gt;Trend Micro OfficeScan, Corporate Edition antivirus software&lt;/li&gt;&lt;li&gt;8-port 10&lt;abbr title=&#39;megabit&#39;&gt;Mbit&lt;/abbr&gt; Hub&lt;/li&gt;&lt;li&gt;4-port LinkSys Cable/&lt;abbr title=&#39;Digital Subscriber Line&#39;&gt;DSL&lt;/abbr&gt; Router (one of the old ones)&lt;/li&gt;&lt;li&gt;4-port LinkSys WRT54G Wireless Cable/&lt;abbr title=&#39;Digital Subscriber Line&#39;&gt;DSL&lt;/abbr&gt; Router&lt;/li&gt;&lt;/ul&gt;That about sums it up. So this is a pretty old setup. But hey, it was pieced together from about 1992 until about 1999. We only recently (about two years ago) &quot;upgraded&quot; to Windows 2000 on the desktops. For some reason, Windows XP is not liked. I think it’s because it looks radically different from Windows NT/2000. But no matter the case, it’s a moot point now.&lt;/p&gt;&lt;h4&gt;A Bit of Momentum&lt;/h4&gt;&lt;p&gt;Well, we bought 5 new machines a few years back. I was trying to automate the installation of the client desktops, but it’s so difficult with Windows 2000 (without having Microsoft&lt;sup&gt;&amp;reg;&lt;/sup&gt; &lt;abbr title=&#39;System Management Server&#39;&gt;SMS&lt;/abbr&gt;, which is too much for our size company anyway). Since it&#39;s nearly impossible to completely automate Windows 2000 (from the installation to client applications) without something like Microsoft&lt;sup&gt;&amp;reg;&lt;/sup&gt; &lt;abbr title=&#39;System Management Server&#39;&gt;SMS&lt;/abbr&gt;, I didn’t get very far before the older client machines started dying, one by one. Eventually, all but one of the new machines were put into production loaded with Windows 2000 Professional (manually).&lt;/p&gt;&lt;p&gt;Now, as you can imagine, this has caused lots of problems:&lt;ol&gt;&lt;li&gt;Each system’s operating system configuration is slightly different (thankfully, the hardware is all the same)&lt;/li&gt;&lt;li&gt;The machine is locked down with Local &lt;abbr title=&#39;Group Policy Objects&#39;&gt;GPO&lt;/abbr&gt;s since we do not have a Windows 2000 Server Active Directory domain.&lt;/li&gt;&lt;ol&gt;&lt;li style=&#39;list-style-type:lower-alpha&#39;&gt;The disadvantage here is that even local administrators have the &lt;abbr title=&#39;Group Policy Object&#39;&gt;GPO&lt;/abbr&gt; applied to their account, locking me out of the system (unless I undo the &lt;abbr title=&#39;Group Policy Object&#39;&gt;GPO&lt;/abbr&gt; while I work on the machine and then put it back on).&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;As alluded to above, there is no real central administration and management of the workstations, making my job 10 times harder.&lt;/li&gt;&lt;li&gt;I no longer have enough computers to have a good test network for the new infrastructure being planned (more on this later).&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;&lt;p&gt;As for our Compaq Proliant server, we call it the Clydesdale. It’s a big old horse that just keeps going and going, even though it’s battered, bruised, and broken. It’s quite a worrisome thing, actually. Recently, we had to invest in some new (well, not new, but procured from eBay) fans since most of the  fans on the server are shot. If the server loses power, sometimes it doesn’t start back up because of a missing (read, not working) fan. Next time it goes down, some new fans are going in that sucker. With those spare parts in hand, we’ll be ok until the migration is complete.&lt;/p&gt;&lt;p&gt;So it’s obvious that that server has got to go, and so it will. About three years ago this coming October, we bought a new Dell PowerEdge 860 server.&lt;/p&gt;&lt;h4&gt;The Tipping Point&lt;/h4&gt;&lt;p&gt;So the last critical client machine died and I replaced it with one of the new boxes with Windows 2000 Professional. No more than two months later, one of the executives says, &quot;I&#39;d like to run the new version of ACT!&quot; Not only on his desktop, but also on the inside sales desktops. I thought, no problem. So I did my research. Turns out, after getting most everyone upgraded to Windows 2000, the latest version of ACT! does not run on Windows 2000. It requires at least Windows XP. And by this time (late 2007), Windows XP was going to be no longer supported by Microsoft&lt;sup&gt;&amp;reg;&lt;/sup&gt; in 2009. This was the tipping point.&lt;/p&gt;&lt;p&gt;Up until this time, software was acquired as needed, paying full retail price (or finding legal copies on eBay or at computer shows). After doing some math, I proposed that now is the time we go all in. I learned that you have to play by their rules, or you end up losing big time.&lt;/p&gt;&lt;h4&gt;A Philosophical Break&lt;/h4&gt;&lt;p&gt;I prefer Microsoft&lt;sup&gt;&amp;reg;&lt;/sup&gt; products. I don’t love Microsoft&lt;sup&gt;&amp;reg;&lt;/sup&gt;&amp;mdash;I’ve had my share of headaches when it comes to their products. But by and large, they work well. However, I don’t dislike Linux. I think it’s a great and viable OS, just not right for our company. I believe in using the right tool for the right job, and evaluate these criteria on a case-by-case basis.&lt;/p&gt;&lt;p&gt;There are studies that show that even with licensing costs, Microsoft&lt;sup&gt;&amp;reg;&lt;/sup&gt; software has a lower &lt;abbr title=&#39;Total Cost of Ownership&#39;&gt;TCO&lt;/abbr&gt; than Linux (because of having to find someone with the technical acumen to administrate it, and despite claims to the contrary, at some point in time, it will need administration and management). But more importantly, we have software in use that can only run on Microsoft&lt;sup&gt;&amp;reg;&lt;/sup&gt; platforms that is critical to our business.&lt;/p&gt;&lt;p&gt;Not to belabor the point, but if you have the technical expertise and the system does what you need it to do, who can argue with free software? So I am not against Linux, it’s just not right for us in this instance.&lt;/p&gt;&lt;h4&gt;Back to the Story&lt;/h4&gt;&lt;p&gt;So after evaluating our options (Linux included), I decided it was best if we entered into a Volume License agreement with Microsoft&lt;sup&gt;&amp;reg;&lt;/sup&gt;. A new project was born. More on that in my next post.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2009/03/state-of-my-companys-network.html</link><author>noreply@blogger.com (Craig S.)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-8130307219229976098</guid><pubDate>Tue, 03 Mar 2009 21:24:00 +0000</pubDate><atom:updated>2009-03-04T14:56:36.898-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">introduction</category><title>A Little More About Me</title><description>&lt;p&gt;If you read my first post, you know that I am currently a student at Kutztown University. I have been fortunate in that my schedule has allowed me to take a full course load while still working two full days a week.&lt;/p&gt;&lt;h4&gt;My Professional Life&lt;/h4&gt;&lt;p&gt;First, I need to start with the legal stuff. Please read my &lt;a href=&quot;http://www.blogger.com/1977/04/disclaimer.html&quot;&gt;disclaimer&lt;/a&gt;, to which a link can be found at the bottom of this blog in the footer. To summarize for purposes of this post, anything I write here are my own views and opinions and do not reflect the views and opinions of my employer. Again, click the link to read my whole disclaimer. It&#39;s sad—the state of this world, that we can&#39;t even do anything without having to cover our butts—but I digress.&lt;/p&gt;&lt;p&gt;Now that that’s out of the way, let’s get started. I work for a small manufacturer of temperature sensors used for industrial process control. The company was founded in 1985 and produces thermocouples and Resistor Temperature Devices (RTDs). Perhaps in another post I’ll explain all about thermocouples and &lt;acronym title=&quot;Resistor Temperature Device&quot;&gt;RTD&lt;/acronym&gt;s and how they work.&lt;/p&gt;&lt;p&gt;Suffice it to say, the company was started well before the Internet that we know today became popular, even before computer networking became what it is today. Computers were at use since the very beginning. But, throughout the early and mid-1990’s, the computing infrastructure grew and eventually became networked.&lt;/p&gt;&lt;p&gt;In 1994, Microsoft&lt;sup&gt;®&lt;/sup&gt; Windows NT 4.0 was released, and this is the network operating system still in use today. As you might have guessed, my company has no need to be on the bleeding edge of technology. Having said that, this network is quite old and no longer suits our purposes. That’s where I come in.&lt;/p&gt;&lt;h4&gt;My Role&lt;/h4&gt;&lt;p&gt;Since my company is a small company, I wear many hats, and not all of them have to deal with &lt;acronym title=&quot;Information Technology&quot;&gt;IT&lt;/acronym&gt;. I’ve served in the following roles at one time or another (sometimes all at the same time) over the last 5 years:&lt;ul&gt;&lt;li&gt;Inventory Control&lt;/li&gt;&lt;li&gt;Shipping/Receiving&lt;/li&gt;&lt;li&gt;Production Manager&lt;/li&gt;&lt;li&gt;Purchasing&lt;/li&gt;&lt;li&gt;Information Technology&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;So I’ve been quite busy. These days, however, my focus has been squarely on &lt;acronym title=&quot;Information Technology&quot;&gt;IT&lt;/acronym&gt;.&lt;/p&gt;&lt;p&gt;I am basically the &lt;acronym title=&quot;Chief Technology Officer&quot;&gt;CTO&lt;/acronym&gt; and/or &lt;acronym title=&quot;Chief Information Officer&quot;&gt;CIO&lt;/acronym&gt;, but I settle for the title &lt;acronym title=&quot;Information Technology&quot;&gt;IT&lt;/acronym&gt; Manager. I am responsible for anything that has something to do with computers. That means that I maintain the website (I did not create it, but I maintain it since I don’t have time to redesign it—which it sorely needs.), maintain the network, and write software when it is needed. I am also the in-house desktop publisher. So as you can see, I have a lot on my plate.&lt;/p&gt;&lt;h4&gt;Looking Ahead…&lt;/h4&gt;&lt;p&gt;So looking ahead, I will be writing about exactly what’s going on with our  network infrastructure. I will be making periodic posts on my progress. I won’t only blog about work, however, but until at least June or July, expect a lot of my posts to center around that. Besides, I will have some valuable information to share with others—I promise. So for the sake of trying to keep these posts somewhat short, I’ll be ending this one. The next one will give more information on the network re-engineering effort. Until then, so long.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2009/03/little-more-about-me.html</link><author>noreply@blogger.com (Craig S.)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5841632161546703012.post-2863590187500611505</guid><pubDate>Mon, 02 Mar 2009 19:17:00 +0000</pubDate><atom:updated>2009-03-02T20:00:56.584-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">introduction</category><title>Biting the Bullet</title><description>&lt;h4&gt;Why I&#39;m starting a blog&lt;/h4&gt;&lt;p&gt;I&#39;ve finally bitten the bullet. Unlike many people, I don&#39;t belong to any social networking sites, and until now, I haven&#39;t blogged. I never got into MySpace, or Facebook, or any of the others that are out there simply because I don&#39;t have time. By the time I got around to thinking about social networking, it has become quite obvious how dangerous social networking can be: from you yourself posting inappropriate content, to your &quot;friends&quot; doing that for you. Many employers now look for you on social networking sites trying to gain a glimpse of who you really are. No thanks. I&#39;ve got nothing to hide, but I don&#39;t want a reason to have something to hide either. Blogging has been around for quite a few years as well. Blogging could be almost as dangerous with all the comment spam, not to mention flippantly posting something that you might otherwis think better of later. But, comment spam can be controlled by not allowing comments (but then, what&#39;s the point of blogging?). As for inadvertantly (or regretfully) posting something? Well,you could delete the entry (as long as its whithin a few hours). But the better advice is to simply think before you post. So with that in mind, I&#39;ve started tihs blog.&lt;/p&gt;&lt;p&gt;I&#39;m so busy, however, that I never have time just to sit down and write for my own desire, let alone anyone else&#39;s reading pleasure, which is another reason I never really started a blog prior to now. Not that I have any more time now than I did before, but if you never make the time, you never will. Having said that, blogging is an important endeavor. It enables me to allow my voice to be heard by anyone who wishes to listen. I hope that even if you don&#39;t agree with everything I write, you will at least approach what I write with an open mind. I&#39;m willing to listen to other perspectives as well. And if I&#39;m wrong, please be gracious and let me know, as I love to learn as opposed to stumble in ignorance.
&lt;/p&gt;&lt;p&gt;But, more importantly, my blog will act simply as an information repository. In today&#39;s world where we are constantly bombarded by information, it is becoming increasingly more difficult to remember all those snippets of interesting things I read or hear about without writing them down somewhere. So this blog is as much (if not more so) for my benefit as it is for anyone else&#39;s—to help me remember those things I would otherwise forget. If anyone finds some useful information in what I have to write, that&#39;s great! I&#39;m glad I could help.&lt;/p&gt;&lt;h4&gt;Why is your blog called Discovering Code?&lt;/h4&gt;&lt;p&gt;This blog will not have one central topic or theme. This is a blog about discovery, and then trying to remember those things I have discovered. Not everything I blog about will necessarily be related to programming, though much of it will be, as that is my passion. My interests are wide and varying, however—from software engineering to computer engineering, to new hardware arriving on the scene, as well as topics related to science in general. I&#39;m an avid Popular Science reader. In short, there may be many things of interest here to many different readers.&lt;/p&gt;&lt;h4&gt;What can you expect from me?&lt;/h4&gt;&lt;p&gt;While I would like to say, &quot;Check back often for my latest entries,&quot; I can&#39;t guarantee how often I will actually post articles on my blog. So please, do check back, but don&#39;t expect something new everyday or even every week. I would like to at least write something here once a month.&lt;/p&gt;&lt;h4&gt;Who are you anyway?&lt;/h4&gt;&lt;p&gt;That&#39;s a very good question, and I&#39;m glad you asked. I am currently a student at Kutztown University, enrolled in the Computer Science Software Engineering program. The goal is to (finally) complete my Bachelor&#39;s Degree with a Minor in Mathematics, and then continue on to obtain my Master&#39;s Degree. My favorite programming language is C#. I have an interest in extending my knowledge in the arena of ASP.NET. Another interest I have, related to programming, is that of compiler theory and construction as well as computer engineering and operating system design (Kutztown University does not have a computer engineering program). I also have a keen interest in most sciences, especially astrophysics, astronomy, and chemistry.&lt;/p&gt;&lt;p&gt;Anyway, that&#39;s a little about me and why I&#39;m starting this blog. Like I said, please check back from time-to-time, hopefully I will have posted something useful, if not interesting at the very least.&lt;/p&gt;</description><link>http://discoveringcode.blogspot.com/2009/03/biting-bullet.html</link><author>noreply@blogger.com (Craig S.)</author></item></channel></rss>