But it’s still OK to have a unit test that member(x,foo)
fails – it could also have a comment saying that this behavior might change in the future (and when the behavior is changed, the test is also changed).
(Incidentally, d{a:1}:<foo
throws an error – and it’s fine to have a test for this also and maybe a comment about how it’s inconsistent with member/2)
That’s the problem – it’s often not obvious how things were intended. As the examples of member/2 and (:<)/2 show, there are multiple possible design choices when the type is not what’s expected (cue @ridgeworks)
Partly because the C layer does complicated things (memory allocation, gc, threading, etc etc) and then presents a much simpler view to the Prolog level. But if you’re doing moderately complex things in Prolog (e.g., writing a compiler or implementing a standard (e.g. protobufs), you’ll probably end up with plenty of test cases in Prolog as well. (Protobufs has ~2000 lines of implementation and ~2700 lines of tests, although the tests are less “dense” than the implementation)
That’s fine for development, but if code is deployed in production, specific handling of exceptions might be needed (non-existent files, permission errors, resource limitations, etc etc)
Anyway, my experience with the Google code base is that even when some module was well-documented, I often ended up with questions about details that weren’t in the documentation but that were covered in the unit cases. (I’ve also had to deal with other large code bases that had far fewer tests; and had to read the code to figure out how it handled certain things, or had to write my own tests to figure out the behavior.)