pFUnit icon indicating copy to clipboard operation
pFUnit copied to clipboard

Vague error when wrong arguments passed to `@assertEqual`

Open kurtsansom opened this issue 4 years ago • 3 comments

Adding incorrect arguments to @assertEqual gives vague errors

Context: When converting a test to pFUnit, the previous system required specifying the size of the array to compare when comparing that two arrays are equal.

What failed with the vague error:

expected = [4.0_dp]
actual = SUT()
call assert_equals(expected, actual, size(expected))

what worked correctly

expected = [4.0_dp]
actual = SUT()
call assert_equals(expected, actual)

pFUnit handles arrays nicely hooray! But the error message provided is super vague (to me)

e.g. error message for the failing code

   33 |   ! @test
      |        1
Error: There is no specific subroutine for the generic ‘assertequal’ at (1)
/media/store/krs/itar_build/heat/heat_main/heat/tests/unit_tests/core/utility/tblp/test_vector_linear_interp.pf:72:8:

Fatal Error: Cannot open module file ‘test_vector_linear_interp.mod’ for reading at (1): No such file or directory
compilation terminated.

I think this is regular fortran speak for I couldn't find a subroutine with the matching signature, but it took me a long time to figure out this silly mistake.

Can or does pFUnit generate warnings for errors like this, specifically a warning during the parsing of the .pf file that can generate a better warning? I think the part I was choking on was connecting @assertEqual to assertequal. Do you have any other suggestions on how that might be made more clear?

could the pre-processing catch this kind of error and fail to generate the .F90 file?

kurtsansom avatar Dec 09 '20 22:12 kurtsansom

The details of just what was wrong with the @assert you attempted would probably help a little bit. But in general the preprocessor is written in a way that is semi-intentionally "dumb". This allows the framework to continue overloading with extensions without needing to go back and make corresponding modifications to the Python preprocessor. There are also limits to what the Python preprocessor can even do without parsing Fortran. There are some checks for the number of arguments, but even those are weak constraints due to the variety of overloads that are permitted.

tclune avatar Dec 10 '20 13:12 tclune

Thank you @tclune. That is very helpful information. I updated my first comment with more clear description of the test comparing two arrays with 1 element.

Is there a debug option that generates more output or a way to generate a warning using those weak constraints?

also I am content with closing this issue due it fundamentally being an "error between chair and computer" but wanted to determine if the was a mechanism to generate a warning, or make it more clear to others when they encounter an error like this.

kurtsansom avatar Dec 10 '20 15:12 kurtsansom

There is no flag that would give a useful message for that type of error. There are many cases of AssertEqual that require 3 arguments, so nothing more can be done in that regard. And there is no way for the parser to know that size(expected) is of a type that is not accepted in the 3rd argument.

I do require optional arguments (e.g., message and location) to be passed using keywords, but that still is only detected by the compiler. Doing something similar with the annotations should be possible and would provide more informative error messages. To flag your example though, we would have to require a keyword even for tolerance (which is otherwise a common 3rd argument). That unfortunately breaks backward compatibility.

OK, so maybe add a switch to the preprocessor that would optionally enforce keywords for some (all?) arguments to the macros? You would then at least get a more informative message during the processing phase if you were willing to live with the more verbose form. Note that it would still not trap cases where the keywords are "right" but the argument is of the wrong type. E.g., if you had typed

@assertEqual(expected=5, found=7, tolerance=size(expected))

You would still get the same confusing message from the compiler as "tolerance" does not accept an integer argument. (I think.)

I am not at all opposed to accepting a contribution to extend the preprocessor in such a fashion. It ought to be relatively straightforward, though probably a bit tedious to capture all the cases that are currently treated generically in one fell swoop.

tclune avatar Dec 11 '20 13:12 tclune