Refactoring the CompileTests

The compile tests were pretty useless before: they would run indeed, but
there was no way of verifying the results of the run except visually in
the output. Now the status and optionally output of every case can be
verified in a concise way.
Add an optional global time limit

Some problems have a large number of test cases to correctly test all
edge cases. So far our support for that has been purposefully subpar
since we want to encourage problem writers to be more efficient with
runner time so we can have certain guarantees regarding how much time
people should wait before getting their results back. Nevertheless, some
test cases are not generated by the problemsetters and are instead added
verbatim from their original source, so it becomes hard to enforce this.

This change adds an optional per-run wall time limit. Any runs that
finish after this limit will get TLE as their status with a time of 0.