Monday, August 15, 2011

Testing After the Fact (git-scribe)

‹prev | My Chain | next›

Up today, hope to finish off my git-scribe tweaks. First up is fixing the remaining test failures.

Fortunately, most of the failures are along the lines of:
1) Failure:
test_scribe_can_generate_a_epub(#<Class:0x00000002ae4e88>) [test/gen_test.rb:60]:
<true> expected but was
<"book.epub">
The expectation and actual are inverted (but that is to be expected when using Test::Unit). That aside, I switched the output of the generator methods to return true on success rather than the file name. I feel that this is OK since other assertions in the test check the actual file system output. So, changing the expectation to true on success resolves the test failure:
test "scribe can generate a epub" do
in_temp_dir do
@scribe.init('t')
Dir.chdir('t') do
ret = @scribe.gen('epub')
assert_equal true, ret
out = Dir.glob('output/**/*')
assert out.include? 'output/book.epub'
end
end
end
With that, I am left with just a single failure. For some reason the test for the mobi generator is failing.

To run just the mobi test, I eventually figure out that I have to pass in a regular expression on the command line:
➜  git-scribe git:(mobi-from-epub) ✗ ruby test/gen_test.rb -n /mobi/
Loaded suite test/gen_test
Started
F
Finished in 3.435042 seconds.

1) Failure:
test_scribe_can_generate_a_mobi(#<Class:0x000000020b89a0>) [test/gen_test.rb:72]:
<true> expected but was
<false>.

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

Test run options: --seed 32642 --name "/mobi/"
Hrm... The only way to return false from the do_mobi generator is for the kindlegen to fail:
def do_mobi
return true if @done['mobi']

do_epub

info "GENERATING MOBI"

decorate_epub_for_mobi

cmd = "kindlegen -verbose book_for_mobi.epub -o book.mobi"
return false unless ex(cmd)

@done['mobi'] = true
end
To access the results of the command from within a git-scribe test, I have to dump the contents of @info to STDERR:
#...
ret = ex(cmd)

$stderr.puts @info.pretty_inspect

return false unless ret
#...
The result is that, indeed, the kindlegen command did fail:
**************************************************
* Amazon.com kindlegen(Linux)   V1.2 build 33307 *
* A command line e-book compiler                 *
* Copyright Amazon.com 2011                      *
**************************************************

option: -verbose: Verbose output
Info(prcgen): Unpacking ePub file
Info(prcgen): Added metadata dc:Title        "Book Title"
Info(prcgen): Added metadata dc:Creator      "Your Name"
Info(prcgen): Parsing files  0000006
Info(prcgen): Parsing file     URL: toc.html
Info(prcgen): Parsing file     URL: index.html
Info(prcgen): Parsing file     URL: ch01.html
Info(prcgen): Parsing file     URL: ch02.html
Warning(prcgen): media file not found  /tmp/mobi-RPoVE5/OEBPS/image/octocat_professor.png
Info(prcgen): Parsing file     URL: ch03.html
Info(prcgen): Parsing file     URL: cover.html
Warning(prcgen): media file not found  /tmp/mobi-RPoVE5/OEBPS/image/octocat_professor.png
...
Info(prcgen): The document identifier is: "Book_Title"
Info(prcgen): The file format version is V6
Info(prcgen): Saving MOBI file
Info(prcgen): MOBI File generated with WARNINGS!
Ah, dang. The image references in ch01.html point at the wrong location now that I renamed the image directory to the plural images:
image::image/octocat_professor.png[description]
After switching that, I have all of my tests passing.

For good measure, I add some tests of my own. One of the features that I added to git-scribe was the inclusion of cover images in the epub. The cover image itself was always in place, but the OPF (Open Packaging Format) file had not referenced it previously. So, to test, I generate an epub, unzip it, and verify that the OPF contains a reference to the cover image:
test "scribe generates an epub with a cover" do
in_temp_dir do
@scribe.init('t')
Dir.chdir('t') do
ret = @scribe.gen('epub')
assert_equal true, ret
        `unzip output/book.epub 2>&1 > /dev/null`
opf = File.read('OEBPS/content.opf')
assert opf.include? 'id="cover-image" href="images/cover.jpg"'
end
end
end
That passes and I do the same for the mobi output. Lastly, I add a test for the generation of the ebook zip file, which should be named for the book title (book_title in the test) and should contain PDF, EPUB, and MOBI in the zip file:
test "scribe can generate an ebook ZIP" do
in_temp_dir do
@scribe.init('t')
Dir.chdir('t') do
ret = @scribe.gen('ebook')
assert_equal true, ret
out = Dir.glob('output/**/*')
        assert out.include? 'output/book_title/book_title.mobi'
assert out.include? 'output/book_title/book_title.epub'
assert out.include? 'output/book_title/book_title.pdf'
assert out.include? 'output/book_title.zip'
end
end
end
With all of these new tests, I already know that they work. The testing has been whether or not Calibre or the Kindle is able to read them. I am certainly not driving toward a known destination via TDD, but rather drawing the map after the fact. I am also not going into extreme detail—just marking the important things along the way. If ever I (or anyone else) needs to make a change, hopefully there is enough there to ensure that the important stuff remains inviolate.

Good. I think I am all done with git-scribe. I have my tests. I have my nicely formatted epub. I have mobi based on said epub. I even have...

Aw nuts. I just remembered. I hacked up the PDF generation code something fierce back when I was still actively writing SPDY Book, but I never went back to ensure that the solution was at all robust or reusable. Dang it. Well, I know what I'm doing tomorrow.

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. ret = @scribe.gen('epub')
    assert_equal true, ret
    ---
    assert @scribe.gen('epub'), "unable to generate"

    ReplyDelete
  3. Yah, I see what you're going for there. I'm not sure exactly how best to do something like this.

    The return value of the gen method is of very little consequence to this test. It is the canary in this coal mine of a test.

    What I am really interested in is the by-product of call to gen. I am really testing that the .epub file is created or that the .epub contains a .ncx file.

    In that case, I don't want to bury the method generating the by-product inside an assert. Admittedly, burying it inside an assignment isn't much better.

    I should probably split it out into separate tests. One to verify that it completes successfully. The other to verify that it contains the right stuff (with a check of the return value).

    ReplyDelete