Having figured out that I probably have a bug, I need to write a test to prove it. So I scurried to the computer and opened up Microsoft Visual Studio. I looked around to find the test for the Shift+Enter, and I couldn t find it. That s odd...or is it? Last Wednesday, Chet and I got together and worked on a different story from this one. As part of that, I brought Chet up to speed on what had happened so far on this story. It had been a couple of days since I had worked on this story, and I had difficulty finding the test for inserting the Shift+Enter. The reason: there is no separate test for that. Instead I had enhanced the InsertPre to test the Shift+Enter also. It didn t take us long to figure out.
Now again today, only four days later, I couldn t figure out where the Shift+Enter test was. Now a case could be made that I should pay more attention. Or that I m becoming forgetful. What were we talking about? Oh, right, I couldn t find that test.
The real lesson is that tests are an important way of recording history and bringing ourselves up to speed on what s in the system. Tests are part of the communication that we try to build into the code. And the code isn t doing enough communicating here. Since I m here to work on the tests, I ll fix that problem as well. Here s the test for InsertPre, which also includes our only test so far for Shift+Enter:
[Test] public void InsertPre() {
model.SetLines (new String[1] {"<P></P>"});
model.SelectionStart = 7;
model.InsertPreTag();
AssertEquals("<pre></pre>", model.Lines[1]);
AssertEquals(14, model.SelectionStart);
model.InsertReturn();
AssertEquals(" < pre > ", model.Lines[1]);
AssertEquals(" < /pre > ", model.Lines[2]); AssertEquals(16, model.SelectionStart);
}
The Shift+Enter part, of course, is the InsertReturn and everything after it, which is just checking that the <pre> line gets split. Since that should be a separate test anyway, as I just mentioned, I ll split it out into a new test. Here s the InsertPre test and the new one:
[Test] public void InsertPre() {
model.SetLines (new String[1] {"<P></P>"});
model.SelectionStart = 7;
model.InsertPreTag();
AssertEquals("<pre></pre>", model.Lines[1]);
AssertEquals(14, model.SelectionStart);
}
[Test] public void ShiftEnter() {
model.SetLines (new String[1] {"<pre></pre>"});
model.SelectionStart = 5;
model.InsertReturn();
AssertEquals("<pre>", model.Lines[0]);
AssertEquals("</pre>", model.Lines[1]);
AssertEquals(7, model.SelectionStart);
}
Now for the test that will fail. Here s what I m thinking about. When we use the <pre> tag, we create several lines. The first one starts with the <pre>, the intermediate ones have code on them, and the last line has code and ends with </pre>. It looks like this:
<pre> code1
code2
code3</pre>
The defect I expect is this: if the cursor is on the first line or the second line, and I hit Enter (not Shift+Enter), what I want is new paragraph tags, after the <pre> tags. What I ll get, however, will be paragraph tags right in the middle of the code. Here s a test that I expect to fail:
[Test] public void ShiftEnterMultipleLines() {
model.SetLines (new String[] {"<pre>code1", "code2","code3</pre>"});
model.SelectionStart = 14; // after co in code2
model.InsertParagraphTag();
AssertEquals("code3</pre>", model.Lines[2]);
AssertEquals("<P></P>", model.Lines[3]);
}
I expect that the first assert will fail, finding the <P> tag there rather than in line 3 where it belongs. And sure enough, that s what happens. Houston, we have a problem.
Think about this a second. Our whole model so far is based on the premise that every tagged item, even a very long paragraph, is really just one line that begins with some tag and ends with the matching tag. Allowing the insertion of a return breaks that fundamental design assumption. We might be up against a big problem here. In fact, the problem is bigger than I realized. Remember that when we do the Alt+S operation to insert a section tag, we re actually inserting multiple lines:
<sect1><title></title>
</sect1>
Typing a title in there and a few paragraphs works just fine, with a result like this:
<sect1><title>Some Section</title>
<P>A paragraph about something.</P>
<P>Another paragraph goes here.</P>
</sect1>
However, if we do another Alt+S, the new section gets inserted right in the middle of the old one, resulting in this:
<sect1><title>Some Section</title>
<P>A paragraph about something.</P>
<P>Another paragraph goes here.</P>
<sect1><title></title>
</sect1>
</sect1>
Chet and I talked about this issue a long time ago. We decided then, as the customers, that we could live with having to cursor to the end of the </sect1> before inserting another section. And we expected that we d write a story to improve that when it started to bug us. But now, as programmers, we re starting to see a big hole in our design. We re concerned that the program doesn t know enough about XML and that bad things might happen because of that.
Now it may seem obvious to you that an XML editor should be based on some kind of data structure that understands XML. It might lead you to start using Microsoft .NET s XML-handling objects right away. And on another day, I might do the same. However, it s my practice in general to do the simplest thing that could possibly work, and working in plain text seems like that to me. I feel that I m pretty safe starting without XML parsing built in, but of course I could be wrong.
Is this the end of simple design plus refactoring as a design strategy? We ll find out.