This post originated from an RSS feed registered with .NET Buzz
by Peter G Provost.
Original Post: OpenPGP.NET - Part 1 - Getting Back Into TDD
Feed Title: Peter Provost's Geek Noise
Feed URL: /error.aspx?aspxerrorpath=/Rss.aspx
Feed Description: Technology news, development articles, Microsoft .NET, and other stuff...
I've decided to keep a running log of my progress on this project... at least until
I get sick and tired of it or until I bring on any other developers. I've also added
a category called OpenPGP.NET to group all of these messages. Here goes...
Last night I started the project. As I stated earlier I want to follow a few important
guidelines while developing this this:
Test-driven Development (aka Example Driven Development)
Since it is primarily a class library it should pass FxCop's rules
It should reuse as much of System.Security.Cryptography as possible
It must comply with OpenPGP RFC 2440
Having read all of the code for SharpPrivacy, some of the code for the Cryptix OpenPGP
Library for Java, and most of the RFC, I decided to get started by implementing
the packet types.
I started with a blank VS.NET solution and added a Class Library Project called Core.
I then added another project called Unit Tests. Setup my references and started thinking
about which tests to start with.
To gain familiarity with the OpenPGP packet structure, I decided to start with the
simplest packet: the User ID Packet. This packet has an OpenPGP packet header (packet
tag and length) followed by a packet body, which for this packet is defined as follows:
A User ID packet consists of data that is intended to represent the name and email
address of the key holder. By convention, it includes an RFC 822 mail name, but there
are no restrictions on its content. The packet length in the header specifies the
length of the user id. If it is text, it is encoded in UTF-8.
So the packet structure is a byte for the packet tag (in this case 13), a byte for
the length (not really true, but also not really important for this packet type) followed
by atrbitrary UTF-8 string.
I decided (for no good reason) to use Streams, so I wrote the following test. Note
that I am using NUnit 2.1 so this syntax may look a little different from what I've
written before.
Compiled and of course it failed because UserIdPacket didn't exist. Added the
UserIdPacket class and added a static ReadPacket method that returned null. Compiled
and ran the tests and of course it failed on the IsNotNull assertion. Excellent.
Now, as Kent Beck points out in his book Test-Driven
Development, you can take teeny-tiny little steps like this, or once you get comfortable
you can take bigger steps. Not feeling comfortable about the code you have to write?
Go back to teeny-tiny steps again.
So I updated the code in ReadPacket to have it return a new UserIdPacket. Voila! The
test runs. Time to move on. I know the code isn't implemented right, but that is a
failure in my tests, not a failure in my code.
So let's fix that by adding more tests. Here is the new TestParsePacket:
Now the test fails as it should. Back to the ParsePacket code...
Some people would go ahead and do the correct implementation at this point, but for
demonstration I'm going to continue taking teeny-tiny steps.
I added a UserId property and initialized it to "Peter Provost <peter@provost.org>".
Bam! Test passes. I win. :)
Once again, the problem is in the tests and not the code. My tests are exhaustive
enough so I will write more tests. I decided to copy the test body and repeat it passing
a different stream and testing for a different value. This test will probably get
me what I want.