@@ -236,6 +236,7 @@ set(CPPCMS_SOURCES | |||
src/applications_pool.cpp | |||
src/application.cpp | |||
src/url_dispatcher.cpp | |||
src/url_mapper.cpp | |||
src/http_cookie.cpp | |||
src/http_file.cpp | |||
src/http_content_type.cpp | |||
@@ -467,6 +468,7 @@ set(ALL_TESTS | |||
serialization_test | |||
status_test | |||
xss_test | |||
url_mapper_test | |||
) | |||
foreach(TEST ${ALL_TESTS}) | |||
add_executable(${TEST} tests/${TEST}.cpp) | |||
@@ -544,6 +546,7 @@ add_test(content_type_parser_test content_type_parser_test) | |||
add_test(cache_backend_test cache_backend_test) | |||
add_test(serialization_test serialization_test) | |||
add_test(xss_test xss_test) | |||
add_test(url_mapper_test url_mapper_test) | |||
add_test(status_test | |||
status_test "-c" "${CNF}/status_test.js" | |||
@@ -80,7 +80,7 @@ class html_type: | |||
class view_block: | |||
pattern=r'^<%\s*view\s+(\w+)\s+uses\s+(:?:?\w+(::\w+)?)(\s+extends\s+(:?:?\w+(::\w+)?))?\s*%>$' | |||
pattern=r'^<%\s*view\s+(\w+)\s+uses\s+(:?:?\w+(::\w+)*)(\s+extends\s+(:?:?\w+(::\w+)?))?\s*%>$' | |||
type='view' | |||
topmost = 0 | |||
def declare(self): | |||
@@ -539,6 +539,18 @@ class gettext_block: | |||
else: | |||
output( "out()<<cppcms::locale::format(cppcms::locale::translate(%s)) %% (%s);" % (s , ') % ('.join(params))) | |||
class url_block: | |||
pattern=r'^<%\s*url\s*('+str_match+')\s*(using(.*))?\s*%>$' | |||
def use(self,m): | |||
s=m.group(1) | |||
params=[] | |||
if m.group(3): | |||
params=make_format_params(m.group(4)) | |||
if not params: | |||
output( "out()<<content.url(%s);" % s) | |||
else: | |||
output( "out()<<content.url(%s, %s);" % (s , ', '.join(params))) | |||
class include_block: | |||
pattern=r'^<%\s*include\s+([a-zA_Z]\w*(::\w+)?)\s*\(\s*(.*)\)\s*%>$'; | |||
@@ -648,6 +660,7 @@ def main(): | |||
skin_block(), view_block(), if_block(), template_block(), end_block(), else_block(), \ | |||
cpp_include_block(), \ | |||
gettext_block(),ngettext_block(), \ | |||
url_block(), \ | |||
foreach_block(), item_block(), empty_block(),separator_block(), \ | |||
include_block(), \ | |||
html_type(), form_block(), \ | |||
@@ -41,6 +41,7 @@ namespace cppcms { | |||
class service; | |||
class url_dispatcher; | |||
class url_mapper; | |||
class applications_pool; | |||
class application; | |||
class base_content; | |||
@@ -55,6 +56,9 @@ namespace cppcms { | |||
namespace json { | |||
class value; | |||
} | |||
namespace filters { | |||
class streamable; | |||
} | |||
/// | |||
@@ -124,12 +128,23 @@ namespace cppcms { | |||
/// | |||
/// Get a dispatched class -- class that responsible on mapping between URLs and a member | |||
/// functions of application class. This member function is application specific and not | |||
/// functions of application class. | |||
/// | |||
/// This member function is application specific and not | |||
/// Connection specific. | |||
/// | |||
url_dispatcher &dispatcher(); | |||
/// | |||
/// Get a url_mapper class -- class that responsible on mapping between real objects and | |||
/// urls displayer on the page. | |||
/// | |||
/// This member function is application specific and not | |||
/// Connection specific. | |||
/// | |||
url_mapper &mapper(); | |||
/// | |||
/// Get a cache_interface instance. Same as context().cache(); | |||
/// | |||
cache_interface &cache(); | |||
@@ -170,6 +185,25 @@ namespace cppcms { | |||
/// | |||
void render(std::string skin,std::string template_name,std::ostream &out,base_content &content); | |||
/// | |||
/// Render a template \a template_name of default skin using this application as content. | |||
/// | |||
/// Side effect requires: output stream for response class, causes all updated session | |||
/// data be saved and all headers be written. You can't change headers after calling this function. | |||
/// | |||
void render(std::string template_name); | |||
/// | |||
/// Render a template \a template_name of \a skin skin using this application as content | |||
/// | |||
/// Side effect requires: output stream for response class, causes all updated session | |||
/// data be saved and all headers be written. You can't change headers after calling this function. | |||
/// | |||
void render(std::string skin,std::string template_name); | |||
/// | |||
/// Register an application \a app as child. Ownership of app is not transfered to parent, however | |||
/// it would shared it's parent reference count. | |||
@@ -274,7 +308,101 @@ namespace cppcms { | |||
/// | |||
virtual void clear(); | |||
/// | |||
/// Translate a message in current locale for given \a message in \a context | |||
/// | |||
std::string translate(char const *context,char const *message); | |||
/// | |||
/// Translate a message in current locale for given \a message | |||
/// | |||
std::string translate(char const *message); | |||
/// | |||
/// Translate a message in current locale for given \a single and \a plural form for number \a n in \a context. | |||
/// | |||
std::string translate(char const *context,char const *single,char const *plural,int n); | |||
/// | |||
/// Translate a message in current locale for given \a single and \a plural form for number \a n | |||
/// | |||
std::string translate(char const *single,char const *plural,int n); | |||
/// | |||
/// Map url-key \a key to actual URL, with parameters | |||
/// | |||
/// Key format is (/|(../)+)?real_key, where real key is the value that is defined | |||
/// in the mapper. | |||
/// | |||
/// - If the ket does not start with "/" or "../" then current dispatcher is used | |||
/// - If it starts with / then the actual mapper being used is root()->mapper() | |||
/// - If it starts with ../ then the actual mapper being used is parent()->mapper() | |||
/// - If it starts with ../../ then the actual mapper being used is parent()->parent()->mapper() and so on | |||
/// | |||
std::string url(std::string const &key); | |||
/// | |||
/// Map url-key \a key to actual URL, with parameter p1 | |||
/// | |||
/// Key format is (/|(../)+)?real_key, where real key is the value that is defined | |||
/// in the mapper. | |||
/// | |||
/// - If the ket does not start with "/" or "../" then current dispatcher is used | |||
/// - If it starts with / then the actual mapper being used is root()->mapper() | |||
/// - If it starts with ../ then the actual mapper being used is parent()->mapper() | |||
/// - If it starts with ../../ then the actual mapper being used is parent()->parent()->mapper() and so on | |||
/// | |||
std::string url(std::string const &key, | |||
filters::streamable const &p1); | |||
/// | |||
/// Map url-key \a key to actual URL, with parameters p1, p2 | |||
/// | |||
/// Key format is (/|(../)+)?real_key, where real key is the value that is defined | |||
/// in the mapper. | |||
/// | |||
/// - If the ket does not start with "/" or "../" then current dispatcher is used | |||
/// - If it starts with / then the actual mapper being used is root()->mapper() | |||
/// - If it starts with ../ then the actual mapper being used is parent()->mapper() | |||
/// - If it starts with ../../ then the actual mapper being used is parent()->parent()->mapper() and so on | |||
/// | |||
std::string url(std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2); | |||
/// | |||
/// Map url-key \a key to actual URL, with parameters p1, p2, p3 | |||
/// | |||
/// Key format is (/|(../)+)?real_key, where real key is the value that is defined | |||
/// in the mapper. | |||
/// | |||
/// - If the ket does not start with "/" or "../" then current dispatcher is used | |||
/// - If it starts with / then the actual mapper being used is root()->mapper() | |||
/// - If it starts with ../ then the actual mapper being used is parent()->mapper() | |||
/// - If it starts with ../../ then the actual mapper being used is parent()->parent()->mapper() and so on | |||
/// | |||
std::string url(std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3); | |||
/// | |||
/// Map url-key \a key to actual URL, with parameters p1, p2, p3, p4 | |||
/// | |||
/// Key format is (/|(../)+)?real_key, where real key is the value that is defined | |||
/// in the mapper. | |||
/// | |||
/// - If the ket does not start with "/" or "../" then current dispatcher is used | |||
/// - If it starts with / then the actual mapper being used is root()->mapper() | |||
/// - If it starts with ../ then the actual mapper being used is parent()->mapper() | |||
/// - If it starts with ../../ then the actual mapper being used is parent()->parent()->mapper() and so on | |||
/// | |||
std::string url(std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4); | |||
private: | |||
url_mapper &get_mapper_for_key(std::string const &key,std::string &real_key); | |||
void recycle(); | |||
void parent(application *parent); | |||
@@ -0,0 +1,80 @@ | |||
/////////////////////////////////////////////////////////////////////////////// | |||
// | |||
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> | |||
// | |||
// This program is free software: you can redistribute it and/or modify | |||
// it under the terms of the GNU Lesser General Public License as published by | |||
// the Free Software Foundation, either version 3 of the License, or | |||
// (at your option) any later version. | |||
// | |||
// This program is distributed in the hope that it will be useful, | |||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
// GNU Lesser General Public License for more details. | |||
// | |||
// You should have received a copy of the GNU Lesser General Public License | |||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
// | |||
/////////////////////////////////////////////////////////////////////////////// | |||
#ifndef CPPCMS_URL_MAPPER_H | |||
#define CPPCMS_URL_MAPPER_H | |||
#include <cppcms/defs.h> | |||
#include <booster/noncopyable.h> | |||
#include <booster/hold_ptr.h> | |||
#include <cppcms/filters.h> | |||
#include <string> | |||
#include <vector> | |||
namespace cppcms { | |||
/// | |||
/// \brief class for mapping URLs - oposite of dispatch | |||
/// | |||
class CPPCMS_API url_mapper : public booster::noncopyable { | |||
public: | |||
url_mapper(); | |||
~url_mapper(); | |||
std::string root(); | |||
void root(std::string const &r); | |||
void assign(std::string const &key,std::string const &url); | |||
void set_value(std::string const &key,std::string const &value); | |||
void clear_value(std::string const &key); | |||
void map( std::ostream &out, | |||
std::string const &key); | |||
void map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1); | |||
void map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2); | |||
void map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3); | |||
void map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4); | |||
private: | |||
std::string real_map(std::string const &key,std::vector<std::string> const ¶ms); | |||
struct data; | |||
booster::hold_ptr<data> d; | |||
}; | |||
}; | |||
#endif |
@@ -16,3 +16,4 @@ | |||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
// | |||
/////////////////////////////////////////////////////////////////////////////// | |||
@@ -21,14 +21,19 @@ | |||
#include <cppcms/application.h> | |||
#include <cppcms/http_context.h> | |||
#include <cppcms/service.h> | |||
#include <cppcms/filters.h> | |||
#include <cppcms/cppcms_error.h> | |||
#include <cppcms/url_dispatcher.h> | |||
#include <cppcms/url_mapper.h> | |||
#include <cppcms/applications_pool.h> | |||
#include <cppcms/http_response.h> | |||
#include <cppcms/views_pool.h> | |||
#include <set> | |||
#include <vector> | |||
#include <sstream> | |||
#include <booster/locale/message.h> | |||
#include <cppcms/config.h> | |||
#ifdef CPPCMS_USE_EXTERNAL_BOOST | |||
@@ -50,6 +55,7 @@ struct application::_data { | |||
booster::shared_ptr<http::context> conn; | |||
int pool_id; | |||
url_dispatcher url; | |||
url_mapper url_map; | |||
std::vector<application *> managed_children; | |||
}; | |||
@@ -92,6 +98,11 @@ url_dispatcher &application::dispatcher() | |||
return d->url; | |||
} | |||
url_mapper &application::mapper() | |||
{ | |||
return d->url_map; | |||
} | |||
booster::shared_ptr<http::context> application::get_context() | |||
{ | |||
return root()->d->conn; | |||
@@ -196,6 +207,29 @@ void application::render(std::string skin,std::string template_name,base_content | |||
service().views_pool().render(skin,template_name,response().out(),content); | |||
} | |||
void application::render(std::string template_name) | |||
{ | |||
base_content *cnt = dynamic_cast<base_content *>(this); | |||
if(!cnt) { | |||
throw cppcms_error( "Can't use application::render(std::string) when the application " | |||
"is not derived from base_content"); | |||
} | |||
render(template_name,*cnt); | |||
} | |||
void application::render(std::string skin,std::string template_name) | |||
{ | |||
base_content *cnt = dynamic_cast<base_content *>(this); | |||
if(!cnt) { | |||
throw cppcms_error( "Can't use application::render(std::string,std::string) when the application " | |||
"is not derived from base_content"); | |||
} | |||
render(skin,template_name,*cnt); | |||
} | |||
void application::render(std::string template_name,std::ostream &out,base_content &content) | |||
{ | |||
service().views_pool().render(context().skin(),template_name,out,content); | |||
@@ -222,6 +256,103 @@ void application::recycle() | |||
assign_context(booster::shared_ptr<http::context>()); | |||
} | |||
std::string application::translate(char const *ctx,char const *message) | |||
{ | |||
return booster::locale::translate(ctx,message).str<char>(context().locale()); | |||
} | |||
std::string application::translate(char const *message) | |||
{ | |||
return booster::locale::translate(message).str<char>(context().locale()); | |||
} | |||
std::string application::translate(char const *ctx,char const *single,char const *plural,int n) | |||
{ | |||
return booster::locale::translate(ctx,single,plural,n).str<char>(context().locale()); | |||
} | |||
std::string application::translate(char const *single,char const *plural,int n) | |||
{ | |||
return booster::locale::translate(single,plural,n).str<char>(context().locale()); | |||
} | |||
url_mapper &application::get_mapper_for_key(std::string const &key,std::string &real_key) | |||
{ | |||
if(!key.empty() && key[0]=='/') { | |||
real_key = key.substr(1); | |||
return root()->mapper(); | |||
} | |||
unsigned index = 0; | |||
application *app = this; | |||
while(key.size() >= index+3 && memcmp(key.c_str()+index,"../",3)==0) { | |||
index+=3; | |||
app = app->parent(); | |||
} | |||
real_key = key.substr(index); | |||
return app->mapper(); | |||
} | |||
std::string application::url(std::string const &key) | |||
{ | |||
std::ostringstream ss; | |||
ss.imbue(context().locale()); | |||
std::string real_key; | |||
url_mapper &mp = get_mapper_for_key(key,real_key); | |||
mp.map(ss,real_key); | |||
return ss.str(); | |||
} | |||
std::string application::url( std::string const &key, | |||
filters::streamable const &p1) | |||
{ | |||
std::ostringstream ss; | |||
ss.imbue(context().locale()); | |||
std::string real_key; | |||
url_mapper &mp = get_mapper_for_key(key,real_key); | |||
mp.map(ss,real_key,p1); | |||
return ss.str(); | |||
} | |||
std::string application::url( std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2) | |||
{ | |||
std::ostringstream ss; | |||
ss.imbue(context().locale()); | |||
std::string real_key; | |||
url_mapper &mp = get_mapper_for_key(key,real_key); | |||
mp.map(ss,real_key,p1,p2); | |||
return ss.str(); | |||
} | |||
std::string application::url( std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3) | |||
{ | |||
std::ostringstream ss; | |||
ss.imbue(context().locale()); | |||
std::string real_key; | |||
url_mapper &mp = get_mapper_for_key(key,real_key); | |||
mp.map(ss,real_key,p1,p2,p3); | |||
return ss.str(); | |||
} | |||
std::string application::url( std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4) | |||
{ | |||
std::ostringstream ss; | |||
ss.imbue(context().locale()); | |||
std::string real_key; | |||
url_mapper &mp = get_mapper_for_key(key,real_key); | |||
mp.map(ss,real_key,p1,p2,p3,p4); | |||
return ss.str(); | |||
} | |||
} // cppcms | |||
@@ -0,0 +1,226 @@ | |||
/////////////////////////////////////////////////////////////////////////////// | |||
// | |||
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> | |||
// | |||
// This program is free software: you can redistribute it and/or modify | |||
// it under the terms of the GNU Lesser General Public License as published by | |||
// the Free Software Foundation, either version 3 of the License, or | |||
// (at your option) any later version. | |||
// | |||
// This program is distributed in the hope that it will be useful, | |||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
// GNU Lesser General Public License for more details. | |||
// | |||
// You should have received a copy of the GNU Lesser General Public License | |||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
// | |||
/////////////////////////////////////////////////////////////////////////////// | |||
#define CPPCMS_SOURCE | |||
#include <cppcms/url_mapper.h> | |||
#include <cppcms/cppcms_error.h> | |||
#include <map> | |||
#include <stdlib.h> | |||
namespace cppcms { | |||
struct url_mapper::data | |||
{ | |||
struct entry { | |||
std::vector<std::string> parts; | |||
std::vector<int> indexes; | |||
std::vector<std::string> keys; | |||
}; | |||
typedef std::map<size_t,entry> by_size_type; | |||
typedef std::map<std::string,by_size_type> by_key_type; | |||
typedef std::map<std::string,std::string> helpers_type; | |||
by_key_type by_key; | |||
helpers_type helpers; | |||
std::string root; | |||
bool map( std::string const key, | |||
std::vector<std::string> const ¶ms, | |||
std::string &output) const | |||
{ | |||
by_key_type::const_iterator kp = by_key.find(key); | |||
if(kp == by_key.end()) | |||
return false; | |||
by_size_type::const_iterator sp = kp->second.find(params.size()); | |||
if(sp == kp->second.end()) | |||
return false; | |||
output.clear(); | |||
output+=root; | |||
entry const &formatting = sp->second; | |||
for(size_t i=0;i<formatting.parts.size();i++) { | |||
output += formatting.parts[i]; | |||
if( i < formatting.indexes.size() ) { | |||
if(formatting.indexes[i]==0) { | |||
std::string const &hkey = formatting.keys[i]; | |||
std::map<std::string,std::string>::const_iterator p = helpers.find(hkey); | |||
if(p != helpers.end()) { | |||
output += p->second; | |||
} | |||
} | |||
else { | |||
output+=params.at(formatting.indexes[i] - 1); | |||
} | |||
} | |||
} | |||
return true; | |||
} | |||
}; | |||
void url_mapper::assign(std::string const &key,std::string const &url) | |||
{ | |||
data::entry e; | |||
std::string::const_iterator prev = url.begin(), p = url.begin(); | |||
int max_index = 0; | |||
while(p!=url.end()) { | |||
if(*p=='{') { | |||
e.parts.push_back(std::string(prev,p)); | |||
prev = p; | |||
while(p!=url.end()) { | |||
if(*p=='}') { | |||
std::string const hkey(prev+1,p); | |||
prev = p+1; | |||
if(hkey.size()==0) { | |||
throw cppcms_error("cppcms::url_mapper: empty index between {}"); | |||
} | |||
bool all_digits = true; | |||
for(unsigned i=0;all_digits && i<hkey.size();i++) { | |||
if(hkey[i] < '0' || '9' <hkey[i]) | |||
all_digits = false; | |||
} | |||
if(!all_digits) { | |||
e.indexes.push_back(0); | |||
e.keys.push_back(hkey); | |||
} | |||
else { | |||
int index = atoi(hkey.c_str()); | |||
if(index == 0) | |||
throw cppcms_error("cppcms::url_mapper: index 0 is invalid"); | |||
max_index = std::max(index,max_index); | |||
e.indexes.push_back(index); | |||
e.keys.resize(e.keys.size()+1); | |||
} | |||
break; | |||
} | |||
else | |||
p++; | |||
} | |||
if(p==url.end()) | |||
throw cppcms_error("cppcms::url_mapper: '{' in url without '}'"); | |||
p++; | |||
} | |||
else if(*p=='}') { | |||
throw cppcms_error("cppcms::url_mapper: '}' in url without '{'"); | |||
} | |||
else | |||
p++; | |||
} | |||
e.parts.push_back(std::string(prev,p)); | |||
d->by_key[key][max_index] = e; | |||
} | |||
void url_mapper::set_value(std::string const &key,std::string const &value) | |||
{ | |||
d->helpers[key]=value; | |||
} | |||
void url_mapper::clear_value(std::string const &key) | |||
{ | |||
d->helpers.erase(key); | |||
} | |||
url_mapper::url_mapper() : d(new url_mapper::data()) | |||
{ | |||
} | |||
url_mapper::~url_mapper() | |||
{ | |||
} | |||
std::string url_mapper::root() | |||
{ | |||
return d->root; | |||
} | |||
void url_mapper::root(std::string const &r) | |||
{ | |||
d->root = r; | |||
} | |||
std::string url_mapper::real_map(std::string const &key,std::vector<std::string> const ¶ms) | |||
{ | |||
std::string result; | |||
if(!d->map(key,params,result)) { | |||
throw cppcms_error("cppcms::url_mapper:invalid key `" + key + "' given"); | |||
} | |||
return result; | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key) | |||
{ | |||
std::vector<std::string> params; | |||
out << real_map(key,params); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1) | |||
{ | |||
std::vector<std::string> params(1); | |||
params[0] = p1.get(out); | |||
out << real_map(key,params); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2) | |||
{ | |||
std::vector<std::string> params(2); | |||
params[0] = p1.get(out); | |||
params[1] = p2.get(out); | |||
out << real_map(key,params); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3) | |||
{ | |||
std::vector<std::string> params(3); | |||
params[0] = p1.get(out); | |||
params[1] = p2.get(out); | |||
params[2] = p3.get(out); | |||
out << real_map(key,params); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4) | |||
{ | |||
std::vector<std::string> params(4); | |||
params[0] = p1.get(out); | |||
params[1] = p2.get(out); | |||
params[2] = p3.get(out); | |||
params[3] = p4.get(out); | |||
out << real_map(key,params); | |||
} | |||
} |
@@ -0,0 +1,126 @@ | |||
/////////////////////////////////////////////////////////////////////////////// | |||
// | |||
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> | |||
// | |||
// This program is free software: you can redistribute it and/or modify | |||
// it under the terms of the GNU Lesser General Public License as published by | |||
// the Free Software Foundation, either version 3 of the License, or | |||
// (at your option) any later version. | |||
// | |||
// This program is distributed in the hope that it will be useful, | |||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
// GNU Lesser General Public License for more details. | |||
// | |||
// You should have received a copy of the GNU Lesser General Public License | |||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
// | |||
/////////////////////////////////////////////////////////////////////////////// | |||
#include <cppcms/url_mapper.h> | |||
#include <cppcms/cppcms_error.h> | |||
#include <sstream> | |||
#include "test.h" | |||
std::string value(std::ostringstream &s) | |||
{ | |||
std::string res = s.str(); | |||
s.str(""); | |||
return res; | |||
} | |||
int main() | |||
{ | |||
try { | |||
cppcms::url_mapper m; | |||
m.assign("foo","/foo"); | |||
m.assign("foo","/foo/{1}"); | |||
m.assign("foo","/foo/{1}/{2}"); | |||
m.assign("foo","/foo/{1}/{2}/{3}"); | |||
m.assign("foo","/foo/{1}/{2}/{3}/{4}"); | |||
m.assign("bar","/bar/{lang}/{1}"); | |||
m.assign("bar","/bar/{2}/{1}"); | |||
m.assign("test1","{1}x"); | |||
m.assign("test2","x{1}"); | |||
m.set_value("lang","en"); | |||
m.root("test.com"); | |||
TEST(m.root()=="test.com"); | |||
std::ostringstream ss; | |||
m.map(ss,"foo"); | |||
TEST(value(ss) == "test.com/foo"); | |||
m.map(ss,"foo",1); | |||
TEST(value(ss) == "test.com/foo/1"); | |||
m.map(ss,"foo",1,2); | |||
TEST(value(ss) == "test.com/foo/1/2"); | |||
m.map(ss,"foo",1,2,3); | |||
TEST(value(ss) == "test.com/foo/1/2/3"); | |||
m.map(ss,"foo",1,2,3,4); | |||
TEST(value(ss) == "test.com/foo/1/2/3/4"); | |||
m.map(ss,"foo",1,"a","b",5); | |||
TEST(value(ss) == "test.com/foo/1/a/b/5"); | |||
m.map(ss,"bar",1); | |||
TEST(value(ss) == "test.com/bar/en/1"); | |||
m.map(ss,"bar",1,"ru"); | |||
TEST(value(ss) == "test.com/bar/ru/1"); | |||
m.root(""); | |||
m.map(ss,"test1",10); | |||
TEST(value(ss) == "10x"); | |||
m.map(ss,"test2",10); | |||
TEST(value(ss) == "x10"); | |||
try { | |||
m.assign("x","a{"); | |||
TEST(0); | |||
} | |||
catch(cppcms::cppcms_error const &e) {} | |||
catch(...) { TEST(0); } | |||
try { | |||
m.assign("x","a}"); | |||
TEST(0); | |||
} | |||
catch(cppcms::cppcms_error const &e) {} | |||
catch(...) { TEST(0); } | |||
try { | |||
m.assign("x","a{0}"); | |||
TEST(0); | |||
} | |||
catch(cppcms::cppcms_error const &e) {} | |||
catch(...) { TEST(0); } | |||
try { | |||
m.map(ss,"undefined"); | |||
TEST(0); | |||
} | |||
catch(cppcms::cppcms_error const &e) {} | |||
catch(...) { TEST(0); } | |||
try { | |||
m.map(ss,"undefined"); | |||
TEST(0); | |||
} | |||
catch(cppcms::cppcms_error const &e) {} | |||
catch(...) { TEST(0); } | |||
try { | |||
m.map(ss,"test1",1,2); | |||
TEST(0); | |||
} | |||
catch(cppcms::cppcms_error const &e) {} | |||
catch(...) { TEST(0); } | |||
} | |||
catch(std::exception const &e) { | |||
std::cerr << "Fail" << e.what() << std::endl; | |||
return 1; | |||
} | |||
std::cout << "ok" << std::endl; | |||
return 0; | |||
} | |||