facter 3.9.6.cfacter.20180612 → 3.11.0.cfacter.20180319

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/ext/facter/facter/CMakeLists.txt +1 -1
  3. data/ext/facter/facter/acceptance/Gemfile +3 -4
  4. data/ext/facter/facter/acceptance/Rakefile +342 -2
  5. data/ext/facter/facter/acceptance/config/aio/options.rb +6 -0
  6. data/ext/facter/facter/acceptance/config/git/options.rb +5 -1
  7. data/ext/facter/facter/acceptance/setup/aio/pre-suite/010_Install.rb +22 -0
  8. data/ext/facter/facter/acceptance/setup/aio/pre-suite/021_InstallAristaModule.rb +12 -0
  9. data/ext/facter/facter/acceptance/setup/aio/pre-suite/022_Remove_LD_PRELOAD.rb +11 -0
  10. data/ext/facter/facter/acceptance/setup/common/00_EnvSetup.rb +64 -0
  11. data/ext/facter/facter/acceptance/setup/common/pre-suite/000-delete-puppet-when-none.rb +11 -0
  12. data/ext/facter/facter/acceptance/setup/git/pre-suite/01_TestSetup.rb +31 -0
  13. data/ext/facter/facter/acceptance/tests/ticket_1238_hostname_fqdn.rb +20 -0
  14. data/ext/facter/facter/lib/CMakeLists.txt +3 -2
  15. data/ext/facter/facter/lib/Doxyfile +1 -1
  16. data/ext/facter/facter/lib/inc/facter/facts/fact.hpp +5 -0
  17. data/ext/facter/facter/lib/inc/internal/facts/aix/networking_resolver.hpp +0 -7
  18. data/ext/facter/facter/lib/inc/internal/facts/freebsd/networking_resolver.hpp +0 -7
  19. data/ext/facter/facter/lib/inc/internal/facts/linux/fips_resolver.hpp +31 -0
  20. data/ext/facter/facter/lib/inc/internal/facts/linux/networking_resolver.hpp +0 -7
  21. data/ext/facter/facter/lib/inc/internal/facts/openbsd/networking_resolver.hpp +0 -7
  22. data/ext/facter/facter/lib/inc/internal/facts/osx/networking_resolver.hpp +0 -7
  23. data/ext/facter/facter/lib/inc/internal/facts/posix/networking_resolver.hpp +0 -7
  24. data/ext/facter/facter/lib/inc/internal/facts/resolvers/fips_resolver.hpp +46 -0
  25. data/ext/facter/facter/lib/inc/internal/facts/resolvers/networking_resolver.hpp +2 -3
  26. data/ext/facter/facter/lib/inc/internal/facts/resolvers/ssh_resolver.hpp +6 -0
  27. data/ext/facter/facter/lib/inc/internal/facts/solaris/networking_resolver.hpp +0 -7
  28. data/ext/facter/facter/lib/schema/facter.yaml +38 -18
  29. data/ext/facter/facter/lib/src/cwrapper.cc +5 -0
  30. data/ext/facter/facter/lib/src/facts/aix/disk_resolver.cc +2 -11
  31. data/ext/facter/facter/lib/src/facts/aix/networking_resolver.cc +0 -5
  32. data/ext/facter/facter/lib/src/facts/freebsd/dmi_resolver.cc +5 -1
  33. data/ext/facter/facter/lib/src/facts/freebsd/networking_resolver.cc +1 -10
  34. data/ext/facter/facter/lib/src/facts/freebsd/virtualization_resolver.cc +1 -4
  35. data/ext/facter/facter/lib/src/facts/linux/collection.cc +2 -0
  36. data/ext/facter/facter/lib/src/facts/linux/fips_resolver.cc +31 -0
  37. data/ext/facter/facter/lib/src/facts/linux/networking_resolver.cc +1 -10
  38. data/ext/facter/facter/lib/src/facts/openbsd/networking_resolver.cc +1 -10
  39. data/ext/facter/facter/lib/src/facts/osx/networking_resolver.cc +1 -10
  40. data/ext/facter/facter/lib/src/facts/posix/networking_resolver.cc +2 -3
  41. data/ext/facter/facter/lib/src/facts/posix/ssh_resolver.cc +3 -2
  42. data/ext/facter/facter/lib/src/facts/resolvers/fips_resolver.cc +23 -0
  43. data/ext/facter/facter/lib/src/facts/resolvers/networking_resolver.cc +7 -23
  44. data/ext/facter/facter/lib/src/facts/resolvers/ssh_resolver.cc +1 -0
  45. data/ext/facter/facter/lib/src/facts/solaris/networking_resolver.cc +0 -5
  46. data/ext/facter/facter/lib/tests/facts/resolvers/ssh_resolver.cc +8 -1
  47. data/ext/facter/facter/lib/tests/facts/schema.cc +17 -0
  48. data/ext/facter/facter/locales/FACTER.pot +2 -23
  49. data/ext/facter/leatherman/CHANGELOG.md +16 -9
  50. data/ext/facter/leatherman/CMakeLists.txt +1 -2
  51. data/ext/facter/leatherman/appveyor.yml +26 -19
  52. data/ext/facter/leatherman/catch/CMakeLists.txt +1 -1
  53. data/ext/facter/leatherman/curl/tests/client_test.cc +396 -398
  54. data/ext/facter/leatherman/curl/tests/mock_curl.cc +2 -0
  55. data/ext/facter/leatherman/curl/tests/request_test.cc +66 -68
  56. data/ext/facter/leatherman/curl/tests/response_test.cc +50 -52
  57. data/ext/facter/leatherman/dynamic_library/tests/dynamic_library_tests.cc +71 -75
  58. data/ext/facter/leatherman/execution/src/execution.cc +3 -0
  59. data/ext/facter/leatherman/execution/src/posix/execution.cc +5 -6
  60. data/ext/facter/leatherman/execution/src/windows/execution.cc +2 -0
  61. data/ext/facter/leatherman/execution/tests/windows/execution.cc +4 -2
  62. data/ext/facter/leatherman/file_util/tests/directory_utils_test.cc +66 -68
  63. data/ext/facter/leatherman/file_util/tests/file_utils_test.cc +175 -177
  64. data/ext/facter/leatherman/json_container/inc/leatherman/json_container/json_container.hpp +7 -0
  65. data/ext/facter/leatherman/json_container/src/json_container.cc +10 -1
  66. data/ext/facter/leatherman/json_container/tests/json_container_test.cc +152 -8
  67. data/ext/facter/leatherman/locale/CMakeLists.txt +0 -7
  68. data/ext/facter/leatherman/locales/leatherman.pot +8 -13
  69. data/ext/facter/leatherman/logging/src/logging.cc +2 -0
  70. data/ext/facter/leatherman/util/tests/timer.cc +1 -3
  71. data/ext/facter/leatherman/vendor/Catch-1.10.0.zip +0 -0
  72. data/ext/facter/leatherman/vendor/nowide/doc/Doxyfile +4 -4
  73. data/ext/facter/leatherman/vendor/nowide/doc/LICENSE_1_0.txt +23 -0
  74. data/ext/facter/leatherman/vendor/nowide/doc/main.txt +62 -54
  75. data/ext/facter/leatherman/vendor/nowide/include/boost/nowide/convert.hpp +16 -16
  76. data/ext/facter/leatherman/vendor/nowide/include/boost/nowide/cstdio.hpp +4 -4
  77. data/ext/facter/leatherman/vendor/nowide/include/boost/nowide/utf8_codecvt.hpp +1 -1
  78. data/ext/facter/leatherman/vendor/nowide/src/iostream.cpp +32 -30
  79. data/ext/facter/leatherman/vendor/nowide/standalone/convert +6 -6
  80. data/ext/facter/leatherman/vendor/nowide/standalone/encoding_utf.hpp +1 -1
  81. data/ext/facter/leatherman/vendor/nowide/standalone/run_convert_and_build.sh +1 -3
  82. metadata +15 -6
  83. data/ext/facter/leatherman/cmake/FindICU.cmake +0 -690
  84. data/ext/facter/leatherman/scripts/travis_target.sh +0 -79
  85. data/ext/facter/leatherman/vendor/catch-1.4.0.zip +0 -0
@@ -6,7 +6,7 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: FACTER 3.9.6\n"
9
+ "Project-Id-Version: FACTER 3.11.0\n"
10
10
  "Report-Msgid-Bugs-To: docs@puppet.com\n"
11
11
  "POT-Creation-Date: \n"
12
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
@@ -275,20 +275,6 @@ msgstr ""
275
275
  msgid "/dev/%1%"
276
276
  msgstr ""
277
277
 
278
- #. debug
279
- #: lib/src/facts/aix/disk_resolver.cc
280
- msgid ""
281
- "Could not open device %1% for reading: %2% (%3%). Disk facts will not be "
282
- "populated for this device"
283
- msgstr ""
284
-
285
- #. debug
286
- #: lib/src/facts/aix/disk_resolver.cc
287
- msgid ""
288
- "Ioctl IOCINFO failed for device %1%: %2% (%3%). Disk facts will not be "
289
- "populated for this device"
290
- msgstr ""
291
-
292
278
  #. warning
293
279
  #: lib/src/facts/aix/disk_resolver.cc
294
280
  msgid ""
@@ -642,7 +628,7 @@ msgstr ""
642
628
  msgid "kenv lookup for {1}"
643
629
  msgstr ""
644
630
 
645
- #. warning
631
+ #. info
646
632
  #: lib/src/facts/freebsd/dmi_resolver.cc
647
633
  msgid "kenv lookup for {1} failed: {2} ({3})"
648
634
  msgstr ""
@@ -1034,13 +1020,6 @@ msgstr ""
1034
1020
  msgid "%02x:%02x:%02x:%02x:%02x:%02x"
1035
1021
  msgstr ""
1036
1022
 
1037
- #: lib/src/facts/resolvers/networking_resolver.cc
1038
- #, c-format
1039
- msgid ""
1040
- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
1041
- "%02x:%02x:%02x:%02x:%02x"
1042
- msgstr ""
1043
-
1044
1023
  #. error
1045
1024
  #: lib/src/facts/resolvers/ruby_resolver.cc
1046
1025
  msgid "error while resolving ruby {1} fact: {2}"
@@ -2,6 +2,22 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
+ ## [1.4.0]
6
+
7
+ ### Changed
8
+ - Updated Catch library to 1.10.0.
9
+ - Updated Boost.Nowide to ec9672b
10
+ - Update Travis CI to use container-based builds
11
+
12
+ ### Fixed
13
+ - Builds with Xcode 9
14
+ - Allow Leatherman.execute calls to opt into allowing tasks to finish without reading stdin (i.e. don't fail when the pipe is closed) via the `allow_stdin_unread` option. This specifically supports pxp-agent's task execution where input may or may not be used. (LTH-149)
15
+
16
+ ## [1.3.0]
17
+
18
+ ### Added
19
+ - A toPrettyJson routine to Leatherman.json\_container that pretty prints a valid JSON object.
20
+
5
21
  ## [1.2.2]
6
22
 
7
23
  ### Fixed
@@ -53,15 +69,6 @@ This is a pre-release version for Leatherman 1.0.0, containing backwards-incompa
53
69
  ### Changed
54
70
  - Remove Ruby bindings for Fixnum and Bignum, replace with Integer for Ruby 2.4 support (LTH-124)
55
71
 
56
- ## [0.12.3]
57
-
58
- This is a maintenance release to re-sync the code version with the tag, in order to make our internal automation happy
59
-
60
- ## [0.12.2]
61
-
62
- ### Added
63
- - Leatherman can now be built with DEP on Windows
64
-
65
72
  ## [0.12.1]
66
73
 
67
74
  ### Fixed
@@ -1,5 +1,5 @@
1
1
  cmake_minimum_required(VERSION 3.2.2)
2
- project(leatherman VERSION 1.2.3)
2
+ project(leatherman VERSION 1.4.0)
3
3
 
4
4
  if (WIN32)
5
5
  link_libraries("-Wl,--nxcompat -Wl,--dynamicbase")
@@ -29,7 +29,6 @@ defoption(LEATHERMAN_DEBUG "Enable verbose logging messages from leatherman macr
29
29
  defoption(LEATHERMAN_ENABLE_TESTING "Build the leatherman test binary" ${LEATHERMAN_DEFAULT_ENABLE})
30
30
  defoption(LEATHERMAN_INSTALL "Install the leatherman libraries and headers" ${LEATHERMAN_DEFAULT_ENABLE})
31
31
  defoption(LEATHERMAN_SHARED "Create shared libraries instead of static" FALSE)
32
- defoption(LEATHERMAN_USE_ICU "Set when Boost is built with ICU" FALSE)
33
32
 
34
33
  set(BUILDING_LEATHERMAN TRUE)
35
34
 
@@ -1,29 +1,36 @@
1
1
  clone_depth: 10
2
- install:
3
- - choco install -y mingw-w64 -Version 5.2.0 -source https://www.myget.org/F/puppetlabs
4
- - choco install -y cmake -Version 3.2.2 -source https://www.myget.org/F/puppetlabs
5
- - choco install -y gettext -Version 0.19.6 -source https://www.myget.org/F/puppetlabs
6
- - choco install -y pl-toolchain-x64 -Version 2015.12.01.1 -source https://www.myget.org/F/puppetlabs
7
- - choco install -y pl-boost-x64 -Version 1.58.0.2 -source https://www.myget.org/F/puppetlabs
8
- - choco install -y pl-openssl-x64 -Version 1.0.24.1 -source https://www.myget.org/F/puppetlabs
9
- - choco install -y pl-curl-x64 -Version 7.46.0.1 -source https://www.myget.org/F/puppetlabs
2
+ environment:
3
+ matrix:
4
+ - shared: OFF
5
+ - shared: ON
6
+
7
+ init:
8
+ - |
9
+ choco install -y mingw-w64 -Version 5.2.0 -source https://www.myget.org/F/puppetlabs
10
+ choco install -y cmake -Version 3.2.2 -source https://www.myget.org/F/puppetlabs
11
+ choco install -y gettext -Version 0.19.6 -source https://www.myget.org/F/puppetlabs
12
+ choco install -y pl-toolchain-x64 -Version 2015.12.01.1 -source https://www.myget.org/F/puppetlabs
13
+ choco install -y pl-boost-x64 -Version 1.58.0.2 -source https://www.myget.org/F/puppetlabs
14
+ choco install -y pl-openssl-x64 -Version 1.0.24.1 -source https://www.myget.org/F/puppetlabs
15
+ choco install -y pl-curl-x64 -Version 7.46.0.1 -source https://www.myget.org/F/puppetlabs
16
+
17
+ - ps: |
18
+ $env:PATH = $env:PATH.Replace("Git\bin", "Git\cmd")
19
+ $env:PATH = $env:PATH.Replace("Git\usr\bin", "Git\cmd")
10
20
 
21
+ install:
11
22
  - SET PATH=C:\Ruby21-x64\bin;C:\tools\mingw64\bin;C:\Program Files\gettext-iconv;%PATH%
12
- - ps: $env:PATH = $env:PATH.Replace("Git\bin", "Git\cmd")
13
- - ps: $env:PATH = $env:PATH.Replace("Git\usr\bin", "Git\cmd")
14
23
 
15
24
  build_script:
16
- - ps: cmake -G "MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE="C:\tools\pl-build-tools\pl-build-toolchain.cmake" -DCMAKE_INSTALL_PREFIX=C:\tools\leatherman -DBOOST_STATIC=ON -DLEATHERMAN_SHARED="$env:shared" .
17
- - ps: mingw32-make install
18
- - ps: 7z.exe a -t7z leatherman.7z C:\tools\leatherman\
25
+ - ps: |
26
+ cmake -G "MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE="C:\tools\pl-build-tools\pl-build-toolchain.cmake" -DCMAKE_INSTALL_PREFIX=C:\tools\leatherman -DBOOST_STATIC=ON -DLEATHERMAN_SHARED="$env:shared" .
27
+ mingw32-make -j2
19
28
 
20
29
  test_script:
21
- - ps: ctest -V 2>&1 | %{ if ($_ -is [System.Management.Automation.ErrorRecord]) { $_ | c++filt } else { $_ } }
22
-
23
- environment:
24
- matrix:
25
- - shared: OFF
26
- - shared: ON
30
+ - ps: |
31
+ ctest -V 2>&1 | %{ if ($_ -is [System.Management.Automation.ErrorRecord]) { $_ | c++filt } else { $_ } }
32
+ mingw32-make install
33
+ 7z.exe a -t7z leatherman.7z C:\tools\leatherman\
27
34
 
28
35
  artifacts:
29
36
  - path: leatherman.7z
@@ -1 +1 @@
1
- add_leatherman_vendored("catch-1.4.0.zip" "catch" "include")
1
+ add_leatherman_vendored("Catch-1.10.0.zip" "Catch-1.10.0" "single_include")
@@ -15,6 +15,7 @@
15
15
  using namespace std;
16
16
  namespace fs = boost::filesystem;
17
17
  namespace nw = boost::nowide;
18
+ using namespace leatherman::curl;
18
19
 
19
20
  #define REQUIRE_THROWS_AS_WITH(expression, exception_type, msg_matcher) {\
20
21
  try {\
@@ -47,354 +48,352 @@ void remove_temp_file() {
47
48
  fs::remove(temp_path);
48
49
  }
49
50
 
50
- namespace leatherman { namespace curl {
51
+ struct mock_client : client {
52
+ curl_handle const& get_handle() { return client::get_handle(); }
53
+ };
51
54
 
52
- struct mock_client : client {
53
- curl_handle const& get_handle() { return client::get_handle(); }
54
- };
55
+ TEST_CASE("curl::client HTTP methods") {
56
+ mock_client test_client;
57
+ request test_request {"http://valid.com/"};
55
58
 
56
- TEST_CASE("curl::client HTTP methods") {
57
- mock_client test_client;
58
- request test_request {"http://valid.com/"};
59
+ SECTION("GET succeeds on a given URL") {
60
+ auto resp = test_client.get(test_request);
61
+ REQUIRE(resp.status_code() == 200);
62
+ }
63
+
64
+ SECTION("POST succeeds on a given URL") {
65
+ auto resp = test_client.post(test_request);
66
+ REQUIRE(resp.status_code() == 200);
67
+ }
68
+
69
+ SECTION("PUT succeeds on a given URL") {
70
+ auto resp = test_client.put(test_request);
71
+ REQUIRE(resp.status_code() == 200);
72
+ }
73
+
74
+ SECTION("Request returns status code 404 on invalid URL") {
75
+ request invalid_test_request {"http://invalid.com/"};
76
+ auto resp = test_client.get(invalid_test_request);
77
+ REQUIRE(resp.status_code() == 404);
78
+ }
79
+ }
59
80
 
60
- SECTION("GET succeeds on a given URL") {
61
- auto resp = test_client.get(test_request);
62
- REQUIRE(resp.status_code() == 200);
63
- }
81
+ TEST_CASE("curl::client HTTP request setup") {
82
+ mock_client test_client;
83
+ request test_request {"http://valid.com"};
64
84
 
65
- SECTION("POST succeeds on a given URL") {
66
- auto resp = test_client.post(test_request);
67
- REQUIRE(resp.status_code() == 200);
68
- }
85
+ SECTION("HTTP method is set to GET given a GET request") {
86
+ auto resp = test_client.get(test_request);
87
+ CURL* const& handle = test_client.get_handle();
88
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
89
+ REQUIRE(test_impl->method == curl_impl::http_method::get);
90
+ }
69
91
 
70
- SECTION("PUT succeeds on a given URL") {
71
- auto resp = test_client.put(test_request);
72
- REQUIRE(resp.status_code() == 200);
73
- }
92
+ SECTION("HTTP method is set to POST given a POST request") {
93
+ auto resp = test_client.post(test_request);
94
+ CURL* const& handle = test_client.get_handle();
95
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
96
+ REQUIRE(test_impl->method == curl_impl::http_method::post);
97
+ }
74
98
 
75
- SECTION("Request returns status code 404 on invalid URL") {
76
- request invalid_test_request {"http://invalid.com/"};
77
- auto resp = test_client.get(invalid_test_request);
78
- REQUIRE(resp.status_code() == 404);
79
- }
99
+ SECTION("HTTP method is set to PUT given a PUT request") {
100
+ auto resp = test_client.put(test_request);
101
+ CURL* const& handle = test_client.get_handle();
102
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
103
+ REQUIRE(test_impl->method == curl_impl::http_method::put);
80
104
  }
81
105
 
82
- TEST_CASE("curl::client HTTP request setup") {
83
- mock_client test_client;
106
+ SECTION("cURL should receive the URL specified in the request") {
107
+ auto resp = test_client.get(test_request);
108
+ CURL* const& handle = test_client.get_handle();
109
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
110
+ REQUIRE(test_impl->request_url == "http://valid.com");
111
+ }
112
+ }
113
+
114
+ TEST_CASE("curl::client header and body writing and reading") {
115
+ mock_client test_client;
116
+
117
+ /*
118
+ * Header writing and reading tests
119
+ */
120
+ SECTION("Custom request headers should be honored in the request to the server") {
84
121
  request test_request {"http://valid.com"};
122
+ test_request.add_header("header_name", "header_value");
123
+ auto resp = test_client.get(test_request);
124
+ CURL* const& handle = test_client.get_handle();
125
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
126
+ REQUIRE(test_impl->header);
127
+ REQUIRE(test_impl->header->data == string("header_name: header_value"));
128
+ }
85
129
 
86
- SECTION("HTTP method is set to GET given a GET request") {
87
- auto resp = test_client.get(test_request);
88
- CURL* const& handle = test_client.get_handle();
89
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
90
- REQUIRE(test_impl->method == curl_impl::http_method::get);
91
- }
92
-
93
- SECTION("HTTP method is set to POST given a POST request") {
94
- auto resp = test_client.post(test_request);
95
- CURL* const& handle = test_client.get_handle();
96
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
97
- REQUIRE(test_impl->method == curl_impl::http_method::post);
98
- }
99
-
100
- SECTION("HTTP method is set to PUT given a PUT request") {
101
- auto resp = test_client.put(test_request);
102
- CURL* const& handle = test_client.get_handle();
103
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
104
- REQUIRE(test_impl->method == curl_impl::http_method::put);
105
- }
106
-
107
- SECTION("cURL should receive the URL specified in the request") {
108
- auto resp = test_client.get(test_request);
109
- CURL* const& handle = test_client.get_handle();
110
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
111
- REQUIRE(test_impl->request_url == "http://valid.com");
112
- }
113
- }
114
-
115
- TEST_CASE("curl::client header and body writing and reading") {
116
- mock_client test_client;
130
+ SECTION("The header response delimiter should be ignored") {
131
+ request test_request {"http://response-delimiter.com/"};
132
+ auto resp = test_client.get(test_request);
133
+ int headers = 0;
134
+ resp.each_header([&](string const& name, string const& value) {
135
+ ++headers;
136
+ return true;
137
+ });
138
+ REQUIRE(headers == 0);
139
+ }
117
140
 
118
- /*
119
- * Header writing and reading tests
120
- */
121
- SECTION("Custom request headers should be honored in the request to the server") {
122
- request test_request {"http://valid.com"};
123
- test_request.add_header("header_name", "header_value");
124
- auto resp = test_client.get(test_request);
125
- CURL* const& handle = test_client.get_handle();
126
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
127
- REQUIRE(test_impl->header);
128
- REQUIRE(test_impl->header->data == string("header_name: header_value"));
129
- }
130
-
131
- SECTION("The header response delimiter should be ignored") {
132
- request test_request {"http://response-delimiter.com/"};
133
- auto resp = test_client.get(test_request);
134
- int headers = 0;
135
- resp.each_header([&](string const& name, string const& value) {
136
- ++headers;
137
- return true;
138
- });
139
- REQUIRE(headers == 0);
140
- }
141
-
142
- SECTION("Non-standard response header should be parsed for name and value") {
143
- request test_request {"http://nonstd-header.com/"};
144
- auto resp = test_client.get(test_request);
145
- REQUIRE(resp.header("nonstd_header_name"));
146
- REQUIRE(*(resp.header("nonstd_header_name")) == "nonstd_header_value");
147
- }
148
-
149
- SECTION("Invalid headers should not be parsed or returned in the response") {
150
- request test_request {"http://invalid-header.com/"};
151
- auto resp = test_client.get(test_request);
152
- int headers = 0;
153
- resp.each_header([&](string const& name, string const& value) {
154
- ++headers;
155
- return true;
156
- });
157
- REQUIRE(headers == 0);
158
- }
159
-
160
- /*
161
- * Body writing and reading tests
162
- */
163
- SECTION("Request body should be settable and readable") {
164
- request test_request {"http://valid.com"};
165
- test_request.body("Hello, I am a request body!", "message");
166
- auto resp = test_client.get(test_request);
167
- CURL* const& handle = test_client.get_handle();
168
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
169
- REQUIRE(test_impl->read_buffer == "Hello, I am a request body!");
170
- }
171
-
172
- SECTION("Response body should be what is in the data part of the cURL response") {
173
- CURL* const& handle = test_client.get_handle();
174
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
175
- test_impl->resp_body = "Hello, I am a response body!";
176
- request test_request {"http://valid.com"};
177
- auto resp = test_client.get(test_request);
178
- REQUIRE(resp.body() == "Hello, I am a response body!");
179
- }
180
- }
181
-
182
- TEST_CASE("curl::client cookies") {
183
- mock_client test_client;
141
+ SECTION("Non-standard response header should be parsed for name and value") {
142
+ request test_request {"http://nonstd-header.com/"};
143
+ auto resp = test_client.get(test_request);
144
+ REQUIRE(resp.header("nonstd_header_name"));
145
+ REQUIRE(*(resp.header("nonstd_header_name")) == "nonstd_header_value");
146
+ }
147
+
148
+ SECTION("Invalid headers should not be parsed or returned in the response") {
149
+ request test_request {"http://invalid-header.com/"};
150
+ auto resp = test_client.get(test_request);
151
+ int headers = 0;
152
+ resp.each_header([&](string const& name, string const& value) {
153
+ ++headers;
154
+ return true;
155
+ });
156
+ REQUIRE(headers == 0);
157
+ }
158
+
159
+ /*
160
+ * Body writing and reading tests
161
+ */
162
+ SECTION("Request body should be settable and readable") {
184
163
  request test_request {"http://valid.com"};
164
+ test_request.body("Hello, I am a request body!", "message");
165
+ auto resp = test_client.get(test_request);
166
+ CURL* const& handle = test_client.get_handle();
167
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
168
+ REQUIRE(test_impl->read_buffer == "Hello, I am a request body!");
169
+ }
185
170
 
186
- SECTION("There should be no cookies in the request by default") {
187
- auto resp = test_client.get(test_request);
188
- CURL* const& handle = test_client.get_handle();
189
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
190
- REQUIRE(test_impl->cookie == "");
191
- }
192
-
193
- SECTION("Cookies should be present in the request when added") {
194
- test_request.add_cookie("cookie_name", "cookie_val");
195
- auto resp = test_client.get(test_request);
196
- CURL* const& handle = test_client.get_handle();
197
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
198
- REQUIRE(test_impl->cookie == "cookie_name=cookie_val");
199
- }
200
-
201
- SECTION("Cookies should be removable from the request") {
202
- test_request.add_cookie("cookie_0", "cookie_val_0");
203
- test_request.add_cookie("cookie_1", "cookie_val_1");
204
- test_request.remove_cookie("cookie_1");
205
- auto resp = test_client.get(test_request);
206
- CURL* const& handle = test_client.get_handle();
207
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
208
- REQUIRE(test_impl->cookie == "cookie_0=cookie_val_0");
209
- }
210
-
211
- SECTION("cURL should receieve cookies specified in the request") {
212
- test_request.add_cookie("cookie_0", "cookie_val_0");
213
- test_request.add_cookie("cookie_1", "cookie_val_1");
214
- auto resp = test_client.get(test_request);
215
- CURL* const& handle = test_client.get_handle();
216
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
217
- REQUIRE(test_impl->cookie == "cookie_0=cookie_val_0; cookie_1=cookie_val_1");
218
- }
219
- }
220
-
221
- TEST_CASE("curl::client CA bundle and SSL setup") {
222
- mock_client test_client;
171
+ SECTION("Response body should be what is in the data part of the cURL response") {
172
+ CURL* const& handle = test_client.get_handle();
173
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
174
+ test_impl->resp_body = "Hello, I am a response body!";
223
175
  request test_request {"http://valid.com"};
176
+ auto resp = test_client.get(test_request);
177
+ REQUIRE(resp.body() == "Hello, I am a response body!");
178
+ }
179
+ }
224
180
 
225
- SECTION("Path to CA certificate should be unspecified by default") {
226
- auto resp = test_client.get(test_request);
227
- CURL* const& handle = test_client.get_handle();
228
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
229
- REQUIRE(test_impl->cacert == "");
230
- }
231
-
232
- SECTION("cURL should receive the path to the CA certificate specified in the request") {
233
- test_client.set_ca_cert("cacert");
234
- auto resp = test_client.get(test_request);
235
- CURL* const& handle = test_client.get_handle();
236
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
237
- REQUIRE(test_impl->cacert == "cacert");
238
- }
239
-
240
- SECTION("Client cert name should be unspecified by default") {
241
- auto resp = test_client.get(test_request);
242
- CURL* const& handle = test_client.get_handle();
243
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
244
- REQUIRE(test_impl->client_cert == "");
245
- }
246
-
247
- SECTION("cURL should receive the client cert name specified in the request") {
248
- test_client.set_client_cert("cert", "key");
249
- auto resp = test_client.get(test_request);
250
- CURL* const& handle = test_client.get_handle();
251
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
252
- REQUIRE(test_impl->client_cert == "cert");
253
- }
254
-
255
- SECTION("Private keyfile name should be unspecified by default") {
256
- auto resp = test_client.get(test_request);
257
- CURL* const& handle = test_client.get_handle();
258
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
259
- REQUIRE(test_impl->client_key == "");
260
- }
261
-
262
- SECTION("cURL should receive the private keyfile name specified in the request") {
263
- test_client.set_client_cert("cert", "key");
264
- auto resp = test_client.get(test_request);
265
- CURL* const& handle = test_client.get_handle();
266
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
267
- REQUIRE(test_impl->client_key == "key");
268
- }
269
-
270
- SECTION("cURL should make an HTTP request with the specified HTTP protocol") {
271
- test_client.set_supported_protocols(CURLPROTO_HTTP);
272
- auto resp = test_client.get(test_request);
273
- CURL* const& handle = test_client.get_handle();
274
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
275
- REQUIRE(test_impl->protocols == CURLPROTO_HTTP);
276
- }
277
-
278
- SECTION("cURL defaults to all protocols if no protocols are specified") {
279
- auto resp = test_client.get(test_request);
280
- CURL* const& handle = test_client.get_handle();
281
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
282
- REQUIRE(test_impl->protocols == CURLPROTO_ALL);
283
- }
284
- }
285
-
286
- TEST_CASE("curl::client errors") {
287
- mock_client test_client;
288
- request test_request {"http://valid.com/"};
181
+ TEST_CASE("curl::client cookies") {
182
+ mock_client test_client;
183
+ request test_request {"http://valid.com"};
184
+
185
+ SECTION("There should be no cookies in the request by default") {
186
+ auto resp = test_client.get(test_request);
187
+ CURL* const& handle = test_client.get_handle();
188
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
189
+ REQUIRE(test_impl->cookie == "");
190
+ }
191
+
192
+ SECTION("Cookies should be present in the request when added") {
193
+ test_request.add_cookie("cookie_name", "cookie_val");
194
+ auto resp = test_client.get(test_request);
195
+ CURL* const& handle = test_client.get_handle();
196
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
197
+ REQUIRE(test_impl->cookie == "cookie_name=cookie_val");
198
+ }
199
+
200
+ SECTION("Cookies should be removable from the request") {
201
+ test_request.add_cookie("cookie_0", "cookie_val_0");
202
+ test_request.add_cookie("cookie_1", "cookie_val_1");
203
+ test_request.remove_cookie("cookie_1");
204
+ auto resp = test_client.get(test_request);
205
+ CURL* const& handle = test_client.get_handle();
206
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
207
+ REQUIRE(test_impl->cookie == "cookie_0=cookie_val_0");
208
+ }
209
+
210
+ SECTION("cURL should receieve cookies specified in the request") {
211
+ test_request.add_cookie("cookie_0", "cookie_val_0");
212
+ test_request.add_cookie("cookie_1", "cookie_val_1");
213
+ auto resp = test_client.get(test_request);
214
+ CURL* const& handle = test_client.get_handle();
215
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
216
+ REQUIRE(test_impl->cookie == "cookie_0=cookie_val_0; cookie_1=cookie_val_1");
217
+ }
218
+ }
219
+
220
+ TEST_CASE("curl::client CA bundle and SSL setup") {
221
+ mock_client test_client;
222
+ request test_request {"http://valid.com"};
223
+
224
+ SECTION("Path to CA certificate should be unspecified by default") {
225
+ auto resp = test_client.get(test_request);
226
+ CURL* const& handle = test_client.get_handle();
227
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
228
+ REQUIRE(test_impl->cacert == "");
229
+ }
230
+
231
+ SECTION("cURL should receive the path to the CA certificate specified in the request") {
232
+ test_client.set_ca_cert("cacert");
233
+ auto resp = test_client.get(test_request);
234
+ CURL* const& handle = test_client.get_handle();
235
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
236
+ REQUIRE(test_impl->cacert == "cacert");
237
+ }
238
+
239
+ SECTION("Client cert name should be unspecified by default") {
240
+ auto resp = test_client.get(test_request);
241
+ CURL* const& handle = test_client.get_handle();
242
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
243
+ REQUIRE(test_impl->client_cert == "");
244
+ }
245
+
246
+ SECTION("cURL should receive the client cert name specified in the request") {
247
+ test_client.set_client_cert("cert", "key");
248
+ auto resp = test_client.get(test_request);
249
+ CURL* const& handle = test_client.get_handle();
250
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
251
+ REQUIRE(test_impl->client_cert == "cert");
252
+ }
253
+
254
+ SECTION("Private keyfile name should be unspecified by default") {
255
+ auto resp = test_client.get(test_request);
256
+ CURL* const& handle = test_client.get_handle();
257
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
258
+ REQUIRE(test_impl->client_key == "");
259
+ }
260
+
261
+ SECTION("cURL should receive the private keyfile name specified in the request") {
262
+ test_client.set_client_cert("cert", "key");
263
+ auto resp = test_client.get(test_request);
264
+ CURL* const& handle = test_client.get_handle();
265
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
266
+ REQUIRE(test_impl->client_key == "key");
267
+ }
268
+
269
+ SECTION("cURL should make an HTTP request with the specified HTTP protocol") {
270
+ test_client.set_supported_protocols(CURLPROTO_HTTP);
271
+ auto resp = test_client.get(test_request);
272
+ CURL* const& handle = test_client.get_handle();
273
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
274
+ REQUIRE(test_impl->protocols == CURLPROTO_HTTP);
275
+ }
276
+
277
+ SECTION("cURL defaults to all protocols if no protocols are specified") {
278
+ auto resp = test_client.get(test_request);
289
279
  CURL* const& handle = test_client.get_handle();
290
280
  auto test_impl = reinterpret_cast<curl_impl* const>(handle);
281
+ REQUIRE(test_impl->protocols == CURLPROTO_ALL);
282
+ }
283
+ }
284
+
285
+ TEST_CASE("curl::client errors") {
286
+ mock_client test_client;
287
+ request test_request {"http://valid.com/"};
288
+ CURL* const& handle = test_client.get_handle();
289
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
290
+
291
+ /*
292
+ * Note: we do not currently test the case where cURL errors
293
+ * on curl_global_init, as the global init is done as part of
294
+ * static initialization in the cURL helper, and there is
295
+ * currently no way to force it to be reinitialized.
296
+ */
297
+
298
+ SECTION("client fails to initialize a libcurl easy session") {
299
+ curl_fail_init mock_error {easy_init_error};
300
+ REQUIRE_THROWS_AS(mock_client(), http_exception);
301
+ }
302
+
303
+ SECTION("client fails to perform a cURL request") {
304
+ test_impl->test_failure_mode = curl_impl::error_mode::easy_perform_error;
305
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_request_exception);
306
+ }
307
+
308
+ SECTION("client fails to set HTTP method to POST") {
309
+ test_impl->test_failure_mode = curl_impl::error_mode::http_post_error;
310
+ REQUIRE_THROWS_AS(test_client.post(test_request), http_curl_setup_exception);
311
+ }
312
+
313
+ SECTION("client fails to set HTTP method to PUT") {
314
+ test_impl->test_failure_mode = curl_impl::error_mode::http_put_error;
315
+ REQUIRE_THROWS_AS(test_client.put(test_request), http_curl_setup_exception);
316
+ }
317
+
318
+ SECTION("client fails to set the request URL") {
319
+ test_impl->test_failure_mode = curl_impl::error_mode::set_url_error;
320
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
321
+ }
322
+
323
+ SECTION("client fails to set the request headers") {
324
+ test_impl->test_failure_mode = curl_impl::error_mode::set_header_error;
325
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
326
+ }
327
+
328
+ SECTION("client fails to set cookies in the request") {
329
+ test_impl->test_failure_mode = curl_impl::error_mode::set_cookie_error;
330
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
331
+ }
332
+
333
+ SECTION("client fails to set the header callback function") {
334
+ test_impl->test_failure_mode = curl_impl::error_mode::header_function_error;
335
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
336
+ }
291
337
 
292
- /*
293
- * Note: we do not currently test the case where cURL errors
294
- * on curl_global_init, as the global init is done as part of
295
- * static initialization in the cURL helper, and there is
296
- * currently no way to force it to be reinitialized.
297
- */
298
-
299
- SECTION("client fails to initialize a libcurl easy session") {
300
- curl_fail_init mock_error {easy_init_error};
301
- REQUIRE_THROWS_AS(mock_client test_client, http_exception);
302
- }
303
-
304
- SECTION("client fails to perform a cURL request") {
305
- test_impl->test_failure_mode = curl_impl::error_mode::easy_perform_error;
306
- REQUIRE_THROWS_AS(test_client.get(test_request), http_request_exception);
307
- }
308
-
309
- SECTION("client fails to set HTTP method to POST") {
310
- test_impl->test_failure_mode = curl_impl::error_mode::http_post_error;
311
- REQUIRE_THROWS_AS(test_client.post(test_request), http_curl_setup_exception);
312
- }
313
-
314
- SECTION("client fails to set HTTP method to PUT") {
315
- test_impl->test_failure_mode = curl_impl::error_mode::http_put_error;
316
- REQUIRE_THROWS_AS(test_client.put(test_request), http_curl_setup_exception);
317
- }
318
-
319
- SECTION("client fails to set the request URL") {
320
- test_impl->test_failure_mode = curl_impl::error_mode::set_url_error;
321
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
322
- }
323
-
324
- SECTION("client fails to set the request headers") {
325
- test_impl->test_failure_mode = curl_impl::error_mode::set_header_error;
326
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
327
- }
328
-
329
- SECTION("client fails to set cookies in the request") {
330
- test_impl->test_failure_mode = curl_impl::error_mode::set_cookie_error;
331
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
332
- }
333
-
334
- SECTION("client fails to set the header callback function") {
335
- test_impl->test_failure_mode = curl_impl::error_mode::header_function_error;
336
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
337
- }
338
-
339
- SECTION("client fails to set the header write location") {
340
- test_impl->test_failure_mode = curl_impl::error_mode::header_context_error;
341
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
342
- }
343
-
344
- SECTION("client fails to set the body writing callback function") {
345
- test_impl->test_failure_mode = curl_impl::error_mode::write_body_function_error;
346
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
347
- }
348
-
349
- SECTION("client fails to set the body write location") {
350
- test_impl->test_failure_mode = curl_impl::error_mode::write_body_context_error;
351
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
352
- }
353
- SECTION("client fails to set the read_body callback function") {
354
- test_impl->test_failure_mode = curl_impl::error_mode::read_body_function_error;
355
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
356
- }
357
-
358
- SECTION("client fails to set the read_body data source") {
359
- test_impl->test_failure_mode = curl_impl::error_mode::read_body_context_error;
360
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
361
- }
362
-
363
- SECTION("client fails to set the connection timeout") {
364
- test_impl->test_failure_mode = curl_impl::error_mode::connect_timeout_error;
365
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
366
- }
367
-
368
- SECTION("client fails to set the request timeout") {
369
- test_impl->test_failure_mode = curl_impl::error_mode::request_timeout_error;
370
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
371
- }
372
-
373
- SECTION("client fails to set certificate authority info") {
374
- test_client.set_ca_cert("certfile");
375
- test_impl->test_failure_mode = curl_impl::error_mode::ca_bundle_error;
376
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
377
- }
378
-
379
- SECTION("client fails to set SSL cert info") {
380
- test_client.set_client_cert("cert", "key");
381
- test_impl->test_failure_mode = curl_impl::error_mode::ssl_cert_error;
382
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
383
- }
384
-
385
- SECTION("client fails to set SSL key info") {
386
- test_client.set_client_cert("cert", "key");
387
- test_impl->test_failure_mode = curl_impl::error_mode::ssl_key_error;
388
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
389
- }
390
-
391
- SECTION("client fails to make http call with https protocol only enabled") {
392
- test_client.set_supported_protocols(CURLPROTO_HTTPS);
393
- test_impl->test_failure_mode = curl_impl::error_mode::protocol_error;
394
- REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
395
- }
338
+ SECTION("client fails to set the header write location") {
339
+ test_impl->test_failure_mode = curl_impl::error_mode::header_context_error;
340
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
396
341
  }
397
342
 
343
+ SECTION("client fails to set the body writing callback function") {
344
+ test_impl->test_failure_mode = curl_impl::error_mode::write_body_function_error;
345
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
346
+ }
347
+
348
+ SECTION("client fails to set the body write location") {
349
+ test_impl->test_failure_mode = curl_impl::error_mode::write_body_context_error;
350
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
351
+ }
352
+ SECTION("client fails to set the read_body callback function") {
353
+ test_impl->test_failure_mode = curl_impl::error_mode::read_body_function_error;
354
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
355
+ }
356
+
357
+ SECTION("client fails to set the read_body data source") {
358
+ test_impl->test_failure_mode = curl_impl::error_mode::read_body_context_error;
359
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
360
+ }
361
+
362
+ SECTION("client fails to set the connection timeout") {
363
+ test_impl->test_failure_mode = curl_impl::error_mode::connect_timeout_error;
364
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
365
+ }
366
+
367
+ SECTION("client fails to set the request timeout") {
368
+ test_impl->test_failure_mode = curl_impl::error_mode::request_timeout_error;
369
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
370
+ }
371
+
372
+ SECTION("client fails to set certificate authority info") {
373
+ test_client.set_ca_cert("certfile");
374
+ test_impl->test_failure_mode = curl_impl::error_mode::ca_bundle_error;
375
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
376
+ }
377
+
378
+ SECTION("client fails to set SSL cert info") {
379
+ test_client.set_client_cert("cert", "key");
380
+ test_impl->test_failure_mode = curl_impl::error_mode::ssl_cert_error;
381
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
382
+ }
383
+
384
+ SECTION("client fails to set SSL key info") {
385
+ test_client.set_client_cert("cert", "key");
386
+ test_impl->test_failure_mode = curl_impl::error_mode::ssl_key_error;
387
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
388
+ }
389
+
390
+ SECTION("client fails to make http call with https protocol only enabled") {
391
+ test_client.set_supported_protocols(CURLPROTO_HTTPS);
392
+ test_impl->test_failure_mode = curl_impl::error_mode::protocol_error;
393
+ REQUIRE_THROWS_AS(test_client.get(test_request), http_curl_setup_exception);
394
+ }
395
+ }
396
+
398
397
  TEST_CASE("curl::client download_file") {
399
398
  mock_client test_client;
400
399
  temp_directory temp_dir;
@@ -542,74 +541,73 @@ namespace leatherman { namespace curl {
542
541
  }
543
542
  }
544
543
 
545
- TEST_CASE("curl::client download_file errors") {
546
- mock_client test_client;
547
- temp_directory temp_dir;
548
- fs::path temp_dir_path = fs::path(temp_dir.get_dir_name());
549
- CURL* const& handle = test_client.get_handle();
550
- auto test_impl = reinterpret_cast<curl_impl* const>(handle);
544
+ TEST_CASE("curl::client download_file errors") {
545
+ mock_client test_client;
546
+ temp_directory temp_dir;
547
+ fs::path temp_dir_path = fs::path(temp_dir.get_dir_name());
548
+ CURL* const& handle = test_client.get_handle();
549
+ auto test_impl = reinterpret_cast<curl_impl* const>(handle);
550
+
551
+ SECTION("when fopen fails, an http_file_operation_exception is thrown") {
552
+ fs::path parent_dir = temp_dir_path / "parent";
553
+ std::string file_path = (parent_dir / "child").string();
554
+ request req("");
555
+ REQUIRE_THROWS_AS_WITH(
556
+ test_client.download_file(req, file_path),
557
+ http_file_operation_exception,
558
+ Catch::Equals("File operation error: failed to open temporary file for writing"));
559
+ }
560
+
561
+ SECTION("when curl_easy_setopt fails, an http_curl_setup_exception is thrown and the temporary file is removed") {
562
+ request req("");
563
+ std::string file_path = (temp_dir_path / "file").string();
564
+ test_impl->test_failure_mode = curl_impl::error_mode::set_url_error;
565
+ REQUIRE_THROWS_AS(test_client.download_file(req, file_path), http_curl_setup_exception);
566
+ // Ensure that the temp file was removed
567
+ REQUIRE(fs::is_empty(temp_dir_path));
568
+ }
569
+
570
+ SECTION("when curl_easy_perform fails due to a CURLE_WRITE_ERROR, but the temporary file is removed, an http_file_operation_exception is thrown") {
571
+ std::string file_path = (temp_dir_path / "file").string();
572
+ request req("");
573
+ test_impl->test_failure_mode = curl_impl::error_mode::easy_perform_write_error;
574
+ REQUIRE_THROWS_AS_WITH(
575
+ test_client.download_file(req, file_path),
576
+ http_file_operation_exception,
577
+ Catch::StartsWith("File operation error: failed to write to the temporary file during download"));
578
+ }
579
+
580
+ SECTION("when curl_easy_perform fails for reasons other than a CURLE_WRITE_ERROR, but the temporary file is removed, only the errbuf message is contained in the thrown http_file_download_exception") {
581
+ std::string file_path = (temp_dir_path / "file").string();
582
+ request req("");
583
+ test_impl->test_failure_mode = curl_impl::error_mode::easy_perform_error;
584
+ REQUIRE_THROWS_AS_WITH(
585
+ test_client.download_file(req, file_path),
586
+ http_file_download_exception,
587
+ Catch::Equals("File download server side error: easy perform failed"));
588
+
589
+ // Ensure that the temp file was removed
590
+ REQUIRE(fs::is_empty(temp_dir_path));
591
+ }
551
592
 
552
- SECTION("when fopen fails, an http_file_operation_exception is thrown") {
553
- fs::path parent_dir = temp_dir_path / "parent";
554
- std::string file_path = (parent_dir / "child").string();
555
- curl::request req("");
556
- REQUIRE_THROWS_AS_WITH(
557
- test_client.download_file(req, file_path),
558
- curl::http_file_operation_exception,
559
- Catch::Equals("File operation error: failed to open temporary file for writing"));
560
- }
561
-
562
- SECTION("when curl_easy_setopt fails, an http_curl_setup_exception is thrown and the temporary file is removed") {
563
- curl::request req("");
564
- std::string file_path = (temp_dir_path / "file").string();
565
- test_impl->test_failure_mode = curl_impl::error_mode::set_url_error;
566
- REQUIRE_THROWS_AS(test_client.download_file(req, file_path), curl::http_curl_setup_exception);
567
- // Ensure that the temp file was removed
568
- REQUIRE(fs::is_empty(temp_dir_path));
569
- }
570
-
571
- SECTION("when curl_easy_perform fails due to a CURLE_WRITE_ERROR, but the temporary file is removed, an http_file_operation_exception is thrown") {
572
- std::string file_path = (temp_dir_path / "file").string();
573
- curl::request req("");
574
- test_impl->test_failure_mode = curl_impl::error_mode::easy_perform_write_error;
575
- REQUIRE_THROWS_AS_WITH(
576
- test_client.download_file(req, file_path),
577
- curl::http_file_operation_exception,
578
- Catch::StartsWith("File operation error: failed to write to the temporary file during download"));
579
- }
580
-
581
- SECTION("when curl_easy_perform fails for reasons other than a CURLE_WRITE_ERROR, but the temporary file is removed, only the errbuf message is contained in the thrown http_file_download_exception") {
582
- std::string file_path = (temp_dir_path / "file").string();
583
- curl::request req("");
584
- test_impl->test_failure_mode = curl_impl::error_mode::easy_perform_error;
585
- REQUIRE_THROWS_AS_WITH(
586
- test_client.download_file(req, file_path),
587
- curl::http_file_download_exception,
588
- Catch::Equals("File download server side error: easy perform failed"));
589
-
590
- // Ensure that the temp file was removed
591
- REQUIRE(fs::is_empty(temp_dir_path));
592
- }
593
-
594
- SECTION("when renaming the temporary file to the user-provided file path fails, an http_file_operation_exception is thrown") {
595
- std::string file_path = (temp_dir_path / "file").string();
596
- curl::request req("https://download.com");
597
- test_impl->trigger_external_failure = remove_temp_file;
598
- REQUIRE_THROWS_AS_WITH(
599
- test_client.download_file(req, file_path),
600
- curl::http_file_operation_exception,
601
- Catch::StartsWith("File operation error: failed to move over the temporary file's downloaded contents"));
602
- }
603
-
604
- SECTION("when writing the temporary file's contents to the response body fails, an http_file_operation_exception is thrown") {
605
- std::string file_path = (temp_dir_path / "file").string();
606
- request req("https://download_trigger_404.com");
607
- test_impl->trigger_external_failure = remove_temp_file;
608
- response res;
609
- REQUIRE_THROWS_AS_WITH(
610
- test_client.download_file(req, file_path, res),
611
- curl::http_file_operation_exception,
612
- Catch::StartsWith("File operation error: failed to write the temporary file's contents to the response body"));
613
- }
614
- }
615
- }}
593
+ SECTION("when renaming the temporary file to the user-provided file path fails, an http_file_operation_exception is thrown") {
594
+ std::string file_path = (temp_dir_path / "file").string();
595
+ request req("https://download.com");
596
+ test_impl->trigger_external_failure = remove_temp_file;
597
+ REQUIRE_THROWS_AS_WITH(
598
+ test_client.download_file(req, file_path),
599
+ http_file_operation_exception,
600
+ Catch::StartsWith("File operation error: failed to move over the temporary file's downloaded contents"));
601
+ }
602
+
603
+ SECTION("when writing the temporary file's contents to the response body fails, an http_file_operation_exception is thrown") {
604
+ std::string file_path = (temp_dir_path / "file").string();
605
+ request req("https://download_trigger_404.com");
606
+ test_impl->trigger_external_failure = remove_temp_file;
607
+ response res;
608
+ REQUIRE_THROWS_AS_WITH(
609
+ test_client.download_file(req, file_path, res),
610
+ http_file_operation_exception,
611
+ Catch::StartsWith("File operation error: failed to write the temporary file's contents to the response body"));
612
+ }
613
+ }