Comment by SAI_Peregrinus
3 hours ago
Or anything where the interaction of small pure functions matters. NAND is a simple pure function. 6 NANDs connected correctly gets you a D flip flop, and suddenly you've got state. Bugs can hide in the combinatorics of all the possible states of your system, and you'll never test them all in polynomial time.
People forget that most tests aren't written to verify if the code is correct or if the spec is being followed. They are mostly written that something isn't broken (mostly to serve as a canary when coding or deploying). There is just too much possible combinations. What you do is doing broad categories and selecting a few candidates to run the code through. But the most important is the theory of the software, having a good understanding of the problem's domain, the model of the solution, and the technical implementation of the solution.
An analogy I've been using is the formula of a curve like y-x^2=0 as the theory of the software. Test points could be (0, 0) (-3, 9), (5, 25). But there's a lot of curves that can pass through these points too. The point's utility is not to prove that you use the correct formula, it's mostly to check if someone has not accidentally change one of the components like the exponent or the minus sign. While the most important for the developer is knowing why we're using this formula.