diff --git a/test/data/profiles/bad_node.lua b/test/data/profiles/bad_node.lua new file mode 100644 index 000000000..74c730587 --- /dev/null +++ b/test/data/profiles/bad_node.lua @@ -0,0 +1,140 @@ +-- copy of testbot with process_node throwing a runtime error + +api_version = 4 + +function setup() + return { + properties = { + continue_straight_at_waypoint = true, + max_speed_for_map_matching = 30/3.6, --km -> m/s + weight_name = 'duration', + process_call_tagless_node = false, + u_turn_penalty = 20, + traffic_light_penalty = 7, -- seconds + use_turn_restrictions = true + }, + + classes = {"motorway", "toll", "TooWords2"}, + + excludable = { + {["motorway"] = true}, + {["toll"] = true}, + {["motorway"] = true, ["toll"] = true} + }, + + default_speed = 24, + speeds = { + primary = 36, + secondary = 18, + tertiary = 12, + steps = 6 + } + } +end + +function process_node (profile, node, result) + if (2 < nil) then + print("2 is less than nil") + end + + -- check if node is a traffic light + -- TODO: a way to set the penalty value +end + +function process_way (profile, way, result) + local highway = way:get_value_by_key("highway") + local toll = way:get_value_by_key("toll") + local name = way:get_value_by_key("name") + local oneway = way:get_value_by_key("oneway") + local route = way:get_value_by_key("route") + local duration = way:get_value_by_key("duration") + local maxspeed = tonumber(way:get_value_by_key ( "maxspeed")) + local maxspeed_forward = tonumber(way:get_value_by_key( "maxspeed:forward")) + local maxspeed_backward = tonumber(way:get_value_by_key( "maxspeed:backward")) + local junction = way:get_value_by_key("junction") + + if name then + result.name = name + end + + result.forward_mode = mode.driving + result.backward_mode = mode.driving + + if duration and durationIsValid(duration) then + result.duration = math.max( 1, parseDuration(duration) ) + result.forward_mode = mode.route + result.backward_mode = mode.route + else + local speed_forw = profile.speeds[highway] or profile.default_speed + local speed_back = speed_forw + + if highway == "river" then + local temp_speed = speed_forw + result.forward_mode = mode.river_down + result.backward_mode = mode.river_up + speed_forw = temp_speed*1.5 + speed_back = temp_speed/1.5 + elseif highway == "steps" then + result.forward_mode = mode.steps_down + result.backward_mode = mode.steps_up + end + + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + speed_forw = maxspeed_forward + else + if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then + speed_forw = maxspeed + end + end + + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + speed_back = maxspeed_backward + else + if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then + speed_back = maxspeed + end + end + + result.forward_speed = speed_forw + result.backward_speed = speed_back + end + + if oneway == "no" or oneway == "0" or oneway == "false" then + -- nothing to do + elseif oneway == "-1" then + result.forward_mode = mode.inaccessible + elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then + result.backward_mode = mode.inaccessible + end + + if highway == 'motorway' then + result.forward_classes["motorway"] = true + result.backward_classes["motorway"] = true + end + + if toll == "yes" then + result.forward_classes["toll"] = true + result.backward_classes["toll"] = true + end + + if junction == 'roundabout' then + result.roundabout = true + end +end + +function process_turn (profile, turn) + if turn.is_u_turn then + turn.duration = turn.duration + profile.properties.u_turn_penalty + turn.weight = turn.weight + profile.properties.u_turn_penalty + end + if turn.has_traffic_light then + turn.duration = turn.duration + profile.properties.traffic_light_penalty + end +end + +return { + setup = setup, + process_way = process_way, + process_node = process_node, + process_turn = process_turn +} diff --git a/test/data/profiles/bad_segment.lua b/test/data/profiles/bad_segment.lua new file mode 100644 index 000000000..cbb5bac19 --- /dev/null +++ b/test/data/profiles/bad_segment.lua @@ -0,0 +1,143 @@ +-- A copy of testbot with process_segment throwing a runtime error + +api_version = 4 + +function setup() + return { + properties = { + continue_straight_at_waypoint = true, + max_speed_for_map_matching = 30/3.6, --km -> m/s + weight_name = 'duration', + process_call_tagless_node = false, + u_turn_penalty = 20, + traffic_light_penalty = 7, -- seconds + use_turn_restrictions = true + }, + + classes = {"motorway", "toll", "TooWords2"}, + + excludable = { + {["motorway"] = true}, + {["toll"] = true}, + {["motorway"] = true, ["toll"] = true} + }, + + default_speed = 24, + speeds = { + primary = 36, + secondary = 18, + tertiary = 12, + steps = 6 + } + } +end + +function process_node (profile, node, result) + -- check if node is a traffic light + -- TODO: a way to set the penalty value +end + +function process_way (profile, way, result) + local highway = way:get_value_by_key("highway") + local toll = way:get_value_by_key("toll") + local name = way:get_value_by_key("name") + local oneway = way:get_value_by_key("oneway") + local route = way:get_value_by_key("route") + local duration = way:get_value_by_key("duration") + local maxspeed = tonumber(way:get_value_by_key ( "maxspeed")) + local maxspeed_forward = tonumber(way:get_value_by_key( "maxspeed:forward")) + local maxspeed_backward = tonumber(way:get_value_by_key( "maxspeed:backward")) + local junction = way:get_value_by_key("junction") + + if name then + result.name = name + end + + result.forward_mode = mode.driving + result.backward_mode = mode.driving + + if duration and durationIsValid(duration) then + result.duration = math.max( 1, parseDuration(duration) ) + result.forward_mode = mode.route + result.backward_mode = mode.route + else + local speed_forw = profile.speeds[highway] or profile.default_speed + local speed_back = speed_forw + + if highway == "river" then + local temp_speed = speed_forw + result.forward_mode = mode.river_down + result.backward_mode = mode.river_up + speed_forw = temp_speed*1.5 + speed_back = temp_speed/1.5 + elseif highway == "steps" then + result.forward_mode = mode.steps_down + result.backward_mode = mode.steps_up + end + + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + speed_forw = maxspeed_forward + else + if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then + speed_forw = maxspeed + end + end + + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + speed_back = maxspeed_backward + else + if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then + speed_back = maxspeed + end + end + + result.forward_speed = speed_forw + result.backward_speed = speed_back + end + + if oneway == "no" or oneway == "0" or oneway == "false" then + -- nothing to do + elseif oneway == "-1" then + result.forward_mode = mode.inaccessible + elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then + result.backward_mode = mode.inaccessible + end + + if highway == 'motorway' then + result.forward_classes["motorway"] = true + result.backward_classes["motorway"] = true + end + + if toll == "yes" then + result.forward_classes["toll"] = true + result.backward_classes["toll"] = true + end + + if junction == 'roundabout' then + result.roundabout = true + end +end + +function process_turn (profile, turn) + if turn.is_u_turn then + turn.duration = turn.duration + profile.properties.u_turn_penalty + turn.weight = turn.weight + profile.properties.u_turn_penalty + end + if turn.has_traffic_light then + turn.duration = turn.duration + profile.properties.traffic_light_penalty + end +end + +function process_segment (profile, segment) + if (2 < nil) then + print("2 is less than nil") + end +end + +return { + setup = setup, + process_way = process_way, + process_node = process_node, + process_turn = process_turn, + process_segment = process_segment +} diff --git a/test/data/profiles/bad_setup.lua b/test/data/profiles/bad_setup.lua new file mode 100644 index 000000000..72e32cc40 --- /dev/null +++ b/test/data/profiles/bad_setup.lua @@ -0,0 +1,140 @@ +-- Copy of testbot profile, with setup throwing a runtime error + +api_version = 4 + +function setup() + if (2 < nil) then -- arithmetic with nil should error + return {} + end + + return { + properties = { + continue_straight_at_waypoint = true, + max_speed_for_map_matching = 30/3.6, --km -> m/s + weight_name = 'duration', + process_call_tagless_node = false, + u_turn_penalty = 20, + traffic_light_penalty = 7, -- seconds + use_turn_restrictions = true + }, + + classes = {"motorway", "toll", "TooWords2"}, + + excludable = { + {["motorway"] = true}, + {["toll"] = true}, + {["motorway"] = true, ["toll"] = true} + }, + + default_speed = 24, + speeds = { + primary = 36, + secondary = 18, + tertiary = 12, + steps = 6 + } + } +end + +function process_node (profile, node, result) + -- check if node is a traffic light + -- TODO: a way to set the penalty value +end + +function process_way (profile, way, result) + local highway = way:get_value_by_key("highway") + local toll = way:get_value_by_key("toll") + local name = way:get_value_by_key("name") + local oneway = way:get_value_by_key("oneway") + local route = way:get_value_by_key("route") + local duration = way:get_value_by_key("duration") + local maxspeed = tonumber(way:get_value_by_key ( "maxspeed")) + local maxspeed_forward = tonumber(way:get_value_by_key( "maxspeed:forward")) + local maxspeed_backward = tonumber(way:get_value_by_key( "maxspeed:backward")) + local junction = way:get_value_by_key("junction") + + if name then + result.name = name + end + + result.forward_mode = mode.driving + result.backward_mode = mode.driving + + if duration and durationIsValid(duration) then + result.duration = math.max( 1, parseDuration(duration) ) + result.forward_mode = mode.route + result.backward_mode = mode.route + else + local speed_forw = profile.speeds[highway] or profile.default_speed + local speed_back = speed_forw + + if highway == "river" then + local temp_speed = speed_forw + result.forward_mode = mode.river_down + result.backward_mode = mode.river_up + speed_forw = temp_speed*1.5 + speed_back = temp_speed/1.5 + elseif highway == "steps" then + result.forward_mode = mode.steps_down + result.backward_mode = mode.steps_up + end + + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + speed_forw = maxspeed_forward + else + if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then + speed_forw = maxspeed + end + end + + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + speed_back = maxspeed_backward + else + if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then + speed_back = maxspeed + end + end + + result.forward_speed = speed_forw + result.backward_speed = speed_back + end + + if oneway == "no" or oneway == "0" or oneway == "false" then + -- nothing to do + elseif oneway == "-1" then + result.forward_mode = mode.inaccessible + elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then + result.backward_mode = mode.inaccessible + end + + if highway == 'motorway' then + result.forward_classes["motorway"] = true + result.backward_classes["motorway"] = true + end + + if toll == "yes" then + result.forward_classes["toll"] = true + result.backward_classes["toll"] = true + end + + if junction == 'roundabout' then + result.roundabout = true + end +end + +function process_turn (profile, turn) + if turn.is_u_turn then + turn.duration = turn.duration + profile.properties.u_turn_penalty + turn.weight = turn.weight + profile.properties.u_turn_penalty + end + if turn.has_traffic_light then + turn.duration = turn.duration + profile.properties.traffic_light_penalty + end +end + +return { + setup = setup, + process_way = process_way, + process_node = process_node, + process_turn = process_turn +} diff --git a/test/data/profiles/bad_turn.lua b/test/data/profiles/bad_turn.lua new file mode 100644 index 000000000..0fecb7d2d --- /dev/null +++ b/test/data/profiles/bad_turn.lua @@ -0,0 +1,140 @@ +-- a copy of testbot with process_turn throwing an error + +api_version = 4 + +function setup() + return { + properties = { + continue_straight_at_waypoint = true, + max_speed_for_map_matching = 30/3.6, --km -> m/s + weight_name = 'duration', + process_call_tagless_node = false, + u_turn_penalty = 20, + traffic_light_penalty = 7, -- seconds + use_turn_restrictions = true + }, + + classes = {"motorway", "toll", "TooWords2"}, + + excludable = { + {["motorway"] = true}, + {["toll"] = true}, + {["motorway"] = true, ["toll"] = true} + }, + + default_speed = 24, + speeds = { + primary = 36, + secondary = 18, + tertiary = 12, + steps = 6 + } + } +end + +function process_node (profile, node, result) + -- check if node is a traffic light + -- TODO: a way to set the penalty value +end + +function process_way (profile, way, result) + local highway = way:get_value_by_key("highway") + local toll = way:get_value_by_key("toll") + local name = way:get_value_by_key("name") + local oneway = way:get_value_by_key("oneway") + local route = way:get_value_by_key("route") + local duration = way:get_value_by_key("duration") + local maxspeed = tonumber(way:get_value_by_key ( "maxspeed")) + local maxspeed_forward = tonumber(way:get_value_by_key( "maxspeed:forward")) + local maxspeed_backward = tonumber(way:get_value_by_key( "maxspeed:backward")) + local junction = way:get_value_by_key("junction") + + if name then + result.name = name + end + + result.forward_mode = mode.driving + result.backward_mode = mode.driving + + if duration and durationIsValid(duration) then + result.duration = math.max( 1, parseDuration(duration) ) + result.forward_mode = mode.route + result.backward_mode = mode.route + else + local speed_forw = profile.speeds[highway] or profile.default_speed + local speed_back = speed_forw + + if highway == "river" then + local temp_speed = speed_forw + result.forward_mode = mode.river_down + result.backward_mode = mode.river_up + speed_forw = temp_speed*1.5 + speed_back = temp_speed/1.5 + elseif highway == "steps" then + result.forward_mode = mode.steps_down + result.backward_mode = mode.steps_up + end + + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + speed_forw = maxspeed_forward + else + if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then + speed_forw = maxspeed + end + end + + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + speed_back = maxspeed_backward + else + if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then + speed_back = maxspeed + end + end + + result.forward_speed = speed_forw + result.backward_speed = speed_back + end + + if oneway == "no" or oneway == "0" or oneway == "false" then + -- nothing to do + elseif oneway == "-1" then + result.forward_mode = mode.inaccessible + elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then + result.backward_mode = mode.inaccessible + end + + if highway == 'motorway' then + result.forward_classes["motorway"] = true + result.backward_classes["motorway"] = true + end + + if toll == "yes" then + result.forward_classes["toll"] = true + result.backward_classes["toll"] = true + end + + if junction == 'roundabout' then + result.roundabout = true + end +end + +function process_turn (profile, turn) + if (2 < nil) then + print("2 is less than nil") + end + + if turn.is_u_turn then + turn.duration = turn.duration + profile.properties.u_turn_penalty + turn.weight = turn.weight + profile.properties.u_turn_penalty + end + if turn.has_traffic_light then + turn.duration = turn.duration + profile.properties.traffic_light_penalty + end +end + +return { + setup = setup, + process_way = process_way, + process_node = process_node, + process_turn = process_turn +} diff --git a/test/data/profiles/bad_way.lua b/test/data/profiles/bad_way.lua new file mode 100644 index 000000000..cb0a3eb72 --- /dev/null +++ b/test/data/profiles/bad_way.lua @@ -0,0 +1,140 @@ +-- copy of testbot with process_way throwing a runtime error + +api_version = 4 + +function setup() + return { + properties = { + continue_straight_at_waypoint = true, + max_speed_for_map_matching = 30/3.6, --km -> m/s + weight_name = 'duration', + process_call_tagless_node = false, + u_turn_penalty = 20, + traffic_light_penalty = 7, -- seconds + use_turn_restrictions = true + }, + + classes = {"motorway", "toll", "TooWords2"}, + + excludable = { + {["motorway"] = true}, + {["toll"] = true}, + {["motorway"] = true, ["toll"] = true} + }, + + default_speed = 24, + speeds = { + primary = 36, + secondary = 18, + tertiary = 12, + steps = 6 + } + } +end + +function process_node (profile, node, result) + -- check if node is a traffic light + -- TODO: a way to set the penalty value +end + +function process_way (profile, way, result) + if (2 < nil) then + print("2 less than nil") + end + + local highway = way:get_value_by_key("highway") + local toll = way:get_value_by_key("toll") + local name = way:get_value_by_key("name") + local oneway = way:get_value_by_key("oneway") + local route = way:get_value_by_key("route") + local duration = way:get_value_by_key("duration") + local maxspeed = tonumber(way:get_value_by_key ( "maxspeed")) + local maxspeed_forward = tonumber(way:get_value_by_key( "maxspeed:forward")) + local maxspeed_backward = tonumber(way:get_value_by_key( "maxspeed:backward")) + local junction = way:get_value_by_key("junction") + + if name then + result.name = name + end + + result.forward_mode = mode.driving + result.backward_mode = mode.driving + + if duration and durationIsValid(duration) then + result.duration = math.max( 1, parseDuration(duration) ) + result.forward_mode = mode.route + result.backward_mode = mode.route + else + local speed_forw = profile.speeds[highway] or profile.default_speed + local speed_back = speed_forw + + if highway == "river" then + local temp_speed = speed_forw + result.forward_mode = mode.river_down + result.backward_mode = mode.river_up + speed_forw = temp_speed*1.5 + speed_back = temp_speed/1.5 + elseif highway == "steps" then + result.forward_mode = mode.steps_down + result.backward_mode = mode.steps_up + end + + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + speed_forw = maxspeed_forward + else + if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then + speed_forw = maxspeed + end + end + + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + speed_back = maxspeed_backward + else + if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then + speed_back = maxspeed + end + end + + result.forward_speed = speed_forw + result.backward_speed = speed_back + end + + if oneway == "no" or oneway == "0" or oneway == "false" then + -- nothing to do + elseif oneway == "-1" then + result.forward_mode = mode.inaccessible + elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then + result.backward_mode = mode.inaccessible + end + + if highway == 'motorway' then + result.forward_classes["motorway"] = true + result.backward_classes["motorway"] = true + end + + if toll == "yes" then + result.forward_classes["toll"] = true + result.backward_classes["toll"] = true + end + + if junction == 'roundabout' then + result.roundabout = true + end +end + +function process_turn (profile, turn) + if turn.is_u_turn then + turn.duration = turn.duration + profile.properties.u_turn_penalty + turn.weight = turn.weight + profile.properties.u_turn_penalty + end + if turn.has_traffic_light then + turn.duration = turn.duration + profile.properties.traffic_light_penalty + end +end + +return { + setup = setup, + process_way = process_way, + process_node = process_node, + process_turn = process_turn +} diff --git a/unit_tests/library/extract.cpp b/unit_tests/library/extract.cpp index aa18c7552..e3a02c072 100644 --- a/unit_tests/library/extract.cpp +++ b/unit_tests/library/extract.cpp @@ -2,8 +2,42 @@ #include "osrm/extractor.hpp" #include "osrm/extractor_config.hpp" +#include "osrm/exception.hpp" #include +#include + +bool file_contains_string(std::string filename, std::string test) { + std::ifstream inp(filename); + + if (inp.is_open()) { + std::string contents; + inp >> contents; + + return(boost::algorithm::contains(contents, test)); + } else { + return false; // just fail the boost assert (shouldn't happen) + } +} + +// utility class to redirect stderr so we can test it +// inspired by https://stackoverflow.com/questions/5405016 +class redirect_stderr { + // constructor: accept a pointer to a buffer where stderr will be redirected + public: redirect_stderr(std::streambuf * buf) + // store the original buffer for later (original buffer returned by rdbuf) + : old(std::cerr.rdbuf(buf)) + { } + + // destructor: restore the original cerr, regardless of how this class gets destroyed + ~redirect_stderr () + { + std::cerr.rdbuf(old); + } + + // place to store the buffer + private: std::streambuf * old; +}; BOOST_AUTO_TEST_SUITE(library_extract) @@ -26,4 +60,109 @@ BOOST_AUTO_TEST_CASE(test_extract_with_valid_config) BOOST_CHECK_NO_THROW(osrm::extract(config)); } +BOOST_AUTO_TEST_CASE(test_setup_runtime_error) +{ + osrm::ExtractorConfig config; + config.input_path = OSRM_TEST_DATA_DIR "/monaco.osm.pbf"; + config.UseDefaultOutputNames(OSRM_TEST_DATA_DIR "/monaco.osm.pbf"); + config.profile_path = OSRM_TEST_DATA_DIR "/profiles/bad_setup.lua"; + config.small_component_size = 1000; + config.requested_num_threads = std::thread::hardware_concurrency(); + + std::stringstream output; + + { + redirect_stderr redir (output.rdbuf()); + BOOST_CHECK_THROW(osrm::extract(config), osrm::util::exception); + } + + // We just look for the line number, file name, and error message. This avoids portability issues + // since the output contains the full path to the file, which may change between systems + BOOST_CHECK(boost::algorithm::contains(output.str(), "bad_setup.lua:6: attempt to compare number with nil")); +} + +BOOST_AUTO_TEST_CASE(test_way_runtime_error) +{ + osrm::ExtractorConfig config; + config.input_path = OSRM_TEST_DATA_DIR "/monaco.osm.pbf"; + config.UseDefaultOutputNames(OSRM_TEST_DATA_DIR "/monaco.osm.pbf"); + config.profile_path = OSRM_TEST_DATA_DIR "/profiles/bad_way.lua"; + config.small_component_size = 1000; + config.requested_num_threads = std::thread::hardware_concurrency(); + + std::stringstream output; + + { + redirect_stderr redir (output.rdbuf()); + BOOST_CHECK_THROW(osrm::extract(config), osrm::util::exception); + } + + // We just look for the line number, file name, and error message. This avoids portability issues + // since the output contains the full path to the file, which may change between systems + BOOST_CHECK(boost::algorithm::contains(output.str(), "bad_way.lua:41: attempt to compare number with nil")); +} + +BOOST_AUTO_TEST_CASE(test_node_runtime_error) +{ + osrm::ExtractorConfig config; + config.input_path = OSRM_TEST_DATA_DIR "/monaco.osm.pbf"; + config.UseDefaultOutputNames(OSRM_TEST_DATA_DIR "/monaco.osm.pbf"); + config.profile_path = OSRM_TEST_DATA_DIR "/profiles/bad_node.lua"; + config.small_component_size = 1000; + config.requested_num_threads = std::thread::hardware_concurrency(); + + std::stringstream output; + + { + redirect_stderr redir (output.rdbuf()); + BOOST_CHECK_THROW(osrm::extract(config), osrm::util::exception); + } + + // We just look for the line number, file name, and error message. This avoids portability issues + // since the output contains the full path to the file, which may change between systems + BOOST_CHECK(boost::algorithm::contains(output.str(), "bad_node.lua:36: attempt to compare number with nil")); +} + +BOOST_AUTO_TEST_CASE(test_segment_runtime_error) +{ + osrm::ExtractorConfig config; + config.input_path = OSRM_TEST_DATA_DIR "/monaco.osm.pbf"; + config.UseDefaultOutputNames(OSRM_TEST_DATA_DIR "/monaco.osm.pbf"); + config.profile_path = OSRM_TEST_DATA_DIR "/profiles/bad_segment.lua"; + config.small_component_size = 1000; + config.requested_num_threads = std::thread::hardware_concurrency(); + + std::stringstream output; + + { + redirect_stderr redir (output.rdbuf()); + BOOST_CHECK_THROW(osrm::extract(config), osrm::util::exception); + } + + // We just look for the line number, file name, and error message. This avoids portability issues + // since the output contains the full path to the file, which may change between systems + BOOST_CHECK(boost::algorithm::contains(output.str(), "bad_segment.lua:132: attempt to compare number with nil")); +} + +BOOST_AUTO_TEST_CASE(test_turn_runtime_error) +{ + osrm::ExtractorConfig config; + config.input_path = OSRM_TEST_DATA_DIR "/monaco.osm.pbf"; + config.UseDefaultOutputNames(OSRM_TEST_DATA_DIR "/monaco.osm.pbf"); + config.profile_path = OSRM_TEST_DATA_DIR "/profiles/bad_turn.lua"; + config.small_component_size = 1000; + config.requested_num_threads = std::thread::hardware_concurrency(); + + std::stringstream output; + + { + redirect_stderr redir (output.rdbuf()); + BOOST_CHECK_THROW(osrm::extract(config), osrm::util::exception); + } + + // We just look for the line number, file name, and error message. This avoids portability issues + // since the output contains the full path to the file, which may change between systems + BOOST_CHECK(boost::algorithm::contains(output.str(), "bad_turn.lua:122: attempt to compare number with nil")); +} + BOOST_AUTO_TEST_SUITE_END()