├── .gitignore ├── test ├── run_tests.sh ├── Makefile ├── path_to_regex_options.cpp ├── path_to_regex_parse.cpp └── path_to_regex_no_options.cpp ├── README.md ├── path_to_regex.hpp └── path_to_regex.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.o 3 | *.d 4 | *~ 5 | -------------------------------------------------------------------------------- /test/run_tests.sh: -------------------------------------------------------------------------------- 1 | # This file is a part of the IncludeOS unikernel - www.includeos.org 2 | # 3 | # Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences 4 | # and Alfred Bratterud 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | #!/bin/sh 19 | 20 | echo ">>> About to run the test suite for routes [path_to_regex]..."; 21 | echo ">>> Building..."; 22 | make; 23 | echo ">>> Running path_to_regex_parse test module..."; 24 | ./path_to_regex_parse; 25 | echo ">>> Running path_to_regex_options test module..."; 26 | ./path_to_regex_options; 27 | echo ">>> Running path_to_regex_no_options test module..."; 28 | ./path_to_regex_no_options; 29 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # This file is a part of the IncludeOS unikernel - www.includeos.org 2 | # 3 | # Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences 4 | # and Alfred Bratterud 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | CXX=$(shell command -v clang++ || command -v clang++-3.8 || command -v clang++-3.7 || command -v clang++-3.6) 19 | CXXFLAGS=-std=c++14 -Ofast 20 | SRC=../path_to_regex.cpp 21 | 22 | all: path_to_regex_parse path_to_regex_options path_to_regex_no_options 23 | 24 | path_to_regex_parse: path_to_regex_parse.cpp 25 | ${CXX} ${CXXFLAGS} -opath_to_regex_parse path_to_regex_parse.cpp ${SRC} 26 | 27 | path_to_regex_options: path_to_regex_options.cpp 28 | ${CXX} ${CXXFLAGS} -opath_to_regex_options path_to_regex_options.cpp ${SRC} 29 | 30 | path_to_regex_no_options: path_to_regex_no_options.cpp 31 | ${CXX} ${CXXFLAGS} -opath_to_regex_no_options path_to_regex_no_options.cpp ${SRC} 32 | 33 | clean: 34 | rm -f path_to_regex_parse 35 | rm -f path_to_regex_options 36 | rm -f path_to_regex_no_options 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # path_to_regex 2 | Turns a route path (string, string pattern or regular expression) into a regex and populates a vector with the route's parameters. [Mana](https://github.com/includeos/mana) uses this library to match incoming request paths with the routes specified by the developer. This is done by the [Router](https://github.com/includeos/mana/blob/master/include/mana/router.hpp), and the developer has access to the parameters through the request. Path_to_regex is a port of the most essential functionality in the JavaScript library [pillarjs/path-to-regexp](https://github.com/pillarjs/path-to-regexp). 3 | 4 | **Example service:** [Acorn Web Server Appliance](https://github.com/includeos/acorn). 5 | 6 | ## Usage 7 | Specifying a route in service.cpp: 8 | ```cpp 9 | Router router; 10 | 11 | // GET /users/5, /users/101 and so on 12 | router.on_get("/users/:id(\\d+)", [](auto req, auto res) { 13 | auto id = req->params().get("id"); 14 | 15 | // Do actions according to "id" 16 | if(id == "42") 17 | // ... 18 | }); 19 | 20 | server.set_routes(router); 21 | ``` 22 | Some route path examples: 23 | ```cpp 24 | // GET / 25 | router.on_get("/", [](auto req, auto res) { 26 | res->send(true); 27 | }); 28 | 29 | // GET /about 30 | router.on_get("/about", [](auto req, auto res) { 31 | res->send(true); 32 | }); 33 | 34 | // GET /acd and /abcd 35 | router.on_get("/ab?cd", [](auto req, auto res) { 36 | res->send(true); 37 | }); 38 | 39 | // GET /abcd, /abbcd, /abbbcd and so on 40 | router.on_get("/ab+cd", [](auto req, auto res) { 41 | res->send(true); 42 | }); 43 | 44 | // GET /abcd, /abxcd, /abRANDOMcd, /ab123cd and so on 45 | router.on_get("/ab*cd", [](auto req, auto res) { 46 | res->send(true); 47 | }); 48 | 49 | // GET /abe and /abcde 50 | router.on_get("/ab(cd)?e", [](auto req, auto res) { 51 | res->send(true); 52 | }); 53 | 54 | // GET /science-paper, /newspaper and so on, but not /newspapers or /paper f.ex. 55 | router.on_get("/.*paper$/", [](auto req, auto res) { 56 | res->send(true); 57 | }); 58 | 59 | // GET /users/jane/books/aeneid, /users/john/books/poetics and so on 60 | router.on_get("/users/:username([a-z]+)/books/:title([a-z]+)", [](auto req, auto res) { 61 | auto username = req->params().get("username"); 62 | auto title = req->params().get("title"); 63 | // First example: username == "jane", title == "aeneid" 64 | // Params' get-method throws ParamException if key doesn't exist 65 | 66 | // Do actions according to the values 67 | 68 | res->send(true); 69 | }); 70 | 71 | // GET /users/2/books/5, /users/15/books/312 and so on 72 | router.on_get("/users/:userId(\\d+)/books/:bookId(\\d+)", [](auto req, auto res) { 73 | auto userId = req->params().get("userId"); 74 | auto bookId = req->params().get("bookId"); 75 | // First example: userId == "2", bookId == "5" 76 | // Params' get-method throws ParamException if key doesn't exist 77 | 78 | // Do actions according to the values 79 | 80 | res->send(true); 81 | }); 82 | ``` 83 | 84 | ## Requirements 85 | * [IncludeOS](https://github.com/hioa-cs/IncludeOS) installed (together with its dependencies) 86 | * [Mana](https://github.com/includeos/mana) 87 | * git 88 | -------------------------------------------------------------------------------- /path_to_regex.hpp: -------------------------------------------------------------------------------- 1 | // This file is a part of the IncludeOS unikernel - www.includeos.org 2 | // 3 | // Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences 4 | // and Alfred Bratterud 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | // https://github.com/pillarjs/path-to-regexp/blob/master/index.js 19 | 20 | #ifndef PATH_TO_REGEX_HPP 21 | #define PATH_TO_REGEX_HPP 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace path2regex { 29 | 30 | struct Token { 31 | std::string name {}; // can be a string or an int (index) 32 | std::string prefix {}; 33 | std::string delimiter {}; 34 | std::string pattern {}; 35 | bool optional {false}; 36 | bool repeat {false}; 37 | bool partial {false}; 38 | bool asterisk {false}; 39 | bool is_string {false}; // If it is a string we only put/have a string in the name-attribute (path in parse-method) 40 | // So if this is true, we can ignore all attributes except name 41 | 42 | void set_string_token(const std::string& name_) { 43 | name = name_; 44 | is_string = true; 45 | } 46 | }; //< struct Token 47 | 48 | using Keys = std::vector; 49 | using Tokens = std::vector; 50 | using Options = std::map; 51 | 52 | /** 53 | * Creates a path-regex from string input (path) 54 | * Updates keys-vector (empty input parameter) 55 | * 56 | * Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method 57 | * Puts the tokens that are keys (not string-tokens) into keys-vector 58 | * 59 | * std::vector keys (empty) 60 | * Is created outside the class and sent in as parameter 61 | * One Token-object in the keys-vector per parameter found in the path 62 | * 63 | * std::map options (optional) 64 | * Can contain bool-values for the keys "sensitive", "strict" and/or "end" 65 | * Default: 66 | * strict = false 67 | * sensitive = false 68 | * end = true 69 | */ 70 | std::regex path_to_regex(const std::string& path, Keys& keys, const Options& options = Options{}); 71 | 72 | /** 73 | * Creates a path-regex from string input (path) 74 | * 75 | * Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method 76 | * 77 | * std::map options (optional) 78 | * Can contain bool-values for the keys "sensitive", "strict" and/or "end" 79 | * Default: 80 | * strict = false 81 | * sensitive = false 82 | * end = true 83 | */ 84 | std::regex path_to_regex(const std::string& path, const Options& options = Options{}); 85 | 86 | /** 87 | * Creates vector of tokens based on the given string (this vector of tokens can be sent as 88 | * input to tokens_to_regex-method and includes tokens that are strings, not only tokens 89 | * that are parameters in str) 90 | */ 91 | Tokens parse(const std::string& str); 92 | 93 | /** 94 | * Creates a regex based on the tokens and options (optional) given 95 | */ 96 | std::regex tokens_to_regex(const Tokens& tokens, const Options& options = Options{}); 97 | 98 | /** 99 | * Goes through the tokens-vector and push all tokens that are not string-tokens 100 | * onto keys-vector 101 | */ 102 | void tokens_to_keys(const Tokens& tokens, Keys& keys); 103 | 104 | } //< namespace path2regex 105 | 106 | #endif //< PATH_TO_REGEX_HPP 107 | -------------------------------------------------------------------------------- /path_to_regex.cpp: -------------------------------------------------------------------------------- 1 | // This file is a part of the IncludeOS unikernel - www.includeos.org 2 | // 3 | // Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences 4 | // and Alfred Bratterud 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | // https://github.com/pillarjs/path-to-regexp/blob/master/index.js 19 | 20 | #include "path_to_regex.hpp" 21 | 22 | namespace path2regex { 23 | 24 | const std::regex PATH_REGEXP = 25 | std::regex{"((\\\\.)|(([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))))"}; 26 | 27 | std::regex path_to_regex(const std::string& path, Keys& keys, const Options& options) { 28 | Tokens all_tokens = parse(path); 29 | tokens_to_keys(all_tokens, keys); // fill keys with relevant tokens 30 | return tokens_to_regex(all_tokens, options); 31 | } 32 | 33 | std::regex path_to_regex(const std::string& path, const Options& options) { 34 | return tokens_to_regex(parse(path), options); 35 | } 36 | 37 | // Parse a string for the raw tokens 38 | std::vector parse(const std::string& str) { 39 | if (str.empty()) 40 | return {}; 41 | 42 | Tokens tokens; 43 | int key = 0; 44 | int index = 0; 45 | std::string path = ""; 46 | std::smatch res; 47 | 48 | for (std::sregex_iterator i = std::sregex_iterator{str.begin(), str.end(), PATH_REGEXP}; 49 | i != std::sregex_iterator{}; ++i) { 50 | 51 | res = *i; 52 | 53 | std::string m = res[0]; // the parameter, f.ex. /:test 54 | std::string escaped = res[2]; 55 | int offset = res.position(); 56 | 57 | // JS: path += str.slice(index, offset); from and included index to and included offset-1 58 | path += str.substr(index, (offset - index)); // from index, number of chars: offset - index 59 | 60 | index = offset + m.size(); 61 | 62 | if (not escaped.empty()) { 63 | path += escaped[1]; // if escaped == \a, escaped[1] == a (if str is "/\\a" f.ex.) 64 | continue; 65 | } 66 | 67 | std::string next = ((size_t) index < str.size()) ? std::string{str.at(index)} : ""; 68 | 69 | std::string prefix = res[4]; // f.ex. / 70 | std::string name = res[5]; // f.ex. test 71 | std::string capture = res[6]; // f.ex. \d+ 72 | std::string group = res[7]; // f.ex. (users|admins) 73 | std::string modifier = res[8]; // f.ex. ? 74 | std::string asterisk = res[9]; // * if path is /* 75 | 76 | // Push the current path onto the tokens 77 | if (not path.empty()) { 78 | Token stringToken; 79 | stringToken.set_string_token(path); 80 | tokens.push_back(stringToken); 81 | path = ""; 82 | } 83 | 84 | bool partial = (not prefix.empty()) and (not next.empty()) and (next not_eq prefix); 85 | bool repeat = (modifier == "+") or (modifier == "*"); 86 | bool optional = (modifier == "?") or (modifier == "*"); 87 | std::string delimiter = (not prefix.empty()) ? prefix : "/"; 88 | std::string pattern; 89 | 90 | if (not capture.empty()) 91 | pattern = capture; 92 | else if (not group.empty()) 93 | pattern = group; 94 | else 95 | pattern = (not asterisk.empty()) ? ".*" : ("[^" + delimiter + "]+?"); 96 | 97 | Token t; 98 | t.name = (not name.empty()) ? name : std::to_string(key++); 99 | t.prefix = prefix; 100 | t.delimiter = delimiter; 101 | t.optional = optional; 102 | t.repeat = repeat; 103 | t.partial = partial; 104 | t.asterisk = (asterisk == "*"); 105 | t.pattern = pattern; 106 | t.is_string = false; 107 | tokens.push_back(t); 108 | } 109 | 110 | // Match any characters still remaining 111 | if ((size_t) index < str.size()) 112 | path += str.substr(index); 113 | 114 | // If the path exists, push it onto the end 115 | if (not path.empty()) { 116 | Token stringToken; 117 | stringToken.set_string_token(path); 118 | tokens.push_back(stringToken); 119 | } 120 | 121 | return tokens; 122 | } 123 | 124 | // Creates a regex based on the given tokens and options (optional) 125 | std::regex tokens_to_regex(const Tokens& tokens, const Options& options) { 126 | if (tokens.empty()) 127 | return std::regex{""}; 128 | 129 | // Set default values for options: 130 | bool strict = false; 131 | bool sensitive = false; 132 | bool end = true; 133 | 134 | if (not options.empty()) { 135 | auto it = options.find("strict"); 136 | strict = (it not_eq options.end()) ? options.find("strict")->second : false; 137 | 138 | it = options.find("sensitive"); 139 | sensitive = (it not_eq options.end()) ? options.find("sensitive")->second : false; 140 | 141 | it = options.find("end"); 142 | end = (it not_eq options.end()) ? options.find("end")->second : true; 143 | } 144 | 145 | std::string route = ""; 146 | Token lastToken = tokens[tokens.size() - 1]; 147 | std::regex re{"(.*\\/$)"}; 148 | bool endsWithSlash = lastToken.is_string and std::regex_match(lastToken.name, re); 149 | // endsWithSlash if the last char in lastToken's name is a slash 150 | 151 | // Iterate over the tokens and create our regexp string 152 | for (size_t i = 0; i < tokens.size(); i++) { 153 | Token token = tokens[i]; 154 | 155 | if (token.is_string) { 156 | route += token.name; 157 | } else { 158 | std::string prefix = token.prefix; 159 | std::string capture = "(?:" + token.pattern + ")"; 160 | 161 | if (token.repeat) 162 | capture += "(?:" + prefix + capture + ")*"; 163 | 164 | if (token.optional) { 165 | 166 | if (not token.partial) 167 | capture = "(?:" + prefix + "(" + capture + "))?"; 168 | else 169 | capture = prefix + "(" + capture + ")?"; 170 | 171 | } else { 172 | capture = prefix + "(" + capture + ")"; 173 | } 174 | 175 | route += capture; 176 | } 177 | } 178 | 179 | // In non-strict mode we allow a slash at the end of match. If the path to 180 | // match already ends with a slash, we remove it for consistency. The slash 181 | // is valid at the end of a path match, not in the middle. This is important 182 | // in non-ending mode, where "/test/" shouldn't match "/test//route". 183 | 184 | if (not strict) { 185 | if (endsWithSlash) 186 | route = route.substr(0, (route.size() - 1)); 187 | 188 | route += "(?:\\/(?=$))?"; 189 | } 190 | 191 | if (end) { 192 | route += "$"; 193 | } else { 194 | // In non-ending mode, we need the capturing groups to match as much as 195 | // possible by using a positive lookahead to the end or next path segment 196 | if (not (strict and endsWithSlash)) 197 | route += "(?=\\/|$)"; 198 | } 199 | 200 | if (sensitive) 201 | return std::regex{"^" + route}; 202 | 203 | return std::regex{"^" + route, std::regex_constants::ECMAScript | std::regex_constants::icase}; 204 | } 205 | 206 | void tokens_to_keys(const Tokens& tokens, Keys& keys) { 207 | for (const auto& token : tokens) 208 | if (not token.is_string) 209 | keys.push_back(token); 210 | } 211 | 212 | } //< namespace route 213 | -------------------------------------------------------------------------------- /test/path_to_regex_options.cpp: -------------------------------------------------------------------------------- 1 | // This file is a part of the IncludeOS unikernel - www.includeos.org 2 | // 3 | // Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences 4 | // and Alfred Bratterud 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #include 19 | #include "../path_to_regex.hpp" 20 | 21 | using namespace std; 22 | using namespace path2regex; 23 | 24 | // ------------ TESTING PATH_TO_REGEX WITH OPTIONS -------------- 25 | 26 | const lest::test test_path_to_regex_options[] = 27 | { 28 | SCENARIO("Calling path_to_regex with options") 29 | { 30 | // Create with option strict 31 | 32 | GIVEN("An empty vector of Tokens (keys) and option strict set to true") 33 | { 34 | Tokens keys; 35 | Options options{ {"strict", true} }; 36 | 37 | WHEN("Calling path_to_regex with path '/:test'") 38 | { 39 | std::regex r = path_to_regex("/:test", keys, options); 40 | 41 | THEN("") 42 | { 43 | 44 | } 45 | } 46 | }/*, 47 | 48 | GIVEN("An empty vector of Tokens (keys) and option strict set to false") 49 | { 50 | vector keys; 51 | map options{ {"strict", false} }; 52 | 53 | WHEN("Calling path_to_regex with path ''") 54 | { 55 | std::regex r = PathToRegex::path_to_regex("", keys, options); 56 | 57 | } 58 | }, 59 | 60 | // Create with option sensitive 61 | 62 | GIVEN("An empty vector of Tokens (keys) and option sensitive set to true") 63 | { 64 | vector keys; 65 | map options{ {"sensitive", true} }; 66 | 67 | WHEN("Calling path_to_regex with path ''") 68 | { 69 | std::regex r = PathToRegex::path_to_regex("", keys, options); 70 | 71 | } 72 | }, 73 | 74 | GIVEN("An empty vector of Tokens (keys) and option sensitive set to false") 75 | { 76 | vector keys; 77 | map options{ {"sensitive", false} }; 78 | 79 | WHEN("Calling path_to_regex with path ''") 80 | { 81 | std::regex r = PathToRegex::path_to_regex("", keys, options); 82 | 83 | } 84 | }, 85 | 86 | // Create with option end 87 | 88 | GIVEN("An empty vector of Tokens (keys) and option end set to true") 89 | { 90 | vector keys; 91 | map options{ {"end", true} }; 92 | 93 | WHEN("Calling path_to_regex with path ''") 94 | { 95 | std::regex r = PathToRegex::path_to_regex("", keys, options); 96 | 97 | } 98 | }, 99 | 100 | GIVEN("An empty vector of Tokens (keys) and option end set to false") 101 | { 102 | vector keys; 103 | map options{ {"end", false} }; 104 | 105 | WHEN("Calling path_to_regex with path ''") 106 | { 107 | std::regex r = PathToRegex::path_to_regex("", keys, options); 108 | 109 | } 110 | }, 111 | 112 | // Create with options strict and sensitive 113 | 114 | GIVEN("An empty vector of Tokens (keys) and options strict and sensitive set to true") 115 | { 116 | vector keys; 117 | map options{ {"strict", true}, {"sensitive", true} }; 118 | 119 | WHEN("Calling path_to_regex with path ''") 120 | { 121 | std::regex r = PathToRegex::path_to_regex("", keys, options); 122 | 123 | } 124 | }, 125 | 126 | GIVEN("An empty vector of Tokens (keys) and options strict and sensitive set to false") 127 | { 128 | vector keys; 129 | map options{ {"strict", false}, {"sensitive", false} }; 130 | 131 | WHEN("Calling path_to_regex with path ''") 132 | { 133 | std::regex r = PathToRegex::path_to_regex("", keys, options); 134 | 135 | } 136 | }, 137 | 138 | GIVEN("An empty vector of Tokens (keys) and option strict set to true and option sensitive set to false") 139 | { 140 | vector keys; 141 | map options{ {"strict", true}, {"sensitive", false} }; 142 | 143 | WHEN("Calling path_to_regex with path ''") 144 | { 145 | std::regex r = PathToRegex::path_to_regex("", keys, options); 146 | 147 | } 148 | }, 149 | 150 | GIVEN("An empty vector of Tokens (keys) and option strict set to false and option sensitive set to true") 151 | { 152 | vector keys; 153 | map options{ {"strict", false}, {"sensitive", true} }; 154 | 155 | WHEN("Calling path_to_regex with path ''") 156 | { 157 | std::regex r = PathToRegex::path_to_regex("", keys, options); 158 | 159 | } 160 | }, 161 | 162 | // Create with options strict and end 163 | 164 | GIVEN("An empty vector of Tokens (keys) and options strict and end set to true") 165 | { 166 | vector keys; 167 | map options{ {"strict", true}, {"end", true} }; 168 | 169 | WHEN("Calling path_to_regex with path ''") 170 | { 171 | std::regex r = PathToRegex::path_to_regex("", keys, options); 172 | 173 | } 174 | }, 175 | 176 | GIVEN("An empty vector of Tokens (keys) and options strict and end set to false") 177 | { 178 | vector keys; 179 | map options{ {"strict", false}, {"end", false} }; 180 | 181 | WHEN("Calling path_to_regex with path ''") 182 | { 183 | std::regex r = PathToRegex::path_to_regex("", keys, options); 184 | 185 | } 186 | }, 187 | 188 | GIVEN("An empty vector of Tokens (keys) and option strict set to true and option end set to false") 189 | { 190 | vector keys; 191 | map options{ {"strict", true}, {"end", false} }; 192 | 193 | WHEN("Calling path_to_regex with path ''") 194 | { 195 | std::regex r = PathToRegex::path_to_regex("", keys, options); 196 | 197 | } 198 | }, 199 | 200 | GIVEN("An empty vector of Tokens (keys) and option strict set to false and option end set to true") 201 | { 202 | vector keys; 203 | map options{ {"strict", false}, {"end", true} }; 204 | 205 | WHEN("Calling path_to_regex with path ''") 206 | { 207 | std::regex r = PathToRegex::path_to_regex("", keys, options); 208 | 209 | } 210 | }, 211 | 212 | // Create with options sensitive and end 213 | 214 | GIVEN("An empty vector of Tokens (keys) and options sensitive and end set to true") 215 | { 216 | vector keys; 217 | map options{ {"sensitive", true}, {"end", true} }; 218 | 219 | WHEN("Calling path_to_regex with path ''") 220 | { 221 | std::regex r = PathToRegex::path_to_regex("", keys, options); 222 | 223 | } 224 | }, 225 | 226 | GIVEN("An empty vector of Tokens (keys) and options sensitive and end set to false") 227 | { 228 | vector keys; 229 | map options{ {"sensitive", false}, {"end", false} }; 230 | 231 | WHEN("Calling path_to_regex with path ''") 232 | { 233 | std::regex r = PathToRegex::path_to_regex("", keys, options); 234 | 235 | } 236 | }, 237 | 238 | GIVEN("An empty vector of Tokens (keys) and option sensitive set to true and option end set to false") 239 | { 240 | vector keys; 241 | map options{ {"sensitive", true}, {"end", false} }; 242 | 243 | WHEN("Calling path_to_regex with path ''") 244 | { 245 | std::regex r = PathToRegex::path_to_regex("", keys, options); 246 | 247 | } 248 | }, 249 | 250 | GIVEN("An empty vector of Tokens (keys) and option sensitive set to false and option end set to true") 251 | { 252 | vector keys; 253 | map options{ {"sensitive", false}, {"end", true} }; 254 | 255 | WHEN("Calling path_to_regex with path ''") 256 | { 257 | std::regex r = PathToRegex::path_to_regex("", keys, options); 258 | 259 | } 260 | }, 261 | 262 | // Create with options strict, sensitive and end 263 | 264 | GIVEN("An empty vector of Tokens (keys) and options strict, sensitive and end set to true") 265 | { 266 | vector keys; 267 | map options{ {"strict", true}, {"sensitive", true}, {"end", true} }; 268 | 269 | WHEN("Calling path_to_regex with path ''") 270 | { 271 | std::regex r = PathToRegex::path_to_regex("", keys, options); 272 | 273 | } 274 | }, 275 | 276 | GIVEN("An empty vector of Tokens (keys) and options strict, sensitive and end set to false") 277 | { 278 | vector keys; 279 | map options{ {"strict", false}, {"sensitive", false}, {"end", false} }; 280 | 281 | WHEN("Calling path_to_regex with path ''") 282 | { 283 | std::regex r = PathToRegex::path_to_regex("", keys, options); 284 | 285 | } 286 | }, 287 | 288 | GIVEN("An empty vector of Tokens (keys) and option strict set to true, sensitive set to true and end set to false") 289 | { 290 | vector keys; 291 | map options{ {"strict", true}, {"sensitive", true}, {"end", false} }; 292 | 293 | WHEN("Calling path_to_regex with path ''") 294 | { 295 | std::regex r = PathToRegex::path_to_regex("", keys, options); 296 | 297 | } 298 | }, 299 | 300 | GIVEN("An empty vector of Tokens (keys) and option strict set to true, sensitive set to false and end set to false") 301 | { 302 | vector keys; 303 | map options{ {"strict", true}, {"sensitive", false}, {"end", false} }; 304 | 305 | WHEN("Calling path_to_regex with path ''") 306 | { 307 | std::regex r = PathToRegex::path_to_regex("", keys, options); 308 | 309 | } 310 | }, 311 | 312 | GIVEN("An empty vector of Tokens (keys) and option strict set to true, sensitive set to false and end set to true") 313 | { 314 | vector keys; 315 | map options{ {"strict", true}, {"sensitive", false}, {"end", true} }; 316 | 317 | WHEN("Calling path_to_regex with path ''") 318 | { 319 | std::regex r = PathToRegex::path_to_regex("", keys, options); 320 | 321 | } 322 | }, 323 | 324 | GIVEN("An empty vector of Tokens (keys) and option strict set to false, sensitive set to false and end set to true") 325 | { 326 | vector keys; 327 | map options{ {"strict", false}, {"sensitive", false}, {"end", true} }; 328 | 329 | WHEN("Calling path_to_regex with path ''") 330 | { 331 | std::regex r = PathToRegex::path_to_regex("", keys, options); 332 | 333 | } 334 | }, 335 | 336 | GIVEN("An empty vector of Tokens (keys) and option strict set to false, sensitive set to true and end set to true") 337 | { 338 | vector keys; 339 | map options{ {"strict", false}, {"sensitive", true}, {"end", true} }; 340 | 341 | WHEN("Calling path_to_regex with path ''") 342 | { 343 | std::regex r = PathToRegex::path_to_regex("", keys, options); 344 | 345 | } 346 | }, 347 | 348 | GIVEN("An empty vector of Tokens (keys) and option strict set to false, sensitive set to true and end set to false") 349 | { 350 | vector keys; 351 | map options{ {"strict", false}, {"sensitive", true}, {"end", false} }; 352 | 353 | WHEN("Calling path_to_regex with path ''") 354 | { 355 | std::regex r = PathToRegex::path_to_regex("", keys, options); 356 | 357 | } 358 | }*/ 359 | } // < SCENARIO (with options) 360 | }; 361 | 362 | int main(int argc, char * argv[]) 363 | { 364 | printf("Running tests of path_to_regex with options...\n"); 365 | 366 | int res = lest::run(test_path_to_regex_options, argc, argv); 367 | 368 | printf("Path_to_regex-tests (with options) completed.\n"); 369 | 370 | return res; 371 | } 372 | -------------------------------------------------------------------------------- /test/path_to_regex_parse.cpp: -------------------------------------------------------------------------------- 1 | // This file is a part of the IncludeOS unikernel - www.includeos.org 2 | // 3 | // Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences 4 | // and Alfred Bratterud 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #include 19 | #include "../path_to_regex.hpp" 20 | 21 | using namespace std; 22 | using namespace path2regex; 23 | 24 | // ---------------- TESTING PATHTOREGEXP PARSE --------------------- 25 | 26 | const lest::test test_path_to_regexp_parse[] = 27 | { 28 | // Testing named parameter 29 | 30 | CASE("String with one named parameter (/:test)") 31 | { 32 | Tokens tokens = parse("/:test"); 33 | 34 | EXPECT_NOT(tokens.empty()); 35 | EXPECT(tokens.size() == 1u); 36 | 37 | Token t = tokens[0]; 38 | 39 | EXPECT(t.name == "test"); 40 | EXPECT(t.prefix == "/"); 41 | EXPECT(t.delimiter == "/"); 42 | EXPECT_NOT(t.optional); 43 | EXPECT_NOT(t.repeat); 44 | EXPECT_NOT(t.partial); 45 | EXPECT_NOT(t.asterisk); 46 | EXPECT(t.pattern == "[^/]+?"); // or "[^\/]+?" 47 | EXPECT_NOT(t.is_string); 48 | }, 49 | 50 | CASE("String with two named parameters (/:test/:date)") 51 | { 52 | Tokens tokens = parse("/:test/:date"); 53 | 54 | EXPECT_NOT(tokens.empty()); 55 | EXPECT(tokens.size() == 2u); 56 | 57 | Token t1 = tokens[0]; 58 | Token t2 = tokens[1]; 59 | 60 | EXPECT(t1.name == "test"); 61 | EXPECT(t1.prefix == "/"); 62 | EXPECT(t1.delimiter == "/"); 63 | EXPECT_NOT(t1.optional); 64 | EXPECT_NOT(t1.repeat); 65 | EXPECT_NOT(t1.partial); 66 | EXPECT_NOT(t1.asterisk); 67 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 68 | EXPECT_NOT(t1.is_string); 69 | 70 | EXPECT(t2.name == "date"); 71 | EXPECT(t2.prefix == "/"); 72 | EXPECT(t2.delimiter == "/"); 73 | EXPECT_NOT(t2.optional); 74 | EXPECT_NOT(t2.repeat); 75 | EXPECT_NOT(t2.partial); 76 | EXPECT_NOT(t2.asterisk); 77 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 78 | EXPECT_NOT(t2.is_string); 79 | }, 80 | 81 | CASE("String with three elements, containing two named parameters (/users/:test/:date)") 82 | { 83 | Tokens tokens = parse("/users/:test/:date"); 84 | 85 | EXPECT_NOT(tokens.empty()); 86 | EXPECT(tokens.size() == 3u); 87 | 88 | Token t1 = tokens[0]; 89 | Token t2 = tokens[1]; 90 | Token t3 = tokens[2]; 91 | 92 | EXPECT(t1.name == "/users"); 93 | EXPECT(t1.prefix == ""); 94 | EXPECT(t1.delimiter == ""); 95 | EXPECT_NOT(t1.optional); 96 | EXPECT_NOT(t1.repeat); 97 | EXPECT_NOT(t1.partial); 98 | EXPECT_NOT(t1.asterisk); 99 | EXPECT(t1.pattern == ""); // or "[^\/]+?" 100 | EXPECT(t1.is_string); 101 | 102 | EXPECT(t2.name == "test"); 103 | EXPECT(t2.prefix == "/"); 104 | EXPECT(t2.delimiter == "/"); 105 | EXPECT_NOT(t2.optional); 106 | EXPECT_NOT(t2.repeat); 107 | EXPECT_NOT(t2.partial); 108 | EXPECT_NOT(t2.asterisk); 109 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 110 | EXPECT_NOT(t2.is_string); 111 | 112 | EXPECT(t3.name == "date"); 113 | EXPECT(t3.prefix == "/"); 114 | EXPECT(t3.delimiter == "/"); 115 | EXPECT_NOT(t3.optional); 116 | EXPECT_NOT(t3.repeat); 117 | EXPECT_NOT(t3.partial); 118 | EXPECT_NOT(t3.asterisk); 119 | EXPECT(t3.pattern == "[^/]+?"); // or "[^\/]+?" 120 | EXPECT_NOT(t3.is_string); 121 | }, 122 | 123 | // Testing no parameters 124 | 125 | CASE("String with no parameters (/test)") 126 | { 127 | Tokens tokens = parse("/test"); 128 | 129 | EXPECT_NOT(tokens.empty()); 130 | EXPECT(tokens.size() == 1u); 131 | 132 | Token t = tokens[0]; 133 | 134 | EXPECT(t.name == "/test"); 135 | EXPECT(t.prefix == ""); 136 | EXPECT(t.delimiter == ""); 137 | EXPECT_NOT(t.optional); 138 | EXPECT_NOT(t.repeat); 139 | EXPECT_NOT(t.partial); 140 | EXPECT_NOT(t.asterisk); 141 | EXPECT(t.pattern == ""); 142 | EXPECT(t.is_string); 143 | }, 144 | 145 | CASE("String with no parameters (/test/users)") 146 | { 147 | Tokens tokens = parse("/test/users"); 148 | 149 | EXPECT_NOT(tokens.empty()); 150 | EXPECT(tokens.size() == 1u); 151 | 152 | Token t = tokens[0]; 153 | 154 | EXPECT(t.name == "/test/users"); 155 | EXPECT(t.prefix == ""); 156 | EXPECT(t.delimiter == ""); 157 | EXPECT_NOT(t.optional); 158 | EXPECT_NOT(t.repeat); 159 | EXPECT_NOT(t.partial); 160 | EXPECT_NOT(t.asterisk); 161 | EXPECT(t.pattern == ""); 162 | EXPECT(t.is_string); 163 | }, 164 | 165 | // Testing optional parameters ( ? ) 166 | 167 | CASE("String with one optional parameter (/:test?)") 168 | { 169 | Tokens tokens = parse("/:test?"); 170 | 171 | EXPECT_NOT(tokens.empty()); 172 | EXPECT(tokens.size() == 1u); 173 | 174 | Token t = tokens[0]; 175 | 176 | EXPECT(t.name == "test"); 177 | EXPECT(t.prefix == "/"); 178 | EXPECT(t.delimiter == "/"); 179 | EXPECT(t.optional); 180 | EXPECT_NOT(t.repeat); 181 | EXPECT_NOT(t.partial); 182 | EXPECT_NOT(t.asterisk); 183 | EXPECT(t.pattern == "[^/]+?"); // or "[^\/]+?" 184 | EXPECT_NOT(t.is_string); 185 | }, 186 | 187 | CASE("String with two optional parameters (/:test?/:date?)") 188 | { 189 | Tokens tokens = parse("/:test?/:date?"); 190 | 191 | EXPECT_NOT(tokens.empty()); 192 | EXPECT(tokens.size() == 2u); 193 | 194 | Token t1 = tokens[0]; 195 | Token t2 = tokens[1]; 196 | 197 | EXPECT(t1.name == "test"); 198 | EXPECT(t1.prefix == "/"); 199 | EXPECT(t1.delimiter == "/"); 200 | EXPECT(t1.optional); 201 | EXPECT_NOT(t1.repeat); 202 | EXPECT_NOT(t1.partial); 203 | EXPECT_NOT(t1.asterisk); 204 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 205 | EXPECT_NOT(t1.is_string); 206 | 207 | EXPECT(t2.name == "date"); 208 | EXPECT(t2.prefix == "/"); 209 | EXPECT(t2.delimiter == "/"); 210 | EXPECT(t2.optional); 211 | EXPECT_NOT(t2.repeat); 212 | EXPECT_NOT(t2.partial); 213 | EXPECT_NOT(t2.asterisk); 214 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 215 | EXPECT_NOT(t2.is_string); 216 | }, 217 | 218 | CASE("String with three elements, containing two optional parameters (/:test?/users/:date?)") 219 | { 220 | Tokens tokens = parse("/:test?/users/:date?"); 221 | 222 | EXPECT_NOT(tokens.empty()); 223 | EXPECT(tokens.size() == 3u); 224 | 225 | Token t1 = tokens[0]; 226 | Token t2 = tokens[1]; 227 | Token t3 = tokens[2]; 228 | 229 | EXPECT(t1.name == "test"); 230 | EXPECT(t1.prefix == "/"); 231 | EXPECT(t1.delimiter == "/"); 232 | EXPECT(t1.optional); 233 | EXPECT_NOT(t1.repeat); 234 | EXPECT_NOT(t1.partial); 235 | EXPECT_NOT(t1.asterisk); 236 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 237 | EXPECT_NOT(t1.is_string); 238 | 239 | EXPECT(t2.name == "/users"); 240 | EXPECT(t2.prefix == ""); 241 | EXPECT(t2.delimiter == ""); 242 | EXPECT_NOT(t2.optional); 243 | EXPECT_NOT(t2.repeat); 244 | EXPECT_NOT(t2.partial); 245 | EXPECT_NOT(t2.asterisk); 246 | EXPECT(t2.pattern == ""); // or "[^\/]+?" 247 | EXPECT(t2.is_string); 248 | 249 | EXPECT(t3.name == "date"); 250 | EXPECT(t3.prefix == "/"); 251 | EXPECT(t3.delimiter == "/"); 252 | EXPECT(t3.optional); 253 | EXPECT_NOT(t3.repeat); 254 | EXPECT_NOT(t3.partial); 255 | EXPECT_NOT(t3.asterisk); 256 | EXPECT(t3.pattern == "[^/]+?"); // or "[^\/]+?" 257 | EXPECT_NOT(t3.is_string); 258 | }, 259 | 260 | CASE("String with two named parameters, where one is optional (/:test/:date?)") 261 | { 262 | Tokens tokens = parse("/:test/:date?"); 263 | 264 | EXPECT_NOT(tokens.empty()); 265 | EXPECT(tokens.size() == 2u); 266 | 267 | Token t1 = tokens[0]; 268 | Token t2 = tokens[1]; 269 | 270 | EXPECT(t1.name == "test"); 271 | EXPECT(t1.prefix == "/"); 272 | EXPECT(t1.delimiter == "/"); 273 | EXPECT_NOT(t1.optional); 274 | EXPECT_NOT(t1.repeat); 275 | EXPECT_NOT(t1.partial); 276 | EXPECT_NOT(t1.asterisk); 277 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 278 | EXPECT_NOT(t1.is_string); 279 | 280 | EXPECT(t2.name == "date"); 281 | EXPECT(t2.prefix == "/"); 282 | EXPECT(t2.delimiter == "/"); 283 | EXPECT(t2.optional); 284 | EXPECT_NOT(t2.repeat); 285 | EXPECT_NOT(t2.partial); 286 | EXPECT_NOT(t2.asterisk); 287 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 288 | EXPECT_NOT(t2.is_string); 289 | }, 290 | 291 | // Testing parameters with asterisk (zero or more) 292 | 293 | CASE("String with one named parameter with asterisk (zero or more) (/:test*)") 294 | { 295 | Tokens tokens = parse("/:test*"); 296 | 297 | EXPECT_NOT(tokens.empty()); 298 | EXPECT(tokens.size() == 1u); 299 | 300 | Token t = tokens[0]; 301 | 302 | EXPECT(t.name == "test"); 303 | EXPECT(t.prefix == "/"); 304 | EXPECT(t.delimiter == "/"); 305 | EXPECT(t.optional); 306 | EXPECT(t.repeat); 307 | EXPECT_NOT(t.partial); 308 | EXPECT_NOT(t.asterisk); 309 | EXPECT(t.pattern == "[^/]+?"); // or "[^\/]+?" 310 | EXPECT_NOT(t.is_string); 311 | }, 312 | 313 | CASE("String with two parameters, where one is a named parameter with asterisk (zero or more) (/:date/:test*)") 314 | { 315 | Tokens tokens = parse("/:date/:test*"); 316 | 317 | EXPECT_NOT(tokens.empty()); 318 | EXPECT(tokens.size() == 2u); 319 | 320 | Token t1 = tokens[0]; 321 | Token t2 = tokens[1]; 322 | 323 | EXPECT(t1.name == "date"); 324 | EXPECT(t1.prefix == "/"); 325 | EXPECT(t1.delimiter == "/"); 326 | EXPECT_NOT(t1.optional); 327 | EXPECT_NOT(t1.repeat); 328 | EXPECT_NOT(t1.partial); 329 | EXPECT_NOT(t1.asterisk); 330 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 331 | EXPECT_NOT(t1.is_string); 332 | 333 | EXPECT(t2.name == "test"); 334 | EXPECT(t2.prefix == "/"); 335 | EXPECT(t2.delimiter == "/"); 336 | EXPECT(t2.optional); 337 | EXPECT(t2.repeat); 338 | EXPECT_NOT(t2.partial); 339 | EXPECT_NOT(t2.asterisk); 340 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 341 | EXPECT_NOT(t2.is_string); 342 | }, 343 | 344 | // Testing parameters with plus (one or more) 345 | 346 | CASE("String with one named parameter with plus (one or more) (/:test+)") 347 | { 348 | Tokens tokens = parse("/:test+"); 349 | 350 | EXPECT_NOT(tokens.empty()); 351 | EXPECT(tokens.size() == 1u); 352 | 353 | Token t = tokens[0]; 354 | 355 | EXPECT(t.name == "test"); 356 | EXPECT(t.prefix == "/"); 357 | EXPECT(t.delimiter == "/"); 358 | EXPECT_NOT(t.optional); 359 | EXPECT(t.repeat); 360 | EXPECT_NOT(t.partial); 361 | EXPECT_NOT(t.asterisk); 362 | EXPECT(t.pattern == "[^/]+?"); // or "[^\/]+?" 363 | EXPECT_NOT(t.is_string); 364 | }, 365 | 366 | CASE("String with two parameters, where one is a named parameter with plus (one or more) (/:id/:test+") 367 | { 368 | Tokens tokens = parse("/:id/:test+"); 369 | 370 | EXPECT_NOT(tokens.empty()); 371 | EXPECT(tokens.size() == 2u); 372 | 373 | Token t1 = tokens[0]; 374 | Token t2 = tokens[1]; 375 | 376 | EXPECT(t1.name == "id"); 377 | EXPECT(t1.prefix == "/"); 378 | EXPECT(t1.delimiter == "/"); 379 | EXPECT_NOT(t1.optional); 380 | EXPECT_NOT(t1.repeat); 381 | EXPECT_NOT(t1.partial); 382 | EXPECT_NOT(t1.asterisk); 383 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 384 | EXPECT_NOT(t1.is_string); 385 | 386 | EXPECT(t2.name == "test"); 387 | EXPECT(t2.prefix == "/"); 388 | EXPECT(t2.delimiter == "/"); 389 | EXPECT_NOT(t2.optional); 390 | EXPECT(t2.repeat); 391 | EXPECT_NOT(t2.partial); 392 | EXPECT_NOT(t2.asterisk); 393 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 394 | EXPECT_NOT(t2.is_string); 395 | }, 396 | 397 | CASE("String with two parameters, where one is a named parameter with plus (one or more) that only takes lower case letters, and one is a named parameter that only takes integers (/:test([a-z])+/:id(\\d+))") 398 | { 399 | Tokens tokens = parse("/:test([a-z])+/:id(\\d+)"); 400 | 401 | EXPECT_NOT(tokens.empty()); 402 | EXPECT(tokens.size() == 2u); 403 | 404 | Token t1 = tokens[0]; 405 | Token t2 = tokens[1]; 406 | 407 | EXPECT(t1.name == "test"); 408 | EXPECT(t1.prefix == "/"); 409 | EXPECT(t1.delimiter == "/"); 410 | EXPECT_NOT(t1.optional); 411 | EXPECT(t1.repeat); 412 | EXPECT_NOT(t1.partial); 413 | EXPECT_NOT(t1.asterisk); 414 | EXPECT(t1.pattern == "[a-z]"); 415 | EXPECT_NOT(t1.is_string); 416 | 417 | EXPECT(t2.name == "id"); 418 | EXPECT(t2.prefix == "/"); 419 | EXPECT(t2.delimiter == "/"); 420 | EXPECT_NOT(t2.optional); 421 | EXPECT_NOT(t2.repeat); 422 | EXPECT_NOT(t2.partial); 423 | EXPECT_NOT(t2.asterisk); 424 | EXPECT(t2.pattern == "\\d+"); // or "\d+" 425 | EXPECT_NOT(t2.is_string); 426 | }, 427 | 428 | // Testing custom match parameters 429 | 430 | CASE("String with one custom match parameter - only integers (one or more) (/:test(\\d+))") 431 | { 432 | Tokens tokens = parse("/:test(\\d+)"); 433 | 434 | EXPECT_NOT(tokens.empty()); 435 | EXPECT(tokens.size() == 1u); 436 | 437 | Token t = tokens[0]; 438 | 439 | EXPECT(t.name == "test"); 440 | EXPECT(t.prefix == "/"); 441 | EXPECT(t.delimiter == "/"); 442 | EXPECT_NOT(t.optional); 443 | EXPECT_NOT(t.repeat); 444 | EXPECT_NOT(t.partial); 445 | EXPECT_NOT(t.asterisk); 446 | EXPECT(t.pattern == "\\d+"); // or "\d+" 447 | EXPECT_NOT(t.is_string); 448 | }, 449 | 450 | CASE("String with one custom match parameter - only a-z (one or more) (/:test([a-z]+))") 451 | { 452 | Tokens tokens = parse("/:test([a-z]+)"); 453 | 454 | EXPECT_NOT(tokens.empty()); 455 | EXPECT(tokens.size() == 1u); 456 | 457 | Token t = tokens[0]; 458 | 459 | EXPECT(t.name == "test"); 460 | EXPECT(t.prefix == "/"); 461 | EXPECT(t.delimiter == "/"); 462 | EXPECT_NOT(t.optional); 463 | EXPECT_NOT(t.repeat); 464 | EXPECT_NOT(t.partial); 465 | EXPECT_NOT(t.asterisk); 466 | EXPECT(t.pattern == "[a-z]+"); 467 | EXPECT_NOT(t.is_string); 468 | }, 469 | 470 | CASE("String with two parameters, where one is a custom match parameter - only integers (one or more) (/:test/:id(\\d+))") 471 | { 472 | Tokens tokens = parse("/:test/:id(\\d+)"); 473 | 474 | EXPECT_NOT(tokens.empty()); 475 | EXPECT(tokens.size() == 2u); 476 | 477 | Token t1 = tokens[0]; 478 | Token t2 = tokens[1]; 479 | 480 | EXPECT(t1.name == "test"); 481 | EXPECT(t1.prefix == "/"); 482 | EXPECT(t1.delimiter == "/"); 483 | EXPECT_NOT(t1.optional); 484 | EXPECT_NOT(t1.repeat); 485 | EXPECT_NOT(t1.partial); 486 | EXPECT_NOT(t1.asterisk); 487 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 488 | EXPECT_NOT(t1.is_string); 489 | 490 | EXPECT(t2.name == "id"); 491 | EXPECT(t2.prefix == "/"); 492 | EXPECT(t2.delimiter == "/"); 493 | EXPECT_NOT(t2.optional); 494 | EXPECT_NOT(t2.repeat); 495 | EXPECT_NOT(t2.partial); 496 | EXPECT_NOT(t2.asterisk); 497 | EXPECT(t2.pattern == "\\d+"); // or "\d+" 498 | EXPECT_NOT(t2.is_string); 499 | }, 500 | 501 | // Testing unnamed parameters 502 | 503 | CASE("String with one unnamed parameter (/(.*)") 504 | { 505 | Tokens tokens = parse("/(.*)"); 506 | 507 | EXPECT_NOT(tokens.empty()); 508 | EXPECT(tokens.size() == 1u); 509 | 510 | Token t = tokens[0]; 511 | 512 | EXPECT(t.name == "0"); 513 | EXPECT(t.prefix == "/"); 514 | EXPECT(t.delimiter == "/"); 515 | EXPECT_NOT(t.optional); 516 | EXPECT_NOT(t.repeat); 517 | EXPECT_NOT(t.partial); 518 | EXPECT_NOT(t.asterisk); 519 | EXPECT(t.pattern == ".*"); 520 | EXPECT_NOT(t.is_string); 521 | }, 522 | 523 | CASE("String with one unnamed parameter that only takes integers (one or more) (/(\\d+))") 524 | { 525 | Tokens tokens = parse("/(\\d+)"); 526 | 527 | EXPECT_NOT(tokens.empty()); 528 | EXPECT(tokens.size() == 1u); 529 | 530 | Token t = tokens[0]; 531 | 532 | EXPECT(t.name == "0"); 533 | EXPECT(t.prefix == "/"); 534 | EXPECT(t.delimiter == "/"); 535 | EXPECT_NOT(t.optional); 536 | EXPECT_NOT(t.repeat); 537 | EXPECT_NOT(t.partial); 538 | EXPECT_NOT(t.asterisk); 539 | EXPECT(t.pattern == "\\d+"); // or \d+ 540 | EXPECT_NOT(t.is_string); 541 | }, 542 | 543 | CASE("String with two parameters, where one is an unnamed parameter (/:test/(.*))") 544 | { 545 | Tokens tokens = parse("/:test/(.*)"); 546 | 547 | EXPECT_NOT(tokens.empty()); 548 | EXPECT(tokens.size() == 2u); 549 | 550 | Token t1 = tokens[0]; 551 | Token t2 = tokens[1]; 552 | 553 | EXPECT(t1.name == "test"); 554 | EXPECT(t1.prefix == "/"); 555 | EXPECT(t1.delimiter == "/"); 556 | EXPECT_NOT(t1.optional); 557 | EXPECT_NOT(t1.repeat); 558 | EXPECT_NOT(t1.partial); 559 | EXPECT_NOT(t1.asterisk); 560 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 561 | EXPECT_NOT(t1.is_string); 562 | 563 | EXPECT(t2.name == "0"); 564 | EXPECT(t2.prefix == "/"); 565 | EXPECT(t2.delimiter == "/"); 566 | EXPECT_NOT(t2.optional); 567 | EXPECT_NOT(t2.repeat); 568 | EXPECT_NOT(t2.partial); 569 | EXPECT_NOT(t2.asterisk); 570 | EXPECT(t2.pattern == ".*"); 571 | EXPECT_NOT(t2.is_string); 572 | }, 573 | 574 | CASE("String with two elements, where one is an unnamed parameter (/users/(.*))") 575 | { 576 | Tokens tokens = parse("/users/(.*)"); 577 | 578 | EXPECT_NOT(tokens.empty()); 579 | EXPECT(tokens.size() == 2u); 580 | 581 | Token t1 = tokens[0]; 582 | Token t2 = tokens[1]; 583 | 584 | EXPECT(t1.name == "/users"); 585 | EXPECT(t1.prefix == ""); 586 | EXPECT(t1.delimiter == ""); 587 | EXPECT_NOT(t1.optional); 588 | EXPECT_NOT(t1.repeat); 589 | EXPECT_NOT(t1.partial); 590 | EXPECT_NOT(t1.asterisk); 591 | EXPECT(t1.pattern == ""); 592 | EXPECT(t1.is_string); 593 | 594 | EXPECT(t2.name == "0"); 595 | EXPECT(t2.prefix == "/"); 596 | EXPECT(t2.delimiter == "/"); 597 | EXPECT_NOT(t2.optional); 598 | EXPECT_NOT(t2.repeat); 599 | EXPECT_NOT(t2.partial); 600 | EXPECT_NOT(t2.asterisk); 601 | EXPECT(t2.pattern == ".*"); 602 | EXPECT_NOT(t2.is_string); 603 | }, 604 | 605 | // Testing asterisk parameter 606 | 607 | CASE("String with one unnamed parameter (/*)") 608 | { 609 | Tokens tokens = parse("/*"); 610 | 611 | EXPECT_NOT(tokens.empty()); 612 | EXPECT(tokens.size() == 1u); 613 | 614 | Token t = tokens[0]; 615 | 616 | EXPECT(t.name == "0"); 617 | EXPECT(t.prefix == "/"); 618 | EXPECT(t.delimiter == "/"); 619 | EXPECT_NOT(t.optional); 620 | EXPECT_NOT(t.repeat); 621 | EXPECT_NOT(t.partial); 622 | EXPECT(t.asterisk); 623 | EXPECT(t.pattern == ".*"); 624 | EXPECT_NOT(t.is_string); 625 | }, 626 | 627 | CASE("String with two parameters, where one is an asterisk (zero or more) (/test/:id/*)") 628 | { 629 | Tokens tokens = parse("/test/:id/*"); 630 | 631 | EXPECT_NOT(tokens.empty()); 632 | EXPECT(tokens.size() == 3u); 633 | 634 | Token t1 = tokens[0]; 635 | Token t2 = tokens[1]; 636 | Token t3 = tokens[2]; 637 | 638 | EXPECT(t1.name == "/test"); 639 | EXPECT(t1.prefix == ""); 640 | EXPECT(t1.delimiter == ""); 641 | EXPECT_NOT(t1.optional); 642 | EXPECT_NOT(t1.repeat); 643 | EXPECT_NOT(t1.partial); 644 | EXPECT_NOT(t1.asterisk); 645 | EXPECT(t1.pattern == ""); 646 | EXPECT(t1.is_string); 647 | 648 | EXPECT(t2.name == "id"); 649 | EXPECT(t2.prefix == "/"); 650 | EXPECT(t2.delimiter == "/"); 651 | EXPECT_NOT(t2.optional); 652 | EXPECT_NOT(t2.repeat); 653 | EXPECT_NOT(t2.partial); 654 | EXPECT_NOT(t2.asterisk); 655 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 656 | EXPECT_NOT(t2.is_string); 657 | 658 | EXPECT(t3.name == "0"); 659 | EXPECT(t3.prefix == "/"); 660 | EXPECT(t3.delimiter == "/"); 661 | EXPECT_NOT(t3.optional); 662 | EXPECT_NOT(t3.repeat); 663 | EXPECT_NOT(t3.partial); 664 | EXPECT(t3.asterisk); 665 | EXPECT(t3.pattern == ".*"); 666 | EXPECT_NOT(t3.is_string); 667 | } 668 | }; 669 | 670 | int main(int argc, char * argv[]) 671 | { 672 | printf("Running tests of PathToRegexp parse-method...\n"); 673 | 674 | int res = lest::run(test_path_to_regexp_parse, argc, argv); 675 | 676 | printf("PathToRegexp parse-tests completed.\n"); 677 | 678 | return res; 679 | } 680 | -------------------------------------------------------------------------------- /test/path_to_regex_no_options.cpp: -------------------------------------------------------------------------------- 1 | // This file is a part of the IncludeOS unikernel - www.includeos.org 2 | // 3 | // Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences 4 | // and Alfred Bratterud 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #include 19 | #include "../path_to_regex.hpp" 20 | 21 | using namespace std; 22 | using namespace path2regex; 23 | 24 | // ------------ TESTING PATH_TO_REGEX WITH NO OPTIONS -------------- 25 | 26 | const lest::test test_path_to_regex_no_options[] = 27 | { 28 | SCENARIO("Creating path_to_regex with no options") 29 | { 30 | GIVEN("An empty vector of Tokens (keys) and no options") 31 | { 32 | Tokens keys; 33 | 34 | WHEN("Calling path_to_regex with empty path") 35 | { 36 | std::regex r = path_to_regex("", keys); 37 | 38 | // Testing keys: 39 | 40 | EXPECT(keys.empty()); 41 | EXPECT(keys.size() == 0u); 42 | 43 | // Testing regex: 44 | 45 | THEN("No paths should match") 46 | { 47 | EXPECT(std::regex_match("", r)); 48 | 49 | EXPECT_NOT(std::regex_match("/route", r)); 50 | EXPECT_NOT(std::regex_match("/route/123", r)); 51 | } 52 | } 53 | 54 | WHEN("Calling path_to_regex with path '/:test'") 55 | { 56 | std::regex r = path_to_regex("/:test", keys); 57 | 58 | // Testing keys: 59 | 60 | EXPECT_NOT(keys.empty()); 61 | EXPECT(keys.size() == 1u); 62 | 63 | Token t = keys[0]; 64 | 65 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 66 | EXPECT(t.name == "test"); 67 | EXPECT(t.prefix == "/"); 68 | EXPECT(t.delimiter == "/"); 69 | EXPECT_NOT(t.optional); 70 | EXPECT_NOT(t.repeat); 71 | EXPECT_NOT(t.partial); 72 | EXPECT_NOT(t.asterisk); 73 | EXPECT(t.pattern == "[^/]+?"); // or "[^\/]+?" 74 | EXPECT_NOT(t.is_string); 75 | 76 | // Testing regex: 77 | 78 | THEN("Only paths with one parameter should match. This can contain any character") 79 | { 80 | EXPECT_NOT(std::regex_match("/", r)); 81 | EXPECT_NOT(std::regex_match("/route/123", r)); 82 | EXPECT_NOT(std::regex_match("/route/something/somethingelse12", r)); 83 | EXPECT_NOT(std::regex_match("route", r)); 84 | 85 | EXPECT(std::regex_match("/route", r)); 86 | EXPECT(std::regex_match("/123", r)); 87 | EXPECT(std::regex_match("/route!)#̈́'", r)); 88 | } 89 | } 90 | 91 | WHEN("Calling path_to_regex with path '/:test/:date'") 92 | { 93 | std::regex r = path_to_regex("/:test/:date", keys); 94 | 95 | // Testing keys: 96 | 97 | EXPECT_NOT(keys.empty()); 98 | EXPECT(keys.size() == 2u); 99 | 100 | Token t1 = keys[0]; 101 | Token t2 = keys[1]; 102 | 103 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 104 | EXPECT(t1.name == "test"); 105 | EXPECT(t1.prefix == "/"); 106 | EXPECT(t1.delimiter == "/"); 107 | EXPECT_NOT(t1.optional); 108 | EXPECT_NOT(t1.repeat); 109 | EXPECT_NOT(t1.partial); 110 | EXPECT_NOT(t1.asterisk); 111 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 112 | EXPECT_NOT(t1.is_string); 113 | 114 | EXPECT(t2.name == "date"); 115 | EXPECT(t2.prefix == "/"); 116 | EXPECT(t2.delimiter == "/"); 117 | EXPECT_NOT(t2.optional); 118 | EXPECT_NOT(t2.repeat); 119 | EXPECT_NOT(t2.partial); 120 | EXPECT_NOT(t2.asterisk); 121 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 122 | EXPECT_NOT(t2.is_string); 123 | 124 | // Testing regex: 125 | 126 | THEN("Only paths with two parameters should match. This can contain any character") 127 | { 128 | EXPECT_NOT(std::regex_match("/", r)); 129 | EXPECT_NOT(std::regex_match("/route", r)); 130 | EXPECT_NOT(std::regex_match("/route/something/somethingelse12", r)); 131 | 132 | EXPECT(std::regex_match("/route/123", r)); 133 | EXPECT(std::regex_match("/123/route", r)); 134 | EXPECT(std::regex_match("/route!)#/route321'", r)); 135 | } 136 | } 137 | 138 | WHEN("Calling path_to_regex with path '/users/:test/:date'") 139 | { 140 | std::regex r = path_to_regex("/users/:test/:date", keys); 141 | 142 | // Testing keys: 143 | 144 | EXPECT_NOT(keys.empty()); 145 | EXPECT(keys.size() == 2u); 146 | 147 | Token t1 = keys[0]; 148 | Token t2 = keys[1]; 149 | 150 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 151 | EXPECT(t1.name == "test"); 152 | EXPECT(t1.prefix == "/"); 153 | EXPECT(t1.delimiter == "/"); 154 | EXPECT_NOT(t1.optional); 155 | EXPECT_NOT(t1.repeat); 156 | EXPECT_NOT(t1.partial); 157 | EXPECT_NOT(t1.asterisk); 158 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 159 | EXPECT_NOT(t1.is_string); 160 | 161 | EXPECT(t2.name == "date"); 162 | EXPECT(t2.prefix == "/"); 163 | EXPECT(t2.delimiter == "/"); 164 | EXPECT_NOT(t2.optional); 165 | EXPECT_NOT(t2.repeat); 166 | EXPECT_NOT(t2.partial); 167 | EXPECT_NOT(t2.asterisk); 168 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 169 | EXPECT_NOT(t2.is_string); 170 | 171 | // Testing regex: 172 | 173 | THEN("Only paths with three elements should match, starting with /users") 174 | { 175 | EXPECT_NOT(std::regex_match("/", r)); 176 | EXPECT_NOT(std::regex_match("/route", r)); 177 | EXPECT_NOT(std::regex_match("/users", r)); 178 | EXPECT_NOT(std::regex_match("/users/123", r)); 179 | EXPECT_NOT(std::regex_match("/users/something/123/else", r)); 180 | EXPECT_NOT(std::regex_match("/route/something/somethingelse12", r)); 181 | 182 | EXPECT(std::regex_match("/users/123/something", r)); 183 | EXPECT(std::regex_match("/users/some12p-?/523", r)); 184 | EXPECT(std::regex_match("/users/route!)#/route321'", r)); 185 | } 186 | } 187 | 188 | WHEN("Calling path_to_regex with path '/test'") 189 | { 190 | std::regex r = path_to_regex("/test", keys); 191 | 192 | // Testing keys: 193 | 194 | EXPECT(keys.empty()); 195 | EXPECT(keys.size() == 0u); 196 | 197 | // Testing regex: 198 | 199 | THEN("Only the path '/test' should match") 200 | { 201 | EXPECT_NOT(std::regex_match("/", r)); 202 | EXPECT_NOT(std::regex_match("/tes", r)); 203 | EXPECT_NOT(std::regex_match("/tests", r)); 204 | EXPECT_NOT(std::regex_match("/test/123", r)); 205 | EXPECT_NOT(std::regex_match("/test/something/somethingelse12", r)); 206 | 207 | EXPECT(std::regex_match("/test", r)); 208 | } 209 | } 210 | 211 | WHEN("Calling path_to_regex with path '/test/users'") 212 | { 213 | std::regex r = path_to_regex("/test/users", keys); 214 | 215 | // Testing keys: 216 | 217 | EXPECT(keys.empty()); 218 | EXPECT(keys.size() == 0u); 219 | 220 | // Testing regex: 221 | 222 | THEN("Only the path '/test/users' should match") 223 | { 224 | EXPECT_NOT(std::regex_match("/", r)); 225 | EXPECT_NOT(std::regex_match("/test", r)); 226 | EXPECT_NOT(std::regex_match("/test/user", r)); 227 | EXPECT_NOT(std::regex_match("/tes/users", r)); 228 | EXPECT_NOT(std::regex_match("/test/users/123", r)); 229 | EXPECT_NOT(std::regex_match("/test/something/somethingelse12", r)); 230 | 231 | EXPECT(std::regex_match("/test/users", r)); 232 | } 233 | } 234 | 235 | WHEN("Calling path_to_regex with path '/:test?'") 236 | { 237 | std::regex r = path_to_regex("/:test?", keys); 238 | 239 | // Testing keys: 240 | 241 | EXPECT_NOT(keys.empty()); 242 | EXPECT(keys.size() == 1u); 243 | 244 | Token t = keys[0]; 245 | 246 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 247 | EXPECT(t.name == "test"); 248 | EXPECT(t.prefix == "/"); 249 | EXPECT(t.delimiter == "/"); 250 | EXPECT(t.optional); 251 | EXPECT_NOT(t.repeat); 252 | EXPECT_NOT(t.partial); 253 | EXPECT_NOT(t.asterisk); 254 | EXPECT(t.pattern == "[^/]+?"); // or "[^\/]+?" 255 | EXPECT_NOT(t.is_string); 256 | 257 | // Testing regex: 258 | 259 | THEN("Only paths with one or no parameters should match") 260 | { 261 | EXPECT_NOT(std::regex_match("/users/123", r)); 262 | EXPECT_NOT(std::regex_match("/users/something/123/else", r)); 263 | EXPECT_NOT(std::regex_match("/route/something/somethingelse12", r)); 264 | 265 | EXPECT(std::regex_match("", r)); 266 | EXPECT(std::regex_match("/", r)); 267 | EXPECT(std::regex_match("/route", r)); 268 | EXPECT(std::regex_match("/users4)", r)); 269 | EXPECT(std::regex_match("/123", r)); 270 | } 271 | } 272 | 273 | WHEN("Calling path_to_regex with path '/:test?/:date?'") 274 | { 275 | std::regex r = path_to_regex("/:test?/:date?", keys); 276 | 277 | // Testing keys: 278 | 279 | EXPECT_NOT(keys.empty()); 280 | EXPECT(keys.size() == 2u); 281 | 282 | Token t1 = keys[0]; 283 | Token t2 = keys[1]; 284 | 285 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 286 | EXPECT(t1.name == "test"); 287 | EXPECT(t1.prefix == "/"); 288 | EXPECT(t1.delimiter == "/"); 289 | EXPECT(t1.optional); 290 | EXPECT_NOT(t1.repeat); 291 | EXPECT_NOT(t1.partial); 292 | EXPECT_NOT(t1.asterisk); 293 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 294 | EXPECT_NOT(t1.is_string); 295 | 296 | EXPECT(t2.name == "date"); 297 | EXPECT(t2.prefix == "/"); 298 | EXPECT(t2.delimiter == "/"); 299 | EXPECT(t2.optional); 300 | EXPECT_NOT(t2.repeat); 301 | EXPECT_NOT(t2.partial); 302 | EXPECT_NOT(t2.asterisk); 303 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 304 | EXPECT_NOT(t2.is_string); 305 | 306 | // Testing regex: 307 | 308 | THEN("Only paths with zero, one or two parameters should match") 309 | { 310 | EXPECT_NOT(std::regex_match("/matilda/123/2016-08-20", r)); 311 | EXPECT_NOT(std::regex_match("/users/matilda/2016-08-20/something", r)); 312 | EXPECT_NOT(std::regex_match("/route/something/somethingelse12", r)); 313 | 314 | EXPECT(std::regex_match("", r)); 315 | EXPECT(std::regex_match("/", r)); 316 | EXPECT(std::regex_match("/matilda", r)); 317 | EXPECT(std::regex_match("/2016-08-20", r)); 318 | EXPECT(std::regex_match("/2016-08-20/matilda", r)); 319 | EXPECT(std::regex_match("/matilda/2016-08-20", r)); 320 | } 321 | } 322 | 323 | WHEN("Calling path_to_regex with path '/:test?/users/:date?'") 324 | { 325 | std::regex r = path_to_regex("/:test?/users/:date?", keys); 326 | 327 | // Testing keys: 328 | 329 | EXPECT_NOT(keys.empty()); 330 | EXPECT(keys.size() == 2u); 331 | 332 | Token t1 = keys[0]; 333 | Token t2 = keys[1]; 334 | 335 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 336 | EXPECT(t1.name == "test"); 337 | EXPECT(t1.prefix == "/"); 338 | EXPECT(t1.delimiter == "/"); 339 | EXPECT(t1.optional); 340 | EXPECT_NOT(t1.repeat); 341 | EXPECT_NOT(t1.partial); 342 | EXPECT_NOT(t1.asterisk); 343 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 344 | EXPECT_NOT(t1.is_string); 345 | 346 | EXPECT(t2.name == "date"); 347 | EXPECT(t2.prefix == "/"); 348 | EXPECT(t2.delimiter == "/"); 349 | EXPECT(t2.optional); 350 | EXPECT_NOT(t2.repeat); 351 | EXPECT_NOT(t2.partial); 352 | EXPECT_NOT(t2.asterisk); 353 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 354 | EXPECT_NOT(t2.is_string); 355 | 356 | // Testing regex: 357 | 358 | THEN("Only paths with zero parameters (but containing /users), one parameter (but containing /users), or two parameters (but containing /users) should match") 359 | { 360 | EXPECT_NOT(std::regex_match("/", r)); 361 | EXPECT_NOT(std::regex_match("/users/something/matilda123", r)); 362 | EXPECT_NOT(std::regex_match("/matilda/123/2016-08-20", r)); 363 | EXPECT_NOT(std::regex_match("/users/matilda/2016-08-20/something", r)); 364 | EXPECT_NOT(std::regex_match("/route/users/somethingelse12/123", r)); 365 | EXPECT_NOT(std::regex_match("/123/matilda/users", r)); 366 | 367 | EXPECT(std::regex_match("/users", r)); 368 | EXPECT(std::regex_match("/matilda/users", r)); 369 | EXPECT(std::regex_match("/matilda/users/2016-08-20", r)); 370 | EXPECT(std::regex_match("/users/2016-08-20", r)); 371 | } 372 | } 373 | 374 | WHEN("Calling path_to_regex with path '/:test/:date?'") 375 | { 376 | std::regex r = path_to_regex("/:test/:date?", keys); 377 | 378 | // Testing keys: 379 | 380 | EXPECT_NOT(keys.empty()); 381 | EXPECT(keys.size() == 2u); 382 | 383 | Token t1 = keys[0]; 384 | Token t2 = keys[1]; 385 | 386 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 387 | EXPECT(t1.name == "test"); 388 | EXPECT(t1.prefix == "/"); 389 | EXPECT(t1.delimiter == "/"); 390 | EXPECT_NOT(t1.optional); 391 | EXPECT_NOT(t1.repeat); 392 | EXPECT_NOT(t1.partial); 393 | EXPECT_NOT(t1.asterisk); 394 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 395 | EXPECT_NOT(t1.is_string); 396 | 397 | EXPECT(t2.name == "date"); 398 | EXPECT(t2.prefix == "/"); 399 | EXPECT(t2.delimiter == "/"); 400 | EXPECT(t2.optional); 401 | EXPECT_NOT(t2.repeat); 402 | EXPECT_NOT(t2.partial); 403 | EXPECT_NOT(t2.asterisk); 404 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 405 | EXPECT_NOT(t2.is_string); 406 | 407 | // Testing regex: 408 | 409 | THEN("Only paths with one or two parameters should match") 410 | { 411 | EXPECT_NOT(std::regex_match("/", r)); 412 | EXPECT_NOT(std::regex_match("/users/something/matilda123", r)); 413 | EXPECT_NOT(std::regex_match("/matilda/123/2016-08-20", r)); 414 | EXPECT_NOT(std::regex_match("/test/matilda/2016-08-20/something", r)); 415 | 416 | EXPECT(std::regex_match("/users", r)); 417 | EXPECT(std::regex_match("/matilda/users", r)); 418 | EXPECT(std::regex_match("/matilda/2016-08-20", r)); 419 | } 420 | } 421 | 422 | WHEN("Calling path_to_regex with path '/:test*'") 423 | { 424 | std::regex r = path_to_regex("/:test*", keys); 425 | 426 | // Testing keys: 427 | 428 | EXPECT_NOT(keys.empty()); 429 | EXPECT(keys.size() == 1u); 430 | 431 | Token t = keys[0]; 432 | 433 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 434 | EXPECT(t.name == "test"); 435 | EXPECT(t.prefix == "/"); 436 | EXPECT(t.delimiter == "/"); 437 | EXPECT(t.optional); 438 | EXPECT(t.repeat); 439 | EXPECT_NOT(t.partial); 440 | EXPECT_NOT(t.asterisk); 441 | EXPECT(t.pattern == "[^/]+?"); // or "[^\/]+?" 442 | EXPECT_NOT(t.is_string); 443 | 444 | // Testing regex: 445 | 446 | THEN("Paths with zero or more parameters should match") 447 | { 448 | EXPECT(std::regex_match("/", r)); 449 | EXPECT(std::regex_match("/users", r)); 450 | EXPECT(std::regex_match("/matilda/users", r)); 451 | EXPECT(std::regex_match("/matilda/2016-08-20", r)); 452 | EXPECT(std::regex_match("/users/something/matilda123", r)); 453 | EXPECT(std::regex_match("/test/something/matilda123/2016-08-15/somethingelse/testing", r)); 454 | } 455 | } 456 | 457 | WHEN("Calling path_to_regex with path '/:date/:test*'") 458 | { 459 | std::regex r = path_to_regex("/:date/:test*", keys); 460 | 461 | // Testing keys: 462 | 463 | EXPECT_NOT(keys.empty()); 464 | EXPECT(keys.size() == 2u); 465 | 466 | Token t1 = keys[0]; 467 | Token t2 = keys[1]; 468 | 469 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 470 | EXPECT(t1.name == "date"); 471 | EXPECT(t1.prefix == "/"); 472 | EXPECT(t1.delimiter == "/"); 473 | EXPECT_NOT(t1.optional); 474 | EXPECT_NOT(t1.repeat); 475 | EXPECT_NOT(t1.partial); 476 | EXPECT_NOT(t1.asterisk); 477 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 478 | EXPECT_NOT(t1.is_string); 479 | 480 | EXPECT(t2.name == "test"); 481 | EXPECT(t2.prefix == "/"); 482 | EXPECT(t2.delimiter == "/"); 483 | EXPECT(t2.optional); 484 | EXPECT(t2.repeat); 485 | EXPECT_NOT(t2.partial); 486 | EXPECT_NOT(t2.asterisk); 487 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 488 | EXPECT_NOT(t2.is_string); 489 | 490 | // Testing regex: 491 | 492 | THEN("Paths with one or more parameters should match") 493 | { 494 | EXPECT_NOT(std::regex_match("/", r)); 495 | 496 | EXPECT(std::regex_match("/users", r)); 497 | EXPECT(std::regex_match("/matilda/users", r)); 498 | EXPECT(std::regex_match("/matilda/2016-08-20", r)); 499 | EXPECT(std::regex_match("/users/something/matilda123", r)); 500 | EXPECT(std::regex_match("/test/something/matilda123/2016-08-15/somethingelse/testing", r)); 501 | } 502 | } 503 | 504 | WHEN("Calling path_to_regex with path '/:test+'") 505 | { 506 | std::regex r = path_to_regex("/:test+", keys); 507 | 508 | // Testing keys: 509 | 510 | EXPECT_NOT(keys.empty()); 511 | EXPECT(keys.size() == 1u); 512 | 513 | Token t = keys[0]; 514 | 515 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 516 | EXPECT(t.name == "test"); 517 | EXPECT(t.prefix == "/"); 518 | EXPECT(t.delimiter == "/"); 519 | EXPECT_NOT(t.optional); 520 | EXPECT(t.repeat); 521 | EXPECT_NOT(t.partial); 522 | EXPECT_NOT(t.asterisk); 523 | EXPECT(t.pattern == "[^/]+?"); // or "[^\/]+?" 524 | EXPECT_NOT(t.is_string); 525 | 526 | // Testing regex: 527 | 528 | THEN("Paths with one or more parameters should match") 529 | { 530 | EXPECT_NOT(std::regex_match("", r)); 531 | EXPECT_NOT(std::regex_match("/", r)); 532 | 533 | EXPECT(std::regex_match("/users", r)); 534 | EXPECT(std::regex_match("/matilda/users", r)); 535 | EXPECT(std::regex_match("/matilda/2016-08-20", r)); 536 | EXPECT(std::regex_match("/users/something/matilda123", r)); 537 | EXPECT(std::regex_match("/test/something/matilda123/2016-08-15/somethingelse/testing", r)); 538 | } 539 | } 540 | 541 | WHEN("Calling path_to_regex with path '/:id/:test+'") 542 | { 543 | std::regex r = path_to_regex("/:id/:test+", keys); 544 | 545 | // Testing keys: 546 | 547 | EXPECT_NOT(keys.empty()); 548 | EXPECT(keys.size() == 2u); 549 | 550 | Token t1 = keys[0]; 551 | Token t2 = keys[1]; 552 | 553 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 554 | EXPECT(t1.name == "id"); 555 | EXPECT(t1.prefix == "/"); 556 | EXPECT(t1.delimiter == "/"); 557 | EXPECT_NOT(t1.optional); 558 | EXPECT_NOT(t1.repeat); 559 | EXPECT_NOT(t1.partial); 560 | EXPECT_NOT(t1.asterisk); 561 | EXPECT(t1.pattern == "[^/]+?"); // or "[^\/]+?" 562 | EXPECT_NOT(t1.is_string); 563 | 564 | EXPECT(t2.name == "test"); 565 | EXPECT(t2.prefix == "/"); 566 | EXPECT(t2.delimiter == "/"); 567 | EXPECT_NOT(t2.optional); 568 | EXPECT(t2.repeat); 569 | EXPECT_NOT(t2.partial); 570 | EXPECT_NOT(t2.asterisk); 571 | EXPECT(t2.pattern == "[^/]+?"); // or "[^\/]+?" 572 | EXPECT_NOT(t2.is_string); 573 | 574 | // Testing regex: 575 | 576 | THEN("Paths with two or more parameters should match") 577 | { 578 | EXPECT_NOT(std::regex_match("/", r)); 579 | EXPECT_NOT(std::regex_match("/users", r)); 580 | 581 | EXPECT(std::regex_match("/matilda/users", r)); 582 | EXPECT(std::regex_match("/matilda/2016-08-20", r)); 583 | EXPECT(std::regex_match("/users/something/matilda123", r)); 584 | EXPECT(std::regex_match("/test/something/matilda123/2016-08-15/somethingelse/testing", r)); 585 | } 586 | } 587 | 588 | WHEN("Calling path_to_regex with path '/:test([a-z])+/:id(\\d+)'") 589 | { 590 | std::regex r = path_to_regex("/:test([a-z])+/:id(\\d+)", keys); 591 | 592 | // Testing keys: 593 | 594 | EXPECT_NOT(keys.empty()); 595 | EXPECT(keys.size() == 2u); 596 | 597 | Token t1 = keys[0]; 598 | Token t2 = keys[1]; 599 | 600 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 601 | EXPECT(t1.name == "test"); 602 | EXPECT(t1.prefix == "/"); 603 | EXPECT(t1.delimiter == "/"); 604 | EXPECT_NOT(t1.optional); 605 | EXPECT(t1.repeat); 606 | EXPECT_NOT(t1.partial); 607 | EXPECT_NOT(t1.asterisk); 608 | EXPECT(t1.pattern == "[a-z]"); 609 | EXPECT_NOT(t1.is_string); 610 | 611 | EXPECT(t2.name == "id"); 612 | EXPECT(t2.prefix == "/"); 613 | EXPECT(t2.delimiter == "/"); 614 | EXPECT_NOT(t2.optional); 615 | EXPECT_NOT(t2.repeat); 616 | EXPECT_NOT(t2.partial); 617 | EXPECT_NOT(t2.asterisk); 618 | EXPECT(t2.pattern == "\\d+"); // or \d+ 619 | EXPECT_NOT(t2.is_string); 620 | 621 | // Testing regex: 622 | 623 | THEN("Paths with two parameters (or more of the first parameter) where the first contains one lower case letter and the second contains one or more integers should match") 624 | { 625 | EXPECT_NOT(std::regex_match("/", r)); 626 | EXPECT_NOT(std::regex_match("/m", r)); 627 | EXPECT_NOT(std::regex_match("/molly/123", r)); 628 | EXPECT_NOT(std::regex_match("/m/u", r)); 629 | EXPECT_NOT(std::regex_match("/M/1234", r)); 630 | EXPECT_NOT(std::regex_match("/1234/1234", r)); 631 | EXPECT_NOT(std::regex_match("/4/1234", r)); 632 | EXPECT_NOT(std::regex_match("/m/1234/1234", r)); 633 | EXPECT_NOT(std::regex_match("/b/2016-08-20", r)); 634 | EXPECT_NOT(std::regex_match("/z/", r)); 635 | 636 | EXPECT(std::regex_match("/m/2", r)); 637 | EXPECT(std::regex_match("/z/1234", r)); 638 | EXPECT(std::regex_match("/t/s/1234", r)); 639 | EXPECT(std::regex_match("/a/z/m/2016", r)); 640 | } 641 | } 642 | 643 | WHEN("Calling path_to_regex with path '/:test(\\d+)'") 644 | { 645 | std::regex r = path_to_regex("/:test(\\d+)", keys); 646 | 647 | // Testing keys: 648 | 649 | EXPECT_NOT(keys.empty()); 650 | EXPECT(keys.size() == 1u); 651 | 652 | Token t = keys[0]; 653 | 654 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 655 | EXPECT(t.name == "test"); 656 | EXPECT(t.prefix == "/"); 657 | EXPECT(t.delimiter == "/"); 658 | EXPECT_NOT(t.optional); 659 | EXPECT_NOT(t.repeat); 660 | EXPECT_NOT(t.partial); 661 | EXPECT_NOT(t.asterisk); 662 | EXPECT(t.pattern == "\\d+"); // or "\d+" 663 | EXPECT_NOT(t.is_string); 664 | 665 | // Testing regex: 666 | 667 | THEN("Paths with one parameter that contains one or more integers should match") 668 | { 669 | EXPECT_NOT(std::regex_match("", r)); 670 | EXPECT_NOT(std::regex_match("/", r)); 671 | EXPECT_NOT(std::regex_match("/users", r)); 672 | EXPECT_NOT(std::regex_match("/12/25", r)); 673 | 674 | EXPECT(std::regex_match("/5", r)); 675 | EXPECT(std::regex_match("/2016", r)); 676 | EXPECT(std::regex_match("/1234563728192938", r)); 677 | } 678 | } 679 | 680 | // TODO 681 | WHEN("Calling path_to_regex with path '/:test([a-z]+)'") 682 | { 683 | // Everything works as expected when is case sensitive 684 | // But when setting the icase constant (ignore case) it doesn't 685 | 686 | /* Basic example for testing icase: 687 | 688 | std::regex test_regex("[a-z]+"); 689 | EXPECT_NOT(std::regex_match("A", test_regex)); 690 | EXPECT_NOT(std::regex_match("B", test_regex)); 691 | EXPECT(std::regex_match("a", test_regex)); 692 | EXPECT(std::regex_match("b", test_regex)); 693 | 694 | std::regex test_regex_2("[a-z]+", std::regex_constants::ECMAScript | std::regex_constants::icase); 695 | EXPECT(std::regex_match("A", test_regex_2)); // OK 696 | EXPECT(std::regex_match("B", test_regex_2)); // FAILS 697 | EXPECT(std::regex_match("C", test_regex_2)); // FAILS 698 | EXPECT(std::regex_match("a", test_regex_2)); 699 | EXPECT(std::regex_match("b", test_regex_2)); 700 | 701 | // Basic example for testing icase end */ 702 | 703 | // Not case sensitive (default) - does not work as expected: 704 | std::regex r = path_to_regex("/:test([a-z]+)", keys); 705 | 706 | // Testing keys: 707 | 708 | EXPECT_NOT(keys.empty()); 709 | EXPECT(keys.size() == 1u); 710 | 711 | Token t = keys[0]; 712 | 713 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 714 | EXPECT(t.name == "test"); 715 | EXPECT(t.prefix == "/"); 716 | EXPECT(t.delimiter == "/"); 717 | EXPECT_NOT(t.optional); 718 | EXPECT_NOT(t.repeat); 719 | EXPECT_NOT(t.partial); 720 | EXPECT_NOT(t.asterisk); 721 | EXPECT(t.pattern == "[a-z]+"); 722 | EXPECT_NOT(t.is_string); 723 | 724 | // Testing regex: 725 | 726 | THEN("Paths with one parameter containing one or more lower case letters should match") 727 | { 728 | EXPECT_NOT(std::regex_match("", r)); 729 | EXPECT_NOT(std::regex_match("/", r)); 730 | EXPECT_NOT(std::regex_match("/matilda/users", r)); 731 | EXPECT_NOT(std::regex_match("/1", r)); 732 | EXPECT_NOT(std::regex_match("/4321", r)); 733 | 734 | // Default is not case sensitive 735 | EXPECT(std::regex_match("/A", r)); // OK WHEN NOT CASE SENSITIVE (icase set) 736 | EXPECT(std::regex_match("/B", r)); // FAILS WHEN NOT CASE SENSITIVE (icase set) 737 | EXPECT(std::regex_match("/Z", r)); // FAILS WHEN NOT CASE SENSITIVE (icase set) 738 | EXPECT(std::regex_match("/Matilda", r)); // FAILS WHEN NOT CASE SENSITIVE (icase set) 739 | 740 | EXPECT(std::regex_match("/a", r)); 741 | EXPECT(std::regex_match("/users", r)); 742 | EXPECT(std::regex_match("/somethingelseentirely", r)); 743 | } 744 | } 745 | 746 | WHEN("Calling path_to_regex with path '/:test/' (endsWithSlash)") 747 | { 748 | std::regex r = path_to_regex("/:test/", keys); 749 | 750 | THEN("The trailing slash will be ignored in non-strict mode (strict is false)") 751 | { 752 | EXPECT(std::regex_match("/123", r)); 753 | } 754 | } 755 | 756 | WHEN("Calling path_to_regex with path '/:test/:id(\\d+)'") 757 | { 758 | std::regex r = path_to_regex("/:test/:id(\\d+)", keys); 759 | 760 | // Testing keys: 761 | 762 | EXPECT_NOT(keys.empty()); 763 | EXPECT(keys.size() == 2u); 764 | 765 | Token t1 = keys[0]; 766 | Token t2 = keys[1]; 767 | 768 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 769 | EXPECT(t1.name == "test"); 770 | EXPECT(t1.prefix == "/"); 771 | EXPECT(t1.delimiter == "/"); 772 | EXPECT_NOT(t1.optional); 773 | EXPECT_NOT(t1.repeat); 774 | EXPECT_NOT(t1.partial); 775 | EXPECT_NOT(t1.asterisk); 776 | EXPECT(t1.pattern == "[^/]+?"); // or [^\/]+? 777 | EXPECT_NOT(t1.is_string); 778 | 779 | EXPECT(t2.name == "id"); 780 | EXPECT(t2.prefix == "/"); 781 | EXPECT(t2.delimiter == "/"); 782 | EXPECT_NOT(t2.optional); 783 | EXPECT_NOT(t2.repeat); 784 | EXPECT_NOT(t2.partial); 785 | EXPECT_NOT(t2.asterisk); 786 | EXPECT(t2.pattern == "\\d+"); // or \d+ 787 | EXPECT_NOT(t2.is_string); 788 | 789 | // Testing regex: 790 | 791 | THEN("Paths with two parameters where the second contains one or more integers should match") 792 | { 793 | EXPECT_NOT(std::regex_match("/", r)); 794 | EXPECT_NOT(std::regex_match("/m", r)); 795 | EXPECT_NOT(std::regex_match("/molly", r)); 796 | EXPECT_NOT(std::regex_match("/molly/", r)); 797 | EXPECT_NOT(std::regex_match("/molly1234/users", r)); 798 | EXPECT_NOT(std::regex_match("/1234", r)); 799 | EXPECT_NOT(std::regex_match("/m/1234/1234", r)); 800 | EXPECT_NOT(std::regex_match("/users/molly/2016", r)); 801 | 802 | EXPECT(std::regex_match("/m/0", r)); 803 | EXPECT(std::regex_match("/molly/123", r)); 804 | EXPECT(std::regex_match("/1234/1234", r)); 805 | EXPECT(std::regex_match("/USERSusers1520!/1234", r)); 806 | EXPECT(std::regex_match("/t/0192830", r)); 807 | EXPECT(std::regex_match("/panel/2016", r)); 808 | } 809 | } 810 | 811 | WHEN("Calling path_to_regex with path '/(.*)'") 812 | { 813 | std::regex r = path_to_regex("/(.*)", keys); 814 | 815 | // Testing keys: 816 | 817 | EXPECT_NOT(keys.empty()); 818 | EXPECT(keys.size() == 1u); 819 | 820 | Token t = keys[0]; 821 | 822 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 823 | EXPECT(t.name == "0"); 824 | EXPECT(t.prefix == "/"); 825 | EXPECT(t.delimiter == "/"); 826 | EXPECT_NOT(t.optional); 827 | EXPECT_NOT(t.repeat); 828 | EXPECT_NOT(t.partial); 829 | EXPECT_NOT(t.asterisk); 830 | EXPECT(t.pattern == ".*"); 831 | EXPECT_NOT(t.is_string); 832 | 833 | // Testing regex: 834 | 835 | THEN("Paths with one parameter containing zero or more characters should match") 836 | { 837 | EXPECT_NOT(std::regex_match("", r)); 838 | 839 | EXPECT(std::regex_match("/matilda/users", r)); // Because of .*: Any character allowed, incl. / 840 | EXPECT(std::regex_match("/", r)); 841 | EXPECT(std::regex_match("/Z", r)); 842 | EXPECT(std::regex_match("/A", r)); 843 | EXPECT(std::regex_match("/B132ab", r)); 844 | EXPECT(std::regex_match("/1", r)); 845 | EXPECT(std::regex_match("/4321", r)); 846 | } 847 | } 848 | 849 | // TODO 850 | WHEN("Calling path_to_regex with path '/users/([a-z]+)/(.?)'") 851 | { 852 | std::regex r = path_to_regex("/users/([a-z]+)/(.?)", keys); 853 | 854 | // Testing keys: 855 | 856 | EXPECT_NOT(keys.empty()); 857 | EXPECT(keys.size() == 2u); 858 | 859 | Token t1 = keys[0]; 860 | Token t2 = keys[1]; 861 | 862 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 863 | EXPECT(t1.name == "0"); 864 | EXPECT(t1.prefix == "/"); 865 | EXPECT(t1.delimiter == "/"); 866 | EXPECT_NOT(t1.optional); 867 | EXPECT_NOT(t1.repeat); 868 | EXPECT_NOT(t1.partial); 869 | EXPECT_NOT(t1.asterisk); 870 | EXPECT(t1.pattern == "[a-z]+"); 871 | EXPECT_NOT(t1.is_string); 872 | 873 | EXPECT(t2.name == "1"); 874 | EXPECT(t2.prefix == "/"); 875 | EXPECT(t2.delimiter == "/"); 876 | EXPECT_NOT(t2.optional); 877 | EXPECT_NOT(t2.repeat); 878 | EXPECT_NOT(t2.partial); 879 | EXPECT_NOT(t2.asterisk); 880 | EXPECT(t2.pattern == ".?"); 881 | EXPECT_NOT(t2.is_string); 882 | 883 | // Testing regex: 884 | 885 | THEN("Paths with three elements, where the first parameter contains one or more lower case letters and the second parameter contains zero or one character, should match") 886 | { 887 | EXPECT_NOT(std::regex_match("/", r)); 888 | EXPECT_NOT(std::regex_match("/users", r)); 889 | EXPECT_NOT(std::regex_match("/users/a/ab", r)); 890 | EXPECT_NOT(std::regex_match("/user/users", r)); 891 | EXPECT_NOT(std::regex_match("/users/1234", r)); 892 | 893 | // TODO: /A is allowed (same error as above) 894 | // While /B is not allowed 895 | // Default (is the case here) is that the regex is not case sensitive (sensitive is false) 896 | EXPECT(std::regex_match("/users/A/a", r)); 897 | EXPECT(std::regex_match("/users/B/a", r)); 898 | 899 | EXPECT_NOT(std::regex_match("/m/abcd/2", r)); 900 | EXPECT_NOT(std::regex_match("/users/molly/2016", r)); 901 | EXPECT_NOT(std::regex_match("/users/abba1520!/t", r)); 902 | 903 | EXPECT(std::regex_match("/users/a/0", r)); 904 | EXPECT(std::regex_match("/users/ab/a", r)); 905 | EXPECT(std::regex_match("/users/saab/", r)); 906 | EXPECT(std::regex_match("/users/some/w", r)); 907 | EXPECT(std::regex_match("/users/p/2", r)); 908 | } 909 | } 910 | 911 | WHEN("Calling path_to_regex with path '/*'") 912 | { 913 | std::regex r = path_to_regex("/*", keys); 914 | 915 | // Testing keys: 916 | 917 | EXPECT_NOT(keys.empty()); 918 | EXPECT(keys.size() == 1u); 919 | 920 | Token t = keys[0]; 921 | 922 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 923 | EXPECT(t.name == "0"); 924 | EXPECT(t.prefix == "/"); 925 | EXPECT(t.delimiter == "/"); 926 | EXPECT_NOT(t.optional); 927 | EXPECT_NOT(t.repeat); 928 | EXPECT_NOT(t.partial); 929 | EXPECT(t.asterisk); 930 | EXPECT(t.pattern == ".*"); 931 | EXPECT_NOT(t.is_string); 932 | 933 | // Testing regex: 934 | 935 | THEN("Paths with one parameter containing zero or more characters should match") 936 | { 937 | EXPECT_NOT(std::regex_match("", r)); 938 | 939 | EXPECT(std::regex_match("/matilda/users", r)); // Because of .*: Any character allowed, incl. / 940 | EXPECT(std::regex_match("/", r)); 941 | EXPECT(std::regex_match("/Z", r)); 942 | EXPECT(std::regex_match("/A", r)); 943 | EXPECT(std::regex_match("/B132ab", r)); 944 | EXPECT(std::regex_match("/1", r)); 945 | EXPECT(std::regex_match("/4321", r)); 946 | } 947 | } 948 | 949 | WHEN("Calling path_to_regex with path '/:id(\\d+)/:date/*'") 950 | { 951 | std::regex r = path_to_regex("/:id(\\d+)/:date/*", keys); 952 | 953 | // Testing keys: 954 | 955 | EXPECT_NOT(keys.empty()); 956 | EXPECT(keys.size() == 3u); 957 | 958 | Token t1 = keys[0]; 959 | Token t2 = keys[1]; 960 | Token t3 = keys[2]; 961 | 962 | // Tested when testing parse-method really, except keys don't contain Tokens where is_string is true 963 | EXPECT(t1.name == "id"); 964 | EXPECT(t1.prefix == "/"); 965 | EXPECT(t1.delimiter == "/"); 966 | EXPECT_NOT(t1.optional); 967 | EXPECT_NOT(t1.repeat); 968 | EXPECT_NOT(t1.partial); 969 | EXPECT_NOT(t1.asterisk); 970 | EXPECT(t1.pattern == "\\d+"); 971 | EXPECT_NOT(t1.is_string); 972 | 973 | EXPECT(t2.name == "date"); 974 | EXPECT(t2.prefix == "/"); 975 | EXPECT(t2.delimiter == "/"); 976 | EXPECT_NOT(t2.optional); 977 | EXPECT_NOT(t2.repeat); 978 | EXPECT_NOT(t2.partial); 979 | EXPECT_NOT(t2.asterisk); 980 | EXPECT(t2.pattern == "[^/]+?"); // or [^\/]+? 981 | EXPECT_NOT(t2.is_string); 982 | 983 | EXPECT(t3.name == "0"); 984 | EXPECT(t3.prefix == "/"); 985 | EXPECT(t3.delimiter == "/"); 986 | EXPECT_NOT(t3.optional); 987 | EXPECT_NOT(t3.repeat); 988 | EXPECT_NOT(t3.partial); 989 | EXPECT(t3.asterisk); 990 | EXPECT(t3.pattern == ".*"); 991 | EXPECT_NOT(t3.is_string); 992 | 993 | // Testing regex: 994 | 995 | THEN("Paths with three parameters, where the first parameter contains one or more integers and the third contains zero or more characters, should match") 996 | { 997 | EXPECT_NOT(std::regex_match("", r)); 998 | EXPECT_NOT(std::regex_match("/b/optional-text/optional", r)); 999 | EXPECT_NOT(std::regex_match("/1/matilda", r)); 1000 | EXPECT_NOT(std::regex_match("/172!optional-text/abcd2918230", r)); 1001 | 1002 | EXPECT(std::regex_match("/0/optional-text/", r)); 1003 | EXPECT(std::regex_match("/0/optional-text/1", r)); 1004 | EXPECT(std::regex_match("/123/optional-text132/45", r)); 1005 | EXPECT(std::regex_match("/2918293/172!optional-text/abcd2918230", r)); 1006 | EXPECT(std::regex_match("/2/143/", r)); 1007 | EXPECT(std::regex_match("/2/143/something", r)); 1008 | EXPECT(std::regex_match("/2/143/something/somethingelse/and/so/on", r)); // Because of *: Any character allowed, incl. / 1009 | } 1010 | } 1011 | } 1012 | } // < SCENARIO (no options) 1013 | }; 1014 | 1015 | int main(int argc, char * argv[]) 1016 | { 1017 | printf("Running tests of path_to_regex with no options...\n"); 1018 | 1019 | int res = lest::run(test_path_to_regex_no_options, argc, argv); 1020 | 1021 | printf("Path_to_regex-tests (with no options) completed.\n"); 1022 | 1023 | return res; 1024 | } 1025 | --------------------------------------------------------------------------------