# Notes (HPFP 14/31): Testing

# 14 Testing

## Intermission: Short Exercise

## 14.7 Chapter Exercises

### Validating numbers into words

### Using QuickCheck

### Failure

Irrational numbers like e.g. the sqaure root of 2 cannot be represented with infinite precision in a finite amount of memory. So an expression like (sqrt 2) is not actually equal to the square root of 2, but rather is an accurate approximation to some precision. So even though square is the inverse of square root, because sqrt cannot be infinitely accurate the square of a square root will have some error. E.g.

`sqrt 2 = 1.4142135, (sqrt 2) ^ 2 = 1.9999999`

### Idempotence

### Make a Gen random generator for the datatype

### Hangman testing

~~Skipping this one, I think that this testing chapter is probably better understood after you understand what monads are. The reader here only barely has the tools to build something for which testing is important.~~

So I went back and did this exercise and my initial instinct has been confirmed. I found it a pretty interesting exercise to build a `Gen Puzzle`

arbitrary puzzle generator, but actually applyting that generator to a reasonable property test for the hangman game is way too complicated for a beginner given the material covered so far. I figured it out, but it requires using the `monadicIO`

function from the `Test.QuickCheck.Monadic`

library, which is super interesting in how it works, but yeah, definitely something I only understood on my second pass through this book.

In any case, check out my new and improved hangman. I was able to refactor out a lot of complexity, using a little monadic goodness. I also simplified the `Puzzle`

type by making it only contain two strings, one for the word and one for guesses:

`data Puzzle = Puzzle { word :: String, guessed :: String } deriving Show`

This simplifies the code enormously, because instead of dragging around a stateful `filledIn :: [Maybe Char]`

, we can instead just compute:

```
discovered :: Puzzle -> [Maybe Char]
= (\x -> if elem x (guessed p) then Just x else Nothing) <$> word p discovered p
```

This is a little slower, sure, to recompute `discovered`

every time we want to check the characters that have already been solved rather than already having it in our `Puzzle`

type. But honestly, the scope of the game is so small that it doesn’t matter. And if for some reason we need `Puzzle`

to work efficiently with million-character words, there are better ways to cache that computation, and bigger inefficiencies, like the use of `String`

, that we would have to address first.

### Validating ciphers

This uses a little `newtype`

trick to make sure that the arbitrary strings we generate are all composed of lowercase characters. The reason being that the `vignere`

and `caesar`

functions have a built-in filter that ensures they only work on lowercase characters. Arguably not a great design decision on my part when I wrote `vignere`

and `caesar`

, but I wanted to test the functions I actually wrote in the previous chapters rather than rework them.

## 14.9 Follow-up resources

- Pedro Vasconcelos; An introduction to QuickCheck testing;
- Koen Claessen and John Hughes; (2000) QuickCheck: A Lightweight Tool for Random Testing of Haskell Programs
- Pedro Vasconcelos;Verifying a Simple Compiler Using Property-based Random Testing;