Fix missing (uncalled) exception hooks (#166)

* Check hooks after expected errors, not just when there are none

Some unit tests had intentional errors, and code to verify that the
appropriate hooks were called, but we never checked.

* Update unit tests to match hooks, now that we are checking

* Fix bug revealed by checking the hooks

Or in other words, bug #161 (thanks abakhirkin for the fix)

* Fix link in documentation
This commit is contained in:
Jeff Trull
2022-06-22 14:22:27 -04:00
committed by GitHub
parent 71fb0d8390
commit 977b67a1d0
8 changed files with 52 additions and 22 deletions
+1 -1
View File
@@ -60,7 +60,7 @@
<span class="type">bool</span> <a href="class_reference_ctxpolicy.html#found_unknown_directive">found_unknown_directive</a>(<span class="type">ContextT</span> <span class="keyword">const</span>&amp; <span class="variable-name">ctx</span>,
<span class="type">ContainerT</span> <span class="keyword">const</span>&amp; <span class="variable-name">line</span>, <span class="type">ContainerT</span>&amp; <span class="variable-name">pending</span>);
</span>
<span class="keyword">template</span> &lt;<span class="keyword">typename</span> ContextT, <span class="keyword">typename</span> ExceptionT&gt;<br> void <a href="class_reference_ctxpolicy.html#trow_exception">throw_exception</a>(ContextT <span class="keyword">const</span> &amp;ctx, <br> ExceptionT <span class="keyword">const</span>&amp; e);<br><br> <span class="comment">// test, whether a given token may be skipped</span><br> <span class="keyword">template</span> &lt;<span class="keyword">typename</span> ContextT&gt;<br> <span class="keyword">bool</span> <a href="class_reference_ctxpolicy.html#may_skip_whitespace">may_skip_whitespace</a> (ContextT <span class="keyword">const</span>&amp; ctx,<br> TokenT &amp;token, <span class="keyword">bool</span> &amp;skipped_newline);<br>
<span class="keyword">template</span> &lt;<span class="keyword">typename</span> ContextT, <span class="keyword">typename</span> ExceptionT&gt;<br> void <a href="class_reference_ctxpolicy.html#throw_exception">throw_exception</a>(ContextT <span class="keyword">const</span> &amp;ctx, <br> ExceptionT <span class="keyword">const</span>&amp; e);<br><br> <span class="comment">// test, whether a given token may be skipped</span><br> <span class="keyword">template</span> &lt;<span class="keyword">typename</span> ContextT&gt;<br> <span class="keyword">bool</span> <a href="class_reference_ctxpolicy.html#may_skip_whitespace">may_skip_whitespace</a> (ContextT <span class="keyword">const</span>&amp; ctx,<br> TokenT &amp;token, <span class="keyword">bool</span> &amp;skipped_newline);<br>
<span class="comment">// Conditional compilation</span><span class="keyword">
template</span> &lt;<br> <span class="keyword">typename</span> ContextT, <span class="keyword">typename</span> TokenT, <br> <span class="keyword">typename</span> ContainerT<br> &gt;<br> <span class="keyword">bool</span> <a href="class_reference_ctxpolicy.html#evaluated_conditional_expression">evaluated_conditional_expression</a>(<br> ContextT <span class="keyword">const</span> &amp;ctx, TokenT <span class="keyword">const</span>&amp; directive, <br> ContainerT <span class="keyword">const</span>&amp; expression, <span class="keyword">bool</span> expression_value);<br>
+1 -1
View File
@@ -165,7 +165,7 @@ namespace boost { namespace wave { namespace util
// helper macro for throwing exceptions with additional parameter
#if !defined(BOOST_WAVE_THROW_NAME_CTX)
#define BOOST_WAVE_THROW_NAME_CTX(ctx, cls, code, msg, act_pos, name) \
boost::wave::util::throw_<cls>(cls::code, msg, act_pos, name) \
boost::wave::util::throw_<cls>(ctx, cls::code, msg, act_pos, name) \
/**/
#endif // BOOST_WAVE_THROW_NAME_CTX
+1 -1
View File
@@ -28,7 +28,7 @@
//H 01: t_2_004.cpp(13): FILE_NAME
//H 02: "a_nonexisting_file.cpp"
//H 03: "a_nonexisting_file.cpp"
//H 17: 5 "a_nonexisting_file.cpp" (5, "a_nonexisting_file.cpp")
//H 17: 5 "a_nonexisting_file.cpp" (5, "a_nonexisting_file.cpp")
//H 10: a_nonexisting_file.cpp(8): #error
//H 16: This error should occur at line 8 of "a_nonexisting_file.cpp"
//H 18: boost::wave::preprocess_exception
+1
View File
@@ -14,4 +14,5 @@
#this_is_a_unknown_pp_directive with some parameter
//H 21: t_2_005.cpp(14): #this_is_a_unknown_pp_directive with some parameter
//H
//H 18: boost::wave::preprocess_exception
+1 -1
View File
@@ -16,7 +16,7 @@
//H 10: t_2_008.cpp(14): #define
//H 08: t_2_008.cpp(14): INCLUDE_FILE="some_include_file.h"
//H 10: t_2_008.cpp(15): #include
//H 10: t_2_008.cpp(15): #include
//H 01: t_2_008.cpp(14): INCLUDE_FILE
//H 02: "some_include_file.h"
//H 03: "some_include_file.h"
+1
View File
@@ -18,4 +18,5 @@
#this_is_a_unknown_pp_directive with some parameter
//H 21: t_2_031.cpp(18): #this_is_a_unknown_pp_directive with some parameter
//H
//H 18: boost::wave::preprocess_exception
+44 -17
View File
@@ -209,7 +209,8 @@ testwave_app::got_expected_result(std::string const& filename,
}
std::string source = expected.substr(pos1+3, p-pos1-3);
std::string result, error, hooks;
bool pp_result = preprocess_file(filename, source,
bool pp_result;
std::tie(pp_result, std::ignore) = preprocess_file(filename, source,
result, error, hooks, "", true);
if (!pp_result) {
std::cerr
@@ -431,7 +432,7 @@ testwave_app::testwave_app(po::variables_map const& vm)
//
// Test the given file (i.e. preprocess the file and compare the result
// against the embedded 'R' comments, if an error occurs compare the error
// message against the given 'E' comments, if no error occurred, compare the
// message against the given 'E' comments. Then, compare the
// generated hooks result against the given 'H' comments).
//
///////////////////////////////////////////////////////////////////////////////
@@ -460,10 +461,12 @@ testwave_app::test_a_file(std::string filename)
bool retval = true; // assume success
bool printed_result = false;
std::string result, error, hooks;
bool pp_result = preprocess_file(filename, instr, result, error, hooks,
expected_cfg_macro);
bool pp_result;
bool suppressed; // true if there is an absent expected config macro
std::tie(pp_result, suppressed) =
preprocess_file(filename, instr, result, error, hooks, expected_cfg_macro);
if (pp_result || !result.empty()) {
// did we expect an error?
// did we expect an error?
std::string expected_error;
if (!extract_special_information(filename, instr, 'E', expected_error))
return false;
@@ -471,7 +474,7 @@ testwave_app::test_a_file(std::string filename)
if (!expected_error.empty() &&
!got_expected_result(filename, error, expected_error))
{
// we expected an error but got none (or a different one)
// we expected an error but got none (or a different one)
if (debuglevel > 2) {
std::cerr
<< filename << ": failed" << std::endl
@@ -491,6 +494,10 @@ testwave_app::test_a_file(std::string filename)
}
retval = false;
}
else if (suppressed)
{
// no need to check result or hooks as the test was not run
}
else if (!got_expected_result(filename, result, expected)) {
// no preprocessing error encountered
if (debuglevel > 2) {
@@ -569,6 +576,23 @@ testwave_app::test_a_file(std::string filename)
std::cerr << filename << ": failed" << std::endl;
}
retval = false;
} else {
// expected error; check the hooks also
if (test_hooks && !expected_hooks.empty() &&
!got_expected_result(filename, hooks, expected_hooks))
{
if (debuglevel > 2) {
std::cerr << filename << ": failed (though caught expected error)" << std::endl
<< "hooks result: " << std::endl << hooks
<< std::endl;
std::cerr << "expected hooks result: " << std::endl
<< expected_hooks << std::endl;
}
else if (debuglevel > 1) {
std::cerr << filename << ": failed" << std::endl;
}
retval = false;
}
}
if (retval) {
@@ -770,7 +794,8 @@ testwave_app::extract_special_information(std::string const& filename,
}
std::string source = value.substr(4, p-4);
std::string result, error, hooks;
bool pp_result = preprocess_file(filename, source,
bool pp_result;
std::tie(pp_result, std::ignore) = preprocess_file(filename, source,
result, error, hooks, "", true);
if (!pp_result) {
std::cerr
@@ -816,7 +841,9 @@ testwave_app::extract_special_information(std::string const& filename,
}
std::string source = value.substr(4, p-4);
std::string result, error, hooks;
bool pp_result = preprocess_file(filename, source,
bool pp_result;
bool suppressed;
std::tie(pp_result, suppressed) = preprocess_file(filename, source,
result, error, hooks, "", true);
if (!pp_result) {
std::cerr
@@ -1426,7 +1453,7 @@ testwave_app::add_predefined_macros(Context& ctx)
// the parameter 'result'.
//
///////////////////////////////////////////////////////////////////////////////
bool
std::tuple<bool, bool> // pass/fail + suppressed (or not) by absent macro
testwave_app::preprocess_file(std::string filename, std::string const& instr,
std::string& result, std::string& error, std::string& hooks,
std::string const& expected_cfg_macro, bool single_line)
@@ -1453,22 +1480,22 @@ testwave_app::preprocess_file(std::string filename, std::string const& instr,
// initialize the context from the options given on the command line
if (!initialise_options(ctx, global_vm, single_line))
return false;
return std::make_tuple(false, false);
// extract the options from the input data and initialize the context
boost::program_options::variables_map local_vm;
if (!extract_options(filename, instr, ctx, single_line, local_vm))
return false;
return std::make_tuple(false, false);
// add special predefined macros
if (!add_predefined_macros(ctx))
return false;
return std::make_tuple(false, false);
if (!expected_cfg_macro.empty() &&
!ctx.is_defined_macro(expected_cfg_macro))
{
// skip this test as it is for a disabled configuration
return false;
return std::make_tuple(true, true);
}
// preprocess the input, loop over all generated tokens collecting the
@@ -1504,7 +1531,7 @@ testwave_app::preprocess_file(std::string filename, std::string const& instr,
// special handling of the whole #line directive is required to
// allow correct file name matching
if (!handle_line_directive(it, end, result))
return false; // unexpected eof
return std::make_tuple(false, false); // unexpected eof
}
else {
// add the value of the current token
@@ -1522,7 +1549,7 @@ testwave_app::preprocess_file(std::string filename, std::string const& instr,
<< e.description() << std::endl;
error = BOOST_WAVETEST_GETSTRING(strm);
return false;
return std::make_tuple(false, false);
}
catch (boost::wave::cpp_exception const& e) {
// some preprocessing error
@@ -1533,7 +1560,7 @@ testwave_app::preprocess_file(std::string filename, std::string const& instr,
<< e.description() << std::endl;
error = BOOST_WAVETEST_GETSTRING(strm);
return false;
return std::make_tuple(false, false);
}
if (9 == debuglevel) {
@@ -1541,5 +1568,5 @@ testwave_app::preprocess_file(std::string filename, std::string const& instr,
<< filename << std::endl;
}
return true;
return std::make_tuple(true, false);
}
+2 -1
View File
@@ -86,7 +86,8 @@ protected:
// Preprocess the given input data and return the generated output through
// the parameter 'result'.
bool preprocess_file(std::string filename, std::string const& instr,
std::tuple<bool, bool> // pass/fail, suppressed by cfg macro (or not)
preprocess_file(std::string filename, std::string const& instr,
std::string& result, std::string& error, std::string& hooks,
std::string const& expected_cfg_macro, bool single_line = false);