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

Sign up to get free protection for your applications and to get access to all the features.
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
+ }