[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: cpp\n\ncompiler:\n    - gcc\n    - clang\n\nbranches:\n  only:\n    - master\n    - dev\n\nbefore_script:\n    - mkdir build\n    - cd build\n    - cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..\n    - phantomjs --webdriver=7777 --webdriver-loglevel=WARN &\n    - npm install http-server -g\n    - http-server ./test/pages --silent &\n\nscript:\n    - cmake --build .\n    - ctest -V\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.8)\nproject(webdriverxx)\n\nif (NOT MSVC)\n\tinclude(CheckCXXCompilerFlag)\n\tCHECK_CXX_COMPILER_FLAG(\"-std=c++11\" COMPILER_SUPPORTS_CXX11)\n\tCHECK_CXX_COMPILER_FLAG(\"-std=c++0x\" COMPILER_SUPPORTS_CXX0X)\n\tif(COMPILER_SUPPORTS_CXX11)\n\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11\")\n\telseif(COMPILER_SUPPORTS_CXX0X)\n\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++0x\")\n\tendif()\nendif()\n\nenable_testing()\n\ninclude_directories(include)\nadd_subdirectory(test)\n\ninstall(DIRECTORY\n\t\t${CMAKE_SOURCE_DIR}/include/\n\t\tDESTINATION /usr/local/include/${PROJECT_NAME}\n\t\tFILES_MATCHING PATTERN \"*\")\n\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Sergey Kogan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "\n# Webdriver++\n\nA C++ client library for [Selenium Webdriver](http://www.seleniumhq.org/).\nYou can use this library in any C++ project.\n\n\n## Install\n\n```bash\nmkdir build\ncd build && cmake ..\nsudo make && sudo make install\n```\n\n## A quick example\n\n##### Dependencies\nYou need to download and run selenium-server before run this example.\nhttp://www.seleniumhq.org/download/\n\n```cpp\n#include <webdriverxx/webdriverxx.h>\nusing namespace webdriverxx;\n\nint main() {\n    WebDriver firefox = Start(Firefox());\n    firefox\n        .Navigate(\"http://google.com\")\n        .FindElement(ByCss(\"input[name=q]\"))\n        .SendKeys(\"Hello, world!\")\n        .Submit();\n    return 0;    \n}\n```\n\n## Features\n\n- Chainable commands.\n- Value-like objects compatible with STL containers.\n- Header-only.\n- Lightweight dependencies:\n    - [libcurl](http://curl.haxx.se/libcurl/),\n    - [picojson](https://github.com/kazuho/picojson).\n- Can be used with any testing framework.\n- Linux, Mac and Windows.\n- clang (3.4), GCC (4.6) and Visual Studio (2010).\n\n## More examples\n\n`#include <webdriverxx/webdriver.h>` and `using namespace webdriverxx`\nare assumed in all examples.\n\n### Start browser\n\n```cpp\n#include <webdriverxx/browsers/firefox.h>\n\nWebDriver ff = Start(Firefox());\n```\n\n```cpp\n#include <webdriverxx/browsers/chrome.h>\n\nWebDriver gc = Start(Chrome());\n```\n\n```cpp\n#include <webdriverxx/browsers/ie.h>\n\nWebDriver ie = Start(InternetExplorer());\n```\n\n### Use proxy\n\n```cpp\nWebDriver ie = Start(InternetExplorer().SetProxy(\n\tSocksProxy(\"127.0.0.1:3128\")\n\t\t.SetUsername(\"user\")\n\t\t.SetPassword(\"12345\")\n\t\t.SetNoProxyFor(\"custom.host\")\n\t));\n```\n\n```cpp\nWebDriver ff = Start(Firefox().SetProxy(DirectConnection()));\n```\n\n### Navigate browser\n\n```cpp\ndriver\n\t.Navigate(\"http://facebook.com\")\n\t.Navigate(\"http://twitter.com\")\n\t.Back()\n\t.Forward()\n\t.Refresh();\n```\n\n### Find elements\n\n```cpp\n// Throws exception if no match is found in the document\nElement menu = driver.FindElement(ById(\"menu\"));\n\n// Returns empty vector if no such elements\n// The search is performed inside the menu element\nstd::vector<Element> items = menu.FindElements(ByClass(\"item\"));\n```\n\n### Send keyboard input\n\n```cpp\n// Sends text input or a shortcut to the element\ndriver.FindElement(ByTag(\"input\")).SendKeys(\"Hello, world!\");\n\n// Sends text input or a shortcut to the active window\ndriver.SendKeys(Shortcut() << keys::Control << \"t\");\n```\n\n### Execute Javascript\n\n```cpp\n// Simple script, no parameters\ndriver.Execute(\"console.log('Hi there!')\");\n\n// A script with one parameter\ndriver.Execute(\"document.title = arguments[0]\", JsArgs() << \"Cowabunga!\");\n\n// A script with more than one parameter\ndriver.Execute(\"document.title = arguments[0] + '-' + arguments[1]\",\n\t\tJsArgs() << \"Beep\" << \"beep\");\n\n// Arrays or containers can also be used as parameters\nconst char* ss[] = { \"Yabba\", \"dabba\", \"doo\" };\ndriver.Execute(\"document.title = arguments[0].join(', ')\", JsArgs() << ss);\n\n// Even an Element can be passed to a script\nauto element = driver.FindElement(ByTag(\"input\"));\ndriver.Execute(\"arguments[0].value = 'That was nuts!'\", JsArgs() << element);\n```\n\n### Get something from Javascript\n\n```cpp\n// Scalar types\nauto title = driver.Eval<std::string>(\"return document.title\")\nauto number = driver.Eval<int>(\"return 123\");\nauto another_number = driver.Eval<double>(\"return 123.5\");\nauto flag = driver.Eval<bool>(\"return true\");\n\n// Containers (all std::back_inserter compatible)\nstd::vector<std::string> v = driver.Eval<std::vector<std::string>>(\n\t\t\"return [ 'abc', 'def' ]\"\n\t\t);\n\n// Elements!\nElement document_element = driver.Eval<Element>(\"return document.documentElement\");\n```\n\n### [Wait implicitly](http://selenium-python.readthedocs.org/en/latest/waits.html) for asynchronous operations\n\n```cpp\ndriver.SetImplicitTimeoutMs(5000);\n\n// Should poll the DOM for 5 seconds before throwing an exception.\nauto element = driver.FindElement(ByName(\"async_element\"));\n```\n\n### [Wait explicitly](http://selenium-python.readthedocs.org/en/latest/waits.html) for asynchronous operations\n\n```cpp\n#include <webdriverxx/wait.h>\n\nauto find_element = [&]{ return driver.FindElement(ById(\"async_element\")); };\nElement element = WaitForValue(find_element);\n```\n\n```cpp\n#include <webdriverxx/wait.h>\n\nauto element_is_selected = [&]{\n\treturn driver.FindElement(ById(\"asynchronously_loaded_element\")).IsSelected();\n\t};\nWaitUntil(element_is_selected);\n```\n\n### Use matchers from [Google Mock](https://code.google.com/p/googlemock/) for waiting\n\n```cpp\n#define WEBDRIVERXX_ENABLE_GMOCK_MATCHERS\n#include <webdriverxx/wait_match.h>\n\ndriver.Navigate(\"http://initial_url.host.net\");\nauto url = [&]{ return driver.GetUrl(); };\nusing namespace ::testing;\nauto final_url = WaitForMatch(url, HasSubstr(\"some_magic\"));\n```\n\n### Testing with real browsers\n\nPrerequisites:\n- [Selenium Server](http://www.seleniumhq.org/download/)\n\n```bash\nselenium-server -p 4444 &\n./webdriverxx --browser=<firefox|chrome|...>\n```\n\n## Advanced topics\n\n### Unicode\n\nThe library is designed to be encoding-agnostic. It doesn't make\nany assumptions about encodings. All strings are transferred\nas is, without modifications.\n\nThe WebDriver protocol is based on UTF-8, so all strings passed\nto the library/received from the library should be/are encoded\nusing UTF-8.\n\n### Thread safety\n\n- Webdriver++ objects are not thread safe. It is not safe to use\nneither any single object nor different objects obtained from a single WebDriver\nconcurrently without synchronization. On the other side, Webdriver++ objects\ndon't use global variables so it is OK to use different instances of WebDriver\nin different threads.\n\n- The CURL library should be explicitly initialized if several WebDrivers are used from\nmultiple threads. Call `curl_global_init(CURL_GLOBAL_ALL);` from `<curl/curl.h>`\nonce per process before using this library.\n\n### Use common capabilities for all browsers\n\n```cpp\nCapabilities common;\ncommon.SetProxy(DirectConnection());\nauto ff = Start(Firefox(common));\nauto ie = Start(InternetExplorer(common));\nauto gc = Start(Chrome(common));\n```\n\n### Use required capabilities\n\n```cpp\nCapabilities required = /* ... */;\nauto ff = Start(Firefox(), required);\n```\n\n### Use custom URL for connecting to WebDriver\n\n```cpp\nconst char* url = \"http://localhost:4444/wd/hub/\";\n\nauto ff = Start(Firefox(), url);\n\n// or\nauto ff = Start(Firefox(), Capabilities() /* required */, url);\n```\n\n### Transfer objects between C++ and Javascript\n\n```cpp\nnamespace custom {\n\nstruct Object {\n\tstd::string string;\n\tint number;\n};\n\n// Conversion functions should be in the same namespace as the object\npicojson::value CustomToJson(const Object& value) {\n\treturn JsonObject()\n\t\t.Set(\"string\", value.string)\n\t\t.Set(\"number\", value.number);\n}\n\nvoid CustomFromJson(const picojson::value& value, Object& result) {\n\tassert(value.is<picojson::object>());\n\tresult.string = FromJson<std::string>(value.get(\"string\"));\n\tresult.number = FromJson<int>(value.get(\"number\"));\n}\n\n} // namespace custom\n\ncustom::Object o1 = { \"abc\", 123 };\ndriver.Execute(\"var o1 = arguments[0];\", JsArgs() << o1);\ncustom::Object o1_copy = driver.Eval<custom::Object>(\"return o1\");\ncustom::Object o2 = driver.Eval<custom::Object>(\"return { string: 'abc', number: 123 }\");\n```\n\n--------------------\n\nCopyright &copy; 2014 Sergey Kogan.\nLicensed under [The MIT license](https://github.com/sekogan/webdriverxx/blob/master/LICENSE).\n"
  },
  {
    "path": "include/webdriverxx/browsers/chrome.h",
    "content": "#ifndef WEBDRIVERXX_BROWSERS_CHROME_H\n#define WEBDRIVERXX_BROWSERS_CHROME_H\n\n#include \"../capabilities.h\"\n\nnamespace webdriverxx {\nnamespace chrome {\n\nstruct PerfLoggingPrefs : JsonObject {\n\tWEBDRIVERXX_PROPERTIES_BEGIN(PerfLoggingPrefs)\n\tWEBDRIVERXX_PROPERTY(EnableNetwork, \"enableNetwork\", bool)\n\tWEBDRIVERXX_PROPERTY(enablePage, \"enablePage\", bool)\n\tWEBDRIVERXX_PROPERTY(enableTimeline, \"enableTimeline\", bool)\n\tWEBDRIVERXX_PROPERTY(tracingCategories, \"tracingCategories\", std::string)\n\tWEBDRIVERXX_PROPERTY(bufferUsageReportingInterval, \"bufferUsageReportingInterval\", int)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\n} // namespace chrome\n\nstruct Chrome : Capabilities { // copyable\n\tChrome(const Capabilities& defaults = Capabilities())\n\t\t: Capabilities(defaults) {\n\t\tSetBrowserName(browser::Chrome);\n\t\tSetVersion(\"\");\n\t\tSetPlatform(platform::Any);\n\t}\n\n\t// See https://sites.google.com/a/chromium.org/chromedriver/capabilities for details\n\tWEBDRIVERXX_PROPERTIES_BEGIN(Chrome)\n\tWEBDRIVERXX_PROPERTY(LoggingPrefs, \"loggingPrefs\", LoggingPrefs)\n\tWEBDRIVERXX_PROPERTY(Args, \"args\", std::vector<std::string>)\n\tWEBDRIVERXX_PROPERTY(Binary, \"binary\", std::string)\n\t// Each extension is a base64-encoded .crx file\n\tWEBDRIVERXX_PROPERTY(Extensions, \"extensions\", std::vector<std::string>)\n\tWEBDRIVERXX_PROPERTY(LocalState, \"localState\", JsonObject)\n\tWEBDRIVERXX_PROPERTY(Prefs, \"prefs\", JsonObject)\n\tWEBDRIVERXX_PROPERTY(Detach, \"detach\", bool)\n\tWEBDRIVERXX_PROPERTY(DebuggerAddress, \"debuggerAddress\", std::string)\n\tWEBDRIVERXX_PROPERTY(ExcludeSwitches, \"excludeSwitches\", std::vector<std::string>)\n\tWEBDRIVERXX_PROPERTY(MinidumpPath, \"minidumpPath\", std::string)\n\tWEBDRIVERXX_PROPERTY(MobileEmulation, \"mobileEmulation\", JsonObject)\n\tWEBDRIVERXX_PROPERTY(PerfLoggingPrefs, \"perfLoggingPrefs\", chrome::PerfLoggingPrefs)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/browsers/firefox.h",
    "content": "#ifndef WEBDRIVERXX_BROWSERS_FIREFOX_H\n#define WEBDRIVERXX_BROWSERS_FIREFOX_H\n\n#include \"../capabilities.h\"\n\nnamespace webdriverxx {\n\nstruct Firefox : Capabilities { // copyable\n\tFirefox(const Capabilities& defaults = Capabilities())\n\t\t: Capabilities(defaults) {\n\t\tSetBrowserName(browser::Firefox);\n\t\tSetVersion(\"\");\n\t\tSetPlatform(platform::Any);\n\t}\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(Firefox)\n\t// Profile is a profile folder, zipped and base64 encoded.\n\t// TODO: add FirefoxProfile \n\tWEBDRIVERXX_PROPERTY(Profile, \"firefox_profile\", std::string)\n\tWEBDRIVERXX_PROPERTY(LoggingPrefs, \"loggingPrefs\", LoggingPrefs)\n\tWEBDRIVERXX_PROPERTY(FirefoxBinary, \"firefox_binary\", std::string)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/browsers/ie.h",
    "content": "#ifndef WEBDRIVERXX_BROWSERS_IE_H\n#define WEBDRIVERXX_BROWSERS_IE_H\n\n#include \"../capabilities.h\"\n\nnamespace webdriverxx {\nnamespace ie {\n\nnamespace log_level {\ntypedef std::string Value;\ntypedef const char* const ConstValue;\nConstValue Trace = \"TRACE\";\nConstValue Debug = \"DEBUG\";\nConstValue Info = \"INFO\";\nConstValue Warning = \"WARN\";\nConstValue Error = \"ERROR\";\nConstValue Fatal = \"FATAL\";\n} // namespace log_level\n\n} // namespace ie\n\nstruct InternetExplorer : Capabilities { // copyable\n\tInternetExplorer(const Capabilities& defaults = Capabilities())\n\t\t: Capabilities(defaults) {\n\t\tSetBrowserName(browser::InternetExplorer);\n\t\tSetVersion(\"\");\n\t\tSetPlatform(platform::Any);\n\t}\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(InternetExplorer)\n\tWEBDRIVERXX_PROPERTY(SkipProtectedModeCheck, \"ignoreProtectedModeSettings\", bool)\n\tWEBDRIVERXX_PROPERTY(IgnoreZoomSetting, \"ignoreZoomSetting\", bool)\n\tWEBDRIVERXX_PROPERTY(InitialUrl, \"initialBrowserUrl\", std::string)\n\tWEBDRIVERXX_PROPERTY(EnablePersistentHover, \"enablePersistentHover\", bool)\n\tWEBDRIVERXX_PROPERTY(EnableElementCacheCleanup, \"enableElementCacheCleanup\", bool)\n\tWEBDRIVERXX_PROPERTY(RequireWindowFocus, \"requireWindowFocus\", bool)\n\tWEBDRIVERXX_PROPERTY(BrowserAttachTimeoutMs, \"browserAttachTimeout\", int)\n\tWEBDRIVERXX_PROPERTY(ForceCreateProcessApi, \"ie.forceCreateProcessApi\", bool)\n\tWEBDRIVERXX_PROPERTY(CommandLineSwitches, \"ie.browserCommandLineSwitches\", std::string)\n\tWEBDRIVERXX_PROPERTY(UsePerProcessProxy, \"ie.usePerProcessProxy\", bool)\n\tWEBDRIVERXX_PROPERTY(EnsureCleanSession, \"ie.ensureCleanSession\", bool)\n\tWEBDRIVERXX_PROPERTY(LogFile, \"logFile\", std::string)\n\tWEBDRIVERXX_PROPERTY(LogLevel, \"logLevel\", ie::log_level::Value)\n\tWEBDRIVERXX_PROPERTY(Host, \"host\", std::string)\n\tWEBDRIVERXX_PROPERTY(ExtractPath, \"extractPath\", std::string)\n\tWEBDRIVERXX_PROPERTY(Silent, \"silent\", bool)\n\tWEBDRIVERXX_PROPERTY(ProxyByServer, \"ie.setProxyByServer\", bool)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/browsers/phantom.h",
    "content": "#ifndef WEBDRIVERXX_BROWSERS_PHANTOM_H\n#define WEBDRIVERXX_BROWSERS_PHANTOM_H\n\n#include \"../capabilities.h\"\n\nnamespace webdriverxx {\n\nstruct Phantom : Capabilities { // copyable\n    Phantom(const Capabilities& defaults = Capabilities())\n\t\t: Capabilities(defaults) {\n\t\tSetBrowserName(browser::Phantom);\n\t\tSetVersion(\"\");\n\t\tSetPlatform(platform::Any);\n\t}\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(Phantom)\n\t// Profile is a profile folder, zipped and base64 encoded.\n\tWEBDRIVERXX_PROPERTY(LoggingPrefs, \"loggingPrefs\", LoggingPrefs)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/by.h",
    "content": "#ifndef WEBDRIVERXX_BY_H\n#define WEBDRIVERXX_BY_H\n\n#include <string>\n\nnamespace webdriverxx {\n\nclass By { // copyable\npublic:\n\tBy(const std::string& strategy, const std::string& value)\n\t\t: strategy_(strategy)\n\t\t, value_(value)\n\t{}\n\n\tconst std::string& GetStrategy() const {\n\t\treturn strategy_;\n\t}\n\n\tconst std::string& GetValue() const {\n\t\treturn value_;\n\t}\n\nprivate:\n\tstd::string strategy_;\n\tstd::string value_;\n};\n\ninline By ByClass(const std::string& value) {\n\treturn By(\"class name\", value);\n}\n\ninline By ByCss(const std::string& value) {\n\treturn By(\"css selector\", value);\n}\n\ninline By ById(const std::string& value) {\n\treturn By(\"id\", value);\n}\n\ninline By ByName(const std::string& value) {\n\treturn By(\"name\", value);\n}\n\ninline By ByLinkText(const std::string& value) {\n\treturn By(\"link text\", value);\n}\n\ninline By ByPartialLinkText(const std::string& value) {\n\treturn By(\"partial link text\", value);\n}\n\ninline By ByTag(const std::string& value) {\n\treturn By(\"tag name\", value);\n}\n\ninline By ByXPath(const std::string& value) {\n\treturn By(\"xpath\", value);\n}\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/capabilities.h",
    "content": "#ifndef WEBDRIVERXX_CAPABILITIES_H\n#define WEBDRIVERXX_CAPABILITIES_H\n\n#include \"conversions.h\"\n#include \"picojson.h\"\n#include <string>\n\nnamespace webdriverxx {\n\nnamespace browser {\ntypedef std::string Value;\ntypedef const char* const ConstValue;\nConstValue Android = \"android\";\nConstValue Chrome = \"chrome\";\nConstValue Firefox = \"firefox\";\nConstValue HtmlUnit = \"htmlunit\";\nConstValue InternetExplorer = \"internet explorer\";\nConstValue IPhone = \"iPhone\";\nConstValue IPad = \"iPad\";\nConstValue Mock = \"mock\";\nConstValue Opera = \"opera\";\nConstValue Safari = \"safari\";\nConstValue Phantom = \"phantomjs\";\n} // namespace browser\n\nnamespace platform {\ntypedef std::string Value;\ntypedef const char* const ConstValue;\nConstValue Any = \"ANY\";\nConstValue Windows = \"WINDOWS\";\nConstValue Xp = \"XP\";\nConstValue Vista = \"VISTA\";\nConstValue Mac = \"MAC\";\nConstValue Linux = \"LINUX\";\nConstValue Unix = \"UNIX\";\nConstValue Android = \"ANDROID\";\n} // namespace platform\n\nnamespace unexpected_alert_behaviour {\ntypedef std::string Value;\ntypedef const char* const ConstValue;\nConstValue Accept = \"accept\";\nConstValue Dismiss = \"dismiss\";\nConstValue Ignore = \"ignore\";\n} // namespace unexpected_alert_behaviour\n\nnamespace proxy_type {\ntypedef std::string Value;\ntypedef const char* const ConstValue;\nConstValue Direct = \"direct\";\nConstValue Manual = \"manual\"; // Manual proxy settings configured, e.g. setting a proxy for HTTP, a proxy for FTP\nConstValue Pac = \"pac\"; // Proxy autoconfiguration from a URL\nConstValue Autodetect = \"autodetect\"; // Proxy autodetection, probably with WPAD\nConstValue System = \"system\"; // Use system settings\n} // namespace proxy_type\n\n#define WEBDRIVERXX_PROPERTIES_BEGIN(this_class)\ttypedef this_class This;\n#define WEBDRIVERXX_PROPERTIES_END()\n\n#define WEBDRIVERXX_PROPERTY_RONLY(name, id, type) \\\n\ttype Get##name() const { return GetOptional<type>(id); } \\\n\tbool Has##name() { return Has(id); }\n\n#define WEBDRIVERXX_PROPERTY(name, id, type) \\\n\tWEBDRIVERXX_PROPERTY_RONLY(name, id, type) \\\n\tThis& Set##name(const type& value) { Set(id, value); return *this; }\n\nstruct Proxy : JsonObject { // copyable\n\tWEBDRIVERXX_PROPERTIES_BEGIN(Proxy)\n\tWEBDRIVERXX_PROPERTY(ProxyType, \"proxyType\", proxy_type::Value)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\nstruct DirectConnection : Proxy { // copyable\n\tDirectConnection() { SetProxyType(proxy_type::Direct); }\n};\n\nstruct AutodetectProxy : Proxy { // copyable\n\tAutodetectProxy() { SetProxyType(proxy_type::Autodetect); }\n};\n\nstruct SystemProxy : Proxy { // copyable\n\tSystemProxy() { SetProxyType(proxy_type::System); }\n};\n\nstruct AutomaticProxyFromUrl : Proxy { // copyable\n\texplicit AutomaticProxyFromUrl(const std::string& url) {\n\t\tSetProxyType(proxy_type::Pac);\n\t\tSetAutoconfigUrl(url);\n\t}\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(AutomaticProxyFromUrl)\n\tWEBDRIVERXX_PROPERTY(AutoconfigUrl, \"proxyAutoconfigUrl\", std::string)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\nstruct ManualProxy : Proxy { // copyable\n\tManualProxy() { SetProxyType(proxy_type::Manual); }\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(ManualProxy)\n\tWEBDRIVERXX_PROPERTY(NoProxyFor, \"noProxy\", std::string)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\nstruct FtpProxy : ManualProxy { // copyable\n\texplicit FtpProxy(const std::string& address) { SetProxyAddress(address); }\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(FtpProxy)\n\tWEBDRIVERXX_PROPERTY(ProxyAddress, \"ftpProxy\", std::string)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\nstruct HttpProxy : ManualProxy { // copyable\n\texplicit HttpProxy(const std::string& address) { SetProxyAddress(address); }\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(HttpProxy)\n\tWEBDRIVERXX_PROPERTY(ProxyAddress, \"httpProxy\", std::string)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\nstruct SslProxy : ManualProxy { // copyable\n\texplicit SslProxy(const std::string& address) { SetProxyAddress(address); }\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(SslProxy)\n\tWEBDRIVERXX_PROPERTY(ProxyAddress, \"sslProxy\", std::string)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\nstruct SocksProxy : ManualProxy { // copyable\n\texplicit SocksProxy(const std::string& address) { SetProxyAddress(address); }\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(SocksProxy)\n\tWEBDRIVERXX_PROPERTY(ProxyAddress, \"socksProxy\", std::string)\n\tWEBDRIVERXX_PROPERTY(Username, \"socksUsername\", std::string)\n\tWEBDRIVERXX_PROPERTY(Password, \"socksPassword\", std::string)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\nnamespace log_level {\ntypedef std::string Value;\ntypedef const char* const ConstValue;\nConstValue Off = \"OFF\";\nConstValue Severe = \"SEVERE\";\nConstValue Warning = \"WARNING\";\nConstValue Info = \"INFO\";\nConstValue Config = \"CONFIG\";\nConstValue Fine = \"FINE\";\nConstValue Finer = \"FINER\";\nConstValue Finest = \"FINEST\";\nConstValue All = \"ALL\";\n} // namespace log_level\n\nstruct LoggingPrefs : JsonObject {\n\tWEBDRIVERXX_PROPERTIES_BEGIN(LoggingPrefs)\n\tWEBDRIVERXX_PROPERTY(Level, \"driver\", log_level::Value)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\n// List of keys and values indicating features that server can or should provide.\nstruct Capabilities : JsonObject { // copyable\n\tCapabilities() {}\n\texplicit Capabilities(const picojson::object& object) : JsonObject(object) {}\n\n\t// Hardcoded capabilities are here just to add some sugar.\n\t// If a capability is not listed below use Get/Set/Has public members.\n\n\tWEBDRIVERXX_PROPERTIES_BEGIN(Capabilities)\n\tWEBDRIVERXX_PROPERTY(BrowserName, \"browserName\", browser::Value)\n\tWEBDRIVERXX_PROPERTY(Version, \"version\", std::string)\n\tWEBDRIVERXX_PROPERTY(Platform, \"platform\", platform::Value)\n\n\tWEBDRIVERXX_PROPERTY_RONLY(TakesScreenshot, \"takesScreenshot\", bool)\n\tWEBDRIVERXX_PROPERTY_RONLY(HandlesAlerts, \"handlesAlerts\", bool)\n\tWEBDRIVERXX_PROPERTY_RONLY(CssSelectorsEnabled, \"cssSelectorsEnabled\", bool)\n\n\tWEBDRIVERXX_PROPERTY(JavascriptEnabled, \"javascriptEnabled\", bool)\n\tWEBDRIVERXX_PROPERTY(DatabaseEnabled, \"databaseEnabled\", bool)\n\tWEBDRIVERXX_PROPERTY(LocationContextEnabled, \"locationContextEnabled\", bool)\n\tWEBDRIVERXX_PROPERTY(ApplicationCacheEnabled, \"applicationCacheEnabled\", bool)\n\tWEBDRIVERXX_PROPERTY(BrowserConnectionEnabled, \"browserConnectionEnabled\", bool)\n\tWEBDRIVERXX_PROPERTY(WebStorageEnabled, \"webStorageEnabled\", bool)\n\tWEBDRIVERXX_PROPERTY(AcceptSslCerts, \"acceptSslCerts\", bool)\n\tWEBDRIVERXX_PROPERTY(Rotatable, \"rotatable\", bool)\n\tWEBDRIVERXX_PROPERTY(NativeEvents, \"nativeEvents\", bool)\n\tWEBDRIVERXX_PROPERTY(Proxy, \"proxy\", Proxy)\n\tWEBDRIVERXX_PROPERTY(UnexpectedAlertBehaviour, \"unexpectedAlertBehaviour\", unexpected_alert_behaviour::Value)\n\tWEBDRIVERXX_PROPERTY(ElementScrollBehavior, \"elementScrollBehavior\", int)\n\n\tWEBDRIVERXX_PROPERTY_RONLY(SessionId, \"webdriver.remote.sessionid\", std::string)\n\tWEBDRIVERXX_PROPERTY(QuietExceptions, \"webdriver.remote.quietExceptions\", bool)\n\tWEBDRIVERXX_PROPERTIES_END()\n};\n\ninline\nvoid CustomFromJson(const picojson::value& value, Capabilities& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"Capabilities is not an object\");\n\tresult = Capabilities(value.get<picojson::object>());\n}\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/client.h",
    "content": "#ifndef WEBDRIVERXX_CLIENT_H\n#define WEBDRIVERXX_CLIENT_H\n\n#include \"session.h\"\n#include \"capabilities.h\"\n#include \"detail/resource.h\"\n#include \"detail/http_connection.h\"\n#include \"picojson.h\"\n#include <string>\n#include <vector>\n\nnamespace webdriverxx {\n\nconst char *const kDefaultWebDriverUrl = \"http://localhost:4444/wd/hub/\";\n\n// Gives low level access to server's resources. You normally should not use it. \nclass Client { // copyable\npublic:\n\texplicit Client(const std::string& url = kDefaultWebDriverUrl);\n\tvirtual ~Client() {}\n\n\tpicojson::object GetStatus() const;\n\n\t// Returns existing sessions.\n\tstd::vector<Session> GetSessions() const;\n\n\t// Creates new session.\n\tSession CreateSession(\n\t\tconst Capabilities& desired,\n\t\tconst Capabilities& required\n\t\t) const;\n\nprivate:\n\tSession MakeSession(\n\t\tconst std::string& id,\n\t\tdetail::Resource::Ownership mode\n\t\t) const;\n\nprivate:\n\tdetail::Shared<detail::Resource> resource_;\n};\n\n} // namespace webdriverxx\n\n#include \"client.inl\"\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/client.inl",
    "content": "#include \"conversions.h\"\n#include \"detail/shared.h\"\n#include \"detail/error_handling.h\"\n#include \"detail/types.h\"\n#include <algorithm>\n\nnamespace webdriverxx {\n\ninline\nClient::Client(const std::string& url)\n\t: resource_(new detail::RootResource(\n\t\turl,\n\t\tdetail::Shared<detail::IHttpClient>(new detail::HttpConnection)\n\t\t))\n{}\n\ninline\npicojson::object Client::GetStatus() const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\tconst auto value = resource_->Get(\"status\").get(\"value\");\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"Value is not an object\");\n\treturn value.get<picojson::object>();\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END()\n}\n\ninline\nstd::vector<Session> Client::GetSessions() const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\tconst auto sessions =\n\t\tFromJson<std::vector<detail::SessionRef>>(\n\t\t\tresource_->Get(\"sessions\").get(\"value\")\n\t\t\t);\n\tstd::vector<Session> result;\n\tresult.reserve(sessions.size());\n\tstd::transform(sessions.begin(), sessions.end(), std::back_inserter(result),\n\t\t[this](const detail::SessionRef& session_ref) {\n\t\t\treturn MakeSession(session_ref.id, detail::Resource::IsObserver);\n\t\t});\n\treturn result;\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END()\n}\n\ninline\nSession Client::CreateSession(\n\tconst Capabilities& desired,\n\tconst Capabilities& required\n\t) const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\tconst auto response = resource_->Post(\"session\",\n\t\tJsonObject()\n\t\t\t.Set(\"desiredCapabilities\", static_cast<picojson::value>(desired))\n\t\t\t.Set(\"requiredCapabilities\", static_cast<picojson::value>(required))\n\t\t\t);\n\n\tWEBDRIVERXX_CHECK(response.get(\"sessionId\").is<std::string>(), \"Session ID is not a string\");\n\tWEBDRIVERXX_CHECK(response.get(\"value\").is<picojson::object>(), \"Capabilities is not an object\");\n\t\n\tconst auto sessionId = response.get(\"sessionId\").to_str();\n\t\n\treturn MakeSession(sessionId, detail::Resource::IsOwner);\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END()\n}\n\ninline\nSession Client::MakeSession(\n\tconst std::string& id,\n\tdetail::Resource::Ownership mode\n\t) const {\n\treturn Session(detail::MakeSubResource(resource_, \"session\", id, mode));\n}\n\n} // namespace webdriverxx\n"
  },
  {
    "path": "include/webdriverxx/conversions.h",
    "content": "#ifndef WEBDRIVERXX_CONVERSIONS_H\n#define WEBDRIVERXX_CONVERSIONS_H\n\n#include \"types.h\"\n#include \"detail/error_handling.h\"\n#include \"detail/meta_tools.h\"\n#include \"picojson.h\"\n#include <algorithm>\n\nnamespace webdriverxx {\n\ntemplate<typename T>\npicojson::value ToJson(const T& value);\n\ntemplate<typename T>\nT FromJson(const picojson::value& value);\n\nclass JsonObject { // copyable\npublic:\n\tJsonObject() : value_(picojson::object()) {}\n\texplicit JsonObject(const picojson::object& object) : value_(object) {}\n\n\ttemplate<typename T>\n\tT Get(const std::string& name) const {\n\t\tconst auto& map = value_.get<picojson::object>();\n\t\tconst auto it = map.find(name);\n\t\tWEBDRIVERXX_CHECK(it != map.end(), detail::Fmt() << \"No \\\"\" << name << \"\\\" in JsonObject\");\n\t\treturn FromJson<T>(it->second);\n\t}\n\n\ttemplate<typename T>\n\tT GetOptional(const std::string& name, const T& default_value = T()) const {\n\t\tconst auto& map = value_.get<picojson::object>();\n\t\tconst auto it = map.find(name);\n\t\treturn it != map.end() ? FromJson<T>(it->second) : default_value;\n\t}\n\n\ttemplate<typename T>\n\tJsonObject& Set(const std::string& name, const T& value) {\n\t\tvalue_.get<picojson::object>()[name] = ToJson(value);\n\t\treturn *this;\n\t}\n\n\tbool Has(const std::string& name) const {\n\t\tconst auto& map = value_.get<picojson::object>();\n\t\treturn map.find(name) != map.end();\n\t}\n\n\toperator const picojson::value& () const {\n\t\treturn value_;\n\t}\n\nprivate:\n\tpicojson::value value_;\n};\n\nnamespace conversions_detail {\n\nstruct DefaultTag {};\nstruct IterableTag {};\n\nusing namespace detail;\n\ntemplate<typename T>\nstruct Tag :\n\tif_<is_iterable<T>, type_is<IterableTag>,\n\ttype_is<DefaultTag>\n\t> {};\n\ntemplate<typename T>\npicojson::value ToJsonImpl(const T& value, DefaultTag) {\n\t// Compile error here usually indicates\n\t// that compiler doesn't know how to convert the type T\n\t// to the picojson::value. Define CustomToJson\n\t// function (see examples below) in the T's namespace\n\t// to resolve the issue.\n\treturn picojson::value(value);\n}\n\ntemplate<typename T>\npicojson::value ToJsonImpl(const T& value, IterableTag) {\n\ttypedef typename std::iterator_traits<decltype(std::begin(value))>::value_type Item;\n\tpicojson::value result = picojson::value(picojson::array());\n\tpicojson::array& dst = result.get<picojson::array>();\n\tstd::transform(std::begin(value), std::end(value), std::back_inserter(dst), [](const Item& item) {\n\t\treturn ToJson(item);\n\t});\n\treturn result;\n}\n\n} // conversions_detail\n\ninline\npicojson::value CustomToJson(const char* value) {\n\treturn picojson::value(value);\n}\n\ninline\npicojson::value CustomToJson(const std::string& value) {\n\treturn ToJson(value.c_str());\n}\n\ninline\npicojson::value CustomToJson(const picojson::value& value) {\n\treturn value;\n}\n\ninline\npicojson::value CustomToJson(const picojson::object& value) {\n\treturn picojson::value(value);\n}\n\ninline\npicojson::value CustomToJson(const JsonObject& value) {\n\treturn static_cast<picojson::value>(value);\n}\n\ninline\npicojson::value CustomToJson(int value) {\n\treturn picojson::value(static_cast<double>(value));\n}\n\ntemplate<typename T>\npicojson::value CustomToJson(const T& value) {\n\tusing conversions_detail::ToJsonImpl;\n\tusing conversions_detail::Tag;\n\treturn ToJsonImpl(value, typename Tag<T>::type());\n}\n\ntemplate<typename T>\npicojson::value ToJson(const T& value) {\n\treturn CustomToJson(value);\n}\n\n///////////////////////////////////////////////////////////////////\n\nnamespace conversions_detail {\n\ntemplate<typename T>\nvoid FromJsonImpl(const picojson::value& value, T& result, DefaultTag) {\n\t// Compile error here usually indicates\n\t// that compiler doesn't know how to convert the picojson::value\n\t// to the type T. Define CustomFromJson function (see examples below)\n\t// in the T's namespace to resolve the issue.\n\tresult = value.get<T>();\n}\n\ntemplate<typename T>\nvoid FromJsonImpl(const picojson::value& value, T& result, IterableTag) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::array>(), \"Value is not an array\");\n\tconst picojson::array& array = value.get<picojson::array>();\n\ttypedef typename std::iterator_traits<decltype(std::begin(result))>::value_type Item;\n\tstd::transform(array.begin(), array.end(), std::back_inserter(result), FromJson<Item>);\n}\n\n} // conversions_detail\n\ninline\nvoid CustomFromJson(const picojson::value& value, std::string& result) {\n\tresult = value.to_str();\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, bool& result) {\n\tresult = value.evaluate_as_boolean();\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, int& result) {\n\tWEBDRIVERXX_CHECK(value.is<double>(), \"Value is not a number\");\n\tresult = static_cast<int>(value.get<double>());\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, unsigned& result) {\n\tWEBDRIVERXX_CHECK(value.is<double>(), \"Value is not a number\");\n\tresult = static_cast<unsigned>(value.get<double>());\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, picojson::value& result) {\n\tresult = value;\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, picojson::object& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"Value is not an object\");\n\tresult = value.get<picojson::object>();\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, JsonObject& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"Value is not an object\");\n\tresult = JsonObject(value.get<picojson::object>());\n}\n\ntemplate<typename T>\nvoid CustomFromJson(const picojson::value& value, T& result) {\n\tusing conversions_detail::FromJsonImpl;\n\tusing conversions_detail::Tag;\n\treturn FromJsonImpl(value, result, typename Tag<T>::type());\n}\n\ntemplate<typename T>\nT FromJson(const picojson::value& value) {\n\tT result;\n\tCustomFromJson(value, result);\n\treturn result;\n}\n\ntemplate<typename T>\nT OptionalFromJson(const picojson::value& value, const T& default_value = T()) {\n\treturn value.is<picojson::null>() ? default_value : FromJson<T>(value);\n}\n\n///////////////////////////////////////////////////////////////////\n\ninline\npicojson::value CustomToJson(const Size& size) {\n\treturn JsonObject()\n\t\t.Set(\"width\", size.width)\n\t\t.Set(\"height\", size.height)\n\t\t;\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, Size& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"Size is not an object\");\n\tresult.width = FromJson<int>(value.get(\"width\"));\n\tresult.height = FromJson<int>(value.get(\"height\"));\n}\n\ninline\npicojson::value CustomToJson(const Point& position) {\n\treturn JsonObject()\n\t\t.Set(\"x\", position.x)\n\t\t.Set(\"y\", position.y)\n\t\t;\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, Point& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"Point is not an object\");\n\tresult.x = FromJson<int>(value.get(\"x\"));\n\tresult.y = FromJson<int>(value.get(\"y\"));\n}\n\ninline\npicojson::value CustomToJson(const Cookie& cookie) {\n\tJsonObject result;\n\tresult.Set(\"name\", cookie.name);\n\tresult.Set(\"value\", cookie.value);\n\tif (!cookie.path.empty()) result.Set(\"path\", cookie.path);\n\tif (!cookie.domain.empty()) result.Set(\"domain\", cookie.domain);\n\tif (cookie.secure) result.Set(\"secure\", true);\n\tif (cookie.http_only) result.Set(\"httpOnly\", true);\n\tif (cookie.expiry != Cookie::NoExpiry) result.Set(\"expiry\", cookie.expiry);\n\treturn result;\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, Cookie& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"Cookie is not an object\");\n\tresult.name = FromJson<std::string>(value.get(\"name\"));\n\tresult.value = FromJson<std::string>(value.get(\"value\"));\n\tresult.path = OptionalFromJson<std::string>(value.get(\"path\"));\n\tresult.domain = OptionalFromJson<std::string>(value.get(\"domain\"));\n\tresult.secure = OptionalFromJson<bool>(value.get(\"secure\"), false);\n\tresult.http_only = OptionalFromJson<bool>(value.get(\"httpOnly\"), false);\n\tresult.expiry = OptionalFromJson<int>(value.get(\"expiry\"), Cookie::NoExpiry);\n}\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/error_handling.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_ERROR_HANDLING_H\n#define WEBDRIVERXX_DETAIL_ERROR_HANDLING_H\n\n#include \"../errors.h\"\n#include <string>\n#include <sstream>\n\nnamespace webdriverxx {\nnamespace detail {\n\nclass Fmt {\npublic:\n\ttemplate<typename T>\n\tFmt& operator << (const T& value) {\n\t\tstream_ << value;\n\t\treturn *this;\n\t}\n\n\toperator std::string() const {\n\t\treturn stream_.str();\n\t}\n\nprivate:\n\tstd::ostringstream stream_;\n};\n\ntemplate<typename T>\nbool BoolCast(T value) {\n\treturn !!value;\n}\n\n} // namespace detail\n} // namespace webdriverxx\n\n#if __cplusplus >= 201103L\n\t#define WEBDRIVERXX_CURRENT_FUNCTION __func__\n#else\n\t#define WEBDRIVERXX_CURRENT_FUNCTION __FUNCTION__\n#endif\n\n#define WEBDRIVERXX_FUNCTION_CONTEXT_BEGIN() \\\n\ttry {\n\n#define WEBDRIVERXX_FUNCTION_CONTEXT_END() \\\n\t} catch (const std::exception& e) { \\\n\t\tthrow ::webdriverxx::WebDriverException(std::string(e.what()) \\\n\t\t\t+ \" called from \" + WEBDRIVERXX_CURRENT_FUNCTION); \\\n\t}\n\n#define WEBDRIVERXX_FUNCTION_CONTEXT_END_EX(details) \\\n\t} catch (const std::exception& e) { \\\n\t\tthrow ::webdriverxx::WebDriverException(std::string(e.what()) \\\n\t\t\t+ \" called from \" + WEBDRIVERXX_CURRENT_FUNCTION \\\n\t\t\t+ \" (\" + std::string(details) + \")\"); \\\n\t}\n\n#define WEBDRIVERXX_THROW(message) \\\n\tthrow ::webdriverxx::WebDriverException(::webdriverxx::detail::Fmt() \\\n\t\t<< std::string(message) \\\n\t\t<< \" at line \" << __LINE__ \\\n\t\t<< \", file \" << __FILE__ \\\n\t\t)\n\n#define WEBDRIVERXX_CHECK(pred, message) \\\n\tfor (;!detail::BoolCast(pred);) \\\n\t\tWEBDRIVERXX_THROW(message)\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/factories.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_FACTORIES_H\n#define WEBDRIVERXX_DETAIL_FACTORIES_H\n\n#include \"shared.h\"\n#include <string>\n\nnamespace webdriverxx {\n\nclass Element;\n\nnamespace detail {\n\nclass Finder;\nclass Resource;\n\nstruct IFinderFactory {\n\tvirtual Finder MakeFinder(const Shared<Resource>& context) = 0;\n\tvirtual ~IFinderFactory() {}\n\n};\n\nstruct IElementFactory {\n\tvirtual Element MakeElement(const std::string& id) = 0;\n\tvirtual ~IElementFactory() {}\n};\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/factories_impl.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_FACTORIES_IMPL_H\n#define WEBDRIVERXX_DETAIL_FACTORIES_IMPL_H\n\n#include \"factories.h\"\n#include \"resource.h\"\n#include \"finder.h\"\n#include \"shared.h\"\n#include \"../element.h\"\n\nnamespace webdriverxx {\nnamespace detail {\n\nclass SessionFactory // noncopyable\n\t: public IElementFactory\n\t, public IFinderFactory\n\t, public SharedObjectBase\n{\npublic:\n\texplicit SessionFactory(const Shared<Resource>& session_resource)\n\t\t: session_resource_(session_resource)\n\t{}\n\n\tvirtual Element MakeElement(const std::string& id) {\n\t\treturn Element(\n\t\t\tid,\n\t\t\tdetail::MakeSubResource(session_resource_, \"element\", id),\n\t\t\tShared<IFinderFactory>(this)\n\t\t\t);\n\t}\n\n\tvirtual Finder MakeFinder(const Shared<Resource>& context) {\n\t\treturn Finder(context, Shared<IElementFactory>(this));\n\t}\n\nprivate:\n\tconst Shared<Resource> session_resource_;\n};\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/finder.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_FINDER_H\n#define WEBDRIVERXX_DETAIL_FINDER_H\n\n#include \"shared.h\"\n#include \"resource.h\"\n#include \"factories.h\"\n#include \"../by.h\"\n#include <vector>\n\nnamespace webdriverxx {\n\nclass Element;\n\nnamespace detail {\n\nclass Finder { // copyable\npublic:\n\tFinder(\n\t\tconst Shared<Resource>& context,\n\t\tconst Shared<IElementFactory>& factory\n\t\t);\n\n\tElement FindElement(const By& by) const;\n\tstd::vector<Element> FindElements(const By& by) const;\n\nprivate:\n\tShared<Resource> context_;\n\tShared<IElementFactory> factory_;\n};\n\n} // namespace detail\n} // namespace webdriverxx\n\n#include \"finder.inl\"\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/finder.inl",
    "content": "#include \"../conversions.h\"\n#include \"../element.h\"\n#include \"types.h\"\n#include <algorithm>\n\nnamespace webdriverxx {\nnamespace detail {\n\ninline\nFinder::Finder(\n\tconst Shared<Resource>& context,\n\tconst Shared<IElementFactory>& factory\n\t)\n\t: context_(context)\n\t, factory_(factory)\n{}\n\ninline\nElement Finder::FindElement(const By& by) const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\treturn factory_->MakeElement(FromJson<ElementRef>(\n\t\tcontext_->Post(\"element\", JsonObject()\n\t\t\t.Set(\"using\", by.GetStrategy())\n\t\t\t.Set(\"value\", by.GetValue())\n\t\t)).ref);\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END_EX(Fmt()\n\t\t<< \"context: \" << context_->GetUrl()\n\t\t<< \", strategy: \" << by.GetStrategy()\n\t\t<< \", value: \" << by.GetValue()\n\t\t)\n}\n\ninline\nstd::vector<Element> Finder::FindElements(const By& by) const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\tconst auto ids =\n\t\tFromJson<std::vector<ElementRef>>(\n\t\t\tcontext_->Post(\"elements\", JsonObject()\n\t\t\t\t.Set(\"using\", by.GetStrategy())\n\t\t\t\t.Set(\"value\", by.GetValue())\n\t\t\t));\n\tstd::vector<Element> result;\n\tresult.reserve(ids.size());\n\tstd::transform(ids.begin(), ids.end(), std::back_inserter(result),\n\t\t[this](const ElementRef& element_ref) {\n\t\t\treturn factory_->MakeElement(element_ref.ref);\n\t\t});\n\treturn result;\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END_EX(Fmt()\n\t\t<< \"context: \" << context_->GetUrl()\n\t\t<< \", strategy: \" << by.GetStrategy()\n\t\t<< \", value: \" << by.GetValue()\n\t\t)\n}\n\n} // namespace detail\n} // namespace webdriverxx\n"
  },
  {
    "path": "include/webdriverxx/detail/http_client.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_HTTP_CLIENT_H\n#define WEBDRIVERXX_DETAIL_HTTP_CLIENT_H\n\n#include <string>\n\nnamespace webdriverxx {\nnamespace detail {\n\nstruct HttpResponse {\n\tlong http_code;\n\tstd::string body;\n\n\tHttpResponse()\n\t\t: http_code(0)\n\t{}\n};\n\nstruct IHttpClient {\n\tvirtual HttpResponse Get(const std::string& url) const = 0;\n\tvirtual HttpResponse Delete(const std::string& url) const = 0;\n\tvirtual HttpResponse Post(const std::string& url, const std::string& data) const = 0;\n\tvirtual ~IHttpClient() {}\n};\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/http_connection.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_HTTP_CONNECTION_H\n#define WEBDRIVERXX_DETAIL_HTTP_CONNECTION_H\n\n#include \"http_client.h\"\n#include \"http_request.h\"\n#include \"error_handling.h\"\n#include \"shared.h\"\n#include <curl/curl.h>\n\nnamespace webdriverxx {\nnamespace detail {\n\nclass HttpConnection // noncopyable\n\t: public IHttpClient\n\t, public SharedObjectBase\n{\npublic:\n\tHttpConnection()\n\t\t: connection_(InitCurl())\n\t{}\n\n\t~HttpConnection() {\n\t\tcurl_easy_cleanup(connection_);\n\t}\n\n\tHttpResponse Get(const std::string& url) const {\n\t\treturn HttpGetRequest(connection_, url).Execute();\n\t}\n\t\n\tHttpResponse Delete(const std::string& url) const {\n\t\treturn HttpDeleteRequest(connection_, url).Execute();\n\t}\n\t\n\tHttpResponse Post(\n\t\tconst std::string& url,\n\t\tconst std::string& upload_data\n\t\t) const {\n\t\treturn HttpPostRequest(connection_, url, upload_data).Execute();\n\t}\n\nprivate:\n\tstatic\n\tCURL* InitCurl() {\n\t\tCURL *const result = curl_easy_init();\n\t\tWEBDRIVERXX_CHECK(result, \"Cannot initialize CURL\");\n\t\treturn result;\n\t}\n\nprivate:\n\tCURL *const connection_;\n};\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/http_request.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_HTTP_REQUEST_H\n#define WEBDRIVERXX_DETAIL_HTTP_REQUEST_H\n\n#include \"error_handling.h\"\n#include <curl/curl.h>\n#include <string>\n#include <algorithm>\n\nnamespace webdriverxx {\nnamespace detail {\n\nconst char *const kContentTypeJson = \"application/json;charset=UTF-8\";\n\nclass HttpHeaders {\npublic:\n\tHttpHeaders() : head_(nullptr) {}\n\n\t~HttpHeaders() {\n\t\tcurl_slist_free_all(head_);\n\t}\n\n\tvoid Add(const std::string& name, const std::string& value) {\n\t\thead_ = curl_slist_append(head_, (name + \": \" + value).c_str());\n\t\tWEBDRIVERXX_CHECK(head_, \"Cannot add HTTP header\");\n\t}\n\n\tcurl_slist* Get() const {\n\t\treturn head_;\n\t}\n\nprivate:\n\tcurl_slist* head_;\n};\n\nclass HttpRequest {\npublic:\n\tHttpRequest(\n\t\tCURL* http_connection,\n\t\tconst std::string& url\n\t\t)\n\t\t: http_connection_(http_connection)\n\t\t, url_(url)\n\t{}\n\n\tvirtual ~HttpRequest() {}\n\n\tHttpResponse Execute() {\n\t\tcurl_easy_reset(http_connection_);\n\t\tSetOption(CURLOPT_URL, url_.c_str());\n\t\tHttpResponse response;\n\t\tSetOption(CURLOPT_WRITEFUNCTION, &WriteCallback);\n\t\tSetOption(CURLOPT_WRITEDATA, &response.body);\n\t\tchar error_message[CURL_ERROR_SIZE];\n  \t\tSetOption(CURLOPT_ERRORBUFFER, &error_message);\n\t\tAddHeader(\"Accept\", kContentTypeJson);\n\t\t\n\t\tSetCustomRequestOptions();\n\t\t\n\t\tSetOption(CURLOPT_HTTPHEADER, headers_.Get());\n\n\t\tconst CURLcode result = curl_easy_perform(http_connection_);\n\t\tWEBDRIVERXX_CHECK(result == CURLE_OK, Fmt()\n\t\t\t<< \"Cannot perform HTTP request (\"\n\t\t\t<< \"result: \" << result\n\t\t\t<< \", message: \" << error_message\n\t\t\t<< \")\"\n\t\t\t);\n\n\t\tresponse.http_code = GetHttpCode();\n\t\treturn response;\n\t}\n\nprotected:\n\tvirtual void SetCustomRequestOptions() {}\n\n\ttemplate<typename T>\n\tvoid SetOption(CURLoption option, const T& value) const {\n\t\tconst auto result = curl_easy_setopt(http_connection_, option, value);\n\t\tWEBDRIVERXX_CHECK(result == CURLE_OK, Fmt()\n\t\t\t<< \"Cannot set HTTP session option (\"\n\t\t\t<< \"option: \" << option\n\t\t\t<< \", message: \\\"\" << curl_easy_strerror(result) << \"\\\"\"\n\t\t\t<< \")\"\n\t\t\t);\n\t}\n\n\tvoid AddHeader(const std::string& name, const std::string& value) {\n\t\theaders_.Add(name, value);\n\t}\n\nprivate:\n\tlong GetHttpCode() const {\n\t\tlong http_code = 0;\n\t\tconst auto result = curl_easy_getinfo(http_connection_, CURLINFO_RESPONSE_CODE, &http_code);\n\t\tWEBDRIVERXX_CHECK(result == CURLE_OK, Fmt()\n\t\t\t<< \"Cannot get HTTP code (\" << curl_easy_strerror(result) << \")\"\n\t\t\t);\n\t\treturn http_code;\n\t}\n\n\tstatic\n\tsize_t WriteCallback(void* buffer, size_t size, size_t nmemb, void* userdata) {\n\t\tstd::string* data_received = reinterpret_cast<std::string*>(userdata);\n\t\tconst auto buffer_size = size * nmemb;\n\t\tdata_received->append(reinterpret_cast<const char*>(buffer), buffer_size);\n\t\treturn buffer_size;\n\t}\n\nprivate:\n\tHttpRequest(HttpRequest&);\n\tHttpRequest& operator=(HttpRequest&);\n\nprivate:\n\tCURL *const http_connection_;\n\tconst std::string url_;\n\tHttpHeaders headers_;\n};\n\ntypedef HttpRequest HttpGetRequest;\n\nclass HttpDeleteRequest : public HttpRequest {\npublic:\n\tHttpDeleteRequest(CURL* http_connection, const std::string& url)\n\t\t: HttpRequest(http_connection, url)\n\t{}\n\nprivate:\n\tvoid SetCustomRequestOptions() {\n\t\tSetOption(CURLOPT_CUSTOMREQUEST, \"DELETE\");\n\t}\n};\n\nclass HttpPostRequest : public HttpRequest {\npublic:\n\tHttpPostRequest(\n\t\tCURL* http_connection,\n\t\tconst std::string& url,\n\t\tconst std::string& upload_data\n\t\t)\n\t\t: HttpRequest(http_connection, url)\n\t\t, upload_data_(upload_data)\n\t\t, unsent_ptr_(upload_data.c_str())\n\t\t, unsent_length_(upload_data.size())\n\t{}\n\nprotected:\n\tvoid SetCustomRequestOptions() {\n\t\tSetOption(CURLOPT_POST, 1L);\n\t\tSetOption(CURLOPT_POSTFIELDSIZE, upload_data_.length());\n\t\tAddHeader(\"Content-Type\", kContentTypeJson);\n\t\tSetOption(CURLOPT_READFUNCTION, ReadCallback);\n\t\tSetOption(CURLOPT_READDATA, this);\n\t}\n\nprivate:\n\tstatic\n\tsize_t ReadCallback(void* buffer, size_t size, size_t nmemb, void* userdata) {\n\t\tHttpPostRequest* that = reinterpret_cast<HttpPostRequest*>(userdata);\n\t\tauto buffer_size = size * nmemb;\n\t\tauto copy_size = that->unsent_length_ < buffer_size ? that->unsent_length_ : buffer_size;\n\t\tstd::copy(that->unsent_ptr_, that->unsent_ptr_ + copy_size,\n\t\t\treinterpret_cast<char*>(buffer));\n\t\tthat->unsent_length_ -= copy_size;\n\t\tthat->unsent_ptr_ += copy_size;\n\t\treturn copy_size;\n\t}\n\nprivate:\n\tconst std::string& upload_data_;\n\tconst char* unsent_ptr_;\n\tsize_t unsent_length_;\n};\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/keyboard.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_KEYBOARD_H\n#define WEBDRIVERXX_DETAIL_KEYBOARD_H\n\n#include \"resource.h\"\n#include \"../conversions.h\"\n#include \"../keys.h\"\n\nnamespace webdriverxx {\nnamespace detail {\n\nclass Keyboard { // copyable\npublic:\n\tKeyboard(const Shared<Resource>& resource, const std::string& command)\n\t\t: resource_(resource)\n\t\t, command_(command)\n\t{}\n\n\tconst Keyboard& SendKeys(const std::string& keys) const {\n\t\treturn SendKeys(Shortcut() << keys);\n\t}\n\n\tconst Keyboard& SendKeys(const Shortcut& shortcut) const {\n\t\tresource_->Post(command_, JsonObject()\n\t\t\t.Set(\"value\", ToJson(shortcut.keys_)));\n\t\treturn *this;\n\t}\n\nprivate:\n\tShared<Resource> resource_;\n\tstd::string command_;\n};\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/meta_tools.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_META_TOOLS_H\n#define WEBDRIVERXX_DETAIL_META_TOOLS_H\n\n#include <type_traits>\n#include <utility>\n#include <iterator>\n#include <string>\n\nnamespace webdriverxx {\nnamespace detail {\n\ntemplate<class T>\nstruct type_is { typedef T type; };\n\ntemplate<class T>\nT& value_ref(); // MSVC2010 doesn't have std::declval\n\ntemplate<class T>\nclass is_iterable {\n\ttemplate<class U>\n\tstatic std::false_type test(...);\n\ttemplate<class U>\n\tstatic decltype(std::begin(value_ref<U>()), std::end(value_ref<U>()),\n\t\tstd::true_type()) test(int);\n\n\ttypedef decltype(test<T>(0)) verdict;\n\npublic:\n\tstatic const bool value = verdict::value;\n};\n\ntemplate<class T>\nstruct is_string : std::is_convertible<const T&, std::string> {};\n\ntemplate<class C, class T1, class T2>\nstruct if_ : std::conditional<C::value, typename T1::type, typename T2::type> {};\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/resource.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_RESOURCE_H\n#define WEBDRIVERXX_DETAIL_RESOURCE_H\n\n#include \"error_handling.h\"\n#include \"http_client.h\"\n#include \"shared.h\"\n#include \"../conversions.h\"\n#include \"../response_status_code.h\"\n#include \"../picojson.h\"\n\nnamespace webdriverxx {\nnamespace detail {\n\nclass Resource : public SharedObjectBase { // noncopyable\npublic:\n\tenum Ownership { IsOwner, IsObserver };\n\n\tResource(\n\t\tconst std::string& url,\n\t\tconst Shared<IHttpClient>& http_client,\n\t\tOwnership mode = IsObserver\n\t\t)\n\t\t: http_client_(http_client)\n\t\t, url_(url)\n\t\t, ownership_(mode)\n\t{}\n\n\tResource(\n\t\tconst Shared<Resource>& parent,\n\t\tconst std::string& name,\n\t\tOwnership mode = IsObserver\n\t\t)\n\t\t: http_client_(parent->http_client_)\n\t\t, parent_(parent)\n\t\t, url_(ConcatUrl(parent->url_, name))\n\t\t, ownership_(mode)\n\t{}\n\n\tvirtual ~Resource() {\n\t\ttry {\n\t\t\tif (ownership_ == IsOwner)\n\t\t\t\tDeleteResource();\n\t\t} catch (const std::exception&) {}\n\t}\n\n\tconst std::string& GetUrl() const {\n\t\treturn url_;\n\t}\n\n\tpicojson::value Get(const std::string& command = std::string()) const {\n\t\treturn Download(command, &IHttpClient::Get, \"GET\");\n\t}\n\n\ttemplate<typename T>\n\tT GetValue(const std::string& command) const {\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\t\treturn FromJson<T>(Get(command));\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_END_EX(detail::Fmt() <<\n\t\t\t\"command: \" << command\n\t\t\t)\n\t}\n\n\tstd::string GetString(const std::string& command) const {\n\t\treturn GetValue<std::string>(command);\n\t}\n\n\tbool GetBool(const std::string& command) const {\n\t\treturn GetValue<bool>(command);\n\t}\n\n\tpicojson::value Delete(const std::string& command = std::string()) const {\n\t\treturn Download(command, &IHttpClient::Delete, \"DELETE\");\n\t}\n\n\tpicojson::value Post(\n\t\tconst std::string& command = std::string(),\n\t\tconst picojson::value& upload_data = picojson::value()\n\t\t) const {\n\t\treturn Upload(command, upload_data, &IHttpClient::Post, \"POST\");\n\t}\n\n\ttemplate<typename T>\n\tvoid Post(\n\t\tconst std::string& command,\n\t\tconst std::string& arg_name,\n\t\tconst T& arg_value\n\t\t) const {\n\t\tPost(command, JsonObject().Set(arg_name, arg_value));\n\t}\t\n\n\ttemplate<typename T>\n\tvoid PostValue(const std::string& command, const T& value) const {\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\t\tPost(command, ToJson(value));\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_END_EX(detail::Fmt() <<\n\t\t\t\"command: \" << command\n\t\t\t)\n\t}\t\n\nprotected:\n\tvirtual picojson::value TransformResponse(picojson::value& response) const {\n\t\tpicojson::value result;\n\t\tresponse.get(\"value\").swap(result);\n\t\treturn result;\n\t}\n\n\tvirtual void DeleteResource() {\n\t\tDelete();\n\t}\n\nprivate:\n\tpicojson::value Download(\n\t\tconst std::string& command, \n\t\tHttpResponse (IHttpClient::* member)(const std::string& url) const,\n\t\tconst char* request_type\n\t\t) const {\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\t\treturn ProcessResponse((http_client_->*member)(\n\t\t\tConcatUrl(url_, command)\n\t\t\t));\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_END_EX(Fmt()\n\t\t\t<< \"request: \" << request_type\n\t\t\t<< \", command: \" << command\n\t\t\t<< \", resource: \" << url_\n\t\t\t)\n\t}\n\n\tstatic std::string ToUploadData(const picojson::value& upload_data)\n\t{\n\t\treturn upload_data.is<picojson::null>() ?\n\t\t\tstd::string() : upload_data.serialize();\n\t}\n\n\tpicojson::value Upload(\n\t\tconst std::string& command, \n\t\tconst picojson::value& upload_data,\n\t\tHttpResponse (IHttpClient::* member)(const std::string& url, const std::string& upload_data) const,\n\t\tconst char* request_type\n\t\t) const {\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\t\treturn ProcessResponse((http_client_->*member)(\n\t\t\tConcatUrl(url_, command),\n\t\t\tToUploadData(upload_data)\n\t\t\t));\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_END_EX(Fmt()\n\t\t\t<< \"request: \" << request_type\n\t\t\t<< \", command: \" << command\n\t\t\t<< \", resource: \" << url_\n\t\t\t<< \", data: \" << ToUploadData(upload_data)\n\t\t\t)\n\t}\n\n\tpicojson::value ProcessResponse(\n\t\tconst HttpResponse& http_response\n\t\t) const {\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\t\tWEBDRIVERXX_CHECK(\n\t\t\thttp_response.http_code / 100 != 4 &&\n\t\t\thttp_response.http_code != 501,\n\t\t\t\"HTTP code indicates that request is invalid\");\n\n\t\tpicojson::value response;\n\t\tstd::string error_message;\n\t\tpicojson::parse(response, http_response.body.begin(), http_response.body.end(), &error_message);\n\n\t\tWEBDRIVERXX_CHECK(error_message.empty(),\n\t\t\tFmt() << \"JSON parser error (\" << error_message << \")\"\n\t\t\t);\n\n\t\tWEBDRIVERXX_CHECK(response.is<picojson::object>(), \"Server response is not an object\");\n\t\tWEBDRIVERXX_CHECK(response.contains(\"status\"), \"Server response has no member \\\"status\\\"\");\n\t\tWEBDRIVERXX_CHECK(response.get(\"status\").is<double>(), \"Response status code is not a number\");\n\t\tconst auto status =\n\t\t\tstatic_cast<response_status_code::Value>(static_cast<int>(response.get(\"status\").get<double>()));\n\t\tWEBDRIVERXX_CHECK(response.contains(\"value\"), \"Server response has no member \\\"value\\\"\");\n\t\tconst auto& value = response.get(\"value\");\n\n\t\tif (http_response.http_code == 500) { // Internal server error\n\t\t\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"Server returned HTTP code 500 and \\\"response.value\\\" is not an object\");\n\t\t\tWEBDRIVERXX_CHECK(value.contains(\"message\"), \"Server response has no member \\\"value.message\\\"\");\n\t\t\tWEBDRIVERXX_CHECK(value.get(\"message\").is<std::string>(), \"\\\"value.message\\\" is not a string\");\n\t\t\tWEBDRIVERXX_THROW(Fmt() << \"Server failed to execute command (\"\n\t\t\t\t<< \"message: \" << value.get(\"message\").to_str()\n\t\t\t\t<< \", status: \" << response_status_code::ToString(status)\n\t\t\t\t<< \", status_code: \" << status\n\t\t\t\t<< \")\"\n\t\t\t\t);\n\t\t}\n\t\tWEBDRIVERXX_CHECK(status == response_status_code::kSuccess, \"Non-zero response status code\");\n\t\tWEBDRIVERXX_CHECK(http_response.http_code == 200, \"Unsupported HTTP code\");\n\n\t\treturn TransformResponse(response);\n\t\tWEBDRIVERXX_FUNCTION_CONTEXT_END_EX(Fmt()\n\t\t\t<< \"HTTP code: \" << http_response.http_code\n\t\t\t<< \", body: \" << http_response.body\n\t\t\t)\n\t}\n\n\tstatic\n\tstd::string ConcatUrl(const std::string& a, const std::string& b, const char delim = '/') {\n\t\tauto result = a.empty() ? b : a;\n\t\tif (!a.empty() && !b.empty()) {\n\t\t\tif (result[result.length()-1] != delim)\n\t\t\t\tresult += delim;\n\t\t\tresult.append(b[0] == delim ? b.begin() + 1 : b.begin(), b.end());\n\t\t}\n\t\treturn result;\n\t}\n\nprivate:\n\tconst Shared<IHttpClient> http_client_;\n\tconst Shared<Resource> parent_;\n\tconst std::string url_;\n\tconst Ownership ownership_;\n};\n\nclass RootResource : public Resource { // noncopyable\npublic:\n\tRootResource(\n\t\tconst std::string& url,\n\t\tconst Shared<IHttpClient>& http_client\n\t\t)\n\t\t: Resource(url, http_client, IsObserver)\n\t{}\n\nprivate:\n\tvirtual picojson::value TransformResponse(picojson::value& response) const {\n\t\tpicojson::value result;\n\t\tresponse.swap(result);\n\t\treturn result;\n\t}\n};\n\ninline\nShared<Resource> MakeSubResource(\n\tconst Shared<Resource>& parent,\n\tconst std::string& subpath,\n\tResource::Ownership mode = Resource::IsObserver\n\t) {\n\treturn Shared<Resource>(new Resource(parent, subpath, mode));\n}\n\ninline\nShared<Resource> MakeSubResource(\n\tconst Shared<Resource>& parent,\n\tconst std::string& subpath1,\n\tconst std::string& subpath2,\n\tResource::Ownership mode = Resource::IsObserver\n\t) {\n\treturn Shared<Resource>(new Resource(parent, subpath1 + \"/\" + subpath2, mode));\n}\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/shared.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_SHARED_H\n#define WEBDRIVERXX_DETAIL_SHARED_H\n\n#include <algorithm>\n\nnamespace webdriverxx {\nnamespace detail {\n\nclass SharedObjectBase { // noncopyable\npublic:\n\tSharedObjectBase() : ref_(0) {}\n\tvirtual ~SharedObjectBase() {}\n\n\tvirtual void AddRef() {\n\t\t++ref_;\n\t}\n\n\tvirtual void Release() {\n\t\tif (--ref_ == 0)\n\t\t\tdelete this;\n\t}\n\nprivate:\n\tSharedObjectBase(SharedObjectBase&);\n\tSharedObjectBase& operator = (SharedObjectBase&);\n\nprivate:\n\tunsigned ref_;\n};\n\n// Copyable, not thread safe\ntemplate<typename T>\nclass Shared {\npublic:\n\tShared()\n\t\t: ptr_(nullptr)\n\t\t, ref_(nullptr)\n\t{}\n\n\ttemplate<typename T2>\n\tShared(T2* ptr)\n\t\t: ptr_(ptr)\n\t\t, ref_(ptr)\n\t{\n\t\tif (ref_) ref_->AddRef();\n\t}\n\n\tShared(const Shared& other)\n\t\t: ptr_(other.ptr_)\n\t\t, ref_(other.ref_)\n\t{\n\t\tif (ref_) ref_->AddRef();\n\t}\n\n\ttemplate<typename T2>\n\tShared(const Shared<T2>& other) \n\t\t: ptr_(other.ptr_)\n\t\t, ref_(other.ref_)\n\t{\n\t\tif (ref_) ref_->AddRef();\n\t}\n\n\t~Shared() {\n\t\tif (ref_) ref_->Release();\n\t}\n\n\tShared& operator = (const Shared& other) {\n\t\tif (&other != this)\n\t\t\tShared<T>(other).Swap(*this);\n\t\treturn *this;\n\t}\n\n\tvoid Swap(Shared& other) {\n\t\tstd::swap(ptr_, other.ptr_);\n\t\tstd::swap(ref_, other.ref_);\n\t}\n\n\tT& operator * () const {\n\t\treturn *ptr_;\n\t}\n\n\tT* operator -> () const {\n\t\treturn ptr_;\n\t}\n\n\tT* Get() const {\n\t\treturn ptr_;\n\t}\n\n\toperator T* () const {\n\t\treturn ptr_;\n\t}\n\nprivate:\n\ttemplate<typename T2>\n\tfriend class Shared;\n\n\tT* ptr_;\n\tSharedObjectBase* ref_;\n};\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/time.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_TIME_H\n#define WEBDRIVERXX_DETAIL_TIME_H\n\n#include \"error_handling.h\"\n#include \"../types.h\"\n\n#ifdef _WIN32\n\n#include <windows.h>\n\n#else\n\n#include <time.h>\n#include <sys/time.h>\n\n#endif\n\nnamespace webdriverxx {\nnamespace detail {\n\ninline\nTimePoint Now() {\n\t#ifdef _WIN32\n\t\tFILETIME time;\n\t\t::GetSystemTimeAsFileTime(&time);\n\t\treturn ((static_cast<TimePoint>(time.dwHighDateTime) << 32)\n\t\t\t+ time.dwLowDateTime)/10000;\n\t#else\n\t\ttimeval time = {};\n\t\tWEBDRIVERXX_CHECK(0 == gettimeofday(&time, nullptr), \"gettimeofday failure\");\n\t\treturn static_cast<TimePoint>(time.tv_sec)*1000 + time.tv_usec/1000;\n\t#endif\n}\n\ninline\nvoid Sleep(Duration milliseconds) {\n\t#ifdef _WIN32\n\t\t::Sleep(static_cast<DWORD>(milliseconds));\n\t#else\n\t\ttimespec time = { static_cast<time_t>(milliseconds/1000),\n\t\t\tstatic_cast<long>(milliseconds%1000)*1000000 };\n\t\twhile (nanosleep(&time, &time)) {}\n\t#endif\n}\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/to_string.h",
    "content": "#ifndef WEBDRIVERXX_TO_STRING_H\n#define WEBDRIVERXX_TO_STRING_H\n\n#include \"meta_tools.h\"\n#include <string>\n#include <sstream>\n\nnamespace webdriverxx {\nnamespace detail {\n\ntemplate<typename T>\nvoid ToStream(const T& value, std::ostream& stream);\n\nnamespace to_string_impl {\n\ntemplate<typename T>\nvoid WriteNonStreamableValue(const T&, std::ostream& stream) {\n\tstream << \"<non-printable>\";\n}\n\n} // namespace to_string_impl\n} // detail\n} // webdriverxx\n\nnamespace webdriverxx_to_string_impl {\n\ntemplate<typename T>\nstd::ostream& operator << (std::ostream& stream, const T& value) {\n\twebdriverxx::detail::to_string_impl::WriteNonStreamableValue(value, stream);\n\treturn stream;\n}\n\n} // namespace webdriverxx_to_string_impl\n\nnamespace webdriverxx {\nnamespace detail {\nnamespace to_string_impl {\n\nstruct DefaultTag {};\nstruct IterableTag {};\nstruct StringTag {};\n\ntemplate<typename T>\nstruct Tag :\n\tif_<is_string<T>, type_is<StringTag>,\n\tif_<is_iterable<T>, type_is<IterableTag>,\n\ttype_is<DefaultTag>\n\t>> {};\n\ntemplate<typename T>\nvoid ToStreamImpl(const T& value, std::ostream& stream, DefaultTag) {\n\tusing namespace webdriverxx_to_string_impl;\n\tstream << value;\n}\n\ntemplate<typename T>\nvoid ToStreamImpl(T* value, std::ostream& stream, DefaultTag) {\n\tstream << '*';\n\tToStream(*value, stream);\n}\n\ninline\nvoid ToStreamImpl(const char value, std::ostream& stream, DefaultTag) {\n\tstream << \"'\" << value << \"'\";\n}\n\ninline\nvoid ToStreamImpl(const char* value, std::ostream& stream, StringTag) {\n\tstream << '\"' << value << '\"';\n}\n\ninline\nvoid ToStreamImpl(const std::string& value, std::ostream& stream, StringTag) {\n\tToStream(value.c_str(), stream);\n}\n\ntemplate<typename T>\nvoid ToStreamImpl(const T& value, std::ostream& stream, IterableTag) {\n\tauto it = std::begin(value);\n\tconst auto end = std::end(value);\n\tint limit = 20;\n\tstream << \"[\";\n\tif (it != end) {\n\t\tToStream(*it, stream);\n\t\twhile (++it != end && --limit > 0) {\n\t\t\tstream << \", \";\n\t\t\tToStream(*it, stream);\n\t\t}\n\t}\n\tstream << \"]\";\n}\n\n} // namespace to_string_impl\n\ntemplate<typename T>\nvoid PrintTo(const T& value, std::ostream* stream) {\n\tusing to_string_impl::ToStreamImpl;\n\tusing to_string_impl::Tag;\n\tToStreamImpl(value, *stream, typename Tag<T>::type());\n}\n\ntemplate<typename T>\nvoid ToStream(const T& value, std::ostream& stream)\n{\n\tPrintTo(value, &stream); // for compatibility with Google Test's values printers\n}\n\ntemplate<typename T>\nstd::string ToString(const T& value) {\n\tstd::ostringstream s;\n\tToStream(value, s);\n\treturn s.str();\n}\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/detail/types.h",
    "content": "#ifndef WEBDRIVERXX_DETAIL_TYPES_H\n#define WEBDRIVERXX_DETAIL_TYPES_H\n\n#include \"../conversions.h\"\n#include \"../capabilities.h\"\n#include \"../picojson.h\"\n#include <string>\n\nnamespace webdriverxx {\nnamespace detail {\n\nstruct SessionRef {\n\tstd::string id;\n\tCapabilities capabilities;\n};\n\nstruct ElementRef {\n\tstd::string ref;\n};\n\ninline\npicojson::value CustomToJson(const ElementRef& ref) {\n\treturn JsonObject()\n\t\t.Set(\"ELEMENT\", ref.ref)\n\t\t;\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, ElementRef& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"ElementRef is not an object\");\n\tresult.ref = FromJson<std::string>(value.get(\"ELEMENT\"));\n\tif (result.ref == \"null\") {\n\t\tstd::stringstream element(value.serialize());\n\t\tstd::string segment;\n\t\tstd::vector<std::string> strArr;\n\t\twhile (std::getline(element, segment, ':')) {\n\t\t\tsegment.erase(std::remove(segment.begin(), segment.end(), '{'), segment.end());\n\t\t\tsegment.erase(std::remove(segment.begin(), segment.end(), '\"'), segment.end());\n\t\t\tsegment.erase(std::remove(segment.begin(), segment.end(), '}'), segment.end());\n\t\t\tstrArr.push_back(segment);\n\t\t}\n\t\tif (strArr.size() >= 1) {\n\t\t\tstd::stringstream ss;\n\t\t\tss << \"{\\\"ELEMENT\\\":\" << \"\\\"\" << strArr[1] << \"\\\"}\";\n\t\t\tpicojson::value jSon;\n\t\t\tpicojson::parse(jSon, ss);\n\t\t\tresult.ref = FromJson<std::string>(jSon.get(\"ELEMENT\"));\n\t\t}\n\t}\n}\n\ninline\nvoid CustomFromJson(const picojson::value& value, SessionRef& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"Session information is not an object\");\n\tresult.id = value.get(\"sessionId\").to_str();\n\tif (value.get(\"capabilities\").is<picojson::object>())\n\t\tresult.capabilities = Capabilities(value.get(\"capabilities\").get<picojson::object>());\n}\n\n} // namespace detail\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/element.h",
    "content": "#ifndef WEBDRIVERXX_ELEMENT_H\n#define WEBDRIVERXX_ELEMENT_H\n\n#include \"by.h\"\n#include \"types.h\"\n#include \"keys.h\"\n#include \"detail/shared.h\"\n#include \"detail/keyboard.h\"\n#include \"detail/resource.h\"\n#include \"detail/factories.h\"\n#include <string>\n#include <vector>\n\nnamespace webdriverxx {\n\n// An element from DOM\nclass Element { // copyable\npublic:\n\tElement();\n\t\n\tElement(\n\t\tconst std::string& ref,\n\t\tconst detail::Shared<detail::Resource>& resource,\n\t\tconst detail::Shared<detail::IFinderFactory>& factory\n\t\t);\n\n\tstd::string GetRef() const; // Returns ID that is used by Webdriver to identify elements\n\n\tbool IsDisplayed() const;\n\tbool IsEnabled() const;\n\tbool IsSelected() const;\n\tPoint GetLocation() const;\n\tPoint GetLocationInView() const;\n\tSize GetSize() const;\n\tstd::string GetAttribute(const std::string& name) const;\n\tstd::string GetCssProperty(const std::string& name) const;\n\tstd::string GetTagName() const;\n\tstd::string GetText() const;\n\n\tElement FindElement(const By& by) const;\n\tstd::vector<Element> FindElements(const By& by) const;\n\n\tconst Element& Clear() const;\n\tconst Element& Click() const;\n\tconst Element& Submit() const;\n\n\tconst Element& SendKeys(const std::string& keys) const;\n\tconst Element& SendKeys(const Shortcut& shortcut) const;\n\n\tbool Equals(const Element& other) const;\n\tbool operator != (const Element& other) const;\n\tbool operator == (const Element& other) const;\n\tbool operator < (const Element& other) const;\n\nprivate:\n\tdetail::Resource& GetResource() const;\n\tdetail::Keyboard GetKeyboard() const;\n\nprivate:\n\tstd::string ref_;\n\tdetail::Shared<detail::Resource> resource_;\n\tdetail::Shared<detail::IFinderFactory> factory_;\n};\n\n} // namespace webdriverxx\n\n#include \"element.inl\"\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/element.inl",
    "content": "#include \"conversions.h\"\n#include \"detail/finder.h\"\n#include \"detail/error_handling.h\"\n\nnamespace webdriverxx {\n\ninline\npicojson::value CustomToJson(const Element& element) {\n\tdetail::ElementRef ref = { element.GetRef() };\n\treturn ToJson(ref);\n}\n\ninline\nElement::Element() {}\n\ninline\nElement::Element(\n\tconst std::string& ref,\n\tconst detail::Shared<detail::Resource>& resource,\n\tconst detail::Shared<detail::IFinderFactory>& factory\n\t)\n\t: ref_(ref)\n\t, resource_(resource)\n\t, factory_(factory)\n{}\n\ninline\nstd::string Element::GetRef() const {\n\treturn ref_;\n}\n\ninline\nbool Element::IsDisplayed() const {\n\treturn GetResource().GetBool(\"displayed\");\n}\n\ninline\nbool Element::IsEnabled() const {\n\treturn GetResource().GetBool(\"enabled\");\n}\n\ninline\nbool Element::IsSelected() const {\n\treturn GetResource().GetBool(\"selected\");\n}\n\ninline\nPoint Element::GetLocation() const {\n\treturn GetResource().GetValue<Point>(\"location\");\n}\n\ninline\nPoint Element::GetLocationInView() const {\n\treturn GetResource().GetValue<Point>(\"location_in_view\");\n}\n\ninline\nSize Element::GetSize() const {\n\treturn GetResource().GetValue<Size>(\"size\");\n}\n\ninline\nstd::string Element::GetAttribute(const std::string& name) const {\n\treturn GetResource().GetString(std::string(\"attribute/\") + name);\n}\n\ninline\nstd::string Element::GetCssProperty(const std::string& name) const {\n\treturn GetResource().GetString(std::string(\"css/\") + name);\n}\n\ninline\nstd::string Element::GetTagName() const {\n\treturn GetResource().GetString(\"name\");\n}\ninline\nstd::string Element::GetText() const {\n\treturn GetResource().GetString(\"text\");\n}\n\ninline\nElement Element::FindElement(const By& by) const {\n\treturn factory_->MakeFinder(&GetResource()).FindElement(by);\n}\n\ninline\nstd::vector<Element> Element::FindElements(const By& by) const {\n\treturn factory_->MakeFinder(&GetResource()).FindElements(by);\n}\n\ninline\nconst Element& Element::Clear() const {\n\tGetResource().Post(\"clear\");\n\treturn *this;\n}\n\ninline\nconst Element& Element::Click() const {\n\tGetResource().Post(\"click\");\n\treturn *this;\n}\n\ninline\nconst Element& Element::Submit() const {\n\tGetResource().Post(\"submit\");\n\treturn *this;\n}\n\ninline\nconst Element& Element::SendKeys(const std::string& keys) const {\n\tGetKeyboard().SendKeys(keys);\n\treturn *this;\n}\n\ninline\nconst Element& Element::SendKeys(const Shortcut& shortcut) const {\n\tGetKeyboard().SendKeys(shortcut);\n\treturn *this;\n}\n\ninline\nbool Element::Equals(const Element& other) const {\n\treturn GetResource().GetBool(std::string(\"equals/\") + other.ref_);\n}\n\ninline\nbool Element::operator != (const Element& other) const {\n\treturn ref_ != other.ref_;\n}\n\ninline\nbool Element::operator == (const Element& other) const {\n\treturn ref_ == other.ref_;\n}\n\ninline\nbool Element::operator < (const Element& other) const {\n\treturn ref_ < other.ref_;\n}\n\ninline\ndetail::Resource& Element::GetResource() const {\n\tWEBDRIVERXX_CHECK(resource_, \"Attempt to use empty element\");\n\treturn *resource_;\n}\n\ninline\ndetail::Keyboard Element::GetKeyboard() const\n{\n\treturn detail::Keyboard(&GetResource(), \"value\");\n}\n\n} // namespace webdriverxx\n"
  },
  {
    "path": "include/webdriverxx/errors.h",
    "content": "#ifndef WEBDRIVERXX_ERRORS_H\n#define WEBDRIVERXX_ERRORS_H\n\n#include <stdexcept>\n#include <string>\n\nnamespace webdriverxx {\n\nstruct WebDriverException : std::runtime_error {\n\texplicit WebDriverException(const std::string& message)\n\t\t: std::runtime_error(message) {}\n};\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/js_args.h",
    "content": "#ifndef WEBDRIVERXX_JS_ARGS_H\n#define WEBDRIVERXX_JS_ARGS_H \n\n#include \"conversions.h\"\n#include \"picojson.h\"\n\nnamespace webdriverxx {\n\nclass Session;\n\nclass JsArgs // copyable\n{\npublic:\n\tJsArgs() : args_(picojson::array()) {}\n\n\t// This member works out of the box for scalar values, Elements and std::vector\n\t// with scalar values or Elements. Additional code is needed to use it\n\t// with custom objects and custom containers. Take a look\n\t// to the TestJsExecutor/CanPassArray, TestJsExecutor/CanPassCustomArray\n\t// and TestJsExecutor/CanPassCustomObjects tests to get details.\n\ttemplate<typename T>\n\tJsArgs& operator << (const T& arg) {\n\t\targs_.get<picojson::array>().push_back(ToJson(arg));\n\t\treturn *this;\n\t}\n\n\t// Alternative backdoor for passing custom data structures as arguments.\n\tJsArgs& operator << (const picojson::value& arg) {\n\t\targs_.get<picojson::array>().push_back(arg);\n\t\treturn *this;\n\t}\n\nprivate:\n\tfriend class Session;\n\tpicojson::value args_;\n};\n\n} // namespace webdriverxx \n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/keys.h",
    "content": "#ifndef WEBDRIVERXX_KEYS_H\n#define WEBDRIVERXX_KEYS_H \n\n#include <string>\n#include <vector>\n\nnamespace webdriverxx {\nnamespace keys { \n\nconst char *const Null = \"\\xee\\x80\\x80\";\nconst char *const Cancel = \"\\xee\\x80\\x81\";\nconst char *const Help = \"\\xee\\x80\\x82\";\nconst char *const Backspace = \"\\xee\\x80\\x83\";\nconst char *const Tab = \"\\xee\\x80\\x84\";\nconst char *const Clear = \"\\xee\\x80\\x85\";\nconst char *const Return = \"\\xee\\x80\\x86\";\nconst char *const Enter = \"\\xee\\x80\\x87\";\nconst char *const Shift = \"\\xee\\x80\\x88\";\nconst char *const Control = \"\\xee\\x80\\x89\";\nconst char *const Alt = \"\\xee\\x80\\x8a\";\nconst char *const Pause = \"\\xee\\x80\\x8b\";\nconst char *const Escape = \"\\xee\\x80\\x8c\";\nconst char *const Space = \"\\xee\\x80\\x8d\";\nconst char *const PageUp = \"\\xee\\x80\\x8e\";\nconst char *const PageDown = \"\\xee\\x80\\x8f\";\nconst char *const End = \"\\xee\\x80\\x90\";\nconst char *const Home = \"\\xee\\x80\\x91\";\nconst char *const Left = \"\\xee\\x80\\x92\";\nconst char *const Up = \"\\xee\\x80\\x93\";\nconst char *const Right = \"\\xee\\x80\\x94\";\nconst char *const Down = \"\\xee\\x80\\x95\";\nconst char *const Insert = \"\\xee\\x80\\x96\";\nconst char *const Delete = \"\\xee\\x80\\x97\";\nconst char *const Semicolon = \"\\xee\\x80\\x98\";\nconst char *const Equals = \"\\xee\\x80\\x99\";\nconst char *const Numpad0 = \"\\xee\\x80\\x9a\";\nconst char *const Numpad1 = \"\\xee\\x80\\x9b\";\nconst char *const Numpad2 = \"\\xee\\x80\\x9c\";\nconst char *const Numpad3 = \"\\xee\\x80\\x9d\";\nconst char *const Numpad4 = \"\\xee\\x80\\x9e\";\nconst char *const Numpad5 = \"\\xee\\x80\\x9f\";\nconst char *const Numpad6 = \"\\xee\\x80\\xa0\";\nconst char *const Numpad7 = \"\\xee\\x80\\xa1\";\nconst char *const Numpad8 = \"\\xee\\x80\\xa2\";\nconst char *const Numpad9 = \"\\xee\\x80\\xa3\";\nconst char *const Multiply = \"\\xee\\x80\\xa4\";\nconst char *const Add = \"\\xee\\x80\\xa5\";\nconst char *const Separator = \"\\xee\\x80\\xa6\";\nconst char *const Subtract = \"\\xee\\x80\\xa7\";\nconst char *const Decimal = \"\\xee\\x80\\xa8\";\nconst char *const Divide = \"\\xee\\x80\\xa9\";\nconst char *const F1 = \"\\xee\\x80\\xb1\";\nconst char *const F2 = \"\\xee\\x80\\xb2\";\nconst char *const F3 = \"\\xee\\x80\\xb3\";\nconst char *const F4 = \"\\xee\\x80\\xb4\";\nconst char *const F5 = \"\\xee\\x80\\xb5\";\nconst char *const F6 = \"\\xee\\x80\\xb6\";\nconst char *const F7 = \"\\xee\\x80\\xb7\";\nconst char *const F8 = \"\\xee\\x80\\xb8\";\nconst char *const F9 = \"\\xee\\x80\\xb9\";\nconst char *const F10 = \"\\xee\\x80\\xba\";\nconst char *const F11 = \"\\xee\\x80\\xbb\";\nconst char *const F12 = \"\\xee\\x80\\xbc\";\nconst char *const Command = \"\\xee\\x80\\xbd\";\nconst char *const Meta = Command;\n\n} // namespace keys \n\nnamespace detail {\nclass Keyboard;\n} // namespace detail\n\nclass Shortcut // copyable\n{\npublic:\n\tShortcut& operator << (const std::string& key) {\n\t\tkeys_.push_back(key);\n\t\treturn *this;\n\t}\n\n\tShortcut& operator << (const char* key) {\n\t\tkeys_.push_back(key);\n\t\treturn *this;\n\t}\n\nprivate:\n\tfriend class detail::Keyboard;\n\tstd::vector<std::string> keys_;\n};\n\n} // namespace webdriverxx \n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/picojson.h",
    "content": "/*\n * Copyright 2009-2010 Cybozu Labs, Inc.\n * Copyright 2011-2014 Kazuho Oku\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n#ifndef picojson_h\n#define picojson_h\n\n#include <algorithm>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <iterator>\n#include <limits>\n#include <map>\n#include <stdexcept>\n#include <string>\n#include <vector>\n\n// for isnan/isinf\n#if __cplusplus>=201103L\n# include <cmath>\n#else\nextern \"C\" {\n# ifdef _MSC_VER\n#  include <float.h>\n# elif defined(__INTEL_COMPILER)\n#  include <mathimf.h>\n# else\n#  include <math.h>\n# endif\n}\n#endif\n\n// experimental support for int64_t (see README.mkdn for detail)\n#ifdef PICOJSON_USE_INT64\n# define __STDC_FORMAT_MACROS\n# include <errno.h>\n# include <inttypes.h>\n#endif\n\n// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0\n#ifndef PICOJSON_USE_LOCALE\n# define PICOJSON_USE_LOCALE 1\n#endif\n#if PICOJSON_USE_LOCALE\nextern \"C\" {\n# include <locale.h>\n}\n#endif\n\n#ifndef PICOJSON_ASSERT\n# define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0)\n#endif\n\n#ifdef _MSC_VER\n    #define SNPRINTF _snprintf_s\n    #pragma warning(push)\n    #pragma warning(disable : 4244) // conversion from int to char\n    #pragma warning(disable : 4127) // conditional expression is constant\n    #pragma warning(disable : 4702) // unreachable code\n#else\n    #define SNPRINTF snprintf\n#endif\n\nnamespace picojson {\n  \n  enum {\n    null_type,\n    boolean_type,\n    number_type,\n    string_type,\n    array_type,\n    object_type\n#ifdef PICOJSON_USE_INT64\n    , int64_type\n#endif\n  };\n  \n  enum {\n    INDENT_WIDTH = 2\n  };\n\n  struct null {};\n  \n  class value {\n  public:\n    typedef std::vector<value> array;\n    typedef std::map<std::string, value> object;\n    union _storage {\n      bool boolean_;\n      double number_;\n#ifdef PICOJSON_USE_INT64\n      int64_t int64_;\n#endif\n      std::string* string_;\n      array* array_;\n      object* object_;\n    };\n  protected:\n    int type_;\n    _storage u_;\n  public:\n    value();\n    value(int type, bool);\n    explicit value(bool b);\n#ifdef PICOJSON_USE_INT64\n    explicit value(int64_t i);\n#endif\n    explicit value(double n);\n    explicit value(const std::string& s);\n    explicit value(const array& a);\n    explicit value(const object& o);\n    explicit value(const char* s);\n    value(const char* s, size_t len);\n    ~value();\n    value(const value& x);\n    value& operator=(const value& x);\n    void swap(value& x);\n    template <typename T> bool is() const;\n    template <typename T> const T& get() const;\n    template <typename T> T& get();\n    bool evaluate_as_boolean() const;\n    const value& get(size_t idx) const;\n    const value& get(const std::string& key) const;\n    value& get(size_t idx);\n    value& get(const std::string& key);\n\n    bool contains(size_t idx) const;\n    bool contains(const std::string& key) const;\n    std::string to_str() const;\n    template <typename Iter> void serialize(Iter os, bool prettify = false) const;\n    std::string serialize(bool prettify = false) const;\n  private:\n    template <typename T> value(const T*); // intentionally defined to block implicit conversion of pointer to bool\n    template <typename Iter> static void _indent(Iter os, int indent);\n    template <typename Iter> void _serialize(Iter os, int indent) const;\n    std::string _serialize(int indent) const;\n  };\n  \n  typedef value::array array;\n  typedef value::object object;\n  \n  inline value::value() : type_(null_type) {}\n  \n  inline value::value(int type, bool) : type_(type) {\n    switch (type) {\n#define INIT(p, v) case p##type: u_.p = v; break\n      INIT(boolean_, false);\n      INIT(number_, 0.0);\n#ifdef PICOJSON_USE_INT64\n      INIT(int64_, 0);\n#endif\n      INIT(string_, new std::string());\n      INIT(array_, new array());\n      INIT(object_, new object());\n#undef INIT\n    default: break;\n    }\n  }\n  \n  inline value::value(bool b) : type_(boolean_type) {\n    u_.boolean_ = b;\n  }\n\n#ifdef PICOJSON_USE_INT64\n  inline value::value(int64_t i) : type_(int64_type) {\n    u_.int64_ = i;\n  }\n#endif\n\n  inline value::value(double n) : type_(number_type) {\n    if (\n#ifdef _MSC_VER\n        ! _finite(n)\n#elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf))\n\t\tstd::isnan(n) || std::isinf(n)\n#else\n        isnan(n) || isinf(n)\n#endif\n        ) {\n      throw std::overflow_error(\"\");\n    }\n    u_.number_ = n;\n  }\n  \n  inline value::value(const std::string& s) : type_(string_type) {\n    u_.string_ = new std::string(s);\n  }\n  \n  inline value::value(const array& a) : type_(array_type) {\n    u_.array_ = new array(a);\n  }\n  \n  inline value::value(const object& o) : type_(object_type) {\n    u_.object_ = new object(o);\n  }\n  \n  inline value::value(const char* s) : type_(string_type) {\n    u_.string_ = new std::string(s);\n  }\n  \n  inline value::value(const char* s, size_t len) : type_(string_type) {\n    u_.string_ = new std::string(s, len);\n  }\n  \n  inline value::~value() {\n    switch (type_) {\n#define DEINIT(p) case p##type: delete u_.p; break\n      DEINIT(string_);\n      DEINIT(array_);\n      DEINIT(object_);\n#undef DEINIT\n    default: break;\n    }\n  }\n  \n  inline value::value(const value& x) : type_(x.type_) {\n    switch (type_) {\n#define INIT(p, v) case p##type: u_.p = v; break\n      INIT(string_, new std::string(*x.u_.string_));\n      INIT(array_, new array(*x.u_.array_));\n      INIT(object_, new object(*x.u_.object_));\n#undef INIT\n    default:\n      u_ = x.u_;\n      break;\n    }\n  }\n  \n  inline value& value::operator=(const value& x) {\n    if (this != &x) {\n      this->~value();\n      new (this) value(x);\n    }\n    return *this;\n  }\n  \n  inline void value::swap(value& x) {\n    std::swap(type_, x.type_);\n    std::swap(u_, x.u_);\n  }\n  \n#define IS(ctype, jtype)\t\t\t     \\\n  template <> inline bool value::is<ctype>() const { \\\n    return type_ == jtype##_type;\t\t     \\\n  }\n  IS(null, null)\n  IS(bool, boolean)\n#ifdef PICOJSON_USE_INT64\n  IS(int64_t, int64)\n#endif\n  IS(std::string, string)\n  IS(array, array)\n  IS(object, object)\n#undef IS\n  template <> inline bool value::is<double>() const {\n    return type_ == number_type\n#ifdef PICOJSON_USE_INT64\n      || type_ == int64_type\n#endif\n      ;\n  }\n  \n#define GET(ctype, var)\t\t\t\t\t\t\\\n  template <> inline const ctype& value::get<ctype>() const {\t\\\n    PICOJSON_ASSERT(\"type mismatch! call is<type>() before get<type>()\" \\\n\t   && is<ctype>());\t\t\t\t        \\\n    return var;\t\t\t\t\t\t\t\\\n  }\t\t\t\t\t\t\t\t\\\n  template <> inline ctype& value::get<ctype>() {\t\t\\\n    PICOJSON_ASSERT(\"type mismatch! call is<type>() before get<type>()\"\t\\\n\t   && is<ctype>());\t\t\t\t\t\\\n    return var;\t\t\t\t\t\t\t\\\n  }\n  GET(bool, u_.boolean_)\n  GET(std::string, *u_.string_)\n  GET(array, *u_.array_)\n  GET(object, *u_.object_)\n#ifdef PICOJSON_USE_INT64\n  GET(double, (type_ == int64_type && (const_cast<value*>(this)->type_ = number_type, const_cast<value*>(this)->u_.number_ = u_.int64_), u_.number_))\n  GET(int64_t, u_.int64_)\n#else\n  GET(double, u_.number_)\n#endif\n#undef GET\n  \n  inline bool value::evaluate_as_boolean() const {\n    switch (type_) {\n    case null_type:\n      return false;\n    case boolean_type:\n      return u_.boolean_;\n    case number_type:\n      return u_.number_ != 0;\n    case string_type:\n      return ! u_.string_->empty();\n    default:\n      return true;\n    }\n  }\n  \n  inline const value& value::get(size_t idx) const {\n    static value s_null;\n    PICOJSON_ASSERT(is<array>());\n    return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;\n  }\n\n  inline value& value::get(size_t idx) {\n    static value s_null;\n    PICOJSON_ASSERT(is<array>());\n    return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;\n  }\n\n  inline const value& value::get(const std::string& key) const {\n    static value s_null;\n    PICOJSON_ASSERT(is<object>());\n    object::const_iterator i = u_.object_->find(key);\n    return i != u_.object_->end() ? i->second : s_null;\n  }\n\n  inline value& value::get(const std::string& key) {\n    static value s_null;\n    PICOJSON_ASSERT(is<object>());\n    object::iterator i = u_.object_->find(key);\n    return i != u_.object_->end() ? i->second : s_null;\n  }\n\n  inline bool value::contains(size_t idx) const {\n    PICOJSON_ASSERT(is<array>());\n    return idx < u_.array_->size();\n  }\n\n  inline bool value::contains(const std::string& key) const {\n    PICOJSON_ASSERT(is<object>());\n    object::const_iterator i = u_.object_->find(key);\n    return i != u_.object_->end();\n  }\n  \n  inline std::string value::to_str() const {\n    switch (type_) {\n    case null_type:      return \"null\";\n    case boolean_type:   return u_.boolean_ ? \"true\" : \"false\";\n#ifdef PICOJSON_USE_INT64\n    case int64_type: {\n      char buf[sizeof(\"-9223372036854775808\")];\n      SNPRINTF(buf, sizeof(buf), \"%\" PRId64, u_.int64_);\n      return buf;\n    }\n#endif\n    case number_type:    {\n      char buf[256];\n      double tmp;\n      SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? \"%.f\" : \"%.17g\", u_.number_);\n#if PICOJSON_USE_LOCALE\n      char *decimal_point = localeconv()->decimal_point;\n      if (strcmp(decimal_point, \".\") != 0) {\n        size_t decimal_point_len = strlen(decimal_point);\n        for (char *p = buf; *p != '\\0'; ++p) {\n          if (strncmp(p, decimal_point, decimal_point_len) == 0) {\n            return std::string(buf, p) + \".\" + (p + decimal_point_len);\n          }\n        }\n      }\n#endif\n      return buf;\n    }\n    case string_type:    return *u_.string_;\n    case array_type:     return \"array\";\n    case object_type:    return \"object\";\n    default:             PICOJSON_ASSERT(0);\n#ifdef _MSC_VER\n      __assume(0);\n#endif\n    }\n    return std::string();\n  }\n  \n  template <typename Iter> void copy(const std::string& s, Iter oi) {\n    std::copy(s.begin(), s.end(), oi);\n  }\n  \n  template <typename Iter> void serialize_str(const std::string& s, Iter oi) {\n    *oi++ = '\"';\n    for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {\n      switch (*i) {\n#define MAP(val, sym) case val: copy(sym, oi); break\n\tMAP('\"', \"\\\\\\\"\");\n\tMAP('\\\\', \"\\\\\\\\\");\n\tMAP('/', \"\\\\/\");\n\tMAP('\\b', \"\\\\b\");\n\tMAP('\\f', \"\\\\f\");\n\tMAP('\\n', \"\\\\n\");\n\tMAP('\\r', \"\\\\r\");\n\tMAP('\\t', \"\\\\t\");\n#undef MAP\n      default:\n\tif (static_cast<unsigned char>(*i) < 0x20 || *i == 0x7f) {\n\t  char buf[7];\n\t  SNPRINTF(buf, sizeof(buf), \"\\\\u%04x\", *i & 0xff);\n\t  copy(buf, buf + 6, oi);\n\t  } else {\n\t  *oi++ = *i;\n\t}\n\tbreak;\n      }\n    }\n    *oi++ = '\"';\n  }\n\n  template <typename Iter> void value::serialize(Iter oi, bool prettify) const {\n    return _serialize(oi, prettify ? 0 : -1);\n  }\n  \n  inline std::string value::serialize(bool prettify) const {\n    return _serialize(prettify ? 0 : -1);\n  }\n\n  template <typename Iter> void value::_indent(Iter oi, int indent) {\n    *oi++ = '\\n';\n    for (int i = 0; i < indent * INDENT_WIDTH; ++i) {\n      *oi++ = ' ';\n    }\n  }\n\n  template <typename Iter> void value::_serialize(Iter oi, int indent) const {\n    switch (type_) {\n    case string_type:\n      serialize_str(*u_.string_, oi);\n      break;\n    case array_type: {\n      *oi++ = '[';\n      if (indent != -1) {\n        ++indent;\n      }\n      for (array::const_iterator i = u_.array_->begin();\n           i != u_.array_->end();\n           ++i) {\n\tif (i != u_.array_->begin()) {\n\t  *oi++ = ',';\n\t}\n        if (indent != -1) {\n          _indent(oi, indent);\n        }\n\ti->_serialize(oi, indent);\n      }\n      if (indent != -1) {\n        --indent;\n        if (! u_.array_->empty()) {\n          _indent(oi, indent);\n        }\n      }\n      *oi++ = ']';\n      break;\n    }\n    case object_type: {\n      *oi++ = '{';\n      if (indent != -1) {\n        ++indent;\n      }\n      for (object::const_iterator i = u_.object_->begin();\n\t   i != u_.object_->end();\n\t   ++i) {\n\tif (i != u_.object_->begin()) {\n\t  *oi++ = ',';\n\t}\n        if (indent != -1) {\n          _indent(oi, indent);\n        }\n\tserialize_str(i->first, oi);\n\t*oi++ = ':';\n        if (indent != -1) {\n          *oi++ = ' ';\n        }\n        i->second._serialize(oi, indent);\n      }\n      if (indent != -1) {\n        --indent;\n        if (! u_.object_->empty()) {\n          _indent(oi, indent);\n        }\n      }\n      *oi++ = '}';\n      break;\n    }\n    default:\n      copy(to_str(), oi);\n      break;\n    }\n    if (indent == 0) {\n      *oi++ = '\\n';\n    }\n  }\n  \n  inline std::string value::_serialize(int indent) const {\n    std::string s;\n    _serialize(std::back_inserter(s), indent);\n    return s;\n  }\n  \n  template <typename Iter> class input {\n  protected:\n    Iter cur_, end_;\n    int last_ch_;\n    bool ungot_;\n    int line_;\n  public:\n    input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}\n    int getc() {\n      if (ungot_) {\n\tungot_ = false;\n\treturn last_ch_;\n      }\n      if (cur_ == end_) {\n\tlast_ch_ = -1;\n\treturn -1;\n      }\n      if (last_ch_ == '\\n') {\n\tline_++;\n      }\n      last_ch_ = *cur_ & 0xff;\n      ++cur_;\n      return last_ch_;\n    }\n    void ungetc() {\n      if (last_ch_ != -1) {\n\tPICOJSON_ASSERT(! ungot_);\n\tungot_ = true;\n      }\n    }\n    Iter cur() const { return cur_; }\n    int line() const { return line_; }\n    void skip_ws() {\n      while (1) {\n\tint ch = getc();\n\tif (! (ch == ' ' || ch == '\\t' || ch == '\\n' || ch == '\\r')) {\n\t  ungetc();\n\t  break;\n\t}\n      }\n    }\n    bool expect(int expect) {\n      skip_ws();\n      if (getc() != expect) {\n\tungetc();\n\treturn false;\n      }\n      return true;\n    }\n    bool match(const std::string& pattern) {\n      for (std::string::const_iterator pi(pattern.begin());\n\t   pi != pattern.end();\n\t   ++pi) {\n\tif (getc() != *pi) {\n\t  ungetc();\n\t  return false;\n\t}\n      }\n      return true;\n    }\n  };\n  \n  template<typename Iter> inline int _parse_quadhex(input<Iter> &in) {\n    int uni_ch = 0, hex;\n    for (int i = 0; i < 4; i++) {\n      if ((hex = in.getc()) == -1) {\n\treturn -1;\n      }\n      if ('0' <= hex && hex <= '9') {\n\thex -= '0';\n      } else if ('A' <= hex && hex <= 'F') {\n\thex -= 'A' - 0xa;\n      } else if ('a' <= hex && hex <= 'f') {\n\thex -= 'a' - 0xa;\n      } else {\n\tin.ungetc();\n\treturn -1;\n      }\n      uni_ch = uni_ch * 16 + hex;\n    }\n    return uni_ch;\n  }\n  \n  template<typename String, typename Iter> inline bool _parse_codepoint(String& out, input<Iter>& in) {\n    int uni_ch;\n    if ((uni_ch = _parse_quadhex(in)) == -1) {\n      return false;\n    }\n    if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {\n      if (0xdc00 <= uni_ch) {\n\t// a second 16-bit of a surrogate pair appeared\n\treturn false;\n      }\n      // first 16-bit of surrogate pair, get the next one\n      if (in.getc() != '\\\\' || in.getc() != 'u') {\n\tin.ungetc();\n\treturn false;\n      }\n      int second = _parse_quadhex(in);\n      if (! (0xdc00 <= second && second <= 0xdfff)) {\n\treturn false;\n      }\n      uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);\n      uni_ch += 0x10000;\n    }\n    if (uni_ch < 0x80) {\n      out.push_back(uni_ch);\n    } else {\n      if (uni_ch < 0x800) {\n\tout.push_back(0xc0 | (uni_ch >> 6));\n      } else {\n\tif (uni_ch < 0x10000) {\n\t  out.push_back(0xe0 | (uni_ch >> 12));\n\t} else {\n\t  out.push_back(0xf0 | (uni_ch >> 18));\n\t  out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));\n\t}\n\tout.push_back(0x80 | ((uni_ch >> 6) & 0x3f));\n      }\n      out.push_back(0x80 | (uni_ch & 0x3f));\n    }\n    return true;\n  }\n  \n  template<typename String, typename Iter> inline bool _parse_string(String& out, input<Iter>& in) {\n    while (1) {\n      int ch = in.getc();\n      if (ch < ' ') {\n\tin.ungetc();\n\treturn false;\n      } else if (ch == '\"') {\n\treturn true;\n      } else if (ch == '\\\\') {\n\tif ((ch = in.getc()) == -1) {\n\t  return false;\n\t}\n\tswitch (ch) {\n#define MAP(sym, val) case sym: out.push_back(val); break\n\t  MAP('\"', '\\\"');\n\t  MAP('\\\\', '\\\\');\n\t  MAP('/', '/');\n\t  MAP('b', '\\b');\n\t  MAP('f', '\\f');\n\t  MAP('n', '\\n');\n\t  MAP('r', '\\r');\n\t  MAP('t', '\\t');\n#undef MAP\n\tcase 'u':\n\t  if (! _parse_codepoint(out, in)) {\n\t    return false;\n\t  }\n\t  break;\n\tdefault:\n\t  return false;\n\t}\n      } else {\n\tout.push_back(ch);\n      }\n    }\n    return false;\n  }\n  \n  template <typename Context, typename Iter> inline bool _parse_array(Context& ctx, input<Iter>& in) {\n    if (! ctx.parse_array_start()) {\n      return false;\n    }\n    size_t idx = 0;\n    if (in.expect(']')) {\n      return ctx.parse_array_stop(idx);\n    }\n    do {\n      if (! ctx.parse_array_item(in, idx)) {\n\treturn false;\n      }\n      idx++;\n    } while (in.expect(','));\n    return in.expect(']') && ctx.parse_array_stop(idx);\n  }\n  \n  template <typename Context, typename Iter> inline bool _parse_object(Context& ctx, input<Iter>& in) {\n    if (! ctx.parse_object_start()) {\n      return false;\n    }\n    if (in.expect('}')) {\n      return true;\n    }\n    do {\n      std::string key;\n      if (! in.expect('\"')\n\t  || ! _parse_string(key, in)\n\t  || ! in.expect(':')) {\n\treturn false;\n      }\n      if (! ctx.parse_object_item(in, key)) {\n\treturn false;\n      }\n    } while (in.expect(','));\n    return in.expect('}');\n  }\n  \n  template <typename Iter> inline std::string _parse_number(input<Iter>& in) {\n    std::string num_str;\n    while (1) {\n      int ch = in.getc();\n      if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-'\n          || ch == 'e' || ch == 'E') {\n        num_str.push_back(ch);\n      } else if (ch == '.') {\n#if PICOJSON_USE_LOCALE\n        num_str += localeconv()->decimal_point;\n#else\n        num_str.push_back('.');\n#endif\n      } else {\n\tin.ungetc();\n\tbreak;\n      }\n    }\n    return num_str;\n  }\n  \n  template <typename Context, typename Iter> inline bool _parse(Context& ctx, input<Iter>& in) {\n    in.skip_ws();\n    int ch = in.getc();\n    switch (ch) {\n#define IS(ch, text, op) case ch: \\\n      if (in.match(text) && op) { \\\n\treturn true; \\\n      } else { \\\n\treturn false; \\\n      }\n      IS('n', \"ull\", ctx.set_null());\n      IS('f', \"alse\", ctx.set_bool(false));\n      IS('t', \"rue\", ctx.set_bool(true));\n#undef IS\n    case '\"':\n      return ctx.parse_string(in);\n    case '[':\n      return _parse_array(ctx, in);\n    case '{':\n      return _parse_object(ctx, in);\n    default:\n      if (('0' <= ch && ch <= '9') || ch == '-') {\n        double f;\n        char *endp;\n\tin.ungetc();\n        std::string num_str = _parse_number(in);\n        if (num_str.empty()) {\n          return false;\n        }\n#ifdef PICOJSON_USE_INT64\n        {\n          errno = 0;\n          intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);\n          if (errno == 0\n              && std::numeric_limits<int64_t>::min() <= ival\n              && ival <= std::numeric_limits<int64_t>::max()\n              && endp == num_str.c_str() + num_str.size()) {\n            ctx.set_int64(ival);\n            return true;\n          }\n        }\n#endif\n        f = strtod(num_str.c_str(), &endp);\n        if (endp == num_str.c_str() + num_str.size()) {\n          ctx.set_number(f);\n          return true;\n        }\n        return false;\n      }\n      break;\n    }\n    in.ungetc();\n    return false;\n  }\n  \n  class deny_parse_context {\n  public:\n    bool set_null() { return false; }\n    bool set_bool(bool) { return false; }\n#ifdef PICOJSON_USE_INT64\n    bool set_int64(int64_t) { return false; }\n#endif\n    bool set_number(double) { return false; }\n    template <typename Iter> bool parse_string(input<Iter>&) { return false; }\n    bool parse_array_start() { return false; }\n    template <typename Iter> bool parse_array_item(input<Iter>&, size_t) {\n      return false;\n    }\n    bool parse_array_stop(size_t) { return false; }\n    bool parse_object_start() { return false; }\n    template <typename Iter> bool parse_object_item(input<Iter>&, const std::string&) {\n      return false;\n    }\n  };\n  \n  class default_parse_context {\n  protected:\n    value* out_;\n  public:\n    default_parse_context(value* out) : out_(out) {}\n    bool set_null() {\n      *out_ = value();\n      return true;\n    }\n    bool set_bool(bool b) {\n      *out_ = value(b);\n      return true;\n    }\n#ifdef PICOJSON_USE_INT64\n    bool set_int64(int64_t i) {\n      *out_ = value(i);\n      return true;\n    }\n#endif\n    bool set_number(double f) {\n      *out_ = value(f);\n      return true;\n    }\n    template<typename Iter> bool parse_string(input<Iter>& in) {\n      *out_ = value(string_type, false);\n      return _parse_string(out_->get<std::string>(), in);\n    }\n    bool parse_array_start() {\n      *out_ = value(array_type, false);\n      return true;\n    }\n    template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {\n      array& a = out_->get<array>();\n      a.push_back(value());\n      default_parse_context ctx(&a.back());\n      return _parse(ctx, in);\n    }\n    bool parse_array_stop(size_t) { return true; }\n    bool parse_object_start() {\n      *out_ = value(object_type, false);\n      return true;\n    }\n    template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string& key) {\n      object& o = out_->get<object>();\n      default_parse_context ctx(&o[key]);\n      return _parse(ctx, in);\n    }\n  private:\n    default_parse_context(const default_parse_context&);\n    default_parse_context& operator=(const default_parse_context&);\n  };\n\n  class null_parse_context {\n  public:\n    struct dummy_str {\n      void push_back(int) {}\n    };\n  public:\n    null_parse_context() {}\n    bool set_null() { return true; }\n    bool set_bool(bool) { return true; }\n#ifdef PICOJSON_USE_INT64\n    bool set_int64(int64_t) { return true; }\n#endif\n    bool set_number(double) { return true; }\n    template <typename Iter> bool parse_string(input<Iter>& in) {\n      dummy_str s;\n      return _parse_string(s, in);\n    }\n    bool parse_array_start() { return true; }\n    template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {\n      return _parse(*this, in);\n    }\n    bool parse_array_stop(size_t) { return true; }\n    bool parse_object_start() { return true; }\n    template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string&) {\n      return _parse(*this, in);\n    }\n  private:\n    null_parse_context(const null_parse_context&);\n    null_parse_context& operator=(const null_parse_context&);\n  };\n  \n  // obsolete, use the version below\n  template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) {\n    std::string err;\n    pos = parse(out, pos, last, &err);\n    return err;\n  }\n  \n  template <typename Context, typename Iter> inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) {\n    input<Iter> in(first, last);\n    if (! _parse(ctx, in) && err != NULL) {\n      char buf[64];\n      SNPRINTF(buf, sizeof(buf), \"syntax error at line %d near: \", in.line());\n      *err = buf;\n      while (1) {\n\tint ch = in.getc();\n\tif (ch == -1 || ch == '\\n') {\n\t  break;\n\t} else if (ch >= ' ') {\n\t  err->push_back(ch);\n\t}\n      }\n    }\n    return in.cur();\n  }\n  \n  template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) {\n    default_parse_context ctx(&out);\n    return _parse(ctx, first, last, err);\n  }\n  \n  inline std::string parse(value& out, std::istream& is) {\n    std::string err;\n    parse(out, std::istreambuf_iterator<char>(is.rdbuf()),\n\t  std::istreambuf_iterator<char>(), &err);\n    return err;\n  }\n  \n  template <typename T> struct last_error_t {\n    static std::string s;\n  };\n  template <typename T> std::string last_error_t<T>::s;\n  \n  inline void set_last_error(const std::string& s) {\n    last_error_t<bool>::s = s;\n  }\n  \n  inline const std::string& get_last_error() {\n    return last_error_t<bool>::s;\n  }\n\n  inline bool operator==(const value& x, const value& y) {\n    if (x.is<null>())\n      return y.is<null>();\n#define PICOJSON_CMP(type)\t\t\t\t\t\\\n    if (x.is<type>())\t\t\t\t\t\t\\\n      return y.is<type>() && x.get<type>() == y.get<type>()\n    PICOJSON_CMP(bool);\n    PICOJSON_CMP(double);\n    PICOJSON_CMP(std::string);\n    PICOJSON_CMP(array);\n    PICOJSON_CMP(object);\n#undef PICOJSON_CMP\n    PICOJSON_ASSERT(0);\n#ifdef _MSC_VER\n    __assume(0);\n#endif\n    return false;\n  }\n  \n  inline bool operator!=(const value& x, const value& y) {\n    return ! (x == y);\n  }\n}\n\nnamespace std {\n  template<> inline void swap(picojson::value& x, picojson::value& y)\n    {\n      x.swap(y);\n    }\n}\n\ninline std::istream& operator>>(std::istream& is, picojson::value& x)\n{\n  picojson::set_last_error(std::string());\n  std::string err = picojson::parse(x, is);\n  if (! err.empty()) {\n    picojson::set_last_error(err);\n    is.setstate(std::ios::failbit);\n  }\n  return is;\n}\n\ninline std::ostream& operator<<(std::ostream& os, const picojson::value& x)\n{\n  x.serialize(std::ostream_iterator<char>(os));\n  return os;\n}\n#ifdef _MSC_VER\n    #pragma warning(pop)\n#endif\n\n#endif\n#ifdef TEST_PICOJSON\n#ifdef _MSC_VER\n    #pragma warning(disable : 4127) // conditional expression is constant\n#endif\n\nusing namespace std;\n  \nstatic bool success = true;\nstatic int test_num = 0;\n\nstatic void ok(bool b, const char* name = \"\")\n{\n  if (! b)\n    success = false;\n  printf(\"%s %d - %s\\n\", b ? \"ok\" : \"ng\", ++test_num, name);\n}\n\nstatic void done_testing()\n{\n  printf(\"1..%d\\n\", test_num);\n}\n\ntemplate <typename T> void is(const T& x, const T& y, const char* name = \"\")\n{\n  if (x == y) {\n    ok(true, name);\n  } else {\n    ok(false, name);\n  }\n}\n\n#include <algorithm>\n#include <sstream>\n#include <float.h>\n#include <limits.h>\n\nint main(void)\n{\n#if PICOJSON_USE_LOCALE\n  setlocale(LC_ALL, \"\");\n#endif\n\n  // constructors\n#define TEST(expr, expected) \\\n    is(picojson::value expr .serialize(), string(expected), \"picojson::value\" #expr)\n  \n  TEST( (true),  \"true\");\n  TEST( (false), \"false\");\n  TEST( (42.0),   \"42\");\n  TEST( (string(\"hello\")), \"\\\"hello\\\"\");\n  TEST( (\"hello\"), \"\\\"hello\\\"\");\n  TEST( (\"hello\", 4), \"\\\"hell\\\"\");\n\n  {\n    double a = 1;\n    for (int i = 0; i < 1024; i++) {\n      picojson::value vi(a);\n      std::stringstream ss;\n      ss << vi;\n      picojson::value vo;\n      ss >> vo;\n      double b = vo.get<double>();\n      if ((i < 53 && a != b) || fabs(a - b) / b > 1e-8) {\n        printf(\"ng i=%d a=%.18e b=%.18e\\n\", i, a, b);\n      }\n      a *= 2;\n    }\n  }\n  \n#undef TEST\n  \n#define TEST(in, type, cmp, serialize_test) {\t\t\t\t\\\n    picojson::value v;\t\t\t\t\t\t\t\\\n    const char* s = in;\t\t\t\t\t\t\t\\\n    string err = picojson::parse(v, s, s + strlen(s));\t\t\t\\\n    ok(err.empty(), in \" no error\");\t\t\t\t\t\\\n    ok(v.is<type>(), in \" check type\");\t\t\t\t\t\\\n    is<type>(v.get<type>(), cmp, in \" correct output\");\t\t\t\\\n    is(*s, '\\0', in \" read to eof\");\t\t\t\t\t\\\n    if (serialize_test) {\t\t\t\t\t\t\\\n      is(v.serialize(), string(in), in \" serialize\");\t\t\t\\\n    }\t\t\t\t\t\t\t\t\t\\\n  }\n  TEST(\"false\", bool, false, true);\n  TEST(\"true\", bool, true, true);\n  TEST(\"90.5\", double, 90.5, false);\n  TEST(\"1.7976931348623157e+308\", double, DBL_MAX, false);\n  TEST(\"\\\"hello\\\"\", string, string(\"hello\"), true);\n  TEST(\"\\\"\\\\\\\"\\\\\\\\\\\\/\\\\b\\\\f\\\\n\\\\r\\\\t\\\"\", string, string(\"\\\"\\\\/\\b\\f\\n\\r\\t\"),\n       true);\n  TEST(\"\\\"\\\\u0061\\\\u30af\\\\u30ea\\\\u30b9\\\"\", string,\n       string(\"a\\xe3\\x82\\xaf\\xe3\\x83\\xaa\\xe3\\x82\\xb9\"), false);\n  TEST(\"\\\"\\\\ud840\\\\udc0b\\\"\", string, string(\"\\xf0\\xa0\\x80\\x8b\"), false);\n#ifdef PICOJSON_USE_INT64\n  TEST(\"0\", int64_t, 0, true);\n  TEST(\"-9223372036854775808\", int64_t, std::numeric_limits<int64_t>::min(), true);\n  TEST(\"9223372036854775807\", int64_t, std::numeric_limits<int64_t>::max(), true);\n#endif\n#undef TEST\n\n#define TEST(type, expr) {\t\t\t\t\t       \\\n    picojson::value v;\t\t\t\t\t\t       \\\n    const char *s = expr;\t\t\t\t\t       \\\n    string err = picojson::parse(v, s, s + strlen(s));\t\t       \\\n    ok(err.empty(), \"empty \" #type \" no error\");\t\t       \\\n    ok(v.is<picojson::type>(), \"empty \" #type \" check type\");\t       \\\n    ok(v.get<picojson::type>().empty(), \"check \" #type \" array size\"); \\\n  }\n  TEST(array, \"[]\");\n  TEST(object, \"{}\");\n#undef TEST\n  \n  {\n    picojson::value v;\n    const char *s = \"[1,true,\\\"hello\\\"]\";\n    string err = picojson::parse(v, s, s + strlen(s));\n    ok(err.empty(), \"array no error\");\n    ok(v.is<picojson::array>(), \"array check type\");\n    is(v.get<picojson::array>().size(), size_t(3), \"check array size\");\n    ok(v.contains(0), \"check contains array[0]\");\n    ok(v.get(0).is<double>(), \"check array[0] type\");\n    is(v.get(0).get<double>(), 1.0, \"check array[0] value\");\n    ok(v.contains(1), \"check contains array[1]\");\n    ok(v.get(1).is<bool>(), \"check array[1] type\");\n    ok(v.get(1).get<bool>(), \"check array[1] value\");\n    ok(v.contains(2), \"check contains array[2]\");\n    ok(v.get(2).is<string>(), \"check array[2] type\");\n    is(v.get(2).get<string>(), string(\"hello\"), \"check array[2] value\");\n    ok(!v.contains(3), \"check not contains array[3]\");\n  }\n  \n  {\n    picojson::value v;\n    const char *s = \"{ \\\"a\\\": true }\";\n    string err = picojson::parse(v, s, s + strlen(s));\n    ok(err.empty(), \"object no error\");\n    ok(v.is<picojson::object>(), \"object check type\");\n    is(v.get<picojson::object>().size(), size_t(1), \"check object size\");\n    ok(v.contains(\"a\"), \"check contains property\");\n    ok(v.get(\"a\").is<bool>(), \"check bool property exists\");\n    is(v.get(\"a\").get<bool>(), true, \"check bool property value\");\n    is(v.serialize(), string(\"{\\\"a\\\":true}\"), \"serialize object\");\n    ok(!v.contains(\"z\"), \"check not contains property\");\n  }\n\n#define TEST(json, msg) do {\t\t\t\t\\\n    picojson::value v;\t\t\t\t\t\\\n    const char *s = json;\t\t\t\t\\\n    string err = picojson::parse(v, s, s + strlen(s));\t\\\n    is(err, string(\"syntax error at line \" msg), msg);\t\\\n  } while (0)\n  TEST(\"falsoa\", \"1 near: oa\");\n  TEST(\"{]\", \"1 near: ]\");\n  TEST(\"\\n\\bbell\", \"2 near: bell\");\n  TEST(\"\\\"abc\\nd\\\"\", \"1 near: \");\n#undef TEST\n  \n  {\n    picojson::value v1, v2;\n    const char *s;\n    string err;\n    s = \"{ \\\"b\\\": true, \\\"a\\\": [1,2,\\\"three\\\"], \\\"d\\\": 2 }\";\n    err = picojson::parse(v1, s, s + strlen(s));\n    s = \"{ \\\"d\\\": 2.0, \\\"b\\\": true, \\\"a\\\": [1,2,\\\"three\\\"] }\";\n    err = picojson::parse(v2, s, s + strlen(s));\n    ok((v1 == v2), \"check == operator in deep comparison\");\n  }\n\n  {\n    picojson::value v1, v2;\n    const char *s;\n    string err;\n    s = \"{ \\\"b\\\": true, \\\"a\\\": [1,2,\\\"three\\\"], \\\"d\\\": 2 }\";\n    err = picojson::parse(v1, s, s + strlen(s));\n    s = \"{ \\\"d\\\": 2.0, \\\"a\\\": [1,\\\"three\\\"], \\\"b\\\": true }\";\n    err = picojson::parse(v2, s, s + strlen(s));\n    ok((v1 != v2), \"check != operator for array in deep comparison\");\n  }\n\n  {\n    picojson::value v1, v2;\n    const char *s;\n    string err;\n    s = \"{ \\\"b\\\": true, \\\"a\\\": [1,2,\\\"three\\\"], \\\"d\\\": 2 }\";\n    err = picojson::parse(v1, s, s + strlen(s));\n    s = \"{ \\\"d\\\": 2.0, \\\"a\\\": [1,2,\\\"three\\\"], \\\"b\\\": false }\";\n    err = picojson::parse(v2, s, s + strlen(s));\n    ok((v1 != v2), \"check != operator for object in deep comparison\");\n  }\n\n  {\n    picojson::value v1, v2;\n    const char *s;\n    string err;\n    s = \"{ \\\"b\\\": true, \\\"a\\\": [1,2,\\\"three\\\"], \\\"d\\\": 2 }\";\n    err = picojson::parse(v1, s, s + strlen(s));\n    picojson::object& o = v1.get<picojson::object>();\n    o.erase(\"b\");\n    picojson::array& a = o[\"a\"].get<picojson::array>();\n    picojson::array::iterator i;\n    i = std::remove(a.begin(), a.end(), picojson::value(std::string(\"three\")));\n    a.erase(i, a.end());\n    s = \"{ \\\"a\\\": [1,2], \\\"d\\\": 2 }\";\n    err = picojson::parse(v2, s, s + strlen(s));\n    ok((v1 == v2), \"check erase()\");\n  }\n\n  ok(picojson::value(3.0).serialize() == \"3\",\n     \"integral number should be serialized as a integer\");\n  \n  {\n    const char* s = \"{ \\\"a\\\": [1,2], \\\"d\\\": 2 }\";\n    picojson::null_parse_context ctx;\n    string err;\n    picojson::_parse(ctx, s, s + strlen(s), &err);\n    ok(err.empty(), \"null_parse_context\");\n  }\n  \n  {\n    picojson::value v1, v2;\n    v1 = picojson::value(true);\n    swap(v1, v2);\n    ok(v1.is<picojson::null>(), \"swap (null)\");\n    ok(v2.get<bool>() == true, \"swap (bool)\");\n\n    v1 = picojson::value(\"a\");\n    v2 = picojson::value(1.0);\n    swap(v1, v2);\n    ok(v1.get<double>() == 1.0, \"swap (dobule)\");\n    ok(v2.get<string>() == \"a\", \"swap (string)\");\n\n    v1 = picojson::value(picojson::object());\n    v2 = picojson::value(picojson::array());\n    swap(v1, v2);\n    ok(v1.is<picojson::array>(), \"swap (array)\");\n    ok(v2.is<picojson::object>(), \"swap (object)\");\n  }\n  \n  {\n    picojson::value v;\n    const char *s = \"{ \\\"a\\\": 1, \\\"b\\\": [ 2, { \\\"b1\\\": \\\"abc\\\" } ], \\\"c\\\": {}, \\\"d\\\": [] }\";\n    string err;\n    err = picojson::parse(v, s, s + strlen(s));\n    ok(err.empty(), \"parse test data for prettifying output\");\n    ok(v.serialize() == \"{\\\"a\\\":1,\\\"b\\\":[2,{\\\"b1\\\":\\\"abc\\\"}],\\\"c\\\":{},\\\"d\\\":[]}\", \"non-prettifying output\");\n    ok(v.serialize(true) == \"{\\n  \\\"a\\\": 1,\\n  \\\"b\\\": [\\n    2,\\n    {\\n      \\\"b1\\\": \\\"abc\\\"\\n    }\\n  ],\\n  \\\"c\\\": {},\\n  \\\"d\\\": []\\n}\\n\", \"prettifying output\");\n  }\n\n  try {\n    picojson::value v(std::numeric_limits<double>::quiet_NaN());\n    ok(false, \"should not accept NaN\");\n  } catch (std::overflow_error e) {\n    ok(true, \"should not accept NaN\");\n  }\n\n  try {\n    picojson::value v(std::numeric_limits<double>::infinity());\n    ok(false, \"should not accept infinity\");\n  } catch (std::overflow_error e) {\n    ok(true, \"should not accept infinity\");\n  }\n\n  try {\n    picojson::value v(123.);\n    ok(! v.is<bool>(), \"is<wrong_type>() should return false\");\n    v.get<bool>();\n    ok(false, \"get<wrong_type>() should raise an error\");\n  } catch (std::runtime_error e) {\n    ok(true, \"get<wrong_type>() should raise an error\");\n  }\n\n#ifdef PICOJSON_USE_INT64\n  {\n    picojson::value v1((int64_t)123);\n    ok(v1.is<int64_t>(), \"is int64_t\");\n    ok(v1.is<double>(), \"is double as well\");\n    ok(v1.serialize() == \"123\", \"serialize the value\");\n    ok(v1.get<int64_t>() == 123, \"value is correct as int64_t\");\n    ok(v1.get<double>(), \"value is correct as double\");\n\n    ok(! v1.is<int64_t>(), \"is no more int64_type once get<double>() is called\");\n    ok(v1.is<double>(), \"and is still a double\");\n\n    const char *s = \"-9223372036854775809\";\n    ok(picojson::parse(v1, s, s + strlen(s)).empty(), \"parse underflowing int64_t\");\n    ok(! v1.is<int64_t>(), \"underflowing int is not int64_t\");\n    ok(v1.is<double>(), \"underflowing int is double\");\n    ok(v1.get<double>() + 9.22337203685478e+18 < 65536, \"double value is somewhat correct\");\n  }\n#endif\n\n  done_testing();\n\n  return success ? 0 : 1;\n}\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/response_status_code.h",
    "content": "#ifndef WEBDRIVERXX_RESPONSE_STATUS_CODE_H\n#define WEBDRIVERXX_RESPONSE_STATUS_CODE_H \n\nnamespace webdriverxx {\nnamespace response_status_code { \n\nenum Value {\n\tkSuccess = 0,\n\tkNoSuchDriver = 6,\n\tkNoSuchElement = 7,\n\tkNoSuchFrame = 8,\n\tkUnknownCommand = 9,\n\tkStaleElementReference = 10,\n\tkElementNotVisible = 11,\n\tkInvalidElementState = 12,\n\tkUnknownError = 13,\n\tkElementIsNotSelectable = 15,\n\tkJavaScriptError = 17,\n\tkXPathLookupError = 19,\n\tkTimeout = 21,\n\tkNoSuchWindow = 23,\n\tkInvalidCookieDomain = 24,\n\tkUnableToSetCookie = 25,\n\tkUnexpectedAlertOpen = 26,\n\tkNoAlertOpenError = 27,\n\tkScriptTimeout = 28,\n\tkInvalidElementCoordinates = 29,\n\tkIMENotAvailable = 30,\n\tkIMEEngineActivationFailed = 31,\n\tkInvalidSelector = 32,\n\tkSessionNotCreatedException = 33,\n\tkMoveTargetOutOfBounds = 34\n}; \n\ninline\nconst char* ToString(Value code) {\n\tswitch(code) {\n\tcase kSuccess: return \"The command executed successfully.\";\n\tcase kNoSuchDriver: return \"A session is either terminated or not started\"; \n\tcase kNoSuchElement: return \"An element could not be located on the page using the given search parameters.\"; \n\tcase kNoSuchFrame: return \"A request to switch to a frame could not be satisfied because the frame could not be found.\"; \n\tcase kUnknownCommand: return \"The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource.\"; \n\tcase kStaleElementReference: return \"An element command failed because the referenced element is no longer attached to the DOM.\"; \n\tcase kElementNotVisible: return \"An element command could not be completed because the element is not visible on the page.\"; \n\tcase kInvalidElementState: return \"An element command could not be completed because the element is in an invalid state (e.g. attempting to click a disabled element).\"; \n\tcase kUnknownError: return \"An unknown server-side error occurred while processing the command.\"; \n\tcase kElementIsNotSelectable: return \"An attempt was made to select an element that cannot be selected.\"; \n\tcase kJavaScriptError: return \"An error occurred while executing user supplied JavaScript.\"; \n\tcase kXPathLookupError: return \"An error occurred while searching for an element by XPath.\"; \n\tcase kTimeout: return \"An operation did not complete before its timeout expired.\"; \n\tcase kNoSuchWindow: return \"A request to switch to a different window could not be satisfied because the window could not be found.\"; \n\tcase kInvalidCookieDomain: return \"An illegal attempt was made to set a cookie under a different domain than the current page.\"; \n\tcase kUnableToSetCookie: return \"A request to set a cookie's value could not be satisfied.\"; \n\tcase kUnexpectedAlertOpen: return \"A modal dialog was open, blocking this operation\"; \n\tcase kNoAlertOpenError: return \"An attempt was made to operate on a modal dialog when one was not open.\"; \n\tcase kScriptTimeout: return \"A script did not complete before its timeout expired.\"; \n\tcase kInvalidElementCoordinates: return \"The coordinates provided to an interactions operation are invalid.\"; \n\tcase kIMENotAvailable: return \"IME was not available.\"; \n\tcase kIMEEngineActivationFailed: return \"An IME engine could not be started.\"; \n\tcase kInvalidSelector: return \"Argument was an invalid selector (e.g. XPath/CSS).\";\n\tcase kSessionNotCreatedException: return \"A new session could not be created.\";\n\tcase kMoveTargetOutOfBounds: return \"Target provided for a move action is out of bounds.\";\n\t}\n\treturn \"Unknown\";\n} \n\n} // namespace response_status_code \n} // namespace webdriverxx \n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/session.h",
    "content": "#ifndef WEBDRIVERXX_SESSION_H\n#define WEBDRIVERXX_SESSION_H\n\n#include \"element.h\"\n#include \"window.h\"\n#include \"by.h\"\n#include \"capabilities.h\"\n#include \"keys.h\"\n#include \"js_args.h\"\n#include \"detail/resource.h\"\n#include \"detail/keyboard.h\"\n#include \"detail/shared.h\"\n#include \"detail/factories_impl.h\"\n#include \"picojson.h\"\n#include <string>\n\nnamespace webdriverxx {\n\nclass Client;\n\nclass Session { // copyable\npublic:\t\n\tCapabilities GetCapabilities() const;\n\tstd::string GetSource() const;\n\tstd::string GetTitle() const;\n\tstd::string GetUrl() const;\n\tstd::string GetScreenshot() const; // Base64 PNG\n\n\tconst Session& Navigate(const std::string& url) const;\n\tconst Session& Get(const std::string& url) const; // Same as Navigate\n\tconst Session& Forward() const;\n\tconst Session& Back() const;\n\tconst Session& Refresh() const;\n\n\tconst Session& Execute(const std::string& script, const JsArgs& args = JsArgs()) const;\n\ttemplate<typename T>\n\tT Eval(const std::string& script, const JsArgs& args = JsArgs()) const;\n\tconst Session& ExecuteAsync(const std::string& script, const JsArgs& args = JsArgs()) const;\n\ttemplate<typename T>\n\tT EvalAsync(const std::string& script, const JsArgs& args = JsArgs()) const;\n\n\tconst Session& SetFocusToFrame(const Element& frame) const;\n\tconst Session& SetFocusToFrame(const std::string& id) const;\n\tconst Session& SetFocusToFrame(int number) const;\n\tconst Session& SetFocusToDefaultFrame() const;\n\tconst Session& SetFocusToParentFrame() const;\n\n\tstd::vector<Window> GetWindows() const;\n\tWindow GetCurrentWindow() const;\n\tconst Session& CloseCurrentWindow() const;\n\tconst Session& SetFocusToWindow(const std::string& window_name) const;\n\tconst Session& SetFocusToWindow(const Window& window) const;\n\t\n\tElement GetActiveElement() const;\n\n\tElement FindElement(const By& by) const;\n\tstd::vector<Element> FindElements(const By& by) const;\n\n\tstd::vector<Cookie> GetCookies() const;\n\tconst Session& SetCookie(const Cookie& cookie) const;\n\tconst Session& DeleteCookies() const;\n\tconst Session& DeleteCookie(const std::string& name) const;\n\n\tstd::string GetAlertText() const;\n\tconst Session& SendKeysToAlert(const std::string& text) const;\n\tconst Session& AcceptAlert() const;\n\tconst Session& DismissAlert() const;\n\n\tconst Session& SendKeys(const std::string& keys) const;\n\tconst Session& SendKeys(const Shortcut& shortcut) const;\n\n\tconst Session& MoveToTopLeftOf(const Element&, const Offset& = Offset()) const;\n\tconst Session& MoveToCenterOf(const Element&) const;\n\tconst Session& MoveTo(const Offset&) const;\n\tconst Session& Click(mouse::Button = mouse::LeftButton) const;\n\tconst Session& DoubleClick() const;\n\tconst Session& ButtonDown(mouse::Button = mouse::LeftButton) const;\n\tconst Session& ButtonUp(mouse::Button = mouse::LeftButton) const;\n\n\tconst Session& SetTimeoutMs(timeout::Type type, int milliseconds);\n\tconst Session& SetImplicitTimeoutMs(int milliseconds);\n\tconst Session& SetAsyncScriptTimeoutMs(int milliseconds);\n\n\tvoid DeleteSession() const; // No need to delete sessions created by WebDriver or Client\n\tvirtual ~Session() {}\n\nprivate:\n\tfriend class Client; // Only Client can create Sessions\n\n\texplicit Session(const detail::Shared<detail::Resource>& resource);\n\n\tWindow MakeWindow(const std::string& handle) const;\n\tdetail::Keyboard GetKeyboard() const;\n\ttemplate<typename T>\n\tvoid InternalEval(const std::string& webdriver_command,\n\t\tconst std::string& script, const JsArgs& args,\n\t\tT& result) const;\n\tvoid InternalEval(const std::string& webdriver_command,\n\t\tconst std::string& script, const JsArgs& args,\n\t\tElement& result) const;\n\tpicojson::value InternalEvalJsonValue(const std::string& command,\n\t\tconst std::string& script, const JsArgs& args) const;\n\tconst Session& InternalSetFocusToFrame(const picojson::value& id) const;\n\tconst Session& InternalMoveTo(const Element*, const Offset*) const;\n\tconst Session& InternalMouseButtonCommand(const char* command, mouse::Button button) const;\n\nprivate:\n\tdetail::Shared<detail::Resource> resource_;\n\tdetail::Shared<detail::SessionFactory> factory_;\n};\n\n} // namespace webdriverxx\n\n#include \"session.inl\"\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/session.inl",
    "content": "#include \"conversions.h\"\n#include \"detail/error_handling.h\"\n#include \"detail/types.h\"\n#include <algorithm>\n\nnamespace webdriverxx {\n\ninline\nSession::Session(const detail::Shared<detail::Resource>& resource)\n\t: resource_(resource)\n\t, factory_(new detail::SessionFactory(resource))\n{}\n\ninline\nvoid Session::DeleteSession() const {\n\tresource_->Delete();\n}\n\ninline\nCapabilities Session::GetCapabilities() const {\n\treturn Capabilities(resource_->Get().get<picojson::object>());\n}\n\ninline\nstd::string Session::GetSource() const {\n\treturn resource_->GetString(\"source\");\n}\n\ninline\nstd::string Session::GetTitle() const {\n\treturn resource_->GetString(\"title\");\n}\n\ninline\nstd::string Session::GetUrl() const {\n\treturn resource_->GetString(\"url\");\n}\n\ninline\nstd::string Session::GetScreenshot() const {\n\treturn resource_->GetString(\"screenshot\");\n}\n\ninline\nconst Session& Session::SetTimeoutMs(timeout::Type type, int milliseconds) {\n\tresource_->Post(\"timeouts\",\n\t\tJsonObject()\n\t\t\t.Set(\"type\", type)\n\t\t\t.Set(\"ms\", milliseconds)\n\t\t);\n\treturn *this;\n}\n\ninline\nconst Session& Session::SetImplicitTimeoutMs(int milliseconds) {\n\tresource_->Post(\"timeouts/implicit_wait\",\n\t\tJsonObject().Set(\"ms\", milliseconds));\n\treturn *this;\n}\n\ninline\nconst Session& Session::SetAsyncScriptTimeoutMs(int milliseconds) {\n\tresource_->Post(\"timeouts/async_script\",\n\t\tJsonObject().Set(\"ms\", milliseconds));\n\treturn *this;\n}\n\ninline\nWindow Session::GetCurrentWindow() const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\treturn MakeWindow(resource_->GetString(\"window_handle\"));\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END()\n}\n\ninline\nconst Session& Session::CloseCurrentWindow() const {\n\tresource_->Delete(\"window\");\n\treturn *this;\n}\n\ninline\nconst Session& Session::Navigate(const std::string& url) const {\n\tresource_->Post(\"url\", \"url\", url);\n\treturn *this;\n}\n\ninline\nconst Session& Session::Get(const std::string& url) const {\n\treturn Navigate(url);\n}\n\ninline\nconst Session& Session::Forward() const {\n\tresource_->Post(\"forward\");\n\treturn *this;\n}\n\ninline\nconst Session& Session::Back() const {\n\tresource_->Post(\"back\");\n\treturn *this;\n}\n\ninline\nconst Session& Session::Refresh() const {\n\tresource_->Post(\"refresh\");\n\treturn *this;\n}\n\ninline\nconst Session& Session::Execute(const std::string& script, const JsArgs& args) const {\n\tInternalEvalJsonValue(\"execute\", script, args);\n\treturn *this;\n}\n\ntemplate<typename T>\nT Session::Eval(const std::string& script, const JsArgs& args) const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\tT result = T();\n\tInternalEval(\"execute\", script, args, result);\n\treturn result;\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END_EX(detail::Fmt()\n\t\t<< \"script: \" << script\n\t\t)\n}\n\ninline\nconst Session& Session::ExecuteAsync(const std::string& script, const JsArgs& args) const {\n\tInternalEvalJsonValue(\"execute_async\", script, args);\n\treturn *this;\n}\n\ntemplate<typename T>\nT Session::EvalAsync(const std::string& script, const JsArgs& args) const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\tT result;\n\tInternalEval(\"execute_async\", script, args, result);\n\treturn result;\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END_EX(detail::Fmt()\n\t\t<< \"script: \" << script\n\t\t)\n}\n\ninline\nconst Session& Session::SetFocusToWindow(const std::string& window_name_or_handle) const {\n\tresource_->Post(\"window\", \"name\", window_name_or_handle);\n\treturn *this;\n}\n\ninline\nconst Session& Session::SetFocusToWindow(const Window& window) const {\n\tSetFocusToWindow(window.GetHandle());\n\treturn *this;\n}\n\ninline\nconst Session& Session::SetFocusToFrame(const Element& frame) const {\n\treturn InternalSetFocusToFrame(ToJson(frame));\n}\n\ninline\nconst Session& Session::SetFocusToFrame(const std::string& id) const {\n\treturn InternalSetFocusToFrame(ToJson(id));\n}\n\ninline\nconst Session& Session::SetFocusToFrame(int number) const {\n\treturn InternalSetFocusToFrame(ToJson(number));\n}\n\ninline\nconst Session& Session::SetFocusToDefaultFrame() const {\n\treturn InternalSetFocusToFrame(picojson::value());\n}\n\ninline\nconst Session& Session::SetFocusToParentFrame() const {\n\tresource_->Post(\"frame/parent\");\n\treturn *this;\n}\n\ninline\nconst Session& Session::InternalSetFocusToFrame(const picojson::value& id) const {\n\tresource_->Post(\"frame\", JsonObject().Set(\"id\", id));\n\treturn *this;\n}\n\ninline\nstd::vector<Window> Session::GetWindows() const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\tconst auto handles =\n\t\tFromJson<std::vector<std::string>>(\n\t\t\tresource_->Get(\"window_handles\")\n\t\t\t);\n\tstd::vector<Window> result;\n\tresult.reserve(handles.size());\n\tstd::transform(handles.begin(), handles.end(), std::back_inserter(result),\n\t\t[this](const std::string& window_handle){\n\t\t\treturn MakeWindow(window_handle);\n\t\t});\n\treturn result;\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END()\n}\n\ninline\nElement Session::GetActiveElement() const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\treturn factory_->MakeElement(FromJson<detail::ElementRef>(resource_->Post(\"element/active\")).ref);\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END()\n}\n\ninline\nElement Session::FindElement(const By& by) const {\n\treturn factory_->MakeFinder(resource_).FindElement(by);\n}\n\ninline\nstd::vector<Element> Session::FindElements(const By& by) const {\n\treturn factory_->MakeFinder(resource_).FindElements(by);\n}\n\ninline\nstd::vector<Cookie> Session::GetCookies() const {\n\tWEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()\n\treturn FromJson<std::vector<Cookie>>(resource_->Get(\"cookie\"));\n\tWEBDRIVERXX_FUNCTION_CONTEXT_END()\n}\n\ninline\nconst Session& Session::SetCookie(const Cookie& cookie) const {\n\tresource_->Post(\"cookie\", JsonObject()\n\t\t.Set(\"cookie\", ToJson(cookie)));\n\treturn *this;\n}\n\ninline\nconst Session& Session::DeleteCookies() const {\n\tresource_->Delete(\"cookie\");\n\treturn *this;\n}\n\ninline\nconst Session& Session::DeleteCookie(const std::string& name) const {\n\tresource_->Delete(std::string(\"cookie/\") + name);\n\treturn *this;\n}\n\ninline\nstd::string Session::GetAlertText() const {\n\treturn resource_->GetString(\"alert_text\");\n}\n\ninline\nconst Session& Session::SendKeysToAlert(const std::string& text) const {\n\tresource_->Post(\"alert_text\", \"text\", text);\n\treturn *this;\n}\n\ninline\nconst Session& Session::AcceptAlert() const {\n\tresource_->Post(\"accept_alert\");\n\treturn *this;\n}\n\ninline\nconst Session& Session::DismissAlert() const {\n\tresource_->Post(\"dismiss_alert\");\n\treturn *this;\n}\n\ninline\nconst Session& Session::SendKeys(const std::string& keys) const {\n\tGetKeyboard().SendKeys(keys);\n\treturn *this;\n}\n\ninline\nconst Session& Session::SendKeys(const Shortcut& shortcut) const {\n\tGetKeyboard().SendKeys(shortcut);\n\treturn *this;\n}\n\ninline\nconst Session& Session::MoveToTopLeftOf(const Element& element, const Offset& offset) const {\n\treturn InternalMoveTo(&element, &offset);\n}\n\ninline\nconst Session& Session::MoveToCenterOf(const Element& element) const {\n\treturn InternalMoveTo(&element, nullptr);\n}\n\ninline\nconst Session& Session::MoveTo(const Offset& offset) const {\n\treturn InternalMoveTo(nullptr, &offset);\n}\n\ninline\nconst Session& Session::InternalMoveTo(\n\tconst Element* element,\n\tconst Offset* offset\n\t) const {\n\tJsonObject args;\n\tif (element)\n\t\targs.Set(\"element\", element->GetRef());\n\tif (offset) {\n\t\targs.Set(\"xoffset\", offset->x);\n\t\targs.Set(\"yoffset\", offset->y);\n\t}\n\tresource_->Post(\"moveto\", args);\n\treturn *this;\n}\n\ninline\nconst Session& Session::Click(mouse::Button button) const {\n\treturn InternalMouseButtonCommand(\"click\", button);\n}\n\ninline\nconst Session& Session::DoubleClick() const {\n\tresource_->Post(\"doubleclick\");\n\treturn *this;\n}\n\ninline\nconst Session& Session::ButtonDown(mouse::Button button) const {\n\treturn InternalMouseButtonCommand(\"buttondown\", button);\n}\n\ninline\nconst Session& Session::ButtonUp(mouse::Button button) const {\n\treturn InternalMouseButtonCommand(\"buttonup\", button);\n}\n\ninline\nconst Session& Session::InternalMouseButtonCommand(const char* command, mouse::Button button) const {\n\tresource_->Post(command, \"button\", static_cast<int>(button));\n\treturn *this;\n}\n\ninline\nWindow Session::MakeWindow(const std::string& handle) const {\n\treturn Window(handle,\n\t\tdetail::MakeSubResource(resource_, \"window\", handle)\n\t\t);\n}\n\ninline\ndetail::Keyboard Session::GetKeyboard() const\n{\n\treturn detail::Keyboard(resource_, \"keys\");\n}\n\ntemplate<typename T>\nvoid Session::InternalEval(const std::string& webdriver_command,\n\tconst std::string& script, const JsArgs& args,\n\tT& result) const {\n\tresult = FromJson<T>(InternalEvalJsonValue(webdriver_command, script, args));\n}\n\ninline\nvoid Session::InternalEval(const std::string& webdriver_command,\n\tconst std::string& script, const JsArgs& args,\n\tElement& result) const {\n\tdetail::ElementRef element_ref;\n\tInternalEval(webdriver_command, script, args, element_ref);\n\tresult = factory_->MakeElement(element_ref.ref);\n}\n\ninline\npicojson::value Session::InternalEvalJsonValue(\n\tconst std::string& webdriver_command,\n\tconst std::string& script,\n\tconst JsArgs& args\n\t) const {\n\treturn resource_->Post(webdriver_command,\n\t\tJsonObject()\n\t\t\t.Set(\"script\", script)\n\t\t\t.Set(\"args\", args.args_)\n\t\t);\n}\n\n} // namespace webdriverxx\n"
  },
  {
    "path": "include/webdriverxx/types.h",
    "content": "#ifndef WEBDRIVERXX_TYPES_H\n#define WEBDRIVERXX_TYPES_H\n\n#include <string>\n\nnamespace webdriverxx {\n\ntypedef unsigned long long TimePoint;\ntypedef unsigned Duration;\n\nstruct Size {\n\tint width;\n\tint height;\n\tSize() : width(0), height(0) {}\n};\n\nstruct Point {\n\tint x;\n\tint y;\n\tPoint() : x(0), y(0) {}\n\tPoint(int x, int y) : x(x), y(y) {}\n};\n\ntypedef Point Offset;\n\nstruct Cookie {\n\tenum {\n\t\tNoExpiry = 0\n\t};\n\n\tstd::string name;\n\tstd::string value;\n\tstd::string path;\n\tstd::string domain;\n\tbool secure;\n\tbool http_only;\n\tint expiry; // seconds since midnight, January 1, 1970 UTC\n\n\tCookie() : secure(false), http_only(false), expiry(NoExpiry) {}\n\tCookie(\n\t\tconst std::string& name,\n\t\tconst std::string& value,\n\t\tconst std::string& path = std::string(),\n\t\tconst std::string& domain = std::string(),\n\t\tbool secure = false,\n\t\tbool http_only = false,\n\t\tint expiry = NoExpiry\n\t\t)\n\t\t: name(name)\n\t\t, value(value)\n\t\t, path(path)\n\t\t, domain(domain)\n\t\t, secure(secure)\n\t\t, http_only(http_only)\n\t\t, expiry(expiry)\n\t{}\n\n\tbool operator == (const Cookie& c) const {\n\t\treturn name == c.name\n\t\t\t&& value == c.value\n\t\t\t&& path == c.path\n\t\t\t&& domain == c.domain\n\t\t\t&& secure == c.secure\n\t\t\t&& http_only == c.http_only\n\t\t\t&& expiry == c.expiry\n\t\t\t;\n\t}\n};\n\nnamespace timeout {\n\ntypedef const char* Type;\n\nType const Implicit = \"implicit\";\nType const PageLoad = \"page load\";\nType const Script = \"script\";\n\n} // namespace timeout\n\nnamespace mouse {\nenum Button {\n\tLeftButton = 0,\n\tMiddleButton = 1,\n\tRightButton = 2\n};\n} // namespace mouse\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/wait.h",
    "content": "#ifndef WEBDRIVERXX_WAIT_H\n#define WEBDRIVERXX_WAIT_H\n\n#include \"detail/error_handling.h\"\n#include \"detail/time.h\"\n#include \"detail/to_string.h\"\n#include <string>\n#include <memory>\n\nnamespace webdriverxx {\nnamespace detail {\n\ntemplate<typename Value, typename DescriptiveGetter>\nValue Wait(\n\tDescriptiveGetter getter,\n\tDuration timeoutMs = 5000,\n\tDuration intervalMs = 50\n\t) {\n\tconst TimePoint timeout = detail::Now() + timeoutMs;\n\tfor (;;) {\n\t\tconst auto value_ptr = getter(nullptr);\n\t\tif (value_ptr)\n\t\t\treturn *value_ptr;\n\t\tif (detail::Now() >= timeout) {\n\t\t\tstd::string description;\n\t\t\tconst auto value_ptr = getter(&description);\n\t\t\tif (value_ptr)\n\t\t\t\treturn *value_ptr;\n\t\t\tthrow WebDriverException(detail::Fmt()\n\t\t\t\t<< \"Timeout after \" << timeoutMs << \"ms of waiting, last attempt returned: \"\n\t\t\t\t<< description\n\t\t\t\t);\n\t\t}\n\t\tdetail::Sleep(intervalMs);\n\t}\n}\n\ntemplate<typename Value, typename Getter>\nstd::unique_ptr<Value> TryToCallGetter(Getter getter, std::string* description) {\n\tstd::unique_ptr<Value> value_ptr;\n\ttry {\n\t\tvalue_ptr.reset(new Value(getter()));\n\t} catch (const std::exception& e) {\n\t\tif (description)\n\t\t\t*description = e.what();\n\t}\n\treturn value_ptr;\n}\n\n} // namespace detail\n\n// Waits for a value returned by a supplied getter.\n// Returns that value or throws exception on timeout.\n// Getter is a function or function-like object that returns some copyable value.\ntemplate<typename Getter>\nauto WaitForValue(\n\tGetter getter,\n\tDuration timeoutMs = 5000,\n\tDuration intervalMs = 50\n\t) -> decltype(getter()) {\n\ttypedef decltype(getter()) Value;\n\treturn detail::Wait<Value>(\n\t\t[&getter](std::string* description) {\n\t\t\treturn detail::TryToCallGetter<Value>(getter, description);\n\t\t},\n\t\ttimeoutMs, intervalMs);\n}\n\n// Waits until a truthy value is returned by a supplied getter.\n// Returns that value or throws exception on timeout.\n// Getter is a function or function-like object that returns some copyable value.\ntemplate<typename Getter>\nauto WaitUntil(\n\tGetter getter,\n\tDuration timeoutMs = 5000,\n\tDuration intervalMs = 50\n\t) -> decltype(getter()) {\n\ttypedef decltype(getter()) Value;\n\treturn detail::Wait<Value>(\n\t\t[&getter](std::string* description) -> std::unique_ptr<Value> {\n\t\t\tauto value_ptr = detail::TryToCallGetter<Value>(getter, description);\n\t\t\tif (!value_ptr || !!*value_ptr)\n\t\t\t\treturn value_ptr;\n\t\t\tif (description)\n\t\t\t\t*description = \"Value is falsy\";\n\t\t\tvalue_ptr.reset();\n\t\t\treturn value_ptr;\n\t\t}, timeoutMs, intervalMs);\n}\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/wait_match.h",
    "content": "#ifndef WEBDRIVERXX_WAIT_MATCH_H\n#define WEBDRIVERXX_WAIT_MATCH_H\n\n#include \"wait.h\"\n#include \"detail/to_string.h\"\n#include <type_traits>\n\n#ifdef WEBDRIVERXX_ENABLE_GMOCK_MATCHERS\n\n#include <gmock/gmock-matchers.h>\n#include <sstream>\n\nnamespace webdriverxx {\nnamespace detail {\n\ntemplate<typename T, typename M>\nclass GMockMatcherAdapter {\npublic:\n\texplicit GMockMatcherAdapter(::testing::Matcher<T> matcher) : matcher_(matcher) {}\n\n\tbool Apply(const T& value) const {\n\t\treturn matcher_.Matches(value);\n\t}\n\n\tstd::string DescribeMismatch(const T& value) const {\n\t\tstd::ostringstream s;\n\t\ts << \"Expected: \";\n\t\tmatcher_.DescribeTo(&s);\n\t\ts << \", actual: \";\n\t\tToStream(value, s);\n\t\tconst auto mismatch_details = GetMismatchDetails(value);\n\t\tif (!mismatch_details.empty())\n\t\t\t s << \", \" << mismatch_details;\n\t\treturn s.str();\n\t}\n\nprivate:\n\tstd::string GetMismatchDetails(const T& value) const {\n\t\tstd::ostringstream s;\n\t\tmatcher_.ExplainMatchResultTo(value, &s);\n\t\treturn s.str();\n\t}\n\nprivate:\n\t::testing::Matcher<T> matcher_;\n};\n\n} // detail\n\ntemplate<class T, class M>\ndetail::GMockMatcherAdapter<T,M> MakeMatcherAdapter(const M& matcher, typename std::enable_if<std::is_convertible<M,::testing::Matcher<T>>::value>::type* = nullptr) {\n\treturn detail::GMockMatcherAdapter<T,M>(matcher);\n};\n\n} // namespace webdriverxx\n\n#endif // WEBDRIVERXX_ENABLE_GMOCK_MATCHERS\n\nnamespace webdriverxx {\nnamespace detail {\n\ntemplate<typename T, typename P>\nclass PredicateMatcherAdapter {\npublic:\n\texplicit PredicateMatcherAdapter(P& predicate) : predicate_(&predicate) {}\n\n\tbool Apply(const T& value) const {\n\t\treturn (*predicate_)(value);\n\t}\n\n\tstd::string DescribeMismatch(const T& value) const {\n\t\treturn detail::Fmt() << \"Value \" << ToString(value) << \" does not match predicate\";\n\t}\n\nprivate:\n\tP* predicate_;\n};\n\n} // detail\n\ntemplate<typename T>\nvoid MakeMatcherAdapter(...);\n\nnamespace detail {\n\ntemplate<typename T, typename M>\nPredicateMatcherAdapter<T,M> SelectMakeMatcherAdapter(M& matcher, std::true_type /*no_custom_adapters*/) {\n\treturn PredicateMatcherAdapter<T,M>(matcher);\n}\n\ntemplate<typename T, typename M>\nauto SelectMakeMatcherAdapter(const M& matcher, std::false_type /*no_custom_adapters*/) -> decltype(MakeMatcherAdapter<T>(matcher)) {\n\treturn MakeMatcherAdapter<T>(matcher);\n}\n\n} // detail\n\n// Waits until a value returned by a getter satisfies a supplied matcher.\n// Returns that value or throws exception on timeout.\n// Getter is a function or function-like object that returns some copyable value.\n// Matcher can be a predicate or a Google Mock matcher (if Google Mock matchers are enabled).\ntemplate<typename Getter, typename Matcher>\nauto WaitForMatch(\n\tGetter getter,\n\tMatcher matcher,\n\tDuration timeoutMs = 5000,\n\tDuration intervalMs = 50\n\t) -> decltype(getter()) {\n\ttypedef decltype(getter()) Value;\n\tconst auto& adapter = detail::SelectMakeMatcherAdapter<Value>(matcher,\n\t\ttypename std::is_same<void,decltype(MakeMatcherAdapter<Value>(matcher))>::type());\n\treturn detail::Wait<Value>([&getter, &adapter](std::string* description) -> std::unique_ptr<Value> {\n\t\t\tauto value_ptr = detail::TryToCallGetter<Value>(getter, description);\n\t\t\tif (value_ptr && !adapter.Apply(*value_ptr)) {\n\t\t\t\tif (description)\n\t\t\t\t\t*description = adapter.DescribeMismatch(*value_ptr);\n\t\t\t\tvalue_ptr.reset();\n\t\t\t}\n\t\t\treturn value_ptr;\n\t\t}, timeoutMs, intervalMs);\n}\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/webdriver.h",
    "content": "#ifndef WEBDRIVERXX_WEBDRIVER_H\n#define WEBDRIVERXX_WEBDRIVER_H\n\n#include \"client.h\"\n#include \"session.h\"\n\nnamespace webdriverxx {\n\n// The main class for interactions with a server. Automatically connects to a server,\n// creates and deletes a session and gives access to session's API.\nclass WebDriver // copyable\n\t: public Client\n\t, public Session {\npublic:\n\texplicit WebDriver(\n\t\tconst Capabilities& desired = Capabilities(),\n\t\tconst Capabilities& required = Capabilities(),\n\t\tconst std::string& url = kDefaultWebDriverUrl\n\t\t)\n\t\t: Client(url)\n\t\t, Session(CreateSession(desired, required))\n\t{}\n};\n\ninline\nWebDriver Start(\n\tconst Capabilities& desired, \n\tconst Capabilities& required = Capabilities(),\n\tconst std::string& url = kDefaultWebDriverUrl\n\t)\n{\n\treturn WebDriver(desired, required, url);\n}\n\ninline\nWebDriver Start(const Capabilities& desired, const std::string& url)\n{\n\treturn Start(desired, Capabilities(), url);\n}\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx/window.h",
    "content": "#ifndef WEBDRIVERXX_WINDOW_H\n#define WEBDRIVERXX_WINDOW_H\n\n#include \"types.h\"\n#include \"conversions.h\"\n#include \"detail/resource.h\"\n#include <string>\n\nnamespace webdriverxx {\n\nclass Window { // copyable\npublic:\n\tWindow(const std::string& handle, const detail::Shared<detail::Resource>& resource)\n\t\t: handle_(handle)\n\t\t, resource_(resource)\n\t{}\n\n\tstd::string GetHandle() const {\n\t\treturn handle_;\n\t}\n\n\tSize GetSize() const {\n\t\treturn resource_->GetValue<Size>(\"size\");\n\t}\n\n\tconst Window& SetSize(const Size& size) const {\n\t\tresource_->PostValue(\"size\", size);\n\t\treturn *this;\n\t}\n\n\tPoint GetPosition() const {\n\t\treturn resource_->GetValue<Point>(\"position\");\n\t}\n\n\tconst Window& SetPosition(const Point& position) const {\n\t\tresource_->PostValue(\"position\", position);\n\t\treturn *this;\n\t}\n\n\tconst Window& Maximize() const {\n\t\tresource_->Post(\"maximize\");\n\t\treturn *this;\n\t}\n\nprivate:\n\tstd::string handle_;\n\tdetail::Shared<detail::Resource> resource_;\n};\n\n} // namespace webdriverxx\n\n#endif\n"
  },
  {
    "path": "include/webdriverxx.h",
    "content": "#ifndef WEBDRIVERXX_H\n#define WEBDRIVERXX_H\n\n#include \"webdriverxx/webdriver.h\"\n#include \"webdriverxx/browsers/chrome.h\"\n#include \"webdriverxx/browsers/firefox.h\"\n#include \"webdriverxx/browsers/ie.h\"\n#include \"webdriverxx/browsers/phantom.h\"\n#include \"webdriverxx/wait.h\"\n#include \"webdriverxx/wait_match.h\"\n\n#endif\n"
  },
  {
    "path": "test/CMakeLists.txt",
    "content": "set(HEADER_FILES\n\t../include/webdriverxx.h \n\t../include/webdriverxx/by.h \n\t../include/webdriverxx/capabilities.h \n\t../include/webdriverxx/client.h \n\t../include/webdriverxx/client.inl \n\t../include/webdriverxx/conversions.h \n\t../include/webdriverxx/element.h \n\t../include/webdriverxx/element.inl \n\t../include/webdriverxx/errors.h \n\t../include/webdriverxx/js_args.h \n\t../include/webdriverxx/keys.h \n\t../include/webdriverxx/response_status_code.h \n\t../include/webdriverxx/session.h \n\t../include/webdriverxx/session.inl \n\t../include/webdriverxx/types.h \n\t../include/webdriverxx/wait.h \n\t../include/webdriverxx/wait_match.h \n\t../include/webdriverxx/webdriver.h \n\t../include/webdriverxx/window.h \n\t../include/webdriverxx/picojson.h\n\t../include/webdriverxx/browsers/chrome.h\n\t../include/webdriverxx/browsers/firefox.h \n\t../include/webdriverxx/browsers/ie.h \n\t../include/webdriverxx/browsers/phantom.h\n\t../include/webdriverxx/detail/error_handling.h\n\t../include/webdriverxx/detail/factories.h \n\t../include/webdriverxx/detail/factories_impl.h \n\t../include/webdriverxx/detail/finder.h \n\t../include/webdriverxx/detail/finder.inl \n\t../include/webdriverxx/detail/http_client.h \n\t../include/webdriverxx/detail/http_connection.h \n\t../include/webdriverxx/detail/http_request.h \n\t../include/webdriverxx/detail/keyboard.h \n\t../include/webdriverxx/detail/meta_tools.h \n\t../include/webdriverxx/detail/resource.h \n\t../include/webdriverxx/detail/shared.h \n\t../include/webdriverxx/detail/time.h \n\t../include/webdriverxx/detail/to_string.h \n\t../include/webdriverxx/detail/types.h \n\t)\n\nset(SOURCE_FILES\n\talerts_test.cpp\n\tbrowsers_test.cpp\n\tcapabilities_test.cpp\n\tconversions_test.cpp\n\tclient_test.cpp\n\telement_test.cpp\n\tenvironment.h\n\texamples_test.cpp\n\tfinder_test.cpp\n\tframes_test.cpp\n\thttp_connection_test.cpp\n\tjs_test.cpp\n\tkeyboard_test.cpp\n\tmain.cpp\n\tmouse_test.cpp\n\tresource_test.cpp\n\tsession_test.cpp\n\tshared_test.cpp\n\tto_string_test.cpp\n\twait_match_test.cpp\n\twait_test.cpp\n\twebdriver_test.cpp\n\t)\n\nfile(COPY pages DESTINATION ${CMAKE_CURRENT_BINARY_DIR})\n\nadd_definitions(-DWEBDRIVERXX_ENABLE_GMOCK_MATCHERS)\n\nif (MSVC)\n\tadd_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /W4 /WX\")\nelseif (\n\t\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"Clang\" OR\n\t\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"GNU\"\n\t)\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wall -Werror\")\n\tif (NOT ${APPLE})\n\t\tset(CMAKE_CXX_FLAGS_RELWITHDEBINFO \"-fsanitize=address -g -O1 -fno-omit-frame-pointer\")\n\tendif()\nendif()\n\n# Coverage\nif (UNIX)\n\tset(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES} Coverage)\n\tset_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS\n\t\t\"Debug\" \"Release\" \"MinSizeRel\" \"RelWithDebInfo\" \"Coverage\")\n\tset(CMAKE_CXX_FLAGS_COVERAGE \"${CMAKE_CXX_FLAGS_DEBUG} --coverage\")\n\tset(CMAKE_C_FLAGS_COVERAGE \"${CMAKE_C_FLAGS_DEBUG} --coverage\")\n\n\tfind_program(LCOV_EXECUTABLE lcov)\n\tfind_program(GENHTML_EXECUTABLE genhtml)\n\n\tadd_custom_target(coverage\n\t\t${LCOV_EXECUTABLE} --directory=. --zerocounters\n\t\tCOMMAND ${CMAKE_CTEST_COMMAND} -V\n\t\tCOMMAND ${LCOV_EXECUTABLE} --capture --directory=. --output-file coverage.info\n\t\tCOMMAND ${GENHTML_EXECUTABLE} coverage.info --output-directory coverage\n\t\tDEPENDS ${PROJECT_NAME}\n\t\t)\nendif()\n\ninclude(ExternalProject)\n\n# CURL\nif (WIN32)\n\texternalproject_add(curl_project\n\t\tURL http://curl.haxx.se/download/curl-7.55.0.tar.gz\n\t\tPREFIX curl\n\t\tCMAKE_ARGS -DCURL_STATICLIB=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_CURL_EXE=OFF -DBUILD_CURL_TESTS=OFF -DCMAKE_USE_OPENSSL=OFF -DCURL_ZLIB=OFF -DHTTP_ONLY=ON\n\t\tINSTALL_COMMAND \"\"\n\t\tUPDATE_COMMAND \"\"\n\t)\n\texternalproject_get_property(curl_project source_dir binary_dir)\n\tinclude_directories(\"${source_dir}/include\")\n\tlink_directories(\"${binary_dir}/lib\")\n\tlist(APPEND LIBS libcurl wsock32 ws2_32)\n\tlist(APPEND DEPS curl_project)\n\tadd_definitions(-DCURL_STATICLIB)\nelse()\n\tfind_package(CURL REQUIRED)\n\tinclude_directories(${CURL_INCLUDE_DIR})\n\tlist(APPEND LIBS ${CURL_LIBRARIES})\nendif()\n\n# Google test\nexternalproject_add(googletest\n\t\tPREFIX googletest\n\t\tGIT_REPOSITORY https://github.com/google/googletest\n\t\tUPDATE_COMMAND \"\"\n)\nexternalproject_get_property(googletest source_dir)\ninclude_directories(\"${source_dir}\")\nlist(APPEND DEPS googletest)\nlist(APPEND LIBS gtest gmock)\n\n# pthread\nif (UNIX)\n\tset(CMAKE_THREAD_PREFER_PTHREAD TRUE)\n\tfind_package(Threads REQUIRED)\n\tlist(APPEND LIBS ${CMAKE_THREAD_LIBS_INIT})\nendif()\n\nadd_library(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES})\nadd_dependencies(${PROJECT_NAME} ${DEPS})\ntarget_link_libraries(${PROJECT_NAME} ${LIBS})\n\nadd_executable(${PROJECT_NAME}_test ${SOURCE_FILES} ${HEADER_FILES})\nadd_dependencies(${PROJECT_NAME}_test ${DEPS})\ntarget_link_libraries(${PROJECT_NAME}_test ${LIBS})\nadd_test(${PROJECT_NAME}_test ${PROJECT_NAME})\n\nif (APPLE)\n\tset_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME} SUFFIX \".dylib\")\nendif()\n\nif (UNIX AND NOT APPLE)\n\tset_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME} SUFFIX \".so\")\nendif()\n\nif (WIN32)\n\tset_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME} SUFFIX \".dll\")\nendif()\n\ninstall(TARGETS ${PROJECT_NAME} DESTINATION /usr/local/lib)\n"
  },
  {
    "path": "test/alerts_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/webdriver.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestAlerts : public ::testing::Test {\nprotected:\n\tstatic void SetUpTestCase() {\n\t\tGetDriver().Navigate(GetTestPageUrl(\"alerts.html\"));\n\t}\n\n\tTestAlerts() : driver(GetDriver()) {}\n\n\tWebDriver driver;\n};\n\nTEST_F(TestAlerts, AcceptsAlert) {\n\tif (IsPhantom()) return;\n\tdriver.Execute(\"alert('abc')\");\n\tdriver.AcceptAlert();\n}\n\nTEST_F(TestAlerts, DismissesAlert) {\n\tif (IsPhantom()) return;\n\tdriver.Execute(\"alert('abc')\");\n\tdriver.DismissAlert();\n}\n\nTEST_F(TestAlerts, GetsAlertText) {\n\tif (IsPhantom()) return;\n\tdriver.Execute(\"alert('abc')\");\n\tASSERT_EQ(\"abc\", driver.GetAlertText());\n\tdriver.DismissAlert();\n}\n\nTEST_F(TestAlerts, SendsKeysToAlert) {\n\tif (IsPhantom()) return;\n\tdriver.Execute(\"result = prompt('abc')\");\n\tdriver.SendKeysToAlert(\"def\");\n\tdriver.AcceptAlert();\n\tASSERT_EQ(\"def\", driver.Eval<std::string>(\"return result\"));\n}\n\nTEST_F(TestAlerts, DismissesSendedKeys) {\n\tif (IsPhantom()) return;\n\tdriver.Execute(\"result = prompt('abc')\");\n\tdriver.SendKeysToAlert(\"def\");\n\tdriver.DismissAlert();\n\tASSERT_FALSE(driver.Eval<bool>(\"return result\"));\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/browsers_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/browsers/chrome.h>\n#include <webdriverxx/browsers/firefox.h>\n#include <webdriverxx/browsers/ie.h>\n#include <webdriverxx/webdriver.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nTEST(Firefox, WithTheSimplestSyntax) {\n\tif (!TestRealBrowsers()) return;\n\tauto ff = Start(Firefox());\n}\n\nTEST(Firefox, WithCustomUrl) {\n\tif (!TestRealBrowsers()) return;\n\tauto ff = Start(Firefox(), kDefaultWebDriverUrl);\n}\n\nTEST(Firefox, WithDefaultCapabilities) {\n\tif (!TestRealBrowsers()) return;\n\tauto defaults = Capabilities().SetProxy(DirectConnection());\n\tauto ff = Start(Firefox(defaults));\n}\n\nTEST(Firefox, HasCapabilitiesProperties) {\n\tif (!TestRealBrowsers()) return;\n\tauto ff = Start(Firefox().SetProxy(DirectConnection()));\n}\n\nTEST(Firefox, ConvertsToJson) {\n\tauto ff = Firefox()\n\t\t.SetLoggingPrefs(LoggingPrefs().SetLevel(log_level::Warning))\n\t\t.SetFirefoxBinary(\"abc\");\n\tconst auto json = ToJson(ff);\n\tconst auto c = FromJson<Capabilities>(json);\n\tconst auto logging = c.Get<JsonObject>(\"loggingPrefs\");\n\tASSERT_EQ(browser::Firefox, c.GetBrowserName());\n\tASSERT_EQ(\"WARNING\", logging.Get<std::string>(\"driver\"));\n\tASSERT_EQ(\"abc\", c.Get<std::string>(\"firefox_binary\"));\n}\n\nTEST(InternetExplorer, ConvertsToJson) {\n\tauto ie = InternetExplorer();\n\tconst auto json = ToJson(ie);\n\tconst auto c = FromJson<Capabilities>(json);\n\tASSERT_EQ(browser::InternetExplorer, c.GetBrowserName());\n}\n\nTEST(Chrome, ConvertsToJson) {\n\tauto gc = Chrome();\n\tconst auto json = ToJson(gc);\n\tconst auto c = FromJson<Capabilities>(json);\n\tASSERT_EQ(browser::Chrome, c.GetBrowserName());\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/capabilities_test.cpp",
    "content": "#include <webdriverxx/capabilities.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nTEST(Capabilities, AllowsToSetAndGetCustomValues) {\n\tCapabilities c;\n\tc.Set(\"int\", 123);\n\tc.Set(\"double\", 456.7);\n\tc.Set(\"string\", \"abc\");\n\tc.Set(\"bool\", true);\n\tASSERT_EQ(123, c.Get<int>(\"int\"));\n\tASSERT_EQ(456.7, c.Get<double>(\"double\"));\n\tASSERT_EQ(\"abc\", c.Get<std::string>(\"string\"));\n\tASSERT_EQ(true, c.Get<bool>(\"bool\"));\n}\n\nTEST(Capabilities, ConvertibleToJson) {\n\tCapabilities c;\n\tc.Set(\"int\", 123);\n\tc.Set(\"string\", \"abc\");\n\tconst auto json = ToJson(c);\n\tconst auto c_copy = FromJson<Capabilities>(json);\n\tASSERT_EQ(123, c_copy.Get<int>(\"int\"));\n\tASSERT_EQ(\"abc\", c_copy.Get<std::string>(\"string\"));\n}\n\nTEST(Capabilities, AllowsToSetProxy) {\n\tCapabilities().SetProxy(DirectConnection());\n\tCapabilities().SetProxy(AutodetectProxy());\n\tCapabilities().SetProxy(SystemProxy());\n\tCapabilities().SetProxy(FtpProxy(\"127.0.0.1:3128\").SetNoProxyFor(\"custom.host\"));\n\tCapabilities().SetProxy(HttpProxy(\"127.0.0.1:3128\").SetNoProxyFor(\"custom.host\"));\n\tCapabilities().SetProxy(SslProxy(\"127.0.0.1:3128\").SetNoProxyFor(\"custom.host\"));\n\tCapabilities().SetProxy(SocksProxy(\"127.0.0.1:3128\")\n\t\t.SetUsername(\"user\").SetPassword(\"12345\").SetNoProxyFor(\"custom.host\")\n\t\t);\n\tCapabilities().SetProxy(AutomaticProxyFromUrl(\"http://some.url\"));\n}\n\nTEST(Capabilities, ConvertsProxyToJson) {\n\tCapabilities c;\n\tc.SetProxy(SocksProxy(\"127.0.0.1:3128\").SetUsername(\"user\")\n\t\t.SetPassword(\"12345\").SetNoProxyFor(\"custom.host\"));\n\tconst auto json = ToJson(c);\n\tconst auto c_copy = FromJson<Capabilities>(json);\n\tconst auto proxy = FromJson<JsonObject>(c_copy.Get<picojson::value>(\"proxy\"));\n\tASSERT_EQ(\"manual\", proxy.Get<std::string>(\"proxyType\"));\n\tASSERT_EQ(\"127.0.0.1:3128\", proxy.Get<std::string>(\"socksProxy\"));\n\tASSERT_EQ(\"user\", proxy.Get<std::string>(\"socksUsername\"));\n\tASSERT_EQ(\"12345\", proxy.Get<std::string>(\"socksPassword\"));\n\tASSERT_EQ(\"custom.host\", proxy.Get<std::string>(\"noProxy\"));\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/client_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/client.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestClient : public ::testing::Test {\nprotected:\n\tstatic void SetUpTestCase() {\n\t\tclient = new Client(GetWebDriverUrl());\n\t}\n\n\tstatic void TearDownTestCase() {\n\t\tdelete client;\n\t\tclient = 0;\n\t}\n\n\tstatic Client* client;\n};\n\nClient* TestClient::client = 0;\n\nTEST_F(TestClient, GetsStatus) {\n\tpicojson::object status = client->GetStatus();\n\tASSERT_TRUE(status[\"build\"].is<picojson::object>());\n\tASSERT_TRUE(status[\"os\"].is<picojson::object>());\n}\n\nTEST_F(TestClient, GetsSessions) {\n\tclient->GetSessions();\n}\n\nTEST_F(TestClient, CreatesSession) {\n \tParameters params = GetParameters();\n\tclient->CreateSession(params.desired, params.required);\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/conversions_test.cpp",
    "content": "#include <webdriverxx/conversions.h>\n#include <gtest/gtest.h>\n#include <vector>\n#include <list>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nTEST(ToJson, ConvertsIntegralTypes) {\n\tASSERT_EQ(123, ToJson(123).get<double>());\n\tint i = 123;\n\tASSERT_EQ(123, ToJson(i).get<double>());\n\tASSERT_EQ(123, ToJson(static_cast<const int>(123)).get<double>());\n\tASSERT_EQ(123.5, ToJson(123.5).get<double>());\n\tASSERT_TRUE(ToJson(true).get<bool>());\n\tASSERT_FALSE(ToJson(false).get<bool>());\n}\n\nTEST(ToJson, ConvertsStrings) {\n\tASSERT_EQ(\"abc\", ToJson(\"abc\").get<std::string>());\n\tstd::string s(\"abc\");\n\tASSERT_EQ(\"abc\", ToJson(s).get<std::string>());\n\tASSERT_EQ(\"abc\", ToJson(s.c_str()).get<std::string>());\n\tASSERT_EQ(\"abc\", ToJson(const_cast<char*>(s.c_str())).get<std::string>());\n\tchar a[] = \"abc\";\n\tASSERT_EQ(\"abc\", ToJson(a).get<std::string>());\n}\n\nTEST(ToJson, ConvertsIterables) {\n\tint i[] = { 123, 456, 789 };\n\tconst auto ji = ToJson(i);\n\tASSERT_TRUE(ji.is<picojson::array>());\n\tASSERT_EQ(3u, ji.get<picojson::array>().size());\n\tASSERT_EQ(789, ji.get<picojson::array>()[2].get<double>());\n\n\tconst char* s[] = { \"abc\", \"def\", \"ghi\" };\n\tconst auto js = ToJson(s);\n\tASSERT_TRUE(js.is<picojson::array>());\n\tASSERT_EQ(3u, js.get<picojson::array>().size());\n\tASSERT_EQ(\"ghi\", js.get<picojson::array>()[2].get<std::string>());\n\n\tstd::vector<int> v(std::begin(i), std::end(i));\n\tconst auto jv = ToJson(v);\n\tASSERT_TRUE(jv.is<picojson::array>());\n\tASSERT_EQ(3u, jv.get<picojson::array>().size());\n\tASSERT_EQ(789, jv.get<picojson::array>()[2].get<double>());\n\n\tstd::list<int> l(std::begin(i), std::end(i));\n\tconst auto jl = ToJson(l);\n\tASSERT_TRUE(jl.is<picojson::array>());\n\tASSERT_EQ(3u, jl.get<picojson::array>().size());\n\tASSERT_EQ(789, jl.get<picojson::array>()[2].get<double>());\n\n\tint ii[2][3] = { { 1, 2, 3 }, { 4, 5, 123 } };\n\tconst auto jii = ToJson(ii);\n\tASSERT_TRUE(jii.is<picojson::array>());\n\tASSERT_EQ(2u, jii.get<picojson::array>().size());\n\tASSERT_TRUE(jii.get<picojson::array>()[0].is<picojson::array>());\n\tASSERT_TRUE(jii.get<picojson::array>()[1].is<picojson::array>());\n\tASSERT_EQ(3u, jii.get<picojson::array>()[0].get<picojson::array>().size());\n\tASSERT_EQ(3u, jii.get<picojson::array>()[1].get<picojson::array>().size());\n\tASSERT_EQ(123, jii.get<picojson::array>()[1].get<picojson::array>()[2].get<double>());\n\n\tstd::vector<int> e;\n\tconst auto je = ToJson(e);\n\tASSERT_TRUE(je.is<picojson::array>());\n\tASSERT_EQ(0u, je.get<picojson::array>().size());\n}\n\nnamespace {\nnamespace custom {\n\nstruct Object {\n\tstd::string string;\n\tint number;\n};\n\npicojson::value CustomToJson(const Object& value) {\n\treturn JsonObject()\n\t\t.Set(\"string\", value.string)\n\t\t.Set(\"number\", value.number);\n}\n\nvoid CustomFromJson(const picojson::value& value, Object& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"custom::Object is not an object\");\n\tresult.string = FromJson<std::string>(value.get(\"string\"));\n\tresult.number = FromJson<int>(value.get(\"number\"));\n}\n\n} // namespace custom\n} // namespace\n\nTEST(ToJson, ConvertsCustomObjects) {\n\tcustom::Object o = { \"abc\", 123 };\n\tconst auto jo = ToJson(o);\n\tASSERT_TRUE(jo.is<picojson::object>());\n\tASSERT_EQ(123, jo.get(\"number\").get<double>());\n\tASSERT_EQ(\"abc\", jo.get(\"string\").get<std::string>());\n\n\tconst custom::Object os[] = { { \"abc\", 123 }, { \"def\", 456 } };\n\tconst auto jos = ToJson(os);\n\tASSERT_TRUE(jos.is<picojson::array>());\n\tASSERT_EQ(2u, jos.get<picojson::array>().size());\n\tASSERT_TRUE(jos.get<picojson::array>()[0].is<picojson::object>());\n\tASSERT_EQ(456, jos.get<picojson::array>()[1].get(\"number\").get<double>());\n}\n\npicojson::value J(const std::string& json) {\n\tpicojson::value result;\n\tpicojson::parse(result, json.begin(), json.end(), nullptr);\n\treturn result;\n}\n\nTEST(FromJson, ConvertsIntegralTypes) {\n\tASSERT_EQ(123, FromJson<int>(J(\"123\")));\n\tASSERT_EQ(123.5, FromJson<double>(J(\"123.5\")));\n\tASSERT_EQ(123u, FromJson<unsigned>(J(\"123\")));\n\tASSERT_FALSE(FromJson<bool>(J(\"false\")));\n\tASSERT_TRUE(FromJson<bool>(J(\"true\")));\n}\n\nTEST(FromJson, ConvertsStrings) {\n\tASSERT_EQ(\"abc\", FromJson<std::string>(J(\"\\\"abc\\\"\")));\n}\n\nTEST(FromJson, ConvertsIterables) {\n\tconst auto i = FromJson<std::vector<int>>(J(\"[ 123, 456, 789 ]\"));\n\tASSERT_EQ(3u, i.size());\n\tASSERT_EQ(123, i[0]);\n\tASSERT_EQ(789, i[2]);\n\n\tconst auto s = FromJson<std::list<std::string>>(J(\"[ \\\"abc\\\", \\\"def\\\" ]\"));\n\tASSERT_EQ(2u, s.size());\n\tASSERT_EQ(\"abc\", s.front());\n\tASSERT_EQ(\"def\", s.back());\n\n\tconst auto e = FromJson<std::vector<int>>(J(\"[]\"));\n\tASSERT_EQ(0u, e.size());\n\n\tconst auto ii = FromJson<std::vector<std::list<int>>>(J(\"[ [ 123, 456 ], [ 789 ] ]\"));\n\tASSERT_EQ(2u, ii.size());\n\tASSERT_EQ(2u, ii[0].size());\n\tASSERT_EQ(1u, ii[1].size());\n\tASSERT_EQ(456, ii[0].back());\n\tASSERT_EQ(789, ii[1].front());\n}\n\nTEST(FromJson, ConvertsCustomObjects) {\n\tconst auto o = FromJson<custom::Object>(J(\"{ \\\"number\\\": 123, \\\"string\\\": \\\"abc\\\" }\"));\n\tASSERT_EQ(123, o.number);\n\tASSERT_EQ(\"abc\", o.string);\n\n\tconst auto os = FromJson<std::vector<custom::Object>>(J(\n\t\t\"[ { \\\"number\\\": 123, \\\"string\\\": \\\"abc\\\" },\"\n\t\t\"{ \\\"number\\\": 456, \\\"string\\\": \\\"def\\\" } ]\"\n\t\t));\n\tASSERT_EQ(2u, os.size());\n\tASSERT_EQ(123, os[0].number);\n\tASSERT_EQ(\"abc\", os[0].string);\n\tASSERT_EQ(456, os[1].number);\n\tASSERT_EQ(\"def\", os[1].string);\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/element_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/webdriver.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestElement : public ::testing::Test {\nprotected:\n\tstatic void SetUpTestCase() {\n\t\tGetDriver().Navigate(GetTestPageUrl(\"element.html\"));\n\t}\n\n\tTestElement() : driver(GetDriver()) {}\n\n\tWebDriver driver;\n};\n\nTEST_F(TestElement, CanBeClicked) {\n\tdriver.FindElement(ByTag(\"input\")).Click();\n}\n\n// TODO: Submit\n\nTEST_F(TestElement, GetsText) {\n\tASSERT_EQ(\"Some text\", driver.FindElement(ById(\"element_with_text\")).GetText());\n}\n\nTEST_F(TestElement, CanBeCleared) {\n\tElement e = driver.FindElement(ByTag(\"input\"));\n\te.SendKeys(\"abc\");\n\tASSERT_NE(\"\", e.GetAttribute(\"value\"));\n\te.Clear();\n\tASSERT_EQ(\"\", e.GetAttribute(\"value\"));\n}\n\nTEST_F(TestElement, GetsTagName) {\n\tASSERT_EQ(\"div\", driver.FindElement(ByTag(\"div\")).GetTagName());\n}\n\n// TODO: IsEnabled\n// TODO: IsSelected\n\nTEST_F(TestElement, GetsAttributes) {\n\tElement e = driver.FindElement(ById(\"div_with_attributes\"));\n\tASSERT_EQ(\"div_with_attributes\", e.GetAttribute(\"id\"));\n\tASSERT_EQ(\"test value\", e.GetAttribute(\"test\"));\n}\n\nTEST_F(TestElement, IsEqualToOtherElement) {\n\tElement e = driver.FindElement(ById(\"first_div\"));\n\tElement other = driver.FindElement(ById(\"first_div\"));\n\tASSERT_TRUE(e.Equals(other));\n\tASSERT_TRUE(e == other);\n}\n\nTEST_F(TestElement, IsNotEqualToOtherElement) {\n\tElement e = driver.FindElement(ById(\"first_div\"));\n\tElement other = driver.FindElement(ById(\"second_div\"));\n\tASSERT_TRUE(!e.Equals(other));\n\tASSERT_TRUE(e != other);\n}\n\nTEST_F(TestElement, HasStrictWeakOrdering) {\n\tElement a = driver.FindElement(ById(\"first_div\"));\n\tElement b = driver.FindElement(ById(\"second_div\"));\n\tElement c = driver.FindElement(ById(\"third_div\"));\n\tElement a2 = a;\n\tif (c < b) std::swap(b, c);\n\tif (b < a) std::swap(a, b);\n\tif (c < b) std::swap(b, c);\n\tASSERT_FALSE(a < a2);\n\tASSERT_FALSE(a2 < a);\n\tASSERT_TRUE(a < b && !(b < a));\n\tASSERT_TRUE(a < b && b < c && a < c);\n}\n\nTEST_F(TestElement, GetsIsDisplayed) {\n\tASSERT_TRUE(driver.FindElement(ById(\"visible\")).IsDisplayed());\n\tASSERT_FALSE(driver.FindElement(ById(\"hidden\")).IsDisplayed());\n}\n\nTEST_F(TestElement, GetsLocation) {\n\tdriver.FindElement(ById(\"visible\")).GetLocation();\n\tdriver.FindElement(ById(\"visible\")).GetLocationInView();\n}\n\nTEST_F(TestElement, GetsSize) {\n\tSize size = driver.FindElement(ById(\"visible\")).GetSize();\n\tASSERT_NE(0, size.width);\n\tASSERT_NE(0, size.height);\n}\n\nTEST_F(TestElement, GetsCssProperty) {\n\tASSERT_EQ(\"none\", driver.FindElement(ById(\"hidden\")).GetCssProperty(\"display\"));\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/environment.h",
    "content": "#ifndef WEBDRIVERXX_ENVIRONMENT_H\n#define WEBDRIVERXX_ENVIRONMENT_H\n\n#include <webdriverxx/webdriver.h>\n#include <webdriverxx/capabilities.h>\n#include <gtest/gtest.h>\n#include <string>\n#include <algorithm>\n\nnamespace test {\n\nconst char* const kDefaultTestWebDriverUrl = \"http://localhost:7777/\";\nconst char* const kDefaultTestPagesUrl = \"http://localhost:8080/\";\n\nstruct Parameters {\n\tstd::string web_driver_url;\n\twebdriverxx::Capabilities required;\n\twebdriverxx::Capabilities desired;\n\tstd::string test_pages_url;\n\tbool test_real_browsers;\n\n\tParameters()\n\t\t: web_driver_url(kDefaultTestWebDriverUrl)\n\t\t, test_pages_url(kDefaultTestPagesUrl)\n\t\t, test_real_browsers(false)\n\t{}\n};\n\nclass Environment : public ::testing::Environment {\npublic:\n\tstatic Environment& Instance() {\n\t\treturn *instance_;\n\t}\n\n\texplicit Environment(const Parameters& parameters)\n\t\t: driver_(0)\n\t\t, parameters_(parameters)\n\t{}\n\n\twebdriverxx::WebDriver& GetDriver() {\n\t\treturn driver_ ? *driver_ : GetFreshDriver();\n\t}\n\n\twebdriverxx::WebDriver& GetFreshDriver() {\n\t\tDeleteDriver();\n\t\tdriver_ = new webdriverxx::WebDriver(CreateDriver());\n\t\treturn *driver_;\n\t}\n\n\twebdriverxx::WebDriver CreateDriver() {\n\t\treturn webdriverxx::WebDriver(\n\t\t\tparameters_.desired,\n\t\t\tparameters_.required,\n\t\t\tparameters_.web_driver_url\n\t\t\t);\n\t}\n\n\tstd::string GetWebDriverUrl() const { return parameters_.web_driver_url; }\n\n\tParameters GetParameters() const { return parameters_; }\n\n\tstd::string GetTestPageUrl(const std::string& page_name) const {\n\t\tstd::string url = parameters_.test_pages_url;\n\t\tif (!url.empty() && url[url.length() - 1] != '/')\n\t\t\turl += \"/\";\n\t\turl += page_name;\n\t\treturn url;\n\t}\n\nprivate:\n\tvoid SetUp() {\n\t\tinstance_ = this;\n\t}\n\n\tvoid TearDown() {\n\t\tinstance_ = 0;\n\t\tDeleteDriver();\n\t}\n\n\tvoid DeleteDriver() {\n\t\tdelete driver_;\n\t\tdriver_ = 0;\n\t}\n\nprivate:\n\tstatic Environment* instance_;\n\twebdriverxx::WebDriver* driver_;\n\tParameters parameters_;\n};\n\ninline Parameters GetParameters() { return Environment::Instance().GetParameters(); }\ninline std::string GetWebDriverUrl() { return Environment::Instance().GetWebDriverUrl(); }\ninline std::string GetTestPageUrl(const std::string& page_name) { return Environment::Instance().GetTestPageUrl(page_name); }\ninline webdriverxx::WebDriver& GetDriver() { return Environment::Instance().GetDriver(); }\ninline webdriverxx::WebDriver& GetFreshDriver() { return Environment::Instance().GetFreshDriver(); }\ninline webdriverxx::WebDriver CreateDriver() { return Environment::Instance().CreateDriver(); }\ninline bool TestRealBrowsers() { return GetParameters().test_real_browsers; }\ninline std::string GetBrowserName() { return GetDriver().GetCapabilities().GetBrowserName(); }\ninline bool IsFirefox() { return GetBrowserName() == webdriverxx::browser::Firefox; }\ninline bool IsPhantom() { return GetBrowserName() == webdriverxx::browser::Phantom; }\n\n} // namespace test\n\n#endif\n"
  },
  {
    "path": "test/examples_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/webdriver.h>\n#ifndef WEBDRIVERXX_ENABLE_GMOCK_MATCHERS\n#define WEBDRIVERXX_ENABLE_GMOCK_MATCHERS\n#endif\n#include <webdriverxx/wait_match.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestExamples : public ::testing::Test {\nprotected:\n\tTestExamples() : driver(GetDriver()) {}\n\n\tvoid StopNavigation() {\n\t\tWaitForMatch([this] {\n\t\t\treturn driver.Navigate(GetTestPageUrl(\"non_existing.html\")).GetUrl();\n\t\t}, ::testing::HasSubstr(\"non_existing\"));\n\t}\n\n\tWebDriver driver;\n};\n\nTEST_F(TestExamples, QuickExample) {\n\tdriver\n\t\t.Navigate(\"http://google.com\")\n\t\t.FindElement(ByCss(\"input[name=q]\"))\n\t\t.SendKeys(\"Hello, world!\")\n\t\t.Submit();\n\n\tStopNavigation(); // Firefox doesn't perform navigation right after Submit.\n}\n\nTEST_F(TestExamples, ImplicitWait) {\n\tdriver.SetImplicitTimeoutMs(0);\n\ttry {\n\t\tElement element = driver.FindElement(ByName(\"akela\"));\n\t\tFAIL();\n\t} catch (const std::exception&) {}\n}\n\nTEST_F(TestExamples, ExplicitWait1) {\n\tauto find_element = [&]{ return driver.FindElement(ById(\"async_loaded\")); };\n\ttry {\n\t\tint timeout = 0;\n\t\tElement element = WaitForValue(find_element, timeout);\n\t\tFAIL();\n\t} catch (const std::exception&) {}\n}\n\nTEST_F(TestExamples, ExplicitWait2) {\n\tauto element_is_selected = [&]{\n\t\treturn driver.FindElement(ById(\"async_loaded\")).IsSelected();\n\t};\n\ttry {\n\t\tint timeout = 0;\n\t\tWaitUntil(element_is_selected, timeout);\n\t\tFAIL();\n\t} catch (const std::exception&) {}\n}\n\nTEST_F(TestExamples, UseGmockMatchers) {\n\tdriver.Navigate(GetTestPageUrl(\"redirect.html\"));\n\tauto url = [&]{ return driver.GetUrl(); };\n\tusing namespace ::testing;\n\tWaitForMatch(url, HasSubstr(\"target\"));\n\tStopNavigation();\t\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/finder_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/webdriver.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestFinder : public ::testing::Test {\nprotected:\n\tstatic void SetUpTestCase() {\n\t\tWebDriver& driver = GetDriver();\n\t\tdriver.Navigate(GetTestPageUrl(\"finder.html\"));\n\t\tdriver.FindElement(ById(\"finder_loaded\"));\n\t\tdriver.SetImplicitTimeoutMs(0);\n\t}\n\n\tstatic void TearDownTestCase() {\n\t\tWebDriver& driver = GetDriver();\n\t\tdriver.SetImplicitTimeoutMs(1000);\n\t}\n\n\tTestFinder() : driver(GetDriver()) {}\n\n\tWebDriver driver;\n};\n\nTEST_F(TestFinder, CanFindElement) {\n\tdriver.FindElement(ById(\"test_id\"));\n}\n\nTEST_F(TestFinder, ThrowsIfElementNotFound) {\n\tASSERT_THROW(driver.FindElement(ById(\"non_existing\")), WebDriverException);\n}\n\nTEST_F(TestFinder, CanFindMoreThanOneElement) {\n\tASSERT_TRUE(0u < driver.FindElements(ByTag(\"div\")).size());\n}\n\nTEST_F(TestFinder, ReturnsZeroIfElementsNotFound) {\n\tASSERT_EQ(0u, driver.FindElements(ById(\"non_existing\")).size());\n}\n\nTEST_F(TestFinder, FindsElementById) {\n\tdriver.FindElement(ById(\"test_id\"));\n\tASSERT_EQ(0u, driver.FindElements(ById(\"non_existing\")).size());\n}\n\nTEST_F(TestFinder, FindsElementByClassName) {\n\tdriver.FindElement(ByClass(\"test_class\"));\n\tASSERT_EQ(0u, driver.FindElements(ByClass(\"non_existing\")).size());\n}\n\nTEST_F(TestFinder, FindsElementByCssSelector) {\n\tdriver.FindElement(ByCss(\"body div#css_selectable\"));\n\tASSERT_EQ(0u, driver.FindElements(ByCss(\"non_existing\")).size());\n}\n\nTEST_F(TestFinder, FindsElementByName) {\n\tdriver.FindElement(ByName(\"test_name\"));\n\tASSERT_EQ(0u, driver.FindElements(ByName(\"non_existing\")).size());\n}\n\nTEST_F(TestFinder, FindsElementByLinkText) {\n\tdriver.FindElement(ByLinkText(\"test link text\"));\n\tASSERT_EQ(0u, driver.FindElements(ByLinkText(\"non_existing\")).size());\n}\n\nTEST_F(TestFinder, FindsElementByPartialLinkText) {\n\tdriver.FindElement(ByPartialLinkText(\"link text\"));\n\tASSERT_EQ(0u, driver.FindElements(ByPartialLinkText(\"non_existing\")).size());\n}\n\nTEST_F(TestFinder, FindsElementByTagName) {\n\tdriver.FindElement(ByTag(\"body\"));\n\tASSERT_EQ(0u, driver.FindElements(ByTag(\"non_existing\")).size());\n}\n\nTEST_F(TestFinder, FindsElementByXPath) {\n\tdriver.FindElement(ByXPath(\"//div\"));\n\tASSERT_EQ(0u, driver.FindElements(ByXPath(\"//non_existing\")).size());\n}\n\nTEST_F(TestFinder, OfElementFindsInnerElement) {\n\tElement outer = driver.FindElement(ById(\"outer\"));\n\touter.FindElement(ById(\"inner\"));\n}\n\nTEST_F(TestFinder, OfElementDoesNotFindItself) {\n\tElement outer = driver.FindElement(ById(\"outer\"));\n\tASSERT_EQ(0u, outer.FindElements(ById(\"outer\")).size());\n}\n\nTEST_F(TestFinder, OfElementDoesNotFindNonExistingInnerElements) {\n\tElement outer = driver.FindElement(ById(\"outer\"));\n\tdriver.FindElement(ById(\"next_after_outer\"));\n\tASSERT_THROW(outer.FindElement(ById(\"next_after_outer\")), WebDriverException);\n\tASSERT_EQ(0u, outer.FindElements(ById(\"next_after_outer\")).size());\n}\n\nTEST_F(TestFinder, OfElementFindsMoreThanOneInnerElement) {\n\tASSERT_EQ(2u, driver.FindElement(ById(\"outer\")).FindElements(ByTag(\"div\")).size());\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/frames_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/webdriver.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestFrames : public ::testing::Test {\nprotected:\n\tTestFrames()\n\t\t: driver(GetDriver())\n\t\t, url(GetTestPageUrl(\"frames.html\"))\n\t{}\n\n\tvoid SetUp()\n\t{\n\t\tdriver.Navigate(url);\n\t}\n\n\tWebDriver driver;\n\tstd::string url;\n};\n\nTEST_F(TestFrames, OnTopFrameByDefault) {\n\tASSERT_EQ(\"top_frame\", driver.FindElement(ById(\"tag\")).GetAttribute(\"value\"));\n}\n\nTEST_F(TestFrames, CanSwitchToFrameByNumber) {\n\tdriver.SetFocusToFrame(1);\n\tASSERT_EQ(\"frame3\", driver.FindElement(ById(\"tag\")).GetAttribute(\"value\"));\n}\n\nTEST_F(TestFrames, CanSwitchToFrameByName) {\n\tdriver.SetFocusToFrame(\"frame3_name\");\n\tASSERT_EQ(\"frame3\", driver.FindElement(ById(\"tag\")).GetAttribute(\"value\"));\n}\n\nTEST_F(TestFrames, CanSwitchToFrameByElement) {\n\tstd::vector<Element> frames = driver.FindElements(ByTag(\"iframe\"));\n\tASSERT_EQ(2u, frames.size());\n\tdriver.SetFocusToFrame(frames[1]);\n\tASSERT_EQ(\"frame3\", driver.FindElement(ById(\"tag\")).GetAttribute(\"value\"));\n}\n\nTEST_F(TestFrames, CanSwitchToDefaultFrame) {\n\tdriver.SetFocusToFrame(1);\n\tdriver.SetFocusToDefaultFrame();\n\tASSERT_EQ(\"top_frame\", driver.FindElement(ById(\"tag\")).GetAttribute(\"value\"));\n}\n\nTEST_F(TestFrames, CanSwitchToDeepFrames) {\n\tdriver.SetFocusToFrame(0).SetFocusToFrame(1);\n\tASSERT_EQ(\"frame2\", driver.FindElement(ById(\"tag\")).GetAttribute(\"value\"));\n}\n\nTEST_F(TestFrames, CanSwitchToParentFrame) {\n\tif (IsPhantom()) return; // Not supported in PhantomJS 1.9.7\n\tdriver.SetFocusToFrame(0).SetFocusToFrame(1)\n\t\t.SetFocusToParentFrame().SetFocusToParentFrame();\n\tASSERT_EQ(\"top_frame\", driver.FindElement(ById(\"tag\")).GetAttribute(\"value\"));\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/http_connection_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/detail/http_connection.h>\n#include <gtest/gtest.h>\n#include <string>\n\nnamespace test {\n\nusing namespace webdriverxx;\nusing namespace webdriverxx::detail;\n\nTEST(HttpConnection, CanBeCreated) {\n\tHttpConnection connection;\n}\n\nTEST(HttpConnection, GetsPage) {\n\tHttpConnection connection;\n\tHttpResponse response = connection.Get(GetWebDriverUrl() + \"status\");\n\tASSERT_EQ(200, response.http_code);\n\tASSERT_TRUE(!response.body.empty());\n}\n\nTEST(HttpConnection, ThrowsExceptionIfPortIsClosed) {\n\tHttpConnection connection;\n\tconst char *const kUrlWithClosedPort = \"http://127.0.0.1:7778/\";\n\tASSERT_THROW(connection.Get(kUrlWithClosedPort), WebDriverException);\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/js_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/webdriver.h>\n#include <gtest/gtest.h>\n#include <list>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestJsExecutor : public ::testing::Test {\nprotected:\n\tstatic void SetUpTestCase() {\n\t\tGetDriver().Navigate(GetTestPageUrl(\"js.html\"));\n\t}\n\n\tTestJsExecutor() : driver(GetDriver()) {}\n\n\tWebDriver driver;\n};\n\nTEST_F(TestJsExecutor, ExecutesSimpleScript) {\n\tdriver.Execute(\"document.title = 'abc'\");\n\tASSERT_EQ(\"abc\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, CanPassStringArgument) {\n\tdriver.Execute(\"document.title = arguments[0]\", JsArgs() << std::string(\"abc\"));\n\tASSERT_EQ(\"abc\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, CanPassStringLiteralArgument) {\n\tdriver.Execute(\"document.title = arguments[0]\", JsArgs() << \"abc\");\n\tASSERT_EQ(\"abc\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, CanPassNumberArgument) {\n\tdriver.Execute(\"document.title = String(arguments[0] + 21)\", JsArgs() << 21);\n\tASSERT_EQ(\"42\", driver.GetTitle());\n\tdriver.Execute(\"document.title = String(arguments[0] + 21)\", JsArgs() << 21.5);\n\tASSERT_EQ(\"42.5\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, CanPassBooleanArgument) {\n\tdriver.Execute(\"a = arguments; document.title = [ typeof(a[0]), a[0], typeof(a[1]), a[1] ].join(',')\",\n\t\tJsArgs() << true << false);\n\tASSERT_EQ(\"boolean,true,boolean,false\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, CanPassMoreThanOneArgument) {\n\tdriver.Execute(\"document.title = arguments[0] + ',' + arguments[1]\",\n\t\tJsArgs() << \"abc\" << \"def\");\n\tASSERT_EQ(\"abc,def\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, CanPassElement) {\n\tElement e = driver.FindElement(ByTag(\"input\")).Clear();\n\tASSERT_EQ(\"\", e.GetAttribute(\"value\"));\n\tdriver.Execute(\"arguments[0].value = arguments[1]\",\n\t\tJsArgs() << e << \"abc\");\n\tASSERT_EQ(\"abc\", e.GetAttribute(\"value\"));\n}\n\nTEST_F(TestJsExecutor, CanPassArray) {\n\tstd::vector<int> numbers;\n\tnumbers.push_back(123);\n\tnumbers.push_back(321);\n\tdriver.Execute(\"document.title = arguments[0][0] + arguments[0][1]\",\n\t\tJsArgs() << numbers);\n\tASSERT_EQ(\"444\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, CanPassOtherContainers) {\n\tstd::list<int> numbers;\n\tnumbers.push_back(123);\n\tnumbers.push_back(321);\n\tdriver.Execute(\"document.title = arguments[0][0] + arguments[0][1]\",\n\t\tJsArgs() << numbers);\n\tASSERT_EQ(\"444\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, CanPassCArray) {\n\tconst char* colors[] = { \"red\", \"green\", \"blue\" };\n\tdriver.Execute(\"document.title = arguments[0].reverse().join(', ')\",\n\t\tJsArgs() << colors);\n\tASSERT_EQ(\"blue, green, red\", driver.GetTitle());\n}\n\nnamespace {\nnamespace custom {\n\nstruct Object {\n\tstd::string string;\n\tint number;\n};\n\npicojson::value CustomToJson(const Object& value) {\n\treturn JsonObject()\n\t\t.Set(\"string\", value.string)\n\t\t.Set(\"number\", value.number);\n}\n\nvoid CustomFromJson(const picojson::value& value, Object& result) {\n\tWEBDRIVERXX_CHECK(value.is<picojson::object>(), \"custom::Object is not an object\");\n\tresult.string = FromJson<std::string>(value.get(\"string\"));\n\tresult.number = FromJson<int>(value.get(\"number\"));\n}\n\n} // namespace custom\n} // namespace\n\nTEST_F(TestJsExecutor, CanPassCustomObject) {\n\tcustom::Object o = { \"abc\", 123 };\n\tdriver.Execute(\"o = arguments[0]; document.title = (o.string + 'def') + (o.number + 1)\",\n\t\tJsArgs() << o);\n\tASSERT_EQ(\"abcdef124\", driver.GetTitle());\n}\n\n///////////////////////////////////////////////////////////////////////////\n\nTEST_F(TestJsExecutor, EvalsString) {\n\tASSERT_EQ(\"abc\", driver.Eval<std::string>(\"return 'abc'\"));\n}\n\nTEST_F(TestJsExecutor, EvalsNumber) {\n\tASSERT_EQ(123, driver.Eval<int>(\"return 123\"));\n\tASSERT_EQ(123.5, driver.Eval<double>(\"return 123.5\"));\n}\n\nTEST_F(TestJsExecutor, EvalsBoolean) {\n\tASSERT_TRUE(true == driver.Eval<bool>(\"return true\"));\n\tASSERT_TRUE(false == driver.Eval<bool>(\"return false\"));\n}\n\nTEST_F(TestJsExecutor, EvalsElement) {\n\tElement e = driver.FindElement(ByTag(\"input\"));\n\tASSERT_EQ(e, driver.Eval<Element>(\"return document.getElementsByTagName('input')[0]\"));\n}\n\nTEST_F(TestJsExecutor, EvalsCustomObject) {\n\tcustom::Object o = driver.Eval<custom::Object>(\"return { string: 'abc', number: 123 }\");\n\tASSERT_EQ(\"abc\", o.string);\n\tASSERT_EQ(123, o.number);\n}\n\nTEST_F(TestJsExecutor, EvalsArrayOfStrings) {\n\tstd::vector<std::string> v = driver.Eval<std::vector<std::string>>(\n\t\t\"return [ 'abc', 'def' ]\"\n\t\t);\n\tASSERT_EQ(2u, v.size());\n\tASSERT_EQ(\"abc\", v[0]);\n\tASSERT_EQ(\"def\", v[1]);\n}\n\nTEST_F(TestJsExecutor, EvalsArrayOfNumbers) {\n\tstd::vector<int> v = driver.Eval<std::vector<int>>(\n\t\t\"return [ 123, 456 ]\"\n\t\t);\n\tASSERT_EQ(2u, v.size());\n\tASSERT_EQ(123, v[0]);\n\tASSERT_EQ(456, v[1]);\n}\n\n///////////////////////////////////////////////////////////////////////////\n\n// Makes asynchronous script from synchronous one\nstd::string AsyncScript(const std::string& script) {\n\treturn std::string()\n\t\t+ \"var args = Array.prototype.slice.call(arguments, 0);\"\n\t\t+ \"var callback = args.pop();\"\n\t\t+ \"setTimeout(function(){\"\n\t\t\t+ \"var result = (function(){\" + script + \"}).apply(this, args);\"\n\t\t\t+ \"callback(result)\"\n\t\t+ \"}, 0);\"\n\t\t;\n}\n\nTEST_F(TestJsExecutor, ExecutesSimpleAsyncScript) {\n\tif (IsPhantom()) return; // Crashes PhantomJS 1.9.7\n\tdriver.ExecuteAsync(AsyncScript(\"document.title = 'abc'\"));\n\tASSERT_EQ(\"abc\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, PassesArgumentsToAsyncScript) {\n\tif (IsPhantom()) return; // Crashes PhantomJS 1.9.7\n\tdriver.ExecuteAsync(AsyncScript(\"document.title = JSON.stringify(Array.prototype.slice.call(arguments, 0))\"),\n\t\tJsArgs() << std::string(\"abc\") << 123 << true);\n\tASSERT_EQ(\"[\\\"abc\\\",123,true]\", driver.GetTitle());\n}\n\nTEST_F(TestJsExecutor, ReturnsValueFromAsyncScript) {\n\tif (IsPhantom()) return; // Crashes PhantomJS 1.9.7\n\tASSERT_EQ(123, driver.EvalAsync<int>(AsyncScript(\"return 123\")));\n}\n\nTEST_F(TestJsExecutor, ReturnsElementFromAsyncScript) {\n\tif (IsPhantom()) return; // Crashes PhantomJS 1.9.7\n\tElement e = driver.FindElement(ByTag(\"input\"));\n\tASSERT_EQ(e, driver.EvalAsync<Element>(AsyncScript(\n\t\t\"return document.getElementsByTagName('input')[0]\")));\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/keyboard_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/webdriver.h>\n#include <webdriverxx/keys.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestKeyboard : public ::testing::Test {\nprotected:\n\tstatic void SetUpTestCase() {\n\t\tGetDriver().Navigate(GetTestPageUrl(\"keyboard.html\"));\n\t}\n\n\tTestKeyboard() : driver(GetDriver()) {}\n\n\tWebDriver driver;\n};\n\nTEST_F(TestKeyboard, SendsKeysToElement) {\n\tElement e = driver.FindElement(ByName(\"first\"));\n\te.Clear()\n\t\t.SendKeys(\"abc\")\n\t\t.SendKeys(keys::Left).SendKeys(keys::Left).SendKeys(keys::Left)\n\t\t.SendKeys(\"def\")\n\t\t;\n\tASSERT_EQ(\"abcdef\", e.GetAttribute(\"value\"));\n}\n\nTEST_F(TestKeyboard, SendsShortcuts) {\n\tElement e = driver.FindElement(ByName(\"first\"));\n\te.Clear()\n\t\t.SendKeys(Shortcut() << keys::Shift << \"a\" << \"bc\")\n\t\t.SendKeys(\"def\")\n\t\t;\n\tASSERT_EQ(\"ABCdef\", e.GetAttribute(\"value\"));\n}\n\nTEST_F(TestKeyboard, SendsKeysToActiveElement) {\n\tElement first = driver.FindElement(ByName(\"first\"));\n\tElement second = driver.FindElement(ByName(\"second\"));\n\tfirst.Click().Clear();\n\tdriver.SendKeys(\"abc\");\n\tsecond.Click().Clear();\n\tdriver.SendKeys(\"def\");\n\tASSERT_EQ(\"abc\", first.GetAttribute(\"value\"));\n\tASSERT_EQ(\"def\", second.GetAttribute(\"value\"));\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/main.cpp",
    "content": "#include \"environment.h\"\n#include <gtest/gtest.h>\n#include <string>\n\nnamespace test {\n\nEnvironment* Environment::instance_ = 0;\n\nbool IsCommandLineArgument(const std::string& arg, const char* name) {\n\treturn arg.find(std::string(\"--\") + name) == 0;\n}\n\nstd::string GetCommandLineArgumentValue(const std::string& arg) {\n\tconst size_t pos = arg.find('=');\n\treturn pos == std::string::npos ? std::string() : arg.substr(pos + 1);\n}\n\nParameters ParseParameters(int argc, char **argv) {\n\tParameters result;\n\tfor(int i = 1; i < argc; ++i) {\n\t\tconst std::string arg = argv[i];\n\t\tif (IsCommandLineArgument(arg, \"browser\")) {\n\t\t\tresult.web_driver_url = webdriverxx::kDefaultWebDriverUrl;\n\t\t\tconst std::string browser_name = GetCommandLineArgumentValue(arg);\n\t\t\tresult.desired.Set(\"browserName\", browser_name);\n\t\t} else if (IsCommandLineArgument(arg, \"pages\")) {\n\t\t\tresult.test_pages_url = GetCommandLineArgumentValue(arg);\n\t\t} else if (IsCommandLineArgument(arg, \"webdriver\")) {\n\t\t\tresult.web_driver_url = GetCommandLineArgumentValue(arg);\n\t\t} else if (IsCommandLineArgument(arg, \"test_real_browsers\")) {\n\t\t\tresult.test_real_browsers = true;\n\t\t}\n\t}\n\treturn result;\n}\n\n} // namespace test\n\nint main(int argc, char **argv) {\n\t::testing::InitGoogleTest(&argc, argv);\n\t::testing::AddGlobalTestEnvironment(\n\t\tnew test::Environment(test::ParseParameters(argc, argv))\n\t\t);\n\treturn RUN_ALL_TESTS();\n}\n"
  },
  {
    "path": "test/mouse_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/session.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestMouse : public ::testing::Test {\nprotected:\n\tstatic void SetUpTestCase() {\n\t\tGetDriver().Navigate(GetTestPageUrl(\"mouse.html\"));\n\t}\n\n\tTestMouse() : driver(GetDriver()) {}\n\n\tvoid SetUp() {\n\t\ttarget = driver.FindElement(ById(\"target\"));\n\t\tclick_type = driver.FindElement(ById(\"click_type\")).Clear();\n\t\tupdown_type = driver.FindElement(ById(\"updown_type\")).Clear();\n\t\tupdown_button = driver.FindElement(ById(\"updown_button\")).Clear();\n\t}\n\n\tstd::string GetValue(const Element& element) {\n\t\treturn element.GetAttribute(\"value\");\n\t}\n\n\tWebDriver driver;\n\tElement target;\n\tElement click_type;\n\tElement updown_type;\n\tElement updown_button;\n};\n\nTEST_F(TestMouse, SendsClick) {\n\tdriver.MoveToCenterOf(target).Click();\n\tASSERT_EQ(\"click\", GetValue(click_type));\n}\n\nTEST_F(TestMouse, MovesPointerInsideTarget) {\n\tdriver.MoveToCenterOf(target).MoveTo(Offset(-45,-45)).Click();\n\tASSERT_EQ(\"click\", GetValue(click_type));\n}\n\nTEST_F(TestMouse, MovesPointerOutsideTarget) {\n\tif (IsFirefox()) return;\n\tdriver.MoveToCenterOf(target).MoveTo(Offset(55,55)).Click();\n\tdriver.MoveToCenterOf(target).MoveTo(Offset(-55,55)).Click();\n\tdriver.MoveToCenterOf(target).MoveTo(Offset(-55,-55)).Click();\n\tdriver.MoveToCenterOf(target).MoveTo(Offset(55,-55)).Click();\n\tASSERT_EQ(\"\", GetValue(click_type));\n}\n\nTEST_F(TestMouse, MovesPointerToTopLeftCorner) {\n\tdriver.MoveToTopLeftOf(target).Click();\n\tASSERT_EQ(\"click\", GetValue(click_type));\n}\n\nTEST_F(TestMouse, MovesPointerToTopLeftCornerWithOffset) {\n\tdriver.MoveToTopLeftOf(target, Offset(95,95)).Click();\n\tASSERT_EQ(\"click\", GetValue(click_type));\n}\n\nTEST_F(TestMouse, MovesPointerToTopLeftCornerWithOffset2) {\n\tif (IsFirefox()) return;\n\tdriver.MoveToTopLeftOf(target, Offset(-5,-5)).Click();\n\tdriver.MoveToTopLeftOf(target, Offset(105,105)).Click();\n\tASSERT_EQ(\"\", GetValue(click_type));\n}\n\nTEST_F(TestMouse, SendsDoubleclicks) {\n\tdriver.MoveToCenterOf(target).DoubleClick();\n\tASSERT_EQ(\"dblclick\", GetValue(click_type));\n}\n\nTEST_F(TestMouse, SendsButtonDown) {\n\tdriver.MoveToCenterOf(target).ButtonDown();\n\tASSERT_EQ(\"mousedown\", GetValue(updown_type));\n\tdriver.ButtonUp();\n}\n\nTEST_F(TestMouse, SendsButtonUp) {\n\tdriver.MoveToCenterOf(target).ButtonDown().ButtonUp();\n\tASSERT_EQ(\"mouseup\", GetValue(updown_type));\n}\n\nTEST_F(TestMouse, SendsDifferentButtons) {\n\tif (IsFirefox()) return;\n\tdriver.MoveToCenterOf(target).ButtonDown(mouse::LeftButton).ButtonUp(mouse::LeftButton);\n\tconst auto left_button = GetValue(updown_button);\n\tdriver.ButtonDown(mouse::RightButton).ButtonUp(mouse::RightButton);\n\tconst auto right_button = GetValue(updown_button);\n\tdriver.ButtonDown(mouse::MiddleButton).ButtonUp(mouse::MiddleButton);\n\tconst auto middle_button = GetValue(updown_button);\n\tASSERT_NE(left_button, right_button);\n\tASSERT_NE(left_button, middle_button);\n\tASSERT_NE(right_button, middle_button);\t\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/pages/alerts.html",
    "content": "<html>\n<body>\n</body>\n</html>"
  },
  {
    "path": "test/pages/element.html",
    "content": "<html>\n<body>\n<div id=\"first_div\"></div>\n<div id=\"second_div\"></div>\n<div id=\"third_div\"></div>\n<div id=\"element_with_text\">Some text</div>\n<div id=\"div_with_attributes\" test=\"test value\"></div>\n<input>\n<div id=\"visible\">visible text</div>\n<div id=\"hidden\" style=\"display:none\">hidden text</div>\n</body>\n</html>"
  },
  {
    "path": "test/pages/finder.html",
    "content": "<html>\n<body>\n<div id=\"test_id\"></div>\n<div class=\"test_class\"></div>\n<div id=\"css_selectable\"></div>\n<input name=\"test_name\">\n<a href=\"\">test link text</a>\n<div id=\"outer\">\n\t<div id=\"inner\"></div>\n\t<div></div>\n</div>\n<div id=\"next_after_outer\"></div>\n<div id=\"finder_loaded\"></div>\n</body>\n</html>"
  },
  {
    "path": "test/pages/frame1.html",
    "content": "<html>\n<body>\n<input id=\"tag\" value=\"frame1\">\n</body>\n</html>"
  },
  {
    "path": "test/pages/frame2.html",
    "content": "<html>\n<body>\n<input id=\"tag\" value=\"frame2\">\n</body>\n</html>"
  },
  {
    "path": "test/pages/frame3.html",
    "content": "<html>\n<body>\n<input id=\"tag\" value=\"frame3\">\n</body>\n</html>"
  },
  {
    "path": "test/pages/frames.html",
    "content": "<html>\n<body>\n<input id=\"tag\" value=\"top_frame\">\n<iframe src=\"frameset.html\" name=\"frameset_name\"></iframe>\n<iframe src=\"frame3.html\" name=\"frame3_name\"></iframe>\n</body>\n</html>"
  },
  {
    "path": "test/pages/frameset.html",
    "content": "<html>\n<frameset rows=\"*\" cols=\"50,*\">\n<frame src=\"frame1.html\" name=\"frame1_name\">\n<frame src=\"frame2.html\" name=\"frame2_name\">\n</frameset>\n</html>"
  },
  {
    "path": "test/pages/js.html",
    "content": "<html>\n<body>\n<input>\n</body>\n</html>"
  },
  {
    "path": "test/pages/keyboard.html",
    "content": "<html>\n<body>\n<input name=\"first\">\n<input name=\"second\">\n</body>\n</html>"
  },
  {
    "path": "test/pages/mouse.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<script type=\"text/javascript\">\n\tfunction report_click(event) {\n\t\tdocument.getElementById('click_type').value = event.type;\n\t\tdocument.getElementById('click_button').value = event.button;\n\t}\n\n\tfunction report_updown(event) {\n\t\tdocument.getElementById('updown_type').value = event.type;\n\t\tdocument.getElementById('updown_button').value = event.button;\n\t}\n\n</script>\n<style type=\"text/css\">\n\t* { border: none; padding: 0; margin: 0; }\n\t#target { width: 100px; height: 100px; margin: 50px; background-color: red; }\n</style>\n</head>\n<body>\n<div id=\"target\"\nonclick=\"report_click(event)\"\nondblclick=\"report_click(event)\"\nonmousedown=\"report_updown(event)\"\nonmouseup=\"report_updown(event)\"\n></div>\n<div><input id=\"click_type\"></div>\n<div><input id=\"click_button\"></div>\n<div><input id=\"updown_type\"></div>\n<div><input id=\"updown_button\"></div>\n</body>\n</html>"
  },
  {
    "path": "test/pages/navigation1.html",
    "content": "<html>\n<body>\nNavigation 1\n<input>\n</body>\n</html>"
  },
  {
    "path": "test/pages/navigation2.html",
    "content": "<html>\n<body>\nNavigation 2\n</body>\n</html>"
  },
  {
    "path": "test/pages/redirect.html",
    "content": "<html>\n<body>\n<script type=\"text/javascript\">location = \"target.html\"</script>\n</body>\n</html>"
  },
  {
    "path": "test/pages/session.html",
    "content": "<html>\n<head>\n<title>Test title</title>\n</head>\n<body>\n<input>\n</body>\n</html>"
  },
  {
    "path": "test/pages/webdriver.html",
    "content": "<html>\n<body>\n<input>\n</body>\n</html>"
  },
  {
    "path": "test/resource_test.cpp",
    "content": "#include <webdriverxx/detail/resource.h>\n#include <webdriverxx/detail/http_client.h>\n#include <webdriverxx/response_status_code.h>\n#include <gtest/gtest.h>\n#include <gmock/gmock.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\nusing namespace webdriverxx::detail;\n\nconst char *const kTestUrl = \"http://test/\";\n\nstruct MockHttpClient : IHttpClient, SharedObjectBase {\n\tMOCK_CONST_METHOD1(Get, HttpResponse(const std::string& url));\n\tMOCK_CONST_METHOD2(Post, HttpResponse(const std::string& url, const std::string& data));\n\tMOCK_CONST_METHOD1(Delete, HttpResponse(const std::string& url));\n};\n\nusing namespace ::testing;\n\nstruct TestResource : Test {\n\tvoid SetUp() {\n\t\thttp_response.http_code = 200;\n\t\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":0,\\\"value\\\":12345}\";\n\t\n\t\thttp_client = Shared<MockHttpClient>(new MockHttpClient);\n\t\tDefaultValue<HttpResponse>::Set(HttpResponse());\n\t\tON_CALL(*http_client, Get(_)).WillByDefault(ReturnPointee(&http_response));\n\t\tON_CALL(*http_client, Post(_,_)).WillByDefault(ReturnPointee(&http_response));\n\t\tON_CALL(*http_client, Delete(_)).WillByDefault(ReturnPointee(&http_response));\n\t\tEXPECT_CALL(*http_client, Get(_)).Times(AnyNumber());\n\t\tEXPECT_CALL(*http_client, Post(_,_)).Times(AnyNumber());\n\t\tEXPECT_CALL(*http_client, Delete(_)).Times(AnyNumber());\n\t}\n\n\tShared<MockHttpClient> http_client;\n\tHttpResponse http_response;\n};\n\n// Positive tests\n\nTEST_F(TestResource, CanBeCreated) {\n\tResource resource(kTestUrl, http_client);\n}\n\nTEST_F(TestResource, ReturnsUrl) {\n\tResource resource(kTestUrl, http_client);\n\tASSERT_EQ(kTestUrl, resource.GetUrl());\n}\n\nTEST_F(TestResource, CanBeUsedToMakeSubResource) {\n\tShared<Resource> a(new Resource(\"a\", http_client));\n\tASSERT_EQ(\"a/c\", MakeSubResource(a, \"c\")->GetUrl());\n\tASSERT_EQ(\"a/c\",MakeSubResource(a, \"/c\")->GetUrl());\n\tShared<Resource> b(new Resource(\"b/\", http_client));\n\tASSERT_EQ(\"b/c\", MakeSubResource(b, \"c\")->GetUrl());\n\tASSERT_EQ(\"b/c\", MakeSubResource(b, \"/c\")->GetUrl());\n}\n\nTEST_F(TestResource, DoesNotDeleteResourceByDefault)\n{\n\tEXPECT_CALL(*http_client, Delete(_)).Times(0);\n\tResource resource(kTestUrl, http_client);\n}\n\nTEST_F(TestResource, DeletesResourceIfOwnershipIsEnabled)\n{\n\tEXPECT_CALL(*http_client, Delete(kTestUrl));\n\tResource resource(kTestUrl, http_client, Resource::IsOwner);\n}\n\nTEST_F(TestResource, SharesOwnershipOfParentResource)\n{\n\tEXPECT_CALL(*http_client, Delete(_)).Times(0);\n\tShared<Resource> parent(new Resource(\"parent\", http_client, Resource::IsOwner));\n\tShared<Resource> child = MakeSubResource(parent, \"child\", Resource::IsOwner);\n\tparent = Shared<Resource>();\n\tMock::VerifyAndClear(http_client); // Parent shouldn't be deleted at this point because child is alive\n\tInSequence check_delete_order;\n\tEXPECT_CALL(*http_client, Delete(\"parent/child\"));\n\tEXPECT_CALL(*http_client, Delete(\"parent\"));\n\tchild = Shared<Resource>();\n}\n\nTEST_F(TestResource, RootResourceReturnsJsonObject)\n{\n\tRootResource resource(kTestUrl, http_client);\n\thttp_response.http_code = 200;\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":0,\\\"value\\\":12345}\";\n\tASSERT_TRUE(resource.Get(\"command\").is<picojson::object>());\n}\n\nTEST_F(TestResource, RootResourceReturnsSessionId)\n{\n\tRootResource resource(kTestUrl, http_client);\n\thttp_response.http_code = 200;\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":0,\\\"value\\\":12345}\";\n\tASSERT_TRUE(resource.Get(\"command\").contains(\"sessionId\"));\n\tASSERT_EQ(\"123\", resource.Get(\"command\").get(\"sessionId\").to_str());\n}\n\nTEST_F(TestResource, RootResourceReturnsNullSessionId)\n{\n\tRootResource resource(kTestUrl, http_client);\n\thttp_response.body = \"{\\\"sessionId\\\":null,\\\"status\\\":0,\\\"value\\\":12345}\";\n\tASSERT_TRUE(resource.Get(\"command\").contains(\"sessionId\"));\n\tASSERT_TRUE(resource.Get(\"command\").get(\"sessionId\").is<picojson::null>());\n}\n\nTEST_F(TestResource, RootResourceReturnsScalarValueFromPositiveResponse)\n{\n\tRootResource resource(kTestUrl, http_client);\n\thttp_response.http_code = 200;\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":0,\\\"value\\\":12345}\";\n\tpicojson::value value = resource.Get(\"command\").get(\"value\");\n\tASSERT_TRUE(value.is<double>());\n\tASSERT_EQ(12345, value.get<double>());\n}\n\nTEST_F(TestResource, RootResourceReturnsObjectValueFromPositiveResponse)\n{\n\tRootResource resource(kTestUrl, http_client);\n\thttp_response.http_code = 200;\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":0,\\\"value\\\":{\\\"member\\\":12345}}\";\n\tpicojson::value value = resource.Get(\"command\").get(\"value\");\n\tASSERT_TRUE(value.is<picojson::object>());\n\tASSERT_TRUE(value.contains(\"member\"));\n\tASSERT_TRUE(value.get(\"member\").is<double>());\n\tASSERT_EQ(12345, value.get(\"member\").get<double>());\n}\n\nTEST_F(TestResource, ReturnsScalarValueFromPositiveResponse)\n{\n\tResource resource(kTestUrl, http_client);\n\thttp_response.http_code = 200;\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":0,\\\"value\\\":12345}\";\n\tpicojson::value value = resource.Get(\"command\");\n\tASSERT_TRUE(value.is<double>());\n\tASSERT_EQ(12345, value.get<double>());\n}\n\nTEST_F(TestResource, ReturnsObjectValueFromPositiveResponse)\n{\n\tResource resource(kTestUrl, http_client);\n\thttp_response.http_code = 200;\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":0,\\\"value\\\":{\\\"member\\\":12345}}\";\n\tpicojson::value value = resource.Get(\"command\");\n\tASSERT_TRUE(value.is<picojson::object>());\n\tASSERT_TRUE(value.contains(\"member\"));\n\tASSERT_TRUE(value.get(\"member\").is<double>());\n\tASSERT_EQ(12345, value.get(\"member\").get<double>());\n}\n\n// Negative tests\n\nTEST_F(TestResource, ThrowsOnHttp404)\n{\n\thttp_response.http_code = 404;\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp400)\n{\n\thttp_response.http_code = 400;\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp499)\n{\n\thttp_response.http_code = 499;\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp501)\n{\n\thttp_response.http_code = 501;\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, DoesNotHideHttpExceptions)\n{\n\tEXPECT_CALL(*http_client, Get(_)).WillOnce(Throw(WebDriverException(\"HTTP failed\")));\n\tResource resource(kTestUrl, http_client);\n\ttry {\n\t\tresource.Get(\"command\");\n\t\tFAIL(); // Shouldn't get here\n\t} catch (const std::exception& e) {\n\t\tconst std::string message = e.what();\n\t\tASSERT_NE(std::string::npos, message.find(\"HTTP failed\"));\n\t}\n}\n\nTEST_F(TestResource, AddsContextToExceptions)\n{\n\tEXPECT_CALL(*http_client, Get(_)).WillOnce(Throw(WebDriverException(\"HTTP failed\")));\n\tResource resource(kTestUrl, http_client);\n\ttry {\n\t\tresource.Get(\"pinky\");\n\t\tFAIL(); // Shouldn't get here\n\t} catch (const std::exception& e) {\n\t\tconst std::string message = e.what();\n\t\tASSERT_NE(std::string::npos, message.find(\"pinky\"));\n\t}\n}\n\nTEST_F(TestResource, WebDriverExceptionContainsCommandAndHttpCodeAndBody)\n{\n\thttp_response.http_code = 501;\n\thttp_response.body = \"--oops--\";\n\tResource resource(kTestUrl, http_client);\n\ttry {\n\t\tresource.Get(\"pinky\");\n\t\tFAIL(); // Shouldn't get here\n\t} catch (const std::exception& e) {\n\t\tconst std::string message = e.what();\n\t\tASSERT_NE(std::string::npos, message.find(\"pinky\"));\n\t\tASSERT_NE(std::string::npos, message.find(\"--oops--\"));\n\t\tASSERT_NE(std::string::npos, message.find(\"501\"));\n\t}\n}\n\nTEST_F(TestResource, WebDriverExceptionContainsStatusAndStatusDescription)\n{\n\thttp_response.http_code = 500;\n\thttp_response.body = Fmt() << \"{\\\"status\\\":\"\n\t\t<< response_status_code::kNoSuchWindow\n\t\t<< \",\\\"value\\\":{\\\"message\\\":\\\"12345\\\"}}\";\n\tResource resource(kTestUrl, http_client);\n\ttry {\n\t\tresource.Get(\"pinky\");\n\t\tFAIL(); // Shouldn't get here\n\t} catch (const std::exception& e) {\n\t\tconst std::string message = e.what();\n\t\tASSERT_NE(std::string::npos, message.find(Fmt() << response_status_code::kNoSuchWindow));\n\t\tASSERT_NE(std::string::npos, message.find(response_status_code::ToString(response_status_code::kNoSuchWindow)));\n\t}\n}\n\nTEST_F(TestResource, ThrowsOnHttp500)\n{\n\thttp_response.http_code = 500;\n\thttp_response.body = \"{\\\"status\\\":12,\\\"value\\\":{\\\"message\\\":\\\"12345\\\"}}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp500AndMissingStatus)\n{\n\thttp_response.http_code = 500;\n\thttp_response.body = \"{\\\"value\\\":{\\\"message\\\":\\\"12345\\\"}}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp500AndInvalidStatus)\n{\n\thttp_response.http_code = 500;\n\thttp_response.body = \"{\\\"status\\\":\\\"xxx\\\",\\\"value\\\":{\\\"message\\\":\\\"12345\\\"}}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp500AndMissingValue)\n{\n\thttp_response.http_code = 500;\n\thttp_response.body = \"{\\\"status\\\":12}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp500AndInvalidValue)\n{\n\thttp_response.http_code = 500;\n\thttp_response.body = \"{\\\"status\\\":\\\"xxx\\\",\\\"value\\\":\\\"12345\\\"}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp500AndMissingMessage)\n{\n\thttp_response.http_code = 500;\n\thttp_response.body = \"{\\\"status\\\":12,\\\"value\\\":{\\\"xxx\\\":\\\"12345\\\"}}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp500AndInvalidMessage)\n{\n\thttp_response.http_code = 500;\n\thttp_response.body = \"{\\\"status\\\":12,\\\"value\\\":{\\\"message\\\":12345}}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp399)\n{\n\thttp_response.http_code = 399;\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnHttp502)\n{\n\thttp_response.http_code = 502;\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnEmptyResponse)\n{\n\tResource resource(kTestUrl, http_client);\n\thttp_response.body = \"\";\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnMalformedResponse)\n{\n\tResource resource(kTestUrl, http_client);\n\thttp_response.body = \"Blah blah blah\";\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsIfResponseIsNotAnObject)\n{\n\tResource resource(kTestUrl, http_client);\n\thttp_response.body = \"\\\"value\\\":123\";\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnMissingStatus)\n{\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"value\\\":12345}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnInvalidStatus)\n{\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":\\\"5\\\",\\\"value\\\":12345}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnNonZeroStatus)\n{\n\tResource resource(kTestUrl, http_client);\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":5,\\\"value\\\":12345}\";\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\nTEST_F(TestResource, ThrowsOnMissingValue)\n{\n\thttp_response.body = \"{\\\"sessionId\\\":\\\"123\\\",\\\"status\\\":0}\";\n\tResource resource(kTestUrl, http_client);\n\tASSERT_THROW(resource.Get(\"command\"), WebDriverException);\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/session_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/session.h>\n#include <gtest/gtest.h>\n#include <algorithm>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nclass TestSession : public ::testing::Test {\nprotected:\n\tTestSession() : driver(GetDriver()) {}\n\n\tvoid ReplaceSpoiledSession() {\n\t\tdriver = GetFreshDriver();\n\t}\n\n\tWebDriver driver;\n};\n\nTEST_F(TestSession, GetsCapabilities)\n{\n\tCapabilities c = driver.GetCapabilities();\n\tASSERT_TRUE(c.Has(\"browserName\"));\n\tASSERT_TRUE(c.Has(\"version\"));\n\tASSERT_TRUE(c.Has(\"platform\"));\n\tASSERT_NE(\"\", c.GetBrowserName());\n}\n\nTEST_F(TestSession, StartsSecondBrowser) {\n\tWebDriver second = CreateDriver();\n}\n\nTEST_F(TestSession, GetsCurrentWindow) {\n\tdriver.GetCurrentWindow();\n}\n\nTEST_F(TestSession, GetsWindowHandle) {\n\tASSERT_NE(\"\", driver.GetCurrentWindow().GetHandle());\n}\n\nTEST_F(TestSession, SetsFocusToWindow) {\n\tdriver.SetFocusToWindow(driver.GetCurrentWindow().GetHandle());\n}\n\nTEST_F(TestSession, ClosesCurrentWindow) {\n\tdriver.CloseCurrentWindow();\n\tReplaceSpoiledSession();\n}\n\nTEST_F(TestSession, GetsWindowSize) {\n\tWindow window = driver.GetCurrentWindow();\n\twindow.GetSize();\n}\n\nTEST_F(TestSession, SetsWindowSize) {\n\tWindow window = driver.GetCurrentWindow();\n\tSize size1;\n\tsize1.width = 601;\n\tsize1.height = 602;\n\twindow.SetSize(size1);\n\tSize size2 = window.GetSize();\n\tASSERT_EQ(601, size2.width);\n\tASSERT_EQ(602, size2.height);\n}\n\nTEST_F(TestSession, GetsWindowPosition) {\n\tWindow window = driver.GetCurrentWindow();\n\twindow.GetPosition();\n}\n\nTEST_F(TestSession, SetsWindowPosition) {\n\tif (IsPhantom()) return;\n\tWindow window = driver.GetCurrentWindow();\n\tPoint position1;\n\tposition1.x = 101;\n\tposition1.y = 102;\n\twindow.SetPosition(position1);\n\tPoint position2 = window.GetPosition();\n\tASSERT_EQ(101, position2.x);\n\tASSERT_EQ(102, position2.y);\n}\n\nTEST_F(TestSession, MaximizesWindow) {\n\tWindow window = driver.GetCurrentWindow();\n\twindow.Maximize();\n}\n\nTEST_F(TestSession, GetsWindows) {\n\tdriver.GetWindows();\n}\n\nTEST_F(TestSession, Navigates) {\n\tstd::string url = GetWebDriverUrl() + \"status\";\n\tdriver.Navigate(url);\n\tASSERT_EQ(url, driver.GetUrl());\n}\n\nTEST_F(TestSession, NavigatesToTestPage) {\n\tconst std::string url = GetTestPageUrl(\"session.html\");\n\tdriver.Navigate(url);\n\tASSERT_EQ(url, driver.GetUrl());\n}\n\nTEST_F(TestSession, GoesBack) {\n\tconst std::string page1 = GetTestPageUrl(\"navigation1.html\");\n\tconst std::string page2 = GetTestPageUrl(\"navigation2.html\");\n\tdriver.Navigate(page1).Navigate(page2).Back();\n\tASSERT_EQ(page1, driver.GetUrl());\n}\n\nTEST_F(TestSession, GoesForward) {\n\tconst std::string page1 = GetTestPageUrl(\"navigation1.html\");\n\tconst std::string page2 = GetTestPageUrl(\"navigation2.html\");\n\tdriver.Navigate(page1).Navigate(page2).Back().Forward();\n\tASSERT_EQ(page2, driver.GetUrl());\n}\n\nTEST_F(TestSession, DoesRefresh) {\n\tconst std::string page = GetTestPageUrl(\"navigation1.html\");\n\tdriver.Navigate(page).FindElement(ByTag(\"input\")).Click().SendKeys(\"abc\");\n\tASSERT_EQ(\"abc\", driver.FindElement(ByTag(\"input\")).GetAttribute(\"value\"));\n\tdriver.Refresh();\n\tASSERT_EQ(page, driver.GetUrl());\n\tASSERT_EQ(\"\", driver.FindElement(ByTag(\"input\")).GetAttribute(\"value\"));\n}\n\nTEST_F(TestSession, GetsPageSource) {\n\tdriver.Navigate(GetTestPageUrl(\"session.html\"));\n\tstd::string source = driver.GetSource();\n\tASSERT_NE(std::string::npos, source.find(\"<html\"));\n\tASSERT_NE(std::string::npos, source.find(\"</html>\"));\n}\n\nTEST_F(TestSession, GetsPageTitle) {\n\tdriver.Navigate(GetTestPageUrl(\"session.html\"));\n\tASSERT_EQ(\"Test title\", driver.GetTitle());\n}\n\nTEST_F(TestSession, GetsScreenshot) {\n\tdriver.Navigate(GetTestPageUrl(\"session.html\"));\n\tASSERT_TRUE(!driver.GetScreenshot().empty());\n}\n\nTEST_F(TestSession, SetsTimeouts) {\n\tdriver.SetTimeoutMs(timeout::Implicit, 1000);\n\tdriver.SetTimeoutMs(timeout::PageLoad, 1000);\n\tdriver.SetTimeoutMs(timeout::Script, 1000);\n}\n\nTEST_F(TestSession, SetsAsyncScriptTimeout) {\n\tdriver.SetAsyncScriptTimeoutMs(1000);\n}\n\nTEST_F(TestSession, SetsImplicitTimeout) {\n\tdriver.SetImplicitTimeoutMs(1000);\n}\n\nTEST_F(TestSession, GetsActiveElement) {\n\tdriver.Navigate(GetTestPageUrl(\"session.html\"));\n\tElement e = driver.FindElement(ByTag(\"input\"));\n\te.Click();\n\tASSERT_EQ(e, driver.GetActiveElement());\n}\n\nCookie FindCookie(\n\tconst std::vector<Cookie>& cookies,\n\tconst std::string& name,\n\tconst Cookie& default_value = Cookie()\n\t) {\n\tconst auto it = std::find_if(cookies.begin(), cookies.end(),\n\t\t[&name](const Cookie& cookie){\n\t\t\treturn cookie.name == name;\n\t\t});\n\treturn it != cookies.end() ? *it : default_value;\n}\n\nnamespace webdriverxx {\n\nvoid PrintTo(const Cookie& c, ::std::ostream* os) {\n\t*os << ToJson(c).serialize();\n}\n\n} // namespace webdriverxx\n\nTEST_F(TestSession, SetsAndGetsCookies) {\n\tdriver.Navigate(GetTestPageUrl(\"session.html\"));\n\tdriver.SetCookie(Cookie(\"name1\", \"value1\")).SetCookie(Cookie(\"name2\", \"value2\"));\n\tstd::vector<Cookie> cookies = driver.GetCookies();\n\tASSERT_TRUE(cookies.size() >= 2u);\n\tASSERT_EQ(\"value1\", FindCookie(cookies, \"name1\").value);\n\tASSERT_EQ(\"value2\", FindCookie(cookies, \"name2\").value);\n}\n\nTEST_F(TestSession, SetsAllFieldsOfACookie) {\n\tconst Cookie c1(\"name1\", \"value1\", \"/path1\", \"domain1.com\", true, true, 123);\n\tconst Cookie c2(\"name2\", \"value2\", \"/path2\", \"domain2.com\", false, false, 124);\n\tASSERT_EQ(c1, FromJson<Cookie>(ToJson(c1)));\n\tASSERT_EQ(c2, FromJson<Cookie>(ToJson(c2)));\n}\n\nTEST_F(TestSession, DeletesCookies) {\n\tdriver.Navigate(GetTestPageUrl(\"session.html\"));\n\tdriver.SetCookie(Cookie(\"name1\", \"value1\")).SetCookie(Cookie(\"name2\", \"value2\"));\n\tdriver.DeleteCookies();\n\tASSERT_EQ(0u, driver.GetCookies().size());\n}\n\nTEST_F(TestSession, DeletesACookie) {\n\tdriver.Navigate(GetTestPageUrl(\"session.html\"));\n\tdriver.SetCookie(Cookie(\"name1\", \"value1\")).SetCookie(Cookie(\"name2\", \"value2\"));\n\tdriver.DeleteCookie(\"name1\");\n\tstd::vector<Cookie> cookies = driver.GetCookies();\n\tASSERT_EQ(\"\", FindCookie(cookies, \"name1\").value);\n\tASSERT_EQ(\"value2\", FindCookie(cookies, \"name2\").value);\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/shared_test.cpp",
    "content": "#include <webdriverxx/detail/shared.h>\n#include <gtest/gtest.h>\n#include <cassert>\n\nnamespace test {\n\nusing namespace webdriverxx::detail;\n\nstruct WidgetMonitor {\n\tWidgetMonitor()\n\t\t: created(0)\n\t\t, copied(0)\n\t\t, deleted(0)\n\t{}\n\n\tint created;\n\tint copied;\n\tint deleted; \n};\n\nstruct Simple : SharedObjectBase {\n\tint n;\n\tSimple() : n() {}\n};\n\nclass Widget : public SharedObjectBase {\npublic:\n\tWidget(WidgetMonitor& monitor)\n\t\t: monitor(monitor) {\n\t\t++monitor.created;\n\t}\n\n\tWidget(const Widget& other)\n\t\t: monitor(other.monitor) {\n\t\t++monitor.created;\n\t}\n\t\n\tWidget& operator = (const Widget& other) {\n\t\tassert(&monitor == &other.monitor);\n\t\t++monitor.copied;\n\t\treturn *this;\n\t}\n\n\tvirtual ~Widget() {\n\t\t++monitor.deleted;\t\t\n\t}\n\nprivate:\n\tWidgetMonitor& monitor;\n};\n\nclass WidgetSubclass : public Widget {\npublic:\n\tWidgetSubclass(WidgetMonitor& monitor) : Widget(monitor) {}\n};\n\nTEST(WidgetMonitor, ZeroByDefault) {\n\tWidgetMonitor m;\n\tASSERT_EQ(0, m.created);\n\tASSERT_EQ(0, m.copied);\n\tASSERT_EQ(0, m.deleted);\n}\n\nTEST(WidgetMonitor, ShowsCreateAndDelete) {\n\tWidgetMonitor m;\n\t((void)Widget(m));\n\tASSERT_EQ(1, m.created);\n\tASSERT_EQ(0, m.copied);\n\tASSERT_EQ(1, m.deleted);\n}\n\nTEST(WidgetMonitor, ShowsCopy) {\n\tWidgetMonitor m;\n\tWidget w1(m);\n\tWidget w2(m);\n\tw2 = w1;\n\tASSERT_EQ(1, m.copied);\n\n}\n\nTEST(WidgetMonitor, MonitorsWidgetSubclass) {\n\tWidgetMonitor m;\n\t((void)WidgetSubclass(m));\n\tASSERT_EQ(1, m.created);\n\tASSERT_EQ(0, m.copied);\n\tASSERT_EQ(1, m.deleted);\n}\n\nTEST(Shared, DeletesWidget) {\n\tWidgetMonitor m;\n\tShared<Widget>(new Widget(m));\n\tASSERT_EQ(1, m.created);\n\tASSERT_EQ(1, m.deleted);\n}\n\nTEST(Shared, ShareSingleWidget) {\n\tWidgetMonitor m;\n\t{\n\t\tShared<Widget> a(new Widget(m));\n\t\tShared<Widget> b = a;\n\t\tShared<Widget> c;\n\t\tc = b;\n\t}\n\tASSERT_EQ(1, m.created);\n\tASSERT_EQ(0, m.copied);\n\tASSERT_EQ(1, m.deleted);\n}\n\nTEST(Shared, SupportsImplicitTypecasts) {\n\tWidgetMonitor m;\n\t{\n\t\tShared<Widget> c;\n\t\tShared<WidgetSubclass> a(new WidgetSubclass(m));\n\t\tShared<Widget> b = a;\n\t\tc = b;\n\t}\n\tASSERT_EQ(1, m.created);\n\tASSERT_EQ(0, m.copied);\n\tASSERT_EQ(1, m.deleted);\n}\n\nTEST(Shared, CanBeUsedInBoolContext) {\n\tShared<Simple> s1;\n\tShared<Simple> s2(new Simple);\n\tASSERT_TRUE(!s1);\n\tASSERT_TRUE(!!s2);\n}\n\nTEST(Shared, CanBeDereferenced) {\n\tSimple* p = new Simple;\n\tShared<Simple> s(p);\n\tp->n = 123;\n\tASSERT_EQ(123, (*s).n);\n\tASSERT_EQ(123, s->n);\n}\n\nTEST(Shared, CanBeCompared) {\n\tShared<Simple> s1;\n\tShared<Simple> s2(new Simple);\n\tShared<Simple> s3 = s2;\n\tShared<Simple> s4(new Simple);\n\tASSERT_TRUE(s1 != s2);\n\tASSERT_TRUE(s1 != s3);\n\tASSERT_TRUE(s2 == s3);\n\tASSERT_TRUE(s2 != s4);\n\tASSERT_TRUE(s1 == s1);\n\tASSERT_TRUE(s2 == s2);\n\tASSERT_TRUE(s3 == s3);\n\tASSERT_TRUE(s4 == s4);\n\tASSERT_TRUE(s1 == 0);\n\tASSERT_TRUE(s2 != 0);\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/to_string_test.cpp",
    "content": "#include <webdriverxx/detail/to_string.h>\r\n#include <gtest/gtest.h>\r\n\r\nnamespace test {\r\n\r\nusing namespace webdriverxx;\r\nusing namespace webdriverxx::detail;\r\n\r\nTEST(ToString, ConvertsIntegralTypes) {\r\n\tASSERT_EQ(\"123\", ToString(123));\r\n\tint i = 123;\r\n\tASSERT_EQ(\"123\", ToString(i));\r\n\tASSERT_EQ(\"123\", ToString(static_cast<const int>(i)));\r\n\tASSERT_EQ(\"'z'\", ToString('z'));\r\n\tchar c = 'z';\r\n\tASSERT_EQ(\"'z'\", ToString(c));\r\n\tASSERT_EQ(\"'z'\", ToString(static_cast<const char>(c)));\r\n}\r\n\r\nnamespace custom {\r\n\r\nstruct A {};\r\n\r\nstruct B {};\r\nstd::ostream& operator << (std::ostream& s, const B&) {\r\n\treturn s << \"B\";\r\n}\r\n\r\nstruct C {};\r\n\r\nvoid ToStream(const C&, std::ostream& s) {\r\n\ts << \"C\";\r\n}\r\n\r\nstruct G {};\r\nvoid PrintTo(const G&, std::ostream* s) {\r\n\t*s << \"G\";\r\n}\r\n\r\n} // namespace custom\r\n\r\nTEST(ToString, ConvertsCustomTypes) {\r\n\tASSERT_EQ(\"<non-printable>\", ToString(custom::A()));\r\n\tASSERT_EQ(\"B\", ToString(custom::B()));\r\n\tASSERT_EQ(\"C\", ToString(custom::C()));\r\n\tASSERT_EQ(\"G\", ToString(custom::G()));\r\n}\r\n\r\nTEST(ToString, ConvertsStrings) {\r\n\tASSERT_EQ(\"\\\"abc\\\"\", ToString(\"abc\"));\r\n\tchar a[] = \"abc\";\r\n\tASSERT_EQ(\"\\\"abc\\\"\", ToString(a));\r\n\tconst char ca[] = \"abc\";\r\n\tASSERT_EQ(\"\\\"abc\\\"\", ToString(ca));\r\n\tchar* pc = a;\r\n\tASSERT_EQ(\"\\\"abc\\\"\", ToString(pc));\r\n\tconst char* pcc = \"abc\";\r\n\tASSERT_EQ(\"\\\"abc\\\"\", ToString(pcc));\r\n\r\n\tASSERT_EQ(\"\\\"abc\\\"\", ToString(std::string(\"abc\")));\r\n\tstd::string s(\"abc\");\r\n\tASSERT_EQ(\"\\\"abc\\\"\", ToString(s));\r\n\tconst std::string cs(\"abc\");\r\n\tASSERT_EQ(\"\\\"abc\\\"\", ToString(cs));\r\n}\r\n\r\nTEST(ToString, ConvertsPointers) {\r\n\tint i = 123;\r\n\tASSERT_EQ(\"*123\", ToString(&i));\r\n\tconst int* cpi = &i;\r\n\tASSERT_EQ(\"**123\", ToString(&cpi));\r\n\tconst std::string s = \"abc\";\r\n\tASSERT_EQ(\"*\\\"abc\\\"\", ToString(&s));\r\n}\r\n\r\nTEST(ToString, ConvertsContainersOfIntegralTypes) {\r\n\tASSERT_EQ(\"[]\", ToString(std::vector<int>()));\r\n\tstd::vector<int> v;\r\n\tv.push_back(123);\r\n\tv.push_back(456);\r\n\tASSERT_EQ(\"*[123, 456]\", ToString(&v));\r\n\tint a[3] = { 123, 456, 789 };\r\n\tASSERT_EQ(\"[123, 456, 789]\", ToString(a));\r\n}\r\n\r\nTEST(ToString, ConvertsContainersOfCustomTypes) {\r\n\tstd::vector<custom::A> as(1);\r\n\tASSERT_EQ(\"[<non-printable>]\", ToString(as));\r\n\tstd::vector<custom::B> bs(1);\r\n\tASSERT_EQ(\"[B]\", ToString(bs));\r\n\tstd::vector<custom::C> cs(1);\r\n\tASSERT_EQ(\"[C]\", ToString(cs));\r\n\tstd::vector<custom::G> gs(1);\r\n\tASSERT_EQ(\"[G]\", ToString(gs));\r\n}\r\n\r\nTEST(ToString, ConvertsContainersOfStrings) {\r\n\tconst char* ss[] = { \"abc\", \"def\" };\r\n\tASSERT_EQ(\"[\\\"abc\\\", \\\"def\\\"]\", ToString(ss));\r\n\tASSERT_EQ(\"*[\\\"abc\\\", \\\"def\\\"]\", ToString(&ss));\r\n}\r\n\r\n} // namespace test\r\n"
  },
  {
    "path": "test/wait_match_test.cpp",
    "content": "#include <webdriverxx/wait_match.h>\r\n#include <gtest/gtest.h>\r\n\r\nnamespace test {\r\n\r\nusing namespace webdriverxx;\r\nusing namespace webdriverxx::detail;\r\n\r\nbool FunctionMatcher(int) { return true; }\r\n\r\nstruct FunctorMatcher {\r\n\tbool operator () (int) const {\r\n\t\treturn true;\r\n\t}\r\n};\r\n\r\nTEST(WaitForMatch, CanBeUsedWithFunctionFunctorAndLambda) {\r\n\tASSERT_EQ(123, WaitForMatch([]{ return 123; }, FunctionMatcher));\r\n\tASSERT_EQ(123, WaitForMatch([]{ return 123; }, FunctorMatcher()));\r\n\tASSERT_EQ(123, WaitForMatch([]{ return 123; }, [](int){ return true; }));\r\n}\r\n\r\nTEST(WaitForMatch, ReturnsMatchedValue) {\r\n\tASSERT_EQ(123, WaitForMatch([]{ return 123; }, [](int){ return true; }));\r\n}\r\n\r\nTEST(WaitForMatch, DoesNotWaitIfValueIsMatched) {\r\n\tDuration timeout = 1000;\r\n\tconst TimePoint start = Now();\r\n\tWaitForMatch([]{ return 0; }, [](int){ return true; }, timeout);\r\n\tASSERT_TRUE(Now() - start < timeout/2);\r\n}\r\n\r\nTEST(WaitForMatch, WaitsUntilValueIsMatched) {\r\n\tDuration timeout = 1000;\r\n\tDuration interval = 0;\r\n\tint counter = 0;\r\n\tWaitForMatch([]{ return 0; }, [&counter](int){ return ++counter == 10; }, timeout, interval);\r\n\tASSERT_EQ(10, counter);\r\n}\r\n\r\nTEST(WaitForMatch, ThrowsExceptionOnTimeout) {\r\n\tDuration timeout = 0;\r\n\tASSERT_THROW(WaitForMatch([]{ return 0; }, [](int){ return false; }, timeout), WebDriverException);\r\n}\r\n\r\nTEST(WaitForMatch, ExplainsTimeout) {\r\n\ttry {\r\n\t\tDuration timeout = 0;\r\n\t\tWaitForMatch([]{ return 0; }, [](int){ return false; }, timeout);\r\n\t\tFAIL();\r\n\t} catch (const std::exception& e) {\r\n\t\tstd::string message = e.what();\r\n\t\tconst auto npos = std::string::npos;\r\n\t\tASSERT_NE(npos, message.find(\"imeout\"));\r\n\t}\r\n}\r\n\r\nTEST(WaitForMatch, CanUseGMockMatchers) {\r\n\tusing namespace ::testing;\r\n\tASSERT_EQ(123, WaitForMatch([]{ return 123; }, Eq(123)));\r\n\tASSERT_EQ(123, WaitForMatch([]{ return 123; }, 123));\r\n\tASSERT_EQ(\"abc\", WaitForMatch([]{ return std::string(\"abc\"); }, \"abc\"));\r\n\tASSERT_EQ(\"abc\", WaitForMatch([]{ return std::string(\"abc\"); }, Eq(\"abc\")));\r\n\tASSERT_EQ(123, WaitForMatch([]{ return 123; }, _));\r\n\tASSERT_EQ(123, WaitForMatch([]{ return 123; }, An<int>()));\r\n\tstd::vector<int> v(1, 123);\r\n\tASSERT_EQ(v, WaitForMatch([&v]{ return v; }, Contains(123)));\r\n\tASSERT_EQ(v, WaitForMatch([&v]{ return v; }, Not(Contains(456))));\r\n\tDuration timeout = 0;\r\n\tASSERT_THROW(WaitForMatch([&v]{ return v; }, Not(Contains(123)), timeout), WebDriverException);\r\n}\r\n\r\nTEST(WaitForMatch, ExplainsGMockMatcherMismatch) {\r\n\ttry {\r\n\t\tDuration timeout = 0;\r\n\t\tusing namespace ::testing;\r\n\t\tWaitForMatch([]{ return 123; }, Eq(456), timeout);\r\n\t\tFAIL();\r\n\t} catch (const std::exception& e) {\r\n\t\tstd::string message = e.what();\r\n\t\tconst auto npos = std::string::npos;\r\n\t\tASSERT_NE(npos, message.find(\"123\"));\r\n\t\tASSERT_NE(npos, message.find(\"456\"));\r\n\t\tASSERT_NE(npos, message.find(\"imeout\"));\r\n\t}\r\n}\r\n\r\n} // namespace test\r\n"
  },
  {
    "path": "test/wait_test.cpp",
    "content": "#include <webdriverxx/wait.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\nusing namespace webdriverxx::detail;\n\nint FunctionGetter() { return 123; }\n\nstruct FunctorGetter {\n\tint operator () () const {\n\t\treturn 456;\n\t}\n};\n\nTEST(WaitForValue, CanBeUsedWithFunctionFunctorAndLambda) {\n\tASSERT_EQ(123, WaitForValue(FunctionGetter));\n\tASSERT_EQ(456, WaitForValue(FunctorGetter()));\n\tASSERT_EQ(789, WaitForValue([]{ return 789; }));\n}\n\nTEST(WaitForValue, DoesNotWaitIfValueIsReturned) {\n\tDuration timeout = 1000;\n\tconst TimePoint start = Now();\n\tWaitForValue(FunctionGetter, timeout);\n\tASSERT_TRUE(Now() - start < timeout/2);\n}\n\nTEST(WaitForValue, CallsGetterOnce) {\n\tint counter = 0;\n\tWaitForValue([&counter]{ return ++counter; });\n\tASSERT_EQ(1, counter);\n}\n\nTEST(WaitForValue, ThrowsExceptionOnTimeout) {\n\tDuration timeout = 0;\n\tASSERT_THROW(WaitForValue([]() -> int { throw std::exception(); }, timeout), WebDriverException);\n}\n\nTEST(WaitForValue, CallsGetterUntilItSucceeds) {\n\tDuration timeout = 1000;\n\tDuration interval = 0;\n\tint counter = 0;\n\tWaitForValue([&counter]() -> int {\n\t\tif (++counter < 10) throw std::exception();\n\t\treturn counter;\n\t}, timeout, interval);\n\tASSERT_EQ(10, counter);\n}\n\nTEST(WaitForValue, PassesErrorMessageFromGetter) {\n\tDuration timeout = 0;\n\ttry {\n\t\tWaitForValue([]() -> int { throw std::runtime_error(\"abc\"); }, timeout);\n\t\tFAIL();\n\t} catch (const WebDriverException& e) {\n\t\tstd::string message = e.what();\n\t\tconst auto npos = std::string::npos;\n\t\tASSERT_NE(npos, message.find(\"abc\"));\n\t\tASSERT_NE(npos, message.find(\"imeout\"));\n\t}\n}\n\nTEST(WaitUntil, DoesNotWaitIfValueNotFalsy) {\n\tDuration timeout = 1000;\n\tconst TimePoint start = Now();\n\tWaitUntil([]{ return true; }, timeout);\n\tASSERT_TRUE(Now() - start < timeout/2);\n}\n\nTEST(WaitUntil, CallsGetterOnce) {\n\tint counter = 0;\n\tWaitUntil([&counter]{ return ++counter; });\n\tASSERT_EQ(1, counter);\n}\n\nTEST(WaitUntil, ThrowsExceptionOnTimeout) {\n\tDuration timeout = 0;\n\tASSERT_THROW(WaitUntil([]() -> bool { throw std::exception(); }, timeout), WebDriverException);\n}\n\nTEST(WaitUntil, ThrowsExceptionOnTimeout2) {\n\tDuration timeout = 0;\n\tASSERT_THROW(WaitUntil([]{ return false; }, timeout), WebDriverException);\n}\n\n} // namespace test\n"
  },
  {
    "path": "test/webdriver_test.cpp",
    "content": "#include \"environment.h\"\n#include <webdriverxx/webdriver.h>\n#include <gtest/gtest.h>\n\nnamespace test {\n\nusing namespace webdriverxx;\n\nTEST(WebDriver, CreatesSession) {\n\tClient client(GetWebDriverUrl());\n\tsize_t number_of_sessions_before = client.GetSessions().size();\n\tWebDriver testee = CreateDriver();\n\tsize_t number_of_sessions_after = client.GetSessions().size();\n\tASSERT_EQ(number_of_sessions_before + 1, number_of_sessions_after);\n}\n\nTEST(WebDriver, DeletesSessionOnDestruction) {\n\tClient client(GetWebDriverUrl());\n\tsize_t number_of_sessions_before = 0;\n\t{\n\t\tWebDriver testee = CreateDriver();\n\t\tnumber_of_sessions_before = client.GetSessions().size();\n\t}\n\tsize_t number_of_sessions_after = client.GetSessions().size();\n\tASSERT_EQ(number_of_sessions_before - 1, number_of_sessions_after);\n}\n\nTEST(WebDriver, IsCopyable) {\n\tWebDriver driver1(GetDriver());\n\tconst WebDriver driver2 = driver1;\n\tWebDriver driver3 = driver1;\n\tdriver3 = driver2;\n\tASSERT_NO_THROW(GetDriver().GetSessions());\n\tASSERT_NO_THROW(driver1.GetSessions());\n\tASSERT_NO_THROW(driver2.GetSessions());\n\tASSERT_NO_THROW(driver3.GetSessions());\n}\n\nTEST(WebDriver, CopyableToClient) {\n\tWebDriver driver = GetDriver();\n\tClient client = driver;\n\tASSERT_NO_THROW(client.GetSessions());\n\tASSERT_NO_THROW(driver.GetSessions());\n}\n\nTEST(WebDriver, CopyableToSession) {\n\tWebDriver driver = GetDriver();\n\tSession session = driver;\n\tASSERT_NO_THROW(session.GetWindows());\n\tASSERT_NO_THROW(driver.GetWindows());\n}\n\nTEST(WebDriver, AndSatelliteObjectsHasNoLifetimeIssues) {\n\t// It is too expensive to restart the driver ->\n\t// try to test all objects in one test.\n\tWebDriver& driver = GetDriver();\n\tdriver.Navigate(GetTestPageUrl(\"webdriver.html\"));\n\n\tElement body = driver.FindElement(ByTag(\"body\"));\n\t{\n\t\tWindow window = driver.GetCurrentWindow();\n\t\t{\n\t\t\tSession session = driver;\n\t\t\t{\n\t\t\t\tClient client = driver;\n\t\t\t\t{\n\t\t\t\t\tWebDriver local_driver = driver;\n\t\t\t\t\tGetFreshDriver(); // Destroy global instance\n\t\t\t\t\tASSERT_NO_THROW(local_driver.GetSessions());\n\t\t\t\t\tASSERT_NO_THROW(local_driver.GetWindows());\n\t\t\t\t\tASSERT_NO_THROW(local_driver.FindElement(ByTag(\"input\")));\n\t\t\t\t}\n\t\t\t\tASSERT_NO_THROW(client.GetSessions());\n\t\t\t}\n\t\t\tASSERT_NO_THROW(session.GetWindows());\n\t\t\tASSERT_NO_THROW(session.FindElement(ByTag(\"input\")));\n\t\t}\n\t\tASSERT_NO_THROW(window.GetSize());\n\t}\n\tASSERT_NO_THROW(body.FindElement(ByTag(\"input\")));\n}\n\n} // namespace test\n"
  }
]