Friday, September 4, 2009

Always Check Boundary Conditions, You Dumb Ass

‹prev | My Chain | next›

A bit of less CSS work and my mini-calendar is functional and pretty:


(commit)

Sadly, a bit of smoke testing turns up a little problem:



Dang it! I missed a boundary condition in my Haml template:
#...
- week = 0
- while ((sunday0 + week*7).mon <= day1.mon)
#...
The value of sunday0 represents the very first day on the calendar. For January 2008, that Sunday was December 30:
cstrom@jaynestown:~/repos/eee-code$ cal 01 2008
January 2008
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Oops. For week zero, the month is 12, but day1.mon is 1. In other words, the while condition evaluates to false immediately.

Dumb ass. Always check boundary conditions.

To drive the boundary condition check, I write a quick Cucumber scenario:
   Scenario: Navigating boundary conditions

Given a "Test" meal enjoyed on 2008-01-23
And a "Test" meal enjoyed on 2007-12-15
When I visit the mini-calendar
Then I should see the calendar for January 2008
And there should be 1 links to meals
When I click on the link to the previous month
Then I should see the calendar for December 2007
And there should be 1 links to meals
Since I am re-using previously defined steps, this scenario should pass right away. Of course, I have that little bug in there:
  Scenario: Navigating boundary conditions
Given a "Test" meal enjoyed on 2008-01-23
And a "Test" meal enjoyed on 2007-12-15
When I visit the mini-calendar
Then I should see the calendar for January 2008
And there should be 1 links to meals
expected following output to contain a <td a/> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head><link href="/stylesheets/style.css" rel="stylesheet" type="text/css"></head>
<html><body id="mini-calendar">
<h1>
<span class="previous">
<a href="/mini/2007/12"><</a>
</span>
January 2008
<span class="next">
>
</span>
</h1>
<table id="mini-calendar"><tr class="day-names">
<th>Su</th>
<th>M</th>
<th>Tu</th>
<th>W</th>
<th>Th</th>
<th>F</th>
<th>Sa</th>
</tr></table>
</body></html>
</html>
(Spec::Expectations::ExpectationNotMetError)
features/mini_calendar.feature:33:in `And there should be 1 links to meals'
When I click on the link to the previous month
Then I should see the calendar for December 2007
And there should be 1 links to meals

Failing Scenarios:
cucumber features/mini_calendar.feature:27 # Scenario: Navigating boundary conditions

1 scenario (1 failed)
8 steps (1 failed, 3 skipped, 4 passed)
0m0.593s
I could just as easily have probed this via an example. Through the use of a Cucumber scenario, I can easily verify my fix not only for the January side of the boundary, but also the December side. Besides, there is a difference between driving the fix (via examples) and verifying the fix (with Cucumber).

The RSpec example that will drive the desired behavior in the Haml template:
  context "January" do
before(:each) do
assigns[:month] = "2008-01"
end

it "should have weeks (probing boundary condition)" do
render("views/mini_calendar.haml")
response.should have_selector("td")
end
end
First, I check to see that this example does fail:
cstrom@jaynestown:~/repos/eee-code$ spec ./spec/views/mini_calendar.haml_spec.rb
..............F

1)
'mini_calendar.haml January should have weeks (probing boundary condition)' FAILED
expected following output to contain a <td/> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head><link href="/stylesheets/style.css" rel="stylesheet" type="text/css"></head>
<html><body id="mini-calendar">
<h1>
<span class="previous">
<
</span>
January 2008
<span class="next">
<a href="/mini/2008/02">></a>
</span>
</h1>
<table id="mini-calendar"><tr class="day-names">
<th>Su</th>
<th>M</th>
<th>Tu</th>
<th>W</th>
<th>Th</th>
<th>F</th>
<th>Sa</th>
</tr></table>
</body></html>
</html>
./spec/views/mini_calendar.haml_spec.rb:107:

Finished in 0.255642 seconds

15 examples, 1 failure
To make this example pass (and hopefully the entire Cucumber scenario), I will update the while condition to compare the ISO 8601 string representation of the month rather than the month itself. This relies on the string "2007-12" being less than "2008-01". The updated while:
...
- week = 0
- while ((sunday0 + week*7).strftime("%Y-%m") <= day1.strftime("%Y-%m"))
...
That makes the example pass as well as the entire Cucumber scenario:
cstrom@jaynestown:~/repos/eee-code$ cucumber -s \
features/mini_calendar.feature:27
Sinatra::Test is deprecated; use Rack::Test instead.
Feature: Mini-calendar

As a curious web user
I want to see a calendar indicating the most recent meals and recipes
So that I can have a sense of how active the site is

Scenario: Navigating boundary conditions
Given a "Test" meal enjoyed on 2008-01-23
And a "Test" meal enjoyed on 2007-12-15
When I visit the mini-calendar
Then I should see the calendar for January 2008
And there should be 1 links to meals
When I click on the link to the previous month
Then I should see the calendar for December 2007
And there should be 1 links to meals

1 scenario (1 passed)
8 steps (8 passed)
0m0.621s
Smoke testing also verifies that the fix has worked:


(commit)

A quick deploy with Vlad:
cstrom@jaynestown:~/repos/eee-code$ rake vlad:stop_app 
cstrom@jaynestown:~/repos/eee-code$ rake vlad:update vlad:migrate vlad:start_app
And the new mini-calendar feature is now on the beta site:



I am a little chagrined that I missed the boundary condition in the first place. Still, it is good to have another feature complete. I will start on one of the two remaining features tomorrow.

1 comment: