Math Parser, Part 4: Tests

Writing test code is a worthwhile practice and building a parser is a good example to prove this claim. We have seen previously that the Parser class consists of many methods and each method is a part of a chain in top-down analysis. It won’t be a good idea to start writing the parser from scratch, add all methods we think necessary and then run the code for the first time. Instead of tempting fate, we should write tests for every line of code we create.

The parser code was showed in the previous part at once. The fact is that I wrote it step by step, adding a new functionality and test code every time. I run the test often and fix any errors as soon as they appeared, before proceeding to the next functionality. Perhaps illustrating this process would be very instructive for those not familiar with test driven development, but I meant to focus on the parser itself. Anyway, here is the test code I wrote:

Test code is written in the format accepted by the RSpec framework (any other test framework could be used as well). Each test covers the other part of functionality: those parts that come directly from the parser specification (like “it should compute 6 when given 2 * 3”) and those part that might go wrong, like “it should calculate long additive expressions from left to right”. Test code has to be stored in a file, e.g. parser_spec.rb. To run the spec, type this at the command line:

spec parser_spec.rb --format specdoc

The “–format specdoc” can be shortened to:

spec parser_spec.rb -f s

Anyway, spec output should be similar to this:

Parser
- should compute 5 when given 2 + 3
- should compute 6 when given 2 * 3
- should compute 89 when given 89
- should raise an error when input is empty
- should omit white spaces
- should treat dot separated floating point numbers as a valid input
- should handle tight expressions
- should calculate long additive expressions from left to right
- should calculate long multiplicative expressions from left to right
- should calculate long, mixed additive and multiplicative expressions from left to right
- should return float pointing numbers when division result is not an integer
- should raise an error on wrong token
- should raise an error on syntax error
- should return Infinity when attempt to divide by zero occurs
- should compute 2 when given (2)
- should compute complex expressions enclosed in parenthesis
- should compute expressions with many subexpressions enclosed in parenthesis
- should handle nested parenthesis
- should raise an error on unbalanced parenthesis
Finished in 0.018552 seconds
19 examples, 0 failures

We end up with a properly working and quite functional parser. It can be further developed or create a base for a completely different program, like some simple XML or YAML parser.