// Test suite for the CGI query parser // // Copyright Bruno Lalande 2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include "cgi_query_parser.hpp" using namespace std; using namespace boost::program_options; struct get_query { public: get_query(const string& query) { setenv("REQUEST_METHOD", "GET", 1); setenv("QUERY_STRING", query.c_str(), 1); } }; struct post_query { public: post_query(const string& query): _old_buffer(cin.rdbuf()), _query_stream(query) { setenv("REQUEST_METHOD", "POST", 1); setenv("CONTENT_LENGTH", boost::lexical_cast(query.size()).c_str(), 1); cin.rdbuf(_query_stream.rdbuf()); } ~post_query() { cin.rdbuf(_old_buffer); } private: streambuf* _old_buffer; istringstream _query_stream; }; void test_no_method(const options_description& desc) { unsetenv("REQUEST_METHOD"); BOOST_CHECK_THROW(cgi_query_parser().options(desc).run(), detail::env_var_error); } void test_invalid_method(const options_description& desc) { setenv("REQUEST_METHOD", "INVALID", 1); BOOST_CHECK_THROW(cgi_query_parser().options(desc).run(), detail::request_method_error); } void test_get_no_query_string(const options_description& desc) { setenv("REQUEST_METHOD", "GET", 1); unsetenv("QUERY_STRING"); BOOST_CHECK_THROW(cgi_query_parser().options(desc).run(), detail::env_var_error); } void test_post_no_content_length(const options_description& desc) { post_query query_maker(""); unsetenv("CONTENT_LENGTH"); BOOST_CHECK(cgi_query_parser().options(desc).run().options.size() == 0); } template void test_no_option(const options_description& desc) { QueryType query(""); BOOST_CHECK(cgi_query_parser().options(desc).run().options.size() == 0); } template void test_one_option_without_value(const options_description& desc) { QueryType query("option"); parsed_options parsed(cgi_query_parser().options(desc).run()); BOOST_CHECK(parsed.options.size() == 1 && parsed.options[0].string_key == "option" && parsed.options[0].value.size() == 1 && parsed.options[0].value[0] == "" && parsed.options[0].unregistered == false); } template void test_one_option_with_value(const options_description& desc) { QueryType query("option=xxx"); parsed_options parsed(cgi_query_parser().options(desc).run()); BOOST_CHECK(parsed.options.size() == 1 && parsed.options[0].string_key == "option" && parsed.options[0].value.size() == 1 && parsed.options[0].value[0] == "xxx" && parsed.options[0].unregistered == false); } template void test_several_options(const options_description& desc) { QueryType query("option&bar=a_bar&foo=a_foo"); parsed_options parsed(cgi_query_parser().options(desc).run()); BOOST_CHECK(parsed.options.size() == 3 && parsed.options[0].string_key == "option" && parsed.options[0].value.size() == 1 && parsed.options[0].value[0] == "" && parsed.options[0].unregistered == false && parsed.options[1].string_key == "bar" && parsed.options[1].value.size() == 1 && parsed.options[1].value[0] == "a_bar" && parsed.options[1].unregistered == false && parsed.options[2].string_key == "foo" && parsed.options[2].value.size() == 1 && parsed.options[2].value[0] == "a_foo" && parsed.options[2].unregistered == false); } template void test_multiple_options(const options_description& desc) { QueryType query("foo=a_foo&bar=a_bar&foo=another_foo&foo=yet_another_foo&bar=another_bar"); parsed_options parsed(cgi_query_parser().options(desc).run()); BOOST_CHECK(parsed.options.size() == 2 && parsed.options[0].string_key == "foo" && parsed.options[0].value.size() == 3 && parsed.options[0].value[0] == "a_foo" && parsed.options[0].value[1] == "another_foo" && parsed.options[0].value[2] == "yet_another_foo" && parsed.options[0].unregistered == false && parsed.options[1].string_key == "bar" && parsed.options[1].value.size() == 2 && parsed.options[1].value[0] == "a_bar" && parsed.options[1].value[1] == "another_bar" && parsed.options[1].unregistered == false); } template void test_escape_sequences(const options_description& desc) { QueryType query("foo=this%3a+is+a+%22foo%22&bar=and+this+%3D%3e+is+a+bar%21%21&W%2bE%2BI%2bR%2BD=and+this+is+weird+%3A%2d%29"); parsed_options parsed(cgi_query_parser().options(desc).run()); BOOST_CHECK(parsed.options.size() == 3 && parsed.options[0].string_key == "foo" && parsed.options[0].value.size() == 1 && parsed.options[0].value[0] == "this: is a \"foo\"" && parsed.options[0].unregistered == false && parsed.options[1].string_key == "bar" && parsed.options[1].value.size() == 1 && parsed.options[1].value[0] == "and this => is a bar!!" && parsed.options[1].unregistered == false && parsed.options[2].string_key == "W+E+I+R+D" && parsed.options[2].value.size() == 1 && parsed.options[2].value[0] == "and this is weird :-)" && parsed.options[2].unregistered == false); } template void test_escape_sequences_preserved(const options_description& desc) { QueryType query("foo=this%3a+is+a+%22foo%22&bar=and+this+%3D%3e+is+a+bar%21%21"); parsed_options parsed(cgi_query_parser().options(desc).preserve_format().run()); BOOST_CHECK(parsed.options.size() == 2 && parsed.options[0].string_key == "foo" && parsed.options[0].value.size() == 1 && parsed.options[0].value[0] == "this%3a+is+a+%22foo%22" && parsed.options[0].unregistered == false && parsed.options[1].string_key == "bar" && parsed.options[1].value.size() == 1 && parsed.options[1].value[0] == "and+this+%3D%3e+is+a+bar%21%21" && parsed.options[1].unregistered == false); } template void test_unregistered_option(const options_description& desc) { QueryType query("foo=ok&invalid=ko&bar=ok"); BOOST_CHECK_THROW(cgi_query_parser().options(desc).run(), unknown_option); } template void test_unregistered_option_allowed(const options_description& desc) { QueryType query("foo=ok&invalid=ok&bar=ok"); parsed_options parsed(cgi_query_parser().options(desc).allow_unregistered().run()); BOOST_CHECK(parsed.options.size() == 3 && parsed.options[0].string_key == "foo" && parsed.options[0].value.size() == 1 && parsed.options[0].value[0] == "ok" && parsed.options[0].unregistered == false && parsed.options[1].string_key == "invalid" && parsed.options[1].value.size() == 1 && parsed.options[1].value[0] == "ok" && parsed.options[1].unregistered == true && parsed.options[2].string_key == "bar" && parsed.options[2].value.size() == 1 && parsed.options[2].value[0] == "ok" && parsed.options[2].unregistered == false); } template void test_integration(const options_description& desc) { QueryType query("option=1234&bar=a_bar&foo=the_foo&bar=another_bar&bar=yet_another_bar"); variables_map vm; store(cgi_query_parser().options(desc).run(), vm); notify(vm); vector expectedBars; expectedBars.push_back("a_bar"); expectedBars.push_back("another_bar"); expectedBars.push_back("yet_another_bar"); BOOST_CHECK(vm.count("option") == 1 && vm["option"].as() == 1234); BOOST_CHECK(vm.count("foo") == 1 && vm["foo"].as() == "the_foo"); BOOST_CHECK(vm.count("bar") == 1 && vm["bar"].as >() == expectedBars); } template void test_all(const options_description& desc) { test_no_option(desc); test_one_option_without_value(desc); test_one_option_with_value(desc); test_several_options(desc); test_multiple_options(desc); test_escape_sequences(desc); test_escape_sequences_preserved(desc); test_unregistered_option(desc); test_unregistered_option_allowed(desc); test_integration(desc); } int test_main(int, char* []) { options_description desc("Allowed options"); desc.add_options() ("option", value(), "") ("foo", value(), "") ("bar", value >(), "") ("W+E+I+R+D", "") ; test_no_method(desc); test_invalid_method(desc); test_get_no_query_string(desc); test_post_no_content_length(desc); test_all(desc); test_all(desc); return 0; }