From 57a7ff2c0720d38bd1384c2b0b09c17a549fcbe4 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Thu, 20 Dec 2018 17:02:57 -0800 Subject: [PATCH] clang-format cpprestsdk (#1005) --- .clang-format | 37 +- Build_android/configure.sh | 4 +- Release/include/cpprest/astreambuf.h | 2130 +++-- Release/include/cpprest/asyncrt_utils.h | 847 +- Release/include/cpprest/base_uri.h | 716 +- Release/include/cpprest/containerstream.h | 982 +- Release/include/cpprest/details/SafeInt3.hpp | 4746 +++++----- Release/include/cpprest/details/basic_types.h | 34 +- .../include/cpprest/details/cpprest_compat.h | 35 +- Release/include/cpprest/details/fileio.h | 290 +- .../include/cpprest/details/http_helpers.h | 70 +- Release/include/cpprest/details/http_server.h | 38 +- .../include/cpprest/details/http_server_api.h | 44 +- Release/include/cpprest/details/nosal.h | 18 +- Release/include/cpprest/details/resource.h | 10 +- .../include/cpprest/details/web_utilities.h | 74 +- Release/include/cpprest/filestream.h | 1709 ++-- Release/include/cpprest/http_client.h | 497 +- Release/include/cpprest/http_compression.h | 18 +- Release/include/cpprest/http_headers.h | 111 +- Release/include/cpprest/http_listener.h | 166 +- Release/include/cpprest/http_msg.h | 567 +- Release/include/cpprest/interopstream.h | 854 +- Release/include/cpprest/json.h | 3219 +++---- Release/include/cpprest/oauth1.h | 187 +- Release/include/cpprest/oauth2.h | 130 +- .../include/cpprest/producerconsumerstream.h | 1134 ++- Release/include/cpprest/rawptrstream.h | 992 +- Release/include/cpprest/streams.h | 2306 +++-- Release/include/cpprest/uri.h | 24 +- Release/include/cpprest/uri_builder.h | 7 +- Release/include/cpprest/version.h | 10 +- Release/include/cpprest/ws_client.h | 322 +- Release/include/cpprest/ws_msg.h | 108 +- Release/include/pplx/pplx.h | 230 +- Release/include/pplx/pplxcancellation_token.h | 929 +- Release/include/pplx/pplxconv.h | 49 +- Release/include/pplx/pplxinterface.h | 101 +- Release/include/pplx/pplxlinux.h | 379 +- Release/include/pplx/pplxtasks.h | 8251 +++++++++-------- Release/include/pplx/pplxwin.h | 351 +- Release/include/pplx/threadpool.h | 33 +- Release/samples/BingRequest/bingrequest.cpp | 78 +- .../BlackJack_Client/BlackJackClient.cpp | 144 +- .../BlackJack_Server/BlackJack_Server.cpp | 31 +- .../BlackJack/BlackJack_Server/Dealer.cpp | 76 +- .../BlackJack/BlackJack_Server/Table.cpp | 202 +- .../BlackJack/BlackJack_Server/Table.h | 44 +- .../BlackJack/BlackJack_Server/messagetypes.h | 139 +- .../BlackJack/BlackJack_Server/stdafx.cpp | 18 +- .../BlackJack/BlackJack_Server/stdafx.h | 42 +- .../BlackJack/BlackJack_UIClient/App.xaml.cpp | 120 +- .../BlackJack/BlackJack_UIClient/App.xaml.h | 42 +- .../BlackJack_UIClient/CardShape.xaml.cpp | 54 +- .../BlackJack_UIClient/CardShape.xaml.h | 54 +- .../BlackJack_UIClient/Player.xaml.cpp | 42 +- .../BlackJack_UIClient/Player.xaml.h | 66 +- .../BlackJack_UIClient/PlayingTable.xaml.cpp | 507 +- .../BlackJack_UIClient/PlayingTable.xaml.h | 239 +- .../BlackJack_UIClient/messagetypes.h | 148 +- .../BlackJack/BlackJack_UIClient/pch.cpp | 18 +- .../BlackJack/BlackJack_UIClient/pch.h | 22 +- Release/samples/CasaLens/casalens.cpp | 126 +- Release/samples/CasaLens/casalens.h | 50 +- Release/samples/CasaLens/datafetcher.cpp | 521 +- Release/samples/CasaLens/stdafx.cpp | 20 +- Release/samples/CasaLens/stdafx.h | 30 +- Release/samples/FacebookDemo/App.xaml | 8 +- Release/samples/FacebookDemo/App.xaml.cpp | 120 +- Release/samples/FacebookDemo/App.xaml.h | 42 +- .../FacebookDemo/Common/StandardStyles.xaml | 20 +- Release/samples/FacebookDemo/Facebook.cpp | 196 +- Release/samples/FacebookDemo/Facebook.h | 43 +- Release/samples/FacebookDemo/MainPage.xaml | 10 +- .../samples/FacebookDemo/MainPage.xaml.cpp | 117 +- Release/samples/FacebookDemo/MainPage.xaml.h | 6 +- Release/samples/FacebookDemo/pch.cpp | 16 +- Release/samples/FacebookDemo/pch.h | 18 +- Release/samples/OAuth2Live/App.xaml.cpp | 101 +- Release/samples/OAuth2Live/App.xaml.h | 24 +- Release/samples/OAuth2Live/MainPage.xaml.cpp | 218 +- Release/samples/OAuth2Live/MainPage.xaml.h | 60 +- Release/samples/OAuth2Live/pch.h | 24 +- Release/samples/Oauth1Client/Oauth1Client.cpp | 156 +- Release/samples/Oauth2Client/Oauth2Client.cpp | 153 +- Release/samples/SearchFile/searchfile.cpp | 217 +- Release/samples/WindowsLiveAuth/App.xaml.cpp | 108 +- Release/samples/WindowsLiveAuth/App.xaml.h | 30 +- .../samples/WindowsLiveAuth/MainPage.xaml.cpp | 193 +- .../samples/WindowsLiveAuth/MainPage.xaml.h | 42 +- .../samples/WindowsLiveAuth/live_connect.h | 768 +- Release/samples/WindowsLiveAuth/pch.cpp | 6 +- Release/samples/WindowsLiveAuth/pch.h | 10 +- Release/src/http/client/http_client.cpp | 158 +- Release/src/http/client/http_client_asio.cpp | 18 +- Release/src/http/client/http_client_impl.h | 81 +- Release/src/http/client/http_client_msg.cpp | 40 +- .../src/http/client/http_client_winhttp.cpp | 1309 +-- Release/src/http/client/http_client_winrt.cpp | 204 +- .../src/http/client/x509_cert_utilities.cpp | 19 +- .../src/http/common/connection_pool_helpers.h | 16 +- Release/src/http/common/http_compression.cpp | 30 +- Release/src/http/common/http_helpers.cpp | 87 +- Release/src/http/common/http_msg.cpp | 647 +- .../src/http/common/internal_http_helpers.h | 47 +- Release/src/http/common/x509_cert_utilities.h | 20 +- Release/src/http/listener/http_listener.cpp | 98 +- .../src/http/listener/http_listener_msg.cpp | 54 +- Release/src/http/listener/http_server_api.cpp | 76 +- .../src/http/listener/http_server_asio.cpp | 774 +- .../src/http/listener/http_server_httpsys.cpp | 728 +- .../src/http/listener/http_server_httpsys.h | 76 +- Release/src/http/listener/http_server_impl.h | 8 +- Release/src/http/oauth/oauth1.cpp | 173 +- Release/src/http/oauth/oauth2.cpp | 81 +- Release/src/json/json.cpp | 439 +- Release/src/json/json_parsing.cpp | 719 +- Release/src/json/json_serialization.cpp | 96 +- Release/src/pch/stdafx.cpp | 18 +- Release/src/pch/stdafx.h | 77 +- Release/src/pplx/pplx.cpp | 113 +- Release/src/pplx/pplxapple.cpp | 62 +- Release/src/pplx/pplxlinux.cpp | 54 +- Release/src/pplx/pplxwin.cpp | 363 +- Release/src/pplx/threadpool.cpp | 11 +- Release/src/streams/fileio_posix.cpp | 341 +- Release/src/streams/fileio_win32.cpp | 487 +- Release/src/streams/fileio_winrt.cpp | 845 +- Release/src/uri/uri.cpp | 913 +- Release/src/uri/uri_builder.cpp | 4 +- Release/src/utilities/asyncrt_utils.cpp | 491 +- Release/src/utilities/base64.cpp | 99 +- Release/src/utilities/web_utilities.cpp | 82 +- Release/src/websockets/client/ws_client.cpp | 50 +- .../src/websockets/client/ws_client_impl.h | 11 +- .../src/websockets/client/ws_client_winrt.cpp | 383 +- .../src/websockets/client/ws_client_wspp.cpp | 553 +- Release/src/websockets/client/ws_msg.cpp | 41 +- .../common/TestRunner/test_module_loader.cpp | 43 +- .../common/TestRunner/test_module_loader.h | 24 +- .../tests/common/TestRunner/test_runner.cpp | 224 +- Release/tests/common/UnitTestpp/COPYING | 33 +- Release/tests/common/UnitTestpp/config.h | 91 +- .../common/UnitTestpp/src/AssertException.cpp | 70 +- .../common/UnitTestpp/src/AssertException.h | 64 +- .../tests/common/UnitTestpp/src/CheckMacros.h | 353 +- Release/tests/common/UnitTestpp/src/Checks.h | 341 +- .../UnitTestpp/src/CompositeTestReporter.cpp | 107 +- .../UnitTestpp/src/CompositeTestReporter.h | 88 +- .../common/UnitTestpp/src/CurrentTest.cpp | 91 +- .../tests/common/UnitTestpp/src/CurrentTest.h | 74 +- .../UnitTestpp/src/DeferredTestReporter.cpp | 63 +- .../UnitTestpp/src/DeferredTestReporter.h | 66 +- .../UnitTestpp/src/DeferredTestResult.cpp | 94 +- .../UnitTestpp/src/DeferredTestResult.h | 84 +- .../common/UnitTestpp/src/ExceptionMacros.h | 76 +- .../tests/common/UnitTestpp/src/ExecuteTest.h | 113 +- .../common/UnitTestpp/src/GlobalSettings.cpp | 91 +- .../common/UnitTestpp/src/GlobalSettings.h | 100 +- .../common/UnitTestpp/src/HelperMacros.h | 124 +- .../common/UnitTestpp/src/MemoryOutStream.cpp | 170 +- .../common/UnitTestpp/src/MemoryOutStream.h | 101 +- .../UnitTestpp/src/Posix/SignalTranslator.cpp | 97 +- .../UnitTestpp/src/Posix/SignalTranslator.h | 78 +- .../UnitTestpp/src/Posix/TimeHelpers.cpp | 79 +- .../common/UnitTestpp/src/Posix/TimeHelpers.h | 72 +- .../common/UnitTestpp/src/ReportAssert.cpp | 123 +- .../common/UnitTestpp/src/ReportAssert.h | 62 +- .../common/UnitTestpp/src/ReportAssertImpl.h | 101 +- Release/tests/common/UnitTestpp/src/Test.cpp | 83 +- Release/tests/common/UnitTestpp/src/Test.h | 76 +- .../common/UnitTestpp/src/TestDetails.cpp | 75 +- .../tests/common/UnitTestpp/src/TestDetails.h | 64 +- .../tests/common/UnitTestpp/src/TestList.cpp | 87 +- .../tests/common/UnitTestpp/src/TestList.h | 66 +- .../tests/common/UnitTestpp/src/TestMacros.h | 363 +- .../common/UnitTestpp/src/TestProperties.h | 133 +- .../common/UnitTestpp/src/TestReporter.cpp | 70 +- .../common/UnitTestpp/src/TestReporter.h | 69 +- .../UnitTestpp/src/TestReporterStdout.cpp | 88 +- .../UnitTestpp/src/TestReporterStdout.h | 71 +- .../common/UnitTestpp/src/TestResults.cpp | 92 +- .../tests/common/UnitTestpp/src/TestResults.h | 70 +- .../common/UnitTestpp/src/TestRunner.cpp | 124 +- .../tests/common/UnitTestpp/src/TestRunner.h | 127 +- .../tests/common/UnitTestpp/src/TestSuite.h | 67 +- .../tests/common/UnitTestpp/src/TimeHelpers.h | 62 +- .../UnitTestpp/src/Win32/TimeHelpers.cpp | 106 +- .../common/UnitTestpp/src/Win32/TimeHelpers.h | 81 +- .../common/UnitTestpp/src/XmlTestReporter.cpp | 122 +- .../common/UnitTestpp/src/XmlTestReporter.h | 70 +- .../tests/common/UnitTestpp/src/stdafx.cpp | 60 +- Release/tests/common/UnitTestpp/src/stdafx.h | 66 +- .../UnitTestpp/src/tests/RecordingReporter.h | 79 +- .../UnitTestpp/src/tests/ScopedCurrentTest.h | 95 +- .../src/tests/TestAssertHandler.cpp | 176 +- .../UnitTestpp/src/tests/TestCheckMacros.cpp | 270 +- .../UnitTestpp/src/tests/TestChecks.cpp | 134 +- .../src/tests/TestCompositeTestReporter.cpp | 312 +- .../UnitTestpp/src/tests/TestCurrentTest.cpp | 95 +- .../src/tests/TestDeferredTestReporter.cpp | 83 +- .../src/tests/TestMemoryOutStream.cpp | 103 +- .../common/UnitTestpp/src/tests/TestTest.cpp | 135 +- .../UnitTestpp/src/tests/TestTestList.cpp | 67 +- .../UnitTestpp/src/tests/TestTestMacros.cpp | 186 +- .../UnitTestpp/src/tests/TestTestResults.cpp | 110 +- .../UnitTestpp/src/tests/TestTestRunner.cpp | 186 +- .../UnitTestpp/src/tests/TestTestSuite.cpp | 63 +- .../UnitTestpp/src/tests/TestUnitTestPP.cpp | 147 +- .../src/tests/TestXmlTestReporter.cpp | 154 +- .../common/UnitTestpp/src/tests/stdafx.cpp | 60 +- .../common/UnitTestpp/src/tests/stdafx.h | 69 +- Release/tests/common/UnitTestpp/unittestpp.h | 64 +- .../include/common_utilities_public.h | 18 +- .../common/utilities/include/locale_guard.h | 45 +- .../common/utilities/include/os_utilities.h | 40 +- .../tests/common/utilities/os_utilities.cpp | 39 +- .../http/client/authentication_tests.cpp | 1077 +-- .../http/client/building_request_tests.cpp | 554 +- .../http/client/client_construction.cpp | 365 +- .../http/client/compression_tests.cpp | 12 +- .../http/client/connection_pool_tests.cpp | 23 +- .../http/client/connections_and_errors.cpp | 604 +- .../functional/http/client/header_tests.cpp | 737 +- .../http/client/http_client_fuzz_tests.cpp | 155 +- .../http/client/http_client_tests.cpp | 50 +- .../http/client/http_client_tests.h | 48 +- .../http/client/http_methods_tests.cpp | 143 +- .../http/client/multiple_requests.cpp | 204 +- .../functional/http/client/oauth1_tests.cpp | 506 +- .../functional/http/client/oauth2_tests.cpp | 559 +- .../functional/http/client/outside_tests.cpp | 569 +- .../http/client/pipeline_stage_tests.cpp | 396 +- .../http/client/progress_handler_tests.cpp | 559 +- .../functional/http/client/proxy_tests.cpp | 351 +- .../http/client/request_helper_tests.cpp | 442 +- .../http/client/request_stream_tests.cpp | 641 +- .../http/client/request_uri_tests.cpp | 261 +- .../http/client/response_extract_tests.cpp | 967 +- .../http/client/response_stream_tests.cpp | 711 +- .../status_code_reason_phrase_tests.cpp | 65 +- .../tests/functional/http/client/stdafx.cpp | 14 +- Release/tests/functional/http/client/stdafx.h | 27 +- .../functional/http/client/timeout_handler.h | 41 +- .../http/client/to_string_tests.cpp | 234 +- .../http/listener/building_response_tests.cpp | 246 +- .../http/listener/connections_and_errors.cpp | 685 +- .../functional/http/listener/header_tests.cpp | 353 +- .../http/listener/http_listener_tests.h | 48 +- .../listener/listener_construction_tests.cpp | 838 +- .../http/listener/reply_helper_tests.cpp | 154 +- .../http/listener/request_extract_tests.cpp | 325 +- .../http/listener/request_handler_tests.cpp | 975 +- .../listener/request_relative_uri_tests.cpp | 245 +- .../http/listener/request_stream_tests.cpp | 151 +- .../http/listener/requests_tests.cpp | 486 +- .../http/listener/response_stream_tests.cpp | 485 +- .../status_code_reason_phrase_tests.cpp | 185 +- .../tests/functional/http/listener/stdafx.cpp | 2 +- .../tests/functional/http/listener/stdafx.h | 38 +- .../http/listener/to_string_tests.cpp | 124 +- .../http/utilities/http_asserts.cpp | 211 +- .../http/utilities/include/http_asserts.h | 243 +- .../utilities/include/http_test_utilities.h | 22 +- .../include/http_test_utilities_public.h | 18 +- .../http/utilities/include/test_http_client.h | 112 +- .../http/utilities/include/test_http_server.h | 110 +- .../utilities/include/test_server_utilities.h | 90 +- .../functional/http/utilities/stdafx.cpp | 14 +- .../tests/functional/http/utilities/stdafx.h | 27 +- .../http/utilities/test_http_client.cpp | 446 +- .../http/utilities/test_http_server.cpp | 450 +- .../http/utilities/test_server_utilities.cpp | 106 +- .../functional/json/construction_tests.cpp | 882 +- Release/tests/functional/json/fuzz_tests.cpp | 114 +- .../tests/functional/json/iterator_tests.cpp | 500 +- .../functional/json/json_numbers_tests.cpp | 562 +- Release/tests/functional/json/json_tests.h | 35 +- .../json/negative_parsing_tests.cpp | 313 +- .../tests/functional/json/parsing_tests.cpp | 1230 +-- Release/tests/functional/json/stdafx.cpp | 14 +- Release/tests/functional/json/stdafx.h | 23 +- .../json/to_as_and_operators_tests.cpp | 994 +- .../functional/misc/atl_headers/Resource.h | 10 +- .../misc/atl_headers/header_test1.cpp | 65 +- .../misc/atl_headers/header_test2.cpp | 64 +- .../pplx/pplx_test/pplx_op_test.cpp | 447 +- .../pplx/pplx_test/pplx_task_options.cpp | 610 +- .../pplx/pplx_test/pplxtask_tests.cpp | 3059 +++--- .../functional/pplx/pplx_test/stdafx.cpp | 12 +- .../tests/functional/pplx/pplx_test/stdafx.h | 25 +- .../functional/streams/CppSparseFile.cpp | 176 +- .../tests/functional/streams/CppSparseFile.h | 116 +- .../functional/streams/fstreambuf_tests.cpp | 1441 ++- .../tests/functional/streams/fuzz_tests.cpp | 171 +- .../functional/streams/istream_tests.cpp | 2333 +++-- .../functional/streams/memstream_tests.cpp | 2906 +++--- .../functional/streams/ostream_tests.cpp | 546 +- Release/tests/functional/streams/prefix.h | 39 +- Release/tests/functional/streams/stdafx.cpp | 15 +- Release/tests/functional/streams/stdafx.h | 38 +- .../functional/streams/stdstream_tests.cpp | 1046 +-- .../tests/functional/streams/streams_tests.h | 89 +- .../streams/winrt_interop_tests.cpp | 404 +- .../tests/functional/uri/accessor_tests.cpp | 79 +- .../tests/functional/uri/combining_tests.cpp | 145 +- .../functional/uri/constructor_tests.cpp | 494 +- .../functional/uri/conversions_tests.cpp | 69 +- .../tests/functional/uri/diagnostic_tests.cpp | 201 +- .../tests/functional/uri/encoding_tests.cpp | 233 +- .../tests/functional/uri/operator_tests.cpp | 113 +- .../functional/uri/resolve_uri_tests.cpp | 118 +- .../tests/functional/uri/splitting_tests.cpp | 283 +- Release/tests/functional/uri/stdafx.cpp | 14 +- Release/tests/functional/uri/stdafx.h | 27 +- .../functional/uri/uri_builder_tests.cpp | 1022 +- Release/tests/functional/uri/uri_tests.h | 35 +- Release/tests/functional/utils/base64.cpp | 456 +- Release/tests/functional/utils/datetime.cpp | 266 +- Release/tests/functional/utils/macro_test.cpp | 56 +- .../utils/nonce_generator_tests.cpp | 81 +- Release/tests/functional/utils/stdafx.cpp | 12 +- Release/tests/functional/utils/stdafx.h | 25 +- Release/tests/functional/utils/strings.cpp | 596 +- Release/tests/functional/utils/utils_tests.h | 34 +- .../utils/win32_encryption_tests.cpp | 59 +- .../client/authentication_tests.cpp | 356 +- .../websockets/client/client_construction.cpp | 402 +- .../websockets/client/close_tests.cpp | 219 +- .../websockets/client/error_tests.cpp | 254 +- .../websockets/client/proxy_tests.cpp | 116 +- .../websockets/client/receive_msg_tests.cpp | 468 +- .../websockets/client/send_msg_tests.cpp | 814 +- .../functional/websockets/client/stdafx.cpp | 14 +- .../functional/websockets/client/stdafx.h | 33 +- .../client/websocket_client_tests.h | 37 +- .../websockets/utilities/stdafx.cpp | 14 +- .../functional/websockets/utilities/stdafx.h | 24 +- .../utilities/test_websocket_server.cpp | 372 +- .../utilities/test_websocket_server.h | 76 +- 340 files changed, 50506 insertions(+), 50507 deletions(-) diff --git a/.clang-format b/.clang-format index 5ef3ed9647..bab911a79f 100644 --- a/.clang-format +++ b/.clang-format @@ -1,31 +1,46 @@ -BasedOnStyle: WebKit -Language: Cpp -Standard: Cpp11 +# https://releases.llvm.org/7.0.0/tools/clang/docs/ClangFormatStyleOptions.html -UseTab: Never -IndentWidth: 4 -ColumnLimit: 120 -PointerAlignment: Left +--- +Language: Cpp -BreakBeforeBraces: Allman +BasedOnStyle: WebKit +AlignAfterOpenBracket: Align +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: false AlwaysBreakTemplateDeclarations: true -AlignAfterOpenBracket: true -AlignOperands: true -AlignTrailingComments: true BinPackArguments: false BinPackParameters: false BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman BreakConstructorInitializersBeforeComma: true +ColumnLimit: 120 ConstructorInitializerAllOnOneLineOrOnePerLine: true Cpp11BracedListStyle: true +FixNamespaceComments: true +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^["<](stdafx|pch)\.h[">]$' + Priority: -1 + - Regex: '^$' + Priority: 3 + - Regex: '^<(WinIoCtl|winhttp|Shellapi)\.h>$' + Priority: 4 + - Regex: '.*' + Priority: 2 IndentCaseLabels: true +IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 2 NamespaceIndentation: None PenaltyReturnTypeOnItsOwnLine: 1000 +PointerAlignment: Left SpaceAfterTemplateKeyword: false +Standard: Cpp11 +UseTab: Never diff --git a/Build_android/configure.sh b/Build_android/configure.sh index 13a7cfb02f..e426c06156 100755 --- a/Build_android/configure.sh +++ b/Build_android/configure.sh @@ -1,7 +1,7 @@ #!/bin/bash # Copyright (C) Microsoft. All rights reserved. # Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -# =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +# =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ # # configure.sh # @@ -9,7 +9,7 @@ # # For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk # -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- set -e diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h index 30e8962e5d..1dcb285ded 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h @@ -1,1214 +1,1180 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Asynchronous I/O: stream buffer. This is an extension to the PPL concurrency features and therefore -* lives in the Concurrency namespace. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Asynchronous I/O: stream buffer. This is an extension to the PPL concurrency features and therefore + * lives in the Concurrency namespace. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include +#include "cpprest/asyncrt_utils.h" +#include "cpprest/details/basic_types.h" +#include "pplx/pplxtasks.h" #include #include #include +#include #include -#include "pplx/pplxtasks.h" -#include "cpprest/details/basic_types.h" -#include "cpprest/asyncrt_utils.h" - #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX namespace Concurrency // since namespace pplx = Concurrency #else namespace pplx #endif { - namespace details - { - template - pplx::task _do_while(F func) - { - pplx::task first = func(); - return first.then([=](bool guard) -> pplx::task { - if (guard) - return pplx::details::_do_while(func); - else - return first; - }); - } - } +namespace details +{ +template +pplx::task _do_while(F func) +{ + pplx::task first = func(); + return first.then([=](bool guard) -> pplx::task { + if (guard) + return pplx::details::_do_while(func); + else + return first; + }); +} +} // namespace details } namespace Concurrency { - /// Library for asynchronous streams. namespace streams +{ +/// +/// Extending the standard char_traits type with one that adds values and types +/// that are unique to "C++ REST SDK" streams. +/// +/// +/// The data type of the basic element of the stream. +/// +template +struct char_traits : std::char_traits<_CharType> { /// - /// Extending the standard char_traits type with one that adds values and types - /// that are unique to "C++ REST SDK" streams. + /// Some synchronous functions will return this value if the operation + /// requires an asynchronous call in a given situation. /// - /// - /// The data type of the basic element of the stream. - /// - template - struct char_traits : std::char_traits<_CharType> + /// An int_type value which implies that an asynchronous call is required. + static typename std::char_traits<_CharType>::int_type requires_async() { - /// - /// Some synchronous functions will return this value if the operation - /// requires an asynchronous call in a given situation. - /// - /// An int_type value which implies that an asynchronous call is required. - static typename std::char_traits<_CharType>::int_type requires_async() { return std::char_traits<_CharType>::eof()-1; } - }; + return std::char_traits<_CharType>::eof() - 1; + } +}; #if !defined(_WIN32) - template<> - struct char_traits : private std::char_traits - { - public: - typedef unsigned char char_type; +template<> +struct char_traits : private std::char_traits +{ +public: + typedef unsigned char char_type; - using std::char_traits::eof; - using std::char_traits::int_type; - using std::char_traits::off_type; - using std::char_traits::pos_type; + using std::char_traits::eof; + using std::char_traits::int_type; + using std::char_traits::off_type; + using std::char_traits::pos_type; - static size_t length(const unsigned char* str) - { - return std::char_traits::length(reinterpret_cast(str)); - } + static size_t length(const unsigned char* str) + { + return std::char_traits::length(reinterpret_cast(str)); + } - static void assign(unsigned char& left, const unsigned char& right) { left = right; } - static unsigned char* assign(unsigned char* left, size_t n, unsigned char value) - { - return reinterpret_cast(std::char_traits::assign(reinterpret_cast(left), n, static_cast(value))); - } + static void assign(unsigned char& left, const unsigned char& right) { left = right; } + static unsigned char* assign(unsigned char* left, size_t n, unsigned char value) + { + return reinterpret_cast( + std::char_traits::assign(reinterpret_cast(left), n, static_cast(value))); + } - static unsigned char* copy(unsigned char* left, const unsigned char* right, size_t n) - { - return reinterpret_cast(std::char_traits::copy(reinterpret_cast(left), reinterpret_cast(right), n)); - } + static unsigned char* copy(unsigned char* left, const unsigned char* right, size_t n) + { + return reinterpret_cast( + std::char_traits::copy(reinterpret_cast(left), reinterpret_cast(right), n)); + } - static unsigned char* move(unsigned char* left, const unsigned char* right, size_t n) - { - return reinterpret_cast(std::char_traits::move(reinterpret_cast(left), reinterpret_cast(right), n)); - } + static unsigned char* move(unsigned char* left, const unsigned char* right, size_t n) + { + return reinterpret_cast( + std::char_traits::move(reinterpret_cast(left), reinterpret_cast(right), n)); + } - static int_type requires_async() { return eof() - 1; } - }; + static int_type requires_async() { return eof() - 1; } +}; #endif - namespace details { +namespace details +{ +/// +/// Stream buffer base class. +/// +template +class basic_streambuf +{ +public: + typedef _CharType char_type; + typedef ::concurrency::streams::char_traits<_CharType> traits; + + typedef typename traits::int_type int_type; + typedef typename traits::pos_type pos_type; + typedef typename traits::off_type off_type; /// - /// Stream buffer base class. + /// Virtual constructor for stream buffers. /// - template - class basic_streambuf - { - public: - typedef _CharType char_type; - typedef ::concurrency::streams::char_traits<_CharType> traits; - - typedef typename traits::int_type int_type; - typedef typename traits::pos_type pos_type; - typedef typename traits::off_type off_type; - - - /// - /// Virtual constructor for stream buffers. - /// - virtual ~basic_streambuf() { } - - /// - /// can_read is used to determine whether a stream buffer will support read operations (get). - /// - virtual bool can_read() const = 0; - - /// - /// can_write is used to determine whether a stream buffer will support write operations (put). - /// - virtual bool can_write() const = 0; - - /// - /// can_seek is used to determine whether a stream buffer supports seeking. - /// - virtual bool can_seek() const = 0; - - /// - /// has_size is used to determine whether a stream buffer supports size(). - /// - virtual bool has_size() const = 0; - - /// - /// is_eof is used to determine whether a read head has reached the end of the buffer. - /// - virtual bool is_eof() const = 0; - - /// - /// Gets the stream buffer size, if one has been set. - /// - /// The direction of buffering (in or out) - /// The size of the internal buffer (for the given direction). - /// An implementation that does not support buffering will always return 0. - virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const = 0; - - /// - /// Sets the stream buffer implementation to buffer or not buffer. - /// - /// The size to use for internal buffering, 0 if no buffering should be done. - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will silently ignore calls to this function and it will not have any effect on what is returned by subsequent calls to . - virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) = 0; - - /// - /// For any input stream, in_avail returns the number of characters that are immediately available - /// to be consumed without blocking. May be used in conjunction with to read data without - /// incurring the overhead of using tasks. - /// - virtual size_t in_avail() const = 0; - - /// - /// Checks if the stream buffer is open. - /// - /// No separation is made between open for reading and open for writing. - virtual bool is_open() const = 0; - - /// - /// Closes the stream buffer, preventing further read or write operations. - /// - /// The I/O mode (in or out) to close for. - virtual pplx::task close(std::ios_base::openmode mode = (std::ios_base::in | std::ios_base::out)) = 0; - - /// - /// Closes the stream buffer with an exception. - /// - /// The I/O mode (in or out) to close for. - /// Pointer to the exception. - virtual pplx::task close(std::ios_base::openmode mode, std::exception_ptr eptr) = 0; - - /// - /// Writes a single character to the stream. - /// - /// The character to write - /// A task that holds the value of the character. This value is EOF if the write operation fails. - virtual pplx::task putc(_CharType ch) = 0; - - /// - /// Writes a number of characters to the stream. - /// - /// A pointer to the block of data to be written. - /// The number of characters to write. - /// A task that holds the number of characters actually written, either 'count' or 0. - virtual pplx::task putn(const _CharType *ptr, size_t count) = 0; - - /// - /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until - /// the returned task completes. - /// - /// A pointer to the block of data to be written. - /// The number of characters to write. - /// A task that holds the number of characters actually written, either 'count' or 0. - virtual pplx::task putn_nocopy(const _CharType *ptr, size_t count) = 0; - - /// - /// Reads a single character from the stream and advances the read position. - /// - /// A task that holds the value of the character. This value is EOF if the read fails. - virtual pplx::task bumpc() = 0; - - /// - /// Reads a single character from the stream and advances the read position. - /// - /// The value of the character. -1 if the read fails. -2 if an asynchronous read is required - /// This is a synchronous operation, but is guaranteed to never block. - virtual int_type sbumpc() = 0; - - /// - /// Reads a single character from the stream without advancing the read position. - /// - /// A task that holds the value of the byte. This value is EOF if the read fails. - virtual pplx::task getc() = 0; - - /// - /// Reads a single character from the stream without advancing the read position. - /// - /// The value of the character. EOF if the read fails. if an asynchronous read is required - /// This is a synchronous operation, but is guaranteed to never block. - virtual int_type sgetc() = 0; - - /// - /// Advances the read position, then returns the next character without advancing again. - /// - /// A task that holds the value of the character. This value is EOF if the read fails. - virtual pplx::task nextc() = 0; - - /// - /// Retreats the read position, then returns the current character without advancing. - /// - /// A task that holds the value of the character. This value is EOF if the read fails, requires_async if an asynchronous read is required - virtual pplx::task ungetc() = 0; - - /// - /// Reads up to a given number of characters from the stream. - /// - /// The address of the target memory area. - /// The maximum number of characters to read. - /// A task that holds the number of characters read. This value is O if the end of the stream is reached. - virtual pplx::task getn(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0; - - /// - /// Copies up to a given number of characters from the stream, synchronously. - /// - /// The address of the target memory area. - /// The maximum number of characters to read. - /// The number of characters copied. O if the end of the stream is reached or an asynchronous read is required. - /// This is a synchronous operation, but is guaranteed to never block. - virtual size_t scopy(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0; - - /// - /// Gets the current read or write position in the stream. - /// - /// The I/O direction to seek (see remarks) - /// The current position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual pos_type getpos(std::ios_base::openmode direction) const = 0; - - /// - /// Gets the size of the stream, if known. Calls to has_size will determine whether - /// the result of size can be relied on. - /// - virtual utility::size64_t size() const = 0; - - /// - /// Seeks to the given position. - /// - /// The offset from the beginning of the stream. - /// The I/O direction to seek (see remarks). - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual pos_type seekpos(pos_type pos, std::ios_base::openmode direction) = 0; - - /// - /// Seeks to a position given by a relative offset. - /// - /// The relative position to seek to - /// The starting point (beginning, end, current) for the seek. - /// The I/O direction to seek (see remarks) - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the mode parameter defines whether to move the read or the write cursor. - virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) = 0; - - /// - /// For output streams, flush any internally buffered data to the underlying medium. - /// - /// A task that returns true if the sync succeeds, false if not. - virtual pplx::task sync() = 0; - - // - // Efficient read and write. - // - // The following routines are intended to be used for more efficient, copy-free, reading and - // writing of data from/to the stream. Rather than having the caller provide a buffer into which - // data is written or from which it is read, the stream buffer provides a pointer directly to the - // internal data blocks that it is using. Since not all stream buffers use internal data structures - // to copy data, the functions may not be supported by all. An application that wishes to use this - // functionality should therefore first try them and check for failure to support. If there is - // such failure, the application should fall back on the copying interfaces (putn / getn) - // - - /// - /// Allocates a contiguous memory block and returns it. - /// - /// The number of characters to allocate. - /// A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit. - virtual _CharType* alloc(_In_ size_t count) = 0; - - /// - /// Submits a block already allocated by the stream buffer. - /// - /// The number of characters to be committed. - virtual void commit(_In_ size_t count) = 0; - - /// - /// Gets a pointer to the next already allocated contiguous block of data. - /// - /// A reference to a pointer variable that will hold the address of the block on success. - /// The number of contiguous characters available at the address in 'ptr'. - /// true if the operation succeeded, false otherwise. - /// - /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that - /// there is no block to return immediately or that the stream buffer does not support the operation. - /// The stream buffer may not de-allocate the block until is called. - /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; - /// a subsequent read will not succeed. - /// - virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) = 0; - - /// - /// Releases a block of data acquired using . This frees the stream buffer to de-allocate the - /// memory, if it so desires. Move the read position ahead by the count. - /// - /// A pointer to the block of data to be released. - /// The number of characters that were read. - virtual void release(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0; - - /// - /// Retrieves the stream buffer exception_ptr if it has been set. - /// - /// Pointer to the exception, if it has been set; otherwise, nullptr will be returned - virtual std::exception_ptr exception() const = 0; - }; - - - template - class streambuf_state_manager : public basic_streambuf<_CharType>, public std::enable_shared_from_this> - { - public: - typedef typename details::basic_streambuf<_CharType>::traits traits; - typedef typename details::basic_streambuf<_CharType>::int_type int_type; - typedef typename details::basic_streambuf<_CharType>::pos_type pos_type; - typedef typename details::basic_streambuf<_CharType>::off_type off_type; - - /// - /// can_read is used to determine whether a stream buffer will support read operations (get). - /// - virtual bool can_read() const - { - return m_stream_can_read; - } + virtual ~basic_streambuf() {} - /// - /// can_write is used to determine whether a stream buffer will support write operations (put). - /// - virtual bool can_write() const - { - return m_stream_can_write; - } + /// + /// can_read is used to determine whether a stream buffer will support read operations (get). + /// + virtual bool can_read() const = 0; - /// - /// Checks if the stream buffer is open. - /// - /// No separation is made between open for reading and open for writing. - virtual bool is_open() const - { - return can_read() || can_write(); - } + /// + /// can_write is used to determine whether a stream buffer will support write operations (put). + /// + virtual bool can_write() const = 0; - /// - /// Closes the stream buffer, preventing further read or write operations. - /// - /// The I/O mode (in or out) to close for. - virtual pplx::task close(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - { - pplx::task closeOp = pplx::task_from_result(); + /// + /// can_seek is used to determine whether a stream buffer supports seeking. + /// + virtual bool can_seek() const = 0; - if (mode & std::ios_base::in && can_read()) { - closeOp = _close_read(); - } + /// + /// has_size is used to determine whether a stream buffer supports size(). + /// + virtual bool has_size() const = 0; - // After the flush_internal task completed, "this" object may have been destroyed, - // accessing the members is invalid, use shared_from_this to avoid access violation exception. - auto this_ptr = std::static_pointer_cast(this->shared_from_this()); + /// + /// is_eof is used to determine whether a read head has reached the end of the buffer. + /// + virtual bool is_eof() const = 0; - if (mode & std::ios_base::out && can_write()) { - if (closeOp.is_done()) - closeOp = closeOp && _close_write().then([this_ptr]{}); // passing down exceptions from closeOp - else - closeOp = closeOp.then([this_ptr] { return this_ptr->_close_write().then([this_ptr]{}); }); - } + /// + /// Gets the stream buffer size, if one has been set. + /// + /// The direction of buffering (in or out) + /// The size of the internal buffer (for the given direction). + /// An implementation that does not support buffering will always return 0. + virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const = 0; - return closeOp; - } + /// + /// Sets the stream buffer implementation to buffer or not buffer. + /// + /// The size to use for internal buffering, 0 if no buffering should be done. + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will silently ignore calls to this function and it + /// will not have any effect on what is returned by subsequent calls to . + virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) = 0; - /// - /// Closes the stream buffer with an exception. - /// - /// The I/O mode (in or out) to close for. - /// Pointer to the exception. - virtual pplx::task close(std::ios_base::openmode mode, std::exception_ptr eptr) - { - if (m_currentException == nullptr) - m_currentException = eptr; - return close(mode); - } + /// + /// For any input stream, in_avail returns the number of characters that are immediately available + /// to be consumed without blocking. May be used in conjunction with to read data without + /// incurring the overhead of using tasks. + /// + virtual size_t in_avail() const = 0; - /// - /// is_eof is used to determine whether a read head has reached the end of the buffer. - /// - virtual bool is_eof() const - { - return m_stream_read_eof; - } + /// + /// Checks if the stream buffer is open. + /// + /// No separation is made between open for reading and open for writing. + virtual bool is_open() const = 0; - /// - /// Writes a single character to the stream. - /// - /// The character to write - /// The value of the character. EOF if the write operation fails - virtual pplx::task putc(_CharType ch) - { - if (!can_write()) - return create_exception_checked_value_task(traits::eof()); + /// + /// Closes the stream buffer, preventing further read or write operations. + /// + /// The I/O mode (in or out) to close for. + virtual pplx::task close(std::ios_base::openmode mode = (std::ios_base::in | std::ios_base::out)) = 0; - return create_exception_checked_task(_putc(ch), [](int_type) { - return false; // no EOF for write - }); - } + /// + /// Closes the stream buffer with an exception. + /// + /// The I/O mode (in or out) to close for. + /// Pointer to the exception. + virtual pplx::task close(std::ios_base::openmode mode, std::exception_ptr eptr) = 0; - /// - /// Writes a number of characters to the stream. - /// - /// A pointer to the block of data to be written. - /// The number of characters to write. - /// The number of characters actually written, either 'count' or 0. - CASABLANCA_DEPRECATED("This API in some cases performs a copy. It is deprecated and will be removed in a future release. Use putn_nocopy instead.") - virtual pplx::task putn(const _CharType *ptr, size_t count) - { - if (!can_write()) - return create_exception_checked_value_task(0); - if (count == 0) - return pplx::task_from_result(0); - - return create_exception_checked_task(_putn(ptr, count, true), [](size_t) { - return false; // no EOF for write - }); - } + /// + /// Writes a single character to the stream. + /// + /// The character to write + /// A task that holds the value of the character. This value is EOF if the write operation + /// fails. + virtual pplx::task putc(_CharType ch) = 0; - /// - /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until - /// the returned task completes. - /// - /// A pointer to the block of data to be written. - /// The number of characters to write. - /// A task that holds the number of characters actually written, either 'count' or 0. - virtual pplx::task putn_nocopy(const _CharType *ptr, size_t count) - { - if (!can_write()) - return create_exception_checked_value_task(0); - if (count == 0) - return pplx::task_from_result(0); - - return create_exception_checked_task(_putn(ptr, count), [](size_t) { - return false; // no EOF for write - }); - } + /// + /// Writes a number of characters to the stream. + /// + /// A pointer to the block of data to be written. + /// The number of characters to write. + /// A task that holds the number of characters actually written, either 'count' or 0. + virtual pplx::task putn(const _CharType* ptr, size_t count) = 0; - /// - /// Reads a single character from the stream and advances the read position. - /// - /// The value of the character. EOF if the read fails. - virtual pplx::task bumpc() - { - if (!can_read()) - return create_exception_checked_value_task(streambuf_state_manager<_CharType>::traits::eof()); + /// + /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until + /// the returned task completes. + /// + /// A pointer to the block of data to be written. + /// The number of characters to write. + /// A task that holds the number of characters actually written, either 'count' or 0. + virtual pplx::task putn_nocopy(const _CharType* ptr, size_t count) = 0; - return create_exception_checked_task(_bumpc(), [](int_type val) { - return val == streambuf_state_manager<_CharType>::traits::eof(); - }); - } + /// + /// Reads a single character from the stream and advances the read position. + /// + /// A task that holds the value of the character. This value is EOF if the read fails. + virtual pplx::task bumpc() = 0; - /// - /// Reads a single character from the stream and advances the read position. - /// - /// The value of the character. -1 if the read fails. -2 if an asynchronous read is required - /// This is a synchronous operation, but is guaranteed to never block. - virtual int_type sbumpc() - { - if ( !(m_currentException == nullptr) ) - std::rethrow_exception(m_currentException); - if (!can_read()) - return traits::eof(); - return check_sync_read_eof(_sbumpc()); - } + /// + /// Reads a single character from the stream and advances the read position. + /// + /// The value of the character. -1 if the read fails. -2 if an asynchronous read is + /// required This is a synchronous operation, but is guaranteed to never block. + virtual int_type sbumpc() = 0; - /// - /// Reads a single character from the stream without advancing the read position. - /// - /// The value of the byte. EOF if the read fails. - virtual pplx::task getc() - { - if (!can_read()) - return create_exception_checked_value_task(traits::eof()); + /// + /// Reads a single character from the stream without advancing the read position. + /// + /// A task that holds the value of the byte. This value is EOF if the read fails. + virtual pplx::task getc() = 0; - return create_exception_checked_task(_getc(), [](int_type val) { - return val == streambuf_state_manager<_CharType>::traits::eof(); - }); - } + /// + /// Reads a single character from the stream without advancing the read position. + /// + /// The value of the character. EOF if the read fails. if an + /// asynchronous read is required This is a synchronous operation, but is guaranteed to never + /// block. + virtual int_type sgetc() = 0; - /// - /// Reads a single character from the stream without advancing the read position. - /// - /// The value of the character. EOF if the read fails. if an asynchronous read is required - /// This is a synchronous operation, but is guaranteed to never block. - virtual int_type sgetc() - { - if ( !(m_currentException == nullptr) ) - std::rethrow_exception(m_currentException); - if (!can_read()) - return traits::eof(); - return check_sync_read_eof(_sgetc()); - } + /// + /// Advances the read position, then returns the next character without advancing again. + /// + /// A task that holds the value of the character. This value is EOF if the read fails. + virtual pplx::task nextc() = 0; - /// - /// Advances the read position, then returns the next character without advancing again. - /// - /// The value of the character. EOF if the read fails. - virtual pplx::task nextc() - { - if (!can_read()) - return create_exception_checked_value_task(traits::eof()); + /// + /// Retreats the read position, then returns the current character without advancing. + /// + /// A task that holds the value of the character. This value is EOF if the read fails, + /// requires_async if an asynchronous read is required + virtual pplx::task ungetc() = 0; - return create_exception_checked_task(_nextc(), [](int_type val) { - return val == streambuf_state_manager<_CharType>::traits::eof(); - }); - } + /// + /// Reads up to a given number of characters from the stream. + /// + /// The address of the target memory area. + /// The maximum number of characters to read. + /// A task that holds the number of characters read. This value is O if the end of the stream is + /// reached. + virtual pplx::task getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0; - /// - /// Retreats the read position, then returns the current character without advancing. - /// - /// The value of the character. EOF if the read fails. if an asynchronous read is required - virtual pplx::task ungetc() - { - if (!can_read()) - return create_exception_checked_value_task(traits::eof()); + /// + /// Copies up to a given number of characters from the stream, synchronously. + /// + /// The address of the target memory area. + /// The maximum number of characters to read. + /// The number of characters copied. O if the end of the stream is reached or an asynchronous read is + /// required. This is a synchronous operation, but is guaranteed to never block. + virtual size_t scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0; - return create_exception_checked_task(_ungetc(), [](int_type) { - return false; - }); - } + /// + /// Gets the current read or write position in the stream. + /// + /// The I/O direction to seek (see remarks) + /// The current position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the direction parameter defines whether to move the read or the write + /// cursor. + virtual pos_type getpos(std::ios_base::openmode direction) const = 0; - /// - /// Reads up to a given number of characters from the stream. - /// - /// The address of the target memory area. - /// The maximum number of characters to read. - /// The number of characters read. O if the end of the stream is reached. - virtual pplx::task getn(_Out_writes_(count) _CharType *ptr, _In_ size_t count) - { - if (!can_read()) - return create_exception_checked_value_task(0); - if (count == 0) - return pplx::task_from_result(0); - - return create_exception_checked_task(_getn(ptr, count), [](size_t val) { - return val == 0; - }); - } + /// + /// Gets the size of the stream, if known. Calls to has_size will determine whether + /// the result of size can be relied on. + /// + virtual utility::size64_t size() const = 0; - /// - /// Copies up to a given number of characters from the stream, synchronously. - /// - /// The address of the target memory area. - /// The maximum number of characters to read. - /// The number of characters copied. O if the end of the stream is reached or an asynchronous read is required. - /// This is a synchronous operation, but is guaranteed to never block. - virtual size_t scopy(_Out_writes_(count) _CharType *ptr, _In_ size_t count) - { - if ( !(m_currentException == nullptr) ) - std::rethrow_exception(m_currentException); - if (!can_read()) - return 0; + /// + /// Seeks to the given position. + /// + /// The offset from the beginning of the stream. + /// The I/O direction to seek (see remarks). + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. For such streams, the direction parameter + /// defines whether to move the read or the write cursor. + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode direction) = 0; - return _scopy(ptr, count); - } + /// + /// Seeks to a position given by a relative offset. + /// + /// The relative position to seek to + /// The starting point (beginning, end, current) for the seek. + /// The I/O direction to seek (see remarks) + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the mode parameter defines whether to move the read or the write cursor. + virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) = 0; - /// - /// For output streams, flush any internally buffered data to the underlying medium. - /// - /// true if the flush succeeds, false if not - virtual pplx::task sync() - { - if (!can_write()) - { - if (m_currentException == nullptr) - return pplx::task_from_result(); - else - return pplx::task_from_exception(m_currentException); - } - return create_exception_checked_task(_sync(), [](bool) { - return false; - }).then([](bool){}); - } + /// + /// For output streams, flush any internally buffered data to the underlying medium. + /// + /// A task that returns true if the sync succeeds, false if not. + virtual pplx::task sync() = 0; + + // + // Efficient read and write. + // + // The following routines are intended to be used for more efficient, copy-free, reading and + // writing of data from/to the stream. Rather than having the caller provide a buffer into which + // data is written or from which it is read, the stream buffer provides a pointer directly to the + // internal data blocks that it is using. Since not all stream buffers use internal data structures + // to copy data, the functions may not be supported by all. An application that wishes to use this + // functionality should therefore first try them and check for failure to support. If there is + // such failure, the application should fall back on the copying interfaces (putn / getn) + // - /// - /// Retrieves the stream buffer exception_ptr if it has been set. - /// - /// Pointer to the exception, if it has been set; otherwise, nullptr will be returned. - virtual std::exception_ptr exception() const - { - return m_currentException; - } + /// + /// Allocates a contiguous memory block and returns it. + /// + /// The number of characters to allocate. + /// A pointer to a block to write to, null if the stream buffer implementation does not support + /// alloc/commit. + virtual _CharType* alloc(_In_ size_t count) = 0; - /// - /// Allocates a contiguous memory block and returns it. - /// - /// The number of characters to allocate. - /// A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit. - /// This is intended as an advanced API to be used only when it is important to avoid extra copies. - _CharType* alloc(size_t count) - { - if (m_alloced) - throw std::logic_error("The buffer is already allocated, this maybe caused by overlap of stream read or write"); + /// + /// Submits a block already allocated by the stream buffer. + /// + /// The number of characters to be committed. + virtual void commit(_In_ size_t count) = 0; + + /// + /// Gets a pointer to the next already allocated contiguous block of data. + /// + /// A reference to a pointer variable that will hold the address of the block on success. + /// The number of contiguous characters available at the address in 'ptr'. + /// true if the operation succeeded, false otherwise. + /// + /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that + /// there is no block to return immediately or that the stream buffer does not support the operation. + /// The stream buffer may not de-allocate the block until is called. + /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; + /// a subsequent read will not succeed. + /// + virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) = 0; - _CharType* alloc_result = _alloc(count); + /// + /// Releases a block of data acquired using . This frees the stream buffer to + /// de-allocate the memory, if it so desires. Move the read position ahead by the count. + /// + /// A pointer to the block of data to be released. + /// The number of characters that were read. + virtual void release(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0; - if (alloc_result) - m_alloced = true; + /// + /// Retrieves the stream buffer exception_ptr if it has been set. + /// + /// Pointer to the exception, if it has been set; otherwise, nullptr will be returned + virtual std::exception_ptr exception() const = 0; +}; - return alloc_result; - } +template +class streambuf_state_manager : public basic_streambuf<_CharType>, + public std::enable_shared_from_this> +{ +public: + typedef typename details::basic_streambuf<_CharType>::traits traits; + typedef typename details::basic_streambuf<_CharType>::int_type int_type; + typedef typename details::basic_streambuf<_CharType>::pos_type pos_type; + typedef typename details::basic_streambuf<_CharType>::off_type off_type; - /// - /// Submits a block already allocated by the stream buffer. - /// - /// The number of characters to be committed. - /// This is intended as an advanced API to be used only when it is important to avoid extra copies. - void commit(size_t count) - { - if (!m_alloced) - throw std::logic_error("The buffer needs to allocate first"); + /// + /// can_read is used to determine whether a stream buffer will support read operations (get). + /// + virtual bool can_read() const { return m_stream_can_read; } - _commit(count); - m_alloced = false; - } + /// + /// can_write is used to determine whether a stream buffer will support write operations (put). + /// + virtual bool can_write() const { return m_stream_can_write; } - public: - virtual bool can_seek() const = 0; - virtual bool has_size() const = 0; - virtual utility::size64_t size() const { return 0; } - virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const = 0; - virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) = 0; - virtual size_t in_avail() const = 0; - virtual pos_type getpos(std::ios_base::openmode direction) const = 0; - virtual pos_type seekpos(pos_type pos, std::ios_base::openmode direction) = 0; - virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) = 0; - virtual bool acquire(_Out_writes_(count) _CharType*& ptr, _In_ size_t& count) = 0; - virtual void release(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0; - protected: - virtual pplx::task _putc(_CharType ch) = 0; - - // This API is only needed for file streams and until we remove the deprecated stream buffer putn overload. - virtual pplx::task _putn(const _CharType *ptr, size_t count, bool) - { - // Default to no copy, only the file streams API overloads and performs a copy. - return _putn(ptr, count); - } - virtual pplx::task _putn(const _CharType *ptr, size_t count) = 0; - - virtual pplx::task _bumpc() = 0; - virtual int_type _sbumpc() = 0; - virtual pplx::task _getc() = 0; - virtual int_type _sgetc() = 0; - virtual pplx::task _nextc() = 0; - virtual pplx::task _ungetc() = 0; - virtual pplx::task _getn(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0; - virtual size_t _scopy(_Out_writes_(count) _CharType *ptr, _In_ size_t count) = 0; - virtual pplx::task _sync() = 0; - virtual _CharType* _alloc(size_t count) = 0; - virtual void _commit(size_t count) = 0; - - /// - /// The real read head close operation, implementation should override it if there is any resource to be released. - /// - virtual pplx::task _close_read() - { - m_stream_can_read = false; - return pplx::task_from_result(); - } + /// + /// Checks if the stream buffer is open. + /// + /// No separation is made between open for reading and open for writing. + virtual bool is_open() const { return can_read() || can_write(); } + + /// + /// Closes the stream buffer, preventing further read or write operations. + /// + /// The I/O mode (in or out) to close for. + virtual pplx::task close(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) + { + pplx::task closeOp = pplx::task_from_result(); - /// - /// The real write head close operation, implementation should override it if there is any resource to be released. - /// - virtual pplx::task _close_write() + if (mode & std::ios_base::in && can_read()) { - m_stream_can_write = false; - return pplx::task_from_result(); + closeOp = _close_read(); } - protected: - streambuf_state_manager(std::ios_base::openmode mode) + // After the flush_internal task completed, "this" object may have been destroyed, + // accessing the members is invalid, use shared_from_this to avoid access violation exception. + auto this_ptr = std::static_pointer_cast(this->shared_from_this()); + + if (mode & std::ios_base::out && can_write()) { - m_stream_can_read = (mode & std::ios_base::in) != 0; - m_stream_can_write = (mode & std::ios_base::out) != 0; - m_stream_read_eof = false; - m_alloced = false; + if (closeOp.is_done()) + closeOp = closeOp && _close_write().then([this_ptr] {}); // passing down exceptions from closeOp + else + closeOp = closeOp.then([this_ptr] { return this_ptr->_close_write().then([this_ptr] {}); }); } - std::exception_ptr m_currentException; - // The in/out mode for the buffer - std::atomic m_stream_can_read; - std::atomic m_stream_can_write; - std::atomic m_stream_read_eof; - std::atomic m_alloced; + return closeOp; + } + + /// + /// Closes the stream buffer with an exception. + /// + /// The I/O mode (in or out) to close for. + /// Pointer to the exception. + virtual pplx::task close(std::ios_base::openmode mode, std::exception_ptr eptr) + { + if (m_currentException == nullptr) m_currentException = eptr; + return close(mode); + } + + /// + /// is_eof is used to determine whether a read head has reached the end of the buffer. + /// + virtual bool is_eof() const { return m_stream_read_eof; } + + /// + /// Writes a single character to the stream. + /// + /// The character to write + /// The value of the character. EOF if the write operation fails + virtual pplx::task putc(_CharType ch) + { + if (!can_write()) return create_exception_checked_value_task(traits::eof()); + + return create_exception_checked_task(_putc(ch), [](int_type) { + return false; // no EOF for write + }); + } + + /// + /// Writes a number of characters to the stream. + /// + /// A pointer to the block of data to be written. + /// The number of characters to write. + /// The number of characters actually written, either 'count' or 0. + CASABLANCA_DEPRECATED("This API in some cases performs a copy. It is deprecated and will be removed in a future " + "release. Use putn_nocopy instead.") + virtual pplx::task putn(const _CharType* ptr, size_t count) + { + if (!can_write()) return create_exception_checked_value_task(0); + if (count == 0) return pplx::task_from_result(0); + + return create_exception_checked_task(_putn(ptr, count, true), [](size_t) { + return false; // no EOF for write + }); + } + + /// + /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until + /// the returned task completes. + /// + /// A pointer to the block of data to be written. + /// The number of characters to write. + /// A task that holds the number of characters actually written, either 'count' or 0. + virtual pplx::task putn_nocopy(const _CharType* ptr, size_t count) + { + if (!can_write()) return create_exception_checked_value_task(0); + if (count == 0) return pplx::task_from_result(0); + + return create_exception_checked_task(_putn(ptr, count), [](size_t) { + return false; // no EOF for write + }); + } + + /// + /// Reads a single character from the stream and advances the read position. + /// + /// The value of the character. EOF if the read fails. + virtual pplx::task bumpc() + { + if (!can_read()) + return create_exception_checked_value_task(streambuf_state_manager<_CharType>::traits::eof()); + + return create_exception_checked_task( + _bumpc(), [](int_type val) { return val == streambuf_state_manager<_CharType>::traits::eof(); }); + } + /// + /// Reads a single character from the stream and advances the read position. + /// + /// The value of the character. -1 if the read fails. -2 if an asynchronous read is + /// required This is a synchronous operation, but is guaranteed to never block. + virtual int_type sbumpc() + { + if (!(m_currentException == nullptr)) std::rethrow_exception(m_currentException); + if (!can_read()) return traits::eof(); + return check_sync_read_eof(_sbumpc()); + } - private: - template - pplx::task<_CharType1> create_exception_checked_value_task(const _CharType1 &val) const + /// + /// Reads a single character from the stream without advancing the read position. + /// + /// The value of the byte. EOF if the read fails. + virtual pplx::task getc() + { + if (!can_read()) return create_exception_checked_value_task(traits::eof()); + + return create_exception_checked_task( + _getc(), [](int_type val) { return val == streambuf_state_manager<_CharType>::traits::eof(); }); + } + + /// + /// Reads a single character from the stream without advancing the read position. + /// + /// The value of the character. EOF if the read fails. if an + /// asynchronous read is required This is a synchronous operation, but is guaranteed to never + /// block. + virtual int_type sgetc() + { + if (!(m_currentException == nullptr)) std::rethrow_exception(m_currentException); + if (!can_read()) return traits::eof(); + return check_sync_read_eof(_sgetc()); + } + + /// + /// Advances the read position, then returns the next character without advancing again. + /// + /// The value of the character. EOF if the read fails. + virtual pplx::task nextc() + { + if (!can_read()) return create_exception_checked_value_task(traits::eof()); + + return create_exception_checked_task( + _nextc(), [](int_type val) { return val == streambuf_state_manager<_CharType>::traits::eof(); }); + } + + /// + /// Retreats the read position, then returns the current character without advancing. + /// + /// The value of the character. EOF if the read fails. if an + /// asynchronous read is required + virtual pplx::task ungetc() + { + if (!can_read()) return create_exception_checked_value_task(traits::eof()); + + return create_exception_checked_task(_ungetc(), [](int_type) { return false; }); + } + + /// + /// Reads up to a given number of characters from the stream. + /// + /// The address of the target memory area. + /// The maximum number of characters to read. + /// The number of characters read. O if the end of the stream is reached. + virtual pplx::task getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + if (!can_read()) return create_exception_checked_value_task(0); + if (count == 0) return pplx::task_from_result(0); + + return create_exception_checked_task(_getn(ptr, count), [](size_t val) { return val == 0; }); + } + + /// + /// Copies up to a given number of characters from the stream, synchronously. + /// + /// The address of the target memory area. + /// The maximum number of characters to read. + /// The number of characters copied. O if the end of the stream is reached or an asynchronous read is + /// required. This is a synchronous operation, but is guaranteed to never block. + virtual size_t scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + if (!(m_currentException == nullptr)) std::rethrow_exception(m_currentException); + if (!can_read()) return 0; + + return _scopy(ptr, count); + } + + /// + /// For output streams, flush any internally buffered data to the underlying medium. + /// + /// true if the flush succeeds, false if not + virtual pplx::task sync() + { + if (!can_write()) { - if (this->exception() == nullptr) - return pplx::task_from_result<_CharType1>(static_cast<_CharType1>(val)); + if (m_currentException == nullptr) + return pplx::task_from_result(); else - return pplx::task_from_exception<_CharType1>(this->exception()); + return pplx::task_from_exception(m_currentException); } + return create_exception_checked_task(_sync(), [](bool) { return false; }).then([](bool) {}); + } - // Set exception and eof states for async read - template - pplx::task<_CharType1> create_exception_checked_task(pplx::task<_CharType1> result, std::function eof_test, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - { - auto thisPointer = this->shared_from_this(); - - auto func1 = [=](pplx::task<_CharType1> t1) -> pplx::task<_CharType1> { - try { - thisPointer->m_stream_read_eof = eof_test(t1.get()); - } catch (...) { - thisPointer->close(mode, std::current_exception()).get(); - return pplx::task_from_exception<_CharType1>(thisPointer->exception(), pplx::task_options()); - } - if (thisPointer->m_stream_read_eof && !(thisPointer->exception() == nullptr)) - return pplx::task_from_exception<_CharType1>(thisPointer->exception(), pplx::task_options()); - return t1; - }; - - if ( result.is_done() ) + /// + /// Retrieves the stream buffer exception_ptr if it has been set. + /// + /// Pointer to the exception, if it has been set; otherwise, nullptr will be returned. + virtual std::exception_ptr exception() const { return m_currentException; } + + /// + /// Allocates a contiguous memory block and returns it. + /// + /// The number of characters to allocate. + /// A pointer to a block to write to, null if the stream buffer implementation does not support + /// alloc/commit. This is intended as an advanced API to be used only when it is important to + /// avoid extra copies. + _CharType* alloc(size_t count) + { + if (m_alloced) + throw std::logic_error( + "The buffer is already allocated, this maybe caused by overlap of stream read or write"); + + _CharType* alloc_result = _alloc(count); + + if (alloc_result) m_alloced = true; + + return alloc_result; + } + + /// + /// Submits a block already allocated by the stream buffer. + /// + /// The number of characters to be committed. + /// This is intended as an advanced API to be used only when it is important to avoid extra + /// copies. + void commit(size_t count) + { + if (!m_alloced) throw std::logic_error("The buffer needs to allocate first"); + + _commit(count); + m_alloced = false; + } + +public: + virtual bool can_seek() const = 0; + virtual bool has_size() const = 0; + virtual utility::size64_t size() const { return 0; } + virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const = 0; + virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) = 0; + virtual size_t in_avail() const = 0; + virtual pos_type getpos(std::ios_base::openmode direction) const = 0; + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode direction) = 0; + virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) = 0; + virtual bool acquire(_Out_writes_(count) _CharType*& ptr, _In_ size_t& count) = 0; + virtual void release(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0; + +protected: + virtual pplx::task _putc(_CharType ch) = 0; + + // This API is only needed for file streams and until we remove the deprecated stream buffer putn overload. + virtual pplx::task _putn(const _CharType* ptr, size_t count, bool) + { + // Default to no copy, only the file streams API overloads and performs a copy. + return _putn(ptr, count); + } + virtual pplx::task _putn(const _CharType* ptr, size_t count) = 0; + + virtual pplx::task _bumpc() = 0; + virtual int_type _sbumpc() = 0; + virtual pplx::task _getc() = 0; + virtual int_type _sgetc() = 0; + virtual pplx::task _nextc() = 0; + virtual pplx::task _ungetc() = 0; + virtual pplx::task _getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0; + virtual size_t _scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0; + virtual pplx::task _sync() = 0; + virtual _CharType* _alloc(size_t count) = 0; + virtual void _commit(size_t count) = 0; + + /// + /// The real read head close operation, implementation should override it if there is any resource to be released. + /// + virtual pplx::task _close_read() + { + m_stream_can_read = false; + return pplx::task_from_result(); + } + + /// + /// The real write head close operation, implementation should override it if there is any resource to be released. + /// + virtual pplx::task _close_write() + { + m_stream_can_write = false; + return pplx::task_from_result(); + } + +protected: + streambuf_state_manager(std::ios_base::openmode mode) + { + m_stream_can_read = (mode & std::ios_base::in) != 0; + m_stream_can_write = (mode & std::ios_base::out) != 0; + m_stream_read_eof = false; + m_alloced = false; + } + + std::exception_ptr m_currentException; + // The in/out mode for the buffer + std::atomic m_stream_can_read; + std::atomic m_stream_can_write; + std::atomic m_stream_read_eof; + std::atomic m_alloced; + +private: + template + pplx::task<_CharType1> create_exception_checked_value_task(const _CharType1& val) const + { + if (this->exception() == nullptr) + return pplx::task_from_result<_CharType1>(static_cast<_CharType1>(val)); + else + return pplx::task_from_exception<_CharType1>(this->exception()); + } + + // Set exception and eof states for async read + template + pplx::task<_CharType1> create_exception_checked_task(pplx::task<_CharType1> result, + std::function eof_test, + std::ios_base::openmode mode = std::ios_base::in | + std::ios_base::out) + { + auto thisPointer = this->shared_from_this(); + + auto func1 = [=](pplx::task<_CharType1> t1) -> pplx::task<_CharType1> { + try { - // If the data is already available, we should avoid scheduling a continuation, so we do it inline. - return func1(result); + thisPointer->m_stream_read_eof = eof_test(t1.get()); } - else + catch (...) { - return result.then(func1); + thisPointer->close(mode, std::current_exception()).get(); + return pplx::task_from_exception<_CharType1>(thisPointer->exception(), pplx::task_options()); } - } + if (thisPointer->m_stream_read_eof && !(thisPointer->exception() == nullptr)) + return pplx::task_from_exception<_CharType1>(thisPointer->exception(), pplx::task_options()); + return t1; + }; - // Set eof states for sync read - int_type check_sync_read_eof(int_type ch) + if (result.is_done()) { - m_stream_read_eof = ch == traits::eof(); - return ch; + // If the data is already available, we should avoid scheduling a continuation, so we do it inline. + return func1(result); } + else + { + return result.then(func1); + } + } - }; + // Set eof states for sync read + int_type check_sync_read_eof(int_type ch) + { + m_stream_read_eof = ch == traits::eof(); + return ch; + } +}; + +} // namespace details + +// Forward declarations +template +class basic_istream; +template +class basic_ostream; + +/// +/// Reference-counted stream buffer. +/// +/// +/// The data type of the basic element of the streambuf. +/// +/// +/// The data type of the basic element of the streambuf. +/// +template +class streambuf : public details::basic_streambuf<_CharType> +{ +public: + typedef typename details::basic_streambuf<_CharType>::traits traits; + typedef typename details::basic_streambuf<_CharType>::int_type int_type; + typedef typename details::basic_streambuf<_CharType>::pos_type pos_type; + typedef typename details::basic_streambuf<_CharType>::off_type off_type; + typedef typename details::basic_streambuf<_CharType>::char_type char_type; - } // namespace details + template + friend class streambuf; - // Forward declarations - template class basic_istream; - template class basic_ostream; + /// + /// Constructor. + /// + /// A pointer to the concrete stream buffer implementation. + streambuf(_In_ const std::shared_ptr>& ptr) : m_buffer(ptr) {} /// - /// Reference-counted stream buffer. + /// Default constructor. /// - /// - /// The data type of the basic element of the streambuf. - /// - /// - /// The data type of the basic element of the streambuf. + streambuf() {} + + /// + /// Converter Constructor. + /// + /// + /// The data type of the basic element of the source streambuf. /// - template - class streambuf : public details::basic_streambuf<_CharType> + /// The source buffer to be converted. + template + streambuf(const streambuf& other) + : m_buffer(std::static_pointer_cast>( + std::static_pointer_cast(other.m_buffer))) { - public: - typedef typename details::basic_streambuf<_CharType>::traits traits; - typedef typename details::basic_streambuf<_CharType>::int_type int_type; - typedef typename details::basic_streambuf<_CharType>::pos_type pos_type; - typedef typename details::basic_streambuf<_CharType>::off_type off_type; - typedef typename details::basic_streambuf<_CharType>::char_type char_type; - - template friend class streambuf; - - /// - /// Constructor. - /// - /// A pointer to the concrete stream buffer implementation. - streambuf(_In_ const std::shared_ptr> &ptr) : m_buffer(ptr) {} - - /// - /// Default constructor. - /// - streambuf() { } - - /// - /// Converter Constructor. - /// - /// - /// The data type of the basic element of the source streambuf. - /// - /// The source buffer to be converted. - template - streambuf(const streambuf &other) : - m_buffer(std::static_pointer_cast>(std::static_pointer_cast(other.m_buffer))) - { - static_assert(std::is_same::pos_type>::value - && std::is_same::off_type>::value - && std::is_integral<_CharType>::value && std::is_integral::value - && std::is_integral::value && std::is_integral::int_type>::value - && sizeof(_CharType) == sizeof(AlterCharType) - && sizeof(int_type) == sizeof(typename details::basic_streambuf::int_type), - "incompatible stream character types"); - } + static_assert(std::is_same::pos_type>::value && + std::is_same::off_type>::value && + std::is_integral<_CharType>::value && std::is_integral::value && + std::is_integral::value && + std::is_integral::int_type>::value && + sizeof(_CharType) == sizeof(AlterCharType) && + sizeof(int_type) == sizeof(typename details::basic_streambuf::int_type), + "incompatible stream character types"); + } - /// - /// Constructs an input stream head for this stream buffer. - /// - /// basic_istream. - concurrency::streams::basic_istream<_CharType> create_istream() const - { - if (!can_read()) throw std::runtime_error("stream buffer not set up for input of data"); - return concurrency::streams::basic_istream<_CharType>(*this); - } + /// + /// Constructs an input stream head for this stream buffer. + /// + /// basic_istream. + concurrency::streams::basic_istream<_CharType> create_istream() const + { + if (!can_read()) throw std::runtime_error("stream buffer not set up for input of data"); + return concurrency::streams::basic_istream<_CharType>(*this); + } + + /// + /// Constructs an output stream for this stream buffer. + /// + /// basic_ostream + concurrency::streams::basic_ostream<_CharType> create_ostream() const + { + if (!can_write()) throw std::runtime_error("stream buffer not set up for output of data"); + return concurrency::streams::basic_ostream<_CharType>(*this); + } + + /// + /// Checks if the stream buffer has been initialized or not. + /// + operator bool() const { return (bool)m_buffer; } - /// - /// Constructs an output stream for this stream buffer. - /// - /// basic_ostream - concurrency::streams::basic_ostream<_CharType> create_ostream() const + /// + /// Destructor + /// + virtual ~streambuf() {} + + const std::shared_ptr>& get_base() const + { + if (!m_buffer) { - if (!can_write()) throw std::runtime_error("stream buffer not set up for output of data"); - return concurrency::streams::basic_ostream<_CharType>(*this); + throw std::invalid_argument("Invalid streambuf object"); } - /// - /// Checks if the stream buffer has been initialized or not. - /// - operator bool() const { return (bool)m_buffer; } + return m_buffer; + } - /// - /// Destructor - /// - virtual ~streambuf() { } + /// + /// can_read is used to determine whether a stream buffer will support read operations (get). + /// + virtual bool can_read() const { return get_base()->can_read(); } - const std::shared_ptr> & get_base() const - { - if (!m_buffer) - { - throw std::invalid_argument("Invalid streambuf object"); - } + /// + /// can_write is used to determine whether a stream buffer will support write operations (put). + /// + virtual bool can_write() const { return get_base()->can_write(); } - return m_buffer; - } + /// + /// can_seek is used to determine whether a stream buffer supports seeking. + /// + /// True if seeking is supported, false otherwise. + virtual bool can_seek() const { return get_base()->can_seek(); } - /// - /// can_read is used to determine whether a stream buffer will support read operations (get). - /// - virtual bool can_read() const { return get_base()->can_read(); } - - /// - /// can_write is used to determine whether a stream buffer will support write operations (put). - /// - virtual bool can_write() const { return get_base()->can_write(); } - - /// - /// can_seek is used to determine whether a stream buffer supports seeking. - /// - /// True if seeking is supported, false otherwise. - virtual bool can_seek() const { return get_base()->can_seek(); } - - /// - /// has_size is used to determine whether a stream buffer supports size(). - /// - /// True if the size API is supported, false otherwise. - virtual bool has_size() const { return get_base()->has_size(); } - - /// - /// Gets the total number of characters in the stream buffer, if known. Calls to has_size will determine whether - /// the result of size can be relied on. - /// - /// The total number of characters in the stream buffer. - virtual utility::size64_t size() const { return get_base()->size(); } - - /// - /// Gets the stream buffer size, if one has been set. - /// - /// The direction of buffering (in or out) - /// The size of the internal buffer (for the given direction). - /// An implementation that does not support buffering will always return 0. - virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const { return get_base()->buffer_size(direction); } - - /// - /// Sets the stream buffer implementation to buffer or not buffer. - /// - /// The size to use for internal buffering, 0 if no buffering should be done. - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will silently ignore calls to this function and it will not have any effect on what is returned by subsequent calls to . - virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) { get_base()->set_buffer_size(size,direction); } - - /// - /// For any input stream, in_avail returns the number of characters that are immediately available - /// to be consumed without blocking. May be used in conjunction with to read data without - /// incurring the overhead of using tasks. - /// - /// Number of characters that are ready to read. - virtual size_t in_avail() const { return get_base()->in_avail(); } - - /// - /// Checks if the stream buffer is open. - /// - /// No separation is made between open for reading and open for writing. - /// True if the stream buffer is open for reading or writing, false otherwise. - virtual bool is_open() const { return get_base()->is_open(); } - - /// - /// is_eof is used to determine whether a read head has reached the end of the buffer. - /// - /// True if at the end of the buffer, false otherwise. - virtual bool is_eof() const { return get_base()->is_eof(); } - - /// - /// Closes the stream buffer, preventing further read or write operations. - /// - /// The I/O mode (in or out) to close for. - virtual pplx::task close(std::ios_base::openmode mode = (std::ios_base::in | std::ios_base::out)) - { - // We preserve the check here to workaround a Dev10 compiler crash - auto buffer = get_base(); - return buffer ? buffer->close(mode) : pplx::task_from_result(); - } + /// + /// has_size is used to determine whether a stream buffer supports size(). + /// + /// True if the size API is supported, false otherwise. + virtual bool has_size() const { return get_base()->has_size(); } - /// - /// Closes the stream buffer with an exception. - /// - /// The I/O mode (in or out) to close for. - /// Pointer to the exception. - virtual pplx::task close(std::ios_base::openmode mode, std::exception_ptr eptr) - { - // We preserve the check here to workaround a Dev10 compiler crash - auto buffer = get_base(); - return buffer ? buffer->close(mode, eptr) : pplx::task_from_result(); - } + /// + /// Gets the total number of characters in the stream buffer, if known. Calls to has_size will determine + /// whether the result of size can be relied on. + /// + /// The total number of characters in the stream buffer. + virtual utility::size64_t size() const { return get_base()->size(); } - /// - /// Writes a single character to the stream. - /// - /// The character to write - /// The value of the character. EOF if the write operation fails - virtual pplx::task putc(_CharType ch) - { - return get_base()->putc(ch); - } + /// + /// Gets the stream buffer size, if one has been set. + /// + /// The direction of buffering (in or out) + /// The size of the internal buffer (for the given direction). + /// An implementation that does not support buffering will always return 0. + virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const + { + return get_base()->buffer_size(direction); + } - /// - /// Allocates a contiguous memory block and returns it. - /// - /// The number of characters to allocate. - /// A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit. - virtual _CharType* alloc(size_t count) - { - return get_base()->alloc(count); - } + /// + /// Sets the stream buffer implementation to buffer or not buffer. + /// + /// The size to use for internal buffering, 0 if no buffering should be done. + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will silently ignore calls to this function and it + /// will not have any effect on what is returned by subsequent calls to . + virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) + { + get_base()->set_buffer_size(size, direction); + } - /// - /// Submits a block already allocated by the stream buffer. - /// - /// The number of characters to be committed. - virtual void commit(size_t count) - { - get_base()->commit(count); - } + /// + /// For any input stream, in_avail returns the number of characters that are immediately available + /// to be consumed without blocking. May be used in conjunction with to read data without + /// incurring the overhead of using tasks. + /// + /// Number of characters that are ready to read. + virtual size_t in_avail() const { return get_base()->in_avail(); } - /// - /// Gets a pointer to the next already allocated contiguous block of data. - /// - /// A reference to a pointer variable that will hold the address of the block on success. - /// The number of contiguous characters available at the address in 'ptr'. - /// true if the operation succeeded, false otherwise. - /// - /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that - /// there is no block to return immediately or that the stream buffer does not support the operation. - /// The stream buffer may not de-allocate the block until is called. - /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; - /// a subsequent read will not succeed. - /// - virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) - { - ptr = nullptr; - count = 0; - return get_base()->acquire(ptr, count); - } + /// + /// Checks if the stream buffer is open. + /// + /// No separation is made between open for reading and open for writing. + /// True if the stream buffer is open for reading or writing, false otherwise. + virtual bool is_open() const { return get_base()->is_open(); } - /// - /// Releases a block of data acquired using . This frees the stream buffer to de-allocate the - /// memory, if it so desires. Move the read position ahead by the count. - /// - /// A pointer to the block of data to be released. - /// The number of characters that were read. - virtual void release(_Out_writes_(count) _CharType *ptr, _In_ size_t count) - { - get_base()->release(ptr, count); - } + /// + /// is_eof is used to determine whether a read head has reached the end of the buffer. + /// + /// True if at the end of the buffer, false otherwise. + virtual bool is_eof() const { return get_base()->is_eof(); } - /// - /// Writes a number of characters to the stream. - /// - /// A pointer to the block of data to be written. - /// The number of characters to write. - /// The number of characters actually written, either 'count' or 0. - CASABLANCA_DEPRECATED("This API in some cases performs a copy. It is deprecated and will be removed in a future release. Use putn_nocopy instead.") - virtual pplx::task putn(const _CharType *ptr, size_t count) - { - return get_base()->putn(ptr, count); - } + /// + /// Closes the stream buffer, preventing further read or write operations. + /// + /// The I/O mode (in or out) to close for. + virtual pplx::task close(std::ios_base::openmode mode = (std::ios_base::in | std::ios_base::out)) + { + // We preserve the check here to workaround a Dev10 compiler crash + auto buffer = get_base(); + return buffer ? buffer->close(mode) : pplx::task_from_result(); + } - /// - /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until - /// the returned task completes. - /// - /// A pointer to the block of data to be written. - /// The number of characters to write. - /// The number of characters actually written, either 'count' or 0. - virtual pplx::task putn_nocopy(const _CharType *ptr, size_t count) - { - return get_base()->putn_nocopy(ptr, count); - } + /// + /// Closes the stream buffer with an exception. + /// + /// The I/O mode (in or out) to close for. + /// Pointer to the exception. + virtual pplx::task close(std::ios_base::openmode mode, std::exception_ptr eptr) + { + // We preserve the check here to workaround a Dev10 compiler crash + auto buffer = get_base(); + return buffer ? buffer->close(mode, eptr) : pplx::task_from_result(); + } - /// - /// Reads a single character from the stream and advances the read position. - /// - /// The value of the character. EOF if the read fails. - virtual pplx::task bumpc() - { - return get_base()->bumpc(); - } + /// + /// Writes a single character to the stream. + /// + /// The character to write + /// The value of the character. EOF if the write operation fails + virtual pplx::task putc(_CharType ch) { return get_base()->putc(ch); } - /// - /// Reads a single character from the stream and advances the read position. - /// - /// The value of the character. -1 if the read fails. -2 if an asynchronous read is required - /// This is a synchronous operation, but is guaranteed to never block. - virtual typename details::basic_streambuf<_CharType>::int_type sbumpc() - { - return get_base()->sbumpc(); - } + /// + /// Allocates a contiguous memory block and returns it. + /// + /// The number of characters to allocate. + /// A pointer to a block to write to, null if the stream buffer implementation does not support + /// alloc/commit. + virtual _CharType* alloc(size_t count) { return get_base()->alloc(count); } - /// - /// Reads a single character from the stream without advancing the read position. - /// - /// The value of the byte. EOF if the read fails. - virtual pplx::task getc() - { - return get_base()->getc(); - } + /// + /// Submits a block already allocated by the stream buffer. + /// + /// The number of characters to be committed. + virtual void commit(size_t count) { get_base()->commit(count); } - /// - /// Reads a single character from the stream without advancing the read position. - /// - /// The value of the character. EOF if the read fails. if an asynchronous read is required - /// This is a synchronous operation, but is guaranteed to never block. - virtual typename details::basic_streambuf<_CharType>::int_type sgetc() - { - return get_base()->sgetc(); - } + /// + /// Gets a pointer to the next already allocated contiguous block of data. + /// + /// A reference to a pointer variable that will hold the address of the block on success. + /// The number of contiguous characters available at the address in 'ptr'. + /// true if the operation succeeded, false otherwise. + /// + /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that + /// there is no block to return immediately or that the stream buffer does not support the operation. + /// The stream buffer may not de-allocate the block until is called. + /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; + /// a subsequent read will not succeed. + /// + virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) + { + ptr = nullptr; + count = 0; + return get_base()->acquire(ptr, count); + } - /// - /// Advances the read position, then returns the next character without advancing again. - /// - /// The value of the character. EOF if the read fails. - pplx::task nextc() - { - return get_base()->nextc(); - } + /// + /// Releases a block of data acquired using . This frees the stream buffer to + /// de-allocate the memory, if it so desires. Move the read position ahead by the count. + /// + /// A pointer to the block of data to be released. + /// The number of characters that were read. + virtual void release(_Out_writes_(count) _CharType* ptr, _In_ size_t count) { get_base()->release(ptr, count); } - /// - /// Retreats the read position, then returns the current character without advancing. - /// - /// The value of the character. EOF if the read fails. if an asynchronous read is required - pplx::task ungetc() - { - return get_base()->ungetc(); - } + /// + /// Writes a number of characters to the stream. + /// + /// A pointer to the block of data to be written. + /// The number of characters to write. + /// The number of characters actually written, either 'count' or 0. + CASABLANCA_DEPRECATED("This API in some cases performs a copy. It is deprecated and will be removed in a future " + "release. Use putn_nocopy instead.") + virtual pplx::task putn(const _CharType* ptr, size_t count) { return get_base()->putn(ptr, count); } - /// - /// Reads up to a given number of characters from the stream. - /// - /// The address of the target memory area. - /// The maximum number of characters to read. - /// The number of characters read. O if the end of the stream is reached. - virtual pplx::task getn(_Out_writes_(count) _CharType *ptr, _In_ size_t count) - { - return get_base()->getn(ptr, count); - } + /// + /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until + /// the returned task completes. + /// + /// A pointer to the block of data to be written. + /// The number of characters to write. + /// The number of characters actually written, either 'count' or 0. + virtual pplx::task putn_nocopy(const _CharType* ptr, size_t count) + { + return get_base()->putn_nocopy(ptr, count); + } - /// - /// Copies up to a given number of characters from the stream, synchronously. - /// - /// The address of the target memory area. - /// The maximum number of characters to read. - /// The number of characters copied. O if the end of the stream is reached or an asynchronous read is required. - /// This is a synchronous operation, but is guaranteed to never block. - virtual size_t scopy(_Out_writes_(count) _CharType *ptr, _In_ size_t count) - { - return get_base()->scopy(ptr, count); - } + /// + /// Reads a single character from the stream and advances the read position. + /// + /// The value of the character. EOF if the read fails. + virtual pplx::task bumpc() { return get_base()->bumpc(); } - /// - /// Gets the current read or write position in the stream. - /// - /// The I/O direction to seek (see remarks) - /// The current position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual typename details::basic_streambuf<_CharType>::pos_type getpos(std::ios_base::openmode direction) const - { - return get_base()->getpos(direction); - } + /// + /// Reads a single character from the stream and advances the read position. + /// + /// The value of the character. -1 if the read fails. -2 if an asynchronous read is + /// required This is a synchronous operation, but is guaranteed to never block. + virtual typename details::basic_streambuf<_CharType>::int_type sbumpc() { return get_base()->sbumpc(); } - /// - /// Seeks to the given position. - /// - /// The offset from the beginning of the stream. - /// The I/O direction to seek (see remarks). - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual typename details::basic_streambuf<_CharType>::pos_type seekpos(typename details::basic_streambuf<_CharType>::pos_type pos, std::ios_base::openmode direction) - { - return get_base()->seekpos(pos, direction); - } + /// + /// Reads a single character from the stream without advancing the read position. + /// + /// The value of the byte. EOF if the read fails. + virtual pplx::task getc() { return get_base()->getc(); } - /// - /// Seeks to a position given by a relative offset. - /// - /// The relative position to seek to - /// The starting point (beginning, end, current) for the seek. - /// The I/O direction to seek (see remarks) - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the mode parameter defines whether to move the read or the write cursor. - virtual typename details::basic_streambuf<_CharType>::pos_type seekoff(typename details::basic_streambuf<_CharType>::off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) - { - return get_base()->seekoff(offset, way, mode); - } + /// + /// Reads a single character from the stream without advancing the read position. + /// + /// The value of the character. EOF if the read fails. if an + /// asynchronous read is required This is a synchronous operation, but is guaranteed to never + /// block. + virtual typename details::basic_streambuf<_CharType>::int_type sgetc() { return get_base()->sgetc(); } - /// - /// For output streams, flush any internally buffered data to the underlying medium. - /// - /// true if the flush succeeds, false if not - virtual pplx::task sync() - { - return get_base()->sync(); - } + /// + /// Advances the read position, then returns the next character without advancing again. + /// + /// The value of the character. EOF if the read fails. + pplx::task nextc() { return get_base()->nextc(); } - /// - /// Retrieves the stream buffer exception_ptr if it has been set. - /// - /// Pointer to the exception, if it has been set; otherwise, nullptr will be returned - virtual std::exception_ptr exception() const - { - return get_base()->exception(); - } + /// + /// Retreats the read position, then returns the current character without advancing. + /// + /// The value of the character. EOF if the read fails. if an + /// asynchronous read is required + pplx::task ungetc() { return get_base()->ungetc(); } + + /// + /// Reads up to a given number of characters from the stream. + /// + /// The address of the target memory area. + /// The maximum number of characters to read. + /// The number of characters read. O if the end of the stream is reached. + virtual pplx::task getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + return get_base()->getn(ptr, count); + } - private: - std::shared_ptr> m_buffer; + /// + /// Copies up to a given number of characters from the stream, synchronously. + /// + /// The address of the target memory area. + /// The maximum number of characters to read. + /// The number of characters copied. O if the end of the stream is reached or an asynchronous read is + /// required. This is a synchronous operation, but is guaranteed to never block. + virtual size_t scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + return get_base()->scopy(ptr, count); + } + + /// + /// Gets the current read or write position in the stream. + /// + /// The I/O direction to seek (see remarks) + /// The current position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the direction parameter defines whether to move the read or the write + /// cursor. + virtual typename details::basic_streambuf<_CharType>::pos_type getpos(std::ios_base::openmode direction) const + { + return get_base()->getpos(direction); + } + + /// + /// Seeks to the given position. + /// + /// The offset from the beginning of the stream. + /// The I/O direction to seek (see remarks). + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. For such streams, the direction parameter + /// defines whether to move the read or the write cursor. + virtual typename details::basic_streambuf<_CharType>::pos_type seekpos( + typename details::basic_streambuf<_CharType>::pos_type pos, std::ios_base::openmode direction) + { + return get_base()->seekpos(pos, direction); + } + + /// + /// Seeks to a position given by a relative offset. + /// + /// The relative position to seek to + /// The starting point (beginning, end, current) for the seek. + /// The I/O direction to seek (see remarks) + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the mode parameter defines whether to move the read or the write cursor. + virtual typename details::basic_streambuf<_CharType>::pos_type seekoff( + typename details::basic_streambuf<_CharType>::off_type offset, + std::ios_base::seekdir way, + std::ios_base::openmode mode) + { + return get_base()->seekoff(offset, way, mode); + } + + /// + /// For output streams, flush any internally buffered data to the underlying medium. + /// + /// true if the flush succeeds, false if not + virtual pplx::task sync() { return get_base()->sync(); } + + /// + /// Retrieves the stream buffer exception_ptr if it has been set. + /// + /// Pointer to the exception, if it has been set; otherwise, nullptr will be returned + virtual std::exception_ptr exception() const { return get_base()->exception(); } - }; +private: + std::shared_ptr> m_buffer; +}; -}} +} // namespace streams +} // namespace Concurrency diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 58ce4fa19d..da1a62c159 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -1,28 +1,28 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Various common utilities. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Various common utilities. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once +#include "cpprest/details/basic_types.h" +#include "pplx/pplxtasks.h" #include #include +#include +#include #include #include #include #include -#include -#include -#include "pplx/pplxtasks.h" -#include "cpprest/details/basic_types.h" #ifndef _WIN32 #include @@ -37,445 +37,444 @@ /// Various utilities for string conversions and date and time manipulation. namespace utility { - // Left over from VS2010 support, remains to avoid breaking. typedef std::chrono::seconds seconds; /// Functions for converting to/from std::chrono::seconds to xml string. namespace timespan { - /// - /// Converts a timespan/interval in seconds to xml duration string as specified by - /// http://www.w3.org/TR/xmlschema-2/#duration - /// - _ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs); +/// +/// Converts a timespan/interval in seconds to xml duration string as specified by +/// http://www.w3.org/TR/xmlschema-2/#duration +/// +_ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs); - /// - /// Converts an xml duration to timespan/interval in seconds - /// http://www.w3.org/TR/xmlschema-2/#duration - /// - _ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t ×panString); -} +/// +/// Converts an xml duration to timespan/interval in seconds +/// http://www.w3.org/TR/xmlschema-2/#duration +/// +_ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t& timespanString); +} // namespace timespan /// Functions for Unicode string conversions. namespace conversions { - /// - /// Converts a UTF-16 string to a UTF-8 string. - /// - /// A two byte character UTF-16 string. - /// A single byte character UTF-8 string. - _ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string &w); +/// +/// Converts a UTF-16 string to a UTF-8 string. +/// +/// A two byte character UTF-16 string. +/// A single byte character UTF-8 string. +_ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string& w); - /// - /// Converts a UTF-8 string to a UTF-16 - /// - /// A single byte character UTF-8 string. - /// A two byte character UTF-16 string. - _ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string &s); +/// +/// Converts a UTF-8 string to a UTF-16 +/// +/// A single byte character UTF-8 string. +/// A two byte character UTF-16 string. +_ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string& s); - /// - /// Converts a ASCII (us-ascii) string to a UTF-16 string. - /// - /// A single byte character us-ascii string. - /// A two byte character UTF-16 string. - _ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string &s); +/// +/// Converts a ASCII (us-ascii) string to a UTF-16 string. +/// +/// A single byte character us-ascii string. +/// A two byte character UTF-16 string. +_ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string& s); - /// - /// Converts a Latin1 (iso-8859-1) string to a UTF-16 string. - /// - /// A single byte character UTF-8 string. - /// A two byte character UTF-16 string. - _ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string &s); +/// +/// Converts a Latin1 (iso-8859-1) string to a UTF-16 string. +/// +/// A single byte character UTF-8 string. +/// A two byte character UTF-16 string. +_ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string& s); - /// - /// Converts a Latin1 (iso-8859-1) string to a UTF-8 string. - /// - /// A single byte character UTF-8 string. - /// A single byte character UTF-8 string. - _ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string &s); +/// +/// Converts a Latin1 (iso-8859-1) string to a UTF-8 string. +/// +/// A single byte character UTF-8 string. +/// A single byte character UTF-8 string. +_ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string& s); - /// - /// Converts to a platform dependent Unicode string type. - /// - /// A single byte character UTF-8 string. - /// A platform dependent string type. +/// +/// Converts to a platform dependent Unicode string type. +/// +/// A single byte character UTF-8 string. +/// A platform dependent string type. #ifdef _UTF16_STRINGS - _ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string &&s); +_ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string&& s); #else - inline utility::string_t&& to_string_t(std::string &&s) { return std::move(s); } +inline utility::string_t&& to_string_t(std::string&& s) { return std::move(s); } #endif - /// - /// Converts to a platform dependent Unicode string type. - /// - /// A two byte character UTF-16 string. - /// A platform dependent string type. +/// +/// Converts to a platform dependent Unicode string type. +/// +/// A two byte character UTF-16 string. +/// A platform dependent string type. #ifdef _UTF16_STRINGS - inline utility::string_t&& to_string_t(utf16string &&s) { return std::move(s); } +inline utility::string_t&& to_string_t(utf16string&& s) { return std::move(s); } #else - _ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string &&s); +_ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string&& s); #endif - /// - /// Converts to a platform dependent Unicode string type. - /// - /// A single byte character UTF-8 string. - /// A platform dependent string type. +/// +/// Converts to a platform dependent Unicode string type. +/// +/// A single byte character UTF-8 string. +/// A platform dependent string type. #ifdef _UTF16_STRINGS - _ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string &s); +_ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string& s); #else - inline const utility::string_t& to_string_t(const std::string &s) { return s; } +inline const utility::string_t& to_string_t(const std::string& s) { return s; } #endif - /// - /// Converts to a platform dependent Unicode string type. - /// - /// A two byte character UTF-16 string. - /// A platform dependent string type. +/// +/// Converts to a platform dependent Unicode string type. +/// +/// A two byte character UTF-16 string. +/// A platform dependent string type. #ifdef _UTF16_STRINGS - inline const utility::string_t& to_string_t(const utf16string &s) { return s; } +inline const utility::string_t& to_string_t(const utf16string& s) { return s; } #else - _ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string &s); +_ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string& s); #endif - /// - /// Converts to a UTF-16 from string. - /// - /// A single byte character UTF-8 string. - /// A two byte character UTF-16 string. - _ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string &value); - - /// - /// Converts to a UTF-16 from string. - /// - /// A two byte character UTF-16 string. - /// A two byte character UTF-16 string. - inline const utf16string& to_utf16string(const utf16string& value) - { - return value; - } - /// - /// Converts to a UTF-16 from string. - /// - /// A two byte character UTF-16 string. - /// A two byte character UTF-16 string. - inline utf16string&& to_utf16string(utf16string&& value) - { - return std::move(value); - } +/// +/// Converts to a UTF-16 from string. +/// +/// A single byte character UTF-8 string. +/// A two byte character UTF-16 string. +_ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string& value); - /// - /// Converts to a UTF-8 string. - /// - /// A single byte character UTF-8 string. - /// A single byte character UTF-8 string. - inline std::string&& to_utf8string(std::string&& value) { return std::move(value); } +/// +/// Converts to a UTF-16 from string. +/// +/// A two byte character UTF-16 string. +/// A two byte character UTF-16 string. +inline const utf16string& to_utf16string(const utf16string& value) { return value; } +/// +/// Converts to a UTF-16 from string. +/// +/// A two byte character UTF-16 string. +/// A two byte character UTF-16 string. +inline utf16string&& to_utf16string(utf16string&& value) { return std::move(value); } - /// - /// Converts to a UTF-8 string. - /// - /// A single byte character UTF-8 string. - /// A single byte character UTF-8 string. - inline const std::string& to_utf8string(const std::string& value) { return value; } +/// +/// Converts to a UTF-8 string. +/// +/// A single byte character UTF-8 string. +/// A single byte character UTF-8 string. +inline std::string&& to_utf8string(std::string&& value) { return std::move(value); } - /// - /// Converts to a UTF-8 string. - /// - /// A two byte character UTF-16 string. - /// A single byte character UTF-8 string. - _ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string &value); +/// +/// Converts to a UTF-8 string. +/// +/// A single byte character UTF-8 string. +/// A single byte character UTF-8 string. +inline const std::string& to_utf8string(const std::string& value) { return value; } - /// - /// Encode the given byte array into a base64 string - /// - _ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector& data); +/// +/// Converts to a UTF-8 string. +/// +/// A two byte character UTF-16 string. +/// A single byte character UTF-8 string. +_ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string& value); - /// - /// Encode the given 8-byte integer into a base64 string - /// - _ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data); +/// +/// Encode the given byte array into a base64 string +/// +_ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector& data); - /// - /// Decode the given base64 string to a byte array - /// - _ASYNCRTIMP std::vector __cdecl from_base64(const utility::string_t& str); +/// +/// Encode the given 8-byte integer into a base64 string +/// +_ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data); - template - CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if locale support is required.") - utility::string_t print_string(const Source &val, const std::locale& loc = std::locale()) - { - utility::ostringstream_t oss; - oss.imbue(loc); - oss << val; - if (oss.bad()) - { - throw std::bad_cast(); - } - return oss.str(); - } +/// +/// Decode the given base64 string to a byte array +/// +_ASYNCRTIMP std::vector __cdecl from_base64(const utility::string_t& str); - CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if locale support is required.") - inline utility::string_t print_string(const utility::string_t &val) +template +CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " + "locale support is required.") +utility::string_t print_string(const Source& val, const std::locale& loc = std::locale()) +{ + utility::ostringstream_t oss; + oss.imbue(loc); + oss << val; + if (oss.bad()) { - return val; + throw std::bad_cast(); } + return oss.str(); +} - namespace details - { +CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " + "locale support is required.") +inline utility::string_t print_string(const utility::string_t& val) { return val; } +namespace details +{ #if defined(__ANDROID__) - template - inline std::string to_string(const T t) - { - std::ostringstream os; - os.imbue(std::locale::classic()); - os << t; - return os.str(); - } +template +inline std::string to_string(const T t) +{ + std::ostringstream os; + os.imbue(std::locale::classic()); + os << t; + return os.str(); +} #endif - template - inline utility::string_t to_string_t(const T t) - { +template +inline utility::string_t to_string_t(const T t) +{ #ifdef _UTF16_STRINGS - using std::to_wstring; - return to_wstring(t); + using std::to_wstring; + return to_wstring(t); #else #if !defined(__ANDROID__) - using std::to_string; + using std::to_string; #endif - return to_string(t); + return to_string(t); #endif - } - - template - utility::string_t print_string(const Source &val) - { - utility::ostringstream_t oss; - oss.imbue(std::locale::classic()); - oss << val; - if (oss.bad()) - { - throw std::bad_cast(); - } - return oss.str(); - } - - inline const utility::string_t& print_string(const utility::string_t &val) - { - return val; - } +} - template - utf8string print_utf8string(const Source& val) - { - return conversions::to_utf8string(print_string(val)); - } - inline const utf8string& print_utf8string(const utf8string& val) - { - return val; - } +template +utility::string_t print_string(const Source& val) +{ + utility::ostringstream_t oss; + oss.imbue(std::locale::classic()); + oss << val; + if (oss.bad()) + { + throw std::bad_cast(); + } + return oss.str(); +} - template - Target scan_string(const utility::string_t &str) - { - Target t; - utility::istringstream_t iss(str); - iss.imbue(std::locale::classic()); - iss >> t; - if (iss.bad()) - { - throw std::bad_cast(); - } - return t; - } +inline const utility::string_t& print_string(const utility::string_t& val) { return val; } - inline const utility::string_t& scan_string(const utility::string_t &str) - { - return str; - } - } +template +utf8string print_utf8string(const Source& val) +{ + return conversions::to_utf8string(print_string(val)); +} +inline const utf8string& print_utf8string(const utf8string& val) { return val; } - template - CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if locale support is required.") - Target scan_string(const utility::string_t &str, const std::locale &loc = std::locale()) +template +Target scan_string(const utility::string_t& str) +{ + Target t; + utility::istringstream_t iss(str); + iss.imbue(std::locale::classic()); + iss >> t; + if (iss.bad()) { - Target t; - utility::istringstream_t iss(str); - iss.imbue(loc); - iss >> t; - if (iss.bad()) - { - throw std::bad_cast(); - } - return t; + throw std::bad_cast(); } + return t; +} + +inline const utility::string_t& scan_string(const utility::string_t& str) { return str; } +} // namespace details - CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if locale support is required.") - inline utility::string_t scan_string(const utility::string_t &str) +template +CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " + "locale support is required.") +Target scan_string(const utility::string_t& str, const std::locale& loc = std::locale()) +{ + Target t; + utility::istringstream_t iss(str); + iss.imbue(loc); + iss >> t; + if (iss.bad()) { - return str; + throw std::bad_cast(); } + return t; } +CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if " + "locale support is required.") +inline utility::string_t scan_string(const utility::string_t& str) { return str; } +} // namespace conversions + namespace details { - /// - /// Cross platform RAII container for setting thread local locale. - /// - class scoped_c_thread_locale - { - public: - _ASYNCRTIMP scoped_c_thread_locale(); - _ASYNCRTIMP ~scoped_c_thread_locale(); +/// +/// Cross platform RAII container for setting thread local locale. +/// +class scoped_c_thread_locale +{ +public: + _ASYNCRTIMP scoped_c_thread_locale(); + _ASYNCRTIMP ~scoped_c_thread_locale(); #if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269 #ifdef _WIN32 - typedef _locale_t xplat_locale; + typedef _locale_t xplat_locale; #else - typedef locale_t xplat_locale; + typedef locale_t xplat_locale; #endif - static _ASYNCRTIMP xplat_locale __cdecl c_locale(); + static _ASYNCRTIMP xplat_locale __cdecl c_locale(); #endif - private: +private: #ifdef _WIN32 - std::string m_prevLocale; - int m_prevThreadSetting; + std::string m_prevLocale; + int m_prevThreadSetting; #elif !(defined(ANDROID) || defined(__ANDROID__)) - locale_t m_prevLocale; + locale_t m_prevLocale; #endif - scoped_c_thread_locale(const scoped_c_thread_locale &); - scoped_c_thread_locale & operator=(const scoped_c_thread_locale &); - }; + scoped_c_thread_locale(const scoped_c_thread_locale&); + scoped_c_thread_locale& operator=(const scoped_c_thread_locale&); +}; - /// - /// Our own implementation of alpha numeric instead of std::isalnum to avoid - /// taking global lock for performance reasons. - /// - inline bool __cdecl is_alnum(const unsigned char uch) CPPREST_NOEXCEPT - { // test if uch is an alnum character - // special casing char to avoid branches - static CPPREST_CONSTEXPR bool is_alnum_table[UCHAR_MAX + 1] = - { - /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */ - /* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0-9 */ - /* 4X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A-Z */ - /* 5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - /* 6X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a-z */ - /* 7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 - /* non-ASCII values initialized to 0 */ - }; - return (is_alnum_table[uch]); - } +/// +/// Our own implementation of alpha numeric instead of std::isalnum to avoid +/// taking global lock for performance reasons. +/// +inline bool __cdecl is_alnum(const unsigned char uch) CPPREST_NOEXCEPT +{ // test if uch is an alnum character + // special casing char to avoid branches + // clang-format off + static CPPREST_CONSTEXPR bool is_alnum_table[UCHAR_MAX + 1] = { + /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */ + /* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0-9 */ + /* 4X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A-Z */ + /* 5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + /* 6X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a-z */ + /* 7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 + /* non-ASCII values initialized to 0 */ + }; + // clang-format on + return (is_alnum_table[uch]); +} - /// - /// Our own implementation of alpha numeric instead of std::isalnum to avoid - /// taking global lock for performance reasons. - /// - inline bool __cdecl is_alnum(const char ch) CPPREST_NOEXCEPT - { - return (is_alnum(static_cast(ch))); - } +/// +/// Our own implementation of alpha numeric instead of std::isalnum to avoid +/// taking global lock for performance reasons. +/// +inline bool __cdecl is_alnum(const char ch) CPPREST_NOEXCEPT { return (is_alnum(static_cast(ch))); } - /// - /// Our own implementation of alpha numeric instead of std::isalnum to avoid - /// taking global lock for performance reasons. - /// - template - inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT - { - // assumes 'x' == L'x' for the ASCII range - typedef typename std::make_unsigned::type UElem; - const auto uch = static_cast(ch); - return (uch <= static_cast('z') && is_alnum(static_cast(uch))); - } +/// +/// Our own implementation of alpha numeric instead of std::isalnum to avoid +/// taking global lock for performance reasons. +/// +template +inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT +{ + // assumes 'x' == L'x' for the ASCII range + typedef typename std::make_unsigned::type UElem; + const auto uch = static_cast(ch); + return (uch <= static_cast('z') && is_alnum(static_cast(uch))); +} - /// - /// Simplistic implementation of make_unique. A better implementation would be based on variadic templates - /// and therefore not be compatible with Dev10. - /// - template - std::unique_ptr<_Type> make_unique() { - return std::unique_ptr<_Type>(new _Type()); - } +/// +/// Simplistic implementation of make_unique. A better implementation would be based on variadic templates +/// and therefore not be compatible with Dev10. +/// +template +std::unique_ptr<_Type> make_unique() +{ + return std::unique_ptr<_Type>(new _Type()); +} - template - std::unique_ptr<_Type> make_unique(_Arg1&& arg1) { - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1))); - } +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1) +{ + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1))); +} - template - std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2) { - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2))); - } +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2) +{ + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2))); +} - template - std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3) { - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3))); - } +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3) +{ + return std::unique_ptr<_Type>( + new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3))); +} - template - std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4) { - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4))); - } +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4) +{ + return std::unique_ptr<_Type>(new _Type( + std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4))); +} - template - std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5) { - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4), std::forward<_Arg5>(arg5))); - } +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5) +{ + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), + std::forward<_Arg2>(arg2), + std::forward<_Arg3>(arg3), + std::forward<_Arg4>(arg4), + std::forward<_Arg5>(arg5))); +} - template - std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5, _Arg6&& arg6) { - return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4), std::forward<_Arg5>(arg5), std::forward<_Arg6>(arg6))); - } +template +std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5, _Arg6&& arg6) +{ + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), + std::forward<_Arg2>(arg2), + std::forward<_Arg3>(arg3), + std::forward<_Arg4>(arg4), + std::forward<_Arg5>(arg5), + std::forward<_Arg6>(arg6))); +} - /// - /// Cross platform utility function for performing case insensitive string equality comparison. - /// - /// First string to compare. - /// Second strong to compare. - /// true if the strings are equivalent, false otherwise - _ASYNCRTIMP bool __cdecl str_iequal(const std::string &left, const std::string &right) CPPREST_NOEXCEPT; +/// +/// Cross platform utility function for performing case insensitive string equality comparison. +/// +/// First string to compare. +/// Second strong to compare. +/// true if the strings are equivalent, false otherwise +_ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& right) CPPREST_NOEXCEPT; - /// - /// Cross platform utility function for performing case insensitive string equality comparison. - /// - /// First string to compare. - /// Second strong to compare. - /// true if the strings are equivalent, false otherwise - _ASYNCRTIMP bool __cdecl str_iequal(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT; +/// +/// Cross platform utility function for performing case insensitive string equality comparison. +/// +/// First string to compare. +/// Second strong to compare. +/// true if the strings are equivalent, false otherwise +_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT; - /// - /// Cross platform utility function for performing case insensitive string less-than comparison. - /// - /// First string to compare. - /// Second strong to compare. - /// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, false. - _ASYNCRTIMP bool __cdecl str_iless(const std::string &left, const std::string &right) CPPREST_NOEXCEPT; +/// +/// Cross platform utility function for performing case insensitive string less-than comparison. +/// +/// First string to compare. +/// Second strong to compare. +/// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, +/// false. +_ASYNCRTIMP bool __cdecl str_iless(const std::string& left, const std::string& right) CPPREST_NOEXCEPT; - /// - /// Cross platform utility function for performing case insensitive string less-than comparison. - /// - /// First string to compare. - /// Second strong to compare. - /// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, false. - _ASYNCRTIMP bool __cdecl str_iless(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT; +/// +/// Cross platform utility function for performing case insensitive string less-than comparison. +/// +/// First string to compare. +/// Second strong to compare. +/// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, +/// false. +_ASYNCRTIMP bool __cdecl str_iless(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT; - /// - /// Convert a string to lowercase in place. - /// - /// The string to convert to lowercase. - _ASYNCRTIMP void __cdecl inplace_tolower(std::string &target) CPPREST_NOEXCEPT; +/// +/// Convert a string to lowercase in place. +/// +/// The string to convert to lowercase. +_ASYNCRTIMP void __cdecl inplace_tolower(std::string& target) CPPREST_NOEXCEPT; - /// - /// Convert a string to lowercase in place. - /// - /// The string to convert to lowercase. - _ASYNCRTIMP void __cdecl inplace_tolower(std::wstring &target) CPPREST_NOEXCEPT; +/// +/// Convert a string to lowercase in place. +/// +/// The string to convert to lowercase. +_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring& target) CPPREST_NOEXCEPT; #ifdef _WIN32 @@ -485,7 +484,7 @@ namespace details class windows_category_impl : public std::error_category { public: - virtual const char *name() const CPPREST_NOEXCEPT { return "windows"; } + virtual const char* name() const CPPREST_NOEXCEPT { return "windows"; } virtual std::string message(int errorCode) const CPPREST_NOEXCEPT; @@ -496,7 +495,7 @@ class windows_category_impl : public std::error_category /// Gets the one global instance of the windows error category. /// /// An error category instance. -_ASYNCRTIMP const std::error_category & __cdecl windows_category(); +_ASYNCRTIMP const std::error_category& __cdecl windows_category(); #else @@ -504,14 +503,14 @@ _ASYNCRTIMP const std::error_category & __cdecl windows_category(); /// Gets the one global instance of the linux error category. /// /// An error category instance. -_ASYNCRTIMP const std::error_category & __cdecl linux_category(); +_ASYNCRTIMP const std::error_category& __cdecl linux_category(); #endif /// /// Gets the one global instance of the current platform's error category. /// -_ASYNCRTIMP const std::error_category & __cdecl platform_category(); +_ASYNCRTIMP const std::error_category& __cdecl platform_category(); /// /// Creates an instance of std::system_error from a OS error code. @@ -538,7 +537,7 @@ inline utility::string_t __cdecl create_error_message(unsigned long errorCode) return utility::conversions::to_string_t(create_error_code(errorCode).message()); } -} +} // namespace details class datetime { @@ -548,7 +547,11 @@ class datetime /// /// Defines the supported date and time string formats. /// - enum date_format { RFC_1123, ISO_8601 }; + enum date_format + { + RFC_1123, + ISO_8601 + }; /// /// Returns the current UTC time. @@ -558,7 +561,10 @@ class datetime /// /// An invalid UTC timestamp value. /// - enum:interval_type { utc_timestamp_invalid = static_cast(-1) }; + enum : interval_type + { + utc_timestamp_invalid = static_cast(-1) + }; /// /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00. @@ -577,9 +583,7 @@ class datetime } } - datetime() : m_interval(0) - { - } + datetime() : m_interval(0) {} /// /// Creates datetime from a string representing time in UTC in RFC 1123 format. @@ -595,89 +599,54 @@ class datetime /// /// Returns the integral time value. /// - interval_type to_interval() const - { - return m_interval; - } + interval_type to_interval() const { return m_interval; } - datetime operator- (interval_type value) const - { - return datetime(m_interval - value); - } + datetime operator-(interval_type value) const { return datetime(m_interval - value); } - datetime operator+ (interval_type value) const - { - return datetime(m_interval + value); - } + datetime operator+(interval_type value) const { return datetime(m_interval + value); } - bool operator== (datetime dt) const - { - return m_interval == dt.m_interval; - } + bool operator==(datetime dt) const { return m_interval == dt.m_interval; } - bool operator!= (const datetime& dt) const - { - return !(*this == dt); - } + bool operator!=(const datetime& dt) const { return !(*this == dt); } - static interval_type from_milliseconds(unsigned int milliseconds) - { - return milliseconds*_msTicks; - } + static interval_type from_milliseconds(unsigned int milliseconds) { return milliseconds * _msTicks; } - static interval_type from_seconds(unsigned int seconds) - { - return seconds*_secondTicks; - } + static interval_type from_seconds(unsigned int seconds) { return seconds * _secondTicks; } - static interval_type from_minutes(unsigned int minutes) - { - return minutes*_minuteTicks; - } + static interval_type from_minutes(unsigned int minutes) { return minutes * _minuteTicks; } - static interval_type from_hours(unsigned int hours) - { - return hours*_hourTicks; - } + static interval_type from_hours(unsigned int hours) { return hours * _hourTicks; } - static interval_type from_days(unsigned int days) - { - return days*_dayTicks; - } + static interval_type from_days(unsigned int days) { return days * _dayTicks; } - bool is_initialized() const - { - return m_interval != 0; - } + bool is_initialized() const { return m_interval != 0; } private: - - friend int operator- (datetime t1, datetime t2); + friend int operator-(datetime t1, datetime t2); static const interval_type _msTicks = static_cast(10000); - static const interval_type _secondTicks = 1000*_msTicks; - static const interval_type _minuteTicks = 60*_secondTicks; - static const interval_type _hourTicks = 60*60*_secondTicks; - static const interval_type _dayTicks = 24*60*60*_secondTicks; - + static const interval_type _secondTicks = 1000 * _msTicks; + static const interval_type _minuteTicks = 60 * _secondTicks; + static const interval_type _hourTicks = 60 * 60 * _secondTicks; + static const interval_type _dayTicks = 24 * 60 * 60 * _secondTicks; #ifdef _WIN32 // void* to avoid pulling in windows.h - static _ASYNCRTIMP bool __cdecl system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, uint64_t seconds, datetime * pdt); + static _ASYNCRTIMP bool __cdecl system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, + uint64_t seconds, + datetime* pdt); #else - static datetime timeval_to_datetime(const timeval &time); + static datetime timeval_to_datetime(const timeval& time); #endif // Private constructor. Use static methods to create an instance. - datetime(interval_type interval) : m_interval(interval) - { - } + datetime(interval_type interval) : m_interval(interval) {} // Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns. interval_type m_interval; }; -inline int operator- (datetime t1, datetime t2) +inline int operator-(datetime t1, datetime t2) { auto diff = (t1.m_interval - t2.m_interval); @@ -693,20 +662,22 @@ inline int operator- (datetime t1, datetime t2) class nonce_generator { public: - /// /// Define default nonce length. /// - enum { default_length = 32 }; + enum + { + default_length = 32 + }; /// /// Nonce generator constructor. /// /// Length of the generated nonce string. - nonce_generator(int length=default_length) : - m_random(static_cast(utility::datetime::utc_timestamp())), - m_length(length) - {} + nonce_generator(int length = default_length) + : m_random(static_cast(utility::datetime::utc_timestamp())), m_length(length) + { + } /// /// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9). @@ -733,4 +704,4 @@ class nonce_generator int m_length; }; -} // namespace utility; +} // namespace utility diff --git a/Release/include/cpprest/base_uri.h b/Release/include/cpprest/base_uri.h index fd82a3985e..7c6943119c 100644 --- a/Release/include/cpprest/base_uri.h +++ b/Release/include/cpprest/base_uri.h @@ -1,423 +1,391 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Protocol independent support for URIs. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Protocol independent support for URIs. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once +#include "cpprest/asyncrt_utils.h" +#include "cpprest/details/basic_types.h" #include #include -#include #include +#include -#include "cpprest/asyncrt_utils.h" -#include "cpprest/details/basic_types.h" +namespace web +{ +namespace details +{ +struct uri_components +{ + uri_components() : m_path(_XPLATSTR("/")), m_port(-1) {} + + uri_components(const uri_components&) = default; + uri_components& operator=(const uri_components&) = default; + + // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. + uri_components(uri_components&& other) CPPREST_NOEXCEPT : m_scheme(std::move(other.m_scheme)), + m_host(std::move(other.m_host)), + m_user_info(std::move(other.m_user_info)), + m_path(std::move(other.m_path)), + m_query(std::move(other.m_query)), + m_fragment(std::move(other.m_fragment)), + m_port(other.m_port) + { + } -namespace web { - namespace details + // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. + uri_components& operator=(uri_components&& other) CPPREST_NOEXCEPT { - struct uri_components + if (this != &other) { - uri_components() : m_path(_XPLATSTR("/")), m_port(-1) {} - - uri_components(const uri_components &) = default; - uri_components & operator=(const uri_components &) = default; - - // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. - uri_components(uri_components &&other) CPPREST_NOEXCEPT : - m_scheme(std::move(other.m_scheme)), - m_host(std::move(other.m_host)), - m_user_info(std::move(other.m_user_info)), - m_path(std::move(other.m_path)), - m_query(std::move(other.m_query)), - m_fragment(std::move(other.m_fragment)), - m_port(other.m_port) - {} - - // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. - uri_components & operator=(uri_components &&other) CPPREST_NOEXCEPT - { - if (this != &other) - { - m_scheme = std::move(other.m_scheme); - m_host = std::move(other.m_host); - m_user_info = std::move(other.m_user_info); - m_path = std::move(other.m_path); - m_query = std::move(other.m_query); - m_fragment = std::move(other.m_fragment); - m_port = other.m_port; - } - return *this; - } - - _ASYNCRTIMP utility::string_t join(); - - utility::string_t m_scheme; - utility::string_t m_host; - utility::string_t m_user_info; - utility::string_t m_path; - utility::string_t m_query; - utility::string_t m_fragment; - int m_port; - }; + m_scheme = std::move(other.m_scheme); + m_host = std::move(other.m_host); + m_user_info = std::move(other.m_user_info); + m_path = std::move(other.m_path); + m_query = std::move(other.m_query); + m_fragment = std::move(other.m_fragment); + m_port = other.m_port; + } + return *this; } + _ASYNCRTIMP utility::string_t join(); + + utility::string_t m_scheme; + utility::string_t m_host; + utility::string_t m_user_info; + utility::string_t m_path; + utility::string_t m_query; + utility::string_t m_fragment; + int m_port; +}; +} // namespace details + +/// +/// A single exception type to represent errors in parsing, encoding, and decoding URIs. +/// +class uri_exception : public std::exception +{ +public: + uri_exception(std::string msg) : m_msg(std::move(msg)) {} + + ~uri_exception() CPPREST_NOEXCEPT {} + + const char* what() const CPPREST_NOEXCEPT { return m_msg.c_str(); } + +private: + std::string m_msg; +}; + +/// +/// A flexible, protocol independent URI implementation. +/// +/// URI instances are immutable. Querying the various fields on an empty URI will return empty strings. Querying +/// various diagnostic members on an empty URI will return false. +/// +/// +/// This implementation accepts both URIs ('http://msn.com/path') and URI relative-references +/// ('/path?query#frag'). +/// +/// This implementation does not provide any scheme-specific handling -- an example of this +/// would be the following: 'http://path1/path'. This is a valid URI, but it's not a valid +/// http-uri -- that is, it's syntactically correct but does not conform to the requirements +/// of the http scheme (http requires a host). +/// We could provide this by allowing a pluggable 'scheme' policy-class, which would provide +/// extra capability for validating and canonicalizing a URI according to scheme, and would +/// introduce a layer of type-safety for URIs of differing schemes, and thus differing semantics. +/// +/// One issue with implementing a scheme-independent URI facility is that of comparing for equality. +/// For instance, these URIs are considered equal 'http://msn.com', 'http://msn.com:80'. That is -- +/// the 'default' port can be either omitted or explicit. Since we don't have a way to map a scheme +/// to it's default port, we don't have a way to know these are equal. This is just one of a class of +/// issues with regard to scheme-specific behavior. +/// +class uri +{ +public: /// - /// A single exception type to represent errors in parsing, encoding, and decoding URIs. + /// The various components of a URI. This enum is used to indicate which + /// URI component is being encoded to the encode_uri_component. This allows + /// specific encoding to be performed. + /// + /// Scheme and port don't allow '%' so they don't need to be encoded. /// - class uri_exception : public std::exception + class components { public: + enum component + { + user_info, + host, + path, + query, + fragment, + full_uri + }; + }; + + /// + /// Encodes a URI component according to RFC 3986. + /// Note if a full URI is specified instead of an individual URI component all + /// characters not in the unreserved set are escaped. + /// + /// The URI as a string. + /// The encoded string. + _ASYNCRTIMP static utility::string_t __cdecl encode_uri(const utility::string_t& raw, + uri::components::component = components::full_uri); - uri_exception(std::string msg) : m_msg(std::move(msg)) {} + /// + /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their + /// hexadecimal representation. + /// + /// The encoded string. + _ASYNCRTIMP static utility::string_t __cdecl encode_data_string(const utility::string_t& data); - ~uri_exception() CPPREST_NOEXCEPT {} + /// + /// Decodes an encoded string. + /// + /// The URI as a string. + /// The decoded string. + _ASYNCRTIMP static utility::string_t __cdecl decode(const utility::string_t& encoded); - const char* what() const CPPREST_NOEXCEPT - { - return m_msg.c_str(); - } + /// + /// Splits a path into its hierarchical components. + /// + /// The path as a string + /// A std::vector<utility::string_t> containing the segments in the path. + _ASYNCRTIMP static std::vector __cdecl split_path(const utility::string_t& path); - private: - std::string m_msg; - }; + /// + /// Splits a query into its key-value components. + /// + /// The query string + /// A std::map<utility::string_t, utility::string_t> containing the key-value components of + /// the query. + _ASYNCRTIMP static std::map __cdecl split_query( + const utility::string_t& query); /// - /// A flexible, protocol independent URI implementation. - /// - /// URI instances are immutable. Querying the various fields on an empty URI will return empty strings. Querying - /// various diagnostic members on an empty URI will return false. + /// Validates a string as a URI. /// /// - /// This implementation accepts both URIs ('http://msn.com/path') and URI relative-references - /// ('/path?query#frag'). - /// - /// This implementation does not provide any scheme-specific handling -- an example of this - /// would be the following: 'http://path1/path'. This is a valid URI, but it's not a valid - /// http-uri -- that is, it's syntactically correct but does not conform to the requirements - /// of the http scheme (http requires a host). - /// We could provide this by allowing a pluggable 'scheme' policy-class, which would provide - /// extra capability for validating and canonicalizing a URI according to scheme, and would - /// introduce a layer of type-safety for URIs of differing schemes, and thus differing semantics. - /// - /// One issue with implementing a scheme-independent URI facility is that of comparing for equality. - /// For instance, these URIs are considered equal 'http://msn.com', 'http://msn.com:80'. That is -- - /// the 'default' port can be either omitted or explicit. Since we don't have a way to map a scheme - /// to it's default port, we don't have a way to know these are equal. This is just one of a class of - /// issues with regard to scheme-specific behavior. + /// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query'). /// - class uri - { - public: + /// The URI string to be validated. + /// true if the given string represents a valid URI, false otherwise. + _ASYNCRTIMP static bool __cdecl validate(const utility::string_t& uri_string); - /// - /// The various components of a URI. This enum is used to indicate which - /// URI component is being encoded to the encode_uri_component. This allows - /// specific encoding to be performed. - /// - /// Scheme and port don't allow '%' so they don't need to be encoded. - /// - class components - { - public: - enum component - { - user_info, - host, - path, - query, - fragment, - full_uri - }; - }; + /// + /// Creates an empty uri + /// + uri() : m_uri(_XPLATSTR("/")) {} - /// - /// Encodes a URI component according to RFC 3986. - /// Note if a full URI is specified instead of an individual URI component all - /// characters not in the unreserved set are escaped. - /// - /// The URI as a string. - /// The encoded string. - _ASYNCRTIMP static utility::string_t __cdecl encode_uri(const utility::string_t &raw, uri::components::component = components::full_uri); - - /// - /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their - /// hexadecimal representation. - /// - /// The encoded string. - _ASYNCRTIMP static utility::string_t __cdecl encode_data_string(const utility::string_t &data); - - /// - /// Decodes an encoded string. - /// - /// The URI as a string. - /// The decoded string. - _ASYNCRTIMP static utility::string_t __cdecl decode(const utility::string_t &encoded); - - /// - /// Splits a path into its hierarchical components. - /// - /// The path as a string - /// A std::vector<utility::string_t> containing the segments in the path. - _ASYNCRTIMP static std::vector __cdecl split_path(const utility::string_t &path); - - /// - /// Splits a query into its key-value components. - /// - /// The query string - /// A std::map<utility::string_t, utility::string_t> containing the key-value components of the query. - _ASYNCRTIMP static std::map __cdecl split_query(const utility::string_t &query); - - /// - /// Validates a string as a URI. - /// - /// - /// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query'). - /// - /// The URI string to be validated. - /// true if the given string represents a valid URI, false otherwise. - _ASYNCRTIMP static bool __cdecl validate(const utility::string_t &uri_string); - - /// - /// Creates an empty uri - /// - uri() : m_uri(_XPLATSTR("/")) {} - - /// - /// Creates a URI from the given encoded string. This will throw an exception if the string - /// does not contain a valid URI. Use uri::validate if processing user-input. - /// - /// A pointer to an encoded string to create the URI instance. - _ASYNCRTIMP uri(const utility::char_t *uri_string); - - /// - /// Creates a URI from the given encoded string. This will throw an exception if the string - /// does not contain a valid URI. Use uri::validate if processing user-input. - /// - /// An encoded URI string to create the URI instance. - _ASYNCRTIMP uri(const utility::string_t &uri_string); - - /// - /// Copy constructor. - /// - uri(const uri &) = default; - - /// - /// Copy assignment operator. - /// - uri & operator=(const uri &) = default; - - /// - /// Move constructor. - /// - // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. - uri(uri &&other) CPPREST_NOEXCEPT : - m_uri(std::move(other.m_uri)), - m_components(std::move(other.m_components)) - {} - - /// - /// Move assignment operator - /// - // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. - uri & operator=(uri &&other) CPPREST_NOEXCEPT - { - if (this != &other) - { - m_uri = std::move(other.m_uri); - m_components = std::move(other.m_components); - } - return *this; - } + /// + /// Creates a URI from the given encoded string. This will throw an exception if the string + /// does not contain a valid URI. Use uri::validate if processing user-input. + /// + /// A pointer to an encoded string to create the URI instance. + _ASYNCRTIMP uri(const utility::char_t* uri_string); - /// - /// Get the scheme component of the URI as an encoded string. - /// - /// The URI scheme as a string. - const utility::string_t &scheme() const { return m_components.m_scheme; } - - /// - /// Get the user information component of the URI as an encoded string. - /// - /// The URI user information as a string. - const utility::string_t &user_info() const { return m_components.m_user_info; } - - /// - /// Get the host component of the URI as an encoded string. - /// - /// The URI host as a string. - const utility::string_t &host() const { return m_components.m_host; } - - /// - /// Get the port component of the URI. Returns -1 if no port is specified. - /// - /// The URI port as an integer. - int port() const { return m_components.m_port; } - - /// - /// Get the path component of the URI as an encoded string. - /// - /// The URI path as a string. - const utility::string_t &path() const { return m_components.m_path; } - - /// - /// Get the query component of the URI as an encoded string. - /// - /// The URI query as a string. - const utility::string_t &query() const { return m_components.m_query; } - - /// - /// Get the fragment component of the URI as an encoded string. - /// - /// The URI fragment as a string. - const utility::string_t &fragment() const { return m_components.m_fragment; } - - /// - /// Creates a new uri object with the same authority portion as this one, omitting the resource and query portions. - /// - /// The new uri object with the same authority. - _ASYNCRTIMP uri authority() const; - - /// - /// Gets the path, query, and fragment portion of this uri, which may be empty. - /// - /// The new URI object with the path, query and fragment portion of this URI. - _ASYNCRTIMP uri resource() const; - - /// - /// An empty URI specifies no components, and serves as a default value - /// - bool is_empty() const - { - return this->m_uri.empty() || this->m_uri == _XPLATSTR("/"); - } + /// + /// Creates a URI from the given encoded string. This will throw an exception if the string + /// does not contain a valid URI. Use uri::validate if processing user-input. + /// + /// An encoded URI string to create the URI instance. + _ASYNCRTIMP uri(const utility::string_t& uri_string); - /// - /// A loopback URI is one which refers to a hostname or ip address with meaning only on the local machine. - /// - /// - /// Examples include "localhost", or ip addresses in the loopback range (127.0.0.0/24). - /// - /// true if this URI references the local host, false otherwise. - bool is_host_loopback() const - { - return !is_empty() && ((host() == _XPLATSTR("localhost")) || (host().size() > 4 && host().substr(0,4) == _XPLATSTR("127."))); - } + /// + /// Copy constructor. + /// + uri(const uri&) = default; - /// - /// A wildcard URI is one which refers to all hostnames that resolve to the local machine (using the * or +) - /// - /// - /// http://*:80 - /// - bool is_host_wildcard() const - { - return !is_empty() && (this->host() == _XPLATSTR("*") || this->host() == _XPLATSTR("+")); - } + /// + /// Copy assignment operator. + /// + uri& operator=(const uri&) = default; - /// - /// A portable URI is one with a hostname that can be resolved globally (used from another machine). - /// - /// true if this URI can be resolved globally (used from another machine), false otherwise. - /// - /// The hostname "localhost" is a reserved name that is guaranteed to resolve to the local machine, - /// and cannot be used for inter-machine communication. Likewise the hostnames "*" and "+" on Windows - /// represent wildcards, and do not map to a resolvable address. - /// - bool is_host_portable() const - { - return !(is_empty() || is_host_loopback() || is_host_wildcard()); - } + /// + /// Move constructor. + /// + // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. + uri(uri&& other) CPPREST_NOEXCEPT : m_uri(std::move(other.m_uri)), m_components(std::move(other.m_components)) {} - /// - /// A default port is one where the port is unspecified, and will be determined by the operating system. - /// The choice of default port may be dictated by the scheme (http -> 80) or not. - /// - /// true if this URI instance has a default port, false otherwise. - bool is_port_default() const + /// + /// Move assignment operator + /// + // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. + uri& operator=(uri&& other) CPPREST_NOEXCEPT + { + if (this != &other) { - return !is_empty() && this->port() == 0; + m_uri = std::move(other.m_uri); + m_components = std::move(other.m_components); } + return *this; + } - /// - /// An "authority" URI is one with only a scheme, optional userinfo, hostname, and (optional) port. - /// - /// true if this is an "authority" URI, false otherwise. - bool is_authority() const - { - return !is_empty() && is_path_empty() && query().empty() && fragment().empty(); - } + /// + /// Get the scheme component of the URI as an encoded string. + /// + /// The URI scheme as a string. + const utility::string_t& scheme() const { return m_components.m_scheme; } - /// - /// Returns whether the other URI has the same authority as this one - /// - /// The URI to compare the authority with. - /// true if both the URI's have the same authority, false otherwise. - bool has_same_authority(const uri &other) const - { - return !is_empty() && this->authority() == other.authority(); - } + /// + /// Get the user information component of the URI as an encoded string. + /// + /// The URI user information as a string. + const utility::string_t& user_info() const { return m_components.m_user_info; } - /// - /// Returns whether the path portion of this URI is empty - /// - /// true if the path portion of this URI is empty, false otherwise. - bool is_path_empty() const - { - return path().empty() || path() == _XPLATSTR("/"); - } + /// + /// Get the host component of the URI as an encoded string. + /// + /// The URI host as a string. + const utility::string_t& host() const { return m_components.m_host; } - /// - /// Returns the full (encoded) URI as a string. - /// - /// The full encoded URI string. - utility::string_t to_string() const - { - return m_uri; - } + /// + /// Get the port component of the URI. Returns -1 if no port is specified. + /// + /// The URI port as an integer. + int port() const { return m_components.m_port; } - /// - /// Returns an URI resolved against this as the base URI - /// according to RFC3986, Section 5 (https://tools.ietf.org/html/rfc3986#section-5). - /// - /// The relative URI to be resolved against this as base. - /// The new resolved URI string. - _ASYNCRTIMP utility::string_t resolve_uri(const utility::string_t &relativeUri) const; + /// + /// Get the path component of the URI as an encoded string. + /// + /// The URI path as a string. + const utility::string_t& path() const { return m_components.m_path; } - _ASYNCRTIMP bool operator == (const uri &other) const; + /// + /// Get the query component of the URI as an encoded string. + /// + /// The URI query as a string. + const utility::string_t& query() const { return m_components.m_query; } - bool operator < (const uri &other) const - { - return m_uri < other.m_uri; - } + /// + /// Get the fragment component of the URI as an encoded string. + /// + /// The URI fragment as a string. + const utility::string_t& fragment() const { return m_components.m_fragment; } - bool operator != (const uri &other) const - { - return !(this->operator == (other)); - } + /// + /// Creates a new uri object with the same authority portion as this one, omitting the resource and query portions. + /// + /// The new uri object with the same authority. + _ASYNCRTIMP uri authority() const; - private: - friend class uri_builder; + /// + /// Gets the path, query, and fragment portion of this uri, which may be empty. + /// + /// The new URI object with the path, query and fragment portion of this URI. + _ASYNCRTIMP uri resource() const; - /// - /// Creates a URI from the given URI components. - /// - /// A URI components object to create the URI instance. - _ASYNCRTIMP uri(const details::uri_components &components); + /// + /// An empty URI specifies no components, and serves as a default value + /// + bool is_empty() const { return this->m_uri.empty() || this->m_uri == _XPLATSTR("/"); } - // Used by uri_builder - static utility::string_t __cdecl encode_query_impl(const utf8string& raw); + /// + /// A loopback URI is one which refers to a hostname or ip address with meaning only on the local machine. + /// + /// + /// Examples include "localhost", or ip addresses in the loopback range (127.0.0.0/24). + /// + /// true if this URI references the local host, false otherwise. + bool is_host_loopback() const + { + return !is_empty() && + ((host() == _XPLATSTR("localhost")) || (host().size() > 4 && host().substr(0, 4) == _XPLATSTR("127."))); + } - utility::string_t m_uri; - details::uri_components m_components; - }; + /// + /// A wildcard URI is one which refers to all hostnames that resolve to the local machine (using the * or +) + /// + /// + /// http://*:80 + /// + bool is_host_wildcard() const + { + return !is_empty() && (this->host() == _XPLATSTR("*") || this->host() == _XPLATSTR("+")); + } + + /// + /// A portable URI is one with a hostname that can be resolved globally (used from another machine). + /// + /// true if this URI can be resolved globally (used from another machine), false + /// otherwise. The hostname "localhost" is a reserved name that is guaranteed to resolve to the + /// local machine, and cannot be used for inter-machine communication. Likewise the hostnames "*" and "+" on Windows + /// represent wildcards, and do not map to a resolvable address. + /// + bool is_host_portable() const { return !(is_empty() || is_host_loopback() || is_host_wildcard()); } + + /// + /// A default port is one where the port is unspecified, and will be determined by the operating system. + /// The choice of default port may be dictated by the scheme (http -> 80) or not. + /// + /// true if this URI instance has a default port, false otherwise. + bool is_port_default() const { return !is_empty() && this->port() == 0; } + + /// + /// An "authority" URI is one with only a scheme, optional userinfo, hostname, and (optional) port. + /// + /// true if this is an "authority" URI, false otherwise. + bool is_authority() const { return !is_empty() && is_path_empty() && query().empty() && fragment().empty(); } + + /// + /// Returns whether the other URI has the same authority as this one + /// + /// The URI to compare the authority with. + /// true if both the URI's have the same authority, false otherwise. + bool has_same_authority(const uri& other) const { return !is_empty() && this->authority() == other.authority(); } + + /// + /// Returns whether the path portion of this URI is empty + /// + /// true if the path portion of this URI is empty, false otherwise. + bool is_path_empty() const { return path().empty() || path() == _XPLATSTR("/"); } + + /// + /// Returns the full (encoded) URI as a string. + /// + /// The full encoded URI string. + utility::string_t to_string() const { return m_uri; } + + /// + /// Returns an URI resolved against this as the base URI + /// according to RFC3986, Section 5 (https://tools.ietf.org/html/rfc3986#section-5). + /// + /// The relative URI to be resolved against this as base. + /// The new resolved URI string. + _ASYNCRTIMP utility::string_t resolve_uri(const utility::string_t& relativeUri) const; + + _ASYNCRTIMP bool operator==(const uri& other) const; + + bool operator<(const uri& other) const { return m_uri < other.m_uri; } + + bool operator!=(const uri& other) const { return !(this->operator==(other)); } + +private: + friend class uri_builder; + + /// + /// Creates a URI from the given URI components. + /// + /// A URI components object to create the URI instance. + _ASYNCRTIMP uri(const details::uri_components& components); + + // Used by uri_builder + static utility::string_t __cdecl encode_query_impl(const utf8string& raw); + + utility::string_t m_uri; + details::uri_components m_components; +}; } // namespace web diff --git a/Release/include/cpprest/containerstream.h b/Release/include/cpprest/containerstream.h index 71b2da843a..7f670d62c4 100644 --- a/Release/include/cpprest/containerstream.h +++ b/Release/include/cpprest/containerstream.h @@ -1,620 +1,590 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* This file defines a basic STL-container-based stream buffer. Reading from the buffer will not remove any data -* from it and seeking is thus supported. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * This file defines a basic STL-container-based stream buffer. Reading from the buffer will not remove any data + * from it and seeking is thus supported. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include -#include -#include -#include - -#include "pplx/pplxtasks.h" #include "cpprest/astreambuf.h" #include "cpprest/streams.h" +#include "pplx/pplxtasks.h" +#include +#include +#include +#include -namespace Concurrency { namespace streams { +namespace Concurrency +{ +namespace streams +{ +// Forward declarations + +template +class container_buffer; + +namespace details +{ +/// +/// The basic_container_buffer class serves as a memory-based steam buffer that supports writing or reading +/// sequences of characters. +/// The class itself should not be used in application code, it is used by the stream definitions farther down in the +/// header file. +/// +/// When closed, neither writing nor reading is supported any longer. basic_container_buffer does not +/// support simultaneous use of the buffer for reading and writing. +template +class basic_container_buffer : public streams::details::streambuf_state_manager +{ +public: + typedef typename _CollectionType::value_type _CharType; + typedef typename basic_streambuf<_CharType>::traits traits; + typedef typename basic_streambuf<_CharType>::int_type int_type; + typedef typename basic_streambuf<_CharType>::pos_type pos_type; + typedef typename basic_streambuf<_CharType>::off_type off_type; - // Forward declarations + /// + /// Returns the underlying data container + /// + _CollectionType& collection() { return m_data; } - template class container_buffer; + /// + /// Destructor + /// + virtual ~basic_container_buffer() + { + // Invoke the synchronous versions since we need to + // purge the request queue before deleting the buffer + this->_close_read(); + this->_close_write(); + } - namespace details { +protected: + /// + /// can_seek is used to determine whether a stream buffer supports seeking. + /// + virtual bool can_seek() const { return this->is_open(); } /// - /// The basic_container_buffer class serves as a memory-based steam buffer that supports writing or reading - /// sequences of characters. - /// The class itself should not be used in application code, it is used by the stream definitions farther down in the header file. + /// has_size is used to determine whether a stream buffer supports size(). /// - /// When closed, neither writing nor reading is supported any longer. basic_container_buffer does not support simultaneous use of the buffer - /// for reading and writing. - template - class basic_container_buffer : public streams::details::streambuf_state_manager - { - public: - typedef typename _CollectionType::value_type _CharType; - typedef typename basic_streambuf<_CharType>::traits traits; - typedef typename basic_streambuf<_CharType>::int_type int_type; - typedef typename basic_streambuf<_CharType>::pos_type pos_type; - typedef typename basic_streambuf<_CharType>::off_type off_type; - - /// - /// Returns the underlying data container - /// - _CollectionType& collection() - { - return m_data; - } + virtual bool has_size() const { return this->is_open(); } - /// - /// Destructor - /// - virtual ~basic_container_buffer() - { - // Invoke the synchronous versions since we need to - // purge the request queue before deleting the buffer - this->_close_read(); - this->_close_write(); - } + /// + /// Gets the size of the stream, if known. Calls to has_size will determine whether + /// the result of size can be relied on. + /// + virtual utility::size64_t size() const { return utility::size64_t(m_data.size()); } + /// + /// Get the stream buffer size, if one has been set. + /// + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will always return '0'. + virtual size_t buffer_size(std::ios_base::openmode = std::ios_base::in) const { return 0; } - protected: - /// - /// can_seek is used to determine whether a stream buffer supports seeking. - /// - virtual bool can_seek() const { return this->is_open(); } + /// + /// Sets the stream buffer implementation to buffer or not buffer. + /// + /// The size to use for internal buffering, 0 if no buffering should be done. + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will silently ignore calls to this function and it + /// will not have any effect on what is returned by subsequent calls to . + virtual void set_buffer_size(size_t, std::ios_base::openmode = std::ios_base::in) { return; } - /// - /// has_size is used to determine whether a stream buffer supports size(). - /// - virtual bool has_size() const { return this->is_open(); } + /// + /// For any input stream, in_avail returns the number of characters that are immediately available + /// to be consumed without blocking. May be used in conjunction with to read data without + /// incurring the overhead of using tasks. + /// + virtual size_t in_avail() const + { + // See the comment in seek around the restriction that we do not allow read head to + // seek beyond the current write_end. + _ASSERTE(m_current_position <= m_data.size()); - /// - /// Gets the size of the stream, if known. Calls to has_size will determine whether - /// the result of size can be relied on. - /// - virtual utility::size64_t size() const - { - return utility::size64_t(m_data.size()); - } + msl::safeint3::SafeInt readhead(m_current_position); + msl::safeint3::SafeInt writeend(m_data.size()); + return (size_t)(writeend - readhead); + } - /// - /// Get the stream buffer size, if one has been set. - /// - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will always return '0'. - virtual size_t buffer_size(std::ios_base::openmode = std::ios_base::in) const - { - return 0; - } + virtual pplx::task _sync() { return pplx::task_from_result(true); } - /// - /// Sets the stream buffer implementation to buffer or not buffer. - /// - /// The size to use for internal buffering, 0 if no buffering should be done. - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will silently ignore calls to this function and it will not have any effect on what is returned by subsequent calls to . - virtual void set_buffer_size(size_t , std::ios_base::openmode = std::ios_base::in) - { - return; - } + virtual pplx::task _putc(_CharType ch) + { + int_type retVal = (this->write(&ch, 1) == 1) ? static_cast(ch) : traits::eof(); + return pplx::task_from_result(retVal); + } - /// - /// For any input stream, in_avail returns the number of characters that are immediately available - /// to be consumed without blocking. May be used in conjunction with to read data without - /// incurring the overhead of using tasks. - /// - virtual size_t in_avail() const - { - // See the comment in seek around the restriction that we do not allow read head to - // seek beyond the current write_end. - _ASSERTE(m_current_position <= m_data.size()); + virtual pplx::task _putn(const _CharType* ptr, size_t count) + { + return pplx::task_from_result(this->write(ptr, count)); + } - msl::safeint3::SafeInt readhead(m_current_position); - msl::safeint3::SafeInt writeend(m_data.size()); - return (size_t)(writeend - readhead); - } + /// + /// Allocates a contiguous memory block and returns it. + /// + /// The number of characters to allocate. + /// A pointer to a block to write to, null if the stream buffer implementation does not support + /// alloc/commit. + _CharType* _alloc(size_t count) + { + if (!this->can_write()) return nullptr; - virtual pplx::task _sync() - { - return pplx::task_from_result(true); - } + // Allocate space + resize_for_write(m_current_position + count); - virtual pplx::task _putc(_CharType ch) - { - int_type retVal = (this->write(&ch, 1) == 1) ? static_cast(ch) : traits::eof(); - return pplx::task_from_result(retVal); - } + // Let the caller copy the data + return (_CharType*)&m_data[m_current_position]; + } - virtual pplx::task _putn(const _CharType *ptr, size_t count) - { - return pplx::task_from_result(this->write(ptr, count)); - } + /// + /// Submits a block already allocated by the stream buffer. + /// + /// The number of characters to be committed. + void _commit(size_t actual) + { + // Update the write position and satisfy any pending reads + update_current_position(m_current_position + actual); + } - /// - /// Allocates a contiguous memory block and returns it. - /// - /// The number of characters to allocate. - /// A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit. - _CharType* _alloc(size_t count) - { - if (!this->can_write()) return nullptr; + /// + /// Gets a pointer to the next already allocated contiguous block of data. + /// + /// A reference to a pointer variable that will hold the address of the block on success. + /// The number of contiguous characters available at the address in 'ptr'. + /// true if the operation succeeded, false otherwise. + /// + /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that + /// there is no block to return immediately or that the stream buffer does not support the operation. + /// The stream buffer may not de-allocate the block until is called. + /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; + /// a subsequent read will not succeed. + /// + virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) + { + ptr = nullptr; + count = 0; - // Allocate space - resize_for_write(m_current_position+count); + if (!this->can_read()) return false; - // Let the caller copy the data - return (_CharType*)&m_data[m_current_position]; - } + count = in_avail(); - /// - /// Submits a block already allocated by the stream buffer. - /// - /// The number of characters to be committed. - void _commit(size_t actual ) + if (count > 0) { - // Update the write position and satisfy any pending reads - update_current_position(m_current_position+actual); + ptr = (_CharType*)&m_data[m_current_position]; + return true; } - - /// - /// Gets a pointer to the next already allocated contiguous block of data. - /// - /// A reference to a pointer variable that will hold the address of the block on success. - /// The number of contiguous characters available at the address in 'ptr'. - /// true if the operation succeeded, false otherwise. - /// - /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that - /// there is no block to return immediately or that the stream buffer does not support the operation. - /// The stream buffer may not de-allocate the block until is called. - /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; - /// a subsequent read will not succeed. - /// - virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) + else { - ptr = nullptr; - count = 0; + // Can only be open for read OR write, not both. If there is no data then + // we have reached the end of the stream so indicate such with true. + return true; + } + } - if (!this->can_read()) return false; + /// + /// Releases a block of data acquired using . This frees the stream buffer to + /// de-allocate the memory, if it so desires. Move the read position ahead by the count. + /// + /// A pointer to the block of data to be released. + /// The number of characters that were read. + virtual void release(_Out_writes_opt_(count) _CharType* ptr, _In_ size_t count) + { + if (ptr != nullptr) update_current_position(m_current_position + count); + } - count = in_avail(); + virtual pplx::task _getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + return pplx::task_from_result(this->read(ptr, count)); + } - if (count > 0) - { - ptr = (_CharType*)&m_data[m_current_position]; - return true; - } - else - { - // Can only be open for read OR write, not both. If there is no data then - // we have reached the end of the stream so indicate such with true. - return true; - } - } + size_t _sgetn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) { return this->read(ptr, count); } - /// - /// Releases a block of data acquired using . This frees the stream buffer to de-allocate the - /// memory, if it so desires. Move the read position ahead by the count. - /// - /// A pointer to the block of data to be released. - /// The number of characters that were read. - virtual void release(_Out_writes_opt_ (count) _CharType *ptr, _In_ size_t count) - { - if (ptr != nullptr) - update_current_position(m_current_position + count); - } + virtual size_t _scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + return this->read(ptr, count, false); + } - virtual pplx::task _getn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - return pplx::task_from_result(this->read(ptr, count)); - } + virtual pplx::task _bumpc() { return pplx::task_from_result(this->read_byte(true)); } - size_t _sgetn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - return this->read(ptr, count); - } + virtual int_type _sbumpc() { return this->read_byte(true); } - virtual size_t _scopy(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - return this->read(ptr, count, false); - } + virtual pplx::task _getc() { return pplx::task_from_result(this->read_byte(false)); } - virtual pplx::task _bumpc() - { - return pplx::task_from_result(this->read_byte(true)); - } + int_type _sgetc() { return this->read_byte(false); } - virtual int_type _sbumpc() - { - return this->read_byte(true); - } + virtual pplx::task _nextc() + { + this->read_byte(true); + return pplx::task_from_result(this->read_byte(false)); + } - virtual pplx::task _getc() - { - return pplx::task_from_result(this->read_byte(false)); - } + virtual pplx::task _ungetc() + { + auto pos = seekoff(-1, std::ios_base::cur, std::ios_base::in); + if (pos == (pos_type)traits::eof()) return pplx::task_from_result(traits::eof()); + return this->getc(); + } - int_type _sgetc() - { - return this->read_byte(false); - } + /// + /// Gets the current read or write position in the stream. + /// + /// The I/O direction to seek (see remarks) + /// The current position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the direction parameter defines whether to move the read or the write + /// cursor. + virtual pos_type getpos(std::ios_base::openmode mode) const + { + if (((mode & std::ios_base::in) && !this->can_read()) || ((mode & std::ios_base::out) && !this->can_write())) + return static_cast(traits::eof()); - virtual pplx::task _nextc() - { - this->read_byte(true); - return pplx::task_from_result(this->read_byte(false)); - } + return static_cast(m_current_position); + } - virtual pplx::task _ungetc() - { - auto pos = seekoff(-1, std::ios_base::cur, std::ios_base::in); - if ( pos == (pos_type)traits::eof()) - return pplx::task_from_result(traits::eof()); - return this->getc(); - } + /// + /// Seeks to the given position. + /// + /// The offset from the beginning of the stream. + /// The I/O direction to seek (see remarks). + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. For such streams, the direction parameter + /// defines whether to move the read or the write cursor. + virtual pos_type seekpos(pos_type position, std::ios_base::openmode mode) + { + pos_type beg(0); - /// - /// Gets the current read or write position in the stream. - /// - /// The I/O direction to seek (see remarks) - /// The current position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual pos_type getpos(std::ios_base::openmode mode) const - { - if ( ((mode & std::ios_base::in) && !this->can_read()) || - ((mode & std::ios_base::out) && !this->can_write())) - return static_cast(traits::eof()); + // In order to support relative seeking from the end position we need to fix an end position. + // Technically, there is no end for the stream buffer as new writes would just expand the buffer. + // For now, we assume that the current write_end is the end of the buffer. We use this artificial + // end to restrict the read head from seeking beyond what is available. - return static_cast(m_current_position); - } + pos_type end(m_data.size()); - /// - /// Seeks to the given position. - /// - /// The offset from the beginning of the stream. - /// The I/O direction to seek (see remarks). - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual pos_type seekpos(pos_type position, std::ios_base::openmode mode) + if (position >= beg) { - pos_type beg(0); - - // In order to support relative seeking from the end position we need to fix an end position. - // Technically, there is no end for the stream buffer as new writes would just expand the buffer. - // For now, we assume that the current write_end is the end of the buffer. We use this artificial - // end to restrict the read head from seeking beyond what is available. + auto pos = static_cast(position); - pos_type end(m_data.size()); - - if (position >= beg) + // Read head + if ((mode & std::ios_base::in) && this->can_read()) { - auto pos = static_cast(position); - - // Read head - if ((mode & std::ios_base::in) && this->can_read()) + if (position <= end) { - if (position <= end) - { - // We do not allow reads to seek beyond the end or before the start position. - update_current_position(pos); - return static_cast(m_current_position); - } - } - - // Write head - if ((mode & std::ios_base::out) && this->can_write()) - { - // Allocate space - resize_for_write(pos); - - // Nothing to really copy - - // Update write head and satisfy read requests if any + // We do not allow reads to seek beyond the end or before the start position. update_current_position(pos); - return static_cast(m_current_position); } } - return static_cast(traits::eof()); - } - - /// - /// Seeks to a position given by a relative offset. - /// - /// The relative position to seek to - /// The starting point (beginning, end, current) for the seek. - /// The I/O direction to seek (see remarks) - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the mode parameter defines whether to move the read or the write cursor. - virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) - { - pos_type beg = 0; - pos_type cur = static_cast(m_current_position); - pos_type end = static_cast(m_data.size()); - - switch ( way ) + // Write head + if ((mode & std::ios_base::out) && this->can_write()) { - case std::ios_base::beg: - return seekpos(beg + offset, mode); + // Allocate space + resize_for_write(pos); - case std::ios_base::cur: - return seekpos(cur + offset, mode); + // Nothing to really copy - case std::ios_base::end: - return seekpos(end + offset, mode); + // Update write head and satisfy read requests if any + update_current_position(pos); - default: - return static_cast(traits::eof()); + return static_cast(m_current_position); } } - private: - template friend class streams::container_buffer; + return static_cast(traits::eof()); + } - /// - /// Constructor - /// - basic_container_buffer(std::ios_base::openmode mode) - : streambuf_state_manager(mode), - m_current_position(0) - { - validate_mode(mode); - } + /// + /// Seeks to a position given by a relative offset. + /// + /// The relative position to seek to + /// The starting point (beginning, end, current) for the seek. + /// The I/O direction to seek (see remarks) + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the mode parameter defines whether to move the read or the write cursor. + virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) + { + pos_type beg = 0; + pos_type cur = static_cast(m_current_position); + pos_type end = static_cast(m_data.size()); - /// - /// Constructor - /// - basic_container_buffer(_CollectionType data, std::ios_base::openmode mode) - : streambuf_state_manager(mode), - m_data(std::move(data)), - m_current_position((mode & std::ios_base::in) ? 0 : m_data.size()) + switch (way) { - validate_mode(mode); - } + case std::ios_base::beg: return seekpos(beg + offset, mode); - static void validate_mode(std::ios_base::openmode mode) - { - // Disallow simultaneous use of the stream buffer for writing and reading. - if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) - throw std::invalid_argument("this combination of modes on container stream not supported"); - } + case std::ios_base::cur: return seekpos(cur + offset, mode); - /// - /// Determine if the request can be satisfied. - /// - bool can_satisfy(size_t) - { - // We can always satisfy a read, at least partially, unless the - // read position is at the very end of the buffer. - return (in_avail() > 0); - } + case std::ios_base::end: return seekpos(end + offset, mode); - /// - /// Reads a byte from the stream and returns it as int_type. - /// Note: This routine shall only be called if can_satisfy() returned true. - /// - int_type read_byte(bool advance = true) - { - _CharType value; - auto read_size = this->read(&value, 1, advance); - return read_size == 1 ? static_cast(value) : traits::eof(); + default: return static_cast(traits::eof()); } + } - /// - /// Reads up to count characters into ptr and returns the count of characters copied. - /// The return value (actual characters copied) could be <= count. - /// Note: This routine shall only be called if can_satisfy() returned true. - /// - size_t read(_Out_writes_ (count) _CharType *ptr, _In_ size_t count, bool advance = true) - { - if (!can_satisfy(count)) - return 0; - - msl::safeint3::SafeInt request_size(count); - msl::safeint3::SafeInt read_size = request_size.Min(in_avail()); - - size_t newPos = m_current_position + read_size; +private: + template + friend class streams::container_buffer; - auto readBegin = std::begin(m_data) + m_current_position; - auto readEnd = std::begin(m_data) + newPos; + /// + /// Constructor + /// + basic_container_buffer(std::ios_base::openmode mode) + : streambuf_state_manager(mode), m_current_position(0) + { + validate_mode(mode); + } -#ifdef _WIN32 - // Avoid warning C4996: Use checked iterators under SECURE_SCL - std::copy(readBegin, readEnd, stdext::checked_array_iterator<_CharType *>(ptr, count)); -#else - std::copy(readBegin, readEnd, ptr); -#endif // _WIN32 + /// + /// Constructor + /// + basic_container_buffer(_CollectionType data, std::ios_base::openmode mode) + : streambuf_state_manager(mode) + , m_data(std::move(data)) + , m_current_position((mode & std::ios_base::in) ? 0 : m_data.size()) + { + validate_mode(mode); + } - if (advance) - { - update_current_position(newPos); - } + static void validate_mode(std::ios_base::openmode mode) + { + // Disallow simultaneous use of the stream buffer for writing and reading. + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + throw std::invalid_argument("this combination of modes on container stream not supported"); + } - return (size_t) read_size; - } + /// + /// Determine if the request can be satisfied. + /// + bool can_satisfy(size_t) + { + // We can always satisfy a read, at least partially, unless the + // read position is at the very end of the buffer. + return (in_avail() > 0); + } - /// - /// Write count characters from the ptr into the stream buffer - /// - size_t write(const _CharType *ptr, size_t count) - { - if (!this->can_write() || (count == 0)) return 0; + /// + /// Reads a byte from the stream and returns it as int_type. + /// Note: This routine shall only be called if can_satisfy() returned true. + /// + int_type read_byte(bool advance = true) + { + _CharType value; + auto read_size = this->read(&value, 1, advance); + return read_size == 1 ? static_cast(value) : traits::eof(); + } - auto newSize = m_current_position + count; + /// + /// Reads up to count characters into ptr and returns the count of characters copied. + /// The return value (actual characters copied) could be <= count. + /// Note: This routine shall only be called if can_satisfy() returned true. + /// + size_t read(_Out_writes_(count) _CharType* ptr, _In_ size_t count, bool advance = true) + { + if (!can_satisfy(count)) return 0; - // Allocate space - resize_for_write(newSize); + msl::safeint3::SafeInt request_size(count); + msl::safeint3::SafeInt read_size = request_size.Min(in_avail()); - // Copy the data - std::copy(ptr, ptr + count, std::begin(m_data) + m_current_position); + size_t newPos = m_current_position + read_size; - // Update write head and satisfy pending reads if any - update_current_position(newSize); + auto readBegin = std::begin(m_data) + m_current_position; + auto readEnd = std::begin(m_data) + newPos; - return count; - } +#ifdef _WIN32 + // Avoid warning C4996: Use checked iterators under SECURE_SCL + std::copy(readBegin, readEnd, stdext::checked_array_iterator<_CharType*>(ptr, count)); +#else + std::copy(readBegin, readEnd, ptr); +#endif // _WIN32 - /// - /// Resize the underlying container to match the new write head - /// - void resize_for_write(size_t newPos) + if (advance) { - // Resize the container if required - if (newPos > m_data.size()) - { - m_data.resize(newPos); - } + update_current_position(newPos); } - /// - /// Updates the write head to the new position - /// - void update_current_position(size_t newPos) - { - // The new write head - m_current_position = newPos; - _ASSERTE(m_current_position <= m_data.size()); - } + return (size_t)read_size; + } - // The actual data store - _CollectionType m_data; + /// + /// Write count characters from the ptr into the stream buffer + /// + size_t write(const _CharType* ptr, size_t count) + { + if (!this->can_write() || (count == 0)) return 0; + + auto newSize = m_current_position + count; + + // Allocate space + resize_for_write(newSize); - // Read/write head - size_t m_current_position; - }; + // Copy the data + std::copy(ptr, ptr + count, std::begin(m_data) + m_current_position); - } // namespace details + // Update write head and satisfy pending reads if any + update_current_position(newSize); + + return count; + } /// - /// The basic_container_buffer class serves as a memory-based steam buffer that supports writing or reading - /// sequences of characters. Note that it cannot be used as a consumer producer buffer. + /// Resize the underlying container to match the new write head /// - /// - /// The type of the container. - /// - /// - /// This is a reference-counted version of basic_container_buffer. - /// - template - class container_buffer : public streambuf + void resize_for_write(size_t newPos) { - public: - typedef typename _CollectionType::value_type char_type; - - /// - /// Creates a container_buffer given a collection, copying its data into the buffer. - /// - /// The collection that is the starting point for the buffer - /// The I/O mode that the buffer should use (in / out) - container_buffer(_CollectionType data, std::ios_base::openmode mode = std::ios_base::in) - : streambuf( - std::shared_ptr>(new streams::details::basic_container_buffer<_CollectionType>(std::move(data), mode))) + // Resize the container if required + if (newPos > m_data.size()) { + m_data.resize(newPos); } + } - /// - /// Creates a container_buffer starting from an empty collection. - /// - /// The I/O mode that the buffer should use (in / out) - container_buffer(std::ios_base::openmode mode = std::ios_base::out) - : streambuf( - std::shared_ptr>(new details::basic_container_buffer<_CollectionType>(mode))) - { - } + /// + /// Updates the write head to the new position + /// + void update_current_position(size_t newPos) + { + // The new write head + m_current_position = newPos; + _ASSERTE(m_current_position <= m_data.size()); + } - _CollectionType& collection() const - { - auto listBuf = static_cast *>(this->get_base().get()); - return listBuf->collection(); - } - }; + // The actual data store + _CollectionType m_data; + + // Read/write head + size_t m_current_position; +}; + +} // namespace details + +/// +/// The basic_container_buffer class serves as a memory-based steam buffer that supports writing or reading +/// sequences of characters. Note that it cannot be used as a consumer producer buffer. +/// +/// +/// The type of the container. +/// +/// +/// This is a reference-counted version of basic_container_buffer. +/// +template +class container_buffer : public streambuf +{ +public: + typedef typename _CollectionType::value_type char_type; /// - /// A static class to allow users to create input and out streams based off STL - /// collections. The sole purpose of this class to avoid users from having to know - /// anything about stream buffers. + /// Creates a container_buffer given a collection, copying its data into the buffer. /// - /// The type of the STL collection. - template - class container_stream + /// The collection that is the starting point for the buffer + /// The I/O mode that the buffer should use (in / out) + container_buffer(_CollectionType data, std::ios_base::openmode mode = std::ios_base::in) + : streambuf( + std::shared_ptr>( + new streams::details::basic_container_buffer<_CollectionType>(std::move(data), mode))) { - public: + } - typedef typename _CollectionType::value_type char_type; - typedef container_buffer<_CollectionType> buffer_type; + /// + /// Creates a container_buffer starting from an empty collection. + /// + /// The I/O mode that the buffer should use (in / out) + container_buffer(std::ios_base::openmode mode = std::ios_base::out) + : streambuf( + std::shared_ptr>( + new details::basic_container_buffer<_CollectionType>(mode))) + { + } - /// - /// Creates an input stream given an STL container. - /// - /// STL container to back the input stream. - /// An input stream. - static concurrency::streams::basic_istream open_istream(_CollectionType data) - { - return concurrency::streams::basic_istream(buffer_type(std::move(data), std::ios_base::in)); - } + _CollectionType& collection() const + { + auto listBuf = static_cast*>(this->get_base().get()); + return listBuf->collection(); + } +}; - /// - /// Creates an output stream using an STL container as the storage. - /// - /// An output stream. - static concurrency::streams::basic_ostream open_ostream() - { - return concurrency::streams::basic_ostream(buffer_type(std::ios_base::out)); - } - }; +/// +/// A static class to allow users to create input and out streams based off STL +/// collections. The sole purpose of this class to avoid users from having to know +/// anything about stream buffers. +/// +/// The type of the STL collection. +template +class container_stream +{ +public: + typedef typename _CollectionType::value_type char_type; + typedef container_buffer<_CollectionType> buffer_type; /// - /// The stringstream allows an input stream to be constructed from std::string or std::wstring - /// For output streams the underlying string container could be retrieved using buf->collection(). + /// Creates an input stream given an STL container. /// - typedef container_stream> stringstream; - typedef stringstream::buffer_type stringstreambuf; + /// STL container to back the input stream. + /// An input stream. + static concurrency::streams::basic_istream open_istream(_CollectionType data) + { + return concurrency::streams::basic_istream(buffer_type(std::move(data), std::ios_base::in)); + } - typedef container_stream wstringstream; - typedef wstringstream::buffer_type wstringstreambuf; + /// + /// Creates an output stream using an STL container as the storage. + /// + /// An output stream. + static concurrency::streams::basic_ostream open_ostream() + { + return concurrency::streams::basic_ostream(buffer_type(std::ios_base::out)); + } +}; +/// +/// The stringstream allows an input stream to be constructed from std::string or std::wstring +/// For output streams the underlying string container could be retrieved using buf->collection(). +/// +typedef container_stream> stringstream; +typedef stringstream::buffer_type stringstreambuf; + +typedef container_stream wstringstream; +typedef wstringstream::buffer_type wstringstreambuf; + +/// +/// The bytestream is a static class that allows an input stream to be constructed from any STL container. +/// +class bytestream +{ +public: /// - /// The bytestream is a static class that allows an input stream to be constructed from any STL container. + /// Creates a single byte character input stream given an STL container. /// - class bytestream + /// The type of the STL collection. + /// STL container to back the input stream. + /// An single byte character input stream. + template + static concurrency::streams::istream open_istream(_CollectionType data) { - public: - - /// - /// Creates a single byte character input stream given an STL container. - /// - /// The type of the STL collection. - /// STL container to back the input stream. - /// An single byte character input stream. - template - static concurrency::streams::istream open_istream(_CollectionType data) - { - return concurrency::streams::istream(streams::container_buffer<_CollectionType>(std::move(data), std::ios_base::in)); - } + return concurrency::streams::istream( + streams::container_buffer<_CollectionType>(std::move(data), std::ios_base::in)); + } - /// - /// Creates a single byte character output stream using an STL container as storage. - /// - /// The type of the STL collection. - /// A single byte character output stream. - template - static concurrency::streams::ostream open_ostream() - { - return concurrency::streams::ostream(streams::container_buffer<_CollectionType>()); - } + /// + /// Creates a single byte character output stream using an STL container as storage. + /// + /// The type of the STL collection. + /// A single byte character output stream. + template + static concurrency::streams::ostream open_ostream() + { + return concurrency::streams::ostream(streams::container_buffer<_CollectionType>()); + } }; - -}} // namespaces +} // namespace streams +} // namespace Concurrency diff --git a/Release/include/cpprest/details/SafeInt3.hpp b/Release/include/cpprest/details/SafeInt3.hpp index 798012bedf..0a9dbdd76a 100644 --- a/Release/include/cpprest/details/SafeInt3.hpp +++ b/Release/include/cpprest/details/SafeInt3.hpp @@ -74,9 +74,9 @@ Please read the leading comments before using the class. // Enable compiling with /Wall under VC #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER -#pragma warning( push ) +#pragma warning(push) // Disable warnings coming from headers -#pragma warning( disable:4987 4820 4987 4820 ) +#pragma warning(disable : 4987 4820 4987 4820) #endif @@ -85,14 +85,14 @@ Please read the leading comments before using the class. #include #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER && defined _M_AMD64 - #include - #define SAFEINT_USE_INTRINSICS 1 +#include +#define SAFEINT_USE_INTRINSICS 1 #else - #define SAFEINT_USE_INTRINSICS 0 +#define SAFEINT_USE_INTRINSICS 0 #endif #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER -#pragma warning( pop ) +#pragma warning(pop) #endif // Various things needed for GCC @@ -116,7 +116,7 @@ Please read the leading comments before using the class. #if SAFEINT_COMPILER == CLANG_COMPILER #if __has_feature(cxx_nullptr) - #define NEEDS_NULLPTR_DEFINED 0 +#define NEEDS_NULLPTR_DEFINED 0 #endif #pragma clang diagnostic push @@ -129,21 +129,21 @@ Please read the leading comments before using the class. // If the user made a choice, respect it #if !defined #if !defined NEEDS_NULLPTR_DEFINED - // Visual Studio 2010 and higher support this - #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER - #if (_MSC_VER < 1600) - #define NEEDS_NULLPTR_DEFINED 1 - #else - #define NEEDS_NULLPTR_DEFINED 0 - #endif - #else - // Let everything else trigger based on whether we use c++11 or above - #if __cplusplus >= 201103L - #define NEEDS_NULLPTR_DEFINED 0 - #else - #define NEEDS_NULLPTR_DEFINED 1 - #endif - #endif +// Visual Studio 2010 and higher support this +#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER +#if (_MSC_VER < 1600) +#define NEEDS_NULLPTR_DEFINED 1 +#else +#define NEEDS_NULLPTR_DEFINED 0 +#endif +#else +// Let everything else trigger based on whether we use c++11 or above +#if __cplusplus >= 201103L +#define NEEDS_NULLPTR_DEFINED 0 +#else +#define NEEDS_NULLPTR_DEFINED 1 +#endif +#endif #endif #if NEEDS_NULLPTR_DEFINED @@ -151,37 +151,37 @@ Please read the leading comments before using the class. #endif #ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#define C_ASSERT_DEFINED_SAFEINT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1] #endif // Let's test some assumptions // We're assuming two's complement negative numbers -C_ASSERT( -1 == static_cast(0xffffffff) ); +C_ASSERT(-1 == static_cast(0xffffffff)); -/************* Compiler Options ***************************************************************************************************** +/************* Compiler Options +***************************************************************************************************** SafeInt supports several compile-time options that can change the behavior of the class. Compiler options: -SAFEINT_WARN_64BIT_PORTABILITY - this re-enables various warnings that happen when /Wp64 is used. Enabling this option is not - recommended. -NEEDS_INT_DEFINED - if your compiler does not support __int8, __int16, __int32 and __int64, you can enable this. -SAFEINT_ASSERT_ON_EXCEPTION - it is often easier to stop on an assert and figure out a problem than to try and figure out - how you landed in the catch block. -SafeIntDefaultExceptionHandler - if you'd like to replace the exception handlers SafeInt provides, define your replacement and - define this. Note - two built in (Windows-specific) options exist: - - SAFEINT_FAILFAST - bypasses all exception handlers, exits the app with an exception +SAFEINT_WARN_64BIT_PORTABILITY - this re-enables various warnings that happen when /Wp64 is used. Enabling this +option is not recommended. NEEDS_INT_DEFINED - if your compiler does not support __int8, __int16, +__int32 and __int64, you can enable this. SAFEINT_ASSERT_ON_EXCEPTION - it is often easier to stop on an assert +and figure out a problem than to try and figure out how you landed in the catch block. SafeIntDefaultExceptionHandler - +if you'd like to replace the exception handlers SafeInt provides, define your replacement and define this. Note - two +built in (Windows-specific) options exist: + - SAFEINT_FAILFAST - bypasses all exception handlers, exits the app with an +exception - SAFEINT_RAISE_EXCEPTION - throws Win32 exceptions, which can be caught -SAFEINT_DISALLOW_UNSIGNED_NEGATION - Invoking the unary negation operator creates warnings, but if you'd like it to completely fail - to compile, define this. -ANSI_CONVERSIONS - This changes the class to use default comparison behavior, which may be unsafe. Enabling this - option is not recommended. -SAFEINT_DISABLE_BINARY_ASSERT - binary AND, OR or XOR operations on mixed size types can produce unexpected results. If you do - this, the default is to assert. Set this if you prefer not to assert under these conditions. -SIZE_T_CAST_NEEDED - some compilers complain if there is not a cast to size_t, others complain if there is one. - This lets you not have your compiler complain. -SAFEINT_DISABLE_SHIFT_ASSERT - Set this option if you don't want to assert when shifting more bits than the type has. Enabling - this option is not recommended. +SAFEINT_DISALLOW_UNSIGNED_NEGATION - Invoking the unary negation operator creates warnings, but if you'd like it to +completely fail to compile, define this. ANSI_CONVERSIONS - This changes the class to use default +comparison behavior, which may be unsafe. Enabling this option is not recommended. SAFEINT_DISABLE_BINARY_ASSERT - +binary AND, OR or XOR operations on mixed size types can produce unexpected results. If you do this, the default is to +assert. Set this if you prefer not to assert under these conditions. SIZE_T_CAST_NEEDED - some compilers +complain if there is not a cast to size_t, others complain if there is one. This lets you not have your compiler +complain. SAFEINT_DISABLE_SHIFT_ASSERT - Set this option if you don't want to assert when shifting more bits than +the type has. Enabling this option is not recommended. ************************************************************************************************************************************/ @@ -509,9 +509,12 @@ SAFEINT_DISABLE_SHIFT_ASSERT - Set this option if you don't want to assert * and you can cast it out (or assign) to a float as well. * 4) There is now an Align method. I noticed people use this a lot, and rarely check errors, so now you have one. * -* Another major improvement is the addition of external functions - if you just want to check an operation, this can now happen: -* All of the following can be invoked without dealing with creating a class, or managing exceptions. This is especially handy -* for 64-bit porting, since SafeCast compiles away for a 32-bit cast from size_t to unsigned long, but checks it for 64-bit. +* Another major improvement is the addition of external functions - if you just want to check an operation, this can now +happen: +* All of the following can be invoked without dealing with creating a class, or managing exceptions. This is especially +handy +* for 64-bit porting, since SafeCast compiles away for a 32-bit cast from size_t to unsigned long, but checks it for +64-bit. * * inline bool SafeCast( const T From, U& To ) throw() * inline bool SafeEquals( const T t, const U u ) throw() @@ -528,9 +531,9 @@ SAFEINT_DISABLE_SHIFT_ASSERT - Set this option if you don't want to assert * */ -//use these if the compiler does not support _intXX +// use these if the compiler does not support _intXX #ifdef NEEDS_INT_DEFINED -#define __int8 char +#define __int8 char #define __int16 short #define __int32 int #define __int64 long long @@ -538,10 +541,8 @@ SAFEINT_DISABLE_SHIFT_ASSERT - Set this option if you don't want to assert namespace msl { - namespace safeint3 { - // catch these to handle errors // Currently implemented code values: // ERROR_ARITHMETIC_OVERFLOW @@ -553,76 +554,75 @@ enum SafeIntError SafeIntDivideByZero }; -} // safeint3 -} // msl - +} // namespace safeint3 +} // namespace msl /* -* Error handler classes -* Using classes to deal with exceptions is going to allow the most -* flexibility, and we can mix different error handlers in the same project -* or even the same file. It isn't advisable to do this in the same function -* because a SafeInt< int, MyExceptionHandler > isn't the same thing as -* SafeInt< int, YourExceptionHander >. -* If for some reason you have to translate between the two, cast one of them back to its -* native type. -* -* To use your own exception class with SafeInt, first create your exception class, -* which may look something like the SafeIntException class below. The second step is to -* create a template specialization that implements SafeIntOnOverflow and SafeIntOnDivZero. -* For example: -* -* template <> class SafeIntExceptionHandler < YourExceptionClass > -* { -* static __declspec(noreturn) void __stdcall SafeIntOnOverflow() -* { -* throw YourExceptionClass( EXCEPTION_INT_OVERFLOW ); -* } -* -* static __declspec(noreturn) void __stdcall SafeIntOnDivZero() -* { -* throw YourExceptionClass( EXCEPTION_INT_DIVIDE_BY_ZERO ); -* } -* }; -* -* typedef SafeIntExceptionHandler < YourExceptionClass > YourSafeIntExceptionHandler -* You'd then declare your SafeInt objects like this: -* SafeInt< int, YourSafeIntExceptionHandler > -* -* Unfortunately, there is no such thing as partial template specialization in typedef -* statements, so you have three options if you find this cumbersome: -* -* 1) Create a holder class: -* -* template < typename T > -* class MySafeInt -* { -* public: -* SafeInt< T, MyExceptionClass> si; -* }; -* -* You'd then declare an instance like so: -* MySafeInt< int > i; -* -* You'd lose handy things like initialization - it would have to be initialized as: -* -* i.si = 0; -* -* 2) You could create a typedef for every int type you deal with: -* -* typedef SafeInt< int, MyExceptionClass > MySafeInt; -* typedef SafeInt< char, MyExceptionClass > MySafeChar; -* -* and so on. The second approach is probably more usable, and will just drop into code -* better, which is the original intent of the SafeInt class. -* -* 3) If you're going to consistently use a different class to handle your exceptions, -* you can override the default typedef like so: -* -* #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler -* -* Overall, this is probably the best approach. -* */ + * Error handler classes + * Using classes to deal with exceptions is going to allow the most + * flexibility, and we can mix different error handlers in the same project + * or even the same file. It isn't advisable to do this in the same function + * because a SafeInt< int, MyExceptionHandler > isn't the same thing as + * SafeInt< int, YourExceptionHander >. + * If for some reason you have to translate between the two, cast one of them back to its + * native type. + * + * To use your own exception class with SafeInt, first create your exception class, + * which may look something like the SafeIntException class below. The second step is to + * create a template specialization that implements SafeIntOnOverflow and SafeIntOnDivZero. + * For example: + * + * template <> class SafeIntExceptionHandler < YourExceptionClass > + * { + * static __declspec(noreturn) void __stdcall SafeIntOnOverflow() + * { + * throw YourExceptionClass( EXCEPTION_INT_OVERFLOW ); + * } + * + * static __declspec(noreturn) void __stdcall SafeIntOnDivZero() + * { + * throw YourExceptionClass( EXCEPTION_INT_DIVIDE_BY_ZERO ); + * } + * }; + * + * typedef SafeIntExceptionHandler < YourExceptionClass > YourSafeIntExceptionHandler + * You'd then declare your SafeInt objects like this: + * SafeInt< int, YourSafeIntExceptionHandler > + * + * Unfortunately, there is no such thing as partial template specialization in typedef + * statements, so you have three options if you find this cumbersome: + * + * 1) Create a holder class: + * + * template < typename T > + * class MySafeInt + * { + * public: + * SafeInt< T, MyExceptionClass> si; + * }; + * + * You'd then declare an instance like so: + * MySafeInt< int > i; + * + * You'd lose handy things like initialization - it would have to be initialized as: + * + * i.si = 0; + * + * 2) You could create a typedef for every int type you deal with: + * + * typedef SafeInt< int, MyExceptionClass > MySafeInt; + * typedef SafeInt< char, MyExceptionClass > MySafeChar; + * + * and so on. The second approach is probably more usable, and will just drop into code + * better, which is the original intent of the SafeInt class. + * + * 3) If you're going to consistently use a different class to handle your exceptions, + * you can override the default typedef like so: + * + * #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler + * + * Overall, this is probably the best approach. + * */ // On the Microsoft compiler, violating a throw() annotation is a silent error. // Other compilers might turn these into exceptions, and some users may want to not have throw() enabled. @@ -635,10 +635,8 @@ enum SafeIntError namespace msl { - namespace safeint3 { - // If you would like to use your own custom assert // Define SAFEINT_ASSERT #if !defined SAFEINT_ASSERT @@ -647,119 +645,117 @@ namespace safeint3 #endif #if defined SAFEINT_ASSERT_ON_EXCEPTION - inline void SafeIntExceptionAssert() SAFEINT_NOTHROW { SAFEINT_ASSERT(false); } +inline void SafeIntExceptionAssert() SAFEINT_NOTHROW { SAFEINT_ASSERT(false); } #else - inline void SafeIntExceptionAssert() SAFEINT_NOTHROW {} +inline void SafeIntExceptionAssert() SAFEINT_NOTHROW {} #endif #if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER - #define SAFEINT_NORETURN __attribute__((noreturn)) - #define SAFEINT_STDCALL - #define SAFEINT_VISIBLE __attribute__ ((__visibility__("default"))) - #define SAFEINT_WEAK __attribute__ ((weak)) +#define SAFEINT_NORETURN __attribute__((noreturn)) +#define SAFEINT_STDCALL +#define SAFEINT_VISIBLE __attribute__((__visibility__("default"))) +#define SAFEINT_WEAK __attribute__((weak)) #else - #define SAFEINT_NORETURN __declspec(noreturn) - #define SAFEINT_STDCALL __stdcall - #define SAFEINT_VISIBLE - #define SAFEINT_WEAK +#define SAFEINT_NORETURN __declspec(noreturn) +#define SAFEINT_STDCALL __stdcall +#define SAFEINT_VISIBLE +#define SAFEINT_WEAK #endif class SAFEINT_VISIBLE SafeIntException { public: SafeIntException() SAFEINT_NOTHROW { m_code = SafeIntNoError; } - SafeIntException( SafeIntError code ) SAFEINT_NOTHROW - { - m_code = code; - } + SafeIntException(SafeIntError code) SAFEINT_NOTHROW { m_code = code; } SafeIntError m_code; }; namespace SafeIntInternal { - // Visual Studio version of SafeInt provides for two possible error - // handlers: - // SafeIntErrorPolicy_SafeIntException - C++ exception, default if not otherwise defined - // SafeIntErrorPolicy_InvalidParameter - Calls fail fast (Windows-specific), bypasses any exception handlers, - // exits the app with a crash - template < typename E > class SafeIntExceptionHandler; +// Visual Studio version of SafeInt provides for two possible error +// handlers: +// SafeIntErrorPolicy_SafeIntException - C++ exception, default if not otherwise defined +// SafeIntErrorPolicy_InvalidParameter - Calls fail fast (Windows-specific), bypasses any exception handlers, +// exits the app with a crash +template +class SafeIntExceptionHandler; - template <> class SafeIntExceptionHandler < SafeIntException > +template<> +class SafeIntExceptionHandler +{ +public: + static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() { - public: - - static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() - { - SafeIntExceptionAssert(); - throw SafeIntException( SafeIntArithmeticOverflow ); - } + SafeIntExceptionAssert(); + throw SafeIntException(SafeIntArithmeticOverflow); + } - static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() - { - SafeIntExceptionAssert(); - throw SafeIntException( SafeIntDivideByZero ); - } - }; + static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() + { + SafeIntExceptionAssert(); + throw SafeIntException(SafeIntDivideByZero); + } +}; #if !defined _CRT_SECURE_INVALID_PARAMETER - // Calling fail fast is somewhat more robust than calling abort, - // but abort is the closest we can manage without Visual Studio support - // Need the header for abort() - #include - #define _CRT_SECURE_INVALID_PARAMETER(msg) abort() +// Calling fail fast is somewhat more robust than calling abort, +// but abort is the closest we can manage without Visual Studio support +// Need the header for abort() +#include +#define _CRT_SECURE_INVALID_PARAMETER(msg) abort() #endif - class SafeInt_InvalidParameter - { - public: - static SAFEINT_NORETURN void SafeIntOnOverflow() SAFEINT_NOTHROW - { - SafeIntExceptionAssert(); - _CRT_SECURE_INVALID_PARAMETER("SafeInt Arithmetic Overflow"); - } +class SafeInt_InvalidParameter +{ +public: + static SAFEINT_NORETURN void SafeIntOnOverflow() SAFEINT_NOTHROW + { + SafeIntExceptionAssert(); + _CRT_SECURE_INVALID_PARAMETER("SafeInt Arithmetic Overflow"); + } - static SAFEINT_NORETURN void SafeIntOnDivZero() SAFEINT_NOTHROW - { - SafeIntExceptionAssert(); - _CRT_SECURE_INVALID_PARAMETER("SafeInt Divide By Zero"); - } - }; + static SAFEINT_NORETURN void SafeIntOnDivZero() SAFEINT_NOTHROW + { + SafeIntExceptionAssert(); + _CRT_SECURE_INVALID_PARAMETER("SafeInt Divide By Zero"); + } +}; -#if defined _WINDOWS_ +#if defined _WINDOWS_ - class SafeIntWin32ExceptionHandler +class SafeIntWin32ExceptionHandler +{ +public: + static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() SAFEINT_NOTHROW { - public: - static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() SAFEINT_NOTHROW - { - SafeIntExceptionAssert(); - RaiseException( static_cast(EXCEPTION_INT_OVERFLOW), EXCEPTION_NONCONTINUABLE, 0, 0); - } + SafeIntExceptionAssert(); + RaiseException(static_cast(EXCEPTION_INT_OVERFLOW), EXCEPTION_NONCONTINUABLE, 0, 0); + } - static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() SAFEINT_NOTHROW - { - SafeIntExceptionAssert(); - RaiseException( static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), EXCEPTION_NONCONTINUABLE, 0, 0); - } - }; + static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() SAFEINT_NOTHROW + { + SafeIntExceptionAssert(); + RaiseException(static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), EXCEPTION_NONCONTINUABLE, 0, 0); + } +}; #endif } // namespace SafeIntInternal // both of these have cross-platform support -typedef SafeIntInternal::SafeIntExceptionHandler < SafeIntException > CPlusPlusExceptionHandler; +typedef SafeIntInternal::SafeIntExceptionHandler CPlusPlusExceptionHandler; typedef SafeIntInternal::SafeInt_InvalidParameter InvalidParameterExceptionHandler; // This exception handler is no longer recommended, but is left here in order not to break existing users -#if defined _WINDOWS_ +#if defined _WINDOWS_ typedef SafeIntInternal::SafeIntWin32ExceptionHandler Win32ExceptionHandler; #endif // For Visual Studio compatibility -#if defined VISUAL_STUDIO_SAFEINT_COMPAT - typedef CPlusPlusExceptionHandler SafeIntErrorPolicy_SafeIntException; - typedef InvalidParameterExceptionHandler SafeIntErrorPolicy_InvalidParameter; +#if defined VISUAL_STUDIO_SAFEINT_COMPAT +typedef CPlusPlusExceptionHandler SafeIntErrorPolicy_SafeIntException; +typedef InvalidParameterExceptionHandler SafeIntErrorPolicy_InvalidParameter; #endif // If the user hasn't defined a default exception handler, @@ -768,27 +764,27 @@ typedef SafeIntInternal::SafeIntWin32ExceptionHandler Win32ExceptionHandler; // This library will use conditional noexcept soon, but not in this release // Some users might mix exception handlers, which is not advised, but is supported #if !defined SafeIntDefaultExceptionHandler - #if defined SAFEINT_RAISE_EXCEPTION - #if !defined _WINDOWS_ - #error Include windows.h in order to use Win32 exceptions - #endif - - #define SafeIntDefaultExceptionHandler Win32ExceptionHandler - #elif defined SAFEINT_FAILFAST - #define SafeIntDefaultExceptionHandler InvalidParameterExceptionHandler - #else - #define SafeIntDefaultExceptionHandler CPlusPlusExceptionHandler - #if !defined SAFEINT_EXCEPTION_HANDLER_CPP - #define SAFEINT_EXCEPTION_HANDLER_CPP 1 - #endif - #endif +#if defined SAFEINT_RAISE_EXCEPTION +#if !defined _WINDOWS_ +#error Include windows.h in order to use Win32 exceptions +#endif + +#define SafeIntDefaultExceptionHandler Win32ExceptionHandler +#elif defined SAFEINT_FAILFAST +#define SafeIntDefaultExceptionHandler InvalidParameterExceptionHandler +#else +#define SafeIntDefaultExceptionHandler CPlusPlusExceptionHandler +#if !defined SAFEINT_EXCEPTION_HANDLER_CPP +#define SAFEINT_EXCEPTION_HANDLER_CPP 1 +#endif +#endif #endif #if !defined SAFEINT_EXCEPTION_HANDLER_CPP #define SAFEINT_EXCEPTION_HANDLER_CPP 0 #endif -// If an error handler is chosen other than C++ exceptions, such as Win32 exceptions, fail fast, +// If an error handler is chosen other than C++ exceptions, such as Win32 exceptions, fail fast, // or abort, then all methods become no throw. Some teams track throw() annotations closely, // and the following option provides for this. #if SAFEINT_EXCEPTION_HANDLER_CPP @@ -799,9 +795,20 @@ typedef SafeIntInternal::SafeIntWin32ExceptionHandler Win32ExceptionHandler; // Turns out we can fool the compiler into not seeing compile-time constants with // a simple template specialization -template < int method > class CompileConst; -template <> class CompileConst { public: static bool Value() SAFEINT_NOTHROW { return true; } }; -template <> class CompileConst { public: static bool Value() SAFEINT_NOTHROW { return false; } }; +template +class CompileConst; +template<> +class CompileConst +{ +public: + static bool Value() SAFEINT_NOTHROW { return true; } +}; +template<> +class CompileConst +{ +public: + static bool Value() SAFEINT_NOTHROW { return false; } +}; // The following template magic is because we're now not allowed // to cast a float to an enum. This means that if we happen to assign @@ -811,49 +818,222 @@ template <> class CompileConst { public: static bool Value() SAFEINT_NOTH // that follows. // If we have support for std, then we can do this easily, and detect enums as well -template < typename T > class NumericType; +template +class NumericType; #if defined _LIBCPP_TYPE_TRAITS || defined _TYPE_TRAITS_ // Continue to special case bool -template <> class NumericType { public: enum{ isBool = true, isFloat = false, isInt = false }; }; -template < typename T > class NumericType +template<> +class NumericType +{ +public: + enum + { + isBool = true, + isFloat = false, + isInt = false + }; +}; +template +class NumericType { - public: - enum - { - isBool = false, // We specialized out a bool - isFloat = std::is_floating_point::value, - // If it is an enum, then consider it an int type - // This does allow someone to make a SafeInt from an enum type, which is not recommended, - // but it also allows someone to add an enum value to a SafeInt, which is handy. - isInt = std::is_integral::value || std::is_enum::value - }; +public: + enum + { + isBool = false, // We specialized out a bool + isFloat = std::is_floating_point::value, + // If it is an enum, then consider it an int type + // This does allow someone to make a SafeInt from an enum type, which is not recommended, + // but it also allows someone to add an enum value to a SafeInt, which is handy. + isInt = std::is_integral::value || std::is_enum::value + }; }; #else -template <> class NumericType { public: enum{ isBool = true, isFloat = false, isInt = false }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template<> +class NumericType +{ +public: + enum + { + isBool = true, + isFloat = false, + isInt = false + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; #if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; #endif -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType<__int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; }; -template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; }; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType<__int64> +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = false, + isInt = true + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = true, + isInt = false + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = true, + isInt = false + }; +}; +template<> +class NumericType +{ +public: + enum + { + isBool = false, + isFloat = true, + isInt = false + }; +}; // Catch-all for anything not supported -template < typename T > class NumericType -{ -public: +template +class NumericType +{ +public: // We have some unknown type, which could be an enum. For parity with the code that uses , // We can try a static_cast - it if compiles, then it might be an enum, and should work. // If it is something else that just happens to have a constructor that takes an int, and a casting operator, @@ -861,129 +1041,176 @@ template < typename T > class NumericType // interact with a SafeInt enum - { - isBool = false, - isFloat = false, - isInt = static_cast( static_cast(0) ) == 0 - }; + { + isBool = false, + isFloat = false, + isInt = static_cast(static_cast(0)) == 0 + }; }; #endif // type traits // Use this to avoid compile-time const truncation warnings -template < int fSigned, int bits > class SafeIntMinMax; - -template <> class SafeIntMinMax< true, 8 > { public: const static signed __int8 min = (-0x7f - 1); - const static signed __int8 max = 0x7f; }; -template <> class SafeIntMinMax< true, 16 > { public: const static __int16 min = ( -0x7fff - 1 ); - const static __int16 max = 0x7fff; }; -template <> class SafeIntMinMax< true, 32 > { public: const static __int32 min = ( -0x7fffffff -1 ); - const static __int32 max = 0x7fffffff; }; -template <> class SafeIntMinMax< true, 64 > { public: const static __int64 min = static_cast<__int64>(0x8000000000000000LL); - const static __int64 max = 0x7fffffffffffffffLL; }; - -template <> class SafeIntMinMax< false, 8 > { public: const static unsigned __int8 min = 0; - const static unsigned __int8 max = 0xff; }; -template <> class SafeIntMinMax< false, 16 > { public: const static unsigned __int16 min = 0; - const static unsigned __int16 max = 0xffff; }; -template <> class SafeIntMinMax< false, 32 > { public: const static unsigned __int32 min = 0; - const static unsigned __int32 max = 0xffffffff; }; -template <> class SafeIntMinMax< false, 64 > { public: const static unsigned __int64 min = 0; - const static unsigned __int64 max = 0xffffffffffffffffULL; }; - -template < typename T > class IntTraits -{ -public: - C_ASSERT( NumericType::isInt ); +template +class SafeIntMinMax; + +template<> +class SafeIntMinMax +{ +public: + const static signed __int8 min = (-0x7f - 1); + const static signed __int8 max = 0x7f; +}; +template<> +class SafeIntMinMax +{ +public: + const static __int16 min = (-0x7fff - 1); + const static __int16 max = 0x7fff; +}; +template<> +class SafeIntMinMax +{ +public: + const static __int32 min = (-0x7fffffff - 1); + const static __int32 max = 0x7fffffff; +}; +template<> +class SafeIntMinMax +{ +public: + const static __int64 min = static_cast<__int64>(0x8000000000000000LL); + const static __int64 max = 0x7fffffffffffffffLL; +}; + +template<> +class SafeIntMinMax +{ +public: + const static unsigned __int8 min = 0; + const static unsigned __int8 max = 0xff; +}; +template<> +class SafeIntMinMax +{ +public: + const static unsigned __int16 min = 0; + const static unsigned __int16 max = 0xffff; +}; +template<> +class SafeIntMinMax +{ +public: + const static unsigned __int32 min = 0; + const static unsigned __int32 max = 0xffffffff; +}; +template<> +class SafeIntMinMax +{ +public: + const static unsigned __int64 min = 0; + const static unsigned __int64 max = 0xffffffffffffffffULL; +}; + +template +class IntTraits +{ +public: + C_ASSERT(NumericType::isInt); enum { - isSigned = ( (T)(-1) < 0 ), - is64Bit = ( sizeof(T) == 8 ), - is32Bit = ( sizeof(T) == 4 ), - is16Bit = ( sizeof(T) == 2 ), - is8Bit = ( sizeof(T) == 1 ), - isLT32Bit = ( sizeof(T) < 4 ), - isLT64Bit = ( sizeof(T) < 8 ), - isInt8 = ( sizeof(T) == 1 && isSigned ), - isUint8 = ( sizeof(T) == 1 && !isSigned ), - isInt16 = ( sizeof(T) == 2 && isSigned ), - isUint16 = ( sizeof(T) == 2 && !isSigned ), - isInt32 = ( sizeof(T) == 4 && isSigned ), - isUint32 = ( sizeof(T) == 4 && !isSigned ), - isInt64 = ( sizeof(T) == 8 && isSigned ), - isUint64 = ( sizeof(T) == 8 && !isSigned ), - bitCount = ( sizeof(T)*8 ), - isBool = ( (T)2 == (T)1 ) + isSigned = ((T)(-1) < 0), + is64Bit = (sizeof(T) == 8), + is32Bit = (sizeof(T) == 4), + is16Bit = (sizeof(T) == 2), + is8Bit = (sizeof(T) == 1), + isLT32Bit = (sizeof(T) < 4), + isLT64Bit = (sizeof(T) < 8), + isInt8 = (sizeof(T) == 1 && isSigned), + isUint8 = (sizeof(T) == 1 && !isSigned), + isInt16 = (sizeof(T) == 2 && isSigned), + isUint16 = (sizeof(T) == 2 && !isSigned), + isInt32 = (sizeof(T) == 4 && isSigned), + isUint32 = (sizeof(T) == 4 && !isSigned), + isInt64 = (sizeof(T) == 8 && isSigned), + isUint64 = (sizeof(T) == 8 && !isSigned), + bitCount = (sizeof(T) * 8), + isBool = ((T)2 == (T)1) }; // On version 13.10 enums cannot define __int64 values // so we'll use const statics instead! // These must be cast to deal with the possibility of a SafeInt being given an enum as an argument - const static T maxInt = static_cast(SafeIntMinMax< isSigned, bitCount >::max); - const static T minInt = static_cast(SafeIntMinMax< isSigned, bitCount >::min); + const static T maxInt = static_cast(SafeIntMinMax::max); + const static T minInt = static_cast(SafeIntMinMax::min); }; -template < typename T > -const T IntTraits< T >::maxInt; -template < typename T > -const T IntTraits< T >::minInt; +template +const T IntTraits::maxInt; +template +const T IntTraits::minInt; -template < typename T, typename U > class SafeIntCompare +template +class SafeIntCompare { public: enum { - isBothSigned = (IntTraits< T >::isSigned && IntTraits< U >::isSigned), - isBothUnsigned = (!IntTraits< T >::isSigned && !IntTraits< U >::isSigned), - isLikeSigned = ((bool)(IntTraits< T >::isSigned) == (bool)(IntTraits< U >::isSigned)), - isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) || - (IntTraits< T >::isSigned && sizeof(T) > sizeof(U))), - isBothLT32Bit = (IntTraits< T >::isLT32Bit && IntTraits< U >::isLT32Bit), - isBothLT64Bit = (IntTraits< T >::isLT64Bit && IntTraits< U >::isLT64Bit) + isBothSigned = (IntTraits::isSigned && IntTraits::isSigned), + isBothUnsigned = (!IntTraits::isSigned && !IntTraits::isSigned), + isLikeSigned = ((bool)(IntTraits::isSigned) == (bool)(IntTraits::isSigned)), + isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) || (IntTraits::isSigned && sizeof(T) > sizeof(U))), + isBothLT32Bit = (IntTraits::isLT32Bit && IntTraits::isLT32Bit), + isBothLT64Bit = (IntTraits::isLT64Bit && IntTraits::isLT64Bit) }; }; -//all of the arithmetic operators can be solved by the same code within -//each of these regions without resorting to compile-time constant conditionals -//most operators collapse the problem into less than the 22 zones, but this is used -//as the first cut -//using this also helps ensure that we handle all of the possible cases correctly +// all of the arithmetic operators can be solved by the same code within +// each of these regions without resorting to compile-time constant conditionals +// most operators collapse the problem into less than the 22 zones, but this is used +// as the first cut +// using this also helps ensure that we handle all of the possible cases correctly -template < typename T, typename U > class IntRegion +template +class IntRegion { public: enum { - //unsigned-unsigned zone - IntZone_UintLT32_UintLT32 = SafeIntCompare< T,U >::isBothUnsigned && SafeIntCompare< T,U >::isBothLT32Bit, - IntZone_Uint32_UintLT64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, - IntZone_UintLT32_Uint32 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, - IntZone_Uint64_Uint = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is64Bit, - IntZone_UintLT64_Uint64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, - //unsigned-signed - IntZone_UintLT32_IntLT32 = !IntTraits< T >::isSigned && IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, - IntZone_Uint32_IntLT64 = IntTraits< T >::isUint32 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, - IntZone_UintLT32_Int32 = !IntTraits< T >::isSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::isInt32, - IntZone_Uint64_Int = IntTraits< T >::isUint64 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, - IntZone_UintLT64_Int64 = !IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isInt64, - IntZone_Uint64_Int64 = IntTraits< T >::isUint64 && IntTraits< U >::isInt64, - //signed-signed - IntZone_IntLT32_IntLT32 = SafeIntCompare< T,U >::isBothSigned && SafeIntCompare< T, U >::isBothLT32Bit, - IntZone_Int32_IntLT64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, - IntZone_IntLT32_Int32 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, - IntZone_Int64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isInt64 && IntTraits< U >::isInt64, - IntZone_Int64_Int = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is64Bit && IntTraits< U >::isLT64Bit, - IntZone_IntLT64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, - //signed-unsigned - IntZone_IntLT32_UintLT32 = IntTraits< T >::isSigned && !IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, - IntZone_Int32_UintLT32 = IntTraits< T >::isInt32 && !IntTraits< U >::isSigned && IntTraits< U >::isLT32Bit, - IntZone_IntLT64_Uint32 = IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isUint32, - IntZone_Int64_UintLT64 = IntTraits< T >::isInt64 && !IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, - IntZone_Int_Uint64 = IntTraits< T >::isSigned && IntTraits< U >::isUint64 && IntTraits< T >::isLT64Bit, - IntZone_Int64_Uint64 = IntTraits< T >::isInt64 && IntTraits< U >::isUint64 + // unsigned-unsigned zone + IntZone_UintLT32_UintLT32 = SafeIntCompare::isBothUnsigned && SafeIntCompare::isBothLT32Bit, + IntZone_Uint32_UintLT64 = + SafeIntCompare::isBothUnsigned && IntTraits::is32Bit && IntTraits::isLT64Bit, + IntZone_UintLT32_Uint32 = + SafeIntCompare::isBothUnsigned && IntTraits::isLT32Bit && IntTraits::is32Bit, + IntZone_Uint64_Uint = SafeIntCompare::isBothUnsigned && IntTraits::is64Bit, + IntZone_UintLT64_Uint64 = + SafeIntCompare::isBothUnsigned && IntTraits::isLT64Bit && IntTraits::is64Bit, + // unsigned-signed + IntZone_UintLT32_IntLT32 = + !IntTraits::isSigned && IntTraits::isSigned && SafeIntCompare::isBothLT32Bit, + IntZone_Uint32_IntLT64 = IntTraits::isUint32 && IntTraits::isSigned && IntTraits::isLT64Bit, + IntZone_UintLT32_Int32 = !IntTraits::isSigned && IntTraits::isLT32Bit && IntTraits::isInt32, + IntZone_Uint64_Int = IntTraits::isUint64 && IntTraits::isSigned && IntTraits::isLT64Bit, + IntZone_UintLT64_Int64 = !IntTraits::isSigned && IntTraits::isLT64Bit && IntTraits::isInt64, + IntZone_Uint64_Int64 = IntTraits::isUint64 && IntTraits::isInt64, + // signed-signed + IntZone_IntLT32_IntLT32 = SafeIntCompare::isBothSigned && SafeIntCompare::isBothLT32Bit, + IntZone_Int32_IntLT64 = SafeIntCompare::isBothSigned && IntTraits::is32Bit && IntTraits::isLT64Bit, + IntZone_IntLT32_Int32 = SafeIntCompare::isBothSigned && IntTraits::isLT32Bit && IntTraits::is32Bit, + IntZone_Int64_Int64 = SafeIntCompare::isBothSigned && IntTraits::isInt64 && IntTraits::isInt64, + IntZone_Int64_Int = SafeIntCompare::isBothSigned && IntTraits::is64Bit && IntTraits::isLT64Bit, + IntZone_IntLT64_Int64 = SafeIntCompare::isBothSigned && IntTraits::isLT64Bit && IntTraits::is64Bit, + // signed-unsigned + IntZone_IntLT32_UintLT32 = + IntTraits::isSigned && !IntTraits::isSigned && SafeIntCompare::isBothLT32Bit, + IntZone_Int32_UintLT32 = IntTraits::isInt32 && !IntTraits::isSigned && IntTraits::isLT32Bit, + IntZone_IntLT64_Uint32 = IntTraits::isSigned && IntTraits::isLT64Bit && IntTraits::isUint32, + IntZone_Int64_UintLT64 = IntTraits::isInt64 && !IntTraits::isSigned && IntTraits::isLT64Bit, + IntZone_Int_Uint64 = IntTraits::isSigned && IntTraits::isUint64 && IntTraits::isLT64Bit, + IntZone_Int64_Uint64 = IntTraits::isInt64 && IntTraits::isUint64 }; }; - // In all of the following functions, we have two versions // One for SafeInt, which throws C++ (or possibly SEH) exceptions // The non-throwing versions are for use by the helper functions that return success and failure. @@ -992,7 +1219,6 @@ template < typename T, typename U > class IntRegion // There's no real alternative to duplicating logic, but keeping the two versions // immediately next to one another will help reduce problems - // useful function to help with getting the magnitude of a negative number enum AbsMethod { @@ -1001,54 +1227,60 @@ enum AbsMethod AbsMethodNoop }; -template < typename T > +template class GetAbsMethod { public: enum { - method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt : - IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop + method = IntTraits::isLT64Bit && IntTraits::isSigned + ? AbsMethodInt + : IntTraits::isInt64 ? AbsMethodInt64 : AbsMethodNoop }; }; // let's go ahead and hard-code a dependency on the // representation of negative numbers to keep compilers from getting overly // happy with optimizing away things like -MIN_INT. -template < typename T, int > class AbsValueHelper; +template +class AbsValueHelper; -template < typename T > class AbsValueHelper < T, AbsMethodInt> +template +class AbsValueHelper { public: - static unsigned __int32 Abs( T t ) SAFEINT_NOTHROW + static unsigned __int32 Abs(T t) SAFEINT_NOTHROW { - SAFEINT_ASSERT( t < 0 ); + SAFEINT_ASSERT(t < 0); return ~(unsigned __int32)t + 1; } }; -template < typename T > class AbsValueHelper < T, AbsMethodInt64 > +template +class AbsValueHelper { public: - static unsigned __int64 Abs( T t ) SAFEINT_NOTHROW + static unsigned __int64 Abs(T t) SAFEINT_NOTHROW { - SAFEINT_ASSERT( t < 0 ); + SAFEINT_ASSERT(t < 0); return ~(unsigned __int64)t + 1; } }; -template < typename T > class AbsValueHelper < T, AbsMethodNoop > +template +class AbsValueHelper { public: - static T Abs( T t ) SAFEINT_NOTHROW + static T Abs(T t) SAFEINT_NOTHROW { // Why are you calling Abs on an unsigned number ??? - SAFEINT_ASSERT( false ); + SAFEINT_ASSERT(false); return t; } }; -template < typename T, bool > class NegationHelper; +template +class NegationHelper; // Previous versions had an assert that the type being negated was 32-bit or higher // In retrospect, this seems like something to just document // Negation will normally upcast to int @@ -1061,14 +1293,15 @@ template < typename T, bool > class NegationHelper; // -(SafeInt(ss)) // will then emit a signed int with the correct value and bitfield -template < typename T > class NegationHelper // Signed +template +class NegationHelper // Signed { public: - template - static T NegativeThrow( T t ) SAFEINT_CPP_THROW + template + static T NegativeThrow(T t) SAFEINT_CPP_THROW { // corner case - if( t != IntTraits< T >::minInt ) + if (t != IntTraits::minInt) { // cast prevents unneeded checks in the case of small ints return -t; @@ -1076,10 +1309,10 @@ template < typename T > class NegationHelper // Signed E::SafeIntOnOverflow(); } - static bool Negative( T t, T& ret ) SAFEINT_NOTHROW + static bool Negative(T t, T& ret) SAFEINT_NOTHROW { // corner case - if( t != IntTraits< T >::minInt ) + if (t != IntTraits::minInt) { // cast prevents unneeded checks in the case of small ints ret = -t; @@ -1091,10 +1324,11 @@ template < typename T > class NegationHelper // Signed // Helper classes to work keep compilers from // optimizing away negation -template < typename T > class SignedNegation; +template +class SignedNegation; -template <> -class SignedNegation +template<> +class SignedNegation { public: static signed __int32 Value(unsigned __int64 in) SAFEINT_NOTHROW @@ -1102,36 +1336,31 @@ class SignedNegation return (signed __int32)(~(unsigned __int32)in + 1); } - static signed __int32 Value(unsigned __int32 in) SAFEINT_NOTHROW - { - return (signed __int32)(~in + 1); - } + static signed __int32 Value(unsigned __int32 in) SAFEINT_NOTHROW { return (signed __int32)(~in + 1); } }; -template <> -class SignedNegation +template<> +class SignedNegation { public: - static signed __int64 Value(unsigned __int64 in) SAFEINT_NOTHROW - { - return (signed __int64)(~in + 1); - } + static signed __int64 Value(unsigned __int64 in) SAFEINT_NOTHROW { return (signed __int64)(~in + 1); } }; -template < typename T > class NegationHelper // unsigned +template +class NegationHelper // unsigned { public: - template - static T NegativeThrow( T t ) SAFEINT_CPP_THROW + template + static T NegativeThrow(T t) SAFEINT_CPP_THROW { #if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); #endif #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER #pragma warning(push) -//this avoids warnings from the unary '-' operator being applied to unsigned numbers -#pragma warning(disable:4146) +// this avoids warnings from the unary '-' operator being applied to unsigned numbers +#pragma warning(disable : 4146) #endif // Note - this could be quenched on gcc // by doing something like: @@ -1144,15 +1373,15 @@ template < typename T > class NegationHelper // unsigned #endif } - static bool Negative( T t, T& ret ) SAFEINT_NOTHROW + static bool Negative(T t, T& ret) SAFEINT_NOTHROW { - if( IntTraits::isLT32Bit ) + if (IntTraits::isLT32Bit) { // See above - SAFEINT_ASSERT( false ); + SAFEINT_ASSERT(false); } #if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); #endif // Do it this way to avoid warning ret = -t; @@ -1160,7 +1389,7 @@ template < typename T > class NegationHelper // unsigned } }; -//core logic to determine casting behavior +// core logic to determine casting behavior enum CastMethod { CastOK = 0, @@ -1174,85 +1403,115 @@ enum CastMethod CastFromBool }; - -template < typename ToType, typename FromType > +template class GetCastMethod { public: enum { - method = ( IntTraits< FromType >::isBool && - !IntTraits< ToType >::isBool ) ? CastFromBool : + method = (IntTraits::isBool && !IntTraits::isBool) + ? CastFromBool + : - ( !IntTraits< FromType >::isBool && - IntTraits< ToType >::isBool ) ? CastToBool : + (!IntTraits::isBool && IntTraits::isBool) + ? CastToBool + : - ( SafeIntCompare< ToType, FromType >::isCastOK ) ? CastOK : + (SafeIntCompare::isCastOK) + ? CastOK + : - ( ( IntTraits< ToType >::isSigned && - !IntTraits< FromType >::isSigned && - sizeof( FromType ) >= sizeof( ToType ) ) || - ( SafeIntCompare< ToType, FromType >::isBothUnsigned && - sizeof( FromType ) > sizeof( ToType ) ) ) ? CastCheckGTMax : + ((IntTraits::isSigned && !IntTraits::isSigned && + sizeof(FromType) >= sizeof(ToType)) || + (SafeIntCompare::isBothUnsigned && sizeof(FromType) > sizeof(ToType))) + ? CastCheckGTMax + : - ( !IntTraits< ToType >::isSigned && - IntTraits< FromType >::isSigned && - sizeof( ToType ) >= sizeof( FromType ) ) ? CastCheckLTZero : + (!IntTraits::isSigned && IntTraits::isSigned && + sizeof(ToType) >= sizeof(FromType)) + ? CastCheckLTZero + : - ( !IntTraits< ToType >::isSigned ) ? CastCheckSafeIntMinMaxUnsigned - : CastCheckSafeIntMinMaxSigned + (!IntTraits::isSigned) ? CastCheckSafeIntMinMaxUnsigned + : CastCheckSafeIntMinMaxSigned }; }; -template < typename FromType > class GetCastMethod < float, FromType > +template +class GetCastMethod { public: - enum{ method = CastOK }; + enum + { + method = CastOK + }; }; -template < typename FromType > class GetCastMethod < double, FromType > +template +class GetCastMethod { public: - enum{ method = CastOK }; + enum + { + method = CastOK + }; }; -template < typename FromType > class GetCastMethod < long double, FromType > +template +class GetCastMethod { public: - enum{ method = CastOK }; + enum + { + method = CastOK + }; }; -template < typename ToType > class GetCastMethod < ToType, float > +template +class GetCastMethod { public: - enum{ method = CastFromFloat }; + enum + { + method = CastFromFloat + }; }; -template < typename ToType > class GetCastMethod < ToType, double > +template +class GetCastMethod { public: - enum{ method = CastFromFloat }; + enum + { + method = CastFromFloat + }; }; -template < typename ToType > class GetCastMethod < ToType, long double > +template +class GetCastMethod { public: - enum{ method = CastFromFloat }; + enum + { + method = CastFromFloat + }; }; -template < typename T, typename U, int > class SafeCastHelper; +template +class SafeCastHelper; -template < typename T, typename U > class SafeCastHelper < T, U, CastOK > +template +class SafeCastHelper { public: - static bool Cast( U u, T& t ) SAFEINT_NOTHROW + static bool Cast(U u, T& t) SAFEINT_NOTHROW { t = (T)u; return true; } - template < typename E > - static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + template + static void CastThrow(U u, T& t) SAFEINT_CPP_THROW { t = (T)u; } @@ -1260,13 +1519,13 @@ template < typename T, typename U > class SafeCastHelper < T, U, CastOK > // special case floats and doubles // tolerate loss of precision -template < typename T, typename U > class SafeCastHelper < T, U, CastFromFloat > +template +class SafeCastHelper { public: - static bool Cast( U u, T& t ) SAFEINT_NOTHROW + static bool Cast(U u, T& t) SAFEINT_NOTHROW { - if( u <= (U)IntTraits< T >::maxInt && - u >= (U)IntTraits< T >::minInt ) + if (u <= (U)IntTraits::maxInt && u >= (U)IntTraits::minInt) { t = (T)u; return true; @@ -1274,11 +1533,10 @@ template < typename T, typename U > class SafeCastHelper < T, U, CastFromFloat > return false; } - template < typename E > - static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + template + static void CastThrow(U u, T& t) SAFEINT_CPP_THROW { - if( u <= (U)IntTraits< T >::maxInt && - u >= (U)IntTraits< T >::minInt ) + if (u <= (U)IntTraits::maxInt && u >= (U)IntTraits::minInt) { t = (T)u; return; @@ -1288,131 +1546,129 @@ template < typename T, typename U > class SafeCastHelper < T, U, CastFromFloat > }; // Match on any method where a bool is cast to type T -template < typename T > class SafeCastHelper < T, bool, CastFromBool > +template +class SafeCastHelper { public: - static bool Cast( bool b, T& t ) SAFEINT_NOTHROW + static bool Cast(bool b, T& t) SAFEINT_NOTHROW { - t = (T)( b ? 1 : 0 ); + t = (T)(b ? 1 : 0); return true; } - template < typename E > - static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW + template + static void CastThrow(bool b, T& t) SAFEINT_CPP_THROW { - t = (T)( b ? 1 : 0 ); + t = (T)(b ? 1 : 0); } }; -template < typename T > class SafeCastHelper < bool, T, CastToBool > +template +class SafeCastHelper { public: - static bool Cast( T t, bool& b ) SAFEINT_NOTHROW + static bool Cast(T t, bool& b) SAFEINT_NOTHROW { b = !!t; return true; } - template < typename E > - static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW + template + static void CastThrow(bool b, T& t) SAFEINT_CPP_THROW { b = !!t; } }; -template < typename T, typename U > class SafeCastHelper < T, U, CastCheckLTZero > +template +class SafeCastHelper { public: - static bool Cast( U u, T& t ) SAFEINT_NOTHROW + static bool Cast(U u, T& t) SAFEINT_NOTHROW { - if( u < 0 ) - return false; + if (u < 0) return false; t = (T)u; return true; } - template < typename E > - static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + template + static void CastThrow(U u, T& t) SAFEINT_CPP_THROW { - if( u < 0 ) - E::SafeIntOnOverflow(); + if (u < 0) E::SafeIntOnOverflow(); t = (T)u; } }; -template < typename T, typename U > class SafeCastHelper < T, U, CastCheckGTMax > +template +class SafeCastHelper { public: - static bool Cast( U u, T& t ) SAFEINT_NOTHROW + static bool Cast(U u, T& t) SAFEINT_NOTHROW { - if( u > (U)IntTraits< T >::maxInt ) - return false; + if (u > (U)IntTraits::maxInt) return false; t = (T)u; return true; } - template < typename E > - static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + template + static void CastThrow(U u, T& t) SAFEINT_CPP_THROW { - if( u > (U)IntTraits< T >::maxInt ) - E::SafeIntOnOverflow(); + if (u > (U)IntTraits::maxInt) E::SafeIntOnOverflow(); t = (T)u; } }; -template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxUnsigned > +template +class SafeCastHelper { public: - static bool Cast( U u, T& t ) SAFEINT_NOTHROW + static bool Cast(U u, T& t) SAFEINT_NOTHROW { // U is signed - T could be either signed or unsigned - if( u > IntTraits< T >::maxInt || u < 0 ) - return false; + if (u > IntTraits::maxInt || u < 0) return false; t = (T)u; return true; } - template < typename E > - static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + template + static void CastThrow(U u, T& t) SAFEINT_CPP_THROW { // U is signed - T could be either signed or unsigned - if( u > IntTraits< T >::maxInt || u < 0 ) - E::SafeIntOnOverflow(); + if (u > IntTraits::maxInt || u < 0) E::SafeIntOnOverflow(); t = (T)u; } }; -template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxSigned > +template +class SafeCastHelper { public: - static bool Cast( U u, T& t ) SAFEINT_NOTHROW + static bool Cast(U u, T& t) SAFEINT_NOTHROW { // T, U are signed - if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt ) - return false; + if (u > IntTraits::maxInt || u < IntTraits::minInt) return false; t = (T)u; return true; } - template < typename E > - static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + template + static void CastThrow(U u, T& t) SAFEINT_CPP_THROW { - //T, U are signed - if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt ) - E::SafeIntOnOverflow(); + // T, U are signed + if (u > IntTraits::maxInt || u < IntTraits::minInt) E::SafeIntOnOverflow(); t = (T)u; } }; -//core logic to determine whether a comparison is valid, or needs special treatment +// core logic to determine whether a comparison is valid, or needs special treatment enum ComparisonMethod { ComparisonMethod_Ok = 0, @@ -1422,26 +1678,26 @@ enum ComparisonMethod ComparisonMethod_UnsignedU }; - // Note - the standard is arguably broken in the case of some integer - // conversion operations - // For example, signed char a = -1 = 0xff - // unsigned int b = 0xffffffff - // If you then test if a < b, a value-preserving cast - // is made, and you're essentially testing - // (unsigned int)a < b == false - // - // I do not think this makes sense - if you perform - // a cast to an __int64, which can clearly preserve both value and signedness - // then you get a different and intuitively correct answer - // IMHO, -1 should be less than 4 billion - // If you prefer to retain the ANSI standard behavior - // insert #define ANSI_CONVERSIONS into your source - // Behavior differences occur in the following cases: - // 8, 16, and 32-bit signed int, unsigned 32-bit int - // any signed int, unsigned 64-bit int - // Note - the signed int must be negative to show the problem - -template < typename T, typename U > +// Note - the standard is arguably broken in the case of some integer +// conversion operations +// For example, signed char a = -1 = 0xff +// unsigned int b = 0xffffffff +// If you then test if a < b, a value-preserving cast +// is made, and you're essentially testing +// (unsigned int)a < b == false +// +// I do not think this makes sense - if you perform +// a cast to an __int64, which can clearly preserve both value and signedness +// then you get a different and intuitively correct answer +// IMHO, -1 should be less than 4 billion +// If you prefer to retain the ANSI standard behavior +// insert #define ANSI_CONVERSIONS into your source +// Behavior differences occur in the following cases: +// 8, 16, and 32-bit signed int, unsigned 32-bit int +// any signed int, unsigned 64-bit int +// Note - the signed int must be negative to show the problem + +template class ValidComparison { public: @@ -1450,131 +1706,141 @@ class ValidComparison #ifdef ANSI_CONVERSIONS method = ComparisonMethod_Ok #else - method = ( ( SafeIntCompare< T, U >::isLikeSigned ) ? ComparisonMethod_Ok : - ( ( IntTraits< T >::isSigned && sizeof(T) < 8 && sizeof(U) < 4 ) || - ( IntTraits< U >::isSigned && sizeof(T) < 4 && sizeof(U) < 8 ) ) ? ComparisonMethod_CastInt : - ( ( IntTraits< T >::isSigned && sizeof(U) < 8 ) || - ( IntTraits< U >::isSigned && sizeof(T) < 8 ) ) ? ComparisonMethod_CastInt64 : - ( !IntTraits< T >::isSigned ) ? ComparisonMethod_UnsignedT : - ComparisonMethod_UnsignedU ) + method = ((SafeIntCompare::isLikeSigned) + ? ComparisonMethod_Ok + : ((IntTraits::isSigned && sizeof(T) < 8 && sizeof(U) < 4) || + (IntTraits::isSigned && sizeof(T) < 4 && sizeof(U) < 8)) + ? ComparisonMethod_CastInt + : ((IntTraits::isSigned && sizeof(U) < 8) || (IntTraits::isSigned && sizeof(T) < 8)) + ? ComparisonMethod_CastInt64 + : (!IntTraits::isSigned) ? ComparisonMethod_UnsignedT : ComparisonMethod_UnsignedU) #endif }; }; -template class EqualityTest; +template +class EqualityTest; -template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok > +template +class EqualityTest { public: - static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( t == u ); } + static bool IsEquals(const T t, const U u) SAFEINT_NOTHROW { return (t == u); } }; -template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt > +template +class EqualityTest { public: - static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t == (int)u ); } + static bool IsEquals(const T t, const U u) SAFEINT_NOTHROW { return ((int)t == (int)u); } }; -template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 > +template +class EqualityTest { public: - static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t == (__int64)u ); } + static bool IsEquals(const T t, const U u) SAFEINT_NOTHROW { return ((__int64)t == (__int64)u); } }; -template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT > +template +class EqualityTest { public: - static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW + static bool IsEquals(const T t, const U u) SAFEINT_NOTHROW { - //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller - if( u < 0 ) - return false; + // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller + if (u < 0) return false; - //else safe to cast to type T - return ( t == (T)u ); + // else safe to cast to type T + return (t == (T)u); } }; -template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU> +template +class EqualityTest { public: - static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW + static bool IsEquals(const T t, const U u) SAFEINT_NOTHROW { - //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller - if( t < 0 ) - return false; + // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller + if (t < 0) return false; - //else safe to cast to type U - return ( (U)t == u ); + // else safe to cast to type U + return ((U)t == u); } }; -template class GreaterThanTest; +template +class GreaterThanTest; -template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok > +template +class GreaterThanTest { public: - static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( t > u ); } + static bool GreaterThan(const T t, const U u) SAFEINT_NOTHROW { return (t > u); } }; -template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt > +template +class GreaterThanTest { public: - static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t > (int)u ); } + static bool GreaterThan(const T t, const U u) SAFEINT_NOTHROW { return ((int)t > (int)u); } }; -template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 > +template +class GreaterThanTest { public: - static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t > (__int64)u ); } + static bool GreaterThan(const T t, const U u) SAFEINT_NOTHROW { return ((__int64)t > (__int64)u); } }; -template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT > +template +class GreaterThanTest { public: - static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW + static bool GreaterThan(const T t, const U u) SAFEINT_NOTHROW { // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller - if( u < 0 ) - return true; + if (u < 0) return true; // else safe to cast to type T - return ( t > (T)u ); + return (t > (T)u); } }; -template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU > +template +class GreaterThanTest { public: - static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW + static bool GreaterThan(const T t, const U u) SAFEINT_NOTHROW { // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller - if( t < 0 ) - return false; + if (t < 0) return false; // else safe to cast to type U - return ( (U)t > u ); + return ((U)t > u); } }; // Modulus is simpler than comparison, but follows much the same logic // using this set of functions, it can't fail except in a div 0 situation -template class ModulusHelper; +template +class ModulusHelper; -template class ModulusHelper +template +class ModulusHelper { public: - static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Modulus(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - if(u == 0) - return SafeIntDivideByZero; + if (u == 0) return SafeIntDivideByZero; - //trap corner case - if( CompileConst< IntTraits< U >::isSigned >::Value() ) + // trap corner case + if (CompileConst::isSigned>::Value()) { // Some compilers don't notice that this only compiles when u is signed // Add cast to make them happy - if( u == (U)-1 ) + if (u == (U)-1) { result = 0; return SafeIntNoError; @@ -1585,16 +1851,15 @@ template class ModulusHelper - static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void ModulusThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { - if(u == 0) - E::SafeIntOnDivZero(); + if (u == 0) E::SafeIntOnDivZero(); - //trap corner case - if( CompileConst< IntTraits< U >::isSigned >::Value() ) + // trap corner case + if (CompileConst::isSigned>::Value()) { - if( u == (U)-1 ) + if (u == (U)-1) { result = 0; return; @@ -1605,18 +1870,18 @@ template class ModulusHelper class ModulusHelper +template +class ModulusHelper { public: - static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Modulus(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - if(u == 0) - return SafeIntDivideByZero; + if (u == 0) return SafeIntDivideByZero; - //trap corner case - if( CompileConst< IntTraits< U >::isSigned >::Value() ) + // trap corner case + if (CompileConst::isSigned>::Value()) { - if( u == (U)-1 ) + if (u == (U)-1) { result = 0; return SafeIntNoError; @@ -1627,16 +1892,15 @@ template class ModulusHelper - static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void ModulusThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { - if(u == 0) - E::SafeIntOnDivZero(); + if (u == 0) E::SafeIntOnDivZero(); - //trap corner case - if( CompileConst< IntTraits< U >::isSigned >::Value() ) + // trap corner case + if (CompileConst::isSigned>::Value()) { - if( u == (U)-1 ) + if (u == (U)-1) { result = 0; return; @@ -1647,18 +1911,18 @@ template class ModulusHelper class ModulusHelper< T, U, ComparisonMethod_CastInt64> +template +class ModulusHelper { public: - static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Modulus(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - if(u == 0) - return SafeIntDivideByZero; + if (u == 0) return SafeIntDivideByZero; - //trap corner case - if( CompileConst< IntTraits< U >::isSigned >::Value() ) + // trap corner case + if (CompileConst::isSigned>::Value()) { - if( u == (U)-1 ) + if (u == (U)-1) { result = 0; return SafeIntNoError; @@ -1669,15 +1933,14 @@ template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_ return SafeIntNoError; } - template < typename E > - static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void ModulusThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { - if(u == 0) - E::SafeIntOnDivZero(); + if (u == 0) E::SafeIntOnDivZero(); - if( CompileConst< IntTraits< U >::isSigned >::Value() ) + if (CompileConst::isSigned>::Value()) { - if( u == (U)-1 ) + if (u == (U)-1) { result = 0; return; @@ -1689,71 +1952,69 @@ template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_ }; // T is unsigned __int64, U is any signed int -template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedT> +template +class ModulusHelper { public: - static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Modulus(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - if(u == 0) - return SafeIntDivideByZero; + if (u == 0) return SafeIntDivideByZero; // u could be negative - if so, need to convert to positive // casts below are always safe due to the way modulus works - if(u < 0) - result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs(u)); + if (u < 0) + result = (T)(t % AbsValueHelper::method>::Abs(u)); else result = (T)(t % u); return SafeIntNoError; } - template < typename E > - static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void ModulusThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { - if(u == 0) - E::SafeIntOnDivZero(); + if (u == 0) E::SafeIntOnDivZero(); // u could be negative - if so, need to convert to positive - if(u < 0) - result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u )); + if (u < 0) + result = (T)(t % AbsValueHelper::method>::Abs(u)); else result = (T)(t % u); } }; // U is unsigned __int64, T any signed int -template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedU> +template +class ModulusHelper { public: - static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Modulus(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - if(u == 0) - return SafeIntDivideByZero; + if (u == 0) return SafeIntDivideByZero; - //t could be negative - if so, need to convert to positive - if(t < 0) - result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1 ); + // t could be negative - if so, need to convert to positive + if (t < 0) + result = (T)(~(AbsValueHelper::method>::Abs(t) % u) + 1); else result = (T)((T)t % u); return SafeIntNoError; } - template < typename E > - static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void ModulusThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { - if(u == 0) - E::SafeIntOnDivZero(); + if (u == 0) E::SafeIntOnDivZero(); - //t could be negative - if so, need to convert to positive - if(t < 0) - result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1); + // t could be negative - if so, need to convert to positive + if (t < 0) + result = (T)(~(AbsValueHelper::method>::Abs(t) % u) + 1); else - result = (T)( (T)t % u ); + result = (T)((T)t % u); } }; -//core logic to determine method to check multiplication +// core logic to determine method to check multiplication enum MultiplicationState { MultiplicationState_CastInt = 0, // One or both signed, smaller than 32-bit @@ -1775,150 +2036,182 @@ enum MultiplicationState MultiplicationState_Error }; -template < typename T, typename U > +template class MultiplicationMethod { public: enum { - // unsigned-unsigned - method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? MultiplicationState_CastUint : - (IntRegion< T,U >::IntZone_Uint32_UintLT64 || - IntRegion< T,U >::IntZone_UintLT32_Uint32) ? MultiplicationState_CastUint64 : - SafeIntCompare< T,U >::isBothUnsigned && - IntTraits< T >::isUint64 && IntTraits< U >::isUint64 ? MultiplicationState_Uint64Uint64 : - (IntRegion< T,U >::IntZone_Uint64_Uint) ? MultiplicationState_Uint64Uint : - (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? MultiplicationState_UintUint64 : - // unsigned-signed - (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? MultiplicationState_CastInt : - (IntRegion< T,U >::IntZone_Uint32_IntLT64 || - IntRegion< T,U >::IntZone_UintLT32_Int32) ? MultiplicationState_CastInt64 : - (IntRegion< T,U >::IntZone_Uint64_Int) ? MultiplicationState_Uint64Int : - (IntRegion< T,U >::IntZone_UintLT64_Int64) ? MultiplicationState_UintInt64 : - (IntRegion< T,U >::IntZone_Uint64_Int64) ? MultiplicationState_Uint64Int64 : - // signed-signed - (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? MultiplicationState_CastInt : - (IntRegion< T,U >::IntZone_Int32_IntLT64 || - IntRegion< T,U >::IntZone_IntLT32_Int32) ? MultiplicationState_CastInt64 : - (IntRegion< T,U >::IntZone_Int64_Int64) ? MultiplicationState_Int64Int64 : - (IntRegion< T,U >::IntZone_Int64_Int) ? MultiplicationState_Int64Int : - (IntRegion< T,U >::IntZone_IntLT64_Int64) ? MultiplicationState_IntInt64 : - // signed-unsigned - (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? MultiplicationState_CastInt : - (IntRegion< T,U >::IntZone_Int32_UintLT32 || - IntRegion< T,U >::IntZone_IntLT64_Uint32) ? MultiplicationState_CastInt64 : - (IntRegion< T,U >::IntZone_Int64_UintLT64) ? MultiplicationState_Int64Uint : - (IntRegion< T,U >::IntZone_Int_Uint64) ? MultiplicationState_IntUint64 : - (IntRegion< T,U >::IntZone_Int64_Uint64 ? MultiplicationState_Int64Uint64 : - MultiplicationState_Error ) ) + // unsigned-unsigned + method = + (IntRegion::IntZone_UintLT32_UintLT32 + ? MultiplicationState_CastUint + : (IntRegion::IntZone_Uint32_UintLT64 || IntRegion::IntZone_UintLT32_Uint32) + ? MultiplicationState_CastUint64 + : SafeIntCompare::isBothUnsigned && IntTraits::isUint64 && IntTraits::isUint64 + ? MultiplicationState_Uint64Uint64 + : (IntRegion::IntZone_Uint64_Uint) + ? MultiplicationState_Uint64Uint + : (IntRegion::IntZone_UintLT64_Uint64) ? MultiplicationState_UintUint64 : + // unsigned-signed + (IntRegion::IntZone_UintLT32_IntLT32) + ? MultiplicationState_CastInt + : (IntRegion::IntZone_Uint32_IntLT64 || + IntRegion::IntZone_UintLT32_Int32) + ? MultiplicationState_CastInt64 + : (IntRegion::IntZone_Uint64_Int) + ? MultiplicationState_Uint64Int + : (IntRegion::IntZone_UintLT64_Int64) + ? MultiplicationState_UintInt64 + : (IntRegion::IntZone_Uint64_Int64) + ? MultiplicationState_Uint64Int64 + : + // signed-signed + (IntRegion::IntZone_IntLT32_IntLT32) + ? MultiplicationState_CastInt + : (IntRegion::IntZone_Int32_IntLT64 || + IntRegion::IntZone_IntLT32_Int32) + ? MultiplicationState_CastInt64 + : (IntRegion::IntZone_Int64_Int64) + ? MultiplicationState_Int64Int64 + : (IntRegion::IntZone_Int64_Int) + ? MultiplicationState_Int64Int + : (IntRegion:: + IntZone_IntLT64_Int64) + ? MultiplicationState_IntInt64 + : + // signed-unsigned + (IntRegion:: + IntZone_IntLT32_UintLT32) + ? MultiplicationState_CastInt + : (IntRegion:: + IntZone_Int32_UintLT32 || + IntRegion:: + IntZone_IntLT64_Uint32) + ? MultiplicationState_CastInt64 + : (IntRegion< + T, + U>:: + IntZone_Int64_UintLT64) + ? MultiplicationState_Int64Uint + : (IntRegion< + T, + U>:: + IntZone_Int_Uint64) + ? MultiplicationState_IntUint64 + : (IntRegion< + T, + U>::IntZone_Int64_Uint64 + ? MultiplicationState_Int64Uint64 + : MultiplicationState_Error)) }; }; -template class MultiplicationHelper; +template +class MultiplicationHelper; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt> +template +class MultiplicationHelper { public: - //accepts signed, both less than 32-bit - static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + // accepts signed, both less than 32-bit + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { int tmp = t * u; - if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt ) - return false; + if (tmp > IntTraits::maxInt || tmp < IntTraits::minInt) return false; ret = (T)tmp; return true; } - template < typename E > - static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + template + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { int tmp = t * u; - if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt ) - E::SafeIntOnOverflow(); + if (tmp > IntTraits::maxInt || tmp < IntTraits::minInt) E::SafeIntOnOverflow(); ret = (T)tmp; } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint > +template +class MultiplicationHelper { public: - //accepts unsigned, both less than 32-bit - static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + // accepts unsigned, both less than 32-bit + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { unsigned int tmp = (unsigned int)(t * u); - if( tmp > IntTraits< T >::maxInt ) - return false; + if (tmp > IntTraits::maxInt) return false; ret = (T)tmp; return true; } - template < typename E > - static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + template + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { - unsigned int tmp = (unsigned int)( t * u ); + unsigned int tmp = (unsigned int)(t * u); - if( tmp > IntTraits< T >::maxInt ) - E::SafeIntOnOverflow(); + if (tmp > IntTraits::maxInt) E::SafeIntOnOverflow(); ret = (T)tmp; } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt64> +template +class MultiplicationHelper { public: - //mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less - static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + // mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { __int64 tmp = (__int64)t * (__int64)u; - if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt) - return false; + if (tmp > (__int64)IntTraits::maxInt || tmp < (__int64)IntTraits::minInt) return false; ret = (T)tmp; return true; } - template < typename E > - static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + template + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { __int64 tmp = (__int64)t * (__int64)u; - if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt) - E::SafeIntOnOverflow(); + if (tmp > (__int64)IntTraits::maxInt || tmp < (__int64)IntTraits::minInt) E::SafeIntOnOverflow(); ret = (T)tmp; } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint64> +template +class MultiplicationHelper { public: - //both unsigned where at least one argument is 32-bit, and both are 32-bit or less - static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + // both unsigned where at least one argument is 32-bit, and both are 32-bit or less + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u; - if(tmp > (unsigned __int64)IntTraits< T >::maxInt) - return false; + if (tmp > (unsigned __int64)IntTraits::maxInt) return false; ret = (T)tmp; return true; } - template < typename E > - static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + template + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u; - if(tmp > (unsigned __int64)IntTraits< T >::maxInt) - E::SafeIntOnOverflow(); + if (tmp > (unsigned __int64)IntTraits::maxInt) E::SafeIntOnOverflow(); ret = (T)tmp; } @@ -1926,32 +2219,36 @@ template < typename T, typename U > class MultiplicationHelper< T, U, Multiplica // T = left arg and return type // U = right arg -template < typename T, typename U > class LargeIntRegMultiply; +template +class LargeIntRegMultiply; #if SAFEINT_USE_INTRINSICS // As usual, unsigned is easy -inline bool IntrinsicMultiplyUint64( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW +inline bool IntrinsicMultiplyUint64(const unsigned __int64& a, + const unsigned __int64& b, + unsigned __int64* pRet) SAFEINT_NOTHROW { unsigned __int64 ulHigh = 0; - *pRet = _umul128(a , b, &ulHigh); + *pRet = _umul128(a, b, &ulHigh); return ulHigh == 0; } // Signed, is not so easy -inline bool IntrinsicMultiplyInt64( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW +inline bool IntrinsicMultiplyInt64(const signed __int64& a, + const signed __int64& b, + signed __int64* pRet) SAFEINT_NOTHROW { __int64 llHigh = 0; - *pRet = _mul128(a , b, &llHigh); + *pRet = _mul128(a, b, &llHigh); // Now we need to figure out what we expect // If llHigh is 0, then treat *pRet as unsigned // If llHigh is < 0, then treat *pRet as signed - if( (a ^ b) < 0 ) + if ((a ^ b) < 0) { // Negative result expected - if( llHigh == -1 && *pRet < 0 || - llHigh == 0 && *pRet == 0 ) + if (llHigh == -1 && *pRet < 0 || llHigh == 0 && *pRet == 0) { // Everything is within range return true; @@ -1961,21 +2258,23 @@ inline bool IntrinsicMultiplyInt64( const signed __int64& a, const signed __int6 { // Result should be positive // Check for overflow - if( llHigh == 0 && (unsigned __int64)*pRet <= IntTraits< signed __int64 >::maxInt ) - return true; + if (llHigh == 0 && (unsigned __int64)*pRet <= IntTraits::maxInt) return true; } return false; } #endif -template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 > +template<> +class LargeIntRegMultiply { public: - static bool RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(const unsigned __int64& a, + const unsigned __int64& b, + unsigned __int64* pRet) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS - return IntrinsicMultiplyUint64( a, b, pRet ); + return IntrinsicMultiplyUint64(a, b, pRet); #else unsigned __int32 aHigh, aLow, bHigh, bLow; @@ -1985,22 +2284,22 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 > // Note - same approach applies for 128 bit math on a 64-bit system aHigh = (unsigned __int32)(a >> 32); - aLow = (unsigned __int32)a; + aLow = (unsigned __int32)a; bHigh = (unsigned __int32)(b >> 32); - bLow = (unsigned __int32)b; + bLow = (unsigned __int32)b; *pRet = 0; - if(aHigh == 0) + if (aHigh == 0) { - if(bHigh != 0) + if (bHigh != 0) { *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh; } } - else if(bHigh == 0) + else if (bHigh == 0) { - if(aHigh != 0) + if (aHigh != 0) { *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow; } @@ -2010,19 +2309,17 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 > return false; } - if(*pRet != 0) + if (*pRet != 0) { unsigned __int64 tmp; - if((unsigned __int32)(*pRet >> 32) != 0) - return false; + if ((unsigned __int32)(*pRet >> 32) != 0) return false; *pRet <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)bLow; *pRet += tmp; - if(*pRet < tmp) - return false; + if (*pRet < tmp) return false; return true; } @@ -2032,12 +2329,13 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 > #endif } - template < typename E > - static void RegMultiplyThrow( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(const unsigned __int64& a, + const unsigned __int64& b, + unsigned __int64* pRet) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS - if( !IntrinsicMultiplyUint64( a, b, pRet ) ) - E::SafeIntOnOverflow(); + if (!IntrinsicMultiplyUint64(a, b, pRet)) E::SafeIntOnOverflow(); #else unsigned __int32 aHigh, aLow, bHigh, bLow; @@ -2047,22 +2345,22 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 > // Note - same approach applies for 128 bit math on a 64-bit system aHigh = (unsigned __int32)(a >> 32); - aLow = (unsigned __int32)a; + aLow = (unsigned __int32)a; bHigh = (unsigned __int32)(b >> 32); - bLow = (unsigned __int32)b; + bLow = (unsigned __int32)b; *pRet = 0; - if(aHigh == 0) + if (aHigh == 0) { - if(bHigh != 0) + if (bHigh != 0) { *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh; } } - else if(bHigh == 0) + else if (bHigh == 0) { - if(aHigh != 0) + if (aHigh != 0) { *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow; } @@ -2072,19 +2370,17 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 > E::SafeIntOnOverflow(); } - if(*pRet != 0) + if (*pRet != 0) { unsigned __int64 tmp; - if((unsigned __int32)(*pRet >> 32) != 0) - E::SafeIntOnOverflow(); + if ((unsigned __int32)(*pRet >> 32) != 0) E::SafeIntOnOverflow(); *pRet <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)bLow; *pRet += tmp; - if(*pRet < tmp) - E::SafeIntOnOverflow(); + if (*pRet < tmp) E::SafeIntOnOverflow(); return; } @@ -2094,13 +2390,14 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 > } }; -template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int32 > +template<> +class LargeIntRegMultiply { public: - static bool RegMultiply( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS - return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ); + return IntrinsicMultiplyUint64(a, (unsigned __int64)b, pRet); #else unsigned __int32 aHigh, aLow; @@ -2109,25 +2406,23 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int32 > // => (aHigh * b * 2^32) + (aLow * b) aHigh = (unsigned __int32)(a >> 32); - aLow = (unsigned __int32)a; + aLow = (unsigned __int32)a; *pRet = 0; - if(aHigh != 0) + if (aHigh != 0) { *pRet = (unsigned __int64)aHigh * (unsigned __int64)b; unsigned __int64 tmp; - if((unsigned __int32)(*pRet >> 32) != 0) - return false; + if ((unsigned __int32)(*pRet >> 32) != 0) return false; *pRet <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)b; *pRet += tmp; - if(*pRet < tmp) - return false; + if (*pRet < tmp) return false; return true; } @@ -2137,12 +2432,13 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int32 > #endif } - template < typename E > - static void RegMultiplyThrow( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(const unsigned __int64& a, + unsigned __int32 b, + unsigned __int64* pRet) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS - if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) ) - E::SafeIntOnOverflow(); + if (!IntrinsicMultiplyUint64(a, (unsigned __int64)b, pRet)) E::SafeIntOnOverflow(); #else unsigned __int32 aHigh, aLow; @@ -2151,25 +2447,23 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int32 > // => (aHigh * b * 2^32) + (aLow * b) aHigh = (unsigned __int32)(a >> 32); - aLow = (unsigned __int32)a; + aLow = (unsigned __int32)a; *pRet = 0; - if(aHigh != 0) + if (aHigh != 0) { *pRet = (unsigned __int64)aHigh * (unsigned __int64)b; unsigned __int64 tmp; - if((unsigned __int32)(*pRet >> 32) != 0) - E::SafeIntOnOverflow(); + if ((unsigned __int32)(*pRet >> 32) != 0) E::SafeIntOnOverflow(); *pRet <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)b; *pRet += tmp; - if(*pRet < tmp) - E::SafeIntOnOverflow(); + if (*pRet < tmp) E::SafeIntOnOverflow(); return; } @@ -2180,72 +2474,71 @@ template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int32 > } }; -template<> class LargeIntRegMultiply< unsigned __int64, signed __int32 > +template<> +class LargeIntRegMultiply { public: // Intrinsic not needed - static bool RegMultiply( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet) SAFEINT_NOTHROW { - if( b < 0 && a != 0 ) - return false; + if (b < 0 && a != 0) return false; #if SAFEINT_USE_INTRINSICS - return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ); + return IntrinsicMultiplyUint64(a, (unsigned __int64)b, pRet); #else - return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply(a, (unsigned __int32)b, pRet); + return LargeIntRegMultiply::RegMultiply(a, (unsigned __int32)b, pRet); #endif } - template < typename E > - static void RegMultiplyThrow( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet) SAFEINT_CPP_THROW { - if( b < 0 && a != 0 ) - E::SafeIntOnOverflow(); + if (b < 0 && a != 0) E::SafeIntOnOverflow(); #if SAFEINT_USE_INTRINSICS - if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) ) - E::SafeIntOnOverflow(); + if (!IntrinsicMultiplyUint64(a, (unsigned __int64)b, pRet)) E::SafeIntOnOverflow(); #else - LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( a, (unsigned __int32)b, pRet ); + LargeIntRegMultiply::template RegMultiplyThrow( + a, (unsigned __int32)b, pRet); #endif } }; -template<> class LargeIntRegMultiply< unsigned __int64, signed __int64 > +template<> +class LargeIntRegMultiply { public: - static bool RegMultiply( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet) SAFEINT_NOTHROW { - if( b < 0 && a != 0 ) - return false; + if (b < 0 && a != 0) return false; #if SAFEINT_USE_INTRINSICS - return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ); + return IntrinsicMultiplyUint64(a, (unsigned __int64)b, pRet); #else - return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply(a, (unsigned __int64)b, pRet); + return LargeIntRegMultiply::RegMultiply(a, (unsigned __int64)b, pRet); #endif } - template < typename E > - static void RegMultiplyThrow( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet) SAFEINT_CPP_THROW { - if( b < 0 && a != 0 ) - E::SafeIntOnOverflow(); + if (b < 0 && a != 0) E::SafeIntOnOverflow(); #if SAFEINT_USE_INTRINSICS - if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) ) - E::SafeIntOnOverflow(); + if (!IntrinsicMultiplyUint64(a, (unsigned __int64)b, pRet)) E::SafeIntOnOverflow(); #else - LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet ); + LargeIntRegMultiply::template RegMultiplyThrow( + a, (unsigned __int64)b, pRet); #endif } }; -template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 > +template<> +class LargeIntRegMultiply { public: // Devolves into ordinary 64-bit calculation - static bool RegMultiply( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(signed __int32 a, const unsigned __int64& b, signed __int32* pRet) SAFEINT_NOTHROW { unsigned __int32 bHigh, bLow; bool fIsNegative = false; @@ -2258,25 +2551,23 @@ template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 > // If the first part is != 0, fail bHigh = (unsigned __int32)(b >> 32); - bLow = (unsigned __int32)b; + bLow = (unsigned __int32)b; *pRet = 0; - if(bHigh != 0 && a != 0) - return false; + if (bHigh != 0 && a != 0) return false; - if( a < 0 ) + if (a < 0) { - - a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); + a = (signed __int32)AbsValueHelper::method>::Abs(a); fIsNegative = true; } unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow; - if( !fIsNegative ) + if (!fIsNegative) { - if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int32)tmp; return true; @@ -2284,9 +2575,9 @@ template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 > } else { - if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 ) + if (tmp <= (unsigned __int64)IntTraits::maxInt + 1) { - *pRet = SignedNegation< signed __int32 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return true; } } @@ -2294,8 +2585,8 @@ template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 > return false; } - template < typename E > - static void RegMultiplyThrow( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(signed __int32 a, const unsigned __int64& b, signed __int32* pRet) SAFEINT_CPP_THROW { unsigned __int32 bHigh, bLow; bool fIsNegative = false; @@ -2305,24 +2596,23 @@ template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 > // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) bHigh = (unsigned __int32)(b >> 32); - bLow = (unsigned __int32)b; + bLow = (unsigned __int32)b; *pRet = 0; - if(bHigh != 0 && a != 0) - E::SafeIntOnOverflow(); + if (bHigh != 0 && a != 0) E::SafeIntOnOverflow(); - if( a < 0 ) + if (a < 0) { - a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); + a = (signed __int32)AbsValueHelper::method>::Abs(a); fIsNegative = true; } unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow; - if( !fIsNegative ) + if (!fIsNegative) { - if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int32)tmp; return; @@ -2330,9 +2620,9 @@ template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 > } else { - if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 ) + if (tmp <= (unsigned __int64)IntTraits::maxInt + 1) { - *pRet = SignedNegation< signed __int32 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return; } } @@ -2341,11 +2631,12 @@ template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 > } }; -template<> class LargeIntRegMultiply< unsigned __int32, unsigned __int64 > +template<> +class LargeIntRegMultiply { public: // Becomes ordinary 64-bit multiplication, intrinsic not needed - static bool RegMultiply( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet) SAFEINT_NOTHROW { // Consider that a*b can be broken up into: // (bHigh * 2^32 + bLow) * a @@ -2353,60 +2644,61 @@ template<> class LargeIntRegMultiply< unsigned __int32, unsigned __int64 > // In this case, the result must fit into 32-bits // If bHigh != 0 && a != 0, immediate error. - if( (unsigned __int32)(b >> 32) != 0 && a != 0 ) - return false; + if ((unsigned __int32)(b >> 32) != 0 && a != 0) return false; unsigned __int64 tmp = b * (unsigned __int64)a; - if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow + if ((unsigned __int32)(tmp >> 32) != 0) // overflow return false; *pRet = (unsigned __int32)tmp; return true; } - template < typename E > - static void RegMultiplyThrow( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(unsigned __int32 a, + const unsigned __int64& b, + unsigned __int32* pRet) SAFEINT_CPP_THROW { - if( (unsigned __int32)(b >> 32) != 0 && a != 0 ) - E::SafeIntOnOverflow(); + if ((unsigned __int32)(b >> 32) != 0 && a != 0) E::SafeIntOnOverflow(); unsigned __int64 tmp = b * (unsigned __int64)a; - if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow + if ((unsigned __int32)(tmp >> 32) != 0) // overflow E::SafeIntOnOverflow(); *pRet = (unsigned __int32)tmp; } }; -template<> class LargeIntRegMultiply< unsigned __int32, signed __int64 > +template<> +class LargeIntRegMultiply { public: - static bool RegMultiply( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet) SAFEINT_NOTHROW { - if( b < 0 && a != 0 ) - return false; - return LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( a, (unsigned __int64)b, pRet ); + if (b < 0 && a != 0) return false; + return LargeIntRegMultiply::RegMultiply(a, (unsigned __int64)b, pRet); } - template < typename E > - static void RegMultiplyThrow( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet) SAFEINT_CPP_THROW { - if( b < 0 && a != 0 ) - E::SafeIntOnOverflow(); + if (b < 0 && a != 0) E::SafeIntOnOverflow(); - LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet ); + LargeIntRegMultiply::template RegMultiplyThrow( + a, (unsigned __int64)b, pRet); } }; -template<> class LargeIntRegMultiply< signed __int64, signed __int64 > +template<> +class LargeIntRegMultiply { public: - static bool RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(const signed __int64& a, const signed __int64& b, signed __int64* pRet) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS - return IntrinsicMultiplyInt64( a, b, pRet ); + return IntrinsicMultiplyInt64(a, b, pRet); #else bool aNegative = false; bool bNegative = false; @@ -2415,34 +2707,35 @@ template<> class LargeIntRegMultiply< signed __int64, signed __int64 > __int64 a1 = a; __int64 b1 = b; - if( a1 < 0 ) + if (a1 < 0) { aNegative = true; - a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + a1 = (signed __int64)AbsValueHelper::method>::Abs(a1); } - if( b1 < 0 ) + if (b1 < 0) { bNegative = true; - b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); + b1 = (signed __int64)AbsValueHelper::method>::Abs(b1); } - if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, &tmp ) ) + if (LargeIntRegMultiply::RegMultiply( + (unsigned __int64)a1, (unsigned __int64)b1, &tmp)) { // The unsigned multiplication didn't overflow - if( aNegative ^ bNegative ) + if (aNegative ^ bNegative) { // Result must be negative - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + if (tmp <= (unsigned __int64)IntTraits::minInt) { - *pRet = SignedNegation< signed __int64 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return true; } } else { // Result must be positive - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int64)tmp; return true; @@ -2454,12 +2747,13 @@ template<> class LargeIntRegMultiply< signed __int64, signed __int64 > #endif } - template < typename E > - static void RegMultiplyThrow( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(const signed __int64& a, + const signed __int64& b, + signed __int64* pRet) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS - if( !IntrinsicMultiplyInt64( a, b, pRet ) ) - E::SafeIntOnOverflow(); + if (!IntrinsicMultiplyInt64(a, b, pRet)) E::SafeIntOnOverflow(); #else bool aNegative = false; bool bNegative = false; @@ -2468,34 +2762,35 @@ template<> class LargeIntRegMultiply< signed __int64, signed __int64 > __int64 a1 = a; __int64 b1 = b; - if( a1 < 0 ) + if (a1 < 0) { aNegative = true; - a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + a1 = (signed __int64)AbsValueHelper::method>::Abs(a1); } - if( b1 < 0 ) + if (b1 < 0) { bNegative = true; - b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); + b1 = (signed __int64)AbsValueHelper::method>::Abs(b1); } - LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, (unsigned __int64)b1, &tmp ); + LargeIntRegMultiply::template RegMultiplyThrow( + (unsigned __int64)a1, (unsigned __int64)b1, &tmp); // The unsigned multiplication didn't overflow or we'd be in the exception handler - if( aNegative ^ bNegative ) + if (aNegative ^ bNegative) { // Result must be negative - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + if (tmp <= (unsigned __int64)IntTraits::minInt) { - *pRet = SignedNegation< signed __int64 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return; } } else { // Result must be positive - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int64)tmp; return; @@ -2507,40 +2802,41 @@ template<> class LargeIntRegMultiply< signed __int64, signed __int64 > } }; -template<> class LargeIntRegMultiply< signed __int64, unsigned __int32 > +template<> +class LargeIntRegMultiply { public: - static bool RegMultiply( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(const signed __int64& a, unsigned __int32 b, signed __int64* pRet) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS - return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ); + return IntrinsicMultiplyInt64(a, (signed __int64)b, pRet); #else bool aNegative = false; unsigned __int64 tmp; __int64 a1 = a; - if( a1 < 0 ) + if (a1 < 0) { aNegative = true; - a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + a1 = (signed __int64)AbsValueHelper::method>::Abs(a1); } - if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, b, &tmp ) ) + if (LargeIntRegMultiply::RegMultiply((unsigned __int64)a1, b, &tmp)) { // The unsigned multiplication didn't overflow - if( aNegative ) + if (aNegative) { // Result must be negative - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + if (tmp <= (unsigned __int64)IntTraits::minInt) { - *pRet = SignedNegation< signed __int64 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return true; } } else { // Result must be positive - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int64)tmp; return true; @@ -2552,39 +2848,39 @@ template<> class LargeIntRegMultiply< signed __int64, unsigned __int32 > #endif } - template < typename E > - static void RegMultiplyThrow( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(const signed __int64& a, unsigned __int32 b, signed __int64* pRet) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS - if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) ) - E::SafeIntOnOverflow(); + if (!IntrinsicMultiplyInt64(a, (signed __int64)b, pRet)) E::SafeIntOnOverflow(); #else bool aNegative = false; unsigned __int64 tmp; __int64 a1 = a; - if( a1 < 0 ) + if (a1 < 0) { aNegative = true; - a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + a1 = (signed __int64)AbsValueHelper::method>::Abs(a1); } - LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, b, &tmp ); + LargeIntRegMultiply::template RegMultiplyThrow( + (unsigned __int64)a1, b, &tmp); // The unsigned multiplication didn't overflow - if( aNegative ) + if (aNegative) { // Result must be negative - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + if (tmp <= (unsigned __int64)IntTraits::minInt) { - *pRet = SignedNegation< signed __int64 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return; } } else { // Result must be positive - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int64)tmp; return; @@ -2596,13 +2892,14 @@ template<> class LargeIntRegMultiply< signed __int64, unsigned __int32 > } }; -template<> class LargeIntRegMultiply< signed __int64, signed __int32 > +template<> +class LargeIntRegMultiply { public: - static bool RegMultiply( const signed __int64& a, signed __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(const signed __int64& a, signed __int32 b, signed __int64* pRet) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS - return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ); + return IntrinsicMultiplyInt64(a, (signed __int64)b, pRet); #else bool aNegative = false; bool bNegative = false; @@ -2611,34 +2908,35 @@ template<> class LargeIntRegMultiply< signed __int64, signed __int32 > __int64 a1 = a; __int64 b1 = b; - if( a1 < 0 ) + if (a1 < 0) { aNegative = true; - a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + a1 = (signed __int64)AbsValueHelper::method>::Abs(a1); } - if( b1 < 0 ) + if (b1 < 0) { bNegative = true; - b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); + b1 = (signed __int64)AbsValueHelper::method>::Abs(b1); } - if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, (unsigned __int32)b1, &tmp ) ) + if (LargeIntRegMultiply::RegMultiply( + (unsigned __int64)a1, (unsigned __int32)b1, &tmp)) { // The unsigned multiplication didn't overflow - if( aNegative ^ bNegative ) + if (aNegative ^ bNegative) { // Result must be negative - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + if (tmp <= (unsigned __int64)IntTraits::minInt) { - *pRet = SignedNegation< signed __int64 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return true; } } else { // Result must be positive - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int64)tmp; return true; @@ -2650,46 +2948,46 @@ template<> class LargeIntRegMultiply< signed __int64, signed __int32 > #endif } - template < typename E > - static void RegMultiplyThrow( signed __int64 a, signed __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(signed __int64 a, signed __int32 b, signed __int64* pRet) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS - if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) ) - E::SafeIntOnOverflow(); + if (!IntrinsicMultiplyInt64(a, (signed __int64)b, pRet)) E::SafeIntOnOverflow(); #else bool aNegative = false; bool bNegative = false; unsigned __int64 tmp; - if( a < 0 ) + if (a < 0) { aNegative = true; - a = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a); + a = (signed __int64)AbsValueHelper::method>::Abs(a); } - if( b < 0 ) + if (b < 0) { bNegative = true; - b = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(b); + b = (signed __int32)AbsValueHelper::method>::Abs(b); } - LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a, (unsigned __int32)b, &tmp ); + LargeIntRegMultiply::template RegMultiplyThrow( + (unsigned __int64)a, (unsigned __int32)b, &tmp); // The unsigned multiplication didn't overflow - if( aNegative ^ bNegative ) + if (aNegative ^ bNegative) { // Result must be negative - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + if (tmp <= (unsigned __int64)IntTraits::minInt) { - *pRet = SignedNegation< signed __int64 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return; } } else { // Result must be positive - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int64)tmp; return; @@ -2701,18 +2999,18 @@ template<> class LargeIntRegMultiply< signed __int64, signed __int32 > } }; -template<> class LargeIntRegMultiply< signed __int32, signed __int64 > +template<> +class LargeIntRegMultiply { public: - static bool RegMultiply( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(signed __int32 a, const signed __int64& b, signed __int32* pRet) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS __int64 tmp; - if( IntrinsicMultiplyInt64( a, b, &tmp ) ) + if (IntrinsicMultiplyInt64(a, b, &tmp)) { - if( tmp > IntTraits< signed __int32 >::maxInt || - tmp < IntTraits< signed __int32 >::minInt ) + if (tmp > IntTraits::maxInt || tmp < IntTraits::minInt) { return false; } @@ -2728,34 +3026,35 @@ template<> class LargeIntRegMultiply< signed __int32, signed __int64 > unsigned __int32 tmp; __int64 b1 = b; - if( a < 0 ) + if (a < 0) { aNegative = true; - a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); + a = (signed __int32)AbsValueHelper::method>::Abs(a); } - if( b1 < 0 ) + if (b1 < 0) { bNegative = true; - b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); + b1 = (signed __int64)AbsValueHelper::method>::Abs(b1); } - if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( (unsigned __int32)a, (unsigned __int64)b1, &tmp ) ) + if (LargeIntRegMultiply::RegMultiply( + (unsigned __int32)a, (unsigned __int64)b1, &tmp)) { // The unsigned multiplication didn't overflow - if( aNegative ^ bNegative ) + if (aNegative ^ bNegative) { // Result must be negative - if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt ) + if (tmp <= (unsigned __int32)IntTraits::minInt) { - *pRet = SignedNegation< signed __int32 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return true; } } else { // Result must be positive - if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt ) + if (tmp <= (unsigned __int32)IntTraits::maxInt) { *pRet = (signed __int32)tmp; return true; @@ -2767,16 +3066,15 @@ template<> class LargeIntRegMultiply< signed __int32, signed __int64 > #endif } - template < typename E > - static void RegMultiplyThrow( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(signed __int32 a, const signed __int64& b, signed __int32* pRet) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS __int64 tmp; - if( IntrinsicMultiplyInt64( a, b, &tmp ) ) + if (IntrinsicMultiplyInt64(a, b, &tmp)) { - if( tmp > IntTraits< signed __int32 >::maxInt || - tmp < IntTraits< signed __int32 >::minInt ) + if (tmp > IntTraits::maxInt || tmp < IntTraits::minInt) { E::SafeIntOnOverflow(); } @@ -2792,34 +3090,35 @@ template<> class LargeIntRegMultiply< signed __int32, signed __int64 > unsigned __int32 tmp; signed __int64 b2 = b; - if( a < 0 ) + if (a < 0) { aNegative = true; - a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); + a = (signed __int32)AbsValueHelper::method>::Abs(a); } - if( b < 0 ) + if (b < 0) { bNegative = true; - b2 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b2); + b2 = (signed __int64)AbsValueHelper::method>::Abs(b2); } - LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)a, (unsigned __int64)b2, &tmp ); + LargeIntRegMultiply::template RegMultiplyThrow( + (unsigned __int32)a, (unsigned __int64)b2, &tmp); // The unsigned multiplication didn't overflow - if( aNegative ^ bNegative ) + if (aNegative ^ bNegative) { // Result must be negative - if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt ) + if (tmp <= (unsigned __int32)IntTraits::minInt) { - *pRet = SignedNegation< signed __int32 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return; } } else { // Result must be positive - if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt ) + if (tmp <= (unsigned __int32)IntTraits::maxInt) { *pRet = (signed __int32)tmp; return; @@ -2831,39 +3130,41 @@ template<> class LargeIntRegMultiply< signed __int32, signed __int64 > } }; -template<> class LargeIntRegMultiply< signed __int64, unsigned __int64 > +template<> +class LargeIntRegMultiply { public: // Leave this one as-is - will call unsigned intrinsic internally - static bool RegMultiply( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW + static bool RegMultiply(const signed __int64& a, const unsigned __int64& b, signed __int64* pRet) SAFEINT_NOTHROW { bool aNegative = false; unsigned __int64 tmp; __int64 a1 = a; - if( a1 < 0 ) + if (a1 < 0) { aNegative = true; - a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + a1 = (signed __int64)AbsValueHelper::method>::Abs(a1); } - if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) ) + if (LargeIntRegMultiply::RegMultiply( + (unsigned __int64)a1, (unsigned __int64)b, &tmp)) { // The unsigned multiplication didn't overflow - if( aNegative ) + if (aNegative) { // Result must be negative - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + if (tmp <= (unsigned __int64)IntTraits::minInt) { - *pRet = SignedNegation< signed __int64 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return true; } } else { // Result must be positive - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int64)tmp; return true; @@ -2874,35 +3175,38 @@ template<> class LargeIntRegMultiply< signed __int64, unsigned __int64 > return false; } - template < typename E > - static void RegMultiplyThrow( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW + template + static void RegMultiplyThrow(const signed __int64& a, + const unsigned __int64& b, + signed __int64* pRet) SAFEINT_CPP_THROW { bool aNegative = false; unsigned __int64 tmp; __int64 a1 = a; - if( a1 < 0 ) + if (a1 < 0) { aNegative = true; - a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + a1 = (signed __int64)AbsValueHelper::method>::Abs(a1); } - if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) ) + if (LargeIntRegMultiply::RegMultiply( + (unsigned __int64)a1, (unsigned __int64)b, &tmp)) { // The unsigned multiplication didn't overflow - if( aNegative ) + if (aNegative) { // Result must be negative - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + if (tmp <= (unsigned __int64)IntTraits::minInt) { - *pRet = SignedNegation< signed __int64 >::Value( tmp ); + *pRet = SignedNegation::Value(tmp); return; } } else { // Result must be positive - if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { *pRet = (signed __int64)tmp; return; @@ -2919,63 +3223,70 @@ template<> class LargeIntRegMultiply< signed __int64, unsigned __int64 > // but the variables being passed to us could be long long, long int, or long, depending on // the compiler. Microsoft compiler knows that long long is the same type as __int64, but gcc doesn't -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint64 > +template +class MultiplicationHelper { public: // T, U are unsigned __int64 - static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isUint64 && IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64 && IntTraits::isUint64); unsigned __int64 t1 = t; unsigned __int64 u1 = u; - return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast(&ret) ); + return LargeIntRegMultiply::RegMultiply( + t1, u1, reinterpret_cast(&ret)); } - template < typename E > + template static void MultiplyThrow(const unsigned __int64& t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isUint64 && IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64 && IntTraits::isUint64); unsigned __int64 t1 = t; unsigned __int64 u1 = u; - LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast(&ret) ); + LargeIntRegMultiply::template RegMultiplyThrow( + t1, u1, reinterpret_cast(&ret)); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint > +template +class MultiplicationHelper { public: // T is unsigned __int64 // U is any unsigned int 32-bit or less - static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64); unsigned __int64 t1 = t; - return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast(&ret) ); + return LargeIntRegMultiply::RegMultiply( + t1, (unsigned __int32)u, reinterpret_cast(&ret)); } - template < typename E > - static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + template + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64); unsigned __int64 t1 = t; - LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast(&ret) ); + LargeIntRegMultiply::template RegMultiplyThrow( + t1, (unsigned __int32)u, reinterpret_cast(&ret)); } }; // converse of the previous function -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintUint64 > +template +class MultiplicationHelper { public: // T is any unsigned int up to 32-bit // U is unsigned __int64 static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64); unsigned __int64 u1 = u; unsigned __int32 tmp; - if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( t, u1, &tmp ) && - SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) ) + if (LargeIntRegMultiply::RegMultiply(t, u1, &tmp) && + SafeCastHelper::method>::Cast(tmp, ret)) { return true; } @@ -2983,75 +3294,83 @@ template < typename T, typename U > class MultiplicationHelper< T, U, Multiplica return false; } - template < typename E > + template static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64); unsigned __int64 u1 = u; unsigned __int32 tmp; - LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( t, u1, &tmp ); - SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret); + LargeIntRegMultiply::template RegMultiplyThrow(t, u1, &tmp); + SafeCastHelper::method>::template CastThrow(tmp, + ret); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int > +template +class MultiplicationHelper { public: // T is unsigned __int64 // U is any signed int, up to 64-bit static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64); unsigned __int64 t1 = t; - return LargeIntRegMultiply< unsigned __int64, signed __int32 >::RegMultiply(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret)); + return LargeIntRegMultiply::RegMultiply( + t1, (signed __int32)u, reinterpret_cast(&ret)); } - template < typename E > + template static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64); unsigned __int64 t1 = t; - LargeIntRegMultiply< unsigned __int64, signed __int32 >::template RegMultiplyThrow< E >(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret)); + LargeIntRegMultiply::template RegMultiplyThrow( + t1, (signed __int32)u, reinterpret_cast(&ret)); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int64 > +template +class MultiplicationHelper { public: // T is unsigned __int64 // U is __int64 static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isUint64 && IntTraits::isInt64 ); + C_ASSERT(IntTraits::isUint64 && IntTraits::isInt64); unsigned __int64 t1 = t; - __int64 u1 = u; - return LargeIntRegMultiply< unsigned __int64, __int64 >::RegMultiply(t1, u1, reinterpret_cast< unsigned __int64* >(&ret)); + __int64 u1 = u; + return LargeIntRegMultiply::RegMultiply( + t1, u1, reinterpret_cast(&ret)); } - template < typename E > + template static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isUint64 && IntTraits::isInt64 ); + C_ASSERT(IntTraits::isUint64 && IntTraits::isInt64); unsigned __int64 t1 = t; - __int64 u1 = u; - LargeIntRegMultiply< unsigned __int64, __int64 >::template RegMultiplyThrow< E >(t1, u1, reinterpret_cast< unsigned __int64* >(&ret)); + __int64 u1 = u; + LargeIntRegMultiply::template RegMultiplyThrow( + t1, u1, reinterpret_cast(&ret)); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintInt64 > +template +class MultiplicationHelper { public: // T is unsigned up to 32-bit // U is __int64 static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isInt64 ); - __int64 u1 = u; + C_ASSERT(IntTraits::isInt64); + __int64 u1 = u; unsigned __int32 tmp; - if( LargeIntRegMultiply< unsigned __int32, __int64 >::RegMultiply( (unsigned __int32)t, u1, &tmp ) && - SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) ) + if (LargeIntRegMultiply::RegMultiply((unsigned __int32)t, u1, &tmp) && + SafeCastHelper::method>::Cast(tmp, ret)) { return true; } @@ -3059,95 +3378,103 @@ template < typename T, typename U > class MultiplicationHelper< T, U, Multiplica return false; } - template < typename E > + template static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isInt64 ); - __int64 u1 = u; + C_ASSERT(IntTraits::isInt64); + __int64 u1 = u; unsigned __int32 tmp; - LargeIntRegMultiply< unsigned __int32, __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)t, u1, &tmp ); - SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret); + LargeIntRegMultiply::template RegMultiplyThrow((unsigned __int32)t, u1, &tmp); + SafeCastHelper::method>::template CastThrow(tmp, + ret); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint > +template +class MultiplicationHelper { public: // T is __int64 // U is unsigned up to 32-bit - static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isInt64 ); - __int64 t1 = t; - return LargeIntRegMultiply< __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) ); + C_ASSERT(IntTraits::isInt64); + __int64 t1 = t; + return LargeIntRegMultiply<__int64, unsigned __int32>::RegMultiply( + t1, (unsigned __int32)u, reinterpret_cast<__int64*>(&ret)); } - template < typename E > - static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + template + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isInt64 ); - __int64 t1 = t; - LargeIntRegMultiply< __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) ); + C_ASSERT(IntTraits::isInt64); + __int64 t1 = t; + LargeIntRegMultiply<__int64, unsigned __int32>::template RegMultiplyThrow( + t1, (unsigned __int32)u, reinterpret_cast<__int64*>(&ret)); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int64 > +template +class MultiplicationHelper { public: // T, U are __int64 - static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isInt64 && IntTraits::isInt64 ); - __int64 t1 = t; - __int64 u1 = u; - return LargeIntRegMultiply< __int64, __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) ); + C_ASSERT(IntTraits::isInt64 && IntTraits::isInt64); + __int64 t1 = t; + __int64 u1 = u; + return LargeIntRegMultiply<__int64, __int64>::RegMultiply(t1, u1, reinterpret_cast<__int64*>(&ret)); } - template < typename E > - static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + template + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isInt64 && IntTraits::isInt64 ); - __int64 t1 = t; - __int64 u1 = u; - LargeIntRegMultiply< __int64, __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret)); + C_ASSERT(IntTraits::isInt64 && IntTraits::isInt64); + __int64 t1 = t; + __int64 u1 = u; + LargeIntRegMultiply<__int64, __int64>::template RegMultiplyThrow(t1, u1, reinterpret_cast<__int64*>(&ret)); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int > +template +class MultiplicationHelper { public: // T is __int64 // U is signed up to 32-bit - static bool Multiply( const T& t, U u, T& ret ) SAFEINT_NOTHROW + static bool Multiply(const T& t, U u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isInt64 ); - __int64 t1 = t; - return LargeIntRegMultiply< __int64, __int32 >::RegMultiply( t1, (__int32)u, reinterpret_cast< __int64* >(&ret)); + C_ASSERT(IntTraits::isInt64); + __int64 t1 = t; + return LargeIntRegMultiply<__int64, __int32>::RegMultiply(t1, (__int32)u, reinterpret_cast<__int64*>(&ret)); } - template < typename E > - static void MultiplyThrow( const __int64& t, U u, T& ret ) SAFEINT_CPP_THROW + template + static void MultiplyThrow(const __int64& t, U u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isInt64 ); - __int64 t1 = t; - LargeIntRegMultiply< __int64, __int32 >::template RegMultiplyThrow< E >(t1, (__int32)u, reinterpret_cast< __int64* >(&ret)); + C_ASSERT(IntTraits::isInt64); + __int64 t1 = t; + LargeIntRegMultiply<__int64, __int32>::template RegMultiplyThrow( + t1, (__int32)u, reinterpret_cast<__int64*>(&ret)); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntUint64 > +template +class MultiplicationHelper { public: // T is signed up to 32-bit // U is unsigned __int64 static bool Multiply(T t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64); unsigned __int64 u1 = u; __int32 tmp; - if( LargeIntRegMultiply< __int32, unsigned __int64 >::RegMultiply( (__int32)t, u1, &tmp ) && - SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) ) + if (LargeIntRegMultiply<__int32, unsigned __int64>::RegMultiply((__int32)t, u1, &tmp) && + SafeCastHelper::method>::Cast(tmp, ret)) { return true; } @@ -3155,54 +3482,57 @@ template < typename T, typename U > class MultiplicationHelper< T, U, Multiplica return false; } - template < typename E > + template static void MultiplyThrow(T t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isUint64 ); + C_ASSERT(IntTraits::isUint64); unsigned __int64 u1 = u; __int32 tmp; - LargeIntRegMultiply< __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp ); - SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret ); + LargeIntRegMultiply<__int32, unsigned __int64>::template RegMultiplyThrow((__int32)t, u1, &tmp); + SafeCastHelper::method>::template CastThrow(tmp, ret); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint64> +template +class MultiplicationHelper { public: // T is __int64 // U is unsigned __int64 - static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isInt64 && IntTraits::isUint64 ); - __int64 t1 = t; + C_ASSERT(IntTraits::isInt64 && IntTraits::isUint64); + __int64 t1 = t; unsigned __int64 u1 = u; - return LargeIntRegMultiply< __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) ); + return LargeIntRegMultiply<__int64, unsigned __int64>::RegMultiply(t1, u1, reinterpret_cast<__int64*>(&ret)); } - template < typename E > - static void MultiplyThrow( const __int64& t, const unsigned __int64& u, T& ret ) SAFEINT_CPP_THROW + template + static void MultiplyThrow(const __int64& t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isInt64 && IntTraits::isUint64 ); - __int64 t1 = t; + C_ASSERT(IntTraits::isInt64 && IntTraits::isUint64); + __int64 t1 = t; unsigned __int64 u1 = u; - LargeIntRegMultiply< __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret) ); + LargeIntRegMultiply<__int64, unsigned __int64>::template RegMultiplyThrow( + t1, u1, reinterpret_cast<__int64*>(&ret)); } }; -template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntInt64> +template +class MultiplicationHelper { public: // T is signed, up to 32-bit // U is __int64 - static bool Multiply( T t, const U& u, T& ret ) SAFEINT_NOTHROW + static bool Multiply(T t, const U& u, T& ret) SAFEINT_NOTHROW { - C_ASSERT( IntTraits::isInt64 ); + C_ASSERT(IntTraits::isInt64); __int64 u1 = u; __int32 tmp; - if( LargeIntRegMultiply< __int32, __int64 >::RegMultiply( (__int32)t, u1, &tmp ) && - SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) ) + if (LargeIntRegMultiply<__int32, __int64>::RegMultiply((__int32)t, u1, &tmp) && + SafeCastHelper::method>::Cast(tmp, ret)) { return true; } @@ -3210,15 +3540,15 @@ template < typename T, typename U > class MultiplicationHelper< T, U, Multiplica return false; } - template < typename E > + template static void MultiplyThrow(T t, const U& u, T& ret) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits::isInt64 ); + C_ASSERT(IntTraits::isInt64); __int64 u1 = u; __int32 tmp; - LargeIntRegMultiply< __int32, __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp ); - SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret ); + LargeIntRegMultiply<__int32, __int64>::template RegMultiplyThrow((__int32)t, u1, &tmp); + SafeCastHelper::method>::template CastThrow(tmp, ret); } }; @@ -3232,82 +3562,85 @@ enum DivisionState DivisionState_SignedSigned }; -template < typename T, typename U > class DivisionMethod +template +class DivisionMethod { public: enum { - method = (SafeIntCompare< T, U >::isBothUnsigned ? DivisionState_OK : - (!IntTraits< T >::isSigned && IntTraits< U >::isSigned) ? DivisionState_UnsignedSigned : - (IntTraits< T >::isSigned && - IntTraits< U >::isUint32 && - IntTraits< T >::isLT64Bit) ? DivisionState_SignedUnsigned32 : - (IntTraits< T >::isSigned && IntTraits< U >::isUint64) ? DivisionState_SignedUnsigned64 : - (IntTraits< T >::isSigned && !IntTraits< U >::isSigned) ? DivisionState_SignedUnsigned : - DivisionState_SignedSigned) + method = + (SafeIntCompare::isBothUnsigned + ? DivisionState_OK + : (!IntTraits::isSigned && IntTraits::isSigned) + ? DivisionState_UnsignedSigned + : (IntTraits::isSigned && IntTraits::isUint32 && IntTraits::isLT64Bit) + ? DivisionState_SignedUnsigned32 + : (IntTraits::isSigned && IntTraits::isUint64) + ? DivisionState_SignedUnsigned64 + : (IntTraits::isSigned && !IntTraits::isSigned) ? DivisionState_SignedUnsigned + : DivisionState_SignedSigned) }; }; -template < typename T, typename U, int state > class DivisionHelper; +template +class DivisionHelper; -template < typename T, typename U > class DivisionHelper< T, U, DivisionState_OK > +template +class DivisionHelper { public: - static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Divide(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - if( u == 0 ) - return SafeIntDivideByZero; + if (u == 0) return SafeIntDivideByZero; - if( t == 0 ) + if (t == 0) { result = 0; return SafeIntNoError; } - result = (T)( t/u ); + result = (T)(t / u); return SafeIntNoError; } - template < typename E > - static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void DivideThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { - if( u == 0 ) - E::SafeIntOnDivZero(); + if (u == 0) E::SafeIntOnDivZero(); - if( t == 0 ) + if (t == 0) { result = 0; return; } - result = (T)( t/u ); + result = (T)(t / u); } }; -template < typename T, typename U > class DivisionHelper< T, U, DivisionState_UnsignedSigned> +template +class DivisionHelper { public: - static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Divide(const T& t, const U& u, T& result) SAFEINT_NOTHROW { + if (u == 0) return SafeIntDivideByZero; - if( u == 0 ) - return SafeIntDivideByZero; - - if( t == 0 ) + if (t == 0) { result = 0; return SafeIntNoError; } - if( u > 0 ) + if (u > 0) { - result = (T)( t/u ); + result = (T)(t / u); return SafeIntNoError; } // it is always an error to try and divide an unsigned number by a negative signed number // unless u is bigger than t - if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t ) + if (AbsValueHelper::method>::Abs(u) > t) { result = 0; return SafeIntNoError; @@ -3316,28 +3649,26 @@ template < typename T, typename U > class DivisionHelper< T, U, DivisionState_Un return SafeIntArithmeticOverflow; } - template < typename E > - static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void DivideThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { + if (u == 0) E::SafeIntOnDivZero(); - if( u == 0 ) - E::SafeIntOnDivZero(); - - if( t == 0 ) + if (t == 0) { result = 0; return; } - if( u > 0 ) + if (u > 0) { - result = (T)( t/u ); + result = (T)(t / u); return; } // it is always an error to try and divide an unsigned number by a negative signed number // unless u is bigger than t - if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t ) + if (AbsValueHelper::method>::Abs(u) > t) { result = 0; return; @@ -3347,15 +3678,15 @@ template < typename T, typename U > class DivisionHelper< T, U, DivisionState_Un } }; -template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned32 > +template +class DivisionHelper { public: - static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Divide(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - if( u == 0 ) - return SafeIntDivideByZero; + if (u == 0) return SafeIntDivideByZero; - if( t == 0 ) + if (t == 0) { result = 0; return SafeIntNoError; @@ -3365,23 +3696,23 @@ template < typename T, typename U > class DivisionHelper< T, U, DivisionState_Si // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional - if( t > 0 ) - result = (T)( t/u ); + if (t > 0) + result = (T)(t / u); else - result = (T)( (__int64)t/(__int64)u ); + result = (T)((__int64)t / (__int64)u); return SafeIntNoError; } - template < typename E > - static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void DivideThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { - if( u == 0 ) + if (u == 0) { E::SafeIntOnDivZero(); } - if( t == 0 ) + if (t == 0) { result = 0; return; @@ -3391,41 +3722,42 @@ template < typename T, typename U > class DivisionHelper< T, U, DivisionState_Si // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional - if( t > 0 ) - result = (T)( t/u ); + if (t > 0) + result = (T)(t / u); else - result = (T)( (__int64)t/(__int64)u ); + result = (T)((__int64)t / (__int64)u); } }; -template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned64 > +template +class DivisionHelper { public: - static SafeIntError Divide( const T& t, const unsigned __int64& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Divide(const T& t, const unsigned __int64& u, T& result) SAFEINT_NOTHROW { - C_ASSERT( IntTraits< U >::isUint64 ); + C_ASSERT(IntTraits::isUint64); - if( u == 0 ) + if (u == 0) { return SafeIntDivideByZero; } - if( t == 0 ) + if (t == 0) { result = 0; return SafeIntNoError; } - if( u <= (unsigned __int64)IntTraits< T >::maxInt ) + if (u <= (unsigned __int64)IntTraits::maxInt) { // Else u can safely be cast to T - if( CompileConst< sizeof( T ) < sizeof( __int64 )>::Value() ) - result = (T)( (int)t/(int)u ); + if (CompileConst::Value()) + result = (T)((int)t / (int)u); else - result = (T)((__int64)t/(__int64)u); + result = (T)((__int64)t / (__int64)u); } else // Corner case - if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt ) + if (t == IntTraits::minInt && u == (unsigned __int64)IntTraits::minInt) { // Min int divided by it's own magnitude is -1 result = -1; @@ -3437,32 +3769,32 @@ template < typename T, typename U > class DivisionHelper< T, U, DivisionState_Si return SafeIntNoError; } - template < typename E > - static void DivideThrow( const T& t, const unsigned __int64& u, T& result ) SAFEINT_CPP_THROW + template + static void DivideThrow(const T& t, const unsigned __int64& u, T& result) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits< U >::isUint64 ); + C_ASSERT(IntTraits::isUint64); - if( u == 0 ) + if (u == 0) { E::SafeIntOnDivZero(); } - if( t == 0 ) + if (t == 0) { result = 0; return; } - if( u <= (unsigned __int64)IntTraits< T >::maxInt ) + if (u <= (unsigned __int64)IntTraits::maxInt) { // Else u can safely be cast to T - if( CompileConst< sizeof( T ) < sizeof( __int64 ) >::Value() ) - result = (T)( (int)t/(int)u ); + if (CompileConst::Value()) + result = (T)((int)t / (int)u); else - result = (T)((__int64)t/(__int64)u); + result = (T)((__int64)t / (__int64)u); } else // Corner case - if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt ) + if (t == IntTraits::minInt && u == (unsigned __int64)IntTraits::minInt) { // Min int divided by it's own magnitude is -1 result = -1; @@ -3474,89 +3806,89 @@ template < typename T, typename U > class DivisionHelper< T, U, DivisionState_Si } }; -template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned> +template +class DivisionHelper { public: // T is any signed, U is unsigned and smaller than 32-bit // In this case, standard operator casting is correct - static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Divide(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - if( u == 0 ) + if (u == 0) { return SafeIntDivideByZero; } - if( t == 0 ) + if (t == 0) { result = 0; return SafeIntNoError; } - result = (T)( t/u ); + result = (T)(t / u); return SafeIntNoError; } - template < typename E > - static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void DivideThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { - if( u == 0 ) + if (u == 0) { E::SafeIntOnDivZero(); } - if( t == 0 ) + if (t == 0) { result = 0; return; } - result = (T)( t/u ); + result = (T)(t / u); } }; -template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedSigned> +template +class DivisionHelper { public: - static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + static SafeIntError Divide(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - if( u == 0 ) + if (u == 0) { return SafeIntDivideByZero; } - if( t == 0 ) + if (t == 0) { result = 0; return SafeIntNoError; } // Must test for corner case - if( t == IntTraits< T >::minInt && u == (U)-1 ) - return SafeIntArithmeticOverflow; + if (t == IntTraits::minInt && u == (U)-1) return SafeIntArithmeticOverflow; - result = (T)( t/u ); + result = (T)(t / u); return SafeIntNoError; } - template < typename E > - static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + template + static void DivideThrow(const T& t, const U& u, T& result) SAFEINT_CPP_THROW { - if(u == 0) + if (u == 0) { E::SafeIntOnDivZero(); } - if( t == 0 ) + if (t == 0) { result = 0; return; } // Must test for corner case - if( t == IntTraits< T >::minInt && u == (U)-1 ) - E::SafeIntOnOverflow(); + if (t == IntTraits::minInt && u == (U)-1) E::SafeIntOnOverflow(); - result = (T)( t/u ); + result = (T)(t / u); } }; @@ -3580,54 +3912,88 @@ enum AdditionState AdditionState_Error }; -template< typename T, typename U > +template class AdditionMethod { public: enum { - //unsigned-unsigned - method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? AdditionState_CastIntCheckMax : - (IntRegion< T,U >::IntZone_Uint32_UintLT64) ? AdditionState_CastUintCheckOverflow : - (IntRegion< T,U >::IntZone_UintLT32_Uint32) ? AdditionState_CastUintCheckOverflowMax : - (IntRegion< T,U >::IntZone_Uint64_Uint) ? AdditionState_CastUint64CheckOverflow : - (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? AdditionState_CastUint64CheckOverflowMax : - //unsigned-signed - (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax : - (IntRegion< T,U >::IntZone_Uint32_IntLT64 || - IntRegion< T,U >::IntZone_UintLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax : - (IntRegion< T,U >::IntZone_Uint64_Int || - IntRegion< T,U >::IntZone_Uint64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax : - (IntRegion< T,U >::IntZone_UintLT64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax2 : - //signed-signed - (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax : - (IntRegion< T,U >::IntZone_Int32_IntLT64 || - IntRegion< T,U >::IntZone_IntLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax : - (IntRegion< T,U >::IntZone_Int64_Int || - IntRegion< T,U >::IntZone_Int64_Int64) ? AdditionState_CastInt64CheckOverflow : - (IntRegion< T,U >::IntZone_IntLT64_Int64) ? AdditionState_CastInt64CheckOverflowSafeIntMinMax : - //signed-unsigned - (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? AdditionState_CastIntCheckMax : - (IntRegion< T,U >::IntZone_Int32_UintLT32 || - IntRegion< T,U >::IntZone_IntLT64_Uint32) ? AdditionState_CastInt64CheckMax : - (IntRegion< T,U >::IntZone_Int64_UintLT64) ? AdditionState_CastInt64CheckOverflowMax : - (IntRegion< T,U >::IntZone_Int64_Uint64) ? AdditionState_ManualCheckInt64Uint64 : - (IntRegion< T,U >::IntZone_Int_Uint64) ? AdditionState_ManualCheck : - AdditionState_Error) + // unsigned-unsigned + method = + (IntRegion::IntZone_UintLT32_UintLT32 + ? AdditionState_CastIntCheckMax + : (IntRegion::IntZone_Uint32_UintLT64) + ? AdditionState_CastUintCheckOverflow + : (IntRegion::IntZone_UintLT32_Uint32) + ? AdditionState_CastUintCheckOverflowMax + : (IntRegion::IntZone_Uint64_Uint) + ? AdditionState_CastUint64CheckOverflow + : (IntRegion::IntZone_UintLT64_Uint64) + ? AdditionState_CastUint64CheckOverflowMax + : + // unsigned-signed + (IntRegion::IntZone_UintLT32_IntLT32) + ? AdditionState_CastIntCheckSafeIntMinMax + : (IntRegion::IntZone_Uint32_IntLT64 || + IntRegion::IntZone_UintLT32_Int32) + ? AdditionState_CastInt64CheckSafeIntMinMax + : (IntRegion::IntZone_Uint64_Int || + IntRegion::IntZone_Uint64_Int64) + ? AdditionState_CastUint64CheckSafeIntMinMax + : (IntRegion::IntZone_UintLT64_Int64) + ? AdditionState_CastUint64CheckSafeIntMinMax2 + : + // signed-signed + (IntRegion::IntZone_IntLT32_IntLT32) + ? AdditionState_CastIntCheckSafeIntMinMax + : (IntRegion::IntZone_Int32_IntLT64 || + IntRegion::IntZone_IntLT32_Int32) + ? AdditionState_CastInt64CheckSafeIntMinMax + : (IntRegion::IntZone_Int64_Int || + IntRegion::IntZone_Int64_Int64) + ? AdditionState_CastInt64CheckOverflow + : (IntRegion::IntZone_IntLT64_Int64) + ? AdditionState_CastInt64CheckOverflowSafeIntMinMax + : + // signed-unsigned + (IntRegion:: + IntZone_IntLT32_UintLT32) + ? AdditionState_CastIntCheckMax + : (IntRegion:: + IntZone_Int32_UintLT32 || + IntRegion:: + IntZone_IntLT64_Uint32) + ? AdditionState_CastInt64CheckMax + : (IntRegion:: + IntZone_Int64_UintLT64) + ? AdditionState_CastInt64CheckOverflowMax + : (IntRegion:: + IntZone_Int64_Uint64) + ? AdditionState_ManualCheckInt64Uint64 + : (IntRegion< + T, + U>:: + IntZone_Int_Uint64) + ? AdditionState_ManualCheck + : AdditionState_Error) }; }; -template < typename T, typename U, int method > class AdditionHelper; +template +class AdditionHelper; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckMax > +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { - //16-bit or less unsigned addition + // 16-bit or less unsigned addition __int32 tmp = lhs + rhs; - if( tmp <= (__int32)IntTraits< T >::maxInt ) + if (tmp <= (__int32)IntTraits::maxInt) { result = (T)tmp; return true; @@ -3636,13 +4002,13 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { - //16-bit or less unsigned addition + // 16-bit or less unsigned addition __int32 tmp = lhs + rhs; - if( tmp <= (__int32)IntTraits< T >::maxInt ) + if (tmp <= (__int32)IntTraits::maxInt) { result = (T)tmp; return; @@ -3652,16 +4018,17 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflow > +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // 32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; - //we added didn't get smaller - if( tmp >= lhs ) + // we added didn't get smaller + if (tmp >= lhs) { result = (T)tmp; return true; @@ -3669,14 +4036,14 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // 32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; - //we added didn't get smaller - if( tmp >= lhs ) + // we added didn't get smaller + if (tmp >= lhs) { result = (T)tmp; return; @@ -3685,16 +4052,17 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflowMax> +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // 32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; // We added and it didn't get smaller or exceed maxInt - if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + if (tmp >= lhs && tmp <= IntTraits::maxInt) { result = (T)tmp; return true; @@ -3702,14 +4070,14 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { - //32-bit or less - both are unsigned + // 32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; // We added and it didn't get smaller or exceed maxInt - if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + if (tmp >= lhs && tmp <= IntTraits::maxInt) { result = (T)tmp; return; @@ -3718,16 +4086,17 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflow> +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it didn't get smaller - if(tmp >= lhs) + if (tmp >= lhs) { result = (T)tmp; return true; @@ -3736,14 +4105,14 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it didn't get smaller - if(tmp >= lhs) + if (tmp >= lhs) { result = (T)tmp; return; @@ -3753,16 +4122,17 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflowMax > +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { - //lhs unsigned __int64, rhs unsigned + // lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it didn't get smaller - if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + if (tmp >= lhs && tmp <= IntTraits::maxInt) { result = (T)tmp; return true; @@ -3771,14 +4141,14 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { - //lhs unsigned __int64, rhs unsigned + // lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it didn't get smaller - if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + if (tmp >= lhs && tmp <= IntTraits::maxInt) { result = (T)tmp; return; @@ -3788,15 +4158,16 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckSafeIntMinMax > +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // 16-bit or less - one or both are signed __int32 tmp = lhs + rhs; - if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt ) + if (tmp <= (__int32)IntTraits::maxInt && tmp >= (__int32)IntTraits::minInt) { result = (T)tmp; return true; @@ -3805,13 +4176,13 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // 16-bit or less - one or both are signed __int32 tmp = lhs + rhs; - if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt ) + if (tmp <= (__int32)IntTraits::maxInt && tmp >= (__int32)IntTraits::minInt) { result = (T)tmp; return; @@ -3821,15 +4192,16 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckSafeIntMinMax > +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // 32-bit or less - one or both are signed __int64 tmp = (__int64)lhs + (__int64)rhs; - if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt ) + if (tmp <= (__int64)IntTraits::maxInt && tmp >= (__int64)IntTraits::minInt) { result = (T)tmp; return true; @@ -3838,13 +4210,13 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // 32-bit or less - one or both are signed __int64 tmp = (__int64)lhs + (__int64)rhs; - if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt ) + if (tmp <= (__int64)IntTraits::maxInt && tmp >= (__int64)IntTraits::minInt) { result = (T)tmp; return; @@ -3854,15 +4226,16 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckMax > +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // 32-bit or less - lhs signed, rhs unsigned __int64 tmp = (__int64)lhs + (__int64)rhs; - if( tmp <= IntTraits< T >::maxInt ) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return true; @@ -3871,13 +4244,13 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // 32-bit or less - lhs signed, rhs unsigned __int64 tmp = (__int64)lhs + (__int64)rhs; - if( tmp <= IntTraits< T >::maxInt ) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return; @@ -3887,20 +4260,21 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax > +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs is unsigned __int64, rhs signed unsigned __int64 tmp; - if( rhs < 0 ) + if (rhs < 0) { // So we're effectively subtracting - tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); + tmp = AbsValueHelper::method>::Abs(rhs); - if( tmp <= lhs ) + if (tmp <= lhs) { result = lhs - tmp; return true; @@ -3912,7 +4286,7 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it did not become smaller - if( tmp >= lhs ) + if (tmp >= lhs) { result = (T)tmp; return true; @@ -3922,18 +4296,18 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is unsigned __int64, rhs signed unsigned __int64 tmp; - if( rhs < 0 ) + if (rhs < 0) { // So we're effectively subtracting - tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); + tmp = AbsValueHelper::method>::Abs(rhs); - if( tmp <= lhs ) + if (tmp <= lhs) { result = lhs - tmp; return; @@ -3945,7 +4319,7 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it did not become smaller - if( tmp >= lhs ) + if (tmp >= lhs) { result = (T)tmp; return; @@ -3956,17 +4330,18 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax2> +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs is unsigned and < 64-bit, rhs signed __int64 - if( rhs < 0 ) + if (rhs < 0) { - if( lhs >= ~(unsigned __int64)( rhs ) + 1 )//negation is safe, since rhs is 64-bit + if (lhs >= ~(unsigned __int64)(rhs) + 1) // negation is safe, since rhs is 64-bit { - result = (T)( lhs + rhs ); + result = (T)(lhs + rhs); return true; } } @@ -3977,7 +4352,7 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff // it is not possible for the operation above to overflow, so just check max - if( tmp <= IntTraits< T >::maxInt ) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return true; @@ -3986,15 +4361,15 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is unsigned and < 64-bit, rhs signed __int64 - if( rhs < 0 ) + if (rhs < 0) { - if( lhs >= ~(unsigned __int64)( rhs ) + 1) //negation is safe, since rhs is 64-bit + if (lhs >= ~(unsigned __int64)(rhs) + 1) // negation is safe, since rhs is 64-bit { - result = (T)( lhs + rhs ); + result = (T)(lhs + rhs); return; } } @@ -4005,7 +4380,7 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff // it is not possible for the operation above to overflow, so just check max - if( tmp <= IntTraits< T >::maxInt ) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return; @@ -4015,65 +4390,63 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflow> +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs is signed __int64, rhs signed __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs); - if( lhs >= 0 ) + if (lhs >= 0) { // mixed sign cannot overflow - if( rhs >= 0 && tmp < lhs ) - return false; + if (rhs >= 0 && tmp < lhs) return false; } else { // lhs negative - if( rhs < 0 && tmp > lhs ) - return false; + if (rhs < 0 && tmp > lhs) return false; } result = (T)tmp; return true; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is signed __int64, rhs signed __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs); - if( lhs >= 0 ) + if (lhs >= 0) { // mixed sign cannot overflow - if( rhs >= 0 && tmp < lhs ) - E::SafeIntOnOverflow(); + if (rhs >= 0 && tmp < lhs) E::SafeIntOnOverflow(); } else { // lhs negative - if( rhs < 0 && tmp > lhs ) - E::SafeIntOnOverflow(); + if (rhs < 0 && tmp > lhs) E::SafeIntOnOverflow(); } result = (T)tmp; } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowSafeIntMinMax> +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { - //rhs is signed __int64, lhs signed + // rhs is signed __int64, lhs signed __int64 tmp; - if( AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::Addition( (__int64)lhs, (__int64)rhs, tmp ) && - tmp <= IntTraits< T >::maxInt && - tmp >= IntTraits< T >::minInt ) + if (AdditionHelper<__int64, __int64, AdditionState_CastInt64CheckOverflow>::Addition( + (__int64)lhs, (__int64)rhs, tmp) && + tmp <= IntTraits::maxInt && tmp >= IntTraits::minInt) { result = (T)tmp; return true; @@ -4082,16 +4455,16 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { - //rhs is signed __int64, lhs signed + // rhs is signed __int64, lhs signed __int64 tmp; - AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::AdditionThrow< E >( (__int64)lhs, (__int64)rhs, tmp ); + AdditionHelper<__int64, __int64, AdditionState_CastInt64CheckOverflow>::AdditionThrow( + (__int64)lhs, (__int64)rhs, tmp); - if( tmp <= IntTraits< T >::maxInt && - tmp >= IntTraits< T >::minInt ) + if (tmp <= IntTraits::maxInt && tmp >= IntTraits::minInt) { result = (T)tmp; return; @@ -4101,15 +4474,16 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowMax> +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { - //lhs is signed __int64, rhs unsigned < 64-bit + // lhs is signed __int64, rhs unsigned < 64-bit unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; - if( (__int64)tmp >= lhs ) + if ((__int64)tmp >= lhs) { result = (T)(__int64)tmp; return true; @@ -4118,15 +4492,15 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is signed __int64, rhs unsigned < 64-bit // Some compilers get optimization-happy, let's thwart them unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; - if( (__int64)tmp >= lhs ) + if ((__int64)tmp >= lhs) { result = (T)(__int64)tmp; return; @@ -4136,18 +4510,19 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_C } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheckInt64Uint64 > +template +class AdditionHelper { public: - static bool Addition( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW + static bool Addition(const __int64& lhs, const unsigned __int64& rhs, __int64& result) SAFEINT_NOTHROW { - C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); + C_ASSERT(IntTraits::isInt64 && IntTraits::isUint64); // rhs is unsigned __int64, lhs __int64 // cast everything to unsigned, perform addition, then // cast back for check - this is done to stop optimizers from removing the code unsigned __int64 tmp = (unsigned __int64)lhs + rhs; - if( (__int64)tmp >= lhs ) + if ((__int64)tmp >= lhs) { result = (__int64)tmp; return true; @@ -4156,14 +4531,14 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_M return false; } - template < typename E > - static void AdditionThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const __int64& lhs, const unsigned __int64& rhs, T& result) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); + C_ASSERT(IntTraits::isInt64 && IntTraits::isUint64); // rhs is unsigned __int64, lhs __int64 unsigned __int64 tmp = (unsigned __int64)lhs + rhs; - if( (__int64)tmp >= lhs ) + if ((__int64)tmp >= lhs) { result = (__int64)tmp; return; @@ -4173,40 +4548,43 @@ template < typename T, typename U > class AdditionHelper < T, U, AdditionState_M } }; -template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheck> +template +class AdditionHelper { public: - static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Addition(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // rhs is unsigned __int64, lhs signed, 32-bit or less - if( (unsigned __int32)( rhs >> 32 ) == 0 ) + if ((unsigned __int32)(rhs >> 32) == 0) { // Now it just happens to work out that the standard behavior does what we want // Adding explicit casts to show exactly what's happening here // Note - this is tweaked to keep optimizers from tossing out the code. unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs; - if( (__int32)tmp >= lhs && SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( (__int32)tmp, result ) ) + if ((__int32)tmp >= lhs && + SafeCastHelper::method>::Cast((__int32)tmp, result)) return true; } return false; } - template < typename E > - static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void AdditionThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // rhs is unsigned __int64, lhs signed, 32-bit or less - if( (unsigned __int32)( rhs >> 32 ) == 0 ) + if ((unsigned __int32)(rhs >> 32) == 0) { // Now it just happens to work out that the standard behavior does what we want // Adding explicit casts to show exactly what's happening here unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs; - if( (__int32)tmp >= lhs ) + if ((__int32)tmp >= lhs) { - SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( (__int32)tmp, result ); + SafeCastHelper::method>::template CastThrow((__int32)tmp, + result); return; } } @@ -4242,103 +4620,133 @@ enum SubtractionState SubtractionState_Error }; -template < typename T, typename U > class SubtractionMethod +template +class SubtractionMethod { public: enum { - // unsigned-unsigned - method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || - (IntRegion< T,U >::IntZone_Uint32_UintLT64) || - (IntRegion< T,U >::IntZone_UintLT32_Uint32) || - (IntRegion< T,U >::IntZone_Uint64_Uint) || - (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned : + // unsigned-unsigned + method = + ((IntRegion::IntZone_UintLT32_UintLT32 || (IntRegion::IntZone_Uint32_UintLT64) || + (IntRegion::IntZone_UintLT32_Uint32) || (IntRegion::IntZone_Uint64_Uint) || + (IntRegion::IntZone_UintLT64_Uint64)) + ? SubtractionState_BothUnsigned + : // unsigned-signed - (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax : - (IntRegion< T,U >::IntZone_Uint32_IntLT64 || - IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax : - (IntRegion< T,U >::IntZone_Uint64_Int || - IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int : - (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 : - // signed-signed - (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax : - (IntRegion< T,U >::IntZone_Int32_IntLT64 || - IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax : - (IntRegion< T,U >::IntZone_Int64_Int || - IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int : - (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt64 : - // signed-unsigned - (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMin : - (IntRegion< T,U >::IntZone_Int32_UintLT32 || - IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMin : - (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint : - (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint64 : - (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint64 : - SubtractionState_Error) + (IntRegion::IntZone_UintLT32_IntLT32) + ? SubtractionState_CastIntCheckSafeIntMinMax + : (IntRegion::IntZone_Uint32_IntLT64 || IntRegion::IntZone_UintLT32_Int32) + ? SubtractionState_CastInt64CheckSafeIntMinMax + : (IntRegion::IntZone_Uint64_Int || IntRegion::IntZone_Uint64_Int64) + ? SubtractionState_Uint64Int + : (IntRegion::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 : + // signed-signed + (IntRegion::IntZone_IntLT32_IntLT32) + ? SubtractionState_CastIntCheckSafeIntMinMax + : (IntRegion::IntZone_Int32_IntLT64 || + IntRegion::IntZone_IntLT32_Int32) + ? SubtractionState_CastInt64CheckSafeIntMinMax + : (IntRegion::IntZone_Int64_Int || + IntRegion::IntZone_Int64_Int64) + ? SubtractionState_Int64Int + : (IntRegion::IntZone_IntLT64_Int64) + ? SubtractionState_IntInt64 + : + // signed-unsigned + (IntRegion::IntZone_IntLT32_UintLT32) + ? SubtractionState_CastIntCheckMin + : (IntRegion::IntZone_Int32_UintLT32 || + IntRegion::IntZone_IntLT64_Uint32) + ? SubtractionState_CastInt64CheckMin + : (IntRegion::IntZone_Int64_UintLT64) + ? SubtractionState_Int64Uint + : (IntRegion::IntZone_Int_Uint64) + ? SubtractionState_IntUint64 + : (IntRegion:: + IntZone_Int64_Uint64) + ? SubtractionState_Int64Uint64 + : SubtractionState_Error) }; }; // this is for the case of U - SafeInt< T, E > -template < typename T, typename U > class SubtractionMethod2 +template +class SubtractionMethod2 { public: enum { - // unsigned-unsigned - method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || - (IntRegion< T,U >::IntZone_Uint32_UintLT64) || - (IntRegion< T,U >::IntZone_UintLT32_Uint32) || - (IntRegion< T,U >::IntZone_Uint64_Uint) || - (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned2 : + // unsigned-unsigned + method = + ((IntRegion::IntZone_UintLT32_UintLT32 || (IntRegion::IntZone_Uint32_UintLT64) || + (IntRegion::IntZone_UintLT32_Uint32) || (IntRegion::IntZone_Uint64_Uint) || + (IntRegion::IntZone_UintLT64_Uint64)) + ? SubtractionState_BothUnsigned2 + : // unsigned-signed - (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 : - (IntRegion< T,U >::IntZone_Uint32_IntLT64 || - IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 : - (IntRegion< T,U >::IntZone_Uint64_Int || - IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int2 : - (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 : - // signed-signed - (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 : - (IntRegion< T,U >::IntZone_Int32_IntLT64 || - IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 : - (IntRegion< T,U >::IntZone_Int64_Int || - IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int2 : - (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt642 : - // signed-unsigned - (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 : - (IntRegion< T,U >::IntZone_Int32_UintLT32 || - IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 : - (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint2 : - (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint642 : - (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint642 : - SubtractionState_Error) + (IntRegion::IntZone_UintLT32_IntLT32) + ? SubtractionState_CastIntCheckSafeIntMinMax2 + : (IntRegion::IntZone_Uint32_IntLT64 || IntRegion::IntZone_UintLT32_Int32) + ? SubtractionState_CastInt64CheckSafeIntMinMax2 + : (IntRegion::IntZone_Uint64_Int || IntRegion::IntZone_Uint64_Int64) + ? SubtractionState_Uint64Int2 + : (IntRegion::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 : + // signed-signed + (IntRegion::IntZone_IntLT32_IntLT32) + ? SubtractionState_CastIntCheckSafeIntMinMax2 + : (IntRegion::IntZone_Int32_IntLT64 || + IntRegion::IntZone_IntLT32_Int32) + ? SubtractionState_CastInt64CheckSafeIntMinMax2 + : (IntRegion::IntZone_Int64_Int || + IntRegion::IntZone_Int64_Int64) + ? SubtractionState_Int64Int2 + : (IntRegion::IntZone_IntLT64_Int64) + ? SubtractionState_IntInt642 + : + // signed-unsigned + (IntRegion::IntZone_IntLT32_UintLT32) + ? SubtractionState_CastIntCheckSafeIntMinMax2 + : (IntRegion::IntZone_Int32_UintLT32 || + IntRegion::IntZone_IntLT64_Uint32) + ? SubtractionState_CastInt64CheckSafeIntMinMax2 + : (IntRegion::IntZone_Int64_UintLT64) + ? SubtractionState_Int64Uint2 + : (IntRegion::IntZone_Int_Uint64) + ? SubtractionState_IntUint642 + : (IntRegion:: + IntZone_Int64_Uint64) + ? SubtractionState_Int64Uint642 + : SubtractionState_Error) }; }; -template < typename T, typename U, int method > class SubtractionHelper; +template +class SubtractionHelper; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // both are unsigned - easy case - if( rhs <= lhs ) + if (rhs <= lhs) { - result = (T)( lhs - rhs ); + result = (T)(lhs - rhs); return true; } return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // both are unsigned - easy case - if( rhs <= lhs ) + if (rhs <= lhs) { - result = (T)( lhs - rhs ); + result = (T)(lhs - rhs); return; } @@ -4346,30 +4754,31 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned2 > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, U& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, U& result) SAFEINT_NOTHROW { // both are unsigned - easy case // Except we do have to check for overflow - lhs could be larger than result can hold - if( rhs <= lhs ) + if (rhs <= lhs) { T tmp = (T)(lhs - rhs); - return SafeCastHelper< U, T, GetCastMethod::method>::Cast( tmp, result); + return SafeCastHelper::method>::Cast(tmp, result); } return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, U& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, U& result) SAFEINT_CPP_THROW { // both are unsigned - easy case - if( rhs <= lhs ) + if (rhs <= lhs) { T tmp = (T)(lhs - rhs); - SafeCastHelper< U, T, GetCastMethod::method >::template CastThrow( tmp, result); + SafeCastHelper::method>::template CastThrow(tmp, result); return; } @@ -4377,16 +4786,17 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckSafeIntMinMax > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs; - if( SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result ) ) + if (SafeCastHelper::method>::Cast(tmp, result)) { result = (T)tmp; return true; @@ -4395,50 +4805,52 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs; - SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result ); + SafeCastHelper::method>::template CastThrow(tmp, result); } }; -template class SubtractionHelper< U, T, SubtractionState_CastIntCheckSafeIntMinMax2 > +template +class SubtractionHelper { public: - static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const U& lhs, const T& rhs, T& result) SAFEINT_NOTHROW { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs; - return SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result ); + return SafeCastHelper::method>::Cast(tmp, result); } - template < typename E > - static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const U& lhs, const T& rhs, T& result) SAFEINT_CPP_THROW { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs; - SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result ); + SafeCastHelper::method>::template CastThrow(tmp, result); } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckMin > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // both values are 16-bit or less // rhs is unsigned - check only minimum __int32 tmp = lhs - rhs; - if( tmp >= (__int32)IntTraits< T >::minInt ) + if (tmp >= (__int32)IntTraits::minInt) { result = (T)tmp; return true; @@ -4447,14 +4859,14 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // both values are 16-bit or less // rhs is unsigned - check only minimum __int32 tmp = lhs - rhs; - if( tmp >= (__int32)IntTraits< T >::minInt ) + if (tmp >= (__int32)IntTraits::minInt) { result = (T)tmp; return; @@ -4464,62 +4876,65 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckSafeIntMinMax > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs; - return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result ); + return SafeCastHelper::method>::Cast(tmp, result); } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs; - SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result ); + SafeCastHelper::method>::template CastThrow(tmp, result); } }; -template class SubtractionHelper< U, T, SubtractionState_CastInt64CheckSafeIntMinMax2 > +template +class SubtractionHelper { public: - static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const U& lhs, const T& rhs, T& result) SAFEINT_NOTHROW { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs; - return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result ); + return SafeCastHelper::method>::Cast(tmp, result); } - template < typename E > - static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const U& lhs, const T& rhs, T& result) SAFEINT_CPP_THROW { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs; - SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result ); + SafeCastHelper::method>::template CastThrow(tmp, result); } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckMin > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // both values are 32-bit or less // rhs is unsigned - check only minimum __int64 tmp = (__int64)lhs - (__int64)rhs; - if( tmp >= (__int64)IntTraits< T >::minInt ) + if (tmp >= (__int64)IntTraits::minInt) { result = (T)tmp; return true; @@ -4528,14 +4943,14 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // both values are 32-bit or less // rhs is unsigned - check only minimum __int64 tmp = (__int64)lhs - (__int64)rhs; - if( tmp >= (__int64)IntTraits< T >::minInt ) + if (tmp >= (__int64)IntTraits::minInt) { result = (T)tmp; return; @@ -4545,18 +4960,19 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Uint64Int > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs is an unsigned __int64, rhs signed // must first see if rhs is positive or negative - if( rhs >= 0 ) + if (rhs >= 0) { - if( (unsigned __int64)rhs <= lhs ) + if ((unsigned __int64)rhs <= lhs) { - result = (T)( lhs - (unsigned __int64)rhs ); + result = (T)(lhs - (unsigned __int64)rhs); return true; } } @@ -4564,25 +4980,24 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt { T tmp = lhs; // we're now effectively adding - result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); + result = lhs + AbsValueHelper::method>::Abs(rhs); - if(result >= tmp) - return true; + if (result >= tmp) return true; } return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is an unsigned __int64, rhs signed // must first see if rhs is positive or negative - if( rhs >= 0 ) + if (rhs >= 0) { - if( (unsigned __int64)rhs <= lhs ) + if ((unsigned __int64)rhs <= lhs) { - result = (T)( lhs - (unsigned __int64)rhs ); + result = (T)(lhs - (unsigned __int64)rhs); return; } } @@ -4590,37 +5005,37 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt { T tmp = lhs; // we're now effectively adding - result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); + result = lhs + AbsValueHelper::method>::Abs(rhs); - if(result >= tmp) - return; + if (result >= tmp) return; } E::SafeIntOnOverflow(); } }; -template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Uint64Int2 > +template +class SubtractionHelper { public: - static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const U& lhs, const T& rhs, T& result) SAFEINT_NOTHROW { // U is unsigned __int64, T is signed - if( rhs < 0 ) + if (rhs < 0) { // treat this as addition unsigned __int64 tmp; - tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs ); + tmp = lhs + (unsigned __int64)AbsValueHelper::method>::Abs(rhs); // must check for addition overflow and max - if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + if (tmp >= lhs && tmp <= IntTraits::maxInt) { result = (T)tmp; return true; } } - else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works + else if ((unsigned __int64)rhs > lhs) // now both are positive, so comparison always works { // result is negative // implies that lhs must fit into T, and result cannot overflow @@ -4633,7 +5048,7 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt // result is positive unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; - if( tmp <= IntTraits< T >::maxInt ) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return true; @@ -4643,25 +5058,25 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const U& lhs, const T& rhs, T& result) SAFEINT_CPP_THROW { // U is unsigned __int64, T is signed - if( rhs < 0 ) + if (rhs < 0) { // treat this as addition unsigned __int64 tmp; - tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs ); + tmp = lhs + (unsigned __int64)AbsValueHelper::method>::Abs(rhs); // must check for addition overflow and max - if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + if (tmp >= lhs && tmp <= IntTraits::maxInt) { result = (T)tmp; return; } } - else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works + else if ((unsigned __int64)rhs > lhs) // now both are positive, so comparison always works { // result is negative // implies that lhs must fit into T, and result cannot overflow @@ -4674,7 +5089,7 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt // result is positive unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; - if( tmp <= IntTraits< T >::maxInt ) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return; @@ -4685,18 +5100,19 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_UintInt64 > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs is an unsigned int32 or smaller, rhs signed __int64 // must first see if rhs is positive or negative - if( rhs >= 0 ) + if (rhs >= 0) { - if( (unsigned __int64)rhs <= lhs ) + if ((unsigned __int64)rhs <= lhs) { - result = (T)( lhs - (T)rhs ); + result = (T)(lhs - (T)rhs); return true; } } @@ -4705,10 +5121,10 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt // we're now effectively adding // since lhs is 32-bit, and rhs cannot exceed 2^63 // this addition cannot overflow - unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe + unsigned __int64 tmp = lhs + ~(unsigned __int64)(rhs) + 1; // negation safe // but we could exceed MaxInt - if(tmp <= IntTraits< T >::maxInt) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return true; @@ -4718,16 +5134,16 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is an unsigned int32 or smaller, rhs signed __int64 // must first see if rhs is positive or negative - if( rhs >= 0 ) + if (rhs >= 0) { - if( (unsigned __int64)rhs <= lhs ) + if ((unsigned __int64)rhs <= lhs) { - result = (T)( lhs - (T)rhs ); + result = (T)(lhs - (T)rhs); return; } } @@ -4736,10 +5152,10 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt // we're now effectively adding // since lhs is 32-bit, and rhs cannot exceed 2^63 // this addition cannot overflow - unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe + unsigned __int64 tmp = lhs + ~(unsigned __int64)(rhs) + 1; // negation safe // but we could exceed MaxInt - if(tmp <= IntTraits< T >::maxInt) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return; @@ -4750,25 +5166,26 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt } }; -template class SubtractionHelper< U, T, SubtractionState_UintInt642 > +template +class SubtractionHelper { public: - static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const U& lhs, const T& rhs, T& result) SAFEINT_NOTHROW { // U unsigned 32-bit or less, T __int64 - if( rhs >= 0 ) + if (rhs >= 0) { // overflow not possible - result = (T)( (__int64)lhs - rhs ); + result = (T)((__int64)lhs - rhs); return true; } else { // we effectively have an addition // which cannot overflow internally - unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs ); + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)(-rhs); - if( tmp <= (unsigned __int64)IntTraits< T >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { result = (T)tmp; return true; @@ -4778,23 +5195,23 @@ template class SubtractionHelper< U, T, SubtractionStat return false; } - template < typename E > - static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const U& lhs, const T& rhs, T& result) SAFEINT_CPP_THROW { // U unsigned 32-bit or less, T __int64 - if( rhs >= 0 ) + if (rhs >= 0) { // overflow not possible - result = (T)( (__int64)lhs - rhs ); + result = (T)((__int64)lhs - rhs); return; } else { // we effectively have an addition // which cannot overflow internally - unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs ); + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)(-rhs); - if( tmp <= (unsigned __int64)IntTraits< T >::maxInt ) + if (tmp <= (unsigned __int64)IntTraits::maxInt) { result = (T)tmp; return; @@ -4805,10 +5222,11 @@ template class SubtractionHelper< U, T, SubtractionStat } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Int > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs is an __int64, rhs signed (up to 64-bit) // we have essentially 4 cases: @@ -4823,8 +5241,8 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt // Note - ideally, we can order these so that true conditionals // lead to success, which enables better pipelining // It isn't practical here - if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2 - ( rhs >= 0 && tmp > lhs ) ) // condition 3 + if ((lhs >= 0 && rhs < 0 && tmp < lhs) || // condition 2 + (rhs >= 0 && tmp > lhs)) // condition 3 { return false; } @@ -4833,8 +5251,8 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt return true; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is an __int64, rhs signed (up to 64-bit) // we have essentially 4 cases: @@ -4849,8 +5267,8 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt // Note - ideally, we can order these so that true conditionals // lead to success, which enables better pipelining // It isn't practical here - if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2 - ( rhs >= 0 && tmp > lhs ) ) // condition 3 + if ((lhs >= 0 && rhs < 0 && tmp < lhs) || // condition 2 + (rhs >= 0 && tmp > lhs)) // condition 3 { E::SafeIntOnOverflow(); } @@ -4859,10 +5277,11 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt } }; -template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Int2 > +template +class SubtractionHelper { public: - static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const U& lhs, const T& rhs, T& result) SAFEINT_NOTHROW { // lhs __int64, rhs any signed int (including __int64) __int64 tmp = lhs - rhs; @@ -4874,12 +5293,11 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt // 3) lhs negative, rhs positive - check result <= lhs // 4) lhs negative, rhs negative - overflow not possible in tmp - if( lhs >= 0 ) + if (lhs >= 0) { // if both positive, overflow to negative not possible // which is why we'll explicitly check maxInt, and not call SafeCast - if( ( IntTraits< T >::isLT64Bit && tmp > IntTraits< T >::maxInt ) || - ( rhs < 0 && tmp < lhs ) ) + if ((IntTraits::isLT64Bit && tmp > IntTraits::maxInt) || (rhs < 0 && tmp < lhs)) { return false; } @@ -4887,8 +5305,7 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt else { // lhs negative - if( ( IntTraits< T >::isLT64Bit && tmp < IntTraits< T >::minInt) || - ( rhs >=0 && tmp > lhs ) ) + if ((IntTraits::isLT64Bit && tmp < IntTraits::minInt) || (rhs >= 0 && tmp > lhs)) { return false; } @@ -4898,8 +5315,8 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt return true; } - template < typename E > - static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const U& lhs, const T& rhs, T& result) SAFEINT_CPP_THROW { // lhs __int64, rhs any signed int (including __int64) __int64 tmp = lhs - rhs; @@ -4911,12 +5328,12 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt // 3) lhs negative, rhs positive - check result <= lhs // 4) lhs negative, rhs negative - overflow not possible in tmp - if( lhs >= 0 ) + if (lhs >= 0) { // if both positive, overflow to negative not possible // which is why we'll explicitly check maxInt, and not call SafeCast - if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp > IntTraits< T >::maxInt ) || - ( rhs < 0 && tmp < lhs ) ) + if ((CompileConst::isLT64Bit>::Value() && tmp > IntTraits::maxInt) || + (rhs < 0 && tmp < lhs)) { E::SafeIntOnOverflow(); } @@ -4924,8 +5341,8 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt else { // lhs negative - if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp < IntTraits< T >::minInt) || - ( rhs >=0 && tmp > lhs ) ) + if ((CompileConst::isLT64Bit>::Value() && tmp < IntTraits::minInt) || + (rhs >= 0 && tmp > lhs)) { E::SafeIntOnOverflow(); } @@ -4935,10 +5352,11 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntInt64 > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs is a 32-bit int or less, rhs __int64 // we have essentially 4 cases: @@ -4950,12 +5368,12 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); - if( lhs >= 0 ) + if (lhs >= 0) { // first case - if( rhs >= 0 ) + if (rhs >= 0) { - if( tmp >= IntTraits< T >::minInt ) + if (tmp >= IntTraits::minInt) { result = (T)tmp; return true; @@ -4964,7 +5382,7 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt else { // second case - if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + if (tmp >= lhs && tmp <= IntTraits::maxInt) { result = (T)tmp; return true; @@ -4975,9 +5393,9 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt { // lhs < 0 // third case - if( rhs >= 0 ) + if (rhs >= 0) { - if( tmp <= lhs && tmp >= IntTraits< T >::minInt ) + if (tmp <= lhs && tmp >= IntTraits::minInt) { result = (T)tmp; return true; @@ -4986,7 +5404,7 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt else { // fourth case - if( tmp <= IntTraits< T >::maxInt ) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return true; @@ -4997,8 +5415,8 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is a 32-bit int or less, rhs __int64 // we have essentially 4 cases: @@ -5010,12 +5428,12 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); - if( lhs >= 0 ) + if (lhs >= 0) { // first case - if( rhs >= 0 ) + if (rhs >= 0) { - if( tmp >= IntTraits< T >::minInt ) + if (tmp >= IntTraits::minInt) { result = (T)tmp; return; @@ -5024,7 +5442,7 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt else { // second case - if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + if (tmp >= lhs && tmp <= IntTraits::maxInt) { result = (T)tmp; return; @@ -5035,9 +5453,9 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt { // lhs < 0 // third case - if( rhs >= 0 ) + if (rhs >= 0) { - if( tmp <= lhs && tmp >= IntTraits< T >::minInt ) + if (tmp <= lhs && tmp >= IntTraits::minInt) { result = (T)tmp; return; @@ -5046,7 +5464,7 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt else { // fourth case - if( tmp <= IntTraits< T >::maxInt ) + if (tmp <= IntTraits::maxInt) { result = (T)tmp; return; @@ -5058,52 +5476,52 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt } }; -template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntInt642 > +template +class SubtractionHelper { public: - static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const U& lhs, const T& rhs, T& result) SAFEINT_NOTHROW { // lhs is any signed int32 or smaller, rhs is int64 __int64 tmp = (__int64)lhs - rhs; - if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || - ( rhs > 0 && tmp > lhs ) ) + if ((lhs >= 0 && rhs < 0 && tmp < lhs) || (rhs > 0 && tmp > lhs)) { return false; - //else OK + // else OK } result = (T)tmp; return true; } - template < typename E > - static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const U& lhs, const T& rhs, T& result) SAFEINT_CPP_THROW { // lhs is any signed int32 or smaller, rhs is int64 __int64 tmp = (__int64)lhs - rhs; - if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || - ( rhs > 0 && tmp > lhs ) ) + if ((lhs >= 0 && rhs < 0 && tmp < lhs) || (rhs > 0 && tmp > lhs)) { E::SafeIntOnOverflow(); - //else OK + // else OK } result = (T)tmp; } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs is a 64-bit int, rhs unsigned int32 or smaller // perform test as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; - if( (__int64)tmp <= lhs ) + if ((__int64)tmp <= lhs) { result = (T)(__int64)tmp; return true; @@ -5112,14 +5530,14 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is a 64-bit int, rhs unsigned int32 or smaller // perform test as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; - if( (__int64)tmp <= lhs ) + if ((__int64)tmp <= lhs) { result = (T)tmp; return; @@ -5129,16 +5547,17 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt } }; -template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint2 > +template +class SubtractionHelper { public: // lhs is __int64, rhs is unsigned 32-bit or smaller - static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const U& lhs, const T& rhs, T& result) SAFEINT_NOTHROW { // Do this as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; - if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt ) + if ((__int64)tmp <= IntTraits::maxInt && (__int64)tmp >= IntTraits::minInt) { result = (T)(__int64)tmp; return true; @@ -5147,13 +5566,13 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const U& lhs, const T& rhs, T& result) SAFEINT_CPP_THROW { // Do this as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; - if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt ) + if ((__int64)tmp <= IntTraits::maxInt && (__int64)tmp >= IntTraits::minInt) { result = (T)(__int64)tmp; return; @@ -5163,31 +5582,32 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt } }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntUint64 > +template +class SubtractionHelper { public: - static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const T& lhs, const U& rhs, T& result) SAFEINT_NOTHROW { // lhs is any signed int, rhs unsigned int64 // check against available range // We need the absolute value of IntTraits< T >::minInt // This will give it to us without extraneous compiler warnings - const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1; + const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits::maxInt + 1; - if( lhs < 0 ) + if (lhs < 0) { - if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) ) + if (rhs <= AbsMinIntT - AbsValueHelper::method>::Abs(lhs)) { - result = (T)( lhs - rhs ); + result = (T)(lhs - rhs); return true; } } else { - if( rhs <= AbsMinIntT + (unsigned __int64)lhs ) + if (rhs <= AbsMinIntT + (unsigned __int64)lhs) { - result = (T)( lhs - rhs ); + result = (T)(lhs - rhs); return true; } } @@ -5195,29 +5615,29 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const T& lhs, const U& rhs, T& result) SAFEINT_CPP_THROW { // lhs is any signed int, rhs unsigned int64 // check against available range // We need the absolute value of IntTraits< T >::minInt // This will give it to us without extraneous compiler warnings - const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1; + const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits::maxInt + 1; - if( lhs < 0 ) + if (lhs < 0) { - if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) ) + if (rhs <= AbsMinIntT - AbsValueHelper::method>::Abs(lhs)) { - result = (T)( lhs - rhs ); + result = (T)(lhs - rhs); return; } } else { - if( rhs <= AbsMinIntT + (unsigned __int64)lhs ) + if (rhs <= AbsMinIntT + (unsigned __int64)lhs) { - result = (T)( lhs - rhs ); + result = (T)(lhs - rhs); return; } } @@ -5226,13 +5646,14 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt } }; -template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntUint642 > +template +class SubtractionHelper { public: - static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const U& lhs, const T& rhs, T& result) SAFEINT_NOTHROW { // We run into upcasting problems on comparison - needs 2 checks - if( lhs >= 0 && (T)lhs >= rhs ) + if (lhs >= 0 && (T)lhs >= rhs) { result = (T)((U)lhs - (U)rhs); return true; @@ -5241,11 +5662,11 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const U& lhs, const T& rhs, T& result) SAFEINT_CPP_THROW { // We run into upcasting problems on comparison - needs 2 checks - if( lhs >= 0 && (T)lhs >= rhs ) + if (lhs >= 0 && (T)lhs >= rhs) { result = (T)((U)lhs - (U)rhs); return; @@ -5253,20 +5674,20 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt E::SafeIntOnOverflow(); } - }; -template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint64 > +template +class SubtractionHelper { public: - static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW + static bool Subtract(const __int64& lhs, const unsigned __int64& rhs, __int64& result) SAFEINT_NOTHROW { - C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); + C_ASSERT(IntTraits::isInt64 && IntTraits::isUint64); // if we subtract, and it gets larger, there's a problem // Perform test as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - rhs; - if( (__int64)tmp <= lhs ) + if ((__int64)tmp <= lhs) { result = (__int64)tmp; return true; @@ -5274,15 +5695,15 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const __int64& lhs, const unsigned __int64& rhs, T& result) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); + C_ASSERT(IntTraits::isInt64 && IntTraits::isUint64); // if we subtract, and it gets larger, there's a problem // Perform test as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - rhs; - if( (__int64)tmp <= lhs ) + if ((__int64)tmp <= lhs) { result = (__int64)tmp; return; @@ -5290,18 +5711,18 @@ template < typename T, typename U > class SubtractionHelper< T, U, SubtractionSt E::SafeIntOnOverflow(); } - }; -template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint642 > +template +class SubtractionHelper { public: // If lhs is negative, immediate problem - return must be positive, and subtracting only makes it // get smaller. If rhs > lhs, then it would also go negative, which is the other case - static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_NOTHROW + static bool Subtract(const __int64& lhs, const unsigned __int64& rhs, T& result) SAFEINT_NOTHROW { - C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 ); - if( lhs >= 0 && (unsigned __int64)lhs >= rhs ) + C_ASSERT(IntTraits::isUint64 && IntTraits::isInt64); + if (lhs >= 0 && (unsigned __int64)lhs >= rhs) { result = (unsigned __int64)lhs - rhs; return true; @@ -5310,11 +5731,11 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt return false; } - template < typename E > - static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW + template + static void SubtractThrow(const __int64& lhs, const unsigned __int64& rhs, T& result) SAFEINT_CPP_THROW { - C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 ); - if( lhs >= 0 && (unsigned __int64)lhs >= rhs ) + C_ASSERT(IntTraits::isUint64 && IntTraits::isInt64); + if (lhs >= 0 && (unsigned __int64)lhs >= rhs) { result = (unsigned __int64)lhs - rhs; return; @@ -5322,7 +5743,6 @@ template < typename U, typename T > class SubtractionHelper< U, T, SubtractionSt E::SafeIntOnOverflow(); } - }; enum BinaryState @@ -5333,7 +5753,8 @@ enum BinaryState BinaryState_Int32 }; -template < typename T, typename U > class BinaryMethod +template +class BinaryMethod { public: enum @@ -5342,12 +5763,10 @@ template < typename T, typename U > class BinaryMethod // return type is smaller than rhs OR // return type is larger and rhs is unsigned // Then binary operations won't produce unexpected results - method = ( sizeof( T ) <= sizeof( U ) || - SafeIntCompare< T, U >::isBothUnsigned || - !IntTraits< U >::isSigned ) ? BinaryState_OK : - IntTraits< U >::isInt8 ? BinaryState_Int8 : - IntTraits< U >::isInt16 ? BinaryState_Int16 - : BinaryState_Int32 + method = (sizeof(T) <= sizeof(U) || SafeIntCompare::isBothUnsigned || !IntTraits::isSigned) + ? BinaryState_OK + : IntTraits::isInt8 ? BinaryState_Int8 + : IntTraits::isInt16 ? BinaryState_Int16 : BinaryState_Int32 }; }; @@ -5357,126 +5776,141 @@ template < typename T, typename U > class BinaryMethod #define BinaryAssert(x) SAFEINT_ASSERT(x) #endif -template < typename T, typename U, int method > class BinaryAndHelper; +template +class BinaryAndHelper; -template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK > +template +class BinaryAndHelper { public: - static T And( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs & rhs ); } + static T And(T lhs, U rhs) SAFEINT_NOTHROW { return (T)(lhs & rhs); } }; -template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 > +template +class BinaryAndHelper { public: - static T And( T lhs, U rhs ) SAFEINT_NOTHROW + static T And(T lhs, U rhs) SAFEINT_NOTHROW { // cast forces sign extension to be zeros - BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int8)rhs ) ); - return (T)( lhs & (unsigned __int8)rhs ); + BinaryAssert((lhs & rhs) == (lhs & (unsigned __int8)rhs)); + return (T)(lhs & (unsigned __int8)rhs); } }; -template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 > +template +class BinaryAndHelper { public: - static T And( T lhs, U rhs ) SAFEINT_NOTHROW + static T And(T lhs, U rhs) SAFEINT_NOTHROW { - //cast forces sign extension to be zeros - BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int16)rhs ) ); - return (T)( lhs & (unsigned __int16)rhs ); + // cast forces sign extension to be zeros + BinaryAssert((lhs & rhs) == (lhs & (unsigned __int16)rhs)); + return (T)(lhs & (unsigned __int16)rhs); } }; -template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 > +template +class BinaryAndHelper { public: - static T And( T lhs, U rhs ) SAFEINT_NOTHROW + static T And(T lhs, U rhs) SAFEINT_NOTHROW { - //cast forces sign extension to be zeros - BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int32)rhs ) ); - return (T)( lhs & (unsigned __int32)rhs ); + // cast forces sign extension to be zeros + BinaryAssert((lhs & rhs) == (lhs & (unsigned __int32)rhs)); + return (T)(lhs & (unsigned __int32)rhs); } }; -template < typename T, typename U, int method > class BinaryOrHelper; +template +class BinaryOrHelper; -template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK > +template +class BinaryOrHelper { public: - static T Or( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs | rhs ); } + static T Or(T lhs, U rhs) SAFEINT_NOTHROW { return (T)(lhs | rhs); } }; -template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 > +template +class BinaryOrHelper { public: - static T Or( T lhs, U rhs ) SAFEINT_NOTHROW + static T Or(T lhs, U rhs) SAFEINT_NOTHROW { - //cast forces sign extension to be zeros - BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int8)rhs ) ); - return (T)( lhs | (unsigned __int8)rhs ); + // cast forces sign extension to be zeros + BinaryAssert((lhs | rhs) == (lhs | (unsigned __int8)rhs)); + return (T)(lhs | (unsigned __int8)rhs); } }; -template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 > +template +class BinaryOrHelper { public: - static T Or( T lhs, U rhs ) SAFEINT_NOTHROW + static T Or(T lhs, U rhs) SAFEINT_NOTHROW { - //cast forces sign extension to be zeros - BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int16)rhs ) ); - return (T)( lhs | (unsigned __int16)rhs ); + // cast forces sign extension to be zeros + BinaryAssert((lhs | rhs) == (lhs | (unsigned __int16)rhs)); + return (T)(lhs | (unsigned __int16)rhs); } }; -template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 > +template +class BinaryOrHelper { public: - static T Or( T lhs, U rhs ) SAFEINT_NOTHROW + static T Or(T lhs, U rhs) SAFEINT_NOTHROW { - //cast forces sign extension to be zeros - BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int32)rhs ) ); - return (T)( lhs | (unsigned __int32)rhs ); + // cast forces sign extension to be zeros + BinaryAssert((lhs | rhs) == (lhs | (unsigned __int32)rhs)); + return (T)(lhs | (unsigned __int32)rhs); } }; -template class BinaryXorHelper; +template +class BinaryXorHelper; -template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK > +template +class BinaryXorHelper { public: - static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs ^ rhs ); } + static T Xor(T lhs, U rhs) SAFEINT_NOTHROW { return (T)(lhs ^ rhs); } }; -template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 > +template +class BinaryXorHelper { public: - static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW + static T Xor(T lhs, U rhs) SAFEINT_NOTHROW { // cast forces sign extension to be zeros - BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int8)rhs ) ); - return (T)( lhs ^ (unsigned __int8)rhs ); + BinaryAssert((lhs ^ rhs) == (lhs ^ (unsigned __int8)rhs)); + return (T)(lhs ^ (unsigned __int8)rhs); } }; -template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 > +template +class BinaryXorHelper { public: - static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW + static T Xor(T lhs, U rhs) SAFEINT_NOTHROW { // cast forces sign extension to be zeros - BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int16)rhs ) ); - return (T)( lhs ^ (unsigned __int16)rhs ); + BinaryAssert((lhs ^ rhs) == (lhs ^ (unsigned __int16)rhs)); + return (T)(lhs ^ (unsigned __int16)rhs); } }; -template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 > +template +class BinaryXorHelper { public: - static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW + static T Xor(T lhs, U rhs) SAFEINT_NOTHROW { // cast forces sign extension to be zeros - BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int32)rhs ) ); - return (T)( lhs ^ (unsigned __int32)rhs ); + BinaryAssert((lhs ^ rhs) == (lhs ^ (unsigned __int32)rhs)); + return (T)(lhs ^ (unsigned __int32)rhs); } }; @@ -5485,121 +5919,122 @@ template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int // External functions that can be used where you only need to check one operation // non-class helper function so that you can check for a cast's validity // and handle errors how you like -template < typename T, typename U > -inline bool SafeCast( const T From, U& To ) SAFEINT_NOTHROW +template +inline bool SafeCast(const T From, U& To) SAFEINT_NOTHROW { - return SafeCastHelper< U, T, GetCastMethod< U, T >::method >::Cast( From, To ); + return SafeCastHelper::method>::Cast(From, To); } -template < typename T, typename U > -inline bool SafeEquals( const T t, const U u ) SAFEINT_NOTHROW +template +inline bool SafeEquals(const T t, const U u) SAFEINT_NOTHROW { - return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u ); + return EqualityTest::method>::IsEquals(t, u); } -template < typename T, typename U > -inline bool SafeNotEquals( const T t, const U u ) SAFEINT_NOTHROW +template +inline bool SafeNotEquals(const T t, const U u) SAFEINT_NOTHROW { - return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u ); + return !EqualityTest::method>::IsEquals(t, u); } -template < typename T, typename U > -inline bool SafeGreaterThan( const T t, const U u ) SAFEINT_NOTHROW +template +inline bool SafeGreaterThan(const T t, const U u) SAFEINT_NOTHROW { - return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u ); + return GreaterThanTest::method>::GreaterThan(t, u); } -template < typename T, typename U > -inline bool SafeGreaterThanEquals( const T t, const U u ) SAFEINT_NOTHROW +template +inline bool SafeGreaterThanEquals(const T t, const U u) SAFEINT_NOTHROW { - return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t ); + return !GreaterThanTest::method>::GreaterThan(u, t); } -template < typename T, typename U > -inline bool SafeLessThan( const T t, const U u ) SAFEINT_NOTHROW +template +inline bool SafeLessThan(const T t, const U u) SAFEINT_NOTHROW { - return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t ); + return GreaterThanTest::method>::GreaterThan(u, t); } -template < typename T, typename U > -inline bool SafeLessThanEquals( const T t, const U u ) SAFEINT_NOTHROW +template +inline bool SafeLessThanEquals(const T t, const U u) SAFEINT_NOTHROW { - return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u ); + return !GreaterThanTest::method>::GreaterThan(t, u); } -template < typename T, typename U > -inline bool SafeModulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW +template +inline bool SafeModulus(const T& t, const U& u, T& result) SAFEINT_NOTHROW { - return ( ModulusHelper< T, U, ValidComparison< T, U >::method >::Modulus( t, u, result ) == SafeIntNoError ); + return (ModulusHelper::method>::Modulus(t, u, result) == SafeIntNoError); } -template < typename T, typename U > -inline bool SafeMultiply( T t, U u, T& result ) SAFEINT_NOTHROW +template +inline bool SafeMultiply(T t, U u, T& result) SAFEINT_NOTHROW { - return MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::Multiply( t, u, result ); + return MultiplicationHelper::method>::Multiply(t, u, result); } -template < typename T, typename U > -inline bool SafeDivide( T t, U u, T& result ) SAFEINT_NOTHROW +template +inline bool SafeDivide(T t, U u, T& result) SAFEINT_NOTHROW { - return ( DivisionHelper< T, U, DivisionMethod< T, U >::method >::Divide( t, u, result ) == SafeIntNoError ); + return (DivisionHelper::method>::Divide(t, u, result) == SafeIntNoError); } -template < typename T, typename U > -inline bool SafeAdd( T t, U u, T& result ) SAFEINT_NOTHROW +template +inline bool SafeAdd(T t, U u, T& result) SAFEINT_NOTHROW { - return AdditionHelper< T, U, AdditionMethod< T, U >::method >::Addition( t, u, result ); + return AdditionHelper::method>::Addition(t, u, result); } -template < typename T, typename U > -inline bool SafeSubtract( T t, U u, T& result ) SAFEINT_NOTHROW +template +inline bool SafeSubtract(T t, U u, T& result) SAFEINT_NOTHROW { - return SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::Subtract( t, u, result ); + return SubtractionHelper::method>::Subtract(t, u, result); } /***************** end external functions ************************************/ // Main SafeInt class // Assumes exceptions can be thrown -template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeInt +template +class SafeInt { public: SafeInt() SAFEINT_NOTHROW { - C_ASSERT( NumericType< T >::isInt ); + C_ASSERT(NumericType::isInt); m_int = 0; } // Having a constructor for every type of int // avoids having the compiler evade our checks when doing implicit casts - // e.g., SafeInt s = 0x7fffffff; - SafeInt( const T& i ) SAFEINT_NOTHROW + SafeInt(const T& i) SAFEINT_NOTHROW { - C_ASSERT( NumericType< T >::isInt ); - //always safe + C_ASSERT(NumericType::isInt); + // always safe m_int = i; } // provide explicit boolean converter - SafeInt( bool b ) SAFEINT_NOTHROW + SafeInt(bool b) SAFEINT_NOTHROW { - C_ASSERT( NumericType< T >::isInt ); - m_int = (T)( b ? 1 : 0 ); + C_ASSERT(NumericType::isInt); + m_int = (T)(b ? 1 : 0); } - template < typename U > - SafeInt(const SafeInt< U, E >& u) SAFEINT_CPP_THROW + template + SafeInt(const SafeInt& u) SAFEINT_CPP_THROW { - C_ASSERT( NumericType< T >::isInt ); - *this = SafeInt< T, E >( (U)u ); + C_ASSERT(NumericType::isInt); + *this = SafeInt((U)u); } - template < typename U > - SafeInt( const U& i ) SAFEINT_CPP_THROW + template + SafeInt(const U& i) SAFEINT_CPP_THROW { - C_ASSERT( NumericType< T >::isInt ); + C_ASSERT(NumericType::isInt); // SafeCast will throw exceptions if i won't fit in type T - SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( i, m_int ); + SafeCastHelper::method>::template CastThrow(i, m_int); } // The destructor is intentionally commented out - no destructor @@ -5607,36 +6042,35 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // inlining characteristics. It wasn't doing anything anyway. // ~SafeInt(){}; - // now start overloading operators // assignment operator // constructors exist for all int types and will ensure safety - template < typename U > - SafeInt< T, E >& operator =( const U& rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator=(const U& rhs) SAFEINT_CPP_THROW { // use constructor to test size // constructor is optimized to do minimal checking based // on whether T can contain U // note - do not change this - *this = SafeInt< T, E >( rhs ); + *this = SafeInt(rhs); return *this; } - SafeInt< T, E >& operator =( const T& rhs ) SAFEINT_NOTHROW + SafeInt& operator=(const T& rhs) SAFEINT_NOTHROW { m_int = rhs; return *this; } - template < typename U > - SafeInt< T, E >& operator =( const SafeInt< U, E >& rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator=(const SafeInt& rhs) SAFEINT_CPP_THROW { - SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( rhs.Ref(), m_int ); + SafeCastHelper::method>::template CastThrow(rhs.Ref(), m_int); return *this; } - SafeInt< T, E >& operator =( const SafeInt< T, E >& rhs ) SAFEINT_NOTHROW + SafeInt& operator=(const SafeInt& rhs) SAFEINT_NOTHROW { m_int = rhs.m_int; return *this; @@ -5644,57 +6078,56 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // Casting operators - operator bool() const SAFEINT_NOTHROW - { - return !!m_int; - } + operator bool() const SAFEINT_NOTHROW { return !!m_int; } operator char() const SAFEINT_CPP_THROW { char val; - SafeCastHelper< char, T, GetCastMethod< char, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, val); return val; } operator signed char() const SAFEINT_CPP_THROW { signed char val; - SafeCastHelper< signed char, T, GetCastMethod< signed char, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, val); return val; } operator unsigned char() const SAFEINT_CPP_THROW { unsigned char val; - SafeCastHelper< unsigned char, T, GetCastMethod< unsigned char, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, val); return val; } operator __int16() const SAFEINT_CPP_THROW { __int16 val; - SafeCastHelper< __int16, T, GetCastMethod< __int16, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper<__int16, T, GetCastMethod<__int16, T>::method>::template CastThrow(m_int, val); return val; } operator unsigned __int16() const SAFEINT_CPP_THROW { unsigned __int16 val; - SafeCastHelper< unsigned __int16, T, GetCastMethod< unsigned __int16, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, + val); return val; } operator __int32() const SAFEINT_CPP_THROW { __int32 val; - SafeCastHelper< __int32, T, GetCastMethod< __int32, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper<__int32, T, GetCastMethod<__int32, T>::method>::template CastThrow(m_int, val); return val; } operator unsigned __int32() const SAFEINT_CPP_THROW { unsigned __int32 val; - SafeCastHelper< unsigned __int32, T, GetCastMethod< unsigned __int32, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, + val); return val; } @@ -5703,28 +6136,29 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI operator long() const SAFEINT_CPP_THROW { long val; - SafeCastHelper< long, T, GetCastMethod< long, T >::method >::template CastThrow< E >( m_int, val ); - return val; + SafeCastHelper::method>::template CastThrow(m_int, val); + return val; } operator unsigned long() const SAFEINT_CPP_THROW { unsigned long val; - SafeCastHelper< unsigned long, T, GetCastMethod< unsigned long, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, val); return val; } operator __int64() const SAFEINT_CPP_THROW { __int64 val; - SafeCastHelper< __int64, T, GetCastMethod< __int64, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper<__int64, T, GetCastMethod<__int64, T>::method>::template CastThrow(m_int, val); return val; } operator unsigned __int64() const SAFEINT_CPP_THROW { unsigned __int64 val; - SafeCastHelper< unsigned __int64, T, GetCastMethod< unsigned __int64, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, + val); return val; } @@ -5732,7 +6166,7 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI operator wchar_t() const SAFEINT_CPP_THROW { wchar_t val; - SafeCastHelper< wchar_t, T, GetCastMethod< wchar_t, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, val); return val; } #endif @@ -5744,7 +6178,7 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI operator size_t() const SAFEINT_CPP_THROW { size_t val; - SafeCastHelper< size_t, T, GetCastMethod< size_t, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, val); return val; } #endif @@ -5753,20 +6187,20 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI operator float() const SAFEINT_CPP_THROW { float val; - SafeCastHelper< float, T, GetCastMethod< float, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, val); return val; } operator double() const SAFEINT_CPP_THROW { double val; - SafeCastHelper< double, T, GetCastMethod< double, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, val); return val; } operator long double() const SAFEINT_CPP_THROW { long double val; - SafeCastHelper< long double, T, GetCastMethod< long double, T >::method >::template CastThrow< E >( m_int, val ); + SafeCastHelper::method>::template CastThrow(m_int, val); return val; } @@ -5783,20 +6217,20 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // This allows you to do unsafe things! // It is meant to allow you to more easily // pass a SafeInt into things like ReadFile - T* operator &() SAFEINT_NOTHROW { return &m_int; } - const T* operator &() const SAFEINT_NOTHROW { return &m_int; } + T* operator&() SAFEINT_NOTHROW { return &m_int; } + const T* operator&() const SAFEINT_NOTHROW { return &m_int; } // Unary operators - bool operator !() const SAFEINT_NOTHROW { return (!m_int) ? true : false; } + bool operator!() const SAFEINT_NOTHROW { return (!m_int) ? true : false; } // operator + (unary) // note - normally, the '+' and '-' operators will upcast to a signed int // for T < 32 bits. This class changes behavior to preserve type - const SafeInt< T, E >& operator +() const SAFEINT_NOTHROW { return *this; } + const SafeInt& operator+() const SAFEINT_NOTHROW { return *this; } - //unary - + // unary - - SafeInt< T, E > operator -() const SAFEINT_CPP_THROW + SafeInt operator-() const SAFEINT_CPP_THROW { // Note - unsigned still performs the bitwise manipulation // will warn at level 2 or higher if the value is 32-bit or larger @@ -5804,9 +6238,9 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI } // prefix increment operator - SafeInt< T, E >& operator ++() SAFEINT_CPP_THROW + SafeInt& operator++() SAFEINT_CPP_THROW { - if( m_int != IntTraits< T >::maxInt ) + if (m_int != IntTraits::maxInt) { ++m_int; return *this; @@ -5815,9 +6249,9 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI } // prefix decrement operator - SafeInt< T, E >& operator --() SAFEINT_CPP_THROW + SafeInt& operator--() SAFEINT_CPP_THROW { - if( m_int != IntTraits< T >::minInt ) + if (m_int != IntTraits::minInt) { --m_int; return *this; @@ -5829,11 +6263,11 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // characteristics // postfix increment operator - SafeInt< T, E > operator ++( int ) SAFEINT_CPP_THROW // dummy arg to comply with spec + SafeInt operator++(int) SAFEINT_CPP_THROW // dummy arg to comply with spec { - if( m_int != IntTraits< T >::maxInt ) + if (m_int != IntTraits::maxInt) { - SafeInt< T, E > tmp( m_int ); + SafeInt tmp(m_int); m_int++; return tmp; @@ -5842,11 +6276,11 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI } // postfix decrement operator - SafeInt< T, E > operator --( int ) SAFEINT_CPP_THROW // dummy arg to comply with spec + SafeInt operator--(int) SAFEINT_CPP_THROW // dummy arg to comply with spec { - if( m_int != IntTraits< T >::minInt ) + if (m_int != IntTraits::minInt) { - SafeInt< T, E > tmp( m_int ); + SafeInt tmp(m_int); m_int--; return tmp; } @@ -5856,7 +6290,7 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // One's complement // Note - this operator will normally change size to an int // cast in return improves perf and maintains type - SafeInt< T, E > operator ~() const SAFEINT_NOTHROW { return SafeInt< T, E >( (T)~m_int ); } + SafeInt operator~() const SAFEINT_NOTHROW { return SafeInt((T)~m_int); } // Binary operators // @@ -5900,181 +6334,184 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // larger than the lhs operand, and it must be the same sign // as well. It does, however, suffer from the same promotion // problems as comparisons, division and other operations - template < typename U > - SafeInt< T, E > operator %( U rhs ) const SAFEINT_CPP_THROW + template + SafeInt operator%(U rhs) const SAFEINT_CPP_THROW { T result; - ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, result ); - return SafeInt< T, E >( result ); + ModulusHelper::method>::template ModulusThrow(m_int, rhs, result); + return SafeInt(result); } - SafeInt< T, E > operator %( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW + SafeInt operator%(SafeInt rhs) const SAFEINT_CPP_THROW { T result; - ModulusHelper< T, T, ValidComparison< T, T >::method >::template ModulusThrow< E >( m_int, rhs, result ); - return SafeInt< T, E >( result ); + ModulusHelper::method>::template ModulusThrow(m_int, rhs, result); + return SafeInt(result); } // Modulus assignment - template < typename U > - SafeInt< T, E >& operator %=( U rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator%=(U rhs) SAFEINT_CPP_THROW { - ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, m_int ); + ModulusHelper::method>::template ModulusThrow(m_int, rhs, m_int); return *this; } - template < typename U > - SafeInt< T, E >& operator %=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator%=(SafeInt rhs) SAFEINT_CPP_THROW { - ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, (U)rhs, m_int ); + ModulusHelper::method>::template ModulusThrow(m_int, (U)rhs, m_int); return *this; } // Multiplication - template < typename U > - SafeInt< T, E > operator *( U rhs ) const SAFEINT_CPP_THROW + template + SafeInt operator*(U rhs) const SAFEINT_CPP_THROW { - T ret( 0 ); - MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, ret ); - return SafeInt< T, E >( ret ); + T ret(0); + MultiplicationHelper::method>::template MultiplyThrow(m_int, rhs, ret); + return SafeInt(ret); } - SafeInt< T, E > operator *( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW + SafeInt operator*(SafeInt rhs) const SAFEINT_CPP_THROW { - T ret( 0 ); - MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, ret ); - return SafeInt< T, E >( ret ); + T ret(0); + MultiplicationHelper::method>::template MultiplyThrow(m_int, (T)rhs, ret); + return SafeInt(ret); } // Multiplication assignment - SafeInt< T, E >& operator *=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW + SafeInt& operator*=(SafeInt rhs) SAFEINT_CPP_THROW { - MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, m_int ); + MultiplicationHelper::method>::template MultiplyThrow(m_int, (T)rhs, m_int); return *this; } - template < typename U > - SafeInt< T, E >& operator *=( U rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator*=(U rhs) SAFEINT_CPP_THROW { - MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, m_int ); + MultiplicationHelper::method>::template MultiplyThrow(m_int, rhs, m_int); return *this; } - template < typename U > - SafeInt< T, E >& operator *=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator*=(SafeInt rhs) SAFEINT_CPP_THROW { - MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs.Ref(), m_int ); + MultiplicationHelper::method>::template MultiplyThrow( + m_int, rhs.Ref(), m_int); return *this; } // Division - template < typename U > - SafeInt< T, E > operator /( U rhs ) const SAFEINT_CPP_THROW + template + SafeInt operator/(U rhs) const SAFEINT_CPP_THROW { - T ret( 0 ); - DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, rhs, ret ); - return SafeInt< T, E >( ret ); + T ret(0); + DivisionHelper::method>::template DivideThrow(m_int, rhs, ret); + return SafeInt(ret); } - SafeInt< T, E > operator /( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW + SafeInt operator/(SafeInt rhs) const SAFEINT_CPP_THROW { - T ret( 0 ); - DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)rhs, ret ); - return SafeInt< T, E >( ret ); + T ret(0); + DivisionHelper::method>::template DivideThrow(m_int, (T)rhs, ret); + return SafeInt(ret); } // Division assignment - SafeInt< T, E >& operator /=( SafeInt< T, E > i ) SAFEINT_CPP_THROW + SafeInt& operator/=(SafeInt i) SAFEINT_CPP_THROW { - DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)i, m_int ); + DivisionHelper::method>::template DivideThrow(m_int, (T)i, m_int); return *this; } - template < typename U > SafeInt< T, E >& operator /=( U i ) SAFEINT_CPP_THROW + template + SafeInt& operator/=(U i) SAFEINT_CPP_THROW { - DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, i, m_int ); + DivisionHelper::method>::template DivideThrow(m_int, i, m_int); return *this; } - template < typename U > SafeInt< T, E >& operator /=( SafeInt< U, E > i ) + template + SafeInt& operator/=(SafeInt i) { - DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, (U)i, m_int ); + DivisionHelper::method>::template DivideThrow(m_int, (U)i, m_int); return *this; } // For addition and subtraction // Addition - SafeInt< T, E > operator +( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW + SafeInt operator+(SafeInt rhs) const SAFEINT_CPP_THROW { - T ret( 0 ); - AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, ret ); - return SafeInt< T, E >( ret ); + T ret(0); + AdditionHelper::method>::template AdditionThrow(m_int, (T)rhs, ret); + return SafeInt(ret); } - template < typename U > - SafeInt< T, E > operator +( U rhs ) const SAFEINT_CPP_THROW + template + SafeInt operator+(U rhs) const SAFEINT_CPP_THROW { - T ret( 0 ); - AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, ret ); - return SafeInt< T, E >( ret ); + T ret(0); + AdditionHelper::method>::template AdditionThrow(m_int, rhs, ret); + return SafeInt(ret); } - //addition assignment - SafeInt< T, E >& operator +=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW + // addition assignment + SafeInt& operator+=(SafeInt rhs) SAFEINT_CPP_THROW { - AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, m_int ); + AdditionHelper::method>::template AdditionThrow(m_int, (T)rhs, m_int); return *this; } - template < typename U > - SafeInt< T, E >& operator +=( U rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator+=(U rhs) SAFEINT_CPP_THROW { - AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, m_int ); + AdditionHelper::method>::template AdditionThrow(m_int, rhs, m_int); return *this; } - template < typename U > - SafeInt< T, E >& operator +=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator+=(SafeInt rhs) SAFEINT_CPP_THROW { - AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, (U)rhs, m_int ); + AdditionHelper::method>::template AdditionThrow(m_int, (U)rhs, m_int); return *this; } // Subtraction - template < typename U > - SafeInt< T, E > operator -( U rhs ) const SAFEINT_CPP_THROW + template + SafeInt operator-(U rhs) const SAFEINT_CPP_THROW { - T ret( 0 ); - SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, ret ); - return SafeInt< T, E >( ret ); + T ret(0); + SubtractionHelper::method>::template SubtractThrow(m_int, rhs, ret); + return SafeInt(ret); } - SafeInt< T, E > operator -(SafeInt< T, E > rhs) const SAFEINT_CPP_THROW + SafeInt operator-(SafeInt rhs) const SAFEINT_CPP_THROW { - T ret( 0 ); - SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, ret ); - return SafeInt< T, E >( ret ); + T ret(0); + SubtractionHelper::method>::template SubtractThrow(m_int, (T)rhs, ret); + return SafeInt(ret); } // Subtraction assignment - SafeInt< T, E >& operator -=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW + SafeInt& operator-=(SafeInt rhs) SAFEINT_CPP_THROW { - SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, m_int ); + SubtractionHelper::method>::template SubtractThrow(m_int, (T)rhs, m_int); return *this; } - template < typename U > - SafeInt< T, E >& operator -=( U rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator-=(U rhs) SAFEINT_CPP_THROW { - SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, m_int ); + SubtractionHelper::method>::template SubtractThrow(m_int, rhs, m_int); return *this; } - template < typename U > - SafeInt< T, E >& operator -=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW + template + SafeInt& operator-=(SafeInt rhs) SAFEINT_CPP_THROW { - SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, (U)rhs, m_int ); + SubtractionHelper::method>::template SubtractThrow(m_int, (U)rhs, m_int); return *this; } @@ -6086,86 +6523,86 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // Left shift // Also, shifting > bitcount is undefined - trap in debug #ifdef SAFEINT_DISABLE_SHIFT_ASSERT - #define ShiftAssert(x) +#define ShiftAssert(x) #else - #define ShiftAssert(x) SAFEINT_ASSERT(x) +#define ShiftAssert(x) SAFEINT_ASSERT(x) #endif - template < typename U > - SafeInt< T, E > operator <<( U bits ) const SAFEINT_NOTHROW + template + SafeInt operator<<(U bits) const SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); - ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + ShiftAssert(!IntTraits::isSigned || bits >= 0); + ShiftAssert(bits < (int)IntTraits::bitCount); - return SafeInt< T, E >( (T)( m_int << bits ) ); + return SafeInt((T)(m_int << bits)); } - template < typename U > - SafeInt< T, E > operator <<( SafeInt< U, E > bits ) const SAFEINT_NOTHROW + template + SafeInt operator<<(SafeInt bits) const SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); - ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount ); + ShiftAssert(!IntTraits::isSigned || (U)bits >= 0); + ShiftAssert((U)bits < (int)IntTraits::bitCount); - return SafeInt< T, E >( (T)( m_int << (U)bits ) ); + return SafeInt((T)(m_int << (U)bits)); } // Left shift assignment - template < typename U > - SafeInt< T, E >& operator <<=( U bits ) SAFEINT_NOTHROW + template + SafeInt& operator<<=(U bits) SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); - ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + ShiftAssert(!IntTraits::isSigned || bits >= 0); + ShiftAssert(bits < (int)IntTraits::bitCount); m_int <<= bits; return *this; } - template < typename U > - SafeInt< T, E >& operator <<=( SafeInt< U, E > bits ) SAFEINT_NOTHROW + template + SafeInt& operator<<=(SafeInt bits) SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); - ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount ); + ShiftAssert(!IntTraits::isSigned || (U)bits >= 0); + ShiftAssert((U)bits < (int)IntTraits::bitCount); m_int <<= (U)bits; return *this; } // Right shift - template < typename U > - SafeInt< T, E > operator >>( U bits ) const SAFEINT_NOTHROW + template + SafeInt operator>>(U bits) const SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); - ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + ShiftAssert(!IntTraits::isSigned || bits >= 0); + ShiftAssert(bits < (int)IntTraits::bitCount); - return SafeInt< T, E >( (T)( m_int >> bits ) ); + return SafeInt((T)(m_int >> bits)); } - template < typename U > - SafeInt< T, E > operator >>( SafeInt< U, E > bits ) const SAFEINT_NOTHROW + template + SafeInt operator>>(SafeInt bits) const SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); - ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + ShiftAssert(!IntTraits::isSigned || (U)bits >= 0); + ShiftAssert(bits < (int)IntTraits::bitCount); - return SafeInt< T, E >( (T)(m_int >> (U)bits) ); + return SafeInt((T)(m_int >> (U)bits)); } // Right shift assignment - template < typename U > - SafeInt< T, E >& operator >>=( U bits ) SAFEINT_NOTHROW + template + SafeInt& operator>>=(U bits) SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); - ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + ShiftAssert(!IntTraits::isSigned || bits >= 0); + ShiftAssert(bits < (int)IntTraits::bitCount); m_int >>= bits; return *this; } - template < typename U > - SafeInt< T, E >& operator >>=( SafeInt< U, E > bits ) SAFEINT_NOTHROW + template + SafeInt& operator>>=(SafeInt bits) SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); - ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount ); + ShiftAssert(!IntTraits::isSigned || (U)bits >= 0); + ShiftAssert((U)bits < (int)IntTraits::bitCount); m_int >>= (U)bits; return *this; @@ -6176,13 +6613,10 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // demand a type T, or something that fits into a type T // Bitwise & - SafeInt< T, E > operator &( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW - { - return SafeInt< T, E >( m_int & (T)rhs ); - } + SafeInt operator&(SafeInt rhs) const SAFEINT_NOTHROW { return SafeInt(m_int & (T)rhs); } - template < typename U > - SafeInt< T, E > operator &( U rhs ) const SAFEINT_NOTHROW + template + SafeInt operator&(U rhs) const SAFEINT_NOTHROW { // we want to avoid setting bits by surprise // consider the case of lhs = int, value = 0xffffffff @@ -6196,129 +6630,117 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // was causing unexpected behavior. Fix is to properly cast your inputs // so that it works like you meant, not unexpectedly - return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs ) ); + return SafeInt(BinaryAndHelper::method>::And(m_int, rhs)); } // Bitwise & assignment - SafeInt< T, E >& operator &=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW + SafeInt& operator&=(SafeInt rhs) SAFEINT_NOTHROW { m_int &= (T)rhs; return *this; } - template < typename U > - SafeInt< T, E >& operator &=( U rhs ) SAFEINT_NOTHROW + template + SafeInt& operator&=(U rhs) SAFEINT_NOTHROW { - m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs ); + m_int = BinaryAndHelper::method>::And(m_int, rhs); return *this; } - template < typename U > - SafeInt< T, E >& operator &=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW + template + SafeInt& operator&=(SafeInt rhs) SAFEINT_NOTHROW { - m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, (U)rhs ); + m_int = BinaryAndHelper::method>::And(m_int, (U)rhs); return *this; } // XOR - SafeInt< T, E > operator ^( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW - { - return SafeInt< T, E >( (T)( m_int ^ (T)rhs ) ); - } + SafeInt operator^(SafeInt rhs) const SAFEINT_NOTHROW { return SafeInt((T)(m_int ^ (T)rhs)); } - template < typename U > - SafeInt< T, E > operator ^( U rhs ) const SAFEINT_NOTHROW + template + SafeInt operator^(U rhs) const SAFEINT_NOTHROW { // If you land in the assert, this is because the bitwise operator // was causing unexpected behavior. Fix is to properly cast your inputs // so that it works like you meant, not unexpectedly - return SafeInt< T, E >( BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs ) ); + return SafeInt(BinaryXorHelper::method>::Xor(m_int, rhs)); } // XOR assignment - SafeInt< T, E >& operator ^=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW + SafeInt& operator^=(SafeInt rhs) SAFEINT_NOTHROW { m_int ^= (T)rhs; return *this; } - template < typename U > - SafeInt< T, E >& operator ^=( U rhs ) SAFEINT_NOTHROW + template + SafeInt& operator^=(U rhs) SAFEINT_NOTHROW { - m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs ); + m_int = BinaryXorHelper::method>::Xor(m_int, rhs); return *this; } - template < typename U > - SafeInt< T, E >& operator ^=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW + template + SafeInt& operator^=(SafeInt rhs) SAFEINT_NOTHROW { - m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, (U)rhs ); + m_int = BinaryXorHelper::method>::Xor(m_int, (U)rhs); return *this; } // bitwise OR - SafeInt< T, E > operator |( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW - { - return SafeInt< T, E >( (T)( m_int | (T)rhs ) ); - } + SafeInt operator|(SafeInt rhs) const SAFEINT_NOTHROW { return SafeInt((T)(m_int | (T)rhs)); } - template < typename U > - SafeInt< T, E > operator |( U rhs ) const SAFEINT_NOTHROW + template + SafeInt operator|(U rhs) const SAFEINT_NOTHROW { - return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs ) ); + return SafeInt(BinaryOrHelper::method>::Or(m_int, rhs)); } // bitwise OR assignment - SafeInt< T, E >& operator |=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW + SafeInt& operator|=(SafeInt rhs) SAFEINT_NOTHROW { m_int |= (T)rhs; return *this; } - template < typename U > - SafeInt< T, E >& operator |=( U rhs ) SAFEINT_NOTHROW + template + SafeInt& operator|=(U rhs) SAFEINT_NOTHROW { - m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs ); + m_int = BinaryOrHelper::method>::Or(m_int, rhs); return *this; } - template < typename U > - SafeInt< T, E >& operator |=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW + template + SafeInt& operator|=(SafeInt rhs) SAFEINT_NOTHROW { - m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, (U)rhs ); + m_int = BinaryOrHelper::method>::Or(m_int, (U)rhs); return *this; } // Miscellaneous helper functions - SafeInt< T, E > Min( SafeInt< T, E > test, const T floor = IntTraits< T >::minInt ) const SAFEINT_NOTHROW + SafeInt Min(SafeInt test, const T floor = IntTraits::minInt) const SAFEINT_NOTHROW { T tmp = test < m_int ? (T)test : m_int; return tmp < floor ? floor : tmp; } - SafeInt< T, E > Max( SafeInt< T, E > test, const T upper = IntTraits< T >::maxInt ) const SAFEINT_NOTHROW + SafeInt Max(SafeInt test, const T upper = IntTraits::maxInt) const SAFEINT_NOTHROW { T tmp = test > m_int ? (T)test : m_int; return tmp > upper ? upper : tmp; } - void Swap( SafeInt< T, E >& with ) SAFEINT_NOTHROW + void Swap(SafeInt& with) SAFEINT_NOTHROW { - T temp( m_int ); + T temp(m_int); m_int = with.m_int; with.m_int = temp; } - static SafeInt< T, E > SafeAtoI( const char* input ) SAFEINT_CPP_THROW - { - return SafeTtoI( input ); - } + static SafeInt SafeAtoI(const char* input) SAFEINT_CPP_THROW { return SafeTtoI(input); } - static SafeInt< T, E > SafeWtoI( const wchar_t* input ) - { - return SafeTtoI( input ); - } + static SafeInt SafeWtoI(const wchar_t* input) { return SafeTtoI(input); } enum alignBits { @@ -6332,80 +6754,73 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI align256 = 8 }; - template < alignBits bits > - const SafeInt< T, E >& Align() SAFEINT_CPP_THROW + template + const SafeInt& Align() SAFEINT_CPP_THROW { // Zero is always aligned - if( m_int == 0 ) - return *this; + if (m_int == 0) return *this; // We don't support aligning negative numbers at this time // Can't align unsigned numbers on bitCount (e.g., 8 bits = 256, unsigned char max = 255) // or signed numbers on bitCount-1 (e.g., 7 bits = 128, signed char max = 127). // Also makes no sense to try to align on negative or no bits. - ShiftAssert( ( ( IntTraits::isSigned && bits < (int)IntTraits< T >::bitCount - 1 ) - || ( !IntTraits::isSigned && bits < (int)IntTraits< T >::bitCount ) ) && - bits >= 0 && ( !IntTraits::isSigned || m_int > 0 ) ); + ShiftAssert(((IntTraits::isSigned && bits < (int)IntTraits::bitCount - 1) || + (!IntTraits::isSigned && bits < (int)IntTraits::bitCount)) && + bits >= 0 && (!IntTraits::isSigned || m_int > 0)); - const T AlignValue = ( (T)1 << bits ) - 1; + const T AlignValue = ((T)1 << bits) - 1; - m_int = (T)( ( m_int + AlignValue ) & ~AlignValue ); + m_int = (T)((m_int + AlignValue) & ~AlignValue); - if( m_int <= 0 ) - E::SafeIntOnOverflow(); + if (m_int <= 0) E::SafeIntOnOverflow(); return *this; } // Commonly needed alignments: - const SafeInt< T, E >& Align2() { return Align< align2 >(); } - const SafeInt< T, E >& Align4() { return Align< align4 >(); } - const SafeInt< T, E >& Align8() { return Align< align8 >(); } - const SafeInt< T, E >& Align16() { return Align< align16 >(); } - const SafeInt< T, E >& Align32() { return Align< align32 >(); } - const SafeInt< T, E >& Align64() { return Align< align64 >(); } -private: + const SafeInt& Align2() { return Align(); } + const SafeInt& Align4() { return Align(); } + const SafeInt& Align8() { return Align(); } + const SafeInt& Align16() { return Align(); } + const SafeInt& Align32() { return Align(); } + const SafeInt& Align64() { return Align(); } +private: // This is almost certainly not the best optimized version of atoi, // but it does not display a typical bug where it isn't possible to set MinInt // and it won't allow you to overflow your integer. // This is here because it is useful, and it is an example of what // can be done easily with SafeInt. - template < typename U > - static SafeInt< T, E > SafeTtoI( U* input ) SAFEINT_CPP_THROW + template + static SafeInt SafeTtoI(U* input) SAFEINT_CPP_THROW { - U* tmp = input; - SafeInt< T, E > s; + U* tmp = input; + SafeInt s; bool negative = false; // Bad input, or empty string - if( input == nullptr || input[0] == 0 ) - E::SafeIntOnOverflow(); + if (input == nullptr || input[0] == 0) E::SafeIntOnOverflow(); - switch( *tmp ) + switch (*tmp) { - case '-': - tmp++; - negative = true; - break; - case '+': - tmp++; - break; + case '-': + tmp++; + negative = true; + break; + case '+': tmp++; break; } - while( *tmp != 0 ) + while (*tmp != 0) { - if( *tmp < '0' || *tmp > '9' ) - break; + if (*tmp < '0' || *tmp > '9') break; - if( (T)s != 0 ) - s *= (T)10; + if ((T)s != 0) s *= (T)10; - if( !negative ) - s += (T)( *tmp - '0' ); + if (!negative) + s += (T)(*tmp - '0'); else - s -= (T)( *tmp - '0' ); + s -= (T)(*tmp - '0'); tmp++; } @@ -6418,165 +6833,166 @@ template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeI // Helper function used to subtract pointers. // Used to squelch warnings -template +template SafeInt SafePtrDiff(const P* p1, const P* p2) SAFEINT_CPP_THROW { - return SafeInt( p1 - p2 ); + return SafeInt(p1 - p2); } // Comparison operators -//Less than -template < typename T, typename U, typename E > -bool operator <( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +// Less than +template +bool operator<(U lhs, SafeInt rhs) SAFEINT_NOTHROW { - return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs ); + return GreaterThanTest::method>::GreaterThan((T)rhs, lhs); } -template < typename T, typename U, typename E > -bool operator <( SafeInt lhs, U rhs ) SAFEINT_NOTHROW +template +bool operator<(SafeInt lhs, U rhs) SAFEINT_NOTHROW { - return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs ); + return GreaterThanTest::method>::GreaterThan(rhs, (T)lhs); } -template < typename T, typename U, typename E > -bool operator <( SafeInt< U, E > lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +bool operator<(SafeInt lhs, SafeInt rhs) SAFEINT_NOTHROW { - return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, (U)lhs ); + return GreaterThanTest::method>::GreaterThan((T)rhs, (U)lhs); } // Greater than -template < typename T, typename U, typename E > -bool operator >( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +bool operator>(U lhs, SafeInt rhs) SAFEINT_NOTHROW { - return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs ); + return GreaterThanTest::method>::GreaterThan(lhs, (T)rhs); } -template < typename T, typename U, typename E > -bool operator >( SafeInt lhs, U rhs ) SAFEINT_NOTHROW +template +bool operator>(SafeInt lhs, U rhs) SAFEINT_NOTHROW { - return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs ); + return GreaterThanTest::method>::GreaterThan((T)lhs, rhs); } -template < typename T, typename U, typename E > -bool operator >( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +bool operator>(SafeInt lhs, SafeInt rhs) SAFEINT_NOTHROW { - return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs ); + return GreaterThanTest::method>::GreaterThan((T)lhs, (U)rhs); } // Greater than or equal -template < typename T, typename U, typename E > -bool operator >=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +bool operator>=(U lhs, SafeInt rhs) SAFEINT_NOTHROW { - return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs ); + return !GreaterThanTest::method>::GreaterThan((T)rhs, lhs); } -template < typename T, typename U, typename E > -bool operator >=( SafeInt lhs, U rhs ) SAFEINT_NOTHROW +template +bool operator>=(SafeInt lhs, U rhs) SAFEINT_NOTHROW { - return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs ); + return !GreaterThanTest::method>::GreaterThan(rhs, (T)lhs); } -template < typename T, typename U, typename E > -bool operator >=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +bool operator>=(SafeInt lhs, SafeInt rhs) SAFEINT_NOTHROW { - return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( (U)rhs, (T)lhs ); + return !GreaterThanTest::method>::GreaterThan((U)rhs, (T)lhs); } // Less than or equal -template < typename T, typename U, typename E > -bool operator <=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +bool operator<=(U lhs, SafeInt rhs) SAFEINT_NOTHROW { - return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs ); + return !GreaterThanTest::method>::GreaterThan(lhs, (T)rhs); } -template < typename T, typename U, typename E > -bool operator <=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW +template +bool operator<=(SafeInt lhs, U rhs) SAFEINT_NOTHROW { - return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs ); + return !GreaterThanTest::method>::GreaterThan((T)lhs, rhs); } -template < typename T, typename U, typename E > -bool operator <=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +bool operator<=(SafeInt lhs, SafeInt rhs) SAFEINT_NOTHROW { - return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs ); + return !GreaterThanTest::method>::GreaterThan((T)lhs, (U)rhs); } // equality // explicit overload for bool -template < typename T, typename E > -bool operator ==( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +bool operator==(bool lhs, SafeInt rhs) SAFEINT_NOTHROW { - return lhs == ( (T)rhs == 0 ? false : true ); + return lhs == ((T)rhs == 0 ? false : true); } -template < typename T, typename E > -bool operator ==( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW +template +bool operator==(SafeInt lhs, bool rhs) SAFEINT_NOTHROW { - return rhs == ( (T)lhs == 0 ? false : true ); + return rhs == ((T)lhs == 0 ? false : true); } -template < typename T, typename U, typename E > -bool operator ==( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +bool operator==(U lhs, SafeInt rhs) SAFEINT_NOTHROW { - return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals((T)rhs, lhs); + return EqualityTest::method>::IsEquals((T)rhs, lhs); } -template < typename T, typename U, typename E > -bool operator ==( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW +template +bool operator==(SafeInt lhs, U rhs) SAFEINT_NOTHROW { - return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs ); + return EqualityTest::method>::IsEquals((T)lhs, rhs); } -template < typename T, typename U, typename E > -bool operator ==( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +bool operator==(SafeInt lhs, SafeInt rhs) SAFEINT_NOTHROW { - return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, (U)rhs ); + return EqualityTest::method>::IsEquals((T)lhs, (U)rhs); } -//not equals -template < typename T, typename U, typename E > -bool operator !=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +// not equals +template +bool operator!=(U lhs, SafeInt rhs) SAFEINT_NOTHROW { - return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)rhs, lhs ); + return !EqualityTest::method>::IsEquals((T)rhs, lhs); } -template < typename T, typename U, typename E > -bool operator !=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW +template +bool operator!=(SafeInt lhs, U rhs) SAFEINT_NOTHROW { - return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs ); + return !EqualityTest::method>::IsEquals((T)lhs, rhs); } -template < typename T, typename U, typename E > -bool operator !=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +bool operator!=(SafeInt lhs, SafeInt rhs) SAFEINT_NOTHROW { - return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( lhs, rhs ); + return !EqualityTest::method>::IsEquals(lhs, rhs); } - -template < typename T, typename E > -bool operator !=( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +bool operator!=(bool lhs, SafeInt rhs) SAFEINT_NOTHROW { - return ( (T)rhs == 0 ? false : true ) != lhs; + return ((T)rhs == 0 ? false : true) != lhs; } -template < typename T, typename E > -bool operator !=( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW +template +bool operator!=(SafeInt lhs, bool rhs) SAFEINT_NOTHROW { - return ( (T)lhs == 0 ? false : true ) != rhs; + return ((T)lhs == 0 ? false : true) != rhs; } +template +class ModulusSimpleCaseHelper; -template < typename T, typename U, typename E, int method > class ModulusSimpleCaseHelper; - -template < typename T, typename E, int method > class ModulusSignedCaseHelper; +template +class ModulusSignedCaseHelper; -template < typename T, typename E > class ModulusSignedCaseHelper < T, E, true > +template +class ModulusSignedCaseHelper { public: - static bool SignedCase( SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_NOTHROW + static bool SignedCase(SafeInt rhs, SafeInt& result) SAFEINT_NOTHROW { - if( (T)rhs == (T)-1 ) + if ((T)rhs == (T)-1) { result = 0; return true; @@ -6585,27 +7001,24 @@ template < typename T, typename E > class ModulusSignedCaseHelper < T, E, true > } }; -template < typename T, typename E > class ModulusSignedCaseHelper < T, E, false > +template +class ModulusSignedCaseHelper { public: - static bool SignedCase( SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW - { - return false; - } + static bool SignedCase(SafeInt /*rhs*/, SafeInt& /*result*/) SAFEINT_NOTHROW { return false; } }; -template < typename T, typename U, typename E > -class ModulusSimpleCaseHelper < T, U, E, true > +template +class ModulusSimpleCaseHelper { public: - static bool ModulusSimpleCase( U lhs, SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_CPP_THROW + static bool ModulusSimpleCase(U lhs, SafeInt rhs, SafeInt& result) SAFEINT_CPP_THROW { - if( rhs != 0 ) + if (rhs != 0) { - if( ModulusSignedCaseHelper< T, E, IntTraits< T >::isSigned >::SignedCase( rhs, result ) ) - return true; + if (ModulusSignedCaseHelper::isSigned>::SignedCase(rhs, result)) return true; - result = SafeInt< T, E >( (T)( lhs % (T)rhs ) ); + result = SafeInt((T)(lhs % (T)rhs)); return true; } @@ -6613,19 +7026,19 @@ class ModulusSimpleCaseHelper < T, U, E, true > } }; -template< typename T, typename U, typename E > -class ModulusSimpleCaseHelper < T, U, E, false > +template +class ModulusSimpleCaseHelper { public: - static bool ModulusSimpleCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW + static bool ModulusSimpleCase(U /*lhs*/, SafeInt /*rhs*/, SafeInt& /*result*/) SAFEINT_NOTHROW { return false; } }; // Modulus -template < typename T, typename U, typename E > -SafeInt< T, E > operator %( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +template +SafeInt operator%(U lhs, SafeInt rhs) SAFEINT_CPP_THROW { // Value of return depends on sign of lhs // This one may not be safe - bounds check in constructor @@ -6633,53 +7046,58 @@ SafeInt< T, E > operator %( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW // Fast-track the simple case // same size and same sign - SafeInt< T, E > result; + SafeInt result; - if( ModulusSimpleCaseHelper< T, U, E, - sizeof(T) == sizeof(U) && (bool)IntTraits< T >::isSigned == (bool)IntTraits< U >::isSigned >::ModulusSimpleCase( lhs, rhs, result ) ) + if (ModulusSimpleCaseHelper < T, + U, + E, + sizeof(T) == sizeof(U) && + (bool)IntTraits::isSigned == (bool)IntTraits::isSigned > ::ModulusSimpleCase(lhs, rhs, result)) return result; - return SafeInt< T, E >( ( SafeInt< U, E >( lhs ) % (T)rhs ) ); + return SafeInt((SafeInt(lhs) % (T)rhs)); } // Multiplication -template < typename T, typename U, typename E > -SafeInt< T, E > operator *( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +template +SafeInt operator*(U lhs, SafeInt rhs)SAFEINT_CPP_THROW { - T ret( 0 ); - MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( (T)rhs, lhs, ret ); - return SafeInt< T, E >(ret); + T ret(0); + MultiplicationHelper::method>::template MultiplyThrow((T)rhs, lhs, ret); + return SafeInt(ret); } -template < typename T, typename U, typename E, int method > class DivisionNegativeCornerCaseHelper; +template +class DivisionNegativeCornerCaseHelper; -template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, true > +template +class DivisionNegativeCornerCaseHelper { public: - static bool NegativeCornerCase( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW + static bool NegativeCornerCase(U lhs, SafeInt rhs, SafeInt& result) SAFEINT_CPP_THROW { // Problem case - normal casting behavior changes meaning // flip rhs to positive // any operator casts now do the right thing U tmp; - if( CompileConst< sizeof(T) == 4 >::Value() ) - tmp = lhs/(U)( ~(unsigned __int32)(T)rhs + 1 ); + if (CompileConst::Value()) + tmp = lhs / (U)(~(unsigned __int32)(T)rhs + 1); else - tmp = lhs/(U)( ~(unsigned __int64)(T)rhs + 1 ); + tmp = lhs / (U)(~(unsigned __int64)(T)rhs + 1); - if( tmp <= (U)IntTraits< T >::maxInt ) + if (tmp <= (U)IntTraits::maxInt) { - result = SafeInt< T, E >( (T)(~(unsigned __int64)tmp + 1) ); + result = SafeInt((T)(~(unsigned __int64)tmp + 1)); return true; } // Corner case - T maxT = IntTraits< T >::maxInt; - if( tmp == (U)maxT + 1 ) + T maxT = IntTraits::maxInt; + if (tmp == (U)maxT + 1) { - T minT = IntTraits< T >::minInt; - result = SafeInt< T, E >( minT ); + T minT = IntTraits::minInt; + result = SafeInt(minT); return true; } @@ -6687,35 +7105,41 @@ template < typename T, typename U, typename E > class DivisionNegativeCornerCase } }; -template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, false > +template +class DivisionNegativeCornerCaseHelper { public: - static bool NegativeCornerCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW + static bool NegativeCornerCase(U /*lhs*/, SafeInt /*rhs*/, SafeInt& /*result*/) SAFEINT_NOTHROW { return false; } }; -template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper; +template +class DivisionCornerCaseHelper; -template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, true > +template +class DivisionCornerCaseHelper { public: - static bool DivisionCornerCase1( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW + static bool DivisionCornerCase1(U lhs, SafeInt rhs, SafeInt& result) SAFEINT_CPP_THROW { - if( (T)rhs > 0 ) + if ((T)rhs > 0) { - result = SafeInt< T, E >( lhs/(T)rhs ); + result = SafeInt(lhs / (T)rhs); return true; } // Now rhs is either negative, or zero - if( (T)rhs != 0 ) + if ((T)rhs != 0) { - if( DivisionNegativeCornerCaseHelper< T, U, E, sizeof( U ) >= 4 && sizeof( T ) <= sizeof( U ) >::NegativeCornerCase( lhs, rhs, result ) ) + if (DivisionNegativeCornerCaseHelper < T, + U, + E, + sizeof(U) >= 4 && sizeof(T) <= sizeof(U) > ::NegativeCornerCase(lhs, rhs, result)) return true; - result = SafeInt< T, E >(lhs/(T)rhs); + result = SafeInt(lhs / (T)rhs); return true; } @@ -6723,23 +7147,26 @@ template < typename T, typename U, typename E > class DivisionCornerCaseHelper < } }; -template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, false > +template +class DivisionCornerCaseHelper { public: - static bool DivisionCornerCase1( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW + static bool DivisionCornerCase1(U /*lhs*/, SafeInt /*rhs*/, SafeInt& /*result*/) SAFEINT_NOTHROW { return false; } }; -template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper2; +template +class DivisionCornerCaseHelper2; -template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, true > +template +class DivisionCornerCaseHelper2 { public: - static bool DivisionCornerCase2( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW + static bool DivisionCornerCase2(U lhs, SafeInt rhs, SafeInt& result) SAFEINT_CPP_THROW { - if( lhs == IntTraits< U >::minInt && (T)rhs == -1 ) + if (lhs == IntTraits::minInt && (T)rhs == -1) { // corner case of a corner case - lhs = min int, rhs = -1, // but rhs is the return type, so in essence, we can return -lhs @@ -6748,12 +7175,12 @@ template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER #pragma warning(push) -//cast truncates constant value -#pragma warning(disable:4310) +// cast truncates constant value +#pragma warning(disable : 4310) #endif - if( CompileConst::Value() ) - result = SafeInt< T, E >( (T)( -(T)IntTraits< U >::minInt ) ); + if (CompileConst::Value()) + result = SafeInt((T)(-(T)IntTraits::minInt)); else E::SafeIntOnOverflow(); @@ -6768,131 +7195,134 @@ template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 } }; -template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, false > +template +class DivisionCornerCaseHelper2 { public: - static bool DivisionCornerCase2( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW + static bool DivisionCornerCase2(U /*lhs*/, SafeInt /*rhs*/, SafeInt& /*result*/) SAFEINT_NOTHROW { return false; } }; // Division -template < typename T, typename U, typename E > SafeInt< T, E > operator /( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +template +SafeInt operator/(U lhs, SafeInt rhs) SAFEINT_CPP_THROW { // Corner case - has to be handled seperately - SafeInt< T, E > result; - if( DivisionCornerCaseHelper< T, U, E, (int)DivisionMethod< U, T >::method == (int)DivisionState_UnsignedSigned >::DivisionCornerCase1( lhs, rhs, result ) ) + SafeInt result; + if (DivisionCornerCaseHelper::method == (int)DivisionState_UnsignedSigned>:: + DivisionCornerCase1(lhs, rhs, result)) return result; - if( DivisionCornerCaseHelper2< T, U, E, SafeIntCompare< T, U >::isBothSigned >::DivisionCornerCase2( lhs, rhs, result ) ) + if (DivisionCornerCaseHelper2::isBothSigned>::DivisionCornerCase2(lhs, rhs, result)) return result; // Otherwise normal logic works with addition of bounds check when casting from U->T U ret; - DivisionHelper< U, T, DivisionMethod< U, T >::method >::template DivideThrow< E >( lhs, (T)rhs, ret ); - return SafeInt< T, E >( ret ); + DivisionHelper::method>::template DivideThrow(lhs, (T)rhs, ret); + return SafeInt(ret); } // Addition -template < typename T, typename U, typename E > -SafeInt< T, E > operator +( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +template +SafeInt operator+(U lhs, SafeInt rhs) SAFEINT_CPP_THROW { - T ret( 0 ); - AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( (T)rhs, lhs, ret ); - return SafeInt< T, E >( ret ); + T ret(0); + AdditionHelper::method>::template AdditionThrow((T)rhs, lhs, ret); + return SafeInt(ret); } // Subtraction -template < typename T, typename U, typename E > -SafeInt< T, E > operator -( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +template +SafeInt operator-(U lhs, SafeInt rhs) SAFEINT_CPP_THROW { - T ret( 0 ); - SubtractionHelper< U, T, SubtractionMethod2< U, T >::method >::template SubtractThrow< E >( lhs, rhs.Ref(), ret ); + T ret(0); + SubtractionHelper::method>::template SubtractThrow(lhs, rhs.Ref(), ret); - return SafeInt< T, E >( ret ); + return SafeInt(ret); } // Overrides designed to deal with cases where a SafeInt is assigned out // to a normal int - this at least makes the last operation safe // += -template < typename T, typename U, typename E > -T& operator +=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +template +T& operator+=(T& lhs, SafeInt rhs) SAFEINT_CPP_THROW { - T ret( 0 ); - AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( lhs, (U)rhs, ret ); + T ret(0); + AdditionHelper::method>::template AdditionThrow(lhs, (U)rhs, ret); lhs = ret; return lhs; } -template < typename T, typename U, typename E > -T& operator -=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +template +T& operator-=(T& lhs, SafeInt rhs) SAFEINT_CPP_THROW { - T ret( 0 ); - SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( lhs, (U)rhs, ret ); + T ret(0); + SubtractionHelper::method>::template SubtractThrow(lhs, (U)rhs, ret); lhs = ret; return lhs; } -template < typename T, typename U, typename E > -T& operator *=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +template +T& operator*=(T& lhs, SafeInt rhs) SAFEINT_CPP_THROW { - T ret( 0 ); - MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( lhs, (U)rhs, ret ); + T ret(0); + MultiplicationHelper::method>::template MultiplyThrow(lhs, (U)rhs, ret); lhs = ret; return lhs; } -template < typename T, typename U, typename E > -T& operator /=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +template +T& operator/=(T& lhs, SafeInt rhs) SAFEINT_CPP_THROW { - T ret( 0 ); - DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( lhs, (U)rhs, ret ); + T ret(0); + DivisionHelper::method>::template DivideThrow(lhs, (U)rhs, ret); lhs = ret; return lhs; } -template < typename T, typename U, typename E > -T& operator %=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +template +T& operator%=(T& lhs, SafeInt rhs) SAFEINT_CPP_THROW { - T ret( 0 ); - ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( lhs, (U)rhs, ret ); + T ret(0); + ModulusHelper::method>::template ModulusThrow(lhs, (U)rhs, ret); lhs = ret; return lhs; } -template < typename T, typename U, typename E > -T& operator &=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +T& operator&=(T& lhs, SafeInt rhs) SAFEINT_NOTHROW { - lhs = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( lhs, (U)rhs ); + lhs = BinaryAndHelper::method>::And(lhs, (U)rhs); return lhs; } -template < typename T, typename U, typename E > -T& operator ^=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +T& operator^=(T& lhs, SafeInt rhs) SAFEINT_NOTHROW { - lhs = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( lhs, (U)rhs ); + lhs = BinaryXorHelper::method>::Xor(lhs, (U)rhs); return lhs; } -template < typename T, typename U, typename E > -T& operator |=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +T& operator|=(T& lhs, SafeInt rhs) SAFEINT_NOTHROW { - lhs = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( lhs, (U)rhs ); + lhs = BinaryOrHelper::method>::Or(lhs, (U)rhs); return lhs; } -template < typename T, typename U, typename E > -T& operator <<=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +T& operator<<=(T& lhs, SafeInt rhs) SAFEINT_NOTHROW { - lhs = (T)( SafeInt< T, E >( lhs ) << (U)rhs ); + lhs = (T)(SafeInt(lhs) << (U)rhs); return lhs; } -template < typename T, typename U, typename E > -T& operator >>=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +template +T& operator>>=(T& lhs, SafeInt rhs) SAFEINT_NOTHROW { - lhs = (T)( SafeInt< T, E >( lhs ) >> (U)rhs ); + lhs = (T)(SafeInt(lhs) >> (U)rhs); return lhs; } @@ -6900,90 +7330,90 @@ T& operator >>=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW // Note - this function makes no attempt to ensure // that the resulting pointer is still in the buffer, only // that no int overflows happened on the way to getting the new pointer -template < typename T, typename U, typename E > -T*& operator +=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +template +T*& operator+=(T*& lhs, SafeInt rhs) SAFEINT_CPP_THROW { // Cast the pointer to a number so we can do arithmetic - SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs ); + SafeInt ptr_val = reinterpret_cast(lhs); // Check first that rhs is valid for the type of ptrdiff_t // and that multiplying by sizeof( T ) doesn't overflow a ptrdiff_t // Next, we need to add 2 SafeInts of different types, so unbox the ptr_diff // Finally, cast the number back to a pointer of the correct type - lhs = reinterpret_cast< T* >( (size_t)( ptr_val + (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) ); + lhs = reinterpret_cast((size_t)(ptr_val + (ptrdiff_t)(SafeInt(rhs) * sizeof(T)))); return lhs; } -template < typename T, typename U, typename E > -T*& operator -=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +template +T*& operator-=(T*& lhs, SafeInt rhs) SAFEINT_CPP_THROW { // Cast the pointer to a number so we can do arithmetic - SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs ); + SafeInt ptr_val = reinterpret_cast(lhs); // See above for comments - lhs = reinterpret_cast< T* >( (size_t)( ptr_val - (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) ); + lhs = reinterpret_cast((size_t)(ptr_val - (ptrdiff_t)(SafeInt(rhs) * sizeof(T)))); return lhs; } -template < typename T, typename U, typename E > -T*& operator *=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +template +T*& operator*=(T*& lhs, SafeInt) SAFEINT_NOTHROW { // This operator explicitly not supported - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); return (lhs = NULL); } -template < typename T, typename U, typename E > -T*& operator /=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +template +T*& operator/=(T*& lhs, SafeInt) SAFEINT_NOTHROW { // This operator explicitly not supported - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); return (lhs = NULL); } -template < typename T, typename U, typename E > -T*& operator %=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +template +T*& operator%=(T*& lhs, SafeInt) SAFEINT_NOTHROW { // This operator explicitly not supported - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); return (lhs = NULL); } -template < typename T, typename U, typename E > -T*& operator &=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +template +T*& operator&=(T*& lhs, SafeInt) SAFEINT_NOTHROW { // This operator explicitly not supported - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); return (lhs = NULL); } -template < typename T, typename U, typename E > -T*& operator ^=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +template +T*& operator^=(T*& lhs, SafeInt) SAFEINT_NOTHROW { // This operator explicitly not supported - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); return (lhs = NULL); } -template < typename T, typename U, typename E > -T*& operator |=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +template +T*& operator|=(T*& lhs, SafeInt) SAFEINT_NOTHROW { // This operator explicitly not supported - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); return (lhs = NULL); } -template < typename T, typename U, typename E > -T*& operator <<=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +template +T*& operator<<=(T*& lhs, SafeInt) SAFEINT_NOTHROW { // This operator explicitly not supported - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); return (lhs = NULL); } -template < typename T, typename U, typename E > -T*& operator >>=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +template +T*& operator>>=(T*& lhs, SafeInt) SAFEINT_NOTHROW { // This operator explicitly not supported - C_ASSERT( sizeof(T) == 0 ); + C_ASSERT(sizeof(T) == 0); return (lhs = NULL); } @@ -6991,23 +7421,23 @@ T*& operator >>=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW // NOTE - shift operators always return the type of the lhs argument // Left shift -template < typename T, typename U, typename E > -SafeInt< U, E > operator <<( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW +template +SafeInt operator<<(U lhs, SafeInt bits) SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 ); - ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount ); + ShiftAssert(!IntTraits::isSigned || (T)bits >= 0); + ShiftAssert((T)bits < (int)IntTraits::bitCount); - return SafeInt< U, E >( (U)( lhs << (T)bits ) ); + return SafeInt((U)(lhs << (T)bits)); } // Right shift -template < typename T, typename U, typename E > -SafeInt< U, E > operator >>( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW +template +SafeInt operator>>(U lhs, SafeInt bits) SAFEINT_NOTHROW { - ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 ); - ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount ); + ShiftAssert(!IntTraits::isSigned || (T)bits >= 0); + ShiftAssert((T)bits < (int)IntTraits::bitCount); - return SafeInt< U, E >( (U)( lhs >> (T)bits ) ); + return SafeInt((U)(lhs >> (T)bits)); } // Bitwise operators @@ -7015,24 +7445,24 @@ SafeInt< U, E > operator >>( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW // demand a type T, or something that fits into a type T. // Bitwise & -template < typename T, typename U, typename E > -SafeInt< T, E > operator &( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +SafeInt operator&(U lhs, SafeInt rhs)SAFEINT_NOTHROW { - return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( (T)rhs, lhs ) ); + return SafeInt(BinaryAndHelper::method>::And((T)rhs, lhs)); } // Bitwise XOR -template < typename T, typename U, typename E > -SafeInt< T, E > operator ^( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +SafeInt operator^(U lhs, SafeInt rhs) SAFEINT_NOTHROW { - return SafeInt< T, E >(BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( (T)rhs, lhs ) ); + return SafeInt(BinaryXorHelper::method>::Xor((T)rhs, lhs)); } // Bitwise OR -template < typename T, typename U, typename E > -SafeInt< T, E > operator |( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +template +SafeInt operator|(U lhs, SafeInt rhs) SAFEINT_NOTHROW { - return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( (T)rhs, lhs ) ); + return SafeInt(BinaryOrHelper::method>::Or((T)rhs, lhs)); } #if SAFEINT_COMPILER == GCC_COMPILER @@ -7043,6 +7473,10 @@ SafeInt< T, E > operator |( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW #pragma clang diagnostic pop #endif -} // utilities -} // safeint3 +#ifdef C_ASSERT_DEFINED_SAFEINT +#undef C_ASSERT +#undef C_ASSERT_DEFINED_SAFEINT +#endif // C_ASSERT_DEFINED_SAFEINT +} // namespace safeint3 +} // namespace msl diff --git a/Release/include/cpprest/details/basic_types.h b/Release/include/cpprest/details/basic_types.h index e9477c736a..d2ceb87189 100644 --- a/Release/include/cpprest/details/basic_types.h +++ b/Release/include/cpprest/details/basic_types.h @@ -1,23 +1,23 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Platform-dependent type definitions -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Platform-dependent type definitions + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include +#include "cpprest/details/cpprest_compat.h" #include #include #include -#include "cpprest/details/cpprest_compat.h" +#include #ifndef _WIN32 #ifndef __STDC_LIMIT_MACROS @@ -32,7 +32,6 @@ namespace utility { - #ifdef _WIN32 #define _UTF16_STRINGS #endif @@ -49,9 +48,9 @@ typedef uint32_t HRESULT; // Needed for PPLX // // On Windows, all strings are wide // -typedef wchar_t char_t ; +typedef wchar_t char_t; typedef std::wstring string_t; -#define _XPLATSTR(x) L ## x +#define _XPLATSTR(x) L##x typedef std::wostringstream ostringstream_t; typedef std::wofstream ofstream_t; typedef std::wostream ostream_t; @@ -88,7 +87,7 @@ typedef std::stringstream stringstream_t; #define U(x) _XPLATSTR(x) #endif // !_TURN_OFF_PLATFORM_STRING -}// namespace utility +} // namespace utility typedef char utf8char; typedef std::string utf8string; @@ -116,7 +115,6 @@ typedef std::basic_istream utf16istream; typedef std::basic_istringstream utf16istringstream; #endif - #if defined(_WIN32) // Include on everything except Windows Desktop ARM, unless explicitly excluded. #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) diff --git a/Release/include/cpprest/details/cpprest_compat.h b/Release/include/cpprest/details/cpprest_compat.h index 25b3e45bda..57f277aaf0 100644 --- a/Release/include/cpprest/details/cpprest_compat.h +++ b/Release/include/cpprest/details/cpprest_compat.h @@ -1,16 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Standard macros and definitions. -* This header has minimal dependency on windows headers and is safe for use in the public API -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Standard macros and definitions. + * This header has minimal dependency on windows headers and is safe for use in the public API + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -30,10 +30,14 @@ #else // ^^^ _WIN32 ^^^ // vvv !_WIN32 vvv -#define __declspec(x) __attribute__ ((x)) +#define __declspec(x) __attribute__((x)) #define dllimport #define novtable /* no novtable equivalent */ -#define __assume(x) do { if (!(x)) __builtin_unreachable(); } while (false) +#define __assume(x) \ + do \ + { \ + if (!(x)) __builtin_unreachable(); \ + } while (false) #define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x #define CPPREST_NOEXCEPT noexcept #define CPPREST_CONSTEXPR constexpr @@ -46,7 +50,7 @@ #if not defined __cdecl #if defined cdecl -#define __cdecl __attribute__ ((cdecl)) +#define __cdecl __attribute__((cdecl)) #else // ^^^ defined cdecl ^^^ // vvv !defined cdecl vvv #define __cdecl #endif // defined cdecl @@ -68,7 +72,6 @@ #endif // __clang__ #endif // _WIN32 - #ifdef _NO_ASYNCRTIMP #define _ASYNCRTIMP #else // ^^^ _NO_ASYNCRTIMP ^^^ // vvv !_NO_ASYNCRTIMP vvv diff --git a/Release/include/cpprest/details/fileio.h b/Release/include/cpprest/details/fileio.h index f60947daf1..ee88c15a5d 100644 --- a/Release/include/cpprest/details/fileio.h +++ b/Release/include/cpprest/details/fileio.h @@ -1,92 +1,95 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* fileio.h -* -* Asynchronous I/O: stream buffer implementation details -* -* We're going to some lengths to avoid exporting C++ class member functions and implementation details across -* module boundaries, and the factoring requires that we keep the implementation details away from the main header -* files. The supporting functions, which are in this file, use C-like signatures to avoid as many issues as -* possible. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * fileio.h + * + * Asynchronous I/O: stream buffer implementation details + * + * We're going to some lengths to avoid exporting C++ class member functions and implementation details across + * module boundaries, and the factoring requires that we keep the implementation details away from the main header + * files. The supporting functions, which are in this file, use C-like signatures to avoid as many issues as + * possible. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifdef _WIN32 #include #endif -#include "pplx/pplxtasks.h" #include "cpprest/details/basic_types.h" +#include "pplx/pplxtasks.h" -namespace Concurrency { namespace streams +namespace Concurrency +{ +namespace streams { namespace details { - /// - /// A record containing the essential private data members of a file stream, - /// in particular the parts that need to be shared between the public header - /// file and the implementation in the implementation file. - /// - struct _file_info +/// +/// A record containing the essential private data members of a file stream, +/// in particular the parts that need to be shared between the public header +/// file and the implementation in the implementation file. +/// +struct _file_info +{ + _ASYNCRTIMP _file_info(std::ios_base::openmode mode, size_t buffer_size) + : m_rdpos(0) + , m_wrpos(0) + , m_atend(false) + , m_buffer_size(buffer_size) + , m_buffer(nullptr) + , m_bufoff(0) + , m_bufsize(0) + , m_buffill(0) + , m_mode(mode) { - _ASYNCRTIMP _file_info(std::ios_base::openmode mode, size_t buffer_size) : - m_rdpos(0), - m_wrpos(0), - m_atend(false), - m_buffer_size(buffer_size), - m_buffer(nullptr), - m_bufoff(0), - m_bufsize(0), - m_buffill(0), - m_mode(mode) - { - } + } - // Positional data + // Positional data - size_t m_rdpos; - size_t m_wrpos; - bool m_atend; + size_t m_rdpos; + size_t m_wrpos; + bool m_atend; - // Input buffer + // Input buffer - size_t m_buffer_size; // The intended size of the buffer to read into. - char *m_buffer; + size_t m_buffer_size; // The intended size of the buffer to read into. + char* m_buffer; - size_t m_bufoff; // File position that the start of the buffer represents. - msl::safeint3::SafeInt m_bufsize; // Buffer allocated size, as actually allocated. - size_t m_buffill; // Amount of file data actually in the buffer + size_t m_bufoff; // File position that the start of the buffer represents. + msl::safeint3::SafeInt m_bufsize; // Buffer allocated size, as actually allocated. + size_t m_buffill; // Amount of file data actually in the buffer - std::ios_base::openmode m_mode; + std::ios_base::openmode m_mode; - pplx::extensibility::recursive_lock_t m_lock; - }; + pplx::extensibility::recursive_lock_t m_lock; +}; +/// +/// This interface provides the necessary callbacks for completion events. +/// +class _filestream_callback +{ +public: + virtual void on_opened(_In_ details::_file_info*) {} + virtual void on_closed() {} + virtual void on_error(const std::exception_ptr&) {} + virtual void on_completed(size_t) {} - /// - /// This interface provides the necessary callbacks for completion events. - /// - class _filestream_callback - { - public: - virtual void on_opened(_In_ details::_file_info *) { } - virtual void on_closed() { } - virtual void on_error(const std::exception_ptr &) { } - virtual void on_completed(size_t) { } - protected: - virtual ~_filestream_callback() {} - }; +protected: + virtual ~_filestream_callback() {} +}; -} -}} +} // namespace details +} // namespace streams +} // namespace Concurrency extern "C" { @@ -102,7 +105,10 @@ extern "C" /// True does not signal that the file will eventually be successfully opened, just that the process was started. /// #if !defined(__cplusplus_winrt) -_ASYNCRTIMP bool __cdecl _open_fsb_str(_In_ concurrency::streams::details::_filestream_callback *callback, const utility::char_t *filename, std::ios_base::openmode mode, int prot); + _ASYNCRTIMP bool __cdecl _open_fsb_str(_In_ concurrency::streams::details::_filestream_callback* callback, + const utility::char_t* filename, + std::ios_base::openmode mode, + int prot); #endif /// @@ -117,78 +123,98 @@ _ASYNCRTIMP bool __cdecl _open_fsb_str(_In_ concurrency::streams::details::_file /// This is only available for WinRT. /// #if defined(__cplusplus_winrt) -_ASYNCRTIMP bool __cdecl _open_fsb_stf_str(_In_ concurrency::streams::details::_filestream_callback *callback, ::Windows::Storage::StorageFile^ file, std::ios_base::openmode mode, int prot); + _ASYNCRTIMP bool __cdecl _open_fsb_stf_str(_In_ concurrency::streams::details::_filestream_callback* callback, + ::Windows::Storage::StorageFile ^ file, + std::ios_base::openmode mode, + int prot); #endif -/// -/// Close a file stream buffer. -/// -/// The file info record of the file -/// A pointer to the callback interface to invoke when the file has been opened. -/// true if the closing operation could be initiated, false otherwise. -/// -/// True does not signal that the file will eventually be successfully closed, just that the process was started. -/// -_ASYNCRTIMP bool __cdecl _close_fsb_nolock(_In_ concurrency::streams::details::_file_info **info, _In_ concurrency::streams::details::_filestream_callback *callback); -_ASYNCRTIMP bool __cdecl _close_fsb(_In_ concurrency::streams::details::_file_info **info, _In_ concurrency::streams::details::_filestream_callback *callback); - + /// + /// Close a file stream buffer. + /// + /// The file info record of the file + /// A pointer to the callback interface to invoke when the file has been opened. + /// true if the closing operation could be initiated, false otherwise. + /// + /// True does not signal that the file will eventually be successfully closed, just that the process was started. + /// + _ASYNCRTIMP bool __cdecl _close_fsb_nolock(_In_ concurrency::streams::details::_file_info** info, + _In_ concurrency::streams::details::_filestream_callback* callback); + _ASYNCRTIMP bool __cdecl _close_fsb(_In_ concurrency::streams::details::_file_info** info, + _In_ concurrency::streams::details::_filestream_callback* callback); -/// -/// Write data from a buffer into the file stream. -/// -/// The file info record of the file -/// A pointer to the callback interface to invoke when the write request is completed. -/// A pointer to a buffer where the data should be placed -/// The size (in characters) of the buffer -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -_ASYNCRTIMP size_t __cdecl _putn_fsb(_In_ concurrency::streams::details::_file_info *info, _In_ concurrency::streams::details::_filestream_callback *callback, const void *ptr, size_t count, size_t char_size); + /// + /// Write data from a buffer into the file stream. + /// + /// The file info record of the file + /// A pointer to the callback interface to invoke when the write request is + /// completed. A pointer to a buffer where the data should be placed The size (in characters) of the buffer 0 if the read request is still outstanding, + /// -1 if the request failed, otherwise the size of the data read into the buffer + _ASYNCRTIMP size_t __cdecl _putn_fsb(_In_ concurrency::streams::details::_file_info* info, + _In_ concurrency::streams::details::_filestream_callback* callback, + const void* ptr, + size_t count, + size_t char_size); -/// -/// Read data from a file stream into a buffer -/// -/// The file info record of the file -/// A pointer to the callback interface to invoke when the write request is completed. -/// A pointer to a buffer where the data should be placed -/// The size (in characters) of the buffer -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -_ASYNCRTIMP size_t __cdecl _getn_fsb(_In_ concurrency::streams::details::_file_info *info, _In_ concurrency::streams::details::_filestream_callback *callback, _Out_writes_ (count) void *ptr, _In_ size_t count, size_t char_size); + /// + /// Read data from a file stream into a buffer + /// + /// The file info record of the file + /// A pointer to the callback interface to invoke when the write request is + /// completed. A pointer to a buffer where the data should be placed The size (in characters) of the buffer 0 if the read request is still outstanding, + /// -1 if the request failed, otherwise the size of the data read into the buffer + _ASYNCRTIMP size_t __cdecl _getn_fsb(_In_ concurrency::streams::details::_file_info* info, + _In_ concurrency::streams::details::_filestream_callback* callback, + _Out_writes_(count) void* ptr, + _In_ size_t count, + size_t char_size); -/// -/// Flush all buffered data to the underlying file. -/// -/// The file info record of the file -/// A pointer to the callback interface to invoke when the write request is completed. -/// true if the request was initiated -_ASYNCRTIMP bool __cdecl _sync_fsb(_In_ concurrency::streams::details::_file_info *info, _In_ concurrency::streams::details::_filestream_callback *callback); + /// + /// Flush all buffered data to the underlying file. + /// + /// The file info record of the file + /// A pointer to the callback interface to invoke when the write request is + /// completed. true if the request was initiated + _ASYNCRTIMP bool __cdecl _sync_fsb(_In_ concurrency::streams::details::_file_info* info, + _In_ concurrency::streams::details::_filestream_callback* callback); -/// -/// Get the size of the underlying file. -/// -/// The file info record of the file -/// The file size -_ASYNCRTIMP utility::size64_t __cdecl _get_size(_In_ concurrency::streams::details::_file_info *info, size_t char_size); + /// + /// Get the size of the underlying file. + /// + /// The file info record of the file + /// The file size + _ASYNCRTIMP utility::size64_t __cdecl _get_size(_In_ concurrency::streams::details::_file_info* info, + size_t char_size); -/// -/// Adjust the internal buffers and pointers when the application seeks to a new read location in the stream. -/// -/// The file info record of the file -/// The new position (offset from the start) in the file stream -/// true if the request was initiated -_ASYNCRTIMP size_t __cdecl _seekrdpos_fsb(_In_ concurrency::streams::details::_file_info *info, size_t pos, size_t char_size); + /// + /// Adjust the internal buffers and pointers when the application seeks to a new read location in the stream. + /// + /// The file info record of the file + /// The new position (offset from the start) in the file stream + /// true if the request was initiated + _ASYNCRTIMP size_t __cdecl _seekrdpos_fsb(_In_ concurrency::streams::details::_file_info* info, + size_t pos, + size_t char_size); -/// -/// Adjust the internal buffers and pointers when the application seeks to a new read location in the stream. -/// -/// The file info record of the file -/// The new position (offset from the start) in the file stream -/// true if the request was initiated -_ASYNCRTIMP size_t __cdecl _seekrdtoend_fsb(_In_ concurrency::streams::details::_file_info *info, int64_t offset, size_t char_size); + /// + /// Adjust the internal buffers and pointers when the application seeks to a new read location in the stream. + /// + /// The file info record of the file + /// The new position (offset from the start) in the file stream + /// true if the request was initiated + _ASYNCRTIMP size_t __cdecl _seekrdtoend_fsb(_In_ concurrency::streams::details::_file_info* info, + int64_t offset, + size_t char_size); -/// -/// Adjust the internal buffers and pointers when the application seeks to a new write location in the stream. -/// -/// The file info record of the file -/// The new position (offset from the start) in the file stream -/// true if the request was initiated -_ASYNCRTIMP size_t __cdecl _seekwrpos_fsb(_In_ concurrency::streams::details::_file_info *info, size_t pos, size_t char_size); + /// + /// Adjust the internal buffers and pointers when the application seeks to a new write location in the stream. + /// + /// The file info record of the file + /// The new position (offset from the start) in the file stream + /// true if the request was initiated + _ASYNCRTIMP size_t __cdecl _seekwrpos_fsb(_In_ concurrency::streams::details::_file_info* info, + size_t pos, + size_t char_size); } diff --git a/Release/include/cpprest/details/http_helpers.h b/Release/include/cpprest/details/http_helpers.h index ad01e2eb67..9bed095b0e 100644 --- a/Release/include/cpprest/details/http_helpers.h +++ b/Release/include/cpprest/details/http_helpers.h @@ -1,44 +1,48 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Implementation Details of the http.h layer of messaging -* -* Functions and types for interoperating with http.h from modern C++ -* This file includes windows definitions and should not be included in a public header -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Implementation Details of the http.h layer of messaging + * + * Functions and types for interoperating with http.h from modern C++ + * This file includes windows definitions and should not be included in a public header + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "cpprest/details/basic_types.h" - #include "cpprest/http_msg.h" -namespace web { namespace http +namespace web +{ +namespace http { namespace details { +namespace chunked_encoding +{ +// Transfer-Encoding: chunked support +static const size_t additional_encoding_space = 12; +static const size_t data_offset = additional_encoding_space - 2; - namespace chunked_encoding - { - // Transfer-Encoding: chunked support - static const size_t additional_encoding_space = 12; - static const size_t data_offset = additional_encoding_space-2; - - // Add the data necessary for properly sending data with transfer-encoding: chunked. - // - // There are up to 12 additional bytes needed for each chunk: - // - // The last chunk requires 5 bytes, and is fixed. - // All other chunks require up to 8 bytes for the length, and four for the two CRLF - // delimiters. - // - _ASYNCRTIMP size_t __cdecl add_chunked_delimiters(_Out_writes_(buffer_size) uint8_t *data, _In_ size_t buffer_size, size_t bytes_read); - } +// Add the data necessary for properly sending data with transfer-encoding: chunked. +// +// There are up to 12 additional bytes needed for each chunk: +// +// The last chunk requires 5 bytes, and is fixed. +// All other chunks require up to 8 bytes for the length, and four for the two CRLF +// delimiters. +// +_ASYNCRTIMP size_t __cdecl add_chunked_delimiters(_Out_writes_(buffer_size) uint8_t* data, + _In_ size_t buffer_size, + size_t bytes_read); +} // namespace chunked_encoding -}}} +} // namespace details +} // namespace http +} // namespace web diff --git a/Release/include/cpprest/details/http_server.h b/Release/include/cpprest/details/http_server.h index 0a94b0361b..37a82ff3dc 100644 --- a/Release/include/cpprest/details/http_server.h +++ b/Release/include/cpprest/details/http_server.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: interface to implement HTTP server to service http_listeners. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: interface to implement HTTP server to service http_listeners. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -17,23 +17,24 @@ #include "cpprest/http_listener.h" -namespace web { namespace http +namespace web +{ +namespace http +{ +namespace experimental { -namespace experimental { namespace details { - /// /// Interface http listeners interact with for receiving and responding to http requests. /// class http_server { public: - /// /// Release any held resources. /// - virtual ~http_server() { }; + virtual ~http_server() {}; /// /// Start listening for incoming requests. @@ -43,12 +44,14 @@ class http_server /// /// Registers an http listener. /// - virtual pplx::task register_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener) = 0; + virtual pplx::task register_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener) = 0; /// /// Unregisters an http listener. /// - virtual pplx::task unregister_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener) = 0; + virtual pplx::task unregister_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener) = 0; /// /// Stop processing and listening for incoming requests. @@ -65,4 +68,5 @@ class http_server } // namespace details } // namespace experimental -}} // namespace web::http +} // namespace http +} // namespace web diff --git a/Release/include/cpprest/details/http_server_api.h b/Release/include/cpprest/details/http_server_api.h index e44e104f02..db1825726d 100644 --- a/Release/include/cpprest/details/http_server_api.h +++ b/Release/include/cpprest/details/http_server_api.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: exposes the entry points to the http server transport apis. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: exposes the entry points to the http server transport apis. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -15,16 +15,17 @@ #error "Error: http server APIs are not supported in XP" #endif //_WIN32_WINNT < _WIN32_WINNT_VISTA -#include - #include "cpprest/http_listener.h" +#include -namespace web { namespace http +namespace web +{ +namespace http +{ +namespace experimental { -namespace experimental { namespace details { - class http_server; /// @@ -37,7 +38,6 @@ class http_server; class http_server_api { public: - /// /// Returns whether or not any listeners are registered. /// @@ -56,20 +56,21 @@ class http_server_api /// /// Registers a listener for HTTP requests and starts receiving. /// - static pplx::task __cdecl register_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener); + static pplx::task __cdecl register_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener); /// /// Unregisters the given listener and stops listening for HTTP requests. /// - static pplx::task __cdecl unregister_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener); + static pplx::task __cdecl unregister_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener); /// /// Gets static HTTP server API. Could be null if no registered listeners. /// - static http_server * __cdecl server_api(); + static http_server* __cdecl server_api(); private: - /// Used to lock access to the server api registration static pplx::extensibility::critical_section_t s_lock; @@ -86,4 +87,7 @@ class http_server_api http_server_api(); }; -}}}} // namespaces +} // namespace details +} // namespace experimental +} // namespace http +} // namespace web diff --git a/Release/include/cpprest/details/nosal.h b/Release/include/cpprest/details/nosal.h index 7aeeec03de..91a2dd8614 100644 --- a/Release/include/cpprest/details/nosal.h +++ b/Release/include/cpprest/details/nosal.h @@ -1,12 +1,12 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -***/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + ***/ #pragma once // selected MS SAL annotations @@ -74,4 +74,4 @@ #ifdef _Inout_updates_bytes_ #undef _Inout_updates_bytes_ #endif -#define _Inout_updates_bytes_(x) \ No newline at end of file +#define _Inout_updates_bytes_(x) diff --git a/Release/include/cpprest/details/resource.h b/Release/include/cpprest/details/resource.h index 7ca31da740..2d61283934 100644 --- a/Release/include/cpprest/details/resource.h +++ b/Release/include/cpprest/details/resource.h @@ -3,12 +3,12 @@ // Used by Resource.rc // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/Release/include/cpprest/details/web_utilities.h b/Release/include/cpprest/details/web_utilities.h index c32a58e5e3..8b99d94aa2 100644 --- a/Release/include/cpprest/details/web_utilities.h +++ b/Release/include/cpprest/details/web_utilities.h @@ -1,28 +1,28 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* utility classes used by the different web:: clients -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * utility classes used by the different web:: clients + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "cpprest/asyncrt_utils.h" +#include "cpprest/uri.h" namespace web { namespace details { - class zero_memory_deleter { public: - _ASYNCRTIMP void operator()(::utility::string_t *data) const; + _ASYNCRTIMP void operator()(::utility::string_t* data) const; }; -typedef std::unique_ptr< ::utility::string_t, zero_memory_deleter> plaintext_string; +typedef std::unique_ptr<::utility::string_t, zero_memory_deleter> plaintext_string; #if defined(_WIN32) && !defined(CPPREST_TARGET_XP) #if defined(__cplusplus_winrt) @@ -30,8 +30,9 @@ class winrt_encryption { public: winrt_encryption() {} - _ASYNCRTIMP winrt_encryption(const std::wstring &data); + _ASYNCRTIMP winrt_encryption(const std::wstring& data); _ASYNCRTIMP plaintext_string decrypt() const; + private: ::pplx::task m_buffer; }; @@ -40,16 +41,17 @@ class win32_encryption { public: win32_encryption() {} - _ASYNCRTIMP win32_encryption(const std::wstring &data); + _ASYNCRTIMP win32_encryption(const std::wstring& data); _ASYNCRTIMP ~win32_encryption(); _ASYNCRTIMP plaintext_string decrypt() const; + private: std::vector m_buffer; size_t m_numCharacters; }; #endif #endif -} +} // namespace details /// /// Represents a set of user credentials (user name and password) to be used @@ -68,23 +70,24 @@ class credentials /// /// User name as a string. /// Password as a string. - credentials(utility::string_t username, const utility::string_t & password) : - m_username(std::move(username)), - m_password(password) - {} + credentials(utility::string_t username, const utility::string_t& password) + : m_username(std::move(username)), m_password(password) + { + } /// /// The user name associated with the credentials. /// /// A string containing the user name. - const utility::string_t &username() const { return m_username; } + const utility::string_t& username() const { return m_username; } /// /// The password for the user name associated with the credentials. /// /// A string containing the password. - CASABLANCA_DEPRECATED("This API is deprecated for security reasons to avoid unnecessary password copies stored in plaintext.") - utility::string_t password() const + CASABLANCA_DEPRECATED( + "This API is deprecated for security reasons to avoid unnecessary password copies stored in plaintext.") + utility::string_t password() const { #if defined(_WIN32) && !defined(CPPREST_TARGET_XP) return utility::string_t(*m_password.decrypt()); @@ -129,9 +132,21 @@ class credentials /// class web_proxy { - enum web_proxy_mode_internal{ use_default_, use_auto_discovery_, disabled_, user_provided_ }; + enum web_proxy_mode_internal + { + use_default_, + use_auto_discovery_, + disabled_, + user_provided_ + }; + public: - enum web_proxy_mode{ use_default = use_default_, use_auto_discovery = use_auto_discovery_, disabled = disabled_}; + enum web_proxy_mode + { + use_default = use_default_, + use_auto_discovery = use_auto_discovery_, + disabled = disabled_ + }; /// /// Constructs a proxy with the default settings. @@ -142,13 +157,13 @@ class web_proxy /// Creates a proxy with specified mode. /// /// Mode to use. - web_proxy( web_proxy_mode mode ) : m_address(_XPLATSTR("")), m_mode(static_cast(mode)) {} + web_proxy(web_proxy_mode mode) : m_address(_XPLATSTR("")), m_mode(static_cast(mode)) {} /// /// Creates a proxy explicitly with provided address. /// /// Proxy URI to use. - web_proxy( uri address ) : m_address(address), m_mode(user_provided_) {} + web_proxy(uri address) : m_address(address), m_mode(user_provided_) {} /// /// Gets this proxy's URI address. Returns an empty URI if not explicitly set by user. @@ -166,8 +181,9 @@ class web_proxy /// Sets the credentials to use for authentication with this proxy. /// /// Credentials to use for this proxy. - void set_credentials(web::credentials cred) { - if( m_mode == disabled_ ) + void set_credentials(web::credentials cred) + { + if (m_mode == disabled_) { throw std::invalid_argument("Cannot attach credentials to a disabled proxy"); } @@ -204,4 +220,4 @@ class web_proxy web::credentials m_credentials; }; -} +} // namespace web diff --git a/Release/include/cpprest/filestream.h b/Release/include/cpprest/filestream.h index de1e0d60a5..39020468fc 100644 --- a/Release/include/cpprest/filestream.h +++ b/Release/include/cpprest/filestream.h @@ -1,22 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Asynchronous File streams -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Asynchronous File streams + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_FILE_STREAMS_H #define CASA_FILE_STREAMS_H -#include "cpprest/details/fileio.h" #include "cpprest/astreambuf.h" +#include "cpprest/details/fileio.h" #include "cpprest/streams.h" #include @@ -25,1096 +25,1063 @@ #define _LWRCASE_CNCRRNCY // Note to reader: we're using lower-case namespace names everywhere, but the 'Concurrency' namespace // is capitalized for historical reasons. The alias let's us pretend that style issue doesn't exist. -namespace Concurrency { } +namespace Concurrency +{ +} namespace concurrency = Concurrency; #endif #endif -namespace Concurrency { namespace streams +namespace Concurrency +{ +namespace streams +{ +// Forward declarations +template +class file_buffer; + +namespace details +{ +// This operation queue is NOT thread safe +class async_operation_queue { - // Forward declarations - template class file_buffer; + pplx::task m_lastOperation; -namespace details { - // This operation queue is NOT thread safe - class async_operation_queue +public: + async_operation_queue() { m_lastOperation = pplx::task_from_result(); } + + // It only accepts functors that take no argument and return pplx::task + // This function may execute op inline, thus it could throw immediately + template + auto enqueue_operation(Func&& op) -> decltype(op()) { - pplx::task m_lastOperation; - public: - async_operation_queue() + decltype(op()) res; // res is task , which always has default constructor + if (m_lastOperation.is_done()) { - m_lastOperation = pplx::task_from_result(); + res = op(); // Exceptions are expected to be thrown directly without catching + if (res.is_done()) return res; } - - // It only accepts functors that take no argument and return pplx::task - // This function may execute op inline, thus it could throw immediately - template - auto enqueue_operation(Func &&op) -> decltype(op()) + else { - decltype(op()) res; // res is task , which always has default constructor - if (m_lastOperation.is_done()) - { - res = op(); // Exceptions are expected to be thrown directly without catching - if (res.is_done()) - return res; - } - else - { - res = m_lastOperation.then([=] { - return op(); // It will cause task unwrapping - }); - } - m_lastOperation = res.then([&] (decltype(op())) { - // This empty task is necessary for keeping the rest of the operations on the list running - // even when the previous operation gets error. - // Don't observe exception here. + res = m_lastOperation.then([=] { + return op(); // It will cause task unwrapping }); - return res; } + m_lastOperation = res.then([&](decltype(op())) { + // This empty task is necessary for keeping the rest of the operations on the list running + // even when the previous operation gets error. + // Don't observe exception here. + }); + return res; + } + + void wait() const { m_lastOperation.wait(); } +}; + +/// +/// Private stream buffer implementation for file streams. +/// The class itself should not be used in application code, it is used by the stream definitions farther down in the +/// header file. +/// +template +class basic_file_buffer : public details::streambuf_state_manager<_CharType> +{ +public: + typedef typename basic_streambuf<_CharType>::traits traits; + typedef typename basic_streambuf<_CharType>::int_type int_type; + typedef typename basic_streambuf<_CharType>::pos_type pos_type; + typedef typename basic_streambuf<_CharType>::off_type off_type; - void wait() const + virtual ~basic_file_buffer() + { + if (this->can_read()) { - m_lastOperation.wait(); + this->_close_read().wait(); } - }; + if (this->can_write()) + { + this->_close_write().wait(); + } + } +protected: /// - /// Private stream buffer implementation for file streams. - /// The class itself should not be used in application code, it is used by the stream definitions farther down in the header file. + /// can_seek is used to determine whether a stream buffer supports seeking. /// - template - class basic_file_buffer : public details::streambuf_state_manager<_CharType> - { - public: - typedef typename basic_streambuf<_CharType>::traits traits; - typedef typename basic_streambuf<_CharType>::int_type int_type; - typedef typename basic_streambuf<_CharType>::pos_type pos_type; - typedef typename basic_streambuf<_CharType>::off_type off_type; + virtual bool can_seek() const { return this->is_open(); } - virtual ~basic_file_buffer() - { - if( this->can_read() ) - { - this->_close_read().wait(); - } + /// + /// has_size is used to determine whether a stream buffer supports size(). + /// + virtual bool has_size() const { return this->is_open(); } - if (this->can_write()) - { - this->_close_write().wait(); - } - } + virtual utility::size64_t size() const + { + if (!this->is_open()) return 0; + return _get_size(m_info, sizeof(_CharType)); + } - protected: + /// + /// Gets the stream buffer size, if one has been set. + /// + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will always return '0'. + virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const + { + if (direction == std::ios_base::in) + return m_info->m_buffer_size; + else + return 0; + } - /// - /// can_seek is used to determine whether a stream buffer supports seeking. - /// - virtual bool can_seek() const { return this->is_open(); } + /// + /// Sets the stream buffer implementation to buffer or not buffer. + /// + /// The size to use for internal buffering, 0 if no buffering should be done. + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will silently ignore calls to this function and it + /// will not have + /// any effect on what is returned by subsequent calls to buffer_size(). + virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) + { + if (direction == std::ios_base::out) return; - /// - /// has_size is used to determine whether a stream buffer supports size(). - /// - virtual bool has_size() const { return this->is_open(); } + m_info->m_buffer_size = size; - virtual utility::size64_t size() const + if (size == 0 && m_info->m_buffer != nullptr) { - if (!this->is_open()) - return 0; - return _get_size(m_info, sizeof(_CharType)); + delete m_info->m_buffer; + m_info->m_buffer = nullptr; } + } + /// + /// For any input stream, in_avail returns the number of characters that are immediately available + /// to be consumed without blocking. May be used in conjunction with to read data without + /// incurring the overhead of using tasks. + /// + virtual size_t in_avail() const + { + pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); - /// - /// Gets the stream buffer size, if one has been set. - /// - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will always return '0'. - virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const - { - if ( direction == std::ios_base::in ) - return m_info->m_buffer_size; - else - return 0; - } - - /// - /// Sets the stream buffer implementation to buffer or not buffer. - /// - /// The size to use for internal buffering, 0 if no buffering should be done. - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will silently ignore calls to this function and it will not have - /// any effect on what is returned by subsequent calls to buffer_size(). - virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) - { - if ( direction == std::ios_base::out ) return; + return _in_avail_unprot(); + } - m_info->m_buffer_size = size; + size_t _in_avail_unprot() const + { + if (!this->is_open()) return 0; - if ( size == 0 && m_info->m_buffer != nullptr ) - { - delete m_info->m_buffer; - m_info->m_buffer = nullptr; - } - } + if (m_info->m_buffer == nullptr || m_info->m_buffill == 0) return 0; + if (m_info->m_bufoff > m_info->m_rdpos || (m_info->m_bufoff + m_info->m_buffill) < m_info->m_rdpos) return 0; - /// - /// For any input stream, in_avail returns the number of characters that are immediately available - /// to be consumed without blocking. May be used in conjunction with to read data without - /// incurring the overhead of using tasks. - /// - virtual size_t in_avail() const - { - pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); + msl::safeint3::SafeInt rdpos(m_info->m_rdpos); + msl::safeint3::SafeInt buffill(m_info->m_buffill); + msl::safeint3::SafeInt bufpos = rdpos - m_info->m_bufoff; - return _in_avail_unprot(); - } + return buffill - bufpos; + } - size_t _in_avail_unprot() const - { - if ( !this->is_open() ) return 0; - - if ( m_info->m_buffer == nullptr || m_info->m_buffill == 0 ) return 0; - if ( m_info->m_bufoff > m_info->m_rdpos || (m_info->m_bufoff+m_info->m_buffill) < m_info->m_rdpos ) return 0; - - msl::safeint3::SafeInt rdpos(m_info->m_rdpos); - msl::safeint3::SafeInt buffill(m_info->m_buffill); - msl::safeint3::SafeInt bufpos = rdpos - m_info->m_bufoff; + _file_info* _close_stream() + { + // indicate that we are no longer open + auto fileInfo = m_info; + m_info = nullptr; + return fileInfo; + } - return buffill - bufpos; - } + static pplx::task _close_file(_In_ _file_info* fileInfo) + { + pplx::task_completion_event result_tce; + auto callback = new _filestream_callback_close(result_tce); - _file_info * _close_stream() + if (!_close_fsb_nolock(&fileInfo, callback)) { - // indicate that we are no longer open - auto fileInfo = m_info; - m_info = nullptr; - return fileInfo; + delete callback; + return pplx::task_from_result(); } + return pplx::create_task(result_tce); + } - static pplx::task _close_file(_In_ _file_info * fileInfo) - { - pplx::task_completion_event result_tce; - auto callback = new _filestream_callback_close(result_tce); + // Workaround GCC compiler bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58972 + void _invoke_parent_close_read() { streambuf_state_manager<_CharType>::_close_read(); } + + pplx::task _close_read() + { + return m_readOps.enqueue_operation([this] { + _invoke_parent_close_read(); - if ( !_close_fsb_nolock(&fileInfo, callback) ) + if (this->can_write()) { - delete callback; return pplx::task_from_result(); } - return pplx::create_task(result_tce); - } + else + { + // Neither heads are open. Close the underlying device + // to indicate that we are no longer open + auto fileInfo = _close_stream(); + + return _close_file(fileInfo); + } + }); + } - // Workaround GCC compiler bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58972 - void _invoke_parent_close_read() + pplx::task _close_write() + { + streambuf_state_manager<_CharType>::_close_write(); + if (this->can_read()) { - streambuf_state_manager<_CharType>::_close_read(); + // Read head is still open. Just flush the write data + return flush_internal(); } - - pplx::task _close_read() + else { - return m_readOps.enqueue_operation([this] - { - _invoke_parent_close_read(); + // Neither heads are open. Close the underlying device - if (this->can_write()) + // We need to flush all writes if the file was opened for writing. + return flush_internal().then([=](pplx::task flushTask) -> pplx::task { + // swallow exception from flush + try { - return pplx::task_from_result(); + flushTask.wait(); } - else + catch (...) { - // Neither heads are open. Close the underlying device - // to indicate that we are no longer open - auto fileInfo = _close_stream(); - - return _close_file(fileInfo); } - }); - } - - pplx::task _close_write() - { - streambuf_state_manager<_CharType>::_close_write(); - if (this->can_read()) - { - // Read head is still open. Just flush the write data - return flush_internal(); - } - else - { - // Neither heads are open. Close the underlying device - - // We need to flush all writes if the file was opened for writing. - return flush_internal().then([=](pplx::task flushTask) -> pplx::task - { - // swallow exception from flush - try - { - flushTask.wait(); - } - catch(...) - { - } - - // indicate that we are no longer open - auto fileInfo = this->_close_stream(); - - return this->_close_file(fileInfo); - }); - } - } - /// - /// Writes a single byte to an output stream. - /// - /// The byte to write - /// A task that holds the value of the byte written. This is EOF if the write operation fails. - virtual pplx::task _putc(_CharType ch) - { - auto result_tce = pplx::task_completion_event(); - auto callback = new _filestream_callback_write(m_info, result_tce); + // indicate that we are no longer open + auto fileInfo = this->_close_stream(); - // Potentially we should consider deprecating this API, it is TERRIBLY inefficient. - std::shared_ptr<_CharType> sharedCh; - try - { - sharedCh = std::make_shared<_CharType>(ch); - } catch (const std::bad_alloc &) - { - delete callback; - throw; - } - - size_t written = _putn_fsb(m_info, callback, sharedCh.get(), 1, sizeof(_CharType)); - if (written == sizeof(_CharType)) - { - delete callback; - return pplx::task_from_result(ch); - } - - return pplx::create_task(result_tce).then([sharedCh](size_t) - { - return static_cast(*sharedCh); + return this->_close_file(fileInfo); }); } + } - /// - /// Allocates a contiguous memory block and returns it. - /// - /// The number of characters to allocate. - /// A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit. - _CharType* _alloc(size_t) - { - return nullptr; - } + /// + /// Writes a single byte to an output stream. + /// + /// The byte to write + /// A task that holds the value of the byte written. This is EOF if the write operation + /// fails. + virtual pplx::task _putc(_CharType ch) + { + auto result_tce = pplx::task_completion_event(); + auto callback = new _filestream_callback_write(m_info, result_tce); - /// - /// Submits a block already allocated by the stream buffer. - /// - /// Count of characters to be committed. - void _commit(size_t) + // Potentially we should consider deprecating this API, it is TERRIBLY inefficient. + std::shared_ptr<_CharType> sharedCh; + try { + sharedCh = std::make_shared<_CharType>(ch); } - - /// - /// Gets a pointer to the next already allocated contiguous block of data. - /// - /// A reference to a pointer variable that will hold the address of the block on success. - /// The number of contiguous characters available at the address in 'ptr'. - /// true if the operation succeeded, false otherwise. - /// - /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that - /// there is no block to return immediately or that the stream buffer does not support the operation. - /// The stream buffer may not de-allocate the block until is called. - /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; - /// a subsequent read will not succeed. - /// - virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) + catch (const std::bad_alloc&) { - ptr = nullptr; - count = 0; - return false; + delete callback; + throw; } - /// - /// Releases a block of data acquired using . This frees the stream buffer to de-allocate the - /// memory, if it so desires. Move the read position ahead by the count. - /// - /// A pointer to the block of data to be released. - /// The number of characters that were read. - virtual void release(_Out_writes_ (count) _CharType *, _In_ size_t count) + size_t written = _putn_fsb(m_info, callback, sharedCh.get(), 1, sizeof(_CharType)); + if (written == sizeof(_CharType)) { - (void)(count); + delete callback; + return pplx::task_from_result(ch); } - /// - /// Writes a number of characters to the stream. - /// - /// A pointer to the block of data to be written. - /// The number of characters to write. - /// A task that holds the number of characters actually written, either 'count' or 0. - virtual pplx::task _putn(const _CharType *ptr, size_t count) - { - auto result_tce = pplx::task_completion_event(); - auto callback = new _filestream_callback_write(m_info, result_tce); - - size_t written = _putn_fsb(m_info, callback, ptr, count, sizeof(_CharType)); + return pplx::create_task(result_tce).then([sharedCh](size_t) { return static_cast(*sharedCh); }); + } - if ( written != 0 && written != size_t(-1) ) - { - delete callback; - written = written/sizeof(_CharType); - return pplx::task_from_result(written); - } - return pplx::create_task(result_tce); - } - - // Temporarily needed until the deprecated putn is removed. - virtual pplx::task _putn(const _CharType *ptr, size_t count, bool copy) - { - if (copy) - { - auto sharedData = std::make_shared>(ptr, ptr + count); - return _putn(ptr, count).then([sharedData](size_t size) - { - return size; - }); - } - else - { - return _putn(ptr, count); - } - } + /// + /// Allocates a contiguous memory block and returns it. + /// + /// The number of characters to allocate. + /// A pointer to a block to write to, null if the stream buffer implementation does not support + /// alloc/commit. + _CharType* _alloc(size_t) { return nullptr; } - /// - /// Reads a single byte from the stream and advance the read position. - /// - /// A task that holds the value of the byte read. This is EOF if the read fails. - virtual pplx::task _bumpc() - { - return m_readOps.enqueue_operation([this]()-> pplx::task { - if ( _in_avail_unprot() > 0 ) - { - pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); + /// + /// Submits a block already allocated by the stream buffer. + /// + /// Count of characters to be committed. + void _commit(size_t) {} - // Check again once the lock is held. + /// + /// Gets a pointer to the next already allocated contiguous block of data. + /// + /// A reference to a pointer variable that will hold the address of the block on success. + /// The number of contiguous characters available at the address in 'ptr'. + /// true if the operation succeeded, false otherwise. + /// + /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that + /// there is no block to return immediately or that the stream buffer does not support the operation. + /// The stream buffer may not de-allocate the block until is called. + /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; + /// a subsequent read will not succeed. + /// + virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) + { + ptr = nullptr; + count = 0; + return false; + } - if ( _in_avail_unprot() > 0 ) - { - auto bufoff = m_info->m_rdpos - m_info->m_bufoff; - _CharType ch = m_info->m_buffer[bufoff*sizeof(_CharType)]; - m_info->m_rdpos += 1; - return pplx::task_from_result(ch); - } - } + /// + /// Releases a block of data acquired using . This frees the stream buffer to + /// de-allocate the memory, if it so desires. Move the read position ahead by the count. + /// + /// A pointer to the block of data to be released. + /// The number of characters that were read. + virtual void release(_Out_writes_(count) _CharType*, _In_ size_t count) { (void)(count); } - auto result_tce = pplx::task_completion_event(); - auto callback = new _filestream_callback_bumpc(m_info, result_tce); + /// + /// Writes a number of characters to the stream. + /// + /// A pointer to the block of data to be written. + /// The number of characters to write. + /// A task that holds the number of characters actually written, either 'count' or 0. + virtual pplx::task _putn(const _CharType* ptr, size_t count) + { + auto result_tce = pplx::task_completion_event(); + auto callback = new _filestream_callback_write(m_info, result_tce); - size_t ch = _getn_fsb(m_info, callback, &callback->m_ch, 1, sizeof(_CharType)); + size_t written = _putn_fsb(m_info, callback, ptr, count, sizeof(_CharType)); - if ( ch == sizeof(_CharType) ) - { - pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); - m_info->m_rdpos += 1; - _CharType ch1 = (_CharType)callback->m_ch; - delete callback; - return pplx::task_from_result(ch1); - } - return pplx::create_task(result_tce); - }); + if (written != 0 && written != size_t(-1)) + { + delete callback; + written = written / sizeof(_CharType); + return pplx::task_from_result(written); } + return pplx::create_task(result_tce); + } - /// - /// Reads a single byte from the stream and advance the read position. - /// - /// The value of the byte. EOF if the read fails. if an asynchronous read is required - /// This is a synchronous operation, but is guaranteed to never block. - virtual int_type _sbumpc() + // Temporarily needed until the deprecated putn is removed. + virtual pplx::task _putn(const _CharType* ptr, size_t count, bool copy) + { + if (copy) { - m_readOps.wait(); - if ( m_info->m_atend ) return traits::eof(); - - if ( _in_avail_unprot() == 0 ) return traits::requires_async(); - - pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); - - if ( _in_avail_unprot() == 0 ) return traits::requires_async(); - - auto bufoff = m_info->m_rdpos - m_info->m_bufoff; - _CharType ch = m_info->m_buffer[bufoff*sizeof(_CharType)]; - m_info->m_rdpos += 1; - return (int_type)ch; + auto sharedData = std::make_shared>(ptr, ptr + count); + return _putn(ptr, count).then([sharedData](size_t size) { return size; }); } - - pplx::task _getcImpl() + else { - if ( _in_avail_unprot() > 0 ) + return _putn(ptr, count); + } + } + + /// + /// Reads a single byte from the stream and advance the read position. + /// + /// A task that holds the value of the byte read. This is EOF if the read fails. + virtual pplx::task _bumpc() + { + return m_readOps.enqueue_operation([this]() -> pplx::task { + if (_in_avail_unprot() > 0) { pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); // Check again once the lock is held. - if ( _in_avail_unprot() > 0 ) + if (_in_avail_unprot() > 0) { auto bufoff = m_info->m_rdpos - m_info->m_bufoff; - _CharType ch = m_info->m_buffer[bufoff*sizeof(_CharType)]; + _CharType ch = m_info->m_buffer[bufoff * sizeof(_CharType)]; + m_info->m_rdpos += 1; return pplx::task_from_result(ch); } } auto result_tce = pplx::task_completion_event(); - auto callback = new _filestream_callback_getc(m_info, result_tce); + auto callback = new _filestream_callback_bumpc(m_info, result_tce); size_t ch = _getn_fsb(m_info, callback, &callback->m_ch, 1, sizeof(_CharType)); - if ( ch == sizeof(_CharType) ) + if (ch == sizeof(_CharType)) { pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); + m_info->m_rdpos += 1; _CharType ch1 = (_CharType)callback->m_ch; delete callback; return pplx::task_from_result(ch1); } return pplx::create_task(result_tce); + }); + } - } + /// + /// Reads a single byte from the stream and advance the read position. + /// + /// The value of the byte. EOF if the read fails. if an asynchronous + /// read is required This is a synchronous operation, but is guaranteed to never block. + virtual int_type _sbumpc() + { + m_readOps.wait(); + if (m_info->m_atend) return traits::eof(); - /// - /// Reads a single byte from the stream without advancing the read position. - /// - /// The value of the byte. EOF if the read fails. - pplx::task _getc() - { - return m_readOps.enqueue_operation([this]()-> pplx::task { - return _getcImpl(); - }); - } + if (_in_avail_unprot() == 0) return traits::requires_async(); - /// - /// Reads a single byte from the stream without advancing the read position. - /// - /// The value of the byte. EOF if the read fails. if an asynchronous read is required - /// This is a synchronous operation, but is guaranteed to never block. - int_type _sgetc() - { - m_readOps.wait(); - if ( m_info->m_atend ) return traits::eof(); + pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); - if ( _in_avail_unprot() == 0 ) return traits::requires_async(); + if (_in_avail_unprot() == 0) return traits::requires_async(); + auto bufoff = m_info->m_rdpos - m_info->m_bufoff; + _CharType ch = m_info->m_buffer[bufoff * sizeof(_CharType)]; + m_info->m_rdpos += 1; + return (int_type)ch; + } + + pplx::task _getcImpl() + { + if (_in_avail_unprot() > 0) + { pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); - if ( _in_avail_unprot() == 0 ) return traits::requires_async(); + // Check again once the lock is held. - auto bufoff = m_info->m_rdpos - m_info->m_bufoff; - _CharType ch = m_info->m_buffer[bufoff*sizeof(_CharType)]; - return (int_type)ch; + if (_in_avail_unprot() > 0) + { + auto bufoff = m_info->m_rdpos - m_info->m_bufoff; + _CharType ch = m_info->m_buffer[bufoff * sizeof(_CharType)]; + return pplx::task_from_result(ch); + } } - /// - /// Advances the read position, then return the next character without advancing again. - /// - /// A task that holds the value of the byte, which is EOF if the read fails. - virtual pplx::task _nextc() - { - return m_readOps.enqueue_operation([this]()-> pplx::task { - _seekrdpos_fsb(m_info, m_info->m_rdpos+1, sizeof(_CharType)); - if ( m_info->m_atend ) - return pplx::task_from_result(basic_file_buffer<_CharType>::traits::eof()); - return this->_getcImpl(); - }); - } + auto result_tce = pplx::task_completion_event(); + auto callback = new _filestream_callback_getc(m_info, result_tce); - /// - /// Retreats the read position, then return the current character without advancing. - /// - /// A task that holds the value of the byte. The value is EOF if the read fails, requires_async if an asynchronous read is required - virtual pplx::task _ungetc() + size_t ch = _getn_fsb(m_info, callback, &callback->m_ch, 1, sizeof(_CharType)); + + if (ch == sizeof(_CharType)) { - return m_readOps.enqueue_operation([this]()-> pplx::task { - if ( m_info->m_rdpos == 0 ) - return pplx::task_from_result(basic_file_buffer<_CharType>::traits::eof()); - _seekrdpos_fsb(m_info, m_info->m_rdpos-1, sizeof(_CharType)); - return this->_getcImpl(); - }); + pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); + _CharType ch1 = (_CharType)callback->m_ch; + delete callback; + return pplx::task_from_result(ch1); } + return pplx::create_task(result_tce); + } - /// - /// Reads up to a given number of characters from the stream. - /// - /// The address of the target memory area - /// The maximum number of characters to read - /// A task that holds the number of characters read. This number is O if the end of the stream is reached, EOF if there is some error. - virtual pplx::task _getn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - return m_readOps.enqueue_operation([=] ()-> pplx::task{ - if ( m_info->m_atend || count == 0 ) - return pplx::task_from_result(0); + /// + /// Reads a single byte from the stream without advancing the read position. + /// + /// The value of the byte. EOF if the read fails. + pplx::task _getc() + { + return m_readOps.enqueue_operation([this]() -> pplx::task { return _getcImpl(); }); + } - if ( _in_avail_unprot() >= count ) - { - pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); + /// + /// Reads a single byte from the stream without advancing the read position. + /// + /// The value of the byte. EOF if the read fails. if an asynchronous + /// read is required This is a synchronous operation, but is guaranteed to never block. + int_type _sgetc() + { + m_readOps.wait(); + if (m_info->m_atend) return traits::eof(); - // Check again once the lock is held. + if (_in_avail_unprot() == 0) return traits::requires_async(); - if ( _in_avail_unprot() >= count ) - { - auto bufoff = m_info->m_rdpos - m_info->m_bufoff; - std::memcpy((void *)ptr, this->m_info->m_buffer+bufoff*sizeof(_CharType), count*sizeof(_CharType)); + pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); - m_info->m_rdpos += count; - return pplx::task_from_result(count); - } - } + if (_in_avail_unprot() == 0) return traits::requires_async(); + + auto bufoff = m_info->m_rdpos - m_info->m_bufoff; + _CharType ch = m_info->m_buffer[bufoff * sizeof(_CharType)]; + return (int_type)ch; + } + + /// + /// Advances the read position, then return the next character without advancing again. + /// + /// A task that holds the value of the byte, which is EOF if the read fails. + virtual pplx::task _nextc() + { + return m_readOps.enqueue_operation([this]() -> pplx::task { + _seekrdpos_fsb(m_info, m_info->m_rdpos + 1, sizeof(_CharType)); + if (m_info->m_atend) return pplx::task_from_result(basic_file_buffer<_CharType>::traits::eof()); + return this->_getcImpl(); + }); + } + + /// + /// Retreats the read position, then return the current character without advancing. + /// + /// A task that holds the value of the byte. The value is EOF if the read fails, + /// requires_async if an asynchronous read is required + virtual pplx::task _ungetc() + { + return m_readOps.enqueue_operation([this]() -> pplx::task { + if (m_info->m_rdpos == 0) + return pplx::task_from_result(basic_file_buffer<_CharType>::traits::eof()); + _seekrdpos_fsb(m_info, m_info->m_rdpos - 1, sizeof(_CharType)); + return this->_getcImpl(); + }); + } + + /// + /// Reads up to a given number of characters from the stream. + /// + /// The address of the target memory area + /// The maximum number of characters to read + /// A task that holds the number of characters read. This number is O if the end of the stream is + /// reached, EOF if there is some error. + virtual pplx::task _getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + return m_readOps.enqueue_operation([=]() -> pplx::task { + if (m_info->m_atend || count == 0) return pplx::task_from_result(0); - auto result_tce = pplx::task_completion_event(); - auto callback = new _filestream_callback_read(m_info, result_tce); + if (_in_avail_unprot() >= count) + { + pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); - size_t read = _getn_fsb(m_info, callback, ptr, count, sizeof(_CharType)); + // Check again once the lock is held. - if ( read != 0 && read != size_t(-1) ) + if (_in_avail_unprot() >= count) { - delete callback; - pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); - m_info->m_rdpos += read/sizeof(_CharType); - return pplx::task_from_result(read/sizeof(_CharType)); + auto bufoff = m_info->m_rdpos - m_info->m_bufoff; + std::memcpy( + (void*)ptr, this->m_info->m_buffer + bufoff * sizeof(_CharType), count * sizeof(_CharType)); + + m_info->m_rdpos += count; + return pplx::task_from_result(count); } - return pplx::create_task(result_tce); - }); - } + } - /// - /// Reads up to a given number of characters from the stream. - /// - /// The address of the target memory area - /// The maximum number of characters to read - /// The number of characters read. O if the end of the stream is reached or an asynchronous read is required. - /// This is a synchronous operation, but is guaranteed to never block. - size_t _sgetn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - m_readOps.wait(); - if ( m_info->m_atend ) return 0; + auto result_tce = pplx::task_completion_event(); + auto callback = new _filestream_callback_read(m_info, result_tce); - if ( count == 0 || in_avail() == 0 ) return 0; + size_t read = _getn_fsb(m_info, callback, ptr, count, sizeof(_CharType)); - pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); + if (read != 0 && read != size_t(-1)) + { + delete callback; + pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); + m_info->m_rdpos += read / sizeof(_CharType); + return pplx::task_from_result(read / sizeof(_CharType)); + } + return pplx::create_task(result_tce); + }); + } - size_t available = _in_avail_unprot(); - size_t copy = (count < available) ? count : available; + /// + /// Reads up to a given number of characters from the stream. + /// + /// The address of the target memory area + /// The maximum number of characters to read + /// The number of characters read. O if the end of the stream is reached or an asynchronous read is + /// required. This is a synchronous operation, but is guaranteed to never block. + size_t _sgetn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + m_readOps.wait(); + if (m_info->m_atend) return 0; - auto bufoff = m_info->m_rdpos - m_info->m_bufoff; - std::memcpy((void *)ptr, this->m_info->m_buffer+bufoff*sizeof(_CharType), copy*sizeof(_CharType)); + if (count == 0 || in_avail() == 0) return 0; - m_info->m_rdpos += copy; - m_info->m_atend = (copy < count); - return copy; - } + pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); - /// - /// Copies up to a given number of characters from the stream. - /// - /// The address of the target memory area - /// The maximum number of characters to copy - /// The number of characters copied. O if the end of the stream is reached or an asynchronous read is required. - /// This is a synchronous operation, but is guaranteed to never block. - virtual size_t _scopy(_CharType *, size_t) - { - return 0; - } + size_t available = _in_avail_unprot(); + size_t copy = (count < available) ? count : available; + + auto bufoff = m_info->m_rdpos - m_info->m_bufoff; + std::memcpy((void*)ptr, this->m_info->m_buffer + bufoff * sizeof(_CharType), copy * sizeof(_CharType)); + + m_info->m_rdpos += copy; + m_info->m_atend = (copy < count); + return copy; + } + + /// + /// Copies up to a given number of characters from the stream. + /// + /// The address of the target memory area + /// The maximum number of characters to copy + /// The number of characters copied. O if the end of the stream is reached or an asynchronous read is + /// required. This is a synchronous operation, but is guaranteed to never block. + virtual size_t _scopy(_CharType*, size_t) { return 0; } + + /// + /// Gets the current read or write position in the stream. + /// + /// The I/O direction to seek (see remarks) + /// The current position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the direction parameter defines whether to move the read or the write + /// cursor. + virtual pos_type getpos(std::ios_base::openmode mode) const + { + return const_cast(this)->seekoff(0, std::ios_base::cur, mode); + } - /// - /// Gets the current read or write position in the stream. - /// - /// The I/O direction to seek (see remarks) - /// The current position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual pos_type getpos(std::ios_base::openmode mode) const + /// + /// Seeks to the given position. + /// + /// The offset from the beginning of the stream + /// The I/O direction to seek (see remarks) + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the direction parameter defines whether to move the read or the write + /// cursor. + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode) + { + if (mode == std::ios_base::in) { - return const_cast(this)->seekoff(0, std::ios_base::cur, mode); + m_readOps.wait(); + return (pos_type)_seekrdpos_fsb(m_info, size_t(pos), sizeof(_CharType)); } - - /// - /// Seeks to the given position. - /// - /// The offset from the beginning of the stream - /// The I/O direction to seek (see remarks) - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode) + else if ((m_info->m_mode & std::ios::ios_base::app) == 0) { - if ( mode == std::ios_base::in ) - { - m_readOps.wait(); - return (pos_type)_seekrdpos_fsb(m_info, size_t(pos), sizeof(_CharType)); - } - else if ( (m_info->m_mode & std::ios::ios_base::app) == 0 ) - { - return (pos_type)_seekwrpos_fsb(m_info, size_t(pos), sizeof(_CharType)); - } - return (pos_type)Concurrency::streams::char_traits<_CharType>::eof(); + return (pos_type)_seekwrpos_fsb(m_info, size_t(pos), sizeof(_CharType)); } + return (pos_type)Concurrency::streams::char_traits<_CharType>::eof(); + } - /// - /// Seeks to a position given by a relative offset. - /// - /// The relative position to seek to - /// The starting point (beginning, end, current) for the seek. - /// The I/O direction to seek (see remarks) - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the mode parameter defines whether to move the read or the write cursor. - virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) + /// + /// Seeks to a position given by a relative offset. + /// + /// The relative position to seek to + /// The starting point (beginning, end, current) for the seek. + /// The I/O direction to seek (see remarks) + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the mode parameter defines whether to move the read or the write cursor. + virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) + { + if (mode == std::ios_base::in) { - if ( mode == std::ios_base::in ) + m_readOps.wait(); + switch (way) { - m_readOps.wait(); - switch ( way ) - { - case std::ios_base::beg: - return (pos_type)_seekrdpos_fsb(m_info, size_t(offset), sizeof(_CharType)); + case std::ios_base::beg: return (pos_type)_seekrdpos_fsb(m_info, size_t(offset), sizeof(_CharType)); case std::ios_base::cur: - return (pos_type)_seekrdpos_fsb(m_info, size_t(m_info->m_rdpos+offset), sizeof(_CharType)); - case std::ios_base::end: - return (pos_type)_seekrdtoend_fsb(m_info, int64_t(offset), sizeof(_CharType)); + return (pos_type)_seekrdpos_fsb(m_info, size_t(m_info->m_rdpos + offset), sizeof(_CharType)); + case std::ios_base::end: return (pos_type)_seekrdtoend_fsb(m_info, int64_t(offset), sizeof(_CharType)); default: // Fail on invalid input (_S_ios_seekdir_end) assert(false); - } } - else if ( (m_info->m_mode & std::ios::ios_base::app) == 0 ) + } + else if ((m_info->m_mode & std::ios::ios_base::app) == 0) + { + switch (way) { - switch ( way ) - { - case std::ios_base::beg: - return (pos_type)_seekwrpos_fsb(m_info, size_t(offset), sizeof(_CharType)); + case std::ios_base::beg: return (pos_type)_seekwrpos_fsb(m_info, size_t(offset), sizeof(_CharType)); case std::ios_base::cur: - return (pos_type)_seekwrpos_fsb(m_info, size_t(m_info->m_wrpos+offset), sizeof(_CharType)); - case std::ios_base::end: - return (pos_type)_seekwrpos_fsb(m_info, size_t(-1), sizeof(_CharType)); + return (pos_type)_seekwrpos_fsb(m_info, size_t(m_info->m_wrpos + offset), sizeof(_CharType)); + case std::ios_base::end: return (pos_type)_seekwrpos_fsb(m_info, size_t(-1), sizeof(_CharType)); default: // Fail on invalid input (_S_ios_seekdir_end) assert(false); - } } - return (pos_type)traits::eof(); } + return (pos_type)traits::eof(); + } - /// - /// For output streams, flush any internally buffered data to the underlying medium. - /// - virtual pplx::task _sync() - { - return flush_internal().then([](){return true;}); - } + /// + /// For output streams, flush any internally buffered data to the underlying medium. + /// + virtual pplx::task _sync() + { + return flush_internal().then([]() { return true; }); + } - private: - template friend class ::concurrency::streams::file_buffer; +private: + template + friend class ::concurrency::streams::file_buffer; - pplx::task flush_internal() - { - pplx::task_completion_event result_tce; - auto callback = utility::details::make_unique<_filestream_callback_write_b>(m_info, result_tce); + pplx::task flush_internal() + { + pplx::task_completion_event result_tce; + auto callback = utility::details::make_unique<_filestream_callback_write_b>(m_info, result_tce); - if ( !_sync_fsb(m_info, callback.get()) ) - { - return pplx::task_from_exception(std::runtime_error("failure to flush stream")); - } - callback.release(); - return pplx::create_task(result_tce); + if (!_sync_fsb(m_info, callback.get())) + { + return pplx::task_from_exception(std::runtime_error("failure to flush stream")); } + callback.release(); + return pplx::create_task(result_tce); + } - basic_file_buffer(_In_ _file_info *info) : streambuf_state_manager<_CharType>(info->m_mode), m_info(info) { } + basic_file_buffer(_In_ _file_info* info) : streambuf_state_manager<_CharType>(info->m_mode), m_info(info) {} #if !defined(__cplusplus_winrt) - static pplx::task>> open( - const utility::string_t &_Filename, - std::ios_base::openmode _Mode = std::ios_base::out, + static pplx::task>> open( + const utility::string_t& _Filename, + std::ios_base::openmode _Mode = std::ios_base::out, #ifdef _WIN32 - int _Prot = (int)std::ios_base::_Openprot + int _Prot = (int)std::ios_base::_Openprot #else - int _Prot = 0 // unsupported on Linux, for now + int _Prot = 0 // unsupported on Linux, for now #endif - ) - { - auto result_tce = pplx::task_completion_event>>(); - auto callback = new _filestream_callback_open(result_tce); - _open_fsb_str(callback, _Filename.c_str(), _Mode, _Prot); - return pplx::create_task(result_tce); - } + ) + { + auto result_tce = pplx::task_completion_event>>(); + auto callback = new _filestream_callback_open(result_tce); + _open_fsb_str(callback, _Filename.c_str(), _Mode, _Prot); + return pplx::create_task(result_tce); + } #else - static pplx::task>> open( - ::Windows::Storage::StorageFile^ file, - std::ios_base::openmode _Mode = std::ios_base::out) + static pplx::task>> open( + ::Windows::Storage::StorageFile ^ file, std::ios_base::openmode _Mode = std::ios_base::out) + { + auto result_tce = pplx::task_completion_event>>(); + auto callback = new _filestream_callback_open(result_tce); + _open_fsb_stf_str(callback, file, _Mode, 0); + return pplx::create_task(result_tce); + } +#endif + + class _filestream_callback_open : public details::_filestream_callback + { + public: + _filestream_callback_open(const pplx::task_completion_event>>& op) + : m_op(op) { - auto result_tce = pplx::task_completion_event>>(); - auto callback = new _filestream_callback_open(result_tce); - _open_fsb_stf_str(callback, file, _Mode, 0); - return pplx::create_task(result_tce); } -#endif - class _filestream_callback_open : public details::_filestream_callback + virtual void on_opened(_In_ _file_info* info) { - public: - _filestream_callback_open(const pplx::task_completion_event>> &op) : m_op(op) { } + m_op.set(std::shared_ptr>(new basic_file_buffer<_CharType>(info))); + delete this; + } - virtual void on_opened(_In_ _file_info *info) - { - m_op.set(std::shared_ptr>(new basic_file_buffer<_CharType>(info))); - delete this; - } + virtual void on_error(const std::exception_ptr& e) + { + m_op.set_exception(e); + delete this; + } - virtual void on_error(const std::exception_ptr & e) - { - m_op.set_exception(e); - delete this; - } + private: + pplx::task_completion_event>> m_op; + }; - private: - pplx::task_completion_event>> m_op; - }; + class _filestream_callback_close : public details::_filestream_callback + { + public: + _filestream_callback_close(const pplx::task_completion_event& op) : m_op(op) {} - class _filestream_callback_close : public details::_filestream_callback + virtual void on_closed() { - public: - _filestream_callback_close(const pplx::task_completion_event &op) : m_op(op) { } - - virtual void on_closed() - { - m_op.set(); - delete this; - } + m_op.set(); + delete this; + } - virtual void on_error(const std::exception_ptr & e) - { - m_op.set_exception(e); - delete this; - } + virtual void on_error(const std::exception_ptr& e) + { + m_op.set_exception(e); + delete this; + } - private: - pplx::task_completion_event m_op; - }; + private: + pplx::task_completion_event m_op; + }; - template - class _filestream_callback_write : public details::_filestream_callback + template + class _filestream_callback_write : public details::_filestream_callback + { + public: + _filestream_callback_write(_In_ _file_info* info, const pplx::task_completion_event& op) + : m_info(info), m_op(op) { - public: - _filestream_callback_write(_In_ _file_info *info, const pplx::task_completion_event &op) : m_info(info), m_op(op) { } + } - virtual void on_completed(size_t result) - { - m_op.set((ResultType)result / sizeof(_CharType)); - delete this; - } + virtual void on_completed(size_t result) + { + m_op.set((ResultType)result / sizeof(_CharType)); + delete this; + } - virtual void on_error(const std::exception_ptr & e) - { - m_op.set_exception(e); - delete this; - } + virtual void on_error(const std::exception_ptr& e) + { + m_op.set_exception(e); + delete this; + } - private: - _file_info *m_info; - pplx::task_completion_event m_op; - }; + private: + _file_info* m_info; + pplx::task_completion_event m_op; + }; - class _filestream_callback_write_b : public details::_filestream_callback + class _filestream_callback_write_b : public details::_filestream_callback + { + public: + _filestream_callback_write_b(_In_ _file_info* info, const pplx::task_completion_event& op) + : m_info(info), m_op(op) { - public: - _filestream_callback_write_b(_In_ _file_info *info, const pplx::task_completion_event &op) : m_info(info), m_op(op) { } - - virtual void on_completed(size_t) - { - m_op.set(); - delete this; - } + } - virtual void on_error(const std::exception_ptr & e) - { - m_op.set_exception(e); - delete this; - } + virtual void on_completed(size_t) + { + m_op.set(); + delete this; + } - private: - _file_info *m_info; - pplx::task_completion_event m_op; - }; + virtual void on_error(const std::exception_ptr& e) + { + m_op.set_exception(e); + delete this; + } + private: + _file_info* m_info; + pplx::task_completion_event m_op; + }; - class _filestream_callback_read : public details::_filestream_callback + class _filestream_callback_read : public details::_filestream_callback + { + public: + _filestream_callback_read(_In_ _file_info* info, const pplx::task_completion_event& op) + : m_info(info), m_op(op) { - public: - _filestream_callback_read(_In_ _file_info *info, const pplx::task_completion_event &op) : m_info(info), m_op(op) { } + } - virtual void on_completed(size_t result) - { - result = result / sizeof(_CharType); - m_info->m_rdpos += result; - m_op.set(result); - delete this; - } + virtual void on_completed(size_t result) + { + result = result / sizeof(_CharType); + m_info->m_rdpos += result; + m_op.set(result); + delete this; + } - virtual void on_error(const std::exception_ptr & e) - { - m_op.set_exception(e); - delete this; - } + virtual void on_error(const std::exception_ptr& e) + { + m_op.set_exception(e); + delete this; + } - private: - _file_info *m_info; - pplx::task_completion_event m_op; - }; + private: + _file_info* m_info; + pplx::task_completion_event m_op; + }; - class _filestream_callback_bumpc : public details::_filestream_callback + class _filestream_callback_bumpc : public details::_filestream_callback + { + public: + _filestream_callback_bumpc(_In_ _file_info* info, const pplx::task_completion_event& op) + : m_ch(0), m_info(info), m_op(op) { - public: - _filestream_callback_bumpc(_In_ _file_info *info, const pplx::task_completion_event &op) : m_ch(0), m_info(info), m_op(op) { } + } - virtual void on_completed(size_t result) + virtual void on_completed(size_t result) + { + if (result == sizeof(_CharType)) { - if ( result == sizeof(_CharType) ) - { - m_info->m_rdpos += 1; - m_op.set(m_ch); - } - else - { - m_op.set(traits::eof()); - } - delete this; + m_info->m_rdpos += 1; + m_op.set(m_ch); } - - virtual void on_error(const std::exception_ptr & e) + else { - m_op.set_exception(e); - delete this; + m_op.set(traits::eof()); } + delete this; + } - int_type m_ch; + virtual void on_error(const std::exception_ptr& e) + { + m_op.set_exception(e); + delete this; + } + + int_type m_ch; - private: - _file_info *m_info; - pplx::task_completion_event m_op; - }; + private: + _file_info* m_info; + pplx::task_completion_event m_op; + }; - class _filestream_callback_getc : public details::_filestream_callback + class _filestream_callback_getc : public details::_filestream_callback + { + public: + _filestream_callback_getc(_In_ _file_info* info, const pplx::task_completion_event& op) + : m_ch(0), m_info(info), m_op(op) { - public: - _filestream_callback_getc(_In_ _file_info *info, const pplx::task_completion_event &op) : m_ch(0), m_info(info), m_op(op) { } + } - virtual void on_completed(size_t result) + virtual void on_completed(size_t result) + { + if (result == sizeof(_CharType)) { - if ( result == sizeof(_CharType) ) - { - m_op.set(m_ch); - } - else - { - m_op.set(traits::eof()); - } - delete this; + m_op.set(m_ch); } - - int_type m_ch; - - virtual void on_error(const std::exception_ptr & e) + else { - m_op.set_exception(e); - delete this; + m_op.set(traits::eof()); } + delete this; + } - private: - _file_info *m_info; - pplx::task_completion_event m_op; - }; + int_type m_ch; + + virtual void on_error(const std::exception_ptr& e) + { + m_op.set_exception(e); + delete this; + } - _file_info *m_info; - async_operation_queue m_readOps; + private: + _file_info* m_info; + pplx::task_completion_event m_op; }; - } // namespace details + _file_info* m_info; + async_operation_queue m_readOps; +}; + +} // namespace details +/// +/// Stream buffer for file streams. +/// +/// +/// The data type of the basic element of the file_buffer. +/// +template +class file_buffer +{ +public: +#if !defined(__cplusplus_winrt) /// - /// Stream buffer for file streams. + /// Open a new stream buffer representing the given file. /// - /// - /// The data type of the basic element of the file_buffer. - /// - template - class file_buffer - { - public: -#if !defined(__cplusplus_winrt) - /// - /// Open a new stream buffer representing the given file. - /// - /// The name of the file - /// The opening mode of the file - /// The file protection mode - /// A task that returns an opened stream buffer on completion. - static pplx::task> open( - const utility::string_t &file_name, - std::ios_base::openmode mode = std::ios_base::out, + /// The name of the file + /// The opening mode of the file + /// The file protection mode + /// A task that returns an opened stream buffer on completion. + static pplx::task> open(const utility::string_t& file_name, + std::ios_base::openmode mode = std::ios_base::out, #ifdef _WIN32 - int prot = _SH_DENYRD + int prot = _SH_DENYRD #else - int prot = 0 // unsupported on Linux + int prot = 0 // unsupported on Linux #endif - ) - { - auto bfb = details::basic_file_buffer<_CharType>::open(file_name, mode, prot); - return bfb.then([](pplx::task>> op) -> streambuf<_CharType> - { - return streambuf<_CharType>(op.get()); - }); - } + ) + { + auto bfb = details::basic_file_buffer<_CharType>::open(file_name, mode, prot); + return bfb.then( + [](pplx::task>> op) -> streambuf<_CharType> { + return streambuf<_CharType>(op.get()); + }); + } #else - /// - /// Open a new stream buffer representing the given file. - /// - /// The StorageFile instance - /// The opening mode of the file - /// The file protection mode - /// A task that returns an opened stream buffer on completion. - static pplx::task> open( - ::Windows::Storage::StorageFile^ file, - std::ios_base::openmode mode = std::ios_base::out) - { - auto bfb = details::basic_file_buffer<_CharType>::open(file, mode); - return bfb.then([](pplx::task>> op) -> streambuf<_CharType> - { - return streambuf<_CharType>(op.get()); - }); - } -#endif - }; - - /// - /// File stream class containing factory functions for file streams. + /// Open a new stream buffer representing the given file. /// - /// - /// The data type of the basic element of the file_stream. - /// - template - class file_stream + /// The StorageFile instance + /// The opening mode of the file + /// The file protection mode + /// A task that returns an opened stream buffer on completion. + static pplx::task> open(::Windows::Storage::StorageFile ^ file, + std::ios_base::openmode mode = std::ios_base::out) { - public: - + auto bfb = details::basic_file_buffer<_CharType>::open(file, mode); + return bfb.then( + [](pplx::task>> op) -> streambuf<_CharType> { + return streambuf<_CharType>(op.get()); + }); + } +#endif +}; + +/// +/// File stream class containing factory functions for file streams. +/// +/// +/// The data type of the basic element of the file_stream. +/// +template +class file_stream +{ +public: #if !defined(__cplusplus_winrt) - /// - /// Open a new input stream representing the given file. - /// The file should already exist on disk, or an exception will be thrown. - /// - /// The name of the file - /// The opening mode of the file - /// The file protection mode - /// A task that returns an opened input stream on completion. - static pplx::task> open_istream( - const utility::string_t &file_name, - std::ios_base::openmode mode = std::ios_base::in, + /// + /// Open a new input stream representing the given file. + /// The file should already exist on disk, or an exception will be thrown. + /// + /// The name of the file + /// The opening mode of the file + /// The file protection mode + /// A task that returns an opened input stream on completion. + static pplx::task> open_istream(const utility::string_t& file_name, + std::ios_base::openmode mode = std::ios_base::in, #ifdef _WIN32 - int prot = (int) std::ios_base::_Openprot + int prot = (int)std::ios_base::_Openprot #else - int prot = 0 + int prot = 0 #endif - ) - { - mode |= std::ios_base::in; - return streams::file_buffer<_CharType>::open(file_name, mode, prot) - .then([](streams::streambuf<_CharType> buf) -> basic_istream<_CharType> - { - return basic_istream<_CharType>(buf); - }); - } + ) + { + mode |= std::ios_base::in; + return streams::file_buffer<_CharType>::open(file_name, mode, prot) + .then([](streams::streambuf<_CharType> buf) -> basic_istream<_CharType> { + return basic_istream<_CharType>(buf); + }); + } - /// - /// Open a new output stream representing the given file. - /// If the file does not exist, it will be create unless the folder or directory - /// where it is to be found also does not exist. - /// - /// The name of the file - /// The opening mode of the file - /// The file protection mode - /// A task that returns an opened output stream on completion. - static pplx::task> open_ostream( - const utility::string_t &file_name, - std::ios_base::openmode mode = std::ios_base::out, + /// + /// Open a new output stream representing the given file. + /// If the file does not exist, it will be create unless the folder or directory + /// where it is to be found also does not exist. + /// + /// The name of the file + /// The opening mode of the file + /// The file protection mode + /// A task that returns an opened output stream on completion. + static pplx::task> open_ostream(const utility::string_t& file_name, + std::ios_base::openmode mode = std::ios_base::out, #ifdef _WIN32 - int prot = (int) std::ios_base::_Openprot + int prot = (int)std::ios_base::_Openprot #else - int prot = 0 + int prot = 0 #endif - ) - { - mode |= std::ios_base::out; - return streams::file_buffer<_CharType>::open(file_name, mode, prot) - .then([](streams::streambuf<_CharType> buf) -> basic_ostream<_CharType> - { - return basic_ostream<_CharType>(buf); - }); - } + ) + { + mode |= std::ios_base::out; + return streams::file_buffer<_CharType>::open(file_name, mode, prot) + .then([](streams::streambuf<_CharType> buf) -> basic_ostream<_CharType> { + return basic_ostream<_CharType>(buf); + }); + } #else - /// - /// Open a new input stream representing the given file. - /// The file should already exist on disk, or an exception will be thrown. - /// - /// The StorageFile reference representing the file - /// The opening mode of the file - /// A task that returns an opened input stream on completion. - static pplx::task> open_istream( - ::Windows::Storage::StorageFile^ file, - std::ios_base::openmode mode = std::ios_base::in) - { - mode |= std::ios_base::in; - return streams::file_buffer<_CharType>::open(file, mode) - .then([](streams::streambuf<_CharType> buf) -> basic_istream<_CharType> - { - return basic_istream<_CharType>(buf); - }); - } + /// + /// Open a new input stream representing the given file. + /// The file should already exist on disk, or an exception will be thrown. + /// + /// The StorageFile reference representing the file + /// The opening mode of the file + /// A task that returns an opened input stream on completion. + static pplx::task> open_istream(::Windows::Storage::StorageFile ^ file, + std::ios_base::openmode mode = std::ios_base::in) + { + mode |= std::ios_base::in; + return streams::file_buffer<_CharType>::open(file, mode) + .then([](streams::streambuf<_CharType> buf) -> basic_istream<_CharType> { + return basic_istream<_CharType>(buf); + }); + } - /// - /// Open a new output stream representing the given file. - /// If the file does not exist, it will be create unless the folder or directory - /// where it is to be found also does not exist. - /// - /// The StorageFile reference representing the file - /// The opening mode of the file - /// A task that returns an opened output stream on completion. - static pplx::task> open_ostream( - ::Windows::Storage::StorageFile^ file, - std::ios_base::openmode mode = std::ios_base::out) - { - mode |= std::ios_base::out; - return streams::file_buffer<_CharType>::open(file, mode) - .then([](streams::streambuf<_CharType> buf) -> basic_ostream<_CharType> - { - return basic_ostream<_CharType>(buf); - }); - } + /// + /// Open a new output stream representing the given file. + /// If the file does not exist, it will be create unless the folder or directory + /// where it is to be found also does not exist. + /// + /// The StorageFile reference representing the file + /// The opening mode of the file + /// A task that returns an opened output stream on completion. + static pplx::task> open_ostream(::Windows::Storage::StorageFile ^ file, + std::ios_base::openmode mode = std::ios_base::out) + { + mode |= std::ios_base::out; + return streams::file_buffer<_CharType>::open(file, mode) + .then([](streams::streambuf<_CharType> buf) -> basic_ostream<_CharType> { + return basic_ostream<_CharType>(buf); + }); + } #endif - }; +}; - typedef file_stream fstream; -}} // namespace concurrency::streams +typedef file_stream fstream; +} // namespace streams +} // namespace Concurrency #endif - - - - - - - - - - - - - - diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index 935bad50ec..743e2b5635 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -1,43 +1,58 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Client-side APIs. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Client-side APIs. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_HTTP_CLIENT_H #define CASA_HTTP_CLIENT_H -#if defined (__cplusplus_winrt) +#if defined(__cplusplus_winrt) #if !defined(__WRL_NO_DEFAULT_LIB__) #define __WRL_NO_DEFAULT_LIB__ #endif -#include #include -namespace web { namespace http{namespace client{ -typedef IXMLHTTPRequest2* native_handle;}}} +#include +namespace web +{ +namespace http +{ +namespace client +{ +typedef IXMLHTTPRequest2* native_handle; +} +} // namespace http +} // namespace web #else -namespace web { namespace http{namespace client{ -typedef void* native_handle;}}} +namespace web +{ +namespace http +{ +namespace client +{ +typedef void* native_handle; +} +} // namespace http +} // namespace web #endif // __cplusplus_winrt -#include -#include - -#include "pplx/pplxtasks.h" +#include "cpprest/asyncrt_utils.h" +#include "cpprest/details/basic_types.h" +#include "cpprest/details/web_utilities.h" #include "cpprest/http_msg.h" #include "cpprest/json.h" #include "cpprest/uri.h" -#include "cpprest/details/web_utilities.h" -#include "cpprest/details/basic_types.h" -#include "cpprest/asyncrt_utils.h" +#include "pplx/pplxtasks.h" +#include +#include #if !defined(CPPREST_TARGET_XP) #include "cpprest/oauth1.h" @@ -65,7 +80,6 @@ namespace http /// HTTP client side library. namespace client { - // credentials and web_proxy class has been moved from web::http::client namespace to web namespace. // The below using declarations ensure we don't break existing code. // Please use the web::credentials and web::web_proxy class going forward. @@ -79,11 +93,11 @@ using web::web_proxy; class http_client_config { public: - http_client_config() : - m_guarantee_order(false), - m_timeout(std::chrono::seconds(30)), - m_chunksize(0), - m_request_compressed(false) + http_client_config() + : m_guarantee_order(false) + , m_timeout(std::chrono::seconds(30)) + , m_chunksize(0) + , m_request_compressed(false) #if !defined(__cplusplus_winrt) , m_validate_certificates(true) #endif @@ -101,10 +115,7 @@ class http_client_config /// Get OAuth 1.0 configuration. /// /// Shared pointer to OAuth 1.0 configuration. - const std::shared_ptr oauth1() const - { - return m_oauth1; - } + const std::shared_ptr oauth1() const { return m_oauth1; } /// /// Set OAuth 1.0 configuration. @@ -120,10 +131,7 @@ class http_client_config /// Get OAuth 2.0 configuration. /// /// Shared pointer to OAuth 2.0 configuration. - const std::shared_ptr oauth2() const - { - return m_oauth2; - } + const std::shared_ptr oauth2() const { return m_oauth2; } /// /// Set OAuth 2.0 configuration. @@ -138,71 +146,51 @@ class http_client_config /// Get the web proxy object /// /// A reference to the web proxy object. - const web_proxy& proxy() const - { - return m_proxy; - } + const web_proxy& proxy() const { return m_proxy; } /// /// Set the web proxy object /// /// A reference to the web proxy object. - void set_proxy(web_proxy proxy) - { - m_proxy = std::move(proxy); - } + void set_proxy(web_proxy proxy) { m_proxy = std::move(proxy); } /// /// Get the client credentials /// /// A reference to the client credentials. - const http::client::credentials& credentials() const - { - return m_credentials; - } + const http::client::credentials& credentials() const { return m_credentials; } /// /// Set the client credentials /// /// A reference to the client credentials. - void set_credentials(const http::client::credentials& cred) - { - m_credentials = cred; - } + void set_credentials(const http::client::credentials& cred) { m_credentials = cred; } /// /// Get the 'guarantee order' property /// /// The value of the property. - bool guarantee_order() const - { - return m_guarantee_order; - } + bool guarantee_order() const { return m_guarantee_order; } /// /// Set the 'guarantee order' property /// /// The value of the property. - CASABLANCA_DEPRECATED("Confusing API will be removed in future releases. If you need to order HTTP requests use task continuations.") - void set_guarantee_order(bool guarantee_order) - { - m_guarantee_order = guarantee_order; - } + CASABLANCA_DEPRECATED( + "Confusing API will be removed in future releases. If you need to order HTTP requests use task continuations.") + void set_guarantee_order(bool guarantee_order) { m_guarantee_order = guarantee_order; } /// /// Get the timeout /// /// The timeout (in seconds) used for each send and receive operation on the client. - utility::seconds timeout() const - { - return std::chrono::duration_cast(m_timeout); - } + utility::seconds timeout() const { return std::chrono::duration_cast(m_timeout); } /// /// Get the timeout /// /// The timeout (in whatever duration) used for each send and receive operation on the client. - template + template T timeout() const { return std::chrono::duration_cast(m_timeout); @@ -210,9 +198,10 @@ class http_client_config /// /// Set the timeout /// - /// The timeout (duration from microseconds range and up) used for each send and receive operation on the client. - template - void set_timeout(const T &timeout) + /// The timeout (duration from microseconds range and up) used for each send and receive + /// operation on the client. + template + void set_timeout(const T& timeout) { m_timeout = std::chrono::duration_cast(timeout); } @@ -220,40 +209,30 @@ class http_client_config /// /// Get the client chunk size. /// - /// The internal buffer size used by the http client when sending and receiving data from the network. - size_t chunksize() const - { - return m_chunksize == 0 ? 64 * 1024 : m_chunksize; - } + /// The internal buffer size used by the http client when sending and receiving data from the + /// network. + size_t chunksize() const { return m_chunksize == 0 ? 64 * 1024 : m_chunksize; } /// /// Sets the client chunk size. /// - /// The internal buffer size used by the http client when sending and receiving data from the network. - /// This is a hint -- an implementation may disregard the setting and use some other chunk size. - void set_chunksize(size_t size) - { - m_chunksize = size; - } + /// The internal buffer size used by the http client when sending and receiving data from the + /// network. This is a hint -- an implementation may disregard the setting and use some other chunk + /// size. + void set_chunksize(size_t size) { m_chunksize = size; } /// /// Returns true if the default chunk size is in use. /// If true, implementations are allowed to choose whatever size is best. /// /// True if default, false if set by user. - bool is_default_chunksize() const - { - return m_chunksize == 0; - } + bool is_default_chunksize() const { return m_chunksize == 0; } /// /// Checks if requesting a compressed response using Content-Encoding is turned on, the default is off. /// /// True if a content-encoded compressed response is allowed, false otherwise - bool request_compressed_response() const - { - return m_request_compressed; - } + bool request_compressed_response() const { return m_request_compressed; } /// /// Request that the server respond with a compressed body using Content-Encoding; to use Transfer-Encoding, do not @@ -262,32 +241,25 @@ class http_client_config /// If true and the server does not support compression, this will have no effect. /// The response body is internally decompressed before the consumer receives the data. /// - /// True to turn on content-encoded response body compression, false otherwise. - /// Please note there is a performance cost due to copying the request data. Currently only supported on Windows and OSX. - void set_request_compressed_response(bool request_compressed) - { - m_request_compressed = request_compressed; - } + /// True to turn on content-encoded response body compression, false + /// otherwise. Please note there is a performance cost due to copying the request data. Currently + /// only supported on Windows and OSX. + void set_request_compressed_response(bool request_compressed) { m_request_compressed = request_compressed; } #if !defined(__cplusplus_winrt) /// /// Gets the server certificate validation property. /// /// True if certificates are to be verified, false otherwise. - bool validate_certificates() const - { - return m_validate_certificates; - } + bool validate_certificates() const { return m_validate_certificates; } /// /// Sets the server certificate validation property. /// - /// False to turn ignore all server certificate validation errors, true otherwise. - /// Note ignoring certificate errors can be dangerous and should be done with caution. - void set_validate_certificates(bool validate_certs) - { - m_validate_certificates = validate_certs; - } + /// False to turn ignore all server certificate validation errors, true + /// otherwise. Note ignoring certificate errors can be dangerous and should be done with + /// caution. + void set_validate_certificates(bool validate_certs) { m_validate_certificates = validate_certs; } #endif #if defined(_WIN32) && !defined(__cplusplus_winrt) @@ -295,10 +267,7 @@ class http_client_config /// Checks if request data buffering is turned on, the default is off. /// /// True if buffering is enabled, false otherwise - bool buffer_request() const - { - return m_buffer_request; - } + bool buffer_request() const { return m_buffer_request; } /// /// Sets the request buffering property. @@ -307,10 +276,7 @@ class http_client_config /// /// True to turn on buffer, false otherwise. /// Please note there is a performance cost due to copying the request data. - void set_buffer_request(bool buffer_request) - { - m_buffer_request = buffer_request; - } + void set_buffer_request(bool buffer_request) { m_buffer_request = buffer_request; } #endif /// @@ -321,7 +287,7 @@ class http_client_config /// Windows Desktop, WinHTTP - HINTERNET (session) /// /// A user callback allowing for customization of the session - void set_nativesessionhandle_options(const std::function &callback) + void set_nativesessionhandle_options(const std::function& callback) { m_set_user_nativesessionhandle_options = callback; } @@ -333,8 +299,7 @@ class http_client_config /// A internal implementation handle. void _invoke_nativesessionhandle_options(native_handle handle) const { - if (m_set_user_nativesessionhandle_options) - m_set_user_nativesessionhandle_options(handle); + if (m_set_user_nativesessionhandle_options) m_set_user_nativesessionhandle_options(handle); } /// @@ -349,9 +314,9 @@ class http_client_config /// http - boost::asio::ip::tcp::socket * /// /// A user callback allowing for customization of the request - void set_nativehandle_options(const std::function &callback) + void set_nativehandle_options(const std::function& callback) { - m_set_user_nativehandle_options = callback; + m_set_user_nativehandle_options = callback; } /// @@ -360,18 +325,18 @@ class http_client_config /// A internal implementation handle. void invoke_nativehandle_options(native_handle handle) const { - if (m_set_user_nativehandle_options) - m_set_user_nativehandle_options(handle); + if (m_set_user_nativehandle_options) m_set_user_nativehandle_options(handle); } #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) /// /// Sets a callback to enable custom setting of the ssl context, at construction time. /// - /// A user callback allowing for customization of the ssl context at construction time. + /// A user callback allowing for customization of the ssl context at construction + /// time. void set_ssl_context_callback(const std::function& callback) { - m_ssl_context_callback = callback; + m_ssl_context_callback = callback; } /// @@ -386,20 +351,15 @@ class http_client_config /// Gets the TLS extension server name indication (SNI) status. /// /// True if TLS server name indication is enabled, false otherwise. - bool is_tlsext_sni_enabled() const - { - return m_tlsext_sni_enabled; - } + bool is_tlsext_sni_enabled() const { return m_tlsext_sni_enabled; } /// /// Sets the TLS extension server name indication (SNI) status. /// - /// False to disable the TLS (ClientHello) extension for server name indication, true otherwise. - /// Note: This setting is enabled by default as it is required in most virtual hosting scenarios. - void set_tlsext_sni_enabled(bool tlsext_sni_enabled) - { - m_tlsext_sni_enabled = tlsext_sni_enabled; - } + /// False to disable the TLS (ClientHello) extension for server name indication, + /// true otherwise. Note: This setting is enabled by default as it is required in most virtual + /// hosting scenarios. + void set_tlsext_sni_enabled(bool tlsext_sni_enabled) { m_tlsext_sni_enabled = tlsext_sni_enabled; } #endif private: @@ -423,7 +383,7 @@ class http_client_config #endif std::function m_set_user_nativehandle_options; - std::function m_set_user_nativesessionhandle_options; + std::function m_set_user_nativesessionhandle_options; #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) std::function m_ssl_context_callback; @@ -445,15 +405,17 @@ class http_client /// /// Creates a new http_client connected to specified uri. /// - /// A string representation of the base uri to be used for all requests. Must start with either "http://" or "https://" - _ASYNCRTIMP http_client(const uri &base_uri); + /// A string representation of the base uri to be used for all requests. Must start with + /// either "http://" or "https://" + _ASYNCRTIMP http_client(const uri& base_uri); /// /// Creates a new http_client connected to specified uri. /// - /// A string representation of the base uri to be used for all requests. Must start with either "http://" or "https://" - /// The http client configuration object containing the possible configuration options to initialize the http_client. - _ASYNCRTIMP http_client(const uri &base_uri, const http_client_config &client_config); + /// A string representation of the base uri to be used for all requests. Must start with + /// either "http://" or "https://" The http client configuration object + /// containing the possible configuration options to initialize the http_client. + _ASYNCRTIMP http_client(const uri& base_uri, const http_client_config& client_config); /// /// Note the destructor doesn't necessarily close the connection and release resources. @@ -479,14 +441,14 @@ class http_client /// Adds an HTTP pipeline stage to the client. /// /// A function object representing the pipeline stage. - _ASYNCRTIMP void add_handler(const std::function __cdecl(http_request, std::shared_ptr)> &handler); - + _ASYNCRTIMP void add_handler(const std::function __cdecl( + http_request, std::shared_ptr)>& handler); /// /// Adds an HTTP pipeline stage to the client. /// /// A shared pointer to a pipeline stage. - _ASYNCRTIMP void add_handler(const std::shared_ptr &stage); + _ASYNCRTIMP void add_handler(const std::shared_ptr& stage); /// /// Asynchronously sends an HTTP request. @@ -494,7 +456,8 @@ class http_client /// Request to send. /// Cancellation token for cancellation of this request operation. /// An asynchronous operation that is completed once a response from the request is received. - _ASYNCRTIMP pplx::task request(http_request request, const pplx::cancellation_token &token = pplx::cancellation_token::none()); + _ASYNCRTIMP pplx::task request( + http_request request, const pplx::cancellation_token& token = pplx::cancellation_token::none()); /// /// Asynchronously sends an HTTP request. @@ -502,7 +465,8 @@ class http_client /// HTTP request method. /// Cancellation token for cancellation of this request operation. /// An asynchronous operation that is completed once a response from the request is received. - pplx::task request(const method &mtd, const pplx::cancellation_token &token = pplx::cancellation_token::none()) + pplx::task request(const method& mtd, + const pplx::cancellation_token& token = pplx::cancellation_token::none()) { http_request msg(mtd); return request(msg, token); @@ -512,13 +476,12 @@ class http_client /// Asynchronously sends an HTTP request. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// Cancellation token for cancellation of this request operation. + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. Cancellation token for cancellation of this request operation. /// An asynchronous operation that is completed once a response from the request is received. - pplx::task request( - const method &mtd, - const utility::string_t &path_query_fragment, - const pplx::cancellation_token &token = pplx::cancellation_token::none()) + pplx::task request(const method& mtd, + const utility::string_t& path_query_fragment, + const pplx::cancellation_token& token = pplx::cancellation_token::none()) { http_request msg(mtd); msg.set_request_uri(path_query_fragment); @@ -529,15 +492,15 @@ class http_client /// Asynchronously sends an HTTP request. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// The data to be used as the message body, represented using the json object library. - /// Cancellation token for cancellation of this request operation. - /// An asynchronous operation that is completed once a response from the request is received. - pplx::task request( - const method &mtd, - const utility::string_t &path_query_fragment, - const json::value &body_data, - const pplx::cancellation_token &token = pplx::cancellation_token::none()) + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. The data to be used as the message body, represented using the json + /// object library. Cancellation token for cancellation of this request + /// operation. An asynchronous operation that is completed once a response from the request is + /// received. + pplx::task request(const method& mtd, + const utility::string_t& path_query_fragment, + const json::value& body_data, + const pplx::cancellation_token& token = pplx::cancellation_token::none()) { http_request msg(mtd); msg.set_request_uri(path_query_fragment); @@ -550,17 +513,16 @@ class http_client /// character encoding of the string is UTF-8. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// A string holding the MIME type of the message body. - /// String containing the text to use in the message body. - /// Cancellation token for cancellation of this request operation. - /// An asynchronous operation that is completed once a response from the request is received. - pplx::task request( - const method &mtd, - const utf8string &path_query_fragment, - const utf8string &body_data, - const utf8string &content_type = "text/plain; charset=utf-8", - const pplx::cancellation_token &token = pplx::cancellation_token::none()) + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. A string holding the MIME type of the message body. String containing the text to use in the message body. Cancellation + /// token for cancellation of this request operation. An asynchronous operation that is completed + /// once a response from the request is received. + pplx::task request(const method& mtd, + const utf8string& path_query_fragment, + const utf8string& body_data, + const utf8string& content_type = "text/plain; charset=utf-8", + const pplx::cancellation_token& token = pplx::cancellation_token::none()) { http_request msg(mtd); msg.set_request_uri(::utility::conversions::to_string_t(path_query_fragment)); @@ -573,17 +535,16 @@ class http_client /// character encoding of the string is UTF-8. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// A string holding the MIME type of the message body. - /// String containing the text to use in the message body. - /// Cancellation token for cancellation of this request operation. - /// An asynchronous operation that is completed once a response from the request is received. - pplx::task request( - const method &mtd, - const utf8string &path_query_fragment, - utf8string &&body_data, - const utf8string &content_type = "text/plain; charset=utf-8", - const pplx::cancellation_token &token = pplx::cancellation_token::none()) + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. A string holding the MIME type of the message body. String containing the text to use in the message body. Cancellation + /// token for cancellation of this request operation. An asynchronous operation that is completed + /// once a response from the request is received. + pplx::task request(const method& mtd, + const utf8string& path_query_fragment, + utf8string&& body_data, + const utf8string& content_type = "text/plain; charset=utf-8", + const pplx::cancellation_token& token = pplx::cancellation_token::none()) { http_request msg(mtd); msg.set_request_uri(::utility::conversions::to_string_t(path_query_fragment)); @@ -596,17 +557,17 @@ class http_client /// character encoding of the string is UTF-16 will perform conversion to UTF-8. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// A string holding the MIME type of the message body. - /// String containing the text to use in the message body. - /// Cancellation token for cancellation of this request operation. - /// An asynchronous operation that is completed once a response from the request is received. + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. A string holding the MIME type of the message body. String containing the text to use in the message body. Cancellation + /// token for cancellation of this request operation. An asynchronous operation that is completed + /// once a response from the request is received. pplx::task request( - const method &mtd, - const utf16string &path_query_fragment, - const utf16string &body_data, - const utf16string &content_type = utility::conversions::to_utf16string("text/plain"), - const pplx::cancellation_token &token = pplx::cancellation_token::none()) + const method& mtd, + const utf16string& path_query_fragment, + const utf16string& body_data, + const utf16string& content_type = utility::conversions::to_utf16string("text/plain"), + const pplx::cancellation_token& token = pplx::cancellation_token::none()) { http_request msg(mtd); msg.set_request_uri(::utility::conversions::to_string_t(path_query_fragment)); @@ -619,15 +580,14 @@ class http_client /// character encoding of the string is UTF-8. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// String containing the text to use in the message body. - /// Cancellation token for cancellation of this request operation. - /// An asynchronous operation that is completed once a response from the request is received. - pplx::task request( - const method &mtd, - const utf8string &path_query_fragment, - const utf8string &body_data, - const pplx::cancellation_token &token) + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. String containing the text to use in the message body. Cancellation token for cancellation of this request operation. An asynchronous + /// operation that is completed once a response from the request is received. + pplx::task request(const method& mtd, + const utf8string& path_query_fragment, + const utf8string& body_data, + const pplx::cancellation_token& token) { return request(mtd, path_query_fragment, body_data, "text/plain; charset=utf-8", token); } @@ -637,15 +597,14 @@ class http_client /// character encoding of the string is UTF-8. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// String containing the text to use in the message body. - /// Cancellation token for cancellation of this request operation. - /// An asynchronous operation that is completed once a response from the request is received. - pplx::task request( - const method &mtd, - const utf8string &path_query_fragment, - utf8string &&body_data, - const pplx::cancellation_token &token) + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. String containing the text to use in the message body. Cancellation token for cancellation of this request operation. An asynchronous + /// operation that is completed once a response from the request is received. + pplx::task request(const method& mtd, + const utf8string& path_query_fragment, + utf8string&& body_data, + const pplx::cancellation_token& token) { http_request msg(mtd); msg.set_request_uri(::utility::conversions::to_string_t(path_query_fragment)); @@ -658,35 +617,34 @@ class http_client /// the character encoding of the string is UTF-16 will perform conversion to UTF-8. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// String containing the text to use in the message body. - /// Cancellation token for cancellation of this request operation. - /// An asynchronous operation that is completed once a response from the request is received. - pplx::task request( - const method &mtd, - const utf16string &path_query_fragment, - const utf16string &body_data, - const pplx::cancellation_token &token) + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. String containing the text to use in the message body. Cancellation token for cancellation of this request operation. An asynchronous + /// operation that is completed once a response from the request is received. + pplx::task request(const method& mtd, + const utf16string& path_query_fragment, + const utf16string& body_data, + const pplx::cancellation_token& token) { - return request(mtd, path_query_fragment, body_data, ::utility::conversions::to_utf16string("text/plain"), token); + return request( + mtd, path_query_fragment, body_data, ::utility::conversions::to_utf16string("text/plain"), token); } -#if !defined (__cplusplus_winrt) +#if !defined(__cplusplus_winrt) /// /// Asynchronously sends an HTTP request. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// An asynchronous stream representing the body data. - /// A string holding the MIME type of the message body. - /// Cancellation token for cancellation of this request operation. - /// A task that is completed once a response from the request is received. - pplx::task request( - const method &mtd, - const utility::string_t &path_query_fragment, - const concurrency::streams::istream &body, - const utility::string_t &content_type = _XPLATSTR("application/octet-stream"), - const pplx::cancellation_token &token = pplx::cancellation_token::none()) + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. An asynchronous stream representing the body data. A string holding the MIME type of the message body. Cancellation + /// token for cancellation of this request operation. A task that is completed once a response from + /// the request is received. + pplx::task request(const method& mtd, + const utility::string_t& path_query_fragment, + const concurrency::streams::istream& body, + const utility::string_t& content_type = _XPLATSTR("application/octet-stream"), + const pplx::cancellation_token& token = pplx::cancellation_token::none()) { http_request msg(mtd); msg.set_request_uri(path_query_fragment); @@ -698,15 +656,14 @@ class http_client /// Asynchronously sends an HTTP request. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// An asynchronous stream representing the body data. - /// Cancellation token for cancellation of this request operation. - /// A task that is completed once a response from the request is received. - pplx::task request( - const method &mtd, - const utility::string_t &path_query_fragment, - const concurrency::streams::istream &body, - const pplx::cancellation_token &token) + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. An asynchronous stream representing the body data. Cancellation token for cancellation of this request operation. A task that is + /// completed once a response from the request is received. + pplx::task request(const method& mtd, + const utility::string_t& path_query_fragment, + const concurrency::streams::istream& body, + const pplx::cancellation_token& token) { return request(mtd, path_query_fragment, body, _XPLATSTR("application/octet-stream"), token); } @@ -716,20 +673,18 @@ class http_client /// Asynchronously sends an HTTP request. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// An asynchronous stream representing the body data. - /// Size of the message body. - /// A string holding the MIME type of the message body. - /// Cancellation token for cancellation of this request operation. - /// A task that is completed once a response from the request is received. + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. An asynchronous stream representing the body data. Size of the message body. A string holding the MIME + /// type of the message body. Cancellation token for cancellation of this request + /// operation. A task that is completed once a response from the request is received. /// Winrt requires to provide content_length. - pplx::task request( - const method &mtd, - const utility::string_t &path_query_fragment, - const concurrency::streams::istream &body, - size_t content_length, - const utility::string_t &content_type = _XPLATSTR("application/octet-stream"), - const pplx::cancellation_token &token = pplx::cancellation_token::none()) + pplx::task request(const method& mtd, + const utility::string_t& path_query_fragment, + const concurrency::streams::istream& body, + size_t content_length, + const utility::string_t& content_type = _XPLATSTR("application/octet-stream"), + const pplx::cancellation_token& token = pplx::cancellation_token::none()) { http_request msg(mtd); msg.set_request_uri(path_query_fragment); @@ -741,34 +696,34 @@ class http_client /// Asynchronously sends an HTTP request. /// /// HTTP request method. - /// String containing the path, query, and fragment, relative to the http_client's base URI. - /// An asynchronous stream representing the body data. - /// Size of the message body. - /// Cancellation token for cancellation of this request operation. - /// A task that is completed once a response from the request is received. - /// Winrt requires to provide content_length. - pplx::task request( - const method &mtd, - const utility::string_t &path_query_fragment, - const concurrency::streams::istream &body, - size_t content_length, - const pplx::cancellation_token &token) + /// String containing the path, query, and fragment, relative to the http_client's + /// base URI. An asynchronous stream representing the body data. Size of the message body. Cancellation token for cancellation + /// of this request operation. A task that is completed once a response from the request is + /// received. Winrt requires to provide content_length. + pplx::task request(const method& mtd, + const utility::string_t& path_query_fragment, + const concurrency::streams::istream& body, + size_t content_length, + const pplx::cancellation_token& token) { return request(mtd, path_query_fragment, body, content_length, _XPLATSTR("application/octet-stream"), token); } private: - - std::shared_ptr< ::web::http::client::http_pipeline> m_pipeline; + std::shared_ptr<::web::http::client::http_pipeline> m_pipeline; }; -namespace details { +namespace details +{ #if defined(_WIN32) -extern const utility::char_t * get_with_body_err_msg; +extern const utility::char_t* get_with_body_err_msg; #endif -} +} // namespace details -}}} +} // namespace client +} // namespace http +} // namespace web #endif diff --git a/Release/include/cpprest/http_compression.h b/Release/include/cpprest/http_compression.h index a4ad996285..b0059a6419 100644 --- a/Release/include/cpprest/http_compression.h +++ b/Release/include/cpprest/http_compression.h @@ -2,13 +2,13 @@ * Copyright (C) Microsoft. All rights reserved. * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * - * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * HTTP Library: Compression and decompression interfaces * * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk * - * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #pragma once @@ -118,13 +118,13 @@ _ASYNCRTIMP bool supported(); namespace algorithm { #if defined(_MSC_VER) && _MSC_VER < 1900 -const utility::char_t * const GZIP = _XPLATSTR("gzip"); -const utility::char_t * const DEFLATE = _XPLATSTR("deflate"); -const utility::char_t * const BROTLI = _XPLATSTR("br"); +const utility::char_t* const GZIP = _XPLATSTR("gzip"); +const utility::char_t* const DEFLATE = _XPLATSTR("deflate"); +const utility::char_t* const BROTLI = _XPLATSTR("br"); #else // ^^^ VS2013 and before ^^^ // vvv VS2015+, and everything else vvv -constexpr const utility::char_t * const GZIP = _XPLATSTR("gzip"); -constexpr const utility::char_t * const DEFLATE = _XPLATSTR("deflate"); -constexpr const utility::char_t * const BROTLI = _XPLATSTR("br"); +constexpr const utility::char_t* const GZIP = _XPLATSTR("gzip"); +constexpr const utility::char_t* const DEFLATE = _XPLATSTR("deflate"); +constexpr const utility::char_t* const BROTLI = _XPLATSTR("br"); #endif /// @@ -135,7 +135,7 @@ constexpr const utility::char_t * const BROTLI = _XPLATSTR("br"); /// the supplied string matches a supported built-in algorithm, and false if not. /// _ASYNCRTIMP bool supported(const utility::string_t& algorithm); -} +} // namespace algorithm /// /// Factory function to instantiate a built-in compression provider with default parameters by compression algorithm diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index 34f0122b3f..4b4f9eaceb 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -1,23 +1,26 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once +#include "cpprest/asyncrt_utils.h" #include #include #include -#include #include -#include "cpprest/asyncrt_utils.h" +#include -namespace web { namespace http { +namespace web +{ +namespace http +{ /// /// Binds an individual reference to a string value. /// @@ -28,7 +31,7 @@ namespace web { namespace http { /// true if the binding succeeds, false otherwise. template CASABLANCA_DEPRECATED("This API is deprecated and will be removed in a future release, std::istringstream instead.") -bool bind(const key_type &text, _t &ref) // const +bool bind(const key_type& text, _t& ref) // const { utility::istringstream_t iss(text); iss >> ref; @@ -48,9 +51,9 @@ bool bind(const key_type &text, _t &ref) // const /// The string value. /// The value to bind to. /// true if the binding succeeds, false otherwise. -template +template CASABLANCA_DEPRECATED("This API is deprecated and will be removed in a future release.") -bool bind(const key_type &text, utility::string_t &ref) //const +bool bind(const key_type& text, utility::string_t& ref) // const { ref = text; return true; @@ -58,35 +61,35 @@ bool bind(const key_type &text, utility::string_t &ref) //const namespace details { - template - bool bind_impl(const key_type &text, _t &ref) +template +bool bind_impl(const key_type& text, _t& ref) +{ + utility::istringstream_t iss(text); + iss.imbue(std::locale::classic()); + iss >> ref; + if (iss.fail() || !iss.eof()) { - utility::istringstream_t iss(text); - iss.imbue(std::locale::classic()); - iss >> ref; - if (iss.fail() || !iss.eof()) - { - return false; - } - - return true; + return false; } - template - bool bind_impl(const key_type &text, utf16string &ref) - { - ref = utility::conversions::to_utf16string(text); - return true; - } + return true; +} - template - bool bind_impl(const key_type &text, std::string &ref) - { - ref = utility::conversions::to_utf8string(text); - return true; - } +template +bool bind_impl(const key_type& text, utf16string& ref) +{ + ref = utility::conversions::to_utf16string(text); + return true; } +template +bool bind_impl(const key_type& text, std::string& ref) +{ + ref = utility::conversions::to_utf8string(text); + return true; +} +} // namespace details + /// /// Represents HTTP headers, acts like a map. /// @@ -96,7 +99,7 @@ class http_headers /// Function object to perform case insensitive comparison of wstrings. struct _case_insensitive_cmp { - bool operator()(const utility::string_t &str1, const utility::string_t &str2) const + bool operator()(const utility::string_t& str1, const utility::string_t& str2) const { return utility::details::str_iless(str1, str2); } @@ -104,8 +107,8 @@ class http_headers private: typedef std::map inner_container; -public: +public: /// /// STL-style typedefs /// @@ -132,15 +135,15 @@ class http_headers /// Copy constructor. /// /// An http_headers object to copy from. - http_headers(const http_headers &other) : m_headers(other.m_headers) {} + http_headers(const http_headers& other) : m_headers(other.m_headers) {} /// /// Assignment operator. /// /// An http_headers object to copy from. - http_headers &operator=(const http_headers &other) + http_headers& operator=(const http_headers& other) { - if(this != &other) + if (this != &other) { m_headers = other.m_headers; } @@ -151,15 +154,15 @@ class http_headers /// Move constructor. /// /// An http_headers object to move. - http_headers(http_headers &&other) : m_headers(std::move(other.m_headers)) {} + http_headers(http_headers&& other) : m_headers(std::move(other.m_headers)) {} /// /// Move assignment operator. /// /// An http_headers object to move. - http_headers &operator=(http_headers &&other) + http_headers& operator=(http_headers&& other) { - if(this != &other) + if (this != &other) { m_headers = std::move(other.m_headers); } @@ -191,10 +194,7 @@ class http_headers /// Removes a header field. /// /// The name of the header field. - void remove(const key_type& name) - { - m_headers.erase(name); - } + void remove(const key_type& name) { m_headers.erase(name); } /// /// Removes all elements from the headers. @@ -223,7 +223,7 @@ class http_headers /// /// Returns a reference to header field with given name, if there is no header field one is inserted. /// - utility::string_t & operator[](const key_type &name) { return m_headers[name]; } + utility::string_t& operator[](const key_type& name) { return m_headers[name]; } /// /// Checks if a header field exists with given name and returns an iterator if found. Otherwise @@ -231,8 +231,8 @@ class http_headers /// /// The name of the header field. /// An iterator to where the HTTP header is found. - iterator find(const key_type &name) { return m_headers.find(name); } - const_iterator find(const key_type &name) const { return m_headers.find(name); } + iterator find(const key_type& name) { return m_headers.find(name); } + const_iterator find(const key_type& name) const { return m_headers.find(name); } /// /// Attempts to match a header field with the given name using the '>>' operator. @@ -241,7 +241,7 @@ class http_headers /// The value of the header field. /// true if header field was found and successfully stored in value parameter. template - bool match(const key_type &name, _t1 &value) const + bool match(const key_type& name, _t1& value) const { auto iter = m_headers.find(name); if (iter == m_headers.end()) @@ -318,4 +318,5 @@ class http_headers // Headers are stored in a map with case insensitive key. inner_container m_headers; }; -}} +} // namespace http +} // namespace web diff --git a/Release/include/cpprest/http_listener.h b/Release/include/cpprest/http_listener.h index ccb0ae9659..a5457c0135 100644 --- a/Release/include/cpprest/http_listener.h +++ b/Release/include/cpprest/http_listener.h @@ -1,27 +1,27 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: HTTP listener (server-side) APIs -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: HTTP listener (server-side) APIs + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_HTTP_LISTENER_H #define CASA_HTTP_LISTENER_H -#include -#include - #include "cpprest/http_msg.h" +#include +#include #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) #include #endif -#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) +#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || \ + defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) namespace web { @@ -33,53 +33,50 @@ namespace experimental /// HTTP server side library. namespace listener { - /// /// Configuration class used to set various options when constructing and http_listener instance. /// class http_listener_config { public: - /// /// Create an http_listener configuration with default options. /// - http_listener_config() - : m_timeout(utility::seconds(120)) - , m_backlog(0) - {} + http_listener_config() : m_timeout(utility::seconds(120)), m_backlog(0) {} /// /// Copy constructor. /// /// http_listener_config to copy. - http_listener_config(const http_listener_config &other) + http_listener_config(const http_listener_config& other) : m_timeout(other.m_timeout) , m_backlog(other.m_backlog) #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) , m_ssl_context_callback(other.m_ssl_context_callback) #endif - {} + { + } /// /// Move constructor. /// /// http_listener_config to move from. - http_listener_config(http_listener_config &&other) + http_listener_config(http_listener_config&& other) : m_timeout(std::move(other.m_timeout)) , m_backlog(std::move(other.m_backlog)) #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) , m_ssl_context_callback(std::move(other.m_ssl_context_callback)) #endif - {} + { + } /// /// Assignment operator. /// /// http_listener_config instance. - http_listener_config & operator=(const http_listener_config &rhs) + http_listener_config& operator=(const http_listener_config& rhs) { - if(this != &rhs) + if (this != &rhs) { m_timeout = rhs.m_timeout; m_backlog = rhs.m_backlog; @@ -94,9 +91,9 @@ class http_listener_config /// Assignment operator. /// /// http_listener_config instance. - http_listener_config & operator=(http_listener_config &&rhs) + http_listener_config& operator=(http_listener_config&& rhs) { - if(this != &rhs) + if (this != &rhs) { m_timeout = std::move(rhs.m_timeout); m_backlog = std::move(rhs.m_backlog); @@ -111,39 +108,27 @@ class http_listener_config /// Get the timeout /// /// The timeout (in seconds). - utility::seconds timeout() const - { - return m_timeout; - } + utility::seconds timeout() const { return m_timeout; } /// /// Set the timeout /// /// The timeout (in seconds) used for each send and receive operation on the client. - void set_timeout(utility::seconds timeout) - { - m_timeout = std::move(timeout); - } + void set_timeout(utility::seconds timeout) { m_timeout = std::move(timeout); } /// /// Get the listen backlog /// - /// The maximum length of the queue of pending connections, or zero for the implementation default. - /// The implementation may not honour this value. - int backlog() const - { - return m_backlog; - } + /// The maximum length of the queue of pending connections, or zero for the implementation + /// default. The implementation may not honour this value. + int backlog() const { return m_backlog; } /// /// Set the listen backlog /// - /// The maximum length of the queue of pending connections, or zero for the implementation default. - /// The implementation may not honour this value. - void set_backlog(int backlog) - { - m_backlog = backlog; - } + /// The maximum length of the queue of pending connections, or zero for the implementation + /// default. The implementation may not honour this value. + void set_backlog(int backlog) { m_backlog = backlog; } #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) /// @@ -158,15 +143,15 @@ class http_listener_config /// /// Set the callback of ssl context /// - /// The function to configure a ssl context which will setup https connections. - void set_ssl_context_callback(const std::function &ssl_context_callback) + /// The function to configure a ssl context which will setup https + /// connections. + void set_ssl_context_callback(const std::function& ssl_context_callback) { m_ssl_context_callback = ssl_context_callback; } #endif private: - utility::seconds m_timeout; int m_backlog; #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) @@ -176,19 +161,13 @@ class http_listener_config namespace details { - /// /// Internal class for pointer to implementation design pattern. /// class http_listener_impl { public: - - http_listener_impl() - : m_closed(true) - , m_close_task(pplx::task_from_result()) - { - } + http_listener_impl() : m_closed(true), m_close_task(pplx::task_from_result()) {} _ASYNCRTIMP http_listener_impl(http::uri address); _ASYNCRTIMP http_listener_impl(http::uri address, http_listener_config config); @@ -202,16 +181,15 @@ class http_listener_impl /// Only HTTP server implementations should call this API. _ASYNCRTIMP void handle_request(http::http_request msg); - const http::uri & uri() const { return m_uri; } + const http::uri& uri() const { return m_uri; } - const http_listener_config & configuration() const { return m_config; } + const http_listener_config& configuration() const { return m_config; } // Handlers std::function m_all_requests; std::map> m_supported_methods; private: - // Default implementation for TRACE and OPTIONS. void handle_trace(http::http_request message); void handle_options(http::http_request message); @@ -235,7 +213,6 @@ class http_listener_impl class http_listener { public: - /// /// Create a listener from a URI. /// @@ -261,22 +238,24 @@ class http_listener /// /// The resulting listener cannot be used for anything, but is useful to initialize a variable /// that will later be overwritten with a real listener instance. - http_listener() - : m_impl(utility::details::make_unique()) - { - } + http_listener() : m_impl(utility::details::make_unique()) {} /// /// Destructor frees any held resources. /// /// Call close() before allowing a listener to be destroyed. - ~http_listener() { - if (m_impl) { + ~http_listener() + { + if (m_impl) + { // As a safe guard close the listener if not already done. // Users are required to call close, but this is just a safeguard. - try { + try + { m_impl->close().wait(); - } catch (...) { + } + catch (...) + { } } } @@ -285,42 +264,32 @@ class http_listener /// Asynchronously open the listener, i.e. start accepting requests. /// /// A task that will be completed once this listener is actually opened, accepting requests. - pplx::task open() - { - return m_impl->open(); - } + pplx::task open() { return m_impl->open(); } /// /// Asynchronously stop accepting requests and close all connections. /// - /// A task that will be completed once this listener is actually closed, no longer accepting requests. - /// - /// This function will stop accepting requests and wait for all outstanding handler calls - /// to finish before completing the task. Waiting on the task returned from close() within - /// a handler and blocking waiting for its result will result in a deadlock. + /// A task that will be completed once this listener is actually closed, no longer accepting + /// requests. This function will stop accepting requests and wait for all outstanding handler + /// calls to finish before completing the task. Waiting on the task returned from close() within a handler and + /// blocking waiting for its result will result in a deadlock. /// /// Call close() before allowing a listener to be destroyed. /// - pplx::task close() - { - return m_impl->close(); - } + pplx::task close() { return m_impl->close(); } /// /// Add a general handler to support all requests. /// /// Function object to be called for all requests. - void support(const std::function &handler) - { - m_impl->m_all_requests = handler; - } + void support(const std::function& handler) { m_impl->m_all_requests = handler; } /// /// Add support for a specific HTTP method. /// /// An HTTP method. /// Function object to be called for all requests for the given HTTP method. - void support(const http::method &method, const std::function &handler) + void support(const http::method& method, const std::function& handler) { m_impl->m_supported_methods[method] = handler; } @@ -329,30 +298,27 @@ class http_listener /// Get the URI of the listener. /// /// The URI this listener is for. - const http::uri & uri() const { return m_impl->uri(); } + const http::uri& uri() const { return m_impl->uri(); } /// /// Get the configuration of this listener. /// /// Configuration this listener was constructed with. - const http_listener_config & configuration() const { return m_impl->configuration(); } + const http_listener_config& configuration() const { return m_impl->configuration(); } /// /// Move constructor. /// /// http_listener instance to construct this one from. - http_listener(http_listener &&other) - : m_impl(std::move(other.m_impl)) - { - } + http_listener(http_listener&& other) : m_impl(std::move(other.m_impl)) {} /// /// Move assignment operator. /// /// http_listener to replace this one with. - http_listener &operator=(http_listener &&other) + http_listener& operator=(http_listener&& other) { - if(this != &other) + if (this != &other) { m_impl = std::move(other.m_impl); } @@ -360,15 +326,17 @@ class http_listener } private: - // No copying of listeners. - http_listener(const http_listener &other); - http_listener &operator=(const http_listener &other); + http_listener(const http_listener& other); + http_listener& operator=(const http_listener& other); std::unique_ptr m_impl; }; -}}}} +} // namespace listener +} // namespace experimental +} // namespace http +} // namespace web #endif #endif diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index ae7c498e4d..41b495c712 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -1,38 +1,36 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Request and reply message definitions. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Request and reply message definitions. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once +#include "cpprest/asyncrt_utils.h" +#include "cpprest/containerstream.h" +#include "cpprest/details/cpprest_compat.h" +#include "cpprest/http_compression.h" +#include "cpprest/http_headers.h" +#include "cpprest/json.h" +#include "cpprest/streams.h" +#include "cpprest/uri.h" +#include "pplx/pplxtasks.h" #include #include #include -#include #include - -#include "pplx/pplxtasks.h" -#include "cpprest/json.h" -#include "cpprest/uri.h" -#include "cpprest/http_headers.h" -#include "cpprest/details/cpprest_compat.h" -#include "cpprest/asyncrt_utils.h" -#include "cpprest/streams.h" -#include "cpprest/containerstream.h" -#include "cpprest/http_compression.h" +#include namespace web { namespace http { - // URI class has been moved from web::http namespace to web namespace. // The below using declarations ensure we don't break existing code. // Please use the web::uri class going forward. @@ -41,7 +39,7 @@ using web::uri_builder; namespace client { - class http_client; +class http_client; } /// @@ -53,7 +51,10 @@ struct http_version uint8_t minor; inline bool operator==(const http_version& other) const { return major == other.major && minor == other.minor; } - inline bool operator<(const http_version& other) const { return major < other.major || (major == other.major && minor < other.minor); } + inline bool operator<(const http_version& other) const + { + return major < other.major || (major == other.major && minor < other.minor); + } inline bool operator!=(const http_version& other) const { return !(*this == other); } inline bool operator>=(const http_version& other) const { return !(*this < other); } @@ -96,7 +97,7 @@ class methods { public: #define _METHODS -#define DAT(a,b) _ASYNCRTIMP const static method a; +#define DAT(a, b) _ASYNCRTIMP const static method a; #include "cpprest/details/http_constants.dat" #undef _METHODS #undef DAT @@ -111,14 +112,14 @@ class status_codes { public: #define _PHRASES -#define DAT(a,b,c) const static status_code a=b; +#define DAT(a, b, c) const static status_code a = b; #include "cpprest/details/http_constants.dat" #undef _PHRASES #undef DAT }; -namespace details { - +namespace details +{ /// /// Constants for MIME types. /// @@ -126,7 +127,7 @@ class mime_types { public: #define _MIME_TYPES -#define DAT(a,b) _ASYNCRTIMP const static utility::string_t a; +#define DAT(a, b) _ASYNCRTIMP const static utility::string_t a; #include "cpprest/details/http_constants.dat" #undef _MIME_TYPES #undef DAT @@ -139,26 +140,27 @@ class charset_types { public: #define _CHARSET_TYPES -#define DAT(a,b) _ASYNCRTIMP const static utility::string_t a; +#define DAT(a, b) _ASYNCRTIMP const static utility::string_t a; #include "cpprest/details/http_constants.dat" #undef _CHARSET_TYPES #undef DAT }; -} +} // namespace details /// Message direction namespace message_direction { - /// - /// Enumeration used to denote the direction of a message: a request with a body is - /// an upload, a response with a body is a download. - /// - enum direction { - upload, - download - }; -} +/// +/// Enumeration used to denote the direction of a message: a request with a body is +/// an upload, a response with a body is a download. +/// +enum direction +{ + upload, + download +}; +} // namespace message_direction typedef utility::string_t reason_phrase; typedef std::function progress_handler; @@ -176,7 +178,7 @@ class header_names { public: #define _HEADER_NAMES -#define DAT(a,b) _ASYNCRTIMP const static utility::string_t a; +#define DAT(a, b) _ASYNCRTIMP const static utility::string_t a; #include "cpprest/details/http_constants.dat" #undef _HEADER_NAMES #undef DAT @@ -188,13 +190,11 @@ class header_names class http_exception : public std::exception { public: - /// /// Creates an http_exception with just a string message and no error code. /// /// Error message string. - http_exception(const utility::string_t &whatArg) - : m_msg(utility::conversions::to_utf8string(whatArg)) {} + http_exception(const utility::string_t& whatArg) : m_msg(utility::conversions::to_utf8string(whatArg)) {} #ifdef _WIN32 /// @@ -209,8 +209,7 @@ class http_exception : public std::exception /// The message of the error code will be used as the what() string message. /// /// Error code value. - http_exception(int errorCode) - : m_errorCode(utility::details::create_error_code(errorCode)) + http_exception(int errorCode) : m_errorCode(utility::details::create_error_code(errorCode)) { m_msg = m_errorCode.message(); } @@ -220,10 +219,11 @@ class http_exception : public std::exception /// /// Error code value. /// Message to use in what() string. - http_exception(int errorCode, const utility::string_t &whatArg) - : m_errorCode(utility::details::create_error_code(errorCode)), - m_msg(utility::conversions::to_utf8string(whatArg)) - {} + http_exception(int errorCode, const utility::string_t& whatArg) + : m_errorCode(utility::details::create_error_code(errorCode)) + , m_msg(utility::conversions::to_utf8string(whatArg)) + { + } #ifdef _WIN32 /// @@ -231,10 +231,10 @@ class http_exception : public std::exception /// /// Error code value. /// Message to use in what() string. - http_exception(int errorCode, std::string whatArg) : - m_errorCode(utility::details::create_error_code(errorCode)), - m_msg(std::move(whatArg)) - {} + http_exception(int errorCode, std::string whatArg) + : m_errorCode(utility::details::create_error_code(errorCode)), m_msg(std::move(whatArg)) + { + } #endif /// @@ -243,7 +243,7 @@ class http_exception : public std::exception /// /// Error code value. /// Error category for the code. - http_exception(int errorCode, const std::error_category &cat) : m_errorCode(std::error_code(errorCode, cat)) + http_exception(int errorCode, const std::error_category& cat) : m_errorCode(std::error_code(errorCode, cat)) { m_msg = m_errorCode.message(); } @@ -252,19 +252,13 @@ class http_exception : public std::exception /// Gets a string identifying the cause of the exception. /// /// A null terminated character string. - const char* what() const CPPREST_NOEXCEPT - { - return m_msg.c_str(); - } + const char* what() const CPPREST_NOEXCEPT { return m_msg.c_str(); } /// /// Retrieves the underlying error code causing this exception. /// /// A std::error_code. - const std::error_code & error_code() const - { - return m_errorCode; - } + const std::error_code& error_code() const { return m_errorCode; } private: std::error_code m_errorCode; @@ -273,7 +267,6 @@ class http_exception : public std::exception namespace details { - /// /// Base class for HTTP messages. /// This class is to store common functionality so it isn't duplicated on @@ -282,19 +275,22 @@ namespace details class http_msg_base { public: - friend class http::client::http_client; _ASYNCRTIMP http_msg_base(); virtual ~http_msg_base() {} - http_headers &headers() { return m_headers; } + http_headers& headers() { return m_headers; } - _ASYNCRTIMP void set_body(const concurrency::streams::istream &instream, const utf8string &contentType); - _ASYNCRTIMP void set_body(const concurrency::streams::istream &instream, const utf16string &contentType); - _ASYNCRTIMP void set_body(const concurrency::streams::istream &instream, utility::size64_t contentLength, const utf8string &contentType); - _ASYNCRTIMP void set_body(const concurrency::streams::istream &instream, utility::size64_t contentLength, const utf16string &contentType); + _ASYNCRTIMP void set_body(const concurrency::streams::istream& instream, const utf8string& contentType); + _ASYNCRTIMP void set_body(const concurrency::streams::istream& instream, const utf16string& contentType); + _ASYNCRTIMP void set_body(const concurrency::streams::istream& instream, + utility::size64_t contentLength, + const utf8string& contentType); + _ASYNCRTIMP void set_body(const concurrency::streams::istream& instream, + utility::size64_t contentLength, + const utf16string& contentType); /// /// Helper function for extract functions. Parses the Content-Type header and check to make sure it matches, @@ -303,7 +299,8 @@ class http_msg_base /// If true ignores the Content-Type header value. /// Function to verify additional information on Content-Type. /// A string containing the charset, an empty string if no Content-Type header is empty. - utility::string_t parse_and_check_content_type(bool ignore_content_type, const std::function &check_content_type); + utility::string_t parse_and_check_content_type( + bool ignore_content_type, const std::function& check_content_type); _ASYNCRTIMP utf8string extract_utf8string(bool ignore_content_type = false); _ASYNCRTIMP utf16string extract_utf16string(bool ignore_content_type = false); @@ -317,27 +314,32 @@ class http_msg_base /// /// Completes this message /// - virtual _ASYNCRTIMP void _complete(utility::size64_t bodySize, const std::exception_ptr &exceptionPtr = std::exception_ptr()); + virtual _ASYNCRTIMP void _complete(utility::size64_t bodySize, + const std::exception_ptr& exceptionPtr = std::exception_ptr()); /// /// Set the stream through which the message body could be read /// - void set_instream(const concurrency::streams::istream &instream) { m_inStream = instream; } + void set_instream(const concurrency::streams::istream& instream) { m_inStream = instream; } /// /// Get the stream through which the message body could be read /// - const concurrency::streams::istream & instream() const { return m_inStream; } + const concurrency::streams::istream& instream() const { return m_inStream; } /// /// Set the stream through which the message body could be written /// - void set_outstream(const concurrency::streams::ostream &outstream, bool is_default) { m_outStream = outstream; m_default_outstream = is_default; } + void set_outstream(const concurrency::streams::ostream& outstream, bool is_default) + { + m_outStream = outstream; + m_default_outstream = is_default; + } /// /// Get the stream through which the message body could be written /// - const concurrency::streams::ostream & outstream() const { return m_outStream; } + const concurrency::streams::ostream& outstream() const { return m_outStream; } /// /// Sets the compressor for the message body @@ -350,15 +352,12 @@ class http_msg_base /// /// Gets the compressor for the message body, if any /// - std::unique_ptr &compressor() - { - return m_compressor; - } + std::unique_ptr& compressor() { return m_compressor; } /// /// Sets the collection of factory classes for decompressors for use with the message body /// - void set_decompress_factories(const std::vector> &factories) + void set_decompress_factories(const std::vector>& factories) { m_decompressors = factories; } @@ -366,19 +365,18 @@ class http_msg_base /// /// Gets the collection of factory classes for decompressors to be used to decompress the message body, if any /// - const std::vector> &decompress_factories() + const std::vector>& decompress_factories() { return m_decompressors; } - const pplx::task_completion_event & _get_data_available() const { return m_data_available; } + const pplx::task_completion_event& _get_data_available() const { return m_data_available; } /// /// Prepare the message with an output stream to receive network data /// _ASYNCRTIMP void _prepare_to_receive_data(); - /// /// Determine the remaining input stream length /// @@ -422,7 +420,6 @@ class http_msg_base _ASYNCRTIMP size_t _get_content_length_and_set_compression(); protected: - std::unique_ptr m_compressor; std::unique_ptr m_decompressor; std::vector> m_decompressors; @@ -465,6 +462,7 @@ class _http_server_context public: _http_server_context() {} virtual ~_http_server_context() {} + private: }; @@ -474,7 +472,7 @@ class _http_server_context class _http_response final : public http::details::http_msg_base { public: - _http_response() : m_status_code((std::numeric_limits::max)()) { } + _http_response() : m_status_code((std::numeric_limits::max)()) {} _http_response(http::status_code code) : m_status_code(code) {} @@ -482,15 +480,18 @@ class _http_response final : public http::details::http_msg_base void set_status_code(http::status_code code) { m_status_code = code; } - const http::reason_phrase & reason_phrase() const { return m_reason_phrase; } + const http::reason_phrase& reason_phrase() const { return m_reason_phrase; } - void set_reason_phrase(const http::reason_phrase &reason) { m_reason_phrase = reason; } + void set_reason_phrase(const http::reason_phrase& reason) { m_reason_phrase = reason; } _ASYNCRTIMP utility::string_t to_string() const; - _http_server_context * _get_server_context() const { return m_server_context.get(); } + _http_server_context* _get_server_context() const { return m_server_context.get(); } - void _set_server_context(std::unique_ptr server_context) { m_server_context = std::move(server_context); } + void _set_server_context(std::unique_ptr server_context) + { + m_server_context = std::move(server_context); + } private: std::unique_ptr<_http_server_context> m_server_context; @@ -501,27 +502,24 @@ class _http_response final : public http::details::http_msg_base } // namespace details - /// /// Represents an HTTP response. /// class http_response { public: - /// /// Constructs a response with an empty status code, no headers, and no body. /// /// A new HTTP response. - http_response() : _m_impl(std::make_shared()) { } + http_response() : _m_impl(std::make_shared()) {} /// /// Constructs a response with given status code, no headers, and no body. /// /// HTTP status code to use in response. /// A new HTTP response. - http_response(http::status_code code) - : _m_impl(std::make_shared(code)) { } + http_response(http::status_code code) : _m_impl(std::make_shared(code)) {} /// /// Gets the status code of the response message. @@ -543,14 +541,14 @@ class http_response /// If no reason phrase is set it will default to the standard one corresponding to the status code. /// /// Reason phrase. - const http::reason_phrase & reason_phrase() const { return _m_impl->reason_phrase(); } + const http::reason_phrase& reason_phrase() const { return _m_impl->reason_phrase(); } /// /// Sets the reason phrase of the response message. /// If no reason phrase is set it will default to the standard one corresponding to the status code. /// /// The reason phrase to set. - void set_reason_phrase(const http::reason_phrase &reason) const { _m_impl->set_reason_phrase(reason); } + void set_reason_phrase(const http::reason_phrase& reason) const { _m_impl->set_reason_phrase(reason); } /// /// Gets the headers of the response message. @@ -559,13 +557,13 @@ class http_response /// /// Use the to fill in desired headers. /// - http_headers &headers() { return _m_impl->headers(); } + http_headers& headers() { return _m_impl->headers(); } /// /// Gets a const reference to the headers of the response message. /// /// HTTP headers for this response. - const http_headers &headers() const { return _m_impl->headers(); } + const http_headers& headers() const { return _m_impl->headers(); } /// /// Generates a string representation of the message, including the body when possible. @@ -588,31 +586,39 @@ class http_response pplx::task extract_string(bool ignore_content_type = false) const { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_string(ignore_content_type); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { + return impl->extract_string(ignore_content_type); + }); } /// - /// Extracts the body of the response message as a UTF-8 string value, checking that the content type is a MIME text type. - /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out. + /// Extracts the body of the response message as a UTF-8 string value, checking that the content type is a MIME text + /// type. A body can only be extracted once because in some cases an optimization is made where the data is 'moved' + /// out. /// /// If true, ignores the Content-Type header and assumes text. /// String containing body of the message. pplx::task extract_utf8string(bool ignore_content_type = false) const { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_utf8string(ignore_content_type); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { + return impl->extract_utf8string(ignore_content_type); + }); } /// - /// Extracts the body of the response message as a UTF-16 string value, checking that the content type is a MIME text type. - /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out. + /// Extracts the body of the response message as a UTF-16 string value, checking that the content type is a MIME + /// text type. A body can only be extracted once because in some cases an optimization is made where the data is + /// 'moved' out. /// /// If true, ignores the Content-Type header and assumes text. /// String containing body of the message. pplx::task extract_utf16string(bool ignore_content_type = false) const { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_utf16string(ignore_content_type); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { + return impl->extract_utf16string(ignore_content_type); + }); } /// @@ -624,7 +630,9 @@ class http_response pplx::task extract_json(bool ignore_content_type = false) const { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->_extract_json(ignore_content_type); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { + return impl->_extract_json(ignore_content_type); + }); } /// @@ -634,7 +642,9 @@ class http_response pplx::task> extract_vector() const { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl](utility::size64_t) { return impl->_extract_vector(); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl](utility::size64_t) { + return impl->_extract_vector(); + }); } /// @@ -642,14 +652,14 @@ class http_response /// the character encoding of the string is UTF-8. /// /// String containing body text. - /// MIME type to set the "Content-Type" header to. Default to "text/plain; charset=utf-8". - /// - /// This will overwrite any previously set body data and "Content-Type" header. + /// MIME type to set the "Content-Type" header to. Default to "text/plain; + /// charset=utf-8". This will overwrite any previously set body data and "Content-Type" header. /// - void set_body(utf8string &&body_text, const utf8string &content_type = utf8string("text/plain; charset=utf-8")) + void set_body(utf8string&& body_text, const utf8string& content_type = utf8string("text/plain; charset=utf-8")) { const auto length = body_text.size(); - _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(body_text)), length, content_type); + _m_impl->set_body( + concurrency::streams::bytestream::open_istream(std::move(body_text)), length, content_type); } /// @@ -657,13 +667,13 @@ class http_response /// the character encoding of the string is UTF-8. /// /// String containing body text. - /// MIME type to set the "Content-Type" header to. Default to "text/plain; charset=utf-8". - /// - /// This will overwrite any previously set body data and "Content-Type" header. + /// MIME type to set the "Content-Type" header to. Default to "text/plain; + /// charset=utf-8". This will overwrite any previously set body data and "Content-Type" header. /// - void set_body(const utf8string &body_text, const utf8string &content_type = utf8string("text/plain; charset=utf-8")) + void set_body(const utf8string& body_text, const utf8string& content_type = utf8string("text/plain; charset=utf-8")) { - _m_impl->set_body(concurrency::streams::bytestream::open_istream(body_text), body_text.size(), content_type); + _m_impl->set_body( + concurrency::streams::bytestream::open_istream(body_text), body_text.size(), content_type); } /// @@ -675,7 +685,8 @@ class http_response /// /// This will overwrite any previously set body data and "Content-Type" header. /// - void set_body(const utf16string &body_text, utf16string content_type = utility::conversions::to_utf16string("text/plain")) + void set_body(const utf16string& body_text, + utf16string content_type = utility::conversions::to_utf16string("text/plain")) { if (content_type.find(::utility::conversions::to_utf16string("charset=")) != content_type.npos) { @@ -684,10 +695,9 @@ class http_response auto utf8body = utility::conversions::utf16_to_utf8(body_text); auto length = utf8body.size(); - _m_impl->set_body(concurrency::streams::bytestream::open_istream( - std::move(utf8body)), - length, - std::move(content_type.append(::utility::conversions::to_utf16string("; charset=utf-8")))); + _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(utf8body)), + length, + std::move(content_type.append(::utility::conversions::to_utf16string("; charset=utf-8")))); } /// @@ -698,11 +708,13 @@ class http_response /// /// This will overwrite any previously set body data. /// - void set_body(const json::value &body_data) + void set_body(const json::value& body_data) { auto body_text = utility::conversions::to_utf8string(body_data.serialize()); auto length = body_text.size(); - set_body(concurrency::streams::bytestream::open_istream(std::move(body_text)), length, _XPLATSTR("application/json")); + set_body(concurrency::streams::bytestream::open_istream(std::move(body_text)), + length, + _XPLATSTR("application/json")); } /// @@ -713,7 +725,7 @@ class http_response /// /// This will overwrite any previously set body data. /// - void set_body(std::vector &&body_data) + void set_body(std::vector&& body_data) { auto length = body_data.size(); set_body(concurrency::streams::bytestream::open_istream(std::move(body_data)), length); @@ -727,7 +739,7 @@ class http_response /// /// This will overwrite any previously set body data. /// - void set_body(const std::vector &body_data) + void set_body(const std::vector& body_data) { set_body(concurrency::streams::bytestream::open_istream(body_data), body_data.size()); } @@ -742,7 +754,8 @@ class http_response /// This cannot be used in conjunction with any external means of setting the body of the request. /// The stream will not be read until the message is sent. /// - void set_body(const concurrency::streams::istream &stream, const utility::string_t &content_type = _XPLATSTR("application/octet-stream")) + void set_body(const concurrency::streams::istream& stream, + const utility::string_t& content_type = _XPLATSTR("application/octet-stream")) { _m_impl->set_body(stream, content_type); } @@ -758,7 +771,9 @@ class http_response /// This cannot be used in conjunction with any external means of setting the body of the request. /// The stream will not be read until the message is sent. /// - void set_body(const concurrency::streams::istream &stream, utility::size64_t content_length, const utility::string_t &content_type = _XPLATSTR("application/octet-stream")) + void set_body(const concurrency::streams::istream& stream, + utility::size64_t content_length, + const utility::string_t& content_type = _XPLATSTR("application/octet-stream")) { _m_impl->set_body(stream, content_length, content_type); } @@ -773,10 +788,7 @@ class http_response /// stream, but it is advisable to do so, since it will allow the network I/O to start earlier /// and the work of sending data can be overlapped with the production of more data. /// - concurrency::streams::istream body() const - { - return _m_impl->instream(); - } + concurrency::streams::istream body() const { return _m_impl->instream(); } /// /// Signals the user (client) when all the data for this response message has been received. @@ -785,36 +797,40 @@ class http_response pplx::task content_ready() const { http_response resp = *this; - return pplx::create_task(_m_impl->_get_data_available()).then([resp](utility::size64_t) mutable { return resp; }); + return pplx::create_task(_m_impl->_get_data_available()).then([resp](utility::size64_t) mutable { + return resp; + }); } std::shared_ptr _get_impl() const { return _m_impl; } - http::details::_http_server_context * _get_server_context() const { return _m_impl->_get_server_context(); } - void _set_server_context(std::unique_ptr server_context) { _m_impl->_set_server_context(std::move(server_context)); } + http::details::_http_server_context* _get_server_context() const { return _m_impl->_get_server_context(); } + void _set_server_context(std::unique_ptr server_context) + { + _m_impl->_set_server_context(std::move(server_context)); + } private: - std::shared_ptr _m_impl; }; -namespace details { +namespace details +{ /// /// Internal representation of an HTTP request message. /// class _http_request final : public http::details::http_msg_base, public std::enable_shared_from_this<_http_request> { public: - _ASYNCRTIMP _http_request(http::method mtd); _ASYNCRTIMP _http_request(std::unique_ptr server_context); virtual ~_http_request() {} - http::method &method() { return m_method; } + http::method& method() { return m_method; } - uri &request_uri() { return m_uri; } + uri& request_uri() { return m_uri; } _ASYNCRTIMP uri absolute_uri() const; @@ -826,52 +842,45 @@ class _http_request final : public http::details::http_msg_base, public std::ena const utility::string_t& remote_address() const { return m_remote_address; } - const pplx::cancellation_token &cancellation_token() const { return m_cancellationToken; } + const pplx::cancellation_token& cancellation_token() const { return m_cancellationToken; } - void set_cancellation_token(const pplx::cancellation_token &token) - { - m_cancellationToken = token; - } + void set_cancellation_token(const pplx::cancellation_token& token) { m_cancellationToken = token; } _ASYNCRTIMP utility::string_t to_string() const; - _ASYNCRTIMP pplx::task reply(const http_response &response); + _ASYNCRTIMP pplx::task reply(const http_response& response); - pplx::task get_response() - { - return pplx::task(m_response); - } + pplx::task get_response() { return pplx::task(m_response); } _ASYNCRTIMP pplx::task _reply_if_not_already(http::status_code status); - void set_response_stream(const concurrency::streams::ostream &stream) - { - m_response_stream = stream; - } + void set_response_stream(const concurrency::streams::ostream& stream) { m_response_stream = stream; } - void set_progress_handler(const progress_handler &handler) + void set_progress_handler(const progress_handler& handler) { m_progress_handler = std::make_shared(handler); } - const concurrency::streams::ostream & _response_stream() const { return m_response_stream; } + const concurrency::streams::ostream& _response_stream() const { return m_response_stream; } - const std::shared_ptr & _progress_handler() const { return m_progress_handler; } + const std::shared_ptr& _progress_handler() const { return m_progress_handler; } - http::details::_http_server_context * _get_server_context() const { return m_server_context.get(); } + http::details::_http_server_context* _get_server_context() const { return m_server_context.get(); } - void _set_server_context(std::unique_ptr server_context) { m_server_context = std::move(server_context); } + void _set_server_context(std::unique_ptr server_context) + { + m_server_context = std::move(server_context); + } - void _set_listener_path(const utility::string_t &path) { m_listener_path = path; } + void _set_listener_path(const utility::string_t& path) { m_listener_path = path; } - void _set_base_uri(const http::uri &base_uri) { m_base_uri = base_uri; } + void _set_base_uri(const http::uri& base_uri) { m_base_uri = base_uri; } - void _set_http_version(const http::http_version &http_version) { m_http_version = http_version; } + void _set_http_version(const http::http_version& http_version) { m_http_version = http_version; } - void _set_remote_address(const utility::string_t &remote_address) { m_remote_address = remote_address; } + void _set_remote_address(const utility::string_t& remote_address) { m_remote_address = remote_address; } private: - // Actual initiates sending the response, without checking if a response has already been sent. pplx::task _reply_impl(http_response response); @@ -902,8 +911,7 @@ class _http_request final : public http::details::http_msg_base, public std::ena utility::string_t m_remote_address; }; - -} // namespace details +} // namespace details /// /// Represents an HTTP request. @@ -914,15 +922,13 @@ class http_request /// /// Constructs a new HTTP request with the 'GET' method. /// - http_request() - : _m_impl(std::make_shared(methods::GET)) {} + http_request() : _m_impl(std::make_shared(methods::GET)) {} /// /// Constructs a new HTTP request with the given request method. /// /// Request method. - http_request(http::method mtd) - : _m_impl(std::make_shared(std::move(mtd))) {} + http_request(http::method mtd) : _m_impl(std::make_shared(std::move(mtd))) {} /// /// Destructor frees any held resources. @@ -933,19 +939,19 @@ class http_request /// Get the method (GET/PUT/POST/DELETE) of the request message. /// /// Request method of this HTTP request. - const http::method &method() const { return _m_impl->method(); } + const http::method& method() const { return _m_impl->method(); } /// /// Set the method (GET/PUT/POST/DELETE) of the request message. /// /// Request method of this HTTP request. - void set_method(const http::method &method) const { _m_impl->method() = method; } + void set_method(const http::method& method) const { _m_impl->method() = method; } /// /// Get the underling URI of the request message. /// /// The uri of this message. - const uri & request_uri() const { return _m_impl->request_uri(); } + const uri& request_uri() const { return _m_impl->request_uri(); } /// /// Set the underling URI of the request message. @@ -980,7 +986,7 @@ class http_request /// /// Use the http_headers::add to fill in desired headers. /// - http_headers &headers() { return _m_impl->headers(); } + http_headers& headers() { return _m_impl->headers(); } /// /// Gets a const reference to the headers of the response message. @@ -989,7 +995,7 @@ class http_request /// /// Use the http_headers::add to fill in desired headers. /// - const http_headers &headers() const { return _m_impl->headers(); } + const http_headers& headers() const { return _m_impl->headers(); } /// /// Returns the HTTP protocol version of this request message. @@ -1015,31 +1021,39 @@ class http_request pplx::task extract_string(bool ignore_content_type = false) { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_string(ignore_content_type); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { + return impl->extract_string(ignore_content_type); + }); } /// - /// Extract the body of the request message as a UTF-8 string value, checking that the content type is a MIME text type. - /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out. + /// Extract the body of the request message as a UTF-8 string value, checking that the content type is a MIME text + /// type. A body can only be extracted once because in some cases an optimization is made where the data is 'moved' + /// out. /// /// If true, ignores the Content-Type header and assumes UTF-8. /// String containing body of the message. pplx::task extract_utf8string(bool ignore_content_type = false) { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_utf8string(ignore_content_type); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { + return impl->extract_utf8string(ignore_content_type); + }); } /// - /// Extract the body of the request message as a UTF-16 string value, checking that the content type is a MIME text type. - /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out. + /// Extract the body of the request message as a UTF-16 string value, checking that the content type is a MIME text + /// type. A body can only be extracted once because in some cases an optimization is made where the data is 'moved' + /// out. /// /// If true, ignores the Content-Type header and assumes UTF-16. /// String containing body of the message. pplx::task extract_utf16string(bool ignore_content_type = false) { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_utf16string(ignore_content_type); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { + return impl->extract_utf16string(ignore_content_type); + }); } /// @@ -1051,7 +1065,9 @@ class http_request pplx::task extract_json(bool ignore_content_type = false) const { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->_extract_json(ignore_content_type); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { + return impl->_extract_json(ignore_content_type); + }); } /// @@ -1061,7 +1077,9 @@ class http_request pplx::task> extract_vector() const { auto impl = _m_impl; - return pplx::create_task(_m_impl->_get_data_available()).then([impl](utility::size64_t) { return impl->_extract_vector(); }); + return pplx::create_task(_m_impl->_get_data_available()).then([impl](utility::size64_t) { + return impl->_extract_vector(); + }); } /// @@ -1069,14 +1087,14 @@ class http_request /// the character encoding of the string is UTF-8. /// /// String containing body text. - /// MIME type to set the "Content-Type" header to. Default to "text/plain; charset=utf-8". - /// - /// This will overwrite any previously set body data and "Content-Type" header. + /// MIME type to set the "Content-Type" header to. Default to "text/plain; + /// charset=utf-8". This will overwrite any previously set body data and "Content-Type" header. /// - void set_body(utf8string &&body_text, const utf8string &content_type = utf8string("text/plain; charset=utf-8")) + void set_body(utf8string&& body_text, const utf8string& content_type = utf8string("text/plain; charset=utf-8")) { const auto length = body_text.size(); - _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(body_text)), length, content_type); + _m_impl->set_body( + concurrency::streams::bytestream::open_istream(std::move(body_text)), length, content_type); } /// @@ -1084,13 +1102,13 @@ class http_request /// the character encoding of the string is UTF-8. /// /// String containing body text. - /// MIME type to set the "Content-Type" header to. Default to "text/plain; charset=utf-8". - /// - /// This will overwrite any previously set body data and "Content-Type" header. + /// MIME type to set the "Content-Type" header to. Default to "text/plain; + /// charset=utf-8". This will overwrite any previously set body data and "Content-Type" header. /// - void set_body(const utf8string &body_text, const utf8string &content_type = utf8string("text/plain; charset=utf-8")) + void set_body(const utf8string& body_text, const utf8string& content_type = utf8string("text/plain; charset=utf-8")) { - _m_impl->set_body(concurrency::streams::bytestream::open_istream(body_text), body_text.size(), content_type); + _m_impl->set_body( + concurrency::streams::bytestream::open_istream(body_text), body_text.size(), content_type); } /// @@ -1103,19 +1121,19 @@ class http_request /// /// This will overwrite any previously set body data and "Content-Type" header. /// - void set_body(const utf16string &body_text, utf16string content_type = utility::conversions::to_utf16string("text/plain")) + void set_body(const utf16string& body_text, + utf16string content_type = utility::conversions::to_utf16string("text/plain")) { - if(content_type.find(::utility::conversions::to_utf16string("charset=")) != content_type.npos) + if (content_type.find(::utility::conversions::to_utf16string("charset=")) != content_type.npos) { throw std::invalid_argument("content_type can't contain a 'charset'."); } auto utf8body = utility::conversions::utf16_to_utf8(body_text); auto length = utf8body.size(); - _m_impl->set_body(concurrency::streams::bytestream::open_istream( - std::move(utf8body)), - length, - std::move(content_type.append(::utility::conversions::to_utf16string("; charset=utf-8")))); + _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(utf8body)), + length, + std::move(content_type.append(::utility::conversions::to_utf16string("; charset=utf-8")))); } /// @@ -1126,11 +1144,13 @@ class http_request /// /// This will overwrite any previously set body data. /// - void set_body(const json::value &body_data) + void set_body(const json::value& body_data) { auto body_text = utility::conversions::to_utf8string(body_data.serialize()); auto length = body_text.size(); - _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(body_text)), length, _XPLATSTR("application/json")); + _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(body_text)), + length, + _XPLATSTR("application/json")); } /// @@ -1141,10 +1161,12 @@ class http_request /// /// This will overwrite any previously set body data. /// - void set_body(std::vector &&body_data) + void set_body(std::vector&& body_data) { auto length = body_data.size(); - _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(body_data)), length, _XPLATSTR("application/octet-stream")); + _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(body_data)), + length, + _XPLATSTR("application/octet-stream")); } /// @@ -1155,7 +1177,7 @@ class http_request /// /// This will overwrite any previously set body data. /// - void set_body(const std::vector &body_data) + void set_body(const std::vector& body_data) { set_body(concurrency::streams::bytestream::open_istream(body_data), body_data.size()); } @@ -1170,7 +1192,8 @@ class http_request /// This cannot be used in conjunction with any other means of setting the body of the request. /// The stream will not be read until the message is sent. /// - void set_body(const concurrency::streams::istream &stream, const utility::string_t &content_type = _XPLATSTR("application/octet-stream")) + void set_body(const concurrency::streams::istream& stream, + const utility::string_t& content_type = _XPLATSTR("application/octet-stream")) { _m_impl->set_body(stream, content_type); } @@ -1186,7 +1209,9 @@ class http_request /// This cannot be used in conjunction with any other means of setting the body of the request. /// The stream will not be read until the message is sent. /// - void set_body(const concurrency::streams::istream &stream, utility::size64_t content_length, const utility::string_t &content_type = _XPLATSTR("application/octet-stream")) + void set_body(const concurrency::streams::istream& stream, + utility::size64_t content_length, + const utility::string_t& content_type = _XPLATSTR("application/octet-stream")) { _m_impl->set_body(stream, content_length, content_type); } @@ -1201,10 +1226,7 @@ class http_request /// stream, but it is advisable to do so, since it will allow the network I/O to start earlier /// and the work of sending data can be overlapped with the production of more data. /// - concurrency::streams::istream body() const - { - return _m_impl->instream(); - } + concurrency::streams::istream body() const { return _m_impl->instream(); } /// /// Defines a stream that will be relied on to hold the body of the HTTP response message that @@ -1215,7 +1237,7 @@ class http_request /// If this function is called, the body of the response should not be accessed in any other /// way. /// - void set_response_stream(const concurrency::streams::ostream &stream) + void set_response_stream(const concurrency::streams::ostream& stream) { return _m_impl->set_response_stream(stream); } @@ -1256,10 +1278,7 @@ class http_request /// /// The compressor itself. /// - std::unique_ptr &compressor() - { - return _m_impl->compressor(); - } + std::unique_ptr& compressor() { return _m_impl->compressor(); } /// /// Sets the default collection of built-in factory classes for decompressors that may be used to @@ -1288,7 +1307,7 @@ class http_request /// This cannot be used in conjunction with any external means of decompression. The TE and Accept-Encoding /// headers must not be set by the client, as they will be managed internally as appropriate. /// - void set_decompress_factories(const std::vector> &factories) + void set_decompress_factories(const std::vector>& factories) { return _m_impl->set_decompress_factories(factories); } @@ -1303,7 +1322,7 @@ class http_request /// This cannot be used in conjunction with any external means of decompression. The TE /// header must not be set by the client, as it will be managed internally. /// - const std::vector> &decompress_factories() const + const std::vector>& decompress_factories() const { return _m_impl->decompress_factories(); } @@ -1336,27 +1355,21 @@ class http_request /// the handler, do not update user interfaces, and to not acquire any locks. If such activities /// are necessary, it is the handler's responsibility to execute that work on a separate thread. /// - void set_progress_handler(const progress_handler &handler) - { - return _m_impl->set_progress_handler(handler); - } + void set_progress_handler(const progress_handler& handler) { return _m_impl->set_progress_handler(handler); } /// /// Asynchronously responses to this HTTP request. /// /// Response to send. /// An asynchronous operation that is completed once response is sent. - pplx::task reply(const http_response &response) const { return _m_impl->reply(response); } + pplx::task reply(const http_response& response) const { return _m_impl->reply(response); } /// /// Asynchronously responses to this HTTP request. /// /// Response status code. /// An asynchronous operation that is completed once response is sent. - pplx::task reply(http::status_code status) const - { - return reply(http_response(status)); - } + pplx::task reply(http::status_code status) const { return reply(http_response(status)); } /// /// Responds to this HTTP request. @@ -1364,7 +1377,7 @@ class http_request /// Response status code. /// Json value to use in the response body. /// An asynchronous operation that is completed once response is sent. - pplx::task reply(http::status_code status, const json::value &body_data) const + pplx::task reply(http::status_code status, const json::value& body_data) const { http_response response(status); response.set_body(body_data); @@ -1382,7 +1395,9 @@ class http_request // Callers of this function do NOT need to block waiting for the response to be /// sent to before the body data is destroyed or goes out of scope. /// - pplx::task reply(http::status_code status, utf8string &&body_data, const utf8string &content_type = "text/plain; charset=utf-8") const + pplx::task reply(http::status_code status, + utf8string&& body_data, + const utf8string& content_type = "text/plain; charset=utf-8") const { http_response response(status); response.set_body(std::move(body_data), content_type); @@ -1401,7 +1416,9 @@ class http_request // Callers of this function do NOT need to block waiting for the response to be /// sent to before the body data is destroyed or goes out of scope. /// - pplx::task reply(http::status_code status, const utf8string &body_data, const utf8string &content_type = "text/plain; charset=utf-8") const + pplx::task reply(http::status_code status, + const utf8string& body_data, + const utf8string& content_type = "text/plain; charset=utf-8") const { http_response response(status); response.set_body(body_data, content_type); @@ -1420,7 +1437,9 @@ class http_request // Callers of this function do NOT need to block waiting for the response to be /// sent to before the body data is destroyed or goes out of scope. /// - pplx::task reply(http::status_code status, const utf16string &body_data, const utf16string &content_type = utility::conversions::to_utf16string("text/plain")) const + pplx::task reply(http::status_code status, + const utf16string& body_data, + const utf16string& content_type = utility::conversions::to_utf16string("text/plain")) const { http_response response(status); response.set_body(body_data, content_type); @@ -1434,7 +1453,9 @@ class http_request /// A string holding the MIME type of the message body. /// An asynchronous stream representing the body data. /// A task that is completed once a response from the request is received. - pplx::task reply(status_code status, const concurrency::streams::istream &body, const utility::string_t &content_type = _XPLATSTR("application/octet-stream")) const + pplx::task reply(status_code status, + const concurrency::streams::istream& body, + const utility::string_t& content_type = _XPLATSTR("application/octet-stream")) const { http_response response(status); response.set_body(body, content_type); @@ -1449,7 +1470,10 @@ class http_request /// A string holding the MIME type of the message body. /// An asynchronous stream representing the body data. /// A task that is completed once a response from the request is received. - pplx::task reply(status_code status, const concurrency::streams::istream &body, utility::size64_t content_length, const utility::string_t &content_type = _XPLATSTR("application/octet-stream")) const + pplx::task reply(status_code status, + const concurrency::streams::istream& body, + utility::size64_t content_length, + const utility::string_t& content_type = _XPLATSTR("application/octet-stream")) const { http_response response(status); response.set_body(body, content_length, content_type); @@ -1470,10 +1494,7 @@ class http_request /// Gets a task representing the response that will eventually be sent. /// /// A task that is completed once response is sent. - pplx::task get_response() const - { - return _m_impl->get_response(); - } + pplx::task get_response() const { return _m_impl->get_response(); } /// /// Generates a string representation of the message, including the body when possible. @@ -1495,43 +1516,44 @@ class http_request /// /// Gets the server context associated with this HTTP message. /// - http::details::_http_server_context * _get_server_context() const { return _m_impl->_get_server_context(); } + http::details::_http_server_context* _get_server_context() const { return _m_impl->_get_server_context(); } /// /// These are used for the initial creation of the HTTP request. /// - static http_request _create_request(std::unique_ptr server_context) { return http_request(std::move(server_context)); } - void _set_server_context(std::unique_ptr server_context) { _m_impl->_set_server_context(std::move(server_context)); } - - void _set_listener_path(const utility::string_t &path) { _m_impl->_set_listener_path(path); } - - const std::shared_ptr & _get_impl() const { return _m_impl; } - - void _set_cancellation_token(const pplx::cancellation_token &token) + static http_request _create_request(std::unique_ptr server_context) { - _m_impl->set_cancellation_token(token); + return http_request(std::move(server_context)); } - - const pplx::cancellation_token & _cancellation_token() const + void _set_server_context(std::unique_ptr server_context) { - return _m_impl->cancellation_token(); + _m_impl->_set_server_context(std::move(server_context)); } - void _set_base_uri(const http::uri &base_uri) - { - _m_impl->_set_base_uri(base_uri); - } + void _set_listener_path(const utility::string_t& path) { _m_impl->_set_listener_path(path); } + + const std::shared_ptr& _get_impl() const { return _m_impl; } + + void _set_cancellation_token(const pplx::cancellation_token& token) { _m_impl->set_cancellation_token(token); } + + const pplx::cancellation_token& _cancellation_token() const { return _m_impl->cancellation_token(); } + + void _set_base_uri(const http::uri& base_uri) { _m_impl->_set_base_uri(base_uri); } private: friend class http::details::_http_request; friend class http::client::http_client; - http_request(std::unique_ptr server_context) : _m_impl(std::make_shared(std::move(server_context))) {} + http_request(std::unique_ptr server_context) + : _m_impl(std::make_shared(std::move(server_context))) + { + } std::shared_ptr _m_impl; }; -namespace client { +namespace client +{ class http_pipeline; } @@ -1543,17 +1565,16 @@ class http_pipeline; /// the application and/or libraries. The default stage will interact with lower-level /// communication layers to actually send the message on the network. When creating a client /// instance, an application may add pipeline stages in front of the already existing -/// stages. Each stage has a reference to the next stage available in the -/// value. +/// stages. Each stage has a reference to the next stage available in the value. /// class http_pipeline_stage : public std::enable_shared_from_this { public: - http_pipeline_stage() = default; - http_pipeline_stage & operator=(const http_pipeline_stage &) = delete; - http_pipeline_stage(const http_pipeline_stage &) = delete; + http_pipeline_stage& operator=(const http_pipeline_stage&) = delete; + http_pipeline_stage(const http_pipeline_stage&) = delete; virtual ~http_pipeline_stage() = default; @@ -1565,36 +1586,26 @@ class http_pipeline_stage : public std::enable_shared_from_this propagate(http_request request) = 0; protected: - /// /// Gets the next stage in the pipeline. /// /// A shared pointer to a pipeline stage. - const std::shared_ptr & next_stage() const - { - return m_next_stage; - } + const std::shared_ptr& next_stage() const { return m_next_stage; } /// /// Gets a shared pointer to this pipeline stage. /// /// A shared pointer to a pipeline stage. CASABLANCA_DEPRECATED("This api is redundant. Use 'shared_from_this()' directly instead.") - std::shared_ptr current_stage() - { - return this->shared_from_this(); - } + std::shared_ptr current_stage() { return this->shared_from_this(); } private: friend class ::web::http::client::http_pipeline; - void set_next_stage(const std::shared_ptr &next) - { - m_next_stage = next; - } + void set_next_stage(const std::shared_ptr& next) { m_next_stage = next; } std::shared_ptr m_next_stage; - }; -}} +} // namespace http +} // namespace web diff --git a/Release/include/cpprest/interopstream.h b/Release/include/cpprest/interopstream.h index 5cf575aa0e..e3287c1beb 100644 --- a/Release/include/cpprest/interopstream.h +++ b/Release/include/cpprest/interopstream.h @@ -1,524 +1,554 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Adapter classes for async and STD stream buffers, used to connect std-based and async-based APIs. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Adapter classes for async and STD stream buffers, used to connect std-based and async-based APIs. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include "pplx/pplxtasks.h" #include "cpprest/astreambuf.h" #include "cpprest/streams.h" +#include "pplx/pplxtasks.h" #if defined(_WIN32) #pragma warning(push) #pragma warning(disable : 4250) #endif -namespace Concurrency { namespace streams { - - template class stdio_ostream; - template class stdio_istream; - - namespace details { - +namespace Concurrency +{ +namespace streams +{ +template +class stdio_ostream; +template +class stdio_istream; + +namespace details +{ +/// +/// The basic_stdio_buffer class serves to support interoperability with STL stream buffers. +/// Sitting atop a std::streambuf, which does all the I/O, instances of this class may read +/// and write data to standard iostreams. The class itself should not be used in application +/// code, it is used by the stream definitions farther down in the header file. +/// +template +class basic_stdio_buffer : public streambuf_state_manager<_CharType> +{ + typedef concurrency::streams::char_traits<_CharType> traits; + typedef typename traits::int_type int_type; + typedef typename traits::pos_type pos_type; + typedef typename traits::off_type off_type; /// - /// The basic_stdio_buffer class serves to support interoperability with STL stream buffers. - /// Sitting atop a std::streambuf, which does all the I/O, instances of this class may read - /// and write data to standard iostreams. The class itself should not be used in application - /// code, it is used by the stream definitions farther down in the header file. + /// Private constructor /// - template - class basic_stdio_buffer : public streambuf_state_manager<_CharType> + basic_stdio_buffer(_In_ std::basic_streambuf<_CharType>* streambuf, std::ios_base::openmode mode) + : streambuf_state_manager<_CharType>(mode), m_buffer(streambuf) { - typedef concurrency::streams::char_traits<_CharType> traits; - typedef typename traits::int_type int_type; - typedef typename traits::pos_type pos_type; - typedef typename traits::off_type off_type; - /// - /// Private constructor - /// - basic_stdio_buffer(_In_ std::basic_streambuf<_CharType>* streambuf, std::ios_base::openmode mode) - : streambuf_state_manager<_CharType>(mode), m_buffer(streambuf) - { - } - - public: - /// - /// Destructor - /// - virtual ~basic_stdio_buffer() - { - this->_close_read(); - this->_close_write(); - } + } - private: - // - // The functions overridden below here are documented elsewhere. - // See astreambuf.h for further information. - // - virtual bool can_seek() const { return this->is_open(); } - virtual bool has_size() const { return false; } - - virtual size_t in_avail() const { return (size_t)m_buffer->in_avail(); } - - virtual size_t buffer_size(std::ios_base::openmode) const { return 0; } - virtual void set_buffer_size(size_t, std::ios_base::openmode) { return; } +public: + /// + /// Destructor + /// + virtual ~basic_stdio_buffer() + { + this->_close_read(); + this->_close_write(); + } - virtual pplx::task _sync() { return pplx::task_from_result(m_buffer->pubsync() == 0); } +private: + // + // The functions overridden below here are documented elsewhere. + // See astreambuf.h for further information. + // + virtual bool can_seek() const { return this->is_open(); } + virtual bool has_size() const { return false; } - virtual pplx::task _putc(_CharType ch) { return pplx::task_from_result(m_buffer->sputc(ch)); } - virtual pplx::task _putn(const _CharType *ptr, size_t size) { return pplx::task_from_result((size_t)m_buffer->sputn(ptr, size)); } + virtual size_t in_avail() const { return (size_t)m_buffer->in_avail(); } - size_t _sgetn(_Out_writes_ (size) _CharType *ptr, _In_ size_t size) const { return m_buffer->sgetn(ptr, size); } - virtual size_t _scopy(_Out_writes_ (size) _CharType *, _In_ size_t size) { (void)(size); return (size_t)-1; } + virtual size_t buffer_size(std::ios_base::openmode) const { return 0; } + virtual void set_buffer_size(size_t, std::ios_base::openmode) { return; } - virtual pplx::task _getn(_Out_writes_ (size) _CharType *ptr, _In_ size_t size) { return pplx::task_from_result((size_t)m_buffer->sgetn(ptr, size)); } + virtual pplx::task _sync() { return pplx::task_from_result(m_buffer->pubsync() == 0); } - virtual int_type _sbumpc() { return m_buffer->sbumpc(); } - virtual int_type _sgetc() { return m_buffer->sgetc(); } + virtual pplx::task _putc(_CharType ch) { return pplx::task_from_result(m_buffer->sputc(ch)); } + virtual pplx::task _putn(const _CharType* ptr, size_t size) + { + return pplx::task_from_result((size_t)m_buffer->sputn(ptr, size)); + } - virtual pplx::task _bumpc() { return pplx::task_from_result(m_buffer->sbumpc()); } - virtual pplx::task _getc() { return pplx::task_from_result(m_buffer->sgetc()); } - virtual pplx::task _nextc() { return pplx::task_from_result(m_buffer->snextc()); } - virtual pplx::task _ungetc() { return pplx::task_from_result(m_buffer->sungetc()); } + size_t _sgetn(_Out_writes_(size) _CharType* ptr, _In_ size_t size) const { return m_buffer->sgetn(ptr, size); } + virtual size_t _scopy(_Out_writes_(size) _CharType*, _In_ size_t size) + { + (void)(size); + return (size_t)-1; + } - virtual pos_type getpos(std::ios_base::openmode mode) const { return m_buffer->pubseekoff(0, std::ios_base::cur, mode); } - virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode) { return m_buffer->pubseekpos(pos, mode); } - virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode mode) { return m_buffer->pubseekoff(off, dir, mode); } + virtual pplx::task _getn(_Out_writes_(size) _CharType* ptr, _In_ size_t size) + { + return pplx::task_from_result((size_t)m_buffer->sgetn(ptr, size)); + } - virtual _CharType* _alloc(size_t) { return nullptr; } - virtual void _commit(size_t) {} + virtual int_type _sbumpc() { return m_buffer->sbumpc(); } + virtual int_type _sgetc() { return m_buffer->sgetc(); } - virtual bool acquire(_CharType*&, size_t&) { return false; } - virtual void release(_CharType *, size_t) { } + virtual pplx::task _bumpc() { return pplx::task_from_result(m_buffer->sbumpc()); } + virtual pplx::task _getc() { return pplx::task_from_result(m_buffer->sgetc()); } + virtual pplx::task _nextc() { return pplx::task_from_result(m_buffer->snextc()); } + virtual pplx::task _ungetc() { return pplx::task_from_result(m_buffer->sungetc()); } - template friend class concurrency::streams::stdio_ostream; - template friend class concurrency::streams::stdio_istream; + virtual pos_type getpos(std::ios_base::openmode mode) const + { + return m_buffer->pubseekoff(0, std::ios_base::cur, mode); + } + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode) { return m_buffer->pubseekpos(pos, mode); } + virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode mode) + { + return m_buffer->pubseekoff(off, dir, mode); + } - std::basic_streambuf<_CharType>* m_buffer; - }; + virtual _CharType* _alloc(size_t) { return nullptr; } + virtual void _commit(size_t) {} - } // namespace details + virtual bool acquire(_CharType*&, size_t&) { return false; } + virtual void release(_CharType*, size_t) {} + template + friend class concurrency::streams::stdio_ostream; + template + friend class concurrency::streams::stdio_istream; + + std::basic_streambuf<_CharType>* m_buffer; +}; + +} // namespace details + +/// +/// stdio_ostream represents an async ostream derived from a standard synchronous stream, as +/// defined by the "std" namespace. It is constructed from a reference to a standard stream, which +/// must be valid for the lifetime of the asynchronous stream. +/// +/// +/// The data type of the basic element of the stdio_ostream. +/// +/// +/// Since std streams are not reference-counted, great care must be taken by an application to make +/// sure that the std stream does not get destroyed until all uses of the asynchronous stream are +/// done and have been serviced. +/// +template +class stdio_ostream : public basic_ostream +{ +public: /// - /// stdio_ostream represents an async ostream derived from a standard synchronous stream, as - /// defined by the "std" namespace. It is constructed from a reference to a standard stream, which - /// must be valid for the lifetime of the asynchronous stream. + /// Constructor /// - /// - /// The data type of the basic element of the stdio_ostream. + /// + /// The data type of the basic element of the source output stream. /// - /// - /// Since std streams are not reference-counted, great care must be taken by an application to make - /// sure that the std stream does not get destroyed until all uses of the asynchronous stream are - /// done and have been serviced. - /// - template - class stdio_ostream : public basic_ostream + /// The synchronous stream that this is using for its I/O + template + stdio_ostream(std::basic_ostream& stream) + : basic_ostream( + streams::streambuf(std::shared_ptr>( + new details::basic_stdio_buffer(stream.rdbuf(), std::ios_base::out)))) { - public: - /// - /// Constructor - /// - /// - /// The data type of the basic element of the source output stream. - /// - /// The synchronous stream that this is using for its I/O - template - stdio_ostream(std::basic_ostream& stream) - : basic_ostream(streams::streambuf(std::shared_ptr>(new details::basic_stdio_buffer(stream.rdbuf(), std::ios_base::out)))) - { - } - - /// - /// Copy constructor - /// - /// The source object - stdio_ostream(const stdio_ostream &other) : basic_ostream(other) { } + } - /// - /// Assignment operator - /// - /// The source object - /// A reference to the output stream object that contains the result of the assignment. - stdio_ostream & operator =(const stdio_ostream &other) { basic_ostream::operator=(other); return *this; } - }; + /// + /// Copy constructor + /// + /// The source object + stdio_ostream(const stdio_ostream& other) : basic_ostream(other) {} /// - /// stdio_istream represents an async istream derived from a standard synchronous stream, as - /// defined by the "std" namespace. It is constructed from a reference to a standard stream, which - /// must be valid for the lifetime of the asynchronous stream. + /// Assignment operator + /// + /// The source object + /// A reference to the output stream object that contains the result of the assignment. + stdio_ostream& operator=(const stdio_ostream& other) + { + basic_ostream::operator=(other); + return *this; + } +}; + +/// +/// stdio_istream represents an async istream derived from a standard synchronous stream, as +/// defined by the "std" namespace. It is constructed from a reference to a standard stream, which +/// must be valid for the lifetime of the asynchronous stream. +/// +/// +/// The data type of the basic element of the stdio_istream. +/// +/// +/// Since std streams are not reference-counted, great care must be taken by an application to make +/// sure that the std stream does not get destroyed until all uses of the asynchronous stream are +/// done and have been serviced. +/// +template +class stdio_istream : public basic_istream +{ +public: + /// + /// Constructor /// - /// - /// The data type of the basic element of the stdio_istream. + /// + /// The data type of the basic element of the source istream /// - /// - /// Since std streams are not reference-counted, great care must be taken by an application to make - /// sure that the std stream does not get destroyed until all uses of the asynchronous stream are - /// done and have been serviced. - /// - template - class stdio_istream : public basic_istream + /// The synchronous stream that this is using for its I/O + template + stdio_istream(std::basic_istream& stream) + : basic_istream( + streams::streambuf(std::shared_ptr>( + new details::basic_stdio_buffer(stream.rdbuf(), std::ios_base::in)))) { - public: - /// - /// Constructor - /// - /// - /// The data type of the basic element of the source istream - /// - /// The synchronous stream that this is using for its I/O - template - stdio_istream(std::basic_istream& stream) - : basic_istream(streams::streambuf(std::shared_ptr>(new details::basic_stdio_buffer(stream.rdbuf(), std::ios_base::in)))) - { - } - - /// - /// Copy constructor - /// - /// The source object - stdio_istream(const stdio_istream &other) : basic_istream(other) { } - - /// - /// Assignment operator - /// - /// The source object - /// A reference to the input stream object that contains the result of the assignment. - stdio_istream & operator =(const stdio_istream &other) { basic_istream::operator=(other); return *this; } - }; + } - namespace details { + /// + /// Copy constructor + /// + /// The source object + stdio_istream(const stdio_istream& other) : basic_istream(other) {} /// - /// IO streams stream buffer implementation used to interface with an async streambuffer underneath. - /// Used for implementing the standard synchronous streams that provide interop between std:: and concurrency::streams:: + /// Assignment operator /// - template - class basic_async_streambuf : public std::basic_streambuf + /// The source object + /// A reference to the input stream object that contains the result of the assignment. + stdio_istream& operator=(const stdio_istream& other) { - public: - typedef concurrency::streams::char_traits traits; - typedef typename traits::int_type int_type; - typedef typename traits::pos_type pos_type; - typedef typename traits::off_type off_type; - - basic_async_streambuf(const streams::streambuf &async_buf) : m_buffer(async_buf) - { - } - protected: - - // - // The following are the functions in std::basic_streambuf that we need to override. - // + basic_istream::operator=(other); + return *this; + } +}; + +namespace details +{ +/// +/// IO streams stream buffer implementation used to interface with an async streambuffer underneath. +/// Used for implementing the standard synchronous streams that provide interop between std:: and concurrency::streams:: +/// +template +class basic_async_streambuf : public std::basic_streambuf +{ +public: + typedef concurrency::streams::char_traits traits; + typedef typename traits::int_type int_type; + typedef typename traits::pos_type pos_type; + typedef typename traits::off_type off_type; + + basic_async_streambuf(const streams::streambuf& async_buf) : m_buffer(async_buf) {} + +protected: + // + // The following are the functions in std::basic_streambuf that we need to override. + // - /// - /// Writes one byte to the stream buffer. - /// - int_type overflow(int_type ch) + /// + /// Writes one byte to the stream buffer. + /// + int_type overflow(int_type ch) + { + try { - try - { return m_buffer.putc(CharType(ch)).get(); } - catch(...) - { - return traits::eof(); - } + catch (...) + { + return traits::eof(); } + } - /// - /// Gets one byte from the stream buffer without moving the read position. - /// - int_type underflow() + /// + /// Gets one byte from the stream buffer without moving the read position. + /// + int_type underflow() + { + try { - try - { return m_buffer.getc().get(); } - catch(...) - { - return traits::eof(); - } + catch (...) + { + return traits::eof(); } + } - /// - /// Gets one byte from the stream buffer and move the read position one character. - /// - int_type uflow() + /// + /// Gets one byte from the stream buffer and move the read position one character. + /// + int_type uflow() + { + try { - try - { return m_buffer.bumpc().get(); } - catch(...) - { - return traits::eof(); - } + catch (...) + { + return traits::eof(); } + } - /// - /// Gets a number of characters from the buffer and place it into the provided memory block. - /// - std::streamsize xsgetn(_Out_writes_ (count) CharType* ptr, _In_ std::streamsize count) - { - size_t cnt = size_t(count); - size_t read_so_far = 0; + /// + /// Gets a number of characters from the buffer and place it into the provided memory block. + /// + std::streamsize xsgetn(_Out_writes_(count) CharType* ptr, _In_ std::streamsize count) + { + size_t cnt = size_t(count); + size_t read_so_far = 0; - try - { + try + { while (read_so_far < cnt) { - size_t rd = m_buffer.getn(ptr+read_so_far, cnt-read_so_far).get(); + size_t rd = m_buffer.getn(ptr + read_so_far, cnt - read_so_far).get(); read_so_far += rd; - if ( rd == 0 ) - break; + if (rd == 0) break; } return read_so_far; } - catch(...) - { - return 0; - } + catch (...) + { + return 0; } + } - /// - /// Writes a given number of characters from the provided block into the stream buffer. - /// - std::streamsize xsputn(const CharType* ptr, std::streamsize count) + /// + /// Writes a given number of characters from the provided block into the stream buffer. + /// + std::streamsize xsputn(const CharType* ptr, std::streamsize count) + { + try { - try - { - return m_buffer.putn_nocopy(ptr, static_cast(count)).get(); - } - catch(...) - { - return 0; - } + return m_buffer.putn_nocopy(ptr, static_cast(count)).get(); } - - /// - /// Synchronizes with the underlying medium. - /// - int sync() // must be int as per std::basic_streambuf + catch (...) { - try - { - m_buffer.sync().wait(); - } - catch(...) - { - } return 0; } + } - /// - /// Seeks to the given offset relative to the beginning, end, or current position. - /// - pos_type seekoff(off_type offset, - std::ios_base::seekdir dir, - std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) + /// + /// Synchronizes with the underlying medium. + /// + int sync() // must be int as per std::basic_streambuf + { + try { - try - { - if ( dir == std::ios_base::cur && offset == 0) // Special case for getting the current position. - return m_buffer.getpos(mode); - return m_buffer.seekoff(offset,dir,mode); - } - catch(...) - { - return (pos_type(-1)); - } + m_buffer.sync().wait(); } - - /// - /// Seeks to the given offset relative to the beginning of the stream. - /// - pos_type seekpos(pos_type pos, - std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) + catch (...) { - try - { - return m_buffer.seekpos(pos, mode); - } - catch(...) - { - return (pos_type(-1)); - } } - - private: - concurrency::streams::streambuf m_buffer; - }; - - } // namespace details + return 0; + } /// - /// A concrete STL ostream which relies on an asynchronous stream for its I/O. + /// Seeks to the given offset relative to the beginning, end, or current position. /// - /// - /// The data type of the basic element of the stream. - /// - template - class async_ostream : public std::basic_ostream + pos_type seekoff(off_type offset, + std::ios_base::seekdir dir, + std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { - public: - /// - /// Constructor - /// - /// - /// The data type of the basic element of the source ostream. - /// - /// The asynchronous stream whose stream buffer should be used for I/O - template - async_ostream(const streams::basic_ostream &astream) - : std::basic_ostream(&m_strbuf), - m_strbuf(astream.streambuf()) + try { + if (dir == std::ios_base::cur && offset == 0) // Special case for getting the current position. + return m_buffer.getpos(mode); + return m_buffer.seekoff(offset, dir, mode); } - - /// - /// Constructor - /// - /// - /// The data type of the basic element of the source streambuf. - /// - /// The asynchronous stream buffer to use for I/O - template - async_ostream(const streams::streambuf &strbuf) - : std::basic_ostream(&m_strbuf), - m_strbuf(strbuf) + catch (...) { + return (pos_type(-1)); } - - private: - details::basic_async_streambuf m_strbuf; - }; + } /// - /// A concrete STL istream which relies on an asynchronous stream for its I/O. + /// Seeks to the given offset relative to the beginning of the stream. /// - /// - /// The data type of the basic element of the stream. - /// - template - class async_istream : public std::basic_istream + pos_type seekpos(pos_type pos, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { - public: - /// - /// Constructor - /// - /// - /// The data type of the basic element of the source istream. - /// - /// The asynchronous stream whose stream buffer should be used for I/O - template - async_istream(const streams::basic_istream &astream) - : std::basic_istream(&m_strbuf), - m_strbuf(astream.streambuf()) + try { + return m_buffer.seekpos(pos, mode); } - - /// - /// Constructor - /// - /// - /// The data type of the basic element of the source streambuf. - /// - /// The asynchronous stream buffer to use for I/O - template - async_istream(const streams::streambuf &strbuf) - : std::basic_istream(&m_strbuf), - m_strbuf(strbuf) + catch (...) { + return (pos_type(-1)); } + } + +private: + concurrency::streams::streambuf m_buffer; +}; + +} // namespace details + +/// +/// A concrete STL ostream which relies on an asynchronous stream for its I/O. +/// +/// +/// The data type of the basic element of the stream. +/// +template +class async_ostream : public std::basic_ostream +{ +public: + /// + /// Constructor + /// + /// + /// The data type of the basic element of the source ostream. + /// + /// The asynchronous stream whose stream buffer should be used for I/O + template + async_ostream(const streams::basic_ostream& astream) + : std::basic_ostream(&m_strbuf), m_strbuf(astream.streambuf()) + { + } - private: - details::basic_async_streambuf m_strbuf; - }; + /// + /// Constructor + /// + /// + /// The data type of the basic element of the source streambuf. + /// + /// The asynchronous stream buffer to use for I/O + template + async_ostream(const streams::streambuf& strbuf) + : std::basic_ostream(&m_strbuf), m_strbuf(strbuf) + { + } + +private: + details::basic_async_streambuf m_strbuf; +}; + +/// +/// A concrete STL istream which relies on an asynchronous stream for its I/O. +/// +/// +/// The data type of the basic element of the stream. +/// +template +class async_istream : public std::basic_istream +{ +public: + /// + /// Constructor + /// + /// + /// The data type of the basic element of the source istream. + /// + /// The asynchronous stream whose stream buffer should be used for I/O + template + async_istream(const streams::basic_istream& astream) + : std::basic_istream(&m_strbuf), m_strbuf(astream.streambuf()) + { + } /// - /// A concrete STL istream which relies on an asynchronous stream buffer for its I/O. + /// Constructor /// - /// - /// The data type of the basic element of the stream. + /// + /// The data type of the basic element of the source streambuf. /// - template - class async_iostream : public std::basic_iostream + /// The asynchronous stream buffer to use for I/O + template + async_istream(const streams::streambuf& strbuf) + : std::basic_istream(&m_strbuf), m_strbuf(strbuf) { - public: - /// - /// Constructor - /// - /// The asynchronous stream buffer to use for I/O - async_iostream(const streams::streambuf &strbuf) - : std::basic_iostream(&m_strbuf), - m_strbuf(strbuf) - { - } + } + +private: + details::basic_async_streambuf m_strbuf; +}; + +/// +/// A concrete STL istream which relies on an asynchronous stream buffer for its I/O. +/// +/// +/// The data type of the basic element of the stream. +/// +template +class async_iostream : public std::basic_iostream +{ +public: + /// + /// Constructor + /// + /// The asynchronous stream buffer to use for I/O + async_iostream(const streams::streambuf& strbuf) + : std::basic_iostream(&m_strbuf), m_strbuf(strbuf) + { + } - private: - details::basic_async_streambuf m_strbuf; - }; +private: + details::basic_async_streambuf m_strbuf; +}; #if defined(__cplusplus_winrt) +/// +/// Static class containing factory functions for WinRT streams implemented on top of Casablanca async streams. +/// +/// WinRT streams are defined in terms of single-byte characters only. +class winrt_stream +{ +public: /// - /// Static class containing factory functions for WinRT streams implemented on top of Casablanca async streams. + /// Creates a WinRT IInputStream reference from an asynchronous stream buffer. /// - /// WinRT streams are defined in terms of single-byte characters only. - class winrt_stream - { - public: - /// - /// Creates a WinRT IInputStream reference from an asynchronous stream buffer. - /// - /// A stream buffer based on a single-byte character. - /// A reference to a WinRT IInputStream. - /// - /// The stream buffer passed in must allow reading. - /// The stream buffer is shared with the caller, allowing data to be passed between the two contexts. For - /// example, using a producer_consumer_buffer, a Casablanca-based caller can pass data to a WinRT component. - /// - _ASYNCRTIMP static Windows::Storage::Streams::IInputStream^ __cdecl create_input_stream(const concurrency::streams::streambuf &buffer); - - /// - /// Creates a WinRT IOutputStream reference from an asynchronous stream buffer. - /// - /// A stream buffer based on a single-byte character. - /// A reference to a WinRT IOutputStream. - /// - /// The stream buffer passed in must allow writing. - /// The stream buffer is shared with the caller, allowing data to be passed between the two contexts. For - /// example, using a producer_consumer_buffer, a Casablanca-based caller can retrieve data from a WinRT component. - /// - _ASYNCRTIMP static Windows::Storage::Streams::IOutputStream^ __cdecl create_output_stream(const concurrency::streams::streambuf &buffer); - - /// - /// Creates a WinRT IRandomAccessStream reference from an asynchronous input stream. - /// - /// A stream based on a single-byte character. - /// A reference to a WinRT IRandomAccessStream. - /// - /// The stream buffer is shared with the caller, allowing data to be passed between the two contexts. For - /// example, using a producer_consumer_buffer, a Casablanca-based caller can pass data to and retrieve data - /// from a WinRT component. - /// - _ASYNCRTIMP static Windows::Storage::Streams::IRandomAccessStream^ __cdecl create_random_access_stream(const concurrency::streams::streambuf &buffer); - }; + /// A stream buffer based on a single-byte character. + /// A reference to a WinRT IInputStream. + /// + /// The stream buffer passed in must allow reading. + /// The stream buffer is shared with the caller, allowing data to be passed between the two contexts. For + /// example, using a producer_consumer_buffer, a Casablanca-based caller can pass data to a WinRT component. + /// + _ASYNCRTIMP static Windows::Storage::Streams::IInputStream ^ + __cdecl create_input_stream(const concurrency::streams::streambuf& buffer); + + /// + /// Creates a WinRT IOutputStream reference from an asynchronous stream buffer. + /// + /// A stream buffer based on a single-byte character. + /// A reference to a WinRT IOutputStream. + /// + /// The stream buffer passed in must allow writing. + /// The stream buffer is shared with the caller, allowing data to be passed between the two contexts. For + /// example, using a producer_consumer_buffer, a Casablanca-based caller can retrieve data from a WinRT + /// component. + /// + _ASYNCRTIMP static Windows::Storage::Streams::IOutputStream ^ + __cdecl create_output_stream(const concurrency::streams::streambuf& buffer); + + /// + /// Creates a WinRT IRandomAccessStream reference from an asynchronous input stream. + /// + /// A stream based on a single-byte character. + /// A reference to a WinRT IRandomAccessStream. + /// + /// The stream buffer is shared with the caller, allowing data to be passed between the two contexts. For + /// example, using a producer_consumer_buffer, a Casablanca-based caller can pass data to and retrieve data + /// from a WinRT component. + /// + _ASYNCRTIMP static Windows::Storage::Streams::IRandomAccessStream ^ + __cdecl create_random_access_stream(const concurrency::streams::streambuf& buffer); +}; #endif -}} // namespaces +} // namespace streams +} // namespace Concurrency #if defined(_WIN32) #pragma warning(pop) -#endif \ No newline at end of file +#endif diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index e817da4fba..4095be50ea 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -1,59 +1,60 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: JSON parser and writer -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: JSON parser and writer + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_JSON_H #define CASA_JSON_H +#include "cpprest/asyncrt_utils.h" +#include "cpprest/details/basic_types.h" +#include #include -#include #include -#include +#include #include -#include -#include "cpprest/details/basic_types.h" -#include "cpprest/asyncrt_utils.h" +#include namespace web { /// Library for parsing and serializing JSON values to and from C++ types. namespace json { - // Various forward declarations. - namespace details - { - class _Value; - class _Number; - class _Null; - class _Boolean; - class _String; - class _Object; - class _Array; - template class JSON_Parser; - } - - namespace details - { - extern bool g_keep_json_object_unsorted; - } +// Various forward declarations. +namespace details +{ +class _Value; +class _Number; +class _Null; +class _Boolean; +class _String; +class _Object; +class _Array; +template +class JSON_Parser; +} // namespace details + +namespace details +{ +extern bool g_keep_json_object_unsorted; +} - /// - /// Preserve the order of the name/value pairs when parsing a JSON object. - /// The default is false, which can yield better performance. - /// - /// true if ordering should be preserved when parsing, false otherwise. - /// Note this is a global setting and affects all JSON parsing done. - void _ASYNCRTIMP __cdecl keep_object_element_order(bool keep_order); +/// +/// Preserve the order of the name/value pairs when parsing a JSON object. +/// The default is false, which can yield better performance. +/// +/// true if ordering should be preserved when parsing, false otherwise. +/// Note this is a global setting and affects all JSON parsing done. +void _ASYNCRTIMP __cdecl keep_object_element_order(bool keep_order); #ifdef _WIN32 #ifdef _DEBUG @@ -61,1923 +62,1725 @@ namespace json #endif #endif - class number; - class array; - class object; +class number; +class array; +class object; +/// +/// A JSON value represented as a C++ class. +/// +class value +{ +public: /// - /// A JSON value represented as a C++ class. + /// This enumeration represents the various kinds of JSON values. /// - class value + enum value_type { - public: - /// - /// This enumeration represents the various kinds of JSON values. - /// - enum value_type - { - /// Number value - Number, - /// Boolean value - Boolean, - /// String value - String, - /// Object value - Object, - /// Array value - Array, - /// Null value - Null - }; - - /// - /// Constructor creating a null value - /// - _ASYNCRTIMP value(); - - /// - /// Constructor creating a JSON number value - /// - /// The C++ value to create a JSON value from - _ASYNCRTIMP value(int32_t value); - - /// - /// Constructor creating a JSON number value - /// - /// The C++ value to create a JSON value from - _ASYNCRTIMP value(uint32_t value); - - /// - /// Constructor creating a JSON number value - /// - /// The C++ value to create a JSON value from - _ASYNCRTIMP value(int64_t value); - - /// - /// Constructor creating a JSON number value - /// - /// The C++ value to create a JSON value from - _ASYNCRTIMP value(uint64_t value); - - /// - /// Constructor creating a JSON number value - /// - /// The C++ value to create a JSON value from - _ASYNCRTIMP value(double value); - - /// - /// Constructor creating a JSON Boolean value - /// - /// The C++ value to create a JSON value from - _ASYNCRTIMP explicit value(bool value); - - /// - /// Constructor creating a JSON string value - /// - /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width - /// - /// This constructor has O(n) performance because it tries to determine if - /// specified string has characters that should be properly escaped in JSON. - /// - _ASYNCRTIMP explicit value(utility::string_t value); - - /// - /// Constructor creating a JSON string value specifying if the string contains characters to escape - /// - /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width - /// Whether contains characters - /// that should be escaped in JSON value - /// - /// This constructor has O(1) performance. - /// - _ASYNCRTIMP explicit value(utility::string_t value, bool has_escape_chars); - - /// - /// Constructor creating a JSON string value - /// - /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width - /// - /// - /// This constructor has O(n) performance because it tries to determine if - /// specified string has characters that should be properly escaped in JSON. - /// - /// - /// This constructor exists in order to avoid string literals matching another constructor, - /// as is very likely. For example, conversion to bool does not require a user-defined conversion, - /// and will therefore match first, which means that the JSON value turns up as a boolean. - /// - /// - _ASYNCRTIMP explicit value(const utility::char_t* value); - - /// - /// Constructor creating a JSON string value - /// - /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width - /// Whether contains characters - /// - /// - /// This overload has O(1) performance. - /// - /// - /// This constructor exists in order to avoid string literals matching another constructor, - /// as is very likely. For example, conversion to bool does not require a user-defined conversion, - /// and will therefore match first, which means that the JSON value turns up as a boolean. - /// - /// - _ASYNCRTIMP explicit value(const utility::char_t* value, bool has_escape_chars); - - /// - /// Copy constructor - /// - _ASYNCRTIMP value(const value &); - - /// - /// Move constructor - /// - _ASYNCRTIMP value(value &&) CPPREST_NOEXCEPT ; - - /// - /// Assignment operator. - /// - /// The JSON value object that contains the result of the assignment. - _ASYNCRTIMP value &operator=(const value &); - - /// - /// Move assignment operator. - /// - /// The JSON value object that contains the result of the assignment. - _ASYNCRTIMP value &operator=(value &&) CPPREST_NOEXCEPT ; - - // Static factories - - /// - /// Creates a null value - /// - /// A JSON null value - static _ASYNCRTIMP value __cdecl null(); - - /// - /// Creates a number value - /// - /// The C++ value to create a JSON value from - /// A JSON number value - static _ASYNCRTIMP value __cdecl number(double value); - - /// - /// Creates a number value - /// - /// The C++ value to create a JSON value from - /// A JSON number value - static _ASYNCRTIMP value __cdecl number(int32_t value); - - /// - /// Creates a number value - /// - /// The C++ value to create a JSON value from - /// A JSON number value - static _ASYNCRTIMP value __cdecl number(uint32_t value); - - /// - /// Creates a number value - /// - /// The C++ value to create a JSON value from - /// A JSON number value - static _ASYNCRTIMP value __cdecl number(int64_t value); - - /// - /// Creates a number value - /// - /// The C++ value to create a JSON value from - /// A JSON number value - static _ASYNCRTIMP value __cdecl number(uint64_t value); - - /// - /// Creates a Boolean value - /// - /// The C++ value to create a JSON value from - /// A JSON Boolean value - static _ASYNCRTIMP value __cdecl boolean(bool value); - - /// - /// Creates a string value - /// - /// The C++ value to create a JSON value from - /// A JSON string value - /// - /// This overload has O(n) performance because it tries to determine if - /// specified string has characters that should be properly escaped in JSON. - /// - static _ASYNCRTIMP value __cdecl string(utility::string_t value); - - /// - /// Creates a string value specifying if the string contains characters to escape - /// - /// The C++ value to create a JSON value from - /// Whether contains characters - /// that should be escaped in JSON value - /// A JSON string value - /// - /// This overload has O(1) performance. - /// - static _ASYNCRTIMP value __cdecl string(utility::string_t value, bool has_escape_chars); + /// Number value + Number, + /// Boolean value + Boolean, + /// String value + String, + /// Object value + Object, + /// Array value + Array, + /// Null value + Null + }; + + /// + /// Constructor creating a null value + /// + _ASYNCRTIMP value(); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(int32_t value); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(uint32_t value); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(int64_t value); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(uint64_t value); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(double value); + + /// + /// Constructor creating a JSON Boolean value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP explicit value(bool value); + + /// + /// Constructor creating a JSON string value + /// + /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character + /// width This constructor has O(n) performance because it tries to determine if specified string + /// has characters that should be properly escaped in JSON. + _ASYNCRTIMP explicit value(utility::string_t value); + + /// + /// Constructor creating a JSON string value specifying if the string contains characters to escape + /// + /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character + /// width Whether contains characters that should + /// be escaped in JSON value This constructor has O(1) performance. + /// + _ASYNCRTIMP explicit value(utility::string_t value, bool has_escape_chars); + + /// + /// Constructor creating a JSON string value + /// + /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character + /// width This constructor has O(n) performance because it tries to determine if specified + /// string has characters that should be properly escaped in JSON. + /// + /// + /// This constructor exists in order to avoid string literals matching another constructor, + /// as is very likely. For example, conversion to bool does not require a user-defined conversion, + /// and will therefore match first, which means that the JSON value turns up as a boolean. + /// + /// + _ASYNCRTIMP explicit value(const utility::char_t* value); + + /// + /// Constructor creating a JSON string value + /// + /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character + /// width Whether contains characters + /// + /// This overload has O(1) performance. + /// + /// + /// This constructor exists in order to avoid string literals matching another constructor, + /// as is very likely. For example, conversion to bool does not require a user-defined conversion, + /// and will therefore match first, which means that the JSON value turns up as a boolean. + /// + /// + _ASYNCRTIMP explicit value(const utility::char_t* value, bool has_escape_chars); + + /// + /// Copy constructor + /// + _ASYNCRTIMP value(const value&); + + /// + /// Move constructor + /// + _ASYNCRTIMP value(value&&) CPPREST_NOEXCEPT; + + /// + /// Assignment operator. + /// + /// The JSON value object that contains the result of the assignment. + _ASYNCRTIMP value& operator=(const value&); + + /// + /// Move assignment operator. + /// + /// The JSON value object that contains the result of the assignment. + _ASYNCRTIMP value& operator=(value&&) CPPREST_NOEXCEPT; + + // Static factories + + /// + /// Creates a null value + /// + /// A JSON null value + static _ASYNCRTIMP value __cdecl null(); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(double value); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(int32_t value); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(uint32_t value); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(int64_t value); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(uint64_t value); + + /// + /// Creates a Boolean value + /// + /// The C++ value to create a JSON value from + /// A JSON Boolean value + static _ASYNCRTIMP value __cdecl boolean(bool value); + + /// + /// Creates a string value + /// + /// The C++ value to create a JSON value from + /// A JSON string value + /// + /// This overload has O(n) performance because it tries to determine if + /// specified string has characters that should be properly escaped in JSON. + /// + static _ASYNCRTIMP value __cdecl string(utility::string_t value); + + /// + /// Creates a string value specifying if the string contains characters to escape + /// + /// The C++ value to create a JSON value from + /// Whether contains characters + /// that should be escaped in JSON value + /// A JSON string value + /// + /// This overload has O(1) performance. + /// + static _ASYNCRTIMP value __cdecl string(utility::string_t value, bool has_escape_chars); #ifdef _WIN32 private: - // Only used internally by JSON parser. - static _ASYNCRTIMP value __cdecl string(const std::string &value); + // Only used internally by JSON parser. + static _ASYNCRTIMP value __cdecl string(const std::string& value); + public: #endif - /// - /// Creates an object value - /// - /// Whether to preserve the original order of the fields - /// An empty JSON object value - static _ASYNCRTIMP json::value __cdecl object(bool keep_order = false); - - /// - /// Creates an object value from a collection of field/values - /// - /// Field names associated with JSON values - /// Whether to preserve the original order of the fields - /// A non-empty JSON object value - static _ASYNCRTIMP json::value __cdecl object(std::vector> fields, bool keep_order = false); - - /// - /// Creates an empty JSON array - /// - /// An empty JSON array value - static _ASYNCRTIMP json::value __cdecl array(); - - /// - /// Creates a JSON array - /// - /// The initial number of elements of the JSON value - /// A JSON array value - static _ASYNCRTIMP json::value __cdecl array(size_t size); - - /// - /// Creates a JSON array - /// - /// A vector of JSON values - /// A JSON array value - static _ASYNCRTIMP json::value __cdecl array(std::vector elements); - - /// - /// Accesses the type of JSON value the current value instance is - /// - /// The value's type - _ASYNCRTIMP json::value::value_type type() const; - - /// - /// Is the current value a null value? - /// - /// true if the value is a null value, false otherwise - bool is_null() const { return type() == Null; }; - - /// - /// Is the current value a number value? - /// - /// true if the value is a number value, false otherwise - bool is_number() const { return type() == Number; } - - /// - /// Is the current value represented as an integer number value? - /// - /// - /// Note that if a json value is a number but represented as a double it can still - /// be retrieved as a integer using as_integer(), however the value will be truncated. - /// - /// true if the value is an integer value, false otherwise. - _ASYNCRTIMP bool is_integer() const; - - /// - /// Is the current value represented as an double number value? - /// - /// - /// Note that if a json value is a number but represented as a int it can still - /// be retrieved as a double using as_double(). - /// - /// true if the value is an double value, false otherwise. - _ASYNCRTIMP bool is_double() const; - - /// - /// Is the current value a Boolean value? - /// - /// true if the value is a Boolean value, false otherwise - bool is_boolean() const { return type() == Boolean; } - - /// - /// Is the current value a string value? - /// - /// true if the value is a string value, false otherwise - bool is_string() const { return type() == String; } - - /// - /// Is the current value an array? - /// - /// true if the value is an array, false otherwise - bool is_array() const { return type() == Array; } - - /// - /// Is the current value an object? - /// - /// true if the value is an object, false otherwise - bool is_object() const { return type() == Object; } - - /// - /// Gets the number of children of the value. - /// - /// The number of children. 0 for all non-composites. - size_t size() const; - - /// - /// Parses a string and construct a JSON value. - /// - /// The C++ value to create a JSON value from, a C++ STL double-byte string - _ASYNCRTIMP static value __cdecl parse(const utility::string_t &value); - - /// - /// Attempts to parse a string and construct a JSON value. - /// - /// The C++ value to create a JSON value from, a C++ STL double-byte string - /// If parsing fails, the error code is greater than 0 - /// The parsed object. Returns web::json::value::null if failed - _ASYNCRTIMP static value __cdecl parse(const utility::string_t &value, std::error_code &errorCode); - - /// - /// Serializes the current JSON value to a C++ string. - /// - /// A string representation of the value - _ASYNCRTIMP utility::string_t serialize() const; - - /// - /// Serializes the current JSON value to a C++ string. - /// - /// A string representation of the value - CASABLANCA_DEPRECATED("This API is deprecated and has been renamed to avoid confusion with as_string(), use ::web::json::value::serialize() instead.") - _ASYNCRTIMP utility::string_t to_string() const; - - /// - /// Parses a JSON value from the contents of an input stream using the native platform character width. - /// - /// The stream to read the JSON value from - /// The JSON value object created from the input stream. - _ASYNCRTIMP static value __cdecl parse(utility::istream_t &input); - - /// - /// Parses a JSON value from the contents of an input stream using the native platform character width. - /// - /// The stream to read the JSON value from - /// If parsing fails, the error code is greater than 0 - /// The parsed object. Returns web::json::value::null if failed - _ASYNCRTIMP static value __cdecl parse(utility::istream_t &input, std::error_code &errorCode); - - /// - /// Writes the current JSON value to a stream with the native platform character width. - /// - /// The stream that the JSON string representation should be written to. - _ASYNCRTIMP void serialize(utility::ostream_t &stream) const; + /// + /// Creates an object value + /// + /// Whether to preserve the original order of the fields + /// An empty JSON object value + static _ASYNCRTIMP json::value __cdecl object(bool keep_order = false); + + /// + /// Creates an object value from a collection of field/values + /// + /// Field names associated with JSON values + /// Whether to preserve the original order of the fields + /// A non-empty JSON object value + static _ASYNCRTIMP json::value __cdecl object(std::vector> fields, + bool keep_order = false); + + /// + /// Creates an empty JSON array + /// + /// An empty JSON array value + static _ASYNCRTIMP json::value __cdecl array(); + + /// + /// Creates a JSON array + /// + /// The initial number of elements of the JSON value + /// A JSON array value + static _ASYNCRTIMP json::value __cdecl array(size_t size); + + /// + /// Creates a JSON array + /// + /// A vector of JSON values + /// A JSON array value + static _ASYNCRTIMP json::value __cdecl array(std::vector elements); + + /// + /// Accesses the type of JSON value the current value instance is + /// + /// The value's type + _ASYNCRTIMP json::value::value_type type() const; + + /// + /// Is the current value a null value? + /// + /// true if the value is a null value, false otherwise + bool is_null() const { return type() == Null; }; + + /// + /// Is the current value a number value? + /// + /// true if the value is a number value, false otherwise + bool is_number() const { return type() == Number; } + + /// + /// Is the current value represented as an integer number value? + /// + /// + /// Note that if a json value is a number but represented as a double it can still + /// be retrieved as a integer using as_integer(), however the value will be truncated. + /// + /// true if the value is an integer value, false otherwise. + _ASYNCRTIMP bool is_integer() const; + + /// + /// Is the current value represented as an double number value? + /// + /// + /// Note that if a json value is a number but represented as a int it can still + /// be retrieved as a double using as_double(). + /// + /// true if the value is an double value, false otherwise. + _ASYNCRTIMP bool is_double() const; + + /// + /// Is the current value a Boolean value? + /// + /// true if the value is a Boolean value, false otherwise + bool is_boolean() const { return type() == Boolean; } + + /// + /// Is the current value a string value? + /// + /// true if the value is a string value, false otherwise + bool is_string() const { return type() == String; } + + /// + /// Is the current value an array? + /// + /// true if the value is an array, false otherwise + bool is_array() const { return type() == Array; } + + /// + /// Is the current value an object? + /// + /// true if the value is an object, false otherwise + bool is_object() const { return type() == Object; } + + /// + /// Gets the number of children of the value. + /// + /// The number of children. 0 for all non-composites. + size_t size() const; + + /// + /// Parses a string and construct a JSON value. + /// + /// The C++ value to create a JSON value from, a C++ STL double-byte string + _ASYNCRTIMP static value __cdecl parse(const utility::string_t& value); + + /// + /// Attempts to parse a string and construct a JSON value. + /// + /// The C++ value to create a JSON value from, a C++ STL double-byte string + /// If parsing fails, the error code is greater than 0 + /// The parsed object. Returns web::json::value::null if failed + _ASYNCRTIMP static value __cdecl parse(const utility::string_t& value, std::error_code& errorCode); + + /// + /// Serializes the current JSON value to a C++ string. + /// + /// A string representation of the value + _ASYNCRTIMP utility::string_t serialize() const; + + /// + /// Serializes the current JSON value to a C++ string. + /// + /// A string representation of the value + CASABLANCA_DEPRECATED("This API is deprecated and has been renamed to avoid confusion with as_string(), use " + "::web::json::value::serialize() instead.") + _ASYNCRTIMP utility::string_t to_string() const; + + /// + /// Parses a JSON value from the contents of an input stream using the native platform character width. + /// + /// The stream to read the JSON value from + /// The JSON value object created from the input stream. + _ASYNCRTIMP static value __cdecl parse(utility::istream_t& input); + + /// + /// Parses a JSON value from the contents of an input stream using the native platform character width. + /// + /// The stream to read the JSON value from + /// If parsing fails, the error code is greater than 0 + /// The parsed object. Returns web::json::value::null if failed + _ASYNCRTIMP static value __cdecl parse(utility::istream_t& input, std::error_code& errorCode); + + /// + /// Writes the current JSON value to a stream with the native platform character width. + /// + /// The stream that the JSON string representation should be written to. + _ASYNCRTIMP void serialize(utility::ostream_t& stream) const; #ifdef _WIN32 - /// - /// Parses a JSON value from the contents of a single-byte (UTF8) stream. - /// - /// The stream to read the JSON value from - _ASYNCRTIMP static value __cdecl parse(std::istream& stream); - - /// - /// Parses a JSON value from the contents of a single-byte (UTF8) stream. - /// - /// The stream to read the JSON value from - /// If parsing fails, the error code is greater than 0 - /// The parsed object. Returns web::json::value::null if failed - _ASYNCRTIMP static value __cdecl parse(std::istream& stream, std::error_code& error); - - /// - /// Serializes the content of the value into a single-byte (UTF8) stream. - /// - /// The stream that the JSON string representation should be written to. - _ASYNCRTIMP void serialize(std::ostream& stream) const; + /// + /// Parses a JSON value from the contents of a single-byte (UTF8) stream. + /// + /// The stream to read the JSON value from + _ASYNCRTIMP static value __cdecl parse(std::istream& stream); + + /// + /// Parses a JSON value from the contents of a single-byte (UTF8) stream. + /// + /// The stream to read the JSON value from + /// If parsing fails, the error code is greater than 0 + /// The parsed object. Returns web::json::value::null if failed + _ASYNCRTIMP static value __cdecl parse(std::istream& stream, std::error_code& error); + + /// + /// Serializes the content of the value into a single-byte (UTF8) stream. + /// + /// The stream that the JSON string representation should be written to. + _ASYNCRTIMP void serialize(std::ostream& stream) const; #endif - /// - /// Converts the JSON value to a C++ double, if and only if it is a number value. - /// Throws if the value is not a number - /// - /// A double representation of the value - _ASYNCRTIMP double as_double() const; - - /// - /// Converts the JSON value to a C++ integer, if and only if it is a number value. - /// Throws if the value is not a number - /// - /// An integer representation of the value - _ASYNCRTIMP int as_integer() const; - - /// - /// Converts the JSON value to a number class, if and only if it is a number value. - /// Throws if the value is not a number - /// - /// An instance of number class - _ASYNCRTIMP const json::number& as_number() const; - - /// - /// Converts the JSON value to a C++ bool, if and only if it is a Boolean value. - /// - /// A C++ bool representation of the value - _ASYNCRTIMP bool as_bool() const; - - /// - /// Converts the JSON value to a json array, if and only if it is an array value. - /// - /// The returned json::array should have the same or shorter lifetime as this - /// An array representation of the value - _ASYNCRTIMP json::array& as_array(); - - /// - /// Converts the JSON value to a json array, if and only if it is an array value. - /// - /// The returned json::array should have the same or shorter lifetime as this - /// An array representation of the value - _ASYNCRTIMP const json::array& as_array() const; - - /// - /// Converts the JSON value to a json object, if and only if it is an object value. - /// - /// An object representation of the value - _ASYNCRTIMP json::object& as_object(); - - /// - /// Converts the JSON value to a json object, if and only if it is an object value. - /// - /// An object representation of the value - _ASYNCRTIMP const json::object& as_object() const; - - /// - /// Converts the JSON value to a C++ STL string, if and only if it is a string value. - /// - /// A C++ STL string representation of the value - _ASYNCRTIMP const utility::string_t& as_string() const; - - /// - /// Compares two JSON values for equality. - /// - /// The JSON value to compare with. - /// True if the values are equal. - _ASYNCRTIMP bool operator==(const value& other) const; - - /// - /// Compares two JSON values for inequality. - /// - /// The JSON value to compare with. - /// True if the values are unequal. - bool operator!=(const value& other) const - { - return !((*this) == other); - } + /// + /// Converts the JSON value to a C++ double, if and only if it is a number value. + /// Throws if the value is not a number + /// + /// A double representation of the value + _ASYNCRTIMP double as_double() const; + + /// + /// Converts the JSON value to a C++ integer, if and only if it is a number value. + /// Throws if the value is not a number + /// + /// An integer representation of the value + _ASYNCRTIMP int as_integer() const; + + /// + /// Converts the JSON value to a number class, if and only if it is a number value. + /// Throws if the value is not a number + /// + /// An instance of number class + _ASYNCRTIMP const json::number& as_number() const; + + /// + /// Converts the JSON value to a C++ bool, if and only if it is a Boolean value. + /// + /// A C++ bool representation of the value + _ASYNCRTIMP bool as_bool() const; + + /// + /// Converts the JSON value to a json array, if and only if it is an array value. + /// + /// The returned json::array should have the same or shorter lifetime as this + /// An array representation of the value + _ASYNCRTIMP json::array& as_array(); + + /// + /// Converts the JSON value to a json array, if and only if it is an array value. + /// + /// The returned json::array should have the same or shorter lifetime as this + /// An array representation of the value + _ASYNCRTIMP const json::array& as_array() const; + + /// + /// Converts the JSON value to a json object, if and only if it is an object value. + /// + /// An object representation of the value + _ASYNCRTIMP json::object& as_object(); + + /// + /// Converts the JSON value to a json object, if and only if it is an object value. + /// + /// An object representation of the value + _ASYNCRTIMP const json::object& as_object() const; + + /// + /// Converts the JSON value to a C++ STL string, if and only if it is a string value. + /// + /// A C++ STL string representation of the value + _ASYNCRTIMP const utility::string_t& as_string() const; + + /// + /// Compares two JSON values for equality. + /// + /// The JSON value to compare with. + /// True if the values are equal. + _ASYNCRTIMP bool operator==(const value& other) const; + + /// + /// Compares two JSON values for inequality. + /// + /// The JSON value to compare with. + /// True if the values are unequal. + bool operator!=(const value& other) const { return !((*this) == other); } + + /// + /// Tests for the presence of a field. + /// + /// The name of the field + /// True if the field exists, false otherwise. + bool has_field(const utility::string_t& key) const; + + /// + /// Tests for the presence of a number field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_number_field(const utility::string_t& key) const; + + /// + /// Tests for the presence of an integer field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_integer_field(const utility::string_t& key) const; + + /// + /// Tests for the presence of a double field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_double_field(const utility::string_t& key) const; + + /// + /// Tests for the presence of a boolean field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_boolean_field(const utility::string_t& key) const; + + /// + /// Tests for the presence of a string field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_string_field(const utility::string_t& key) const; + + /// + /// Tests for the presence of an array field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_array_field(const utility::string_t& key) const; + + /// + /// Tests for the presence of an object field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_object_field(const utility::string_t& key) const; + + /// + /// Accesses a field of a JSON object. + /// + /// The name of the field + /// The value kept in the field; null if the field does not exist + CASABLANCA_DEPRECATED( + "This API is deprecated and will be removed in a future release, use json::value::at() instead.") + value get(const utility::string_t& key) const; + + /// + /// Erases an element of a JSON array. Throws if index is out of bounds. + /// + /// The index of the element to erase in the JSON array. + _ASYNCRTIMP void erase(size_t index); + + /// + /// Erases an element of a JSON object. Throws if the key doesn't exist. + /// + /// The key of the element to erase in the JSON object. + _ASYNCRTIMP void erase(const utility::string_t& key); + + /// + /// Accesses an element of a JSON array. Throws when index out of bounds. + /// + /// The index of an element in the JSON array. + /// A reference to the value. + _ASYNCRTIMP json::value& at(size_t index); + + /// + /// Accesses an element of a JSON array. Throws when index out of bounds. + /// + /// The index of an element in the JSON array. + /// A reference to the value. + _ASYNCRTIMP const json::value& at(size_t index) const; + + /// + /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value. + _ASYNCRTIMP json::value& at(const utility::string_t& key); + + /// + /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value. + _ASYNCRTIMP const json::value& at(const utility::string_t& key) const; - /// - /// Tests for the presence of a field. - /// - /// The name of the field - /// True if the field exists, false otherwise. - bool has_field(const utility::string_t &key) const; - - /// - /// Tests for the presence of a number field - /// - /// The name of the field - /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_number_field(const utility::string_t &key) const; - - /// - /// Tests for the presence of an integer field - /// - /// The name of the field - /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_integer_field(const utility::string_t &key) const; - - /// - /// Tests for the presence of a double field - /// - /// The name of the field - /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_double_field(const utility::string_t &key) const; - - /// - /// Tests for the presence of a boolean field - /// - /// The name of the field - /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_boolean_field(const utility::string_t &key) const; - - /// - /// Tests for the presence of a string field - /// - /// The name of the field - /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_string_field(const utility::string_t &key) const; - - /// - /// Tests for the presence of an array field - /// - /// The name of the field - /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_array_field(const utility::string_t &key) const; - - /// - /// Tests for the presence of an object field - /// - /// The name of the field - /// True if the field exists, false otherwise. - _ASYNCRTIMP bool has_object_field(const utility::string_t &key) const; - - /// - /// Accesses a field of a JSON object. - /// - /// The name of the field - /// The value kept in the field; null if the field does not exist - CASABLANCA_DEPRECATED("This API is deprecated and will be removed in a future release, use json::value::at() instead.") - value get(const utility::string_t &key) const; - - /// - /// Erases an element of a JSON array. Throws if index is out of bounds. - /// - /// The index of the element to erase in the JSON array. - _ASYNCRTIMP void erase(size_t index); - - /// - /// Erases an element of a JSON object. Throws if the key doesn't exist. - /// - /// The key of the element to erase in the JSON object. - _ASYNCRTIMP void erase(const utility::string_t &key); - - /// - /// Accesses an element of a JSON array. Throws when index out of bounds. - /// - /// The index of an element in the JSON array. - /// A reference to the value. - _ASYNCRTIMP json::value& at(size_t index); - - /// - /// Accesses an element of a JSON array. Throws when index out of bounds. - /// - /// The index of an element in the JSON array. - /// A reference to the value. - _ASYNCRTIMP const json::value& at(size_t index) const; - - /// - /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. - /// - /// The key of an element in the JSON object. - /// If the key exists, a reference to the value. - _ASYNCRTIMP json::value& at(const utility::string_t& key); - - /// - /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. - /// - /// The key of an element in the JSON object. - /// If the key exists, a reference to the value. - _ASYNCRTIMP const json::value& at(const utility::string_t& key) const; - - /// - /// Accesses a field of a JSON object. - /// - /// The name of the field - /// A reference to the value kept in the field. - _ASYNCRTIMP value & operator [] (const utility::string_t &key); + /// + /// Accesses a field of a JSON object. + /// + /// The name of the field + /// A reference to the value kept in the field. + _ASYNCRTIMP value& operator[](const utility::string_t& key); #ifdef _WIN32 private: - // Only used internally by JSON parser - _ASYNCRTIMP value & operator [] (const std::string &key) - { - // JSON object stores its field map as a unordered_map of string_t, so this conversion is hard to avoid - return operator[](utility::conversions::to_string_t(key)); - } + // Only used internally by JSON parser + _ASYNCRTIMP value& operator[](const std::string& key) + { + // JSON object stores its field map as a unordered_map of string_t, so this conversion is hard to avoid + return operator[](utility::conversions::to_string_t(key)); + } + public: #endif - /// - /// Accesses an element of a JSON array. - /// - /// The index of an element in the JSON array - /// The value kept at the array index; null if outside the boundaries of the array - CASABLANCA_DEPRECATED("This API is deprecated and will be removed in a future release, use json::value::at() instead.") - value get(size_t index) const; - - /// - /// Accesses an element of a JSON array. - /// - /// The index of an element in the JSON array. - /// A reference to the value kept in the field. - _ASYNCRTIMP value & operator [] (size_t index); - - private: - friend class web::json::details::_Object; - friend class web::json::details::_Array; - template friend class web::json::details::JSON_Parser; + /// + /// Accesses an element of a JSON array. + /// + /// The index of an element in the JSON array + /// The value kept at the array index; null if outside the boundaries of the array + CASABLANCA_DEPRECATED( + "This API is deprecated and will be removed in a future release, use json::value::at() instead.") + value get(size_t index) const; + + /// + /// Accesses an element of a JSON array. + /// + /// The index of an element in the JSON array. + /// A reference to the value kept in the field. + _ASYNCRTIMP value& operator[](size_t index); + +private: + friend class web::json::details::_Object; + friend class web::json::details::_Array; + template + friend class web::json::details::JSON_Parser; #ifdef _WIN32 - /// - /// Writes the current JSON value as a double-byte string to a string instance. - /// - /// The string that the JSON representation should be written to. - _ASYNCRTIMP void format(std::basic_string &string) const; + /// + /// Writes the current JSON value as a double-byte string to a string instance. + /// + /// The string that the JSON representation should be written to. + _ASYNCRTIMP void format(std::basic_string& string) const; #endif - /// - /// Serializes the content of the value into a string instance in UTF8 format - /// - /// The string that the JSON representation should be written to - _ASYNCRTIMP void format(std::basic_string& string) const; + /// + /// Serializes the content of the value into a string instance in UTF8 format + /// + /// The string that the JSON representation should be written to + _ASYNCRTIMP void format(std::basic_string& string) const; #ifdef ENABLE_JSON_VALUE_VISUALIZER - explicit value(std::unique_ptr v, value_type kind) : m_value(std::move(v)), m_kind(kind) + explicit value(std::unique_ptr v, value_type kind) : m_value(std::move(v)), m_kind(kind) #else - explicit value(std::unique_ptr v) : m_value(std::move(v)) + explicit value(std::unique_ptr v) : m_value(std::move(v)) #endif - {} + { + } - std::unique_ptr m_value; + std::unique_ptr m_value; #ifdef ENABLE_JSON_VALUE_VISUALIZER - value_type m_kind; + value_type m_kind; #endif - }; +}; - /// - /// A single exception type to represent errors in parsing, converting, and accessing - /// elements of JSON values. - /// - class json_exception : public std::exception - { - private: - std::string _message; - public: - json_exception(const char * const message) : _message(message) { } +/// +/// A single exception type to represent errors in parsing, converting, and accessing +/// elements of JSON values. +/// +class json_exception : public std::exception +{ +private: + std::string _message; + +public: + json_exception(const char* const message) : _message(message) {} #ifdef _UTF16_STRINGS - json_exception(const wchar_t * const message) : _message(utility::conversions::utf16_to_utf8(message)) { } + json_exception(const wchar_t* const message) : _message(utility::conversions::utf16_to_utf8(message)) {} #endif // _UTF16_STRINGS - json_exception(std::string&& message) : _message(std::move(message)) { } + json_exception(std::string&& message) : _message(std::move(message)) {} - // Must be narrow string because it derives from std::exception - const char* what() const CPPREST_NOEXCEPT - { - return _message.c_str(); - } - }; + // Must be narrow string because it derives from std::exception + const char* what() const CPPREST_NOEXCEPT { return _message.c_str(); } +}; + +namespace details +{ +enum json_error +{ + left_over_character_in_stream = 1, + malformed_array_literal, + malformed_comment, + malformed_literal, + malformed_object_literal, + malformed_numeric_literal, + malformed_string_literal, + malformed_token, + mismatched_brances, + nesting, + unexpected_token +}; + +class json_error_category_impl : public std::error_category +{ +public: + virtual const char* name() const CPPREST_NOEXCEPT override { return "json"; } - namespace details + virtual std::string message(int ev) const override { - enum json_error - { - left_over_character_in_stream = 1, - malformed_array_literal, - malformed_comment, - malformed_literal, - malformed_object_literal, - malformed_numeric_literal, - malformed_string_literal, - malformed_token, - mismatched_brances, - nesting, - unexpected_token - }; - - class json_error_category_impl : public std::error_category - { - public: - virtual const char* name() const CPPREST_NOEXCEPT override - { - return "json"; - } + switch (ev) + { + case json_error::left_over_character_in_stream: + return "Left-over characters in stream after parsing a JSON value"; + case json_error::malformed_array_literal: return "Malformed array literal"; + case json_error::malformed_comment: return "Malformed comment"; + case json_error::malformed_literal: return "Malformed literal"; + case json_error::malformed_object_literal: return "Malformed object literal"; + case json_error::malformed_numeric_literal: return "Malformed numeric literal"; + case json_error::malformed_string_literal: return "Malformed string literal"; + case json_error::malformed_token: return "Malformed token"; + case json_error::mismatched_brances: return "Mismatched braces"; + case json_error::nesting: return "Nesting too deep"; + case json_error::unexpected_token: return "Unexpected token"; + default: return "Unknown json error"; + } + } +}; - virtual std::string message(int ev) const override - { - switch (ev) - { - case json_error::left_over_character_in_stream: - return "Left-over characters in stream after parsing a JSON value"; - case json_error::malformed_array_literal: - return "Malformed array literal"; - case json_error::malformed_comment: - return "Malformed comment"; - case json_error::malformed_literal: - return "Malformed literal"; - case json_error::malformed_object_literal: - return "Malformed object literal"; - case json_error::malformed_numeric_literal: - return "Malformed numeric literal"; - case json_error::malformed_string_literal: - return "Malformed string literal"; - case json_error::malformed_token: - return "Malformed token"; - case json_error::mismatched_brances: - return "Mismatched braces"; - case json_error::nesting: - return "Nesting too deep"; - case json_error::unexpected_token: - return "Unexpected token"; - default: - return "Unknown json error"; - } - } - }; +const json_error_category_impl& json_error_category(); +} // namespace details - const json_error_category_impl& json_error_category(); - } +/// +/// A JSON array represented as a C++ class. +/// +class array +{ + typedef std::vector storage_type; + +public: + typedef storage_type::iterator iterator; + typedef storage_type::const_iterator const_iterator; + typedef storage_type::reverse_iterator reverse_iterator; + typedef storage_type::const_reverse_iterator const_reverse_iterator; + typedef storage_type::size_type size_type; + +private: + array() : m_elements() {} + array(size_type size) : m_elements(size) {} + array(storage_type elements) : m_elements(std::move(elements)) {} +public: /// - /// A JSON array represented as a C++ class. + /// Gets the beginning iterator element of the array /// - class array - { - typedef std::vector storage_type; - - public: - typedef storage_type::iterator iterator; - typedef storage_type::const_iterator const_iterator; - typedef storage_type::reverse_iterator reverse_iterator; - typedef storage_type::const_reverse_iterator const_reverse_iterator; - typedef storage_type::size_type size_type; - - private: - array() : m_elements() { } - array(size_type size) : m_elements(size) { } - array(storage_type elements) : m_elements(std::move(elements)) { } - - public: - /// - /// Gets the beginning iterator element of the array - /// - /// An iterator to the beginning of the JSON array. - iterator begin() - { - return m_elements.begin(); - } + /// An iterator to the beginning of the JSON array. + iterator begin() { return m_elements.begin(); } - /// - /// Gets the beginning const iterator element of the array. - /// - /// A const_iterator to the beginning of the JSON array. - const_iterator begin() const - { - return m_elements.cbegin(); - } + /// + /// Gets the beginning const iterator element of the array. + /// + /// A const_iterator to the beginning of the JSON array. + const_iterator begin() const { return m_elements.cbegin(); } - /// - /// Gets the end iterator element of the array - /// - /// An iterator to the end of the JSON array. - iterator end() - { - return m_elements.end(); - } + /// + /// Gets the end iterator element of the array + /// + /// An iterator to the end of the JSON array. + iterator end() { return m_elements.end(); } - /// - /// Gets the end const iterator element of the array. - /// - /// A const_iterator to the end of the JSON array. - const_iterator end() const - { - return m_elements.cend(); - } + /// + /// Gets the end const iterator element of the array. + /// + /// A const_iterator to the end of the JSON array. + const_iterator end() const { return m_elements.cend(); } - /// - /// Gets the beginning reverse iterator element of the array - /// - /// An reverse_iterator to the beginning of the JSON array. - reverse_iterator rbegin() - { - return m_elements.rbegin(); - } + /// + /// Gets the beginning reverse iterator element of the array + /// + /// An reverse_iterator to the beginning of the JSON array. + reverse_iterator rbegin() { return m_elements.rbegin(); } - /// - /// Gets the beginning const reverse iterator element of the array - /// - /// An const_reverse_iterator to the beginning of the JSON array. - const_reverse_iterator rbegin() const - { - return m_elements.rbegin(); - } + /// + /// Gets the beginning const reverse iterator element of the array + /// + /// An const_reverse_iterator to the beginning of the JSON array. + const_reverse_iterator rbegin() const { return m_elements.rbegin(); } - /// - /// Gets the end reverse iterator element of the array - /// - /// An reverse_iterator to the end of the JSON array. - reverse_iterator rend() - { - return m_elements.rend(); - } + /// + /// Gets the end reverse iterator element of the array + /// + /// An reverse_iterator to the end of the JSON array. + reverse_iterator rend() { return m_elements.rend(); } - /// - /// Gets the end const reverse iterator element of the array - /// - /// An const_reverse_iterator to the end of the JSON array. - const_reverse_iterator rend() const - { - return m_elements.crend(); - } + /// + /// Gets the end const reverse iterator element of the array + /// + /// An const_reverse_iterator to the end of the JSON array. + const_reverse_iterator rend() const { return m_elements.crend(); } - /// - /// Gets the beginning const iterator element of the array. - /// - /// A const_iterator to the beginning of the JSON array. - const_iterator cbegin() const - { - return m_elements.cbegin(); - } + /// + /// Gets the beginning const iterator element of the array. + /// + /// A const_iterator to the beginning of the JSON array. + const_iterator cbegin() const { return m_elements.cbegin(); } - /// - /// Gets the end const iterator element of the array. - /// - /// A const_iterator to the end of the JSON array. - const_iterator cend() const - { - return m_elements.cend(); - } + /// + /// Gets the end const iterator element of the array. + /// + /// A const_iterator to the end of the JSON array. + const_iterator cend() const { return m_elements.cend(); } - /// - /// Gets the beginning const reverse iterator element of the array. - /// - /// A const_reverse_iterator to the beginning of the JSON array. - const_reverse_iterator crbegin() const - { - return m_elements.crbegin(); - } + /// + /// Gets the beginning const reverse iterator element of the array. + /// + /// A const_reverse_iterator to the beginning of the JSON array. + const_reverse_iterator crbegin() const { return m_elements.crbegin(); } - /// - /// Gets the end const reverse iterator element of the array. - /// - /// A const_reverse_iterator to the end of the JSON array. - const_reverse_iterator crend() const - { - return m_elements.crend(); - } + /// + /// Gets the end const reverse iterator element of the array. + /// + /// A const_reverse_iterator to the end of the JSON array. + const_reverse_iterator crend() const { return m_elements.crend(); } - /// - /// Deletes an element of the JSON array. - /// - /// A const_iterator to the element to delete. - /// Iterator to the new location of the element following the erased element. - /// GCC doesn't support erase with const_iterator on vector yet. In the future this should be changed. - iterator erase(iterator position) - { - return m_elements.erase(position); - } + /// + /// Deletes an element of the JSON array. + /// + /// A const_iterator to the element to delete. + /// Iterator to the new location of the element following the erased element. + /// GCC doesn't support erase with const_iterator on vector yet. In the future this should be + /// changed. + iterator erase(iterator position) { return m_elements.erase(position); } - /// - /// Deletes the element at an index of the JSON array. - /// - /// The index of the element to delete. - void erase(size_type index) + /// + /// Deletes the element at an index of the JSON array. + /// + /// The index of the element to delete. + void erase(size_type index) + { + if (index >= m_elements.size()) { - if (index >= m_elements.size()) - { - throw json_exception("index out of bounds"); - } - m_elements.erase(m_elements.begin() + index); + throw json_exception("index out of bounds"); } + m_elements.erase(m_elements.begin() + index); + } - /// - /// Accesses an element of a JSON array. Throws when index out of bounds. - /// - /// The index of an element in the JSON array. - /// A reference to the value kept in the field. - json::value& at(size_type index) - { - if (index >= m_elements.size()) - throw json_exception("index out of bounds"); + /// + /// Accesses an element of a JSON array. Throws when index out of bounds. + /// + /// The index of an element in the JSON array. + /// A reference to the value kept in the field. + json::value& at(size_type index) + { + if (index >= m_elements.size()) throw json_exception("index out of bounds"); - return m_elements[index]; - } + return m_elements[index]; + } - /// - /// Accesses an element of a JSON array. Throws when index out of bounds. - /// - /// The index of an element in the JSON array. - /// A reference to the value kept in the field. - const json::value& at(size_type index) const - { - if (index >= m_elements.size()) - throw json_exception("index out of bounds"); + /// + /// Accesses an element of a JSON array. Throws when index out of bounds. + /// + /// The index of an element in the JSON array. + /// A reference to the value kept in the field. + const json::value& at(size_type index) const + { + if (index >= m_elements.size()) throw json_exception("index out of bounds"); - return m_elements[index]; - } + return m_elements[index]; + } - /// - /// Accesses an element of a JSON array. - /// - /// The index of an element in the JSON array. - /// A reference to the value kept in the field. - json::value& operator[](size_type index) - { - msl::safeint3::SafeInt nMinSize(index); - nMinSize += 1; - msl::safeint3::SafeInt nlastSize(m_elements.size()); - if (nlastSize < nMinSize) - m_elements.resize(nMinSize); + /// + /// Accesses an element of a JSON array. + /// + /// The index of an element in the JSON array. + /// A reference to the value kept in the field. + json::value& operator[](size_type index) + { + msl::safeint3::SafeInt nMinSize(index); + nMinSize += 1; + msl::safeint3::SafeInt nlastSize(m_elements.size()); + if (nlastSize < nMinSize) m_elements.resize(nMinSize); - return m_elements[index]; - } + return m_elements[index]; + } + + /// + /// Gets the number of elements of the array. + /// + /// The number of elements. + size_type size() const { return m_elements.size(); } - /// - /// Gets the number of elements of the array. - /// - /// The number of elements. - size_type size() const +private: + storage_type m_elements; + + friend class details::_Array; + template + friend class json::details::JSON_Parser; +}; + +/// +/// A JSON object represented as a C++ class. +/// +class object +{ + typedef std::vector> storage_type; + +public: + typedef storage_type::iterator iterator; + typedef storage_type::const_iterator const_iterator; + typedef storage_type::reverse_iterator reverse_iterator; + typedef storage_type::const_reverse_iterator const_reverse_iterator; + typedef storage_type::size_type size_type; + +private: + object(bool keep_order = false) : m_elements(), m_keep_order(keep_order) {} + object(storage_type elements, bool keep_order = false) : m_elements(std::move(elements)), m_keep_order(keep_order) + { + if (!keep_order) { - return m_elements.size(); + sort(m_elements.begin(), m_elements.end(), compare_pairs); } + } - private: - storage_type m_elements; +public: + /// + /// Gets the beginning iterator element of the object + /// + /// An iterator to the beginning of the JSON object. + iterator begin() { return m_elements.begin(); } - friend class details::_Array; - template friend class json::details::JSON_Parser; - }; + /// + /// Gets the beginning const iterator element of the object. + /// + /// A const_iterator to the beginning of the JSON object. + const_iterator begin() const { return m_elements.cbegin(); } /// - /// A JSON object represented as a C++ class. + /// Gets the end iterator element of the object /// - class object - { - typedef std::vector> storage_type; - - public: - typedef storage_type::iterator iterator; - typedef storage_type::const_iterator const_iterator; - typedef storage_type::reverse_iterator reverse_iterator; - typedef storage_type::const_reverse_iterator const_reverse_iterator; - typedef storage_type::size_type size_type; - - private: - object(bool keep_order = false) : m_elements(), m_keep_order(keep_order) { } - object(storage_type elements, bool keep_order = false) : m_elements(std::move(elements)), m_keep_order(keep_order) - { - if (!keep_order) { - sort(m_elements.begin(), m_elements.end(), compare_pairs); - } - } + /// An iterator to the end of the JSON object. + iterator end() { return m_elements.end(); } - public: - /// - /// Gets the beginning iterator element of the object - /// - /// An iterator to the beginning of the JSON object. - iterator begin() - { - return m_elements.begin(); - } + /// + /// Gets the end const iterator element of the object. + /// + /// A const_iterator to the end of the JSON object. + const_iterator end() const { return m_elements.cend(); } - /// - /// Gets the beginning const iterator element of the object. - /// - /// A const_iterator to the beginning of the JSON object. - const_iterator begin() const - { - return m_elements.cbegin(); - } + /// + /// Gets the beginning reverse iterator element of the object + /// + /// An reverse_iterator to the beginning of the JSON object. + reverse_iterator rbegin() { return m_elements.rbegin(); } - /// - /// Gets the end iterator element of the object - /// - /// An iterator to the end of the JSON object. - iterator end() - { - return m_elements.end(); - } + /// + /// Gets the beginning const reverse iterator element of the object + /// + /// An const_reverse_iterator to the beginning of the JSON object. + const_reverse_iterator rbegin() const { return m_elements.rbegin(); } - /// - /// Gets the end const iterator element of the object. - /// - /// A const_iterator to the end of the JSON object. - const_iterator end() const - { - return m_elements.cend(); - } + /// + /// Gets the end reverse iterator element of the object + /// + /// An reverse_iterator to the end of the JSON object. + reverse_iterator rend() { return m_elements.rend(); } - /// - /// Gets the beginning reverse iterator element of the object - /// - /// An reverse_iterator to the beginning of the JSON object. - reverse_iterator rbegin() - { - return m_elements.rbegin(); - } + /// + /// Gets the end const reverse iterator element of the object + /// + /// An const_reverse_iterator to the end of the JSON object. + const_reverse_iterator rend() const { return m_elements.crend(); } - /// - /// Gets the beginning const reverse iterator element of the object - /// - /// An const_reverse_iterator to the beginning of the JSON object. - const_reverse_iterator rbegin() const - { - return m_elements.rbegin(); - } + /// + /// Gets the beginning const iterator element of the object. + /// + /// A const_iterator to the beginning of the JSON object. + const_iterator cbegin() const { return m_elements.cbegin(); } - /// - /// Gets the end reverse iterator element of the object - /// - /// An reverse_iterator to the end of the JSON object. - reverse_iterator rend() - { - return m_elements.rend(); - } + /// + /// Gets the end const iterator element of the object. + /// + /// A const_iterator to the end of the JSON object. + const_iterator cend() const { return m_elements.cend(); } - /// - /// Gets the end const reverse iterator element of the object - /// - /// An const_reverse_iterator to the end of the JSON object. - const_reverse_iterator rend() const - { - return m_elements.crend(); - } + /// + /// Gets the beginning const reverse iterator element of the object. + /// + /// A const_reverse_iterator to the beginning of the JSON object. + const_reverse_iterator crbegin() const { return m_elements.crbegin(); } - /// - /// Gets the beginning const iterator element of the object. - /// - /// A const_iterator to the beginning of the JSON object. - const_iterator cbegin() const - { - return m_elements.cbegin(); - } + /// + /// Gets the end const reverse iterator element of the object. + /// + /// A const_reverse_iterator to the end of the JSON object. + const_reverse_iterator crend() const { return m_elements.crend(); } - /// - /// Gets the end const iterator element of the object. - /// - /// A const_iterator to the end of the JSON object. - const_iterator cend() const - { - return m_elements.cend(); - } + /// + /// Deletes an element of the JSON object. + /// + /// A const_iterator to the element to delete. + /// Iterator to the new location of the element following the erased element. + /// GCC doesn't support erase with const_iterator on vector yet. In the future this should be + /// changed. + iterator erase(iterator position) { return m_elements.erase(position); } - /// - /// Gets the beginning const reverse iterator element of the object. - /// - /// A const_reverse_iterator to the beginning of the JSON object. - const_reverse_iterator crbegin() const + /// + /// Deletes an element of the JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + void erase(const utility::string_t& key) + { + auto iter = find_by_key(key); + if (iter == m_elements.end()) { - return m_elements.crbegin(); + throw web::json::json_exception("Key not found"); } - /// - /// Gets the end const reverse iterator element of the object. - /// - /// A const_reverse_iterator to the end of the JSON object. - const_reverse_iterator crend() const - { - return m_elements.crend(); - } + m_elements.erase(iter); + } - /// - /// Deletes an element of the JSON object. - /// - /// A const_iterator to the element to delete. - /// Iterator to the new location of the element following the erased element. - /// GCC doesn't support erase with const_iterator on vector yet. In the future this should be changed. - iterator erase(iterator position) + /// + /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value kept in the field. + json::value& at(const utility::string_t& key) + { + auto iter = find_by_key(key); + if (iter == m_elements.end()) { - return m_elements.erase(position); + throw web::json::json_exception("Key not found"); } - /// - /// Deletes an element of the JSON object. If the key doesn't exist, this method throws. - /// - /// The key of an element in the JSON object. - void erase(const utility::string_t &key) - { - auto iter = find_by_key(key); - if (iter == m_elements.end()) - { - throw web::json::json_exception("Key not found"); - } - - m_elements.erase(iter); - } + return iter->second; + } - /// - /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. - /// - /// The key of an element in the JSON object. - /// If the key exists, a reference to the value kept in the field. - json::value& at(const utility::string_t& key) + /// + /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value kept in the field. + const json::value& at(const utility::string_t& key) const + { + auto iter = find_by_key(key); + if (iter == m_elements.end()) { - auto iter = find_by_key(key); - if (iter == m_elements.end()) - { - throw web::json::json_exception("Key not found"); - } - - return iter->second; + throw web::json::json_exception("Key not found"); } - /// - /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. - /// - /// The key of an element in the JSON object. - /// If the key exists, a reference to the value kept in the field. - const json::value& at(const utility::string_t& key) const - { - auto iter = find_by_key(key); - if (iter == m_elements.end()) - { - throw web::json::json_exception("Key not found"); - } + return iter->second; + } - return iter->second; - } + /// + /// Accesses an element of a JSON object. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value kept in the field, otherwise a newly created null value + /// that will be stored for the given key. + json::value& operator[](const utility::string_t& key) + { + auto iter = find_insert_location(key); - /// - /// Accesses an element of a JSON object. - /// - /// The key of an element in the JSON object. - /// If the key exists, a reference to the value kept in the field, otherwise a newly created null value that will be stored for the given key. - json::value& operator[](const utility::string_t& key) + if (iter == m_elements.end() || key != iter->first) { - auto iter = find_insert_location(key); + return m_elements.insert(iter, std::pair(key, value()))->second; + } - if (iter == m_elements.end() || key != iter->first) - { - return m_elements.insert(iter, std::pair(key, value()))->second; - } + return iter->second; + } - return iter->second; - } + /// + /// Gets an iterator to an element of a JSON object. + /// + /// The key of an element in the JSON object. + /// A const iterator to the value kept in the field. + const_iterator find(const utility::string_t& key) const { return find_by_key(key); } - /// - /// Gets an iterator to an element of a JSON object. - /// - /// The key of an element in the JSON object. - /// A const iterator to the value kept in the field. - const_iterator find(const utility::string_t& key) const - { - return find_by_key(key); - } + /// + /// Gets the number of elements of the object. + /// + /// The number of elements. + size_type size() const { return m_elements.size(); } - /// - /// Gets the number of elements of the object. - /// - /// The number of elements. - size_type size() const - { - return m_elements.size(); - } + /// + /// Checks if there are any elements in the JSON object. + /// + /// True if empty. + bool empty() const { return m_elements.empty(); } - /// - /// Checks if there are any elements in the JSON object. - /// - /// True if empty. - bool empty() const - { - return m_elements.empty(); - } - private: +private: + static bool compare_pairs(const std::pair& p1, + const std::pair& p2) + { + return p1.first < p2.first; + } + static bool compare_with_key(const std::pair& p1, const utility::string_t& key) + { + return p1.first < key; + } - static bool compare_pairs(const std::pair& p1, const std::pair& p2) - { - return p1.first < p2.first; - } - static bool compare_with_key(const std::pair& p1, const utility::string_t& key) + storage_type::iterator find_insert_location(const utility::string_t& key) + { + if (m_keep_order) { - return p1.first < key; + return std::find_if(m_elements.begin(), + m_elements.end(), + [&key](const std::pair& p) { return p.first == key; }); } - - storage_type::iterator find_insert_location(const utility::string_t &key) + else { - if (m_keep_order) - { - return std::find_if(m_elements.begin(), m_elements.end(), - [&key](const std::pair& p) { - return p.first == key; - }); - } - else - { - return std::lower_bound(m_elements.begin(), m_elements.end(), key, compare_with_key); - } + return std::lower_bound(m_elements.begin(), m_elements.end(), key, compare_with_key); } + } - storage_type::const_iterator find_by_key(const utility::string_t& key) const + storage_type::const_iterator find_by_key(const utility::string_t& key) const + { + if (m_keep_order) { - if (m_keep_order) - { - return std::find_if(m_elements.begin(), m_elements.end(), - [&key](const std::pair& p) { - return p.first == key; - }); - } - else - { - auto iter = std::lower_bound(m_elements.begin(), m_elements.end(), key, compare_with_key); - if (iter != m_elements.end() && key != iter->first) - { - return m_elements.end(); - } - return iter; - } + return std::find_if(m_elements.begin(), + m_elements.end(), + [&key](const std::pair& p) { return p.first == key; }); } - - storage_type::iterator find_by_key(const utility::string_t& key) + else { - auto iter = find_insert_location(key); + auto iter = std::lower_bound(m_elements.begin(), m_elements.end(), key, compare_with_key); if (iter != m_elements.end() && key != iter->first) { return m_elements.end(); } return iter; } + } + + storage_type::iterator find_by_key(const utility::string_t& key) + { + auto iter = find_insert_location(key); + if (iter != m_elements.end() && key != iter->first) + { + return m_elements.end(); + } + return iter; + } - storage_type m_elements; - bool m_keep_order; - friend class details::_Object; + storage_type m_elements; + bool m_keep_order; + friend class details::_Object; - template friend class json::details::JSON_Parser; - }; + template + friend class json::details::JSON_Parser; +}; +/// +/// A JSON number represented as a C++ class. +/// +class number +{ + // Note that these constructors make sure that only negative integers are stored as signed int64 (while others + // convert to unsigned int64). This helps handling number objects e.g. comparing two numbers. + + number(double value) : m_value(value), m_type(double_type) {} + number(int32_t value) : m_intval(value), m_type(value < 0 ? signed_type : unsigned_type) {} + number(uint32_t value) : m_intval(value), m_type(unsigned_type) {} + number(int64_t value) : m_intval(value), m_type(value < 0 ? signed_type : unsigned_type) {} + number(uint64_t value) : m_uintval(value), m_type(unsigned_type) {} + +public: /// - /// A JSON number represented as a C++ class. + /// Does the number fit into int32? /// - class number - { - // Note that these constructors make sure that only negative integers are stored as signed int64 (while others convert to unsigned int64). - // This helps handling number objects e.g. comparing two numbers. - - number(double value) : m_value(value), m_type(double_type) { } - number(int32_t value) : m_intval(value), m_type(value < 0 ? signed_type : unsigned_type) { } - number(uint32_t value) : m_intval(value), m_type(unsigned_type) { } - number(int64_t value) : m_intval(value), m_type(value < 0 ? signed_type : unsigned_type) { } - number(uint64_t value) : m_uintval(value), m_type(unsigned_type) { } - - public: - - /// - /// Does the number fit into int32? - /// - /// true if the number fits into int32, false otherwise - _ASYNCRTIMP bool is_int32() const; - - /// - /// Does the number fit into unsigned int32? - /// - /// true if the number fits into unsigned int32, false otherwise - _ASYNCRTIMP bool is_uint32() const; - - /// - /// Does the number fit into int64? - /// - /// true if the number fits into int64, false otherwise - _ASYNCRTIMP bool is_int64() const; - - /// - /// Does the number fit into unsigned int64? - /// - /// true if the number fits into unsigned int64, false otherwise - bool is_uint64() const - { - switch (m_type) - { - case signed_type : return m_intval >= 0; - case unsigned_type : return true; - case double_type : - default : - return false; - } - } + /// true if the number fits into int32, false otherwise + _ASYNCRTIMP bool is_int32() const; - /// - /// Converts the JSON number to a C++ double. - /// - /// A double representation of the number - double to_double() const - { - switch (m_type) - { - case double_type : return m_value; - case signed_type : return static_cast(m_intval); - case unsigned_type : return static_cast(m_uintval); - default : return false; - } - } + /// + /// Does the number fit into unsigned int32? + /// + /// true if the number fits into unsigned int32, false otherwise + _ASYNCRTIMP bool is_uint32() const; - /// - /// Converts the JSON number to int32. - /// - /// An int32 representation of the number - int32_t to_int32() const - { - if (m_type == double_type) - return static_cast(m_value); - else - return static_cast(m_intval); - } + /// + /// Does the number fit into int64? + /// + /// true if the number fits into int64, false otherwise + _ASYNCRTIMP bool is_int64() const; - /// - /// Converts the JSON number to unsigned int32. - /// - /// An unsigned int32 representation of the number - uint32_t to_uint32() const + /// + /// Does the number fit into unsigned int64? + /// + /// true if the number fits into unsigned int64, false otherwise + bool is_uint64() const + { + switch (m_type) { - if (m_type == double_type) - return static_cast(m_value); - else - return static_cast(m_intval); + case signed_type: return m_intval >= 0; + case unsigned_type: return true; + case double_type: + default: return false; } + } - /// - /// Converts the JSON number to int64. - /// - /// An int64 representation of the number - int64_t to_int64() const + /// + /// Converts the JSON number to a C++ double. + /// + /// A double representation of the number + double to_double() const + { + switch (m_type) { - if (m_type == double_type) - return static_cast(m_value); - else - return static_cast(m_intval); + case double_type: return m_value; + case signed_type: return static_cast(m_intval); + case unsigned_type: return static_cast(m_uintval); + default: return false; } + } - /// - /// Converts the JSON number to unsigned int64. - /// - /// An unsigned int64 representation of the number - uint64_t to_uint64() const - { - if (m_type == double_type) - return static_cast(m_value); - else - return static_cast(m_intval); - } + /// + /// Converts the JSON number to int32. + /// + /// An int32 representation of the number + int32_t to_int32() const + { + if (m_type == double_type) + return static_cast(m_value); + else + return static_cast(m_intval); + } - /// - /// Is the number represented internally as an integral type? - /// - /// true if the number is represented as an integral type, false otherwise - bool is_integral() const - { - return m_type != double_type; - } + /// + /// Converts the JSON number to unsigned int32. + /// + /// An unsigned int32 representation of the number + uint32_t to_uint32() const + { + if (m_type == double_type) + return static_cast(m_value); + else + return static_cast(m_intval); + } - /// - /// Compares two JSON numbers for equality. - /// - /// The JSON number to compare with. - /// True if the numbers are equal. - bool operator==(const number &other) const - { - if (m_type != other.m_type) - return false; + /// + /// Converts the JSON number to int64. + /// + /// An int64 representation of the number + int64_t to_int64() const + { + if (m_type == double_type) + return static_cast(m_value); + else + return static_cast(m_intval); + } - switch (m_type) - { - case json::number::type::signed_type : - return m_intval == other.m_intval; - case json::number::type::unsigned_type : - return m_uintval == other.m_uintval; - case json::number::type::double_type : - return m_value == other.m_value; - } - __assume(0); - // Absence of this return statement provokes a warning from Intel - // compiler, but its presence results in a warning from MSVC, so - // we have to resort to conditional compilation to keep both happy. -#ifdef __INTEL_COMPILER - return false; -#endif - } + /// + /// Converts the JSON number to unsigned int64. + /// + /// An unsigned int64 representation of the number + uint64_t to_uint64() const + { + if (m_type == double_type) + return static_cast(m_value); + else + return static_cast(m_intval); + } - private: - union - { - int64_t m_intval; - uint64_t m_uintval; - double m_value; - }; + /// + /// Is the number represented internally as an integral type? + /// + /// true if the number is represented as an integral type, false otherwise + bool is_integral() const { return m_type != double_type; } - enum type + /// + /// Compares two JSON numbers for equality. + /// + /// The JSON number to compare with. + /// True if the numbers are equal. + bool operator==(const number& other) const + { + if (m_type != other.m_type) return false; + + switch (m_type) { - signed_type=0, unsigned_type, double_type - } m_type; + case json::number::type::signed_type: return m_intval == other.m_intval; + case json::number::type::unsigned_type: return m_uintval == other.m_uintval; + case json::number::type::double_type: return m_value == other.m_value; + } + __assume(0); + // Absence of this return statement provokes a warning from Intel + // compiler, but its presence results in a warning from MSVC, so + // we have to resort to conditional compilation to keep both happy. +#ifdef __INTEL_COMPILER + return false; +#endif + } - friend class details::_Number; +private: + union { + int64_t m_intval; + uint64_t m_uintval; + double m_value; }; - namespace details + enum type { - class _Value - { - public: - virtual std::unique_ptr<_Value> _copy_value() = 0; + signed_type = 0, + unsigned_type, + double_type + } m_type; - virtual bool has_field(const utility::string_t &) const { return false; } - virtual value get_field(const utility::string_t &) const { throw json_exception("not an object"); } - virtual value get_element(array::size_type) const { throw json_exception("not an array"); } + friend class details::_Number; +}; + +namespace details +{ +class _Value +{ +public: + virtual std::unique_ptr<_Value> _copy_value() = 0; - virtual value &index(const utility::string_t &) { throw json_exception("not an object"); } - virtual value &index(array::size_type) { throw json_exception("not an array"); } + virtual bool has_field(const utility::string_t&) const { return false; } + virtual value get_field(const utility::string_t&) const { throw json_exception("not an object"); } + virtual value get_element(array::size_type) const { throw json_exception("not an array"); } - virtual const value &cnst_index(const utility::string_t &) const { throw json_exception("not an object"); } - virtual const value &cnst_index(array::size_type) const { throw json_exception("not an array"); } + virtual value& index(const utility::string_t&) { throw json_exception("not an object"); } + virtual value& index(array::size_type) { throw json_exception("not an array"); } - // Common function used for serialization to strings and streams. - virtual void serialize_impl(std::string& str) const - { - format(str); - } + virtual const value& cnst_index(const utility::string_t&) const { throw json_exception("not an object"); } + virtual const value& cnst_index(array::size_type) const { throw json_exception("not an array"); } + + // Common function used for serialization to strings and streams. + virtual void serialize_impl(std::string& str) const { format(str); } #ifdef _WIN32 - virtual void serialize_impl(std::wstring& str) const - { - format(str); - } + virtual void serialize_impl(std::wstring& str) const { format(str); } #endif - virtual utility::string_t to_string() const - { - utility::string_t str; - serialize_impl(str); - return str; - } + virtual utility::string_t to_string() const + { + utility::string_t str; + serialize_impl(str); + return str; + } - virtual json::value::value_type type() const { return json::value::Null; } + virtual json::value::value_type type() const { return json::value::Null; } - virtual bool is_integer() const { throw json_exception("not a number"); } - virtual bool is_double() const { throw json_exception("not a number"); } + virtual bool is_integer() const { throw json_exception("not a number"); } + virtual bool is_double() const { throw json_exception("not a number"); } - virtual const json::number& as_number() { throw json_exception("not a number"); } - virtual double as_double() const { throw json_exception("not a number"); } - virtual int as_integer() const { throw json_exception("not a number"); } - virtual bool as_bool() const { throw json_exception("not a boolean"); } - virtual json::array& as_array() { throw json_exception("not an array"); } - virtual const json::array& as_array() const { throw json_exception("not an array"); } - virtual json::object& as_object() { throw json_exception("not an object"); } - virtual const json::object& as_object() const { throw json_exception("not an object"); } - virtual const utility::string_t& as_string() const { throw json_exception("not a string"); } + virtual const json::number& as_number() { throw json_exception("not a number"); } + virtual double as_double() const { throw json_exception("not a number"); } + virtual int as_integer() const { throw json_exception("not a number"); } + virtual bool as_bool() const { throw json_exception("not a boolean"); } + virtual json::array& as_array() { throw json_exception("not an array"); } + virtual const json::array& as_array() const { throw json_exception("not an array"); } + virtual json::object& as_object() { throw json_exception("not an object"); } + virtual const json::object& as_object() const { throw json_exception("not an object"); } + virtual const utility::string_t& as_string() const { throw json_exception("not a string"); } - virtual size_t size() const { return 0; } + virtual size_t size() const { return 0; } - virtual ~_Value() {} + virtual ~_Value() {} - protected: - _Value() {} +protected: + _Value() {} - virtual void format(std::basic_string& stream) const - { - stream.append("null"); - } + virtual void format(std::basic_string& stream) const { stream.append("null"); } #ifdef _WIN32 - virtual void format(std::basic_string& stream) const - { - stream.append(L"null"); - } + virtual void format(std::basic_string& stream) const { stream.append(L"null"); } #endif - private: +private: + friend class web::json::value; +}; - friend class web::json::value; - }; +class _Null : public _Value +{ +public: + virtual std::unique_ptr<_Value> _copy_value() { return utility::details::make_unique<_Null>(); } + virtual json::value::value_type type() const { return json::value::Null; } +}; - class _Null : public _Value - { - public: - virtual std::unique_ptr<_Value> _copy_value() - { - return utility::details::make_unique<_Null>(); - } - virtual json::value::value_type type() const { return json::value::Null; } - }; +class _Number : public _Value +{ +public: + _Number(double value) : m_number(value) {} + _Number(int32_t value) : m_number(value) {} + _Number(uint32_t value) : m_number(value) {} + _Number(int64_t value) : m_number(value) {} + _Number(uint64_t value) : m_number(value) {} - class _Number : public _Value - { - public: - _Number(double value) : m_number(value) { } - _Number(int32_t value) : m_number(value) { } - _Number(uint32_t value) : m_number(value) { } - _Number(int64_t value) : m_number(value) { } - _Number(uint64_t value) : m_number(value) { } - - virtual std::unique_ptr<_Value> _copy_value() - { - return utility::details::make_unique<_Number>(*this); - } + virtual std::unique_ptr<_Value> _copy_value() { return utility::details::make_unique<_Number>(*this); } - virtual json::value::value_type type() const { return json::value::Number; } + virtual json::value::value_type type() const { return json::value::Number; } - virtual bool is_integer() const { return m_number.is_integral(); } - virtual bool is_double() const { return !m_number.is_integral(); } + virtual bool is_integer() const { return m_number.is_integral(); } + virtual bool is_double() const { return !m_number.is_integral(); } - virtual double as_double() const - { - return m_number.to_double(); - } + virtual double as_double() const { return m_number.to_double(); } - virtual int as_integer() const - { - return m_number.to_int32(); - } + virtual int as_integer() const { return m_number.to_int32(); } - virtual const number& as_number() { return m_number; } + virtual const number& as_number() { return m_number; } - protected: - virtual void format(std::basic_string& stream) const ; +protected: + virtual void format(std::basic_string& stream) const; #ifdef _WIN32 - virtual void format(std::basic_string& stream) const; + virtual void format(std::basic_string& stream) const; #endif - private: - template friend class json::details::JSON_Parser; +private: + template + friend class json::details::JSON_Parser; - json::number m_number; - }; + json::number m_number; +}; - class _Boolean : public _Value - { - public: - _Boolean(bool value) : m_value(value) { } +class _Boolean : public _Value +{ +public: + _Boolean(bool value) : m_value(value) {} - virtual std::unique_ptr<_Value> _copy_value() - { - return utility::details::make_unique<_Boolean>(*this); - } + virtual std::unique_ptr<_Value> _copy_value() { return utility::details::make_unique<_Boolean>(*this); } - virtual json::value::value_type type() const { return json::value::Boolean; } + virtual json::value::value_type type() const { return json::value::Boolean; } - virtual bool as_bool() const { return m_value; } + virtual bool as_bool() const { return m_value; } - protected: - virtual void format(std::basic_string& stream) const - { - stream.append(m_value ? "true" : "false"); - } +protected: + virtual void format(std::basic_string& stream) const { stream.append(m_value ? "true" : "false"); } #ifdef _WIN32 - virtual void format(std::basic_string& stream) const - { - stream.append(m_value ? L"true" : L"false"); - } + virtual void format(std::basic_string& stream) const { stream.append(m_value ? L"true" : L"false"); } #endif - private: - template friend class json::details::JSON_Parser; - bool m_value; - }; - - class _String : public _Value - { - public: +private: + template + friend class json::details::JSON_Parser; + bool m_value; +}; - _String(utility::string_t value) : m_string(std::move(value)) - { - m_has_escape_char = has_escape_chars(*this); - } - _String(utility::string_t value, bool escaped_chars) - : m_string(std::move(value)), - m_has_escape_char(escaped_chars) - { } +class _String : public _Value +{ +public: + _String(utility::string_t value) : m_string(std::move(value)) { m_has_escape_char = has_escape_chars(*this); } + _String(utility::string_t value, bool escaped_chars) : m_string(std::move(value)), m_has_escape_char(escaped_chars) + { + } #ifdef _WIN32 - _String(std::string &&value) : m_string(utility::conversions::to_utf16string(std::move(value))) - { - m_has_escape_char = has_escape_chars(*this); - } - _String(std::string &&value, bool escape_chars) - : m_string(utility::conversions::to_utf16string(std::move(value))), - m_has_escape_char(escape_chars) - { } + _String(std::string&& value) : m_string(utility::conversions::to_utf16string(std::move(value))) + { + m_has_escape_char = has_escape_chars(*this); + } + _String(std::string&& value, bool escape_chars) + : m_string(utility::conversions::to_utf16string(std::move(value))), m_has_escape_char(escape_chars) + { + } #endif - virtual std::unique_ptr<_Value> _copy_value() - { - return utility::details::make_unique<_String>(*this); - } + virtual std::unique_ptr<_Value> _copy_value() { return utility::details::make_unique<_String>(*this); } - virtual json::value::value_type type() const { return json::value::String; } + virtual json::value::value_type type() const { return json::value::String; } - virtual const utility::string_t & as_string() const; + virtual const utility::string_t& as_string() const; - virtual void serialize_impl(std::string& str) const - { - serialize_impl_char_type(str); - } + virtual void serialize_impl(std::string& str) const { serialize_impl_char_type(str); } #ifdef _WIN32 - virtual void serialize_impl(std::wstring& str) const - { - serialize_impl_char_type(str); - } + virtual void serialize_impl(std::wstring& str) const { serialize_impl_char_type(str); } #endif - protected: - virtual void format(std::basic_string& str) const; +protected: + virtual void format(std::basic_string& str) const; #ifdef _WIN32 - virtual void format(std::basic_string& str) const; + virtual void format(std::basic_string& str) const; #endif - private: - friend class _Object; - friend class _Array; +private: + friend class _Object; + friend class _Array; - size_t get_reserve_size() const - { - return m_string.size() + 2; - } + size_t get_reserve_size() const { return m_string.size() + 2; } - template - void serialize_impl_char_type(std::basic_string& str) const - { - // To avoid repeated allocations reserve some space all up front. - // size of string + 2 for quotes - str.reserve(get_reserve_size()); - format(str); - } + template + void serialize_impl_char_type(std::basic_string& str) const + { + // To avoid repeated allocations reserve some space all up front. + // size of string + 2 for quotes + str.reserve(get_reserve_size()); + format(str); + } - std::string as_utf8_string() const; - utf16string as_utf16_string() const; + std::string as_utf8_string() const; + utf16string as_utf16_string() const; - utility::string_t m_string; + utility::string_t m_string; - // There are significant performance gains that can be made by knowing whether - // or not a character that requires escaping is present. - bool m_has_escape_char; - static bool has_escape_chars(const _String &str); - }; + // There are significant performance gains that can be made by knowing whether + // or not a character that requires escaping is present. + bool m_has_escape_char; + static bool has_escape_chars(const _String& str); +}; - template - _ASYNCRTIMP void append_escape_string(std::basic_string& str, const std::basic_string& escaped); +template +_ASYNCRTIMP void append_escape_string(std::basic_string& str, const std::basic_string& escaped); - void format_string(const utility::string_t& key, utility::string_t& str); +void format_string(const utility::string_t& key, utility::string_t& str); #ifdef _WIN32 - void format_string(const utility::string_t& key, std::string& str); +void format_string(const utility::string_t& key, std::string& str); #endif - class _Object : public _Value - { - public: - - _Object(bool keep_order) : m_object(keep_order) { } - _Object(object::storage_type fields, bool keep_order) : m_object(std::move(fields), keep_order) { } +class _Object : public _Value +{ +public: + _Object(bool keep_order) : m_object(keep_order) {} + _Object(object::storage_type fields, bool keep_order) : m_object(std::move(fields), keep_order) {} - virtual std::unique_ptr<_Value> _copy_value() - { - return utility::details::make_unique<_Object>(*this); - } + virtual std::unique_ptr<_Value> _copy_value() { return utility::details::make_unique<_Object>(*this); } - virtual json::object& as_object() { return m_object; } + virtual json::object& as_object() { return m_object; } - virtual const json::object& as_object() const { return m_object; } + virtual const json::object& as_object() const { return m_object; } - virtual json::value::value_type type() const { return json::value::Object; } + virtual json::value::value_type type() const { return json::value::Object; } - virtual bool has_field(const utility::string_t &) const; + virtual bool has_field(const utility::string_t&) const; - virtual json::value &index(const utility::string_t &key); + virtual json::value& index(const utility::string_t& key); - bool is_equal(const _Object* other) const - { - if (m_object.size() != other->m_object.size()) - return false; + bool is_equal(const _Object* other) const + { + if (m_object.size() != other->m_object.size()) return false; - return std::equal(std::begin(m_object), std::end(m_object), std::begin(other->m_object)); - } + return std::equal(std::begin(m_object), std::end(m_object), std::begin(other->m_object)); + } - virtual void serialize_impl(std::string& str) const - { - // To avoid repeated allocations reserve some space all up front. - str.reserve(get_reserve_size()); - format(str); - } + virtual void serialize_impl(std::string& str) const + { + // To avoid repeated allocations reserve some space all up front. + str.reserve(get_reserve_size()); + format(str); + } #ifdef _WIN32 - virtual void serialize_impl(std::wstring& str) const - { - // To avoid repeated allocations reserve some space all up front. - str.reserve(get_reserve_size()); - format(str); - } + virtual void serialize_impl(std::wstring& str) const + { + // To avoid repeated allocations reserve some space all up front. + str.reserve(get_reserve_size()); + format(str); + } #endif - size_t size() const { return m_object.size(); } + size_t size() const { return m_object.size(); } - protected: - virtual void format(std::basic_string& str) const - { - format_impl(str); - } +protected: + virtual void format(std::basic_string& str) const { format_impl(str); } #ifdef _WIN32 - virtual void format(std::basic_string& str) const - { - format_impl(str); - } + virtual void format(std::basic_string& str) const { format_impl(str); } #endif - private: - json::object m_object; +private: + json::object m_object; - template friend class json::details::JSON_Parser; + template + friend class json::details::JSON_Parser; - template - void format_impl(std::basic_string& str) const + template + void format_impl(std::basic_string& str) const + { + str.push_back('{'); + if (!m_object.empty()) + { + auto lastElement = m_object.end() - 1; + for (auto iter = m_object.begin(); iter != lastElement; ++iter) { - str.push_back('{'); - if(!m_object.empty()) - { - auto lastElement = m_object.end() - 1; - for (auto iter = m_object.begin(); iter != lastElement; ++iter) - { - format_string(iter->first, str); - str.push_back(':'); - iter->second.format(str); - str.push_back(','); - } - format_string(lastElement->first, str); - str.push_back(':'); - lastElement->second.format(str); - } - str.push_back('}'); + format_string(iter->first, str); + str.push_back(':'); + iter->second.format(str); + str.push_back(','); } + format_string(lastElement->first, str); + str.push_back(':'); + lastElement->second.format(str); + } + str.push_back('}'); + } - size_t get_reserve_size() const + size_t get_reserve_size() const + { + // This is a heuristic we can tune more in the future: + // Basically size of string plus + // sum size of value if an object, array, or string. + size_t reserveSize = 2; // For brackets {} + for (auto iter = m_object.begin(); iter != m_object.end(); ++iter) + { + reserveSize += iter->first.length() + 2; // 2 for quotes + size_t valueSize = iter->second.size() * 20; // Multiply by each object/array element + if (valueSize == 0) { - // This is a heuristic we can tune more in the future: - // Basically size of string plus - // sum size of value if an object, array, or string. - size_t reserveSize = 2; // For brackets {} - for(auto iter = m_object.begin(); iter != m_object.end(); ++iter) + if (iter->second.type() == json::value::String) + { + valueSize = static_cast<_String*>(iter->second.m_value.get())->get_reserve_size(); + } + else { - reserveSize += iter->first.length() + 2; // 2 for quotes - size_t valueSize = iter->second.size() * 20; // Multiply by each object/array element - if(valueSize == 0) - { - if(iter->second.type() == json::value::String) - { - valueSize = static_cast<_String *>(iter->second.m_value.get())->get_reserve_size(); - } - else - { - valueSize = 5; // true, false, or null - } - } - reserveSize += valueSize; + valueSize = 5; // true, false, or null } - return reserveSize; } - }; + reserveSize += valueSize; + } + return reserveSize; + } +}; - class _Array : public _Value - { - public: - _Array() {} - _Array(array::size_type size) : m_array(size) {} - _Array(array::storage_type elements) : m_array(std::move(elements)) { } +class _Array : public _Value +{ +public: + _Array() {} + _Array(array::size_type size) : m_array(size) {} + _Array(array::storage_type elements) : m_array(std::move(elements)) {} - virtual std::unique_ptr<_Value> _copy_value() - { - return utility::details::make_unique<_Array>(*this); - } + virtual std::unique_ptr<_Value> _copy_value() { return utility::details::make_unique<_Array>(*this); } - virtual json::value::value_type type() const { return json::value::Array; } + virtual json::value::value_type type() const { return json::value::Array; } - virtual json::array& as_array() { return m_array; } - virtual const json::array& as_array() const { return m_array; } + virtual json::array& as_array() { return m_array; } + virtual const json::array& as_array() const { return m_array; } - virtual json::value &index(json::array::size_type index) - { - return m_array[index]; - } + virtual json::value& index(json::array::size_type index) { return m_array[index]; } - bool is_equal(const _Array* other) const - { - if ( m_array.size() != other->m_array.size()) - return false; + bool is_equal(const _Array* other) const + { + if (m_array.size() != other->m_array.size()) return false; - auto iterT = m_array.cbegin(); - auto iterO = other->m_array.cbegin(); - auto iterTe = m_array.cend(); - auto iterOe = other->m_array.cend(); + auto iterT = m_array.cbegin(); + auto iterO = other->m_array.cbegin(); + auto iterTe = m_array.cend(); + auto iterOe = other->m_array.cend(); - for (; iterT != iterTe && iterO != iterOe; ++iterT, ++iterO) - { - if ( *iterT != *iterO ) - return false; - } + for (; iterT != iterTe && iterO != iterOe; ++iterT, ++iterO) + { + if (*iterT != *iterO) return false; + } - return true; - } + return true; + } - virtual void serialize_impl(std::string& str) const - { - // To avoid repeated allocations reserve some space all up front. - str.reserve(get_reserve_size()); - format(str); - } + virtual void serialize_impl(std::string& str) const + { + // To avoid repeated allocations reserve some space all up front. + str.reserve(get_reserve_size()); + format(str); + } #ifdef _WIN32 - virtual void serialize_impl(std::wstring& str) const - { - // To avoid repeated allocations reserve some space all up front. - str.reserve(get_reserve_size()); - format(str); - } + virtual void serialize_impl(std::wstring& str) const + { + // To avoid repeated allocations reserve some space all up front. + str.reserve(get_reserve_size()); + format(str); + } #endif - size_t size() const { return m_array.size(); } + size_t size() const { return m_array.size(); } - protected: - virtual void format(std::basic_string& str) const - { - format_impl(str); - } +protected: + virtual void format(std::basic_string& str) const { format_impl(str); } #ifdef _WIN32 - virtual void format(std::basic_string& str) const - { - format_impl(str); - } + virtual void format(std::basic_string& str) const { format_impl(str); } #endif - private: - json::array m_array; - - template friend class json::details::JSON_Parser; +private: + json::array m_array; - template - void format_impl(std::basic_string& str) const - { - str.push_back('['); - if(!m_array.m_elements.empty()) - { - auto lastElement = m_array.m_elements.end() - 1; - for (auto iter = m_array.m_elements.begin(); iter != lastElement; ++iter) - { - iter->format(str); - str.push_back(','); - } - lastElement->format(str); - } - str.push_back(']'); - } + template + friend class json::details::JSON_Parser; - size_t get_reserve_size() const + template + void format_impl(std::basic_string& str) const + { + str.push_back('['); + if (!m_array.m_elements.empty()) + { + auto lastElement = m_array.m_elements.end() - 1; + for (auto iter = m_array.m_elements.begin(); iter != lastElement; ++iter) { - // This is a heuristic we can tune more in the future: - // Basically sum size of each value if an object, array, or string by a multiplier. - size_t reserveSize = 2; // For brackets [] - for(auto iter = m_array.cbegin(); iter != m_array.cend(); ++iter) - { - size_t valueSize = iter->size() * 20; // Per each nested array/object - - if(valueSize == 0) - valueSize = 5; // true, false, or null - - reserveSize += valueSize; - } - return reserveSize; + iter->format(str); + str.push_back(','); } - }; - } // namespace details - - /// - /// Gets the number of children of the value. - /// - /// The number of children. 0 for all non-composites. - inline size_t json::value::size() const - { - return m_value->size(); + lastElement->format(str); + } + str.push_back(']'); } - /// - /// Test for the presence of a field. - /// - /// The name of the field - /// True if the field exists, false otherwise. - inline bool json::value::has_field(const utility::string_t& key) const + size_t get_reserve_size() const { - return m_value->has_field(key); - } + // This is a heuristic we can tune more in the future: + // Basically sum size of each value if an object, array, or string by a multiplier. + size_t reserveSize = 2; // For brackets [] + for (auto iter = m_array.cbegin(); iter != m_array.cend(); ++iter) + { + size_t valueSize = iter->size() * 20; // Per each nested array/object - /// - /// Access a field of a JSON object. - /// - /// The name of the field - /// The value kept in the field; null if the field does not exist - inline json::value json::value::get(const utility::string_t& key) const - { - return m_value->get_field(key); - } + if (valueSize == 0) valueSize = 5; // true, false, or null - /// - /// Access an element of a JSON array. - /// - /// The index of an element in the JSON array - /// The value kept at the array index; null if outside the boundaries of the array - inline json::value json::value::get(size_t index) const - { - return m_value->get_element(index); + reserveSize += valueSize; + } + return reserveSize; } - - /// - /// A standard std::ostream operator to facilitate writing JSON values to streams. - /// - /// The output stream to write the JSON value to. - /// The JSON value to be written to the stream. - /// The output stream object - _ASYNCRTIMP utility::ostream_t& __cdecl operator << (utility::ostream_t &os, const json::value &val); - - /// - /// A standard std::istream operator to facilitate reading JSON values from streams. - /// - /// The input stream to read the JSON value from. - /// The JSON value object read from the stream. - /// The input stream object. - _ASYNCRTIMP utility::istream_t& __cdecl operator >> (utility::istream_t &is, json::value &val); -}} +}; +} // namespace details + +/// +/// Gets the number of children of the value. +/// +/// The number of children. 0 for all non-composites. +inline size_t json::value::size() const { return m_value->size(); } + +/// +/// Test for the presence of a field. +/// +/// The name of the field +/// True if the field exists, false otherwise. +inline bool json::value::has_field(const utility::string_t& key) const { return m_value->has_field(key); } + +/// +/// Access a field of a JSON object. +/// +/// The name of the field +/// The value kept in the field; null if the field does not exist +inline json::value json::value::get(const utility::string_t& key) const { return m_value->get_field(key); } + +/// +/// Access an element of a JSON array. +/// +/// The index of an element in the JSON array +/// The value kept at the array index; null if outside the boundaries of the array +inline json::value json::value::get(size_t index) const { return m_value->get_element(index); } + +/// +/// A standard std::ostream operator to facilitate writing JSON values to streams. +/// +/// The output stream to write the JSON value to. +/// The JSON value to be written to the stream. +/// The output stream object +_ASYNCRTIMP utility::ostream_t& __cdecl operator<<(utility::ostream_t& os, const json::value& val); + +/// +/// A standard std::istream operator to facilitate reading JSON values from streams. +/// +/// The input stream to read the JSON value from. +/// The JSON value object read from the stream. +/// The input stream object. +_ASYNCRTIMP utility::istream_t& __cdecl operator>>(utility::istream_t& is, json::value& val); +} // namespace json +} // namespace web #endif diff --git a/Release/include/cpprest/oauth1.h b/Release/include/cpprest/oauth1.h index c15c1d1723..dbc45bdd71 100644 --- a/Release/include/cpprest/oauth1.h +++ b/Release/include/cpprest/oauth1.h @@ -1,22 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Oauth 1.0 -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Oauth 1.0 + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_OAUTH1_H #define CASA_OAUTH1_H -#include "cpprest/http_msg.h" #include "cpprest/details/web_utilities.h" +#include "cpprest/http_msg.h" namespace web { @@ -24,16 +24,15 @@ namespace http { namespace client { - // Forward declaration to avoid circular include dependency. - class http_client_config; -} +// Forward declaration to avoid circular include dependency. +class http_client_config; +} // namespace client /// oAuth 1.0 library. namespace oauth1 { namespace details { - class oauth1_handler; // State currently used by oauth1_config to authenticate request. @@ -43,14 +42,16 @@ class oauth1_handler; class oauth1_state { public: - oauth1_state(utility::string_t timestamp, utility::string_t nonce, - utility::string_t extra_key=utility::string_t(), - utility::string_t extra_value=utility::string_t()) : - m_timestamp(std::move(timestamp)), - m_nonce(std::move(nonce)), - m_extra_key(std::move(extra_key)), - m_extra_value(std::move(extra_value)) - {} + oauth1_state(utility::string_t timestamp, + utility::string_t nonce, + utility::string_t extra_key = utility::string_t(), + utility::string_t extra_value = utility::string_t()) + : m_timestamp(std::move(timestamp)) + , m_nonce(std::move(nonce)) + , m_extra_key(std::move(extra_key)) + , m_extra_value(std::move(extra_value)) + { + } const utility::string_t& timestamp() const { return m_timestamp; } void set_timestamp(utility::string_t timestamp) { m_timestamp = std::move(timestamp); } @@ -83,12 +84,11 @@ class oauth1_strings #undef DAT }; -} // namespace web::http::oauth1::details +} // namespace details /// oAuth functionality is currently in beta. namespace experimental { - /// /// Constant strings for OAuth 1.0 signature methods. /// @@ -97,7 +97,7 @@ class oauth1_methods { public: #define _OAUTH1_METHODS -#define DAT(a,b) _ASYNCRTIMP static const oauth1_method a; +#define DAT(a, b) _ASYNCRTIMP static const oauth1_method a; #include "cpprest/details/http_constants.dat" #undef _OAUTH1_METHODS #undef DAT @@ -123,7 +123,6 @@ class oauth1_exception : public std::exception class oauth1_token { public: - /// /// Constructs an initially empty invalid access token. /// @@ -134,10 +133,10 @@ class oauth1_token /// /// Access token string. /// Token secret string. - oauth1_token(utility::string_t access_token, utility::string_t secret) : - m_token(std::move(access_token)), - m_secret(std::move(secret)) - {} + oauth1_token(utility::string_t access_token, utility::string_t secret) + : m_token(std::move(access_token)), m_secret(std::move(secret)) + { + } /// /// Get access token validity state. @@ -156,13 +155,13 @@ class oauth1_token /// Set access token. /// /// Access token string to set. - void set_access_token(utility::string_t &&access_token) { m_token = std::move(access_token); } + void set_access_token(utility::string_t&& access_token) { m_token = std::move(access_token); } /// /// Set access token. /// /// Access token string to set. - void set_access_token(const utility::string_t &access_token) { m_token = access_token; } + void set_access_token(const utility::string_t& access_token) { m_token = access_token; } /// /// Get token secret. @@ -174,26 +173,29 @@ class oauth1_token /// Set token secret. /// /// Token secret string to set. - void set_secret(utility::string_t &&secret) { m_secret = std::move(secret); } + void set_secret(utility::string_t&& secret) { m_secret = std::move(secret); } /// /// Set token secret. /// /// Token secret string to set. - void set_secret(const utility::string_t &secret) { m_secret = secret; } + void set_secret(const utility::string_t& secret) { m_secret = secret; } /// /// Retrieves any additional parameters. /// /// A map containing the additional parameters. - const std::map &additional_parameters() const { return m_additional_parameters; } + const std::map& additional_parameters() const + { + return m_additional_parameters; + } /// /// Sets a specific parameter additional parameter. /// /// Parameter name. /// Parameter value. - void set_additional_parameter(utility::string_t &¶mName, utility::string_t &¶mValue) + void set_additional_parameter(utility::string_t&& paramName, utility::string_t&& paramValue) { m_additional_parameters[std::move(paramName)] = std::move(paramValue); } @@ -203,7 +205,7 @@ class oauth1_token /// /// Parameter name. /// Parameter value. - void set_additional_parameter(const utility::string_t ¶mName, const utility::string_t ¶mValue) + void set_additional_parameter(const utility::string_t& paramName, const utility::string_t& paramValue) { m_additional_parameters[paramName] = paramValue; } @@ -227,20 +229,25 @@ class oauth1_token class oauth1_config { public: - oauth1_config(utility::string_t consumer_key, utility::string_t consumer_secret, - utility::string_t temp_endpoint, utility::string_t auth_endpoint, - utility::string_t token_endpoint, utility::string_t callback_uri, - oauth1_method method, utility::string_t realm=utility::string_t()) : - m_consumer_key(std::move(consumer_key)), - m_consumer_secret(std::move(consumer_secret)), - m_temp_endpoint(std::move(temp_endpoint)), - m_auth_endpoint(std::move(auth_endpoint)), - m_token_endpoint(std::move(token_endpoint)), - m_callback_uri(std::move(callback_uri)), - m_realm(std::move(realm)), - m_method(std::move(method)), - m_is_authorization_completed(false) - {} + oauth1_config(utility::string_t consumer_key, + utility::string_t consumer_secret, + utility::string_t temp_endpoint, + utility::string_t auth_endpoint, + utility::string_t token_endpoint, + utility::string_t callback_uri, + oauth1_method method, + utility::string_t realm = utility::string_t()) + : m_consumer_key(std::move(consumer_key)) + , m_consumer_secret(std::move(consumer_secret)) + , m_temp_endpoint(std::move(temp_endpoint)) + , m_auth_endpoint(std::move(auth_endpoint)) + , m_token_endpoint(std::move(token_endpoint)) + , m_callback_uri(std::move(callback_uri)) + , m_realm(std::move(realm)) + , m_method(std::move(method)) + , m_is_authorization_completed(false) + { + } /// /// Builds an authorization URI to be loaded in a web browser/view. @@ -261,8 +268,8 @@ class oauth1_config /// When access token is successfully obtained, set_token() is called, and config is /// ready for use by oauth1_handler. /// - /// The URI where web browser/view was redirected after resource owner's authorization. - /// Task that fetches the access token based on redirected URI. + /// The URI where web browser/view was redirected after resource owner's + /// authorization. Task that fetches the access token based on redirected URI. _ASYNCRTIMP pplx::task token_from_redirected_uri(const web::http::uri& redirected_uri); /// @@ -283,7 +290,7 @@ class oauth1_config /// If successful, the resulting token is set as active via set_token(). /// /// Task that fetches the access token based on the verifier. - pplx::task refresh_token(const utility::string_t &key) + pplx::task refresh_token(const utility::string_t& key) { return _request_token(_generate_auth_state(key, m_token.additional_parameters().at(key)), false); } @@ -400,7 +407,10 @@ class oauth1_config /// and both consumer_key() and consumer_secret() are set (=non-empty). /// /// The configuration enabled state. - bool is_enabled() const { return token().is_valid_access_token() && !(consumer_key().empty() || consumer_secret().empty()); } + bool is_enabled() const + { + return token().is_valid_access_token() && !(consumer_key().empty() || consumer_secret().empty()); + } // Builds signature base string according to: // http://tools.ietf.org/html/rfc5849#section-3.4.1.1 @@ -418,14 +428,12 @@ class oauth1_config // Builds PLAINTEXT signature according to: // http://tools.ietf.org/html/rfc5849#section-3.4.4 - utility::string_t _build_plaintext_signature() const - { - return _build_key(); - } + utility::string_t _build_plaintext_signature() const { return _build_key(); } details::oauth1_state _generate_auth_state(utility::string_t extra_key, utility::string_t extra_value) { - return details::oauth1_state(_generate_timestamp(), _generate_nonce(), std::move(extra_key), std::move(extra_value)); + return details::oauth1_state( + _generate_timestamp(), _generate_nonce(), std::move(extra_key), std::move(extra_value)); } details::oauth1_state _generate_auth_state() @@ -444,20 +452,26 @@ class oauth1_config /// /// Key as a string value. /// Value as a string value. - void add_parameter(const utility::string_t &key, const utility::string_t &value) { m_parameters_to_sign[key] = value; } + void add_parameter(const utility::string_t& key, const utility::string_t& value) + { + m_parameters_to_sign[key] = value; + } /// /// Adds a key value parameter. /// /// Key as a string value. /// Value as a string value. - void add_parameter(utility::string_t &&key, utility::string_t &&value) { m_parameters_to_sign[std::move(key)] = std::move(value); } + void add_parameter(utility::string_t&& key, utility::string_t&& value) + { + m_parameters_to_sign[std::move(key)] = std::move(value); + } /// /// Sets entire map or parameters replacing all previously values. /// /// Map of values. - void set_parameters(const std::map ¶meters) + void set_parameters(const std::map& parameters) { m_parameters_to_sign.clear(); m_parameters_to_sign = parameters; @@ -472,39 +486,29 @@ class oauth1_config /// Get the web proxy object /// /// A reference to the web proxy object. - const web_proxy& proxy() const - { - return m_proxy; - } + const web_proxy& proxy() const { return m_proxy; } /// /// Set the web proxy object that will be used by token_from_code and token_from_refresh /// /// A reference to the web proxy object. - void set_proxy(const web_proxy& proxy) - { - m_proxy = proxy; - } + void set_proxy(const web_proxy& proxy) { m_proxy = proxy; } private: friend class web::http::client::http_client_config; friend class web::http::oauth1::details::oauth1_handler; - oauth1_config() : - m_is_authorization_completed(false) - {} + oauth1_config() : m_is_authorization_completed(false) {} - utility::string_t _generate_nonce() - { - return m_nonce_generator.generate(); - } + utility::string_t _generate_nonce() { return m_nonce_generator.generate(); } static utility::string_t _generate_timestamp() { return utility::conversions::details::to_string_t(utility::datetime::utc_timestamp()); } - _ASYNCRTIMP static std::vector __cdecl _hmac_sha1(const utility::string_t& key, const utility::string_t& data); + _ASYNCRTIMP static std::vector __cdecl _hmac_sha1(const utility::string_t& key, + const utility::string_t& data); static utility::string_t _build_base_string_uri(const uri& u); @@ -517,12 +521,9 @@ class oauth1_config return uri::encode_data_string(consumer_secret()) + _XPLATSTR("&") + uri::encode_data_string(m_token.secret()); } - void _authenticate_request(http_request &req) - { - _authenticate_request(req, _generate_auth_state()); - } + void _authenticate_request(http_request& req) { _authenticate_request(req, _generate_auth_state()); } - _ASYNCRTIMP void _authenticate_request(http_request &req, details::oauth1_state state); + _ASYNCRTIMP void _authenticate_request(http_request& req, details::oauth1_state state); _ASYNCRTIMP pplx::task _request_token(details::oauth1_state state, bool is_temp_token_request); @@ -537,7 +538,7 @@ class oauth1_config utility::string_t m_realm; oauth1_method m_method; - std::map m_parameters_to_sign; + std::map m_parameters_to_sign; web::web_proxy m_proxy; @@ -545,17 +546,14 @@ class oauth1_config bool m_is_authorization_completed; }; -} // namespace web::http::oauth1::experimental +} // namespace experimental namespace details { - class oauth1_handler : public http_pipeline_stage { public: - oauth1_handler(std::shared_ptr cfg) : - m_config(std::move(cfg)) - {} + oauth1_handler(std::shared_ptr cfg) : m_config(std::move(cfg)) {} virtual pplx::task propagate(http_request request) override { @@ -570,6 +568,9 @@ class oauth1_handler : public http_pipeline_stage std::shared_ptr m_config; }; -}}}} +} // namespace details +} // namespace oauth1 +} // namespace http +} // namespace web #endif diff --git a/Release/include/cpprest/oauth2.h b/Release/include/cpprest/oauth2.h index 016eba83ff..693ebbe34c 100644 --- a/Release/include/cpprest/oauth2.h +++ b/Release/include/cpprest/oauth2.h @@ -1,22 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Oauth 2.0 -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Oauth 2.0 + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_OAUTH2_H #define CASA_OAUTH2_H -#include "cpprest/http_msg.h" #include "cpprest/details/web_utilities.h" +#include "cpprest/http_msg.h" namespace web { @@ -24,16 +24,15 @@ namespace http { namespace client { - // Forward declaration to avoid circular include dependency. - class http_client_config; -} +// Forward declaration to avoid circular include dependency. +class http_client_config; +} // namespace client /// oAuth 2.0 library. namespace oauth2 { namespace details { - class oauth2_handler; // Constant strings for OAuth 2.0. @@ -48,12 +47,11 @@ class oauth2_strings #undef DAT }; -} // namespace web::http::oauth2::details +} // namespace details /// oAuth functionality is currently in beta. namespace experimental { - /// /// Exception type for OAuth 2.0 errors. /// @@ -74,16 +72,18 @@ class oauth2_exception : public std::exception class oauth2_token { public: - /// /// Value for undefined expiration time in expires_in(). /// - enum { undefined_expiration = -1 }; + enum + { + undefined_expiration = -1 + }; - oauth2_token(utility::string_t access_token=utility::string_t()) : - m_access_token(std::move(access_token)), - m_expires_in(undefined_expiration) - {} + oauth2_token(utility::string_t access_token = utility::string_t()) + : m_access_token(std::move(access_token)), m_expires_in(undefined_expiration) + { + } /// /// Get access token validity state. @@ -201,23 +201,26 @@ class oauth2_token class oauth2_config { public: - - oauth2_config(utility::string_t client_key, utility::string_t client_secret, - utility::string_t auth_endpoint, utility::string_t token_endpoint, - utility::string_t redirect_uri, utility::string_t scope=utility::string_t(), - utility::string_t user_agent=utility::string_t()) : - m_client_key(std::move(client_key)), - m_client_secret(std::move(client_secret)), - m_auth_endpoint(std::move(auth_endpoint)), - m_token_endpoint(std::move(token_endpoint)), - m_redirect_uri(std::move(redirect_uri)), - m_scope(std::move(scope)), - m_user_agent(std::move(user_agent)), - m_implicit_grant(false), - m_bearer_auth(true), - m_http_basic_auth(true), - m_access_token_key(details::oauth2_strings::access_token) - {} + oauth2_config(utility::string_t client_key, + utility::string_t client_secret, + utility::string_t auth_endpoint, + utility::string_t token_endpoint, + utility::string_t redirect_uri, + utility::string_t scope = utility::string_t(), + utility::string_t user_agent = utility::string_t()) + : m_client_key(std::move(client_key)) + , m_client_secret(std::move(client_secret)) + , m_auth_endpoint(std::move(auth_endpoint)) + , m_token_endpoint(std::move(token_endpoint)) + , m_redirect_uri(std::move(redirect_uri)) + , m_scope(std::move(scope)) + , m_user_agent(std::move(user_agent)) + , m_implicit_grant(false) + , m_bearer_auth(true) + , m_http_basic_auth(true) + , m_access_token_key(details::oauth2_strings::access_token) + { + } /// /// Builds an authorization URI to be loaded in the web browser/view. @@ -242,8 +245,8 @@ class oauth2_config /// See: http://tools.ietf.org/html/rfc6749#section-4.2 /// In both cases, the 'state' parameter is parsed and is verified to match state(). /// - /// The URI where web browser/view was redirected after resource owner's authorization. - /// Task that fetches the token(s) based on redirected URI. + /// The URI where web browser/view was redirected after resource owner's + /// authorization. Task that fetches the token(s) based on redirected URI. _ASYNCRTIMP pplx::task token_from_redirected_uri(const web::http::uri& redirected_uri); /// @@ -276,7 +279,8 @@ class oauth2_config { uri_builder ub; ub.append_query(details::oauth2_strings::grant_type, details::oauth2_strings::refresh_token, false); - ub.append_query(details::oauth2_strings::refresh_token, uri::encode_data_string(token().refresh_token()), false); + ub.append_query( + details::oauth2_strings::refresh_token, uri::encode_data_string(token().refresh_token()), false); return _request_token(ub); } @@ -430,37 +434,31 @@ class oauth2_config /// Get access token key. /// /// Access token key string. - const utility::string_t& access_token_key() const { return m_access_token_key; } + const utility::string_t& access_token_key() const { return m_access_token_key; } /// /// Set access token key. /// If the service requires a "non-standard" key you must set it here. /// Default: "access_token". /// void set_access_token_key(utility::string_t access_token_key) { m_access_token_key = std::move(access_token_key); } - + /// /// Get the web proxy object /// /// A reference to the web proxy object. - const web_proxy& proxy() const - { - return m_proxy; - } + const web_proxy& proxy() const { return m_proxy; } /// /// Set the web proxy object that will be used by token_from_code and token_from_refresh /// /// A reference to the web proxy object. - void set_proxy(const web_proxy& proxy) - { - m_proxy = proxy; - } - + void set_proxy(const web_proxy& proxy) { m_proxy = proxy; } + /// /// Get user agent to be used in oauth2 flows. /// /// User agent string. - const utility::string_t& user_agent() const { return m_user_agent; } + const utility::string_t& user_agent() const { return m_user_agent; } /// /// Set user agent to be used in oauth2 flows. /// If none is provided a default user agent is provided. @@ -471,17 +469,13 @@ class oauth2_config friend class web::http::client::http_client_config; friend class web::http::oauth2::details::oauth2_handler; - oauth2_config() : - m_implicit_grant(false), - m_bearer_auth(true), - m_http_basic_auth(true) - {} + oauth2_config() : m_implicit_grant(false), m_bearer_auth(true), m_http_basic_auth(true) {} _ASYNCRTIMP pplx::task _request_token(uri_builder& request_body); oauth2_token _parse_token_from_json(const json::value& token_json); - void _authenticate_request(http_request &req) const + void _authenticate_request(http_request& req) const { if (bearer_auth()) { @@ -516,17 +510,14 @@ class oauth2_config utility::nonce_generator m_state_generator; }; -} // namespace web::http::oauth2::experimental +} // namespace experimental namespace details { - class oauth2_handler : public http_pipeline_stage { public: - oauth2_handler(std::shared_ptr cfg) : - m_config(std::move(cfg)) - {} + oauth2_handler(std::shared_ptr cfg) : m_config(std::move(cfg)) {} virtual pplx::task propagate(http_request request) override { @@ -541,6 +532,9 @@ class oauth2_handler : public http_pipeline_stage std::shared_ptr m_config; }; -}}}} +} // namespace details +} // namespace oauth2 +} // namespace http +} // namespace web #endif diff --git a/Release/include/cpprest/producerconsumerstream.h b/Release/include/cpprest/producerconsumerstream.h index b2467a7ca7..39a57a7306 100644 --- a/Release/include/cpprest/producerconsumerstream.h +++ b/Release/include/cpprest/producerconsumerstream.h @@ -1,697 +1,655 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* This file defines a basic memory-based stream buffer, which allows consumer / producer pairs to communicate -* data via a buffer. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * This file defines a basic memory-based stream buffer, which allows consumer / producer pairs to communicate + * data via a buffer. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_PRODUCER_CONSUMER_STREAMS_H #define CASA_PRODUCER_CONSUMER_STREAMS_H -#include -#include +#include "cpprest/astreambuf.h" +#include "pplx/pplxtasks.h" #include #include +#include +#include -#include "pplx/pplxtasks.h" -#include "cpprest/astreambuf.h" - -namespace Concurrency { namespace streams { - - namespace details { +namespace Concurrency +{ +namespace streams +{ +namespace details +{ +/// +/// The basic_producer_consumer_buffer class serves as a memory-based steam buffer that supports both writing and +/// reading sequences of characters. It can be used as a consumer/producer buffer. +/// +template +class basic_producer_consumer_buffer : public streams::details::streambuf_state_manager<_CharType> +{ +public: + typedef typename ::concurrency::streams::char_traits<_CharType> traits; + typedef typename basic_streambuf<_CharType>::int_type int_type; + typedef typename basic_streambuf<_CharType>::pos_type pos_type; + typedef typename basic_streambuf<_CharType>::off_type off_type; - /// - /// The basic_producer_consumer_buffer class serves as a memory-based steam buffer that supports both writing and reading - /// sequences of characters. It can be used as a consumer/producer buffer. - /// - template - class basic_producer_consumer_buffer : public streams::details::streambuf_state_manager<_CharType> - { - public: - typedef typename ::concurrency::streams::char_traits<_CharType> traits; - typedef typename basic_streambuf<_CharType>::int_type int_type; - typedef typename basic_streambuf<_CharType>::pos_type pos_type; - typedef typename basic_streambuf<_CharType>::off_type off_type; - - /// - /// Constructor - /// - basic_producer_consumer_buffer(size_t alloc_size) - : streambuf_state_manager<_CharType>(std::ios_base::out | std::ios_base::in), - m_alloc_size(alloc_size), - m_allocBlock(nullptr), - m_total(0), m_total_read(0), m_total_written(0), - m_synced(0) - { - } + /// + /// Constructor + /// + basic_producer_consumer_buffer(size_t alloc_size) + : streambuf_state_manager<_CharType>(std::ios_base::out | std::ios_base::in) + , m_alloc_size(alloc_size) + , m_allocBlock(nullptr) + , m_total(0) + , m_total_read(0) + , m_total_written(0) + , m_synced(0) + { + } - /// - /// Destructor - /// - virtual ~basic_producer_consumer_buffer() - { - // Note: there is no need to call 'wait()' on the result of close(), - // since we happen to know that close() will return without actually - // doing anything asynchronously. Should the implementation of _close_write() - // change in that regard, this logic may also have to change. - this->_close_read(); - this->_close_write(); - - _ASSERTE(m_requests.empty()); - m_blocks.clear(); - } + /// + /// Destructor + /// + virtual ~basic_producer_consumer_buffer() + { + // Note: there is no need to call 'wait()' on the result of close(), + // since we happen to know that close() will return without actually + // doing anything asynchronously. Should the implementation of _close_write() + // change in that regard, this logic may also have to change. + this->_close_read(); + this->_close_write(); - /// - /// can_seek is used to determine whether a stream buffer supports seeking. - /// - virtual bool can_seek() const { return false; } - - /// - /// has_size is used to determine whether a stream buffer supports size(). - /// - virtual bool has_size() const { return false; } - - /// - /// Get the stream buffer size, if one has been set. - /// - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will always return '0'. - virtual size_t buffer_size(std::ios_base::openmode = std::ios_base::in) const - { - return 0; - } + _ASSERTE(m_requests.empty()); + m_blocks.clear(); + } - /// - /// Sets the stream buffer implementation to buffer or not buffer. - /// - /// The size to use for internal buffering, 0 if no buffering should be done. - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will silently ignore calls to this function and it will not have any effect on what is returned by subsequent calls to . - virtual void set_buffer_size(size_t , std::ios_base::openmode = std::ios_base::in) - { - return; - } + /// + /// can_seek is used to determine whether a stream buffer supports seeking. + /// + virtual bool can_seek() const { return false; } - /// - /// For any input stream, in_avail returns the number of characters that are immediately available - /// to be consumed without blocking. May be used in conjunction with to read data without - /// incurring the overhead of using tasks. - /// - virtual size_t in_avail() const { return m_total; } - - - /// - /// Gets the current read or write position in the stream. - /// - /// The I/O direction to seek (see remarks) - /// The current position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual pos_type getpos(std::ios_base::openmode mode) const - { - if ( ((mode & std::ios_base::in) && !this->can_read()) || - ((mode & std::ios_base::out) && !this->can_write())) - return static_cast(traits::eof()); - - if (mode == std::ios_base::in) - return (pos_type)m_total_read; - else if (mode == std::ios_base::out) - return (pos_type)m_total_written; - else - return (pos_type)traits::eof(); - } + /// + /// has_size is used to determine whether a stream buffer supports size(). + /// + virtual bool has_size() const { return false; } - // Seeking is not supported - virtual pos_type seekpos(pos_type, std::ios_base::openmode) { return (pos_type)traits::eof(); } - virtual pos_type seekoff(off_type , std::ios_base::seekdir , std::ios_base::openmode ) { return (pos_type)traits::eof(); } + /// + /// Get the stream buffer size, if one has been set. + /// + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will always return '0'. + virtual size_t buffer_size(std::ios_base::openmode = std::ios_base::in) const { return 0; } - /// - /// Allocates a contiguous memory block and returns it. - /// - /// The number of characters to allocate. - /// A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit. - virtual _CharType* _alloc(size_t count) - { - if (!this->can_write()) - { - return nullptr; - } - - // We always allocate a new block even if the count could be satisfied by - // the current write block. While this does lead to wasted space it allows for - // easier book keeping - - _ASSERTE(!m_allocBlock); - m_allocBlock = std::make_shared<_block>(count); - return m_allocBlock->wbegin(); - } + /// + /// Sets the stream buffer implementation to buffer or not buffer. + /// + /// The size to use for internal buffering, 0 if no buffering should be done. + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will silently ignore calls to this function and it + /// will not have any effect on what is returned by subsequent calls to . + virtual void set_buffer_size(size_t, std::ios_base::openmode = std::ios_base::in) { return; } - /// - /// Submits a block already allocated by the stream buffer. - /// - /// The number of characters to be committed. - virtual void _commit(size_t count) - { - pplx::extensibility::scoped_critical_section_t l(m_lock); + /// + /// For any input stream, in_avail returns the number of characters that are immediately available + /// to be consumed without blocking. May be used in conjunction with to read data without + /// incurring the overhead of using tasks. + /// + virtual size_t in_avail() const { return m_total; } - // The count does not reflect the actual size of the block. - // Since we do not allow any more writes to this block it would suffice. - // If we ever change the algorithm to reuse blocks then this needs to be revisited. + /// + /// Gets the current read or write position in the stream. + /// + /// The I/O direction to seek (see remarks) + /// The current position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the direction parameter defines whether to move the read or the write + /// cursor. + virtual pos_type getpos(std::ios_base::openmode mode) const + { + if (((mode & std::ios_base::in) && !this->can_read()) || ((mode & std::ios_base::out) && !this->can_write())) + return static_cast(traits::eof()); + + if (mode == std::ios_base::in) + return (pos_type)m_total_read; + else if (mode == std::ios_base::out) + return (pos_type)m_total_written; + else + return (pos_type)traits::eof(); + } + + // Seeking is not supported + virtual pos_type seekpos(pos_type, std::ios_base::openmode) { return (pos_type)traits::eof(); } + virtual pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode) + { + return (pos_type)traits::eof(); + } - _ASSERTE((bool)m_allocBlock); - m_allocBlock->update_write_head(count); - m_blocks.push_back(m_allocBlock); - m_allocBlock = nullptr; + /// + /// Allocates a contiguous memory block and returns it. + /// + /// The number of characters to allocate. + /// A pointer to a block to write to, null if the stream buffer implementation does not support + /// alloc/commit. + virtual _CharType* _alloc(size_t count) + { + if (!this->can_write()) + { + return nullptr; + } - update_write_head(count); - } + // We always allocate a new block even if the count could be satisfied by + // the current write block. While this does lead to wasted space it allows for + // easier book keeping - /// - /// Gets a pointer to the next already allocated contiguous block of data. - /// - /// A reference to a pointer variable that will hold the address of the block on success. - /// The number of contiguous characters available at the address in 'ptr'. - /// true if the operation succeeded, false otherwise. - /// - /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that - /// there is no block to return immediately or that the stream buffer does not support the operation. - /// The stream buffer may not de-allocate the block until is called. - /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; - /// a subsequent read will not succeed. - /// - virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) - { - count = 0; - ptr = nullptr; + _ASSERTE(!m_allocBlock); + m_allocBlock = std::make_shared<_block>(count); + return m_allocBlock->wbegin(); + } - if (!this->can_read()) return false; + /// + /// Submits a block already allocated by the stream buffer. + /// + /// The number of characters to be committed. + virtual void _commit(size_t count) + { + pplx::extensibility::scoped_critical_section_t l(m_lock); - pplx::extensibility::scoped_critical_section_t l(m_lock); + // The count does not reflect the actual size of the block. + // Since we do not allow any more writes to this block it would suffice. + // If we ever change the algorithm to reuse blocks then this needs to be revisited. - if (m_blocks.empty()) - { - // If the write head has been closed then have reached the end of the - // stream (return true), otherwise more data could be written later (return false). - return !this->can_write(); - } - else - { - auto block = m_blocks.front(); + _ASSERTE((bool)m_allocBlock); + m_allocBlock->update_write_head(count); + m_blocks.push_back(m_allocBlock); + m_allocBlock = nullptr; - count = block->rd_chars_left(); - ptr = block->rbegin(); + update_write_head(count); + } - _ASSERTE(ptr != nullptr); - return true; - } - } + /// + /// Gets a pointer to the next already allocated contiguous block of data. + /// + /// A reference to a pointer variable that will hold the address of the block on success. + /// The number of contiguous characters available at the address in 'ptr'. + /// true if the operation succeeded, false otherwise. + /// + /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that + /// there is no block to return immediately or that the stream buffer does not support the operation. + /// The stream buffer may not de-allocate the block until is called. + /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; + /// a subsequent read will not succeed. + /// + virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) + { + count = 0; + ptr = nullptr; - /// - /// Releases a block of data acquired using . This frees the stream buffer to de-allocate the - /// memory, if it so desires. Move the read position ahead by the count. - /// - /// A pointer to the block of data to be released. - /// The number of characters that were read. - virtual void release(_Out_writes_opt_ (count) _CharType *ptr, _In_ size_t count) - { - if (ptr == nullptr) return; + if (!this->can_read()) return false; - pplx::extensibility::scoped_critical_section_t l(m_lock); - auto block = m_blocks.front(); + pplx::extensibility::scoped_critical_section_t l(m_lock); - _ASSERTE(block->rd_chars_left() >= count); - block->m_read += count; + if (m_blocks.empty()) + { + // If the write head has been closed then have reached the end of the + // stream (return true), otherwise more data could be written later (return false). + return !this->can_write(); + } + else + { + auto block = m_blocks.front(); - update_read_head(count); - } + count = block->rd_chars_left(); + ptr = block->rbegin(); - protected: + _ASSERTE(ptr != nullptr); + return true; + } + } - virtual pplx::task _sync() - { - pplx::extensibility::scoped_critical_section_t l(m_lock); + /// + /// Releases a block of data acquired using . This frees the stream buffer to + /// de-allocate the memory, if it so desires. Move the read position ahead by the count. + /// + /// A pointer to the block of data to be released. + /// The number of characters that were read. + virtual void release(_Out_writes_opt_(count) _CharType* ptr, _In_ size_t count) + { + if (ptr == nullptr) return; - m_synced = in_avail(); + pplx::extensibility::scoped_critical_section_t l(m_lock); + auto block = m_blocks.front(); - fulfill_outstanding(); + _ASSERTE(block->rd_chars_left() >= count); + block->m_read += count; - return pplx::task_from_result(true); - } + update_read_head(count); + } - virtual pplx::task _putc(_CharType ch) - { - return pplx::task_from_result((this->write(&ch, 1) == 1) ? static_cast(ch) : traits::eof()); - } +protected: + virtual pplx::task _sync() + { + pplx::extensibility::scoped_critical_section_t l(m_lock); - virtual pplx::task _putn(const _CharType *ptr, size_t count) - { - return pplx::task_from_result(this->write(ptr, count)); - } + m_synced = in_avail(); + fulfill_outstanding(); - virtual pplx::task _getn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - pplx::task_completion_event tce; - enqueue_request(_request(count, [this, ptr, count, tce]() - { - // VS 2010 resolves read to a global function. Explicit - // invocation through the "this" pointer fixes the issue. - tce.set(this->read(ptr, count)); - })); - return pplx::create_task(tce); - } + return pplx::task_from_result(true); + } - virtual size_t _sgetn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - pplx::extensibility::scoped_critical_section_t l(m_lock); - return can_satisfy(count) ? this->read(ptr, count) : (size_t)traits::requires_async(); - } + virtual pplx::task _putc(_CharType ch) + { + return pplx::task_from_result((this->write(&ch, 1) == 1) ? static_cast(ch) : traits::eof()); + } - virtual size_t _scopy(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - pplx::extensibility::scoped_critical_section_t l(m_lock); - return can_satisfy(count) ? this->read(ptr, count, false) : (size_t)traits::requires_async(); - } + virtual pplx::task _putn(const _CharType* ptr, size_t count) + { + return pplx::task_from_result(this->write(ptr, count)); + } - virtual pplx::task _bumpc() - { - pplx::task_completion_event tce; - enqueue_request(_request(1, [this, tce]() - { - tce.set(this->read_byte(true)); - })); - return pplx::create_task(tce); - } + virtual pplx::task _getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + pplx::task_completion_event tce; + enqueue_request(_request(count, [this, ptr, count, tce]() { + // VS 2010 resolves read to a global function. Explicit + // invocation through the "this" pointer fixes the issue. + tce.set(this->read(ptr, count)); + })); + return pplx::create_task(tce); + } + + virtual size_t _sgetn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + pplx::extensibility::scoped_critical_section_t l(m_lock); + return can_satisfy(count) ? this->read(ptr, count) : (size_t)traits::requires_async(); + } - virtual int_type _sbumpc() - { - pplx::extensibility::scoped_critical_section_t l(m_lock); - return can_satisfy(1) ? this->read_byte(true) : traits::requires_async(); - } + virtual size_t _scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + pplx::extensibility::scoped_critical_section_t l(m_lock); + return can_satisfy(count) ? this->read(ptr, count, false) : (size_t)traits::requires_async(); + } - virtual pplx::task _getc() - { - pplx::task_completion_event tce; - enqueue_request(_request(1, [this, tce]() - { - tce.set(this->read_byte(false)); - })); - return pplx::create_task(tce); - } + virtual pplx::task _bumpc() + { + pplx::task_completion_event tce; + enqueue_request(_request(1, [this, tce]() { tce.set(this->read_byte(true)); })); + return pplx::create_task(tce); + } - int_type _sgetc() - { - pplx::extensibility::scoped_critical_section_t l(m_lock); - return can_satisfy(1) ? this->read_byte(false) : traits::requires_async(); - } + virtual int_type _sbumpc() + { + pplx::extensibility::scoped_critical_section_t l(m_lock); + return can_satisfy(1) ? this->read_byte(true) : traits::requires_async(); + } - virtual pplx::task _nextc() - { - pplx::task_completion_event tce; - enqueue_request(_request(1, [this, tce]() - { - this->read_byte(true); - tce.set(this->read_byte(false)); - })); - return pplx::create_task(tce); - } + virtual pplx::task _getc() + { + pplx::task_completion_event tce; + enqueue_request(_request(1, [this, tce]() { tce.set(this->read_byte(false)); })); + return pplx::create_task(tce); + } - virtual pplx::task _ungetc() - { - return pplx::task_from_result(traits::eof()); - } + int_type _sgetc() + { + pplx::extensibility::scoped_critical_section_t l(m_lock); + return can_satisfy(1) ? this->read_byte(false) : traits::requires_async(); + } - private: + virtual pplx::task _nextc() + { + pplx::task_completion_event tce; + enqueue_request(_request(1, [this, tce]() { + this->read_byte(true); + tce.set(this->read_byte(false)); + })); + return pplx::create_task(tce); + } - /// - /// Close the stream buffer for writing - /// - pplx::task _close_write() - { - // First indicate that there could be no more writes. - // Fulfill outstanding relies on that to flush all the - // read requests. - this->m_stream_can_write = false; + virtual pplx::task _ungetc() { return pplx::task_from_result(traits::eof()); } - { - pplx::extensibility::scoped_critical_section_t l(this->m_lock); +private: + /// + /// Close the stream buffer for writing + /// + pplx::task _close_write() + { + // First indicate that there could be no more writes. + // Fulfill outstanding relies on that to flush all the + // read requests. + this->m_stream_can_write = false; - // This runs on the thread that called close. - this->fulfill_outstanding(); - } + { + pplx::extensibility::scoped_critical_section_t l(this->m_lock); - return pplx::task_from_result(); - } + // This runs on the thread that called close. + this->fulfill_outstanding(); + } - /// - /// Updates the write head by an offset specified by count - /// - /// This should be called with the lock held - void update_write_head(size_t count) - { - m_total += count; - m_total_written += count; - fulfill_outstanding(); - } + return pplx::task_from_result(); + } - /// - /// Writes count characters from ptr into the stream buffer - /// - size_t write(const _CharType *ptr, size_t count) - { - if (!this->can_write() || (count == 0)) return 0; + /// + /// Updates the write head by an offset specified by count + /// + /// This should be called with the lock held + void update_write_head(size_t count) + { + m_total += count; + m_total_written += count; + fulfill_outstanding(); + } - // If no one is going to read, why bother? - // Just pretend to be writing! - if (!this->can_read()) return count; + /// + /// Writes count characters from ptr into the stream buffer + /// + size_t write(const _CharType* ptr, size_t count) + { + if (!this->can_write() || (count == 0)) return 0; - pplx::extensibility::scoped_critical_section_t l(m_lock); + // If no one is going to read, why bother? + // Just pretend to be writing! + if (!this->can_read()) return count; - // Allocate a new block if necessary - if ( m_blocks.empty() || m_blocks.back()->wr_chars_left() < count ) - { - msl::safeint3::SafeInt alloc = m_alloc_size.Max(count); - m_blocks.push_back(std::make_shared<_block>(alloc)); - } + pplx::extensibility::scoped_critical_section_t l(m_lock); - // The block at the back is always the write head - auto last = m_blocks.back(); - auto countWritten = last->write(ptr, count); - _ASSERTE(countWritten == count); + // Allocate a new block if necessary + if (m_blocks.empty() || m_blocks.back()->wr_chars_left() < count) + { + msl::safeint3::SafeInt alloc = m_alloc_size.Max(count); + m_blocks.push_back(std::make_shared<_block>(alloc)); + } - update_write_head(countWritten); - return countWritten; - } + // The block at the back is always the write head + auto last = m_blocks.back(); + auto countWritten = last->write(ptr, count); + _ASSERTE(countWritten == count); - /// - /// Fulfill pending requests - /// - /// This should be called with the lock held - void fulfill_outstanding() - { - while ( !m_requests.empty() ) - { - auto req = m_requests.front(); + update_write_head(countWritten); + return countWritten; + } - // If we cannot satisfy the request then we need - // to wait for the producer to write data - if (!can_satisfy(req.size())) return; + /// + /// Fulfill pending requests + /// + /// This should be called with the lock held + void fulfill_outstanding() + { + while (!m_requests.empty()) + { + auto req = m_requests.front(); - // We have enough data to satisfy this request - req.complete(); + // If we cannot satisfy the request then we need + // to wait for the producer to write data + if (!can_satisfy(req.size())) return; - // Remove it from the request queue - m_requests.pop(); - } - } + // We have enough data to satisfy this request + req.complete(); - /// - /// Represents a memory block - /// - class _block - { - public: - _block(size_t size) - : m_read(0), m_pos(0), m_size(size), m_data(new _CharType[size]) - { - } - - ~_block() - { - delete [] m_data; - } - - // Read head - size_t m_read; - - // Write head - size_t m_pos; - - // Allocation size (of m_data) - size_t m_size; - - // The data store - _CharType * m_data; - - // Pointer to the read head - _CharType * rbegin() - { - return m_data + m_read; - } - - // Pointer to the write head - _CharType * wbegin() - { - return m_data + m_pos; - } - - // Read up to count characters from the block - size_t read(_Out_writes_ (count) _CharType * dest, _In_ size_t count, bool advance = true) - { - msl::safeint3::SafeInt avail(rd_chars_left()); - auto countRead = static_cast(avail.Min(count)); - - _CharType * beg = rbegin(); - _CharType * end = rbegin() + countRead; + // Remove it from the request queue + m_requests.pop(); + } + } -#ifdef _WIN32 - // Avoid warning C4996: Use checked iterators under SECURE_SCL - std::copy(beg, end, stdext::checked_array_iterator<_CharType *>(dest, count)); -#else - std::copy(beg, end, dest); -#endif // _WIN32 + /// + /// Represents a memory block + /// + class _block + { + public: + _block(size_t size) : m_read(0), m_pos(0), m_size(size), m_data(new _CharType[size]) {} - if (advance) - { - m_read += countRead; - } + ~_block() { delete[] m_data; } - return countRead; - } + // Read head + size_t m_read; - // Write count characters into the block - size_t write(const _CharType * src, size_t count) - { - msl::safeint3::SafeInt avail(wr_chars_left()); - auto countWritten = static_cast(avail.Min(count)); + // Write head + size_t m_pos; - const _CharType * srcEnd = src + countWritten; + // Allocation size (of m_data) + size_t m_size; -#ifdef _WIN32 - // Avoid warning C4996: Use checked iterators under SECURE_SCL - std::copy(src, srcEnd, stdext::checked_array_iterator<_CharType *>(wbegin(), static_cast(avail))); -#else - std::copy(src, srcEnd, wbegin()); -#endif // _WIN32 + // The data store + _CharType* m_data; - update_write_head(countWritten); - return countWritten; - } + // Pointer to the read head + _CharType* rbegin() { return m_data + m_read; } - void update_write_head(size_t count) - { - m_pos += count; - } + // Pointer to the write head + _CharType* wbegin() { return m_data + m_pos; } - size_t rd_chars_left() const { return m_pos-m_read; } - size_t wr_chars_left() const { return m_size-m_pos; } + // Read up to count characters from the block + size_t read(_Out_writes_(count) _CharType* dest, _In_ size_t count, bool advance = true) + { + msl::safeint3::SafeInt avail(rd_chars_left()); + auto countRead = static_cast(avail.Min(count)); - private: + _CharType* beg = rbegin(); + _CharType* end = rbegin() + countRead; - // Copy is not supported - _block(const _block&); - _block& operator=(const _block&); - }; +#ifdef _WIN32 + // Avoid warning C4996: Use checked iterators under SECURE_SCL + std::copy(beg, end, stdext::checked_array_iterator<_CharType*>(dest, count)); +#else + std::copy(beg, end, dest); +#endif // _WIN32 - /// - /// Represents a request on the stream buffer - typically reads - /// - class _request + if (advance) { - public: + m_read += countRead; + } - typedef std::function func_type; - _request(size_t count, const func_type& func) - : m_func(func), m_count(count) - { - } + return countRead; + } - void complete() - { - m_func(); - } + // Write count characters into the block + size_t write(const _CharType* src, size_t count) + { + msl::safeint3::SafeInt avail(wr_chars_left()); + auto countWritten = static_cast(avail.Min(count)); - size_t size() const - { - return m_count; - } + const _CharType* srcEnd = src + countWritten; - private: +#ifdef _WIN32 + // Avoid warning C4996: Use checked iterators under SECURE_SCL + std::copy(src, srcEnd, stdext::checked_array_iterator<_CharType*>(wbegin(), static_cast(avail))); +#else + std::copy(src, srcEnd, wbegin()); +#endif // _WIN32 - func_type m_func; - size_t m_count; - }; + update_write_head(countWritten); + return countWritten; + } - void enqueue_request(_request req) - { - pplx::extensibility::scoped_critical_section_t l(m_lock); - - if (can_satisfy(req.size())) - { - // We can immediately fulfill the request. - req.complete(); - } - else - { - // We must wait for data to arrive. - m_requests.push(req); - } - } + void update_write_head(size_t count) { m_pos += count; } - /// - /// Determine if the request can be satisfied. - /// - bool can_satisfy(size_t count) - { - return (m_synced > 0) || (this->in_avail() >= count) || !this->can_write(); - } + size_t rd_chars_left() const { return m_pos - m_read; } + size_t wr_chars_left() const { return m_size - m_pos; } - /// - /// Reads a byte from the stream and returns it as int_type. - /// Note: This routine shall only be called if can_satisfy() returned true. - /// - /// This should be called with the lock held - int_type read_byte(bool advance = true) - { - _CharType value; - auto read_size = this->read(&value, 1, advance); - return read_size == 1 ? static_cast(value) : traits::eof(); - } + private: + // Copy is not supported + _block(const _block&); + _block& operator=(const _block&); + }; - /// - /// Reads up to count characters into ptr and returns the count of characters copied. - /// The return value (actual characters copied) could be <= count. - /// Note: This routine shall only be called if can_satisfy() returned true. - /// - /// This should be called with the lock held - size_t read(_Out_writes_ (count) _CharType *ptr, _In_ size_t count, bool advance = true) - { - _ASSERTE(can_satisfy(count)); + /// + /// Represents a request on the stream buffer - typically reads + /// + class _request + { + public: + typedef std::function func_type; + _request(size_t count, const func_type& func) : m_func(func), m_count(count) {} - size_t read = 0; + void complete() { m_func(); } - for (auto iter = begin(m_blocks); iter != std::end(m_blocks); ++iter) - { - auto block = *iter; - auto read_from_block = block->read(ptr + read, count - read, advance); + size_t size() const { return m_count; } - read += read_from_block; + private: + func_type m_func; + size_t m_count; + }; - _ASSERTE(count >= read); - if (read == count) break; - } + void enqueue_request(_request req) + { + pplx::extensibility::scoped_critical_section_t l(m_lock); - if (advance) - { - update_read_head(read); - } + if (can_satisfy(req.size())) + { + // We can immediately fulfill the request. + req.complete(); + } + else + { + // We must wait for data to arrive. + m_requests.push(req); + } + } - return read; - } + /// + /// Determine if the request can be satisfied. + /// + bool can_satisfy(size_t count) { return (m_synced > 0) || (this->in_avail() >= count) || !this->can_write(); } - /// - /// Updates the read head by the specified offset - /// - /// This should be called with the lock held - void update_read_head(size_t count) - { - m_total -= count; - m_total_read += count; - - if ( m_synced > 0 ) - m_synced = (m_synced > count) ? (m_synced-count) : 0; - - // The block at the front is always the read head. - // Purge empty blocks so that the block at the front reflects the read head - while (!m_blocks.empty()) - { - // If front block is not empty - we are done - if (m_blocks.front()->rd_chars_left() > 0) break; - - // The block has no more data to be read. Relase the block - m_blocks.pop_front(); - } - } + /// + /// Reads a byte from the stream and returns it as int_type. + /// Note: This routine shall only be called if can_satisfy() returned true. + /// + /// This should be called with the lock held + int_type read_byte(bool advance = true) + { + _CharType value; + auto read_size = this->read(&value, 1, advance); + return read_size == 1 ? static_cast(value) : traits::eof(); + } - // The in/out mode for the buffer - std::ios_base::openmode m_mode; + /// + /// Reads up to count characters into ptr and returns the count of characters copied. + /// The return value (actual characters copied) could be <= count. + /// Note: This routine shall only be called if can_satisfy() returned true. + /// + /// This should be called with the lock held + size_t read(_Out_writes_(count) _CharType* ptr, _In_ size_t count, bool advance = true) + { + _ASSERTE(can_satisfy(count)); - // Default block size - msl::safeint3::SafeInt m_alloc_size; + size_t read = 0; - // Block used for alloc/commit - std::shared_ptr<_block> m_allocBlock; + for (auto iter = begin(m_blocks); iter != std::end(m_blocks); ++iter) + { + auto block = *iter; + auto read_from_block = block->read(ptr + read, count - read, advance); + + read += read_from_block; - // Total available data - size_t m_total; + _ASSERTE(count >= read); + if (read == count) break; + } - size_t m_total_read; - size_t m_total_written; + if (advance) + { + update_read_head(read); + } - // Keeps track of the number of chars that have been flushed but still - // remain to be consumed by a read operation. - size_t m_synced; + return read; + } - // The producer-consumer buffer is intended to be used concurrently by a reader - // and a writer, who are not coordinating their accesses to the buffer (coordination - // being what the buffer is for in the first place). Thus, we have to protect - // against some of the internal data elements against concurrent accesses - // and the possibility of inconsistent states. A simple non-recursive lock - // should be sufficient for those purposes. - pplx::extensibility::critical_section_t m_lock; + /// + /// Updates the read head by the specified offset + /// + /// This should be called with the lock held + void update_read_head(size_t count) + { + m_total -= count; + m_total_read += count; - // Memory blocks - std::deque> m_blocks; + if (m_synced > 0) m_synced = (m_synced > count) ? (m_synced - count) : 0; - // Queue of requests - std::queue<_request> m_requests; - }; + // The block at the front is always the read head. + // Purge empty blocks so that the block at the front reflects the read head + while (!m_blocks.empty()) + { + // If front block is not empty - we are done + if (m_blocks.front()->rd_chars_left() > 0) break; - } // namespace details + // The block has no more data to be read. Relase the block + m_blocks.pop_front(); + } + } + + // The in/out mode for the buffer + std::ios_base::openmode m_mode; + + // Default block size + msl::safeint3::SafeInt m_alloc_size; + + // Block used for alloc/commit + std::shared_ptr<_block> m_allocBlock; + + // Total available data + size_t m_total; + + size_t m_total_read; + size_t m_total_written; + + // Keeps track of the number of chars that have been flushed but still + // remain to be consumed by a read operation. + size_t m_synced; + + // The producer-consumer buffer is intended to be used concurrently by a reader + // and a writer, who are not coordinating their accesses to the buffer (coordination + // being what the buffer is for in the first place). Thus, we have to protect + // against some of the internal data elements against concurrent accesses + // and the possibility of inconsistent states. A simple non-recursive lock + // should be sufficient for those purposes. + pplx::extensibility::critical_section_t m_lock; + + // Memory blocks + std::deque> m_blocks; + + // Queue of requests + std::queue<_request> m_requests; +}; + +} // namespace details + +/// +/// The producer_consumer_buffer class serves as a memory-based steam buffer that supports both writing and reading +/// sequences of bytes. It can be used as a consumer/producer buffer. +/// +/// +/// The data type of the basic element of the producer_consumer_buffer. +/// +/// +/// This is a reference-counted version of basic_producer_consumer_buffer. +template +class producer_consumer_buffer : public streambuf<_CharType> +{ +public: + typedef _CharType char_type; /// - /// The producer_consumer_buffer class serves as a memory-based steam buffer that supports both writing and reading - /// sequences of bytes. It can be used as a consumer/producer buffer. + /// Create a producer_consumer_buffer. /// - /// - /// The data type of the basic element of the producer_consumer_buffer. - /// - /// - /// This is a reference-counted version of basic_producer_consumer_buffer. - template - class producer_consumer_buffer : public streambuf<_CharType> + /// The internal default block size. + producer_consumer_buffer(size_t alloc_size = 512) + : streambuf<_CharType>(std::make_shared>(alloc_size)) { - public: - typedef _CharType char_type; - - /// - /// Create a producer_consumer_buffer. - /// - /// The internal default block size. - producer_consumer_buffer(size_t alloc_size = 512) - : streambuf<_CharType>(std::make_shared>(alloc_size)) - { - } - }; + } +}; -}} // namespaces +} // namespace streams +} // namespace Concurrency -#endif \ No newline at end of file +#endif diff --git a/Release/include/cpprest/rawptrstream.h b/Release/include/cpprest/rawptrstream.h index fe6e930a59..2b0a97f86a 100644 --- a/Release/include/cpprest/rawptrstream.h +++ b/Release/include/cpprest/rawptrstream.h @@ -1,630 +1,598 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* This file defines a stream buffer that is based on a raw pointer and block size. Unlike a vector-based -* stream buffer, the buffer cannot be expanded or contracted, it has a fixed capacity. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * This file defines a stream buffer that is based on a raw pointer and block size. Unlike a vector-based + * stream buffer, the buffer cannot be expanded or contracted, it has a fixed capacity. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_RAWPTR_STREAMS_H #define CASA_RAWPTR_STREAMS_H -#include -#include +#include "cpprest/astreambuf.h" +#include "cpprest/streams.h" +#include "pplx/pplxtasks.h" #include #include +#include +#include -#include "pplx/pplxtasks.h" -#include "cpprest/astreambuf.h" -#include "cpprest/streams.h" +namespace Concurrency +{ +namespace streams +{ +// Forward declarations +template +class rawptr_buffer; + +namespace details +{ +/// +/// The basic_rawptr_buffer class serves as a memory-based steam buffer that supports both writing and reading +/// sequences of characters to and from a fixed-size block. +/// +template +class basic_rawptr_buffer : public streams::details::streambuf_state_manager<_CharType> +{ +public: + typedef _CharType char_type; + + typedef typename basic_streambuf<_CharType>::traits traits; + typedef typename basic_streambuf<_CharType>::int_type int_type; + typedef typename basic_streambuf<_CharType>::pos_type pos_type; + typedef typename basic_streambuf<_CharType>::off_type off_type; -namespace Concurrency { namespace streams { + /// + /// Constructor + /// + basic_rawptr_buffer() + : streambuf_state_manager<_CharType>(std::ios_base::in | std::ios_base::out) + , m_data(nullptr) + , m_current_position(0) + , m_size(0) + { + } - // Forward declarations - template class rawptr_buffer; + /// + /// Destructor + /// + virtual ~basic_rawptr_buffer() + { + this->_close_read(); + this->_close_write(); + } - namespace details { +protected: + /// + /// can_seek is used to determine whether a stream buffer supports seeking. + /// + virtual bool can_seek() const { return this->is_open(); } /// - /// The basic_rawptr_buffer class serves as a memory-based steam buffer that supports both writing and reading - /// sequences of characters to and from a fixed-size block. + /// has_size is used to determine whether a stream buffer supports size(). /// - template - class basic_rawptr_buffer : public streams::details::streambuf_state_manager<_CharType> - { - public: - typedef _CharType char_type; - - typedef typename basic_streambuf<_CharType>::traits traits; - typedef typename basic_streambuf<_CharType>::int_type int_type; - typedef typename basic_streambuf<_CharType>::pos_type pos_type; - typedef typename basic_streambuf<_CharType>::off_type off_type; - - /// - /// Constructor - /// - basic_rawptr_buffer() - : streambuf_state_manager<_CharType>(std::ios_base::in | std::ios_base::out), - m_data(nullptr), - m_current_position(0), - m_size(0) - { - } + virtual bool has_size() const { return this->is_open(); } - /// - /// Destructor - /// - virtual ~basic_rawptr_buffer() - { - this->_close_read(); - this->_close_write(); - } + /// + /// Gets the size of the stream, if known. Calls to has_size will determine whether + /// the result of size can be relied on. + /// + virtual utility::size64_t size() const { return utility::size64_t(m_size); } - protected: + /// + /// Get the stream buffer size, if one has been set. + /// + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will always return '0'. + virtual size_t buffer_size(std::ios_base::openmode = std::ios_base::in) const { return 0; } - /// - /// can_seek is used to determine whether a stream buffer supports seeking. - /// - virtual bool can_seek() const { return this->is_open(); } + /// + /// Set the stream buffer implementation to buffer or not buffer. + /// + /// The size to use for internal buffering, 0 if no buffering should be done. + /// The direction of buffering (in or out) + /// An implementation that does not support buffering will silently ignore calls to this function and it + /// will not have + /// any effect on what is returned by subsequent calls to buffer_size(). + virtual void set_buffer_size(size_t, std::ios_base::openmode = std::ios_base::in) { return; } - /// - /// has_size is used to determine whether a stream buffer supports size(). - /// - virtual bool has_size() const { return this->is_open(); } + /// + /// For any input stream, in_avail returns the number of characters that are immediately available + /// to be consumed without blocking. May be used in conjunction with and sgetn() to + /// read data without incurring the overhead of using tasks. + /// + virtual size_t in_avail() const + { + // See the comment in seek around the restiction that we do not allow read head to + // seek beyond the current size. + _ASSERTE(m_current_position <= m_size); - /// - /// Gets the size of the stream, if known. Calls to has_size will determine whether - /// the result of size can be relied on. - /// - virtual utility::size64_t size() const - { - return utility::size64_t(m_size); - } + msl::safeint3::SafeInt readhead(m_current_position); + msl::safeint3::SafeInt writeend(m_size); + return (size_t)(writeend - readhead); + } - /// - /// Get the stream buffer size, if one has been set. - /// - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will always return '0'. - virtual size_t buffer_size(std::ios_base::openmode = std::ios_base::in) const + /// + /// Closes the stream buffer, preventing further read or write operations. + /// + /// The I/O mode (in or out) to close for. + virtual pplx::task close(std::ios_base::openmode mode) + { + if (mode & std::ios_base::in) { - return 0; + this->_close_read().get(); // Safe to call get() here. } - /// - /// Set the stream buffer implementation to buffer or not buffer. - /// - /// The size to use for internal buffering, 0 if no buffering should be done. - /// The direction of buffering (in or out) - /// An implementation that does not support buffering will silently ignore calls to this function and it will not have - /// any effect on what is returned by subsequent calls to buffer_size(). - virtual void set_buffer_size(size_t , std::ios_base::openmode = std::ios_base::in) + if (mode & std::ios_base::out) { - return; + this->_close_write().get(); // Safe to call get() here. } - /// - /// For any input stream, in_avail returns the number of characters that are immediately available - /// to be consumed without blocking. May be used in conjunction with and sgetn() to - /// read data without incurring the overhead of using tasks. - /// - virtual size_t in_avail() const + if (!this->can_read() && !this->can_write()) { - // See the comment in seek around the restiction that we do not allow read head to - // seek beyond the current size. - _ASSERTE(m_current_position <= m_size); - - msl::safeint3::SafeInt readhead(m_current_position); - msl::safeint3::SafeInt writeend(m_size); - return (size_t)(writeend - readhead); + m_data = nullptr; } - /// - /// Closes the stream buffer, preventing further read or write operations. - /// - /// The I/O mode (in or out) to close for. - virtual pplx::task close(std::ios_base::openmode mode) - { - if (mode & std::ios_base::in) - { - this->_close_read().get(); // Safe to call get() here. - } + // Exceptions will be propagated out of _close_read or _close_write + return pplx::task_from_result(); + } - if (mode & std::ios_base::out) - { - this->_close_write().get(); // Safe to call get() here. - } + virtual pplx::task _sync() { return pplx::task_from_result(true); } - if ( !this->can_read() && !this->can_write() ) - { - m_data = nullptr; - } + virtual pplx::task _putc(_CharType ch) + { + if (m_current_position >= m_size) return pplx::task_from_result(traits::eof()); + int_type retVal = (this->write(&ch, 1) == 1) ? static_cast(ch) : traits::eof(); + return pplx::task_from_result(retVal); + } - // Exceptions will be propagated out of _close_read or _close_write - return pplx::task_from_result(); - } + virtual pplx::task _putn(const _CharType* ptr, size_t count) + { + msl::safeint3::SafeInt newSize = msl::safeint3::SafeInt(count) + m_current_position; + if (newSize > m_size) + return pplx::task_from_exception( + std::make_exception_ptr(std::runtime_error("Writing past the end of the buffer"))); + return pplx::task_from_result(this->write(ptr, count)); + } - virtual pplx::task _sync() - { - return pplx::task_from_result(true); - } + /// + /// Allocates a contiguous memory block and returns it. + /// + /// The number of characters to allocate. + /// A pointer to a block to write to, null if the stream buffer implementation does not support + /// alloc/commit. + _CharType* _alloc(size_t count) + { + if (!this->can_write()) return nullptr; - virtual pplx::task _putc(_CharType ch) - { - if (m_current_position >= m_size) - return pplx::task_from_result(traits::eof()); - int_type retVal = (this->write(&ch, 1) == 1) ? static_cast(ch) : traits::eof(); - return pplx::task_from_result(retVal); - } + msl::safeint3::SafeInt readhead(m_current_position); + msl::safeint3::SafeInt writeend(m_size); + size_t space_left = (size_t)(writeend - readhead); - virtual pplx::task _putn(const _CharType *ptr, size_t count) - { - msl::safeint3::SafeInt newSize = msl::safeint3::SafeInt(count) + m_current_position; - if ( newSize > m_size ) - return pplx::task_from_exception(std::make_exception_ptr(std::runtime_error("Writing past the end of the buffer"))); - return pplx::task_from_result(this->write(ptr, count)); - } + if (space_left < count) return nullptr; - /// - /// Allocates a contiguous memory block and returns it. - /// - /// The number of characters to allocate. - /// A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit. - _CharType* _alloc(size_t count) - { - if (!this->can_write()) return nullptr; + // Let the caller copy the data + return (_CharType*)(m_data + m_current_position); + } - msl::safeint3::SafeInt readhead(m_current_position); - msl::safeint3::SafeInt writeend(m_size); - size_t space_left = (size_t)(writeend - readhead); + /// + /// Submits a block already allocated by the stream buffer. + /// + /// The number of characters to be committed. + void _commit(size_t actual) + { + // Update the write position and satisfy any pending reads + update_current_position(m_current_position + actual); + } - if (space_left < count) return nullptr; + /// + /// Gets a pointer to the next already allocated contiguous block of data. + /// + /// A reference to a pointer variable that will hold the address of the block on success. + /// The number of contiguous characters available at the address in 'ptr'. + /// true if the operation succeeded, false otherwise. + /// + /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that + /// there is no block to return immediately or that the stream buffer does not support the operation. + /// The stream buffer may not de-allocate the block until is called. + /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; + /// a subsequent read will not succeed. + /// + virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) + { + count = 0; + ptr = nullptr; - // Let the caller copy the data - return (_CharType*)(m_data+m_current_position); - } + if (!this->can_read()) return false; + + count = in_avail(); - /// - /// Submits a block already allocated by the stream buffer. - /// - /// The number of characters to be committed. - void _commit(size_t actual) + if (count > 0) { - // Update the write position and satisfy any pending reads - update_current_position(m_current_position+actual); + ptr = (_CharType*)(m_data + m_current_position); + return true; } - - /// - /// Gets a pointer to the next already allocated contiguous block of data. - /// - /// A reference to a pointer variable that will hold the address of the block on success. - /// The number of contiguous characters available at the address in 'ptr'. - /// true if the operation succeeded, false otherwise. - /// - /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that - /// there is no block to return immediately or that the stream buffer does not support the operation. - /// The stream buffer may not de-allocate the block until is called. - /// If the end of the stream is reached, the function will return true, a null pointer, and a count of zero; - /// a subsequent read will not succeed. - /// - virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) + else { - count = 0; ptr = nullptr; - if (!this->can_read()) return false; - - count = in_avail(); + // Can only be open for read OR write, not both. If there is no data then + // we have reached the end of the stream so indicate such with true. + return true; + } + } - if (count > 0) - { - ptr = (_CharType*)(m_data+m_current_position); - return true; - } - else - { - ptr = nullptr; + /// + /// Releases a block of data acquired using . This frees the stream buffer to + /// de-allocate the memory, if it so desires. Move the read position ahead by the count. + /// + /// A pointer to the block of data to be released. + /// The number of characters that were read. + virtual void release(_Out_writes_opt_(count) _CharType* ptr, _In_ size_t count) + { + if (ptr != nullptr) update_current_position(m_current_position + count); + } - // Can only be open for read OR write, not both. If there is no data then - // we have reached the end of the stream so indicate such with true. - return true; - } - } + virtual pplx::task _getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + return pplx::task_from_result(this->read(ptr, count)); + } - /// - /// Releases a block of data acquired using . This frees the stream buffer to de-allocate the - /// memory, if it so desires. Move the read position ahead by the count. - /// - /// A pointer to the block of data to be released. - /// The number of characters that were read. - virtual void release(_Out_writes_opt_ (count) _CharType *ptr, _In_ size_t count) - { - if (ptr != nullptr) - update_current_position(m_current_position + count); - } + size_t _sgetn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) { return this->read(ptr, count); } - virtual pplx::task _getn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - return pplx::task_from_result(this->read(ptr, count)); - } + virtual size_t _scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + return this->read(ptr, count, false); + } - size_t _sgetn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - return this->read(ptr, count); - } + virtual pplx::task _bumpc() { return pplx::task_from_result(this->read_byte(true)); } - virtual size_t _scopy(_Out_writes_ (count) _CharType *ptr, _In_ size_t count) - { - return this->read(ptr, count, false); - } + virtual int_type _sbumpc() { return this->read_byte(true); } - virtual pplx::task _bumpc() - { - return pplx::task_from_result(this->read_byte(true)); - } + virtual pplx::task _getc() { return pplx::task_from_result(this->read_byte(false)); } - virtual int_type _sbumpc() - { - return this->read_byte(true); - } + int_type _sgetc() { return this->read_byte(false); } - virtual pplx::task _getc() - { - return pplx::task_from_result(this->read_byte(false)); - } + virtual pplx::task _nextc() + { + if (m_current_position >= m_size - 1) return pplx::task_from_result(basic_streambuf<_CharType>::traits::eof()); - int_type _sgetc() - { - return this->read_byte(false); - } + this->read_byte(true); + return pplx::task_from_result(this->read_byte(false)); + } - virtual pplx::task _nextc() - { - if (m_current_position >= m_size-1) - return pplx::task_from_result(basic_streambuf<_CharType>::traits::eof()); + virtual pplx::task _ungetc() + { + auto pos = seekoff(-1, std::ios_base::cur, std::ios_base::in); + if (pos == (pos_type)traits::eof()) return pplx::task_from_result(traits::eof()); + return this->getc(); + } - this->read_byte(true); - return pplx::task_from_result(this->read_byte(false)); - } + /// + /// Gets the current read or write position in the stream. + /// + /// The I/O direction to seek (see remarks) + /// The current position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the direction parameter defines whether to move the read or the write + /// cursor. + virtual pos_type getpos(std::ios_base::openmode mode) const + { + if (((mode & std::ios_base::in) && !this->can_read()) || ((mode & std::ios_base::out) && !this->can_write())) + return static_cast(traits::eof()); - virtual pplx::task _ungetc() - { - auto pos = seekoff(-1, std::ios_base::cur, std::ios_base::in); - if ( pos == (pos_type)traits::eof()) - return pplx::task_from_result(traits::eof()); - return this->getc(); - } + if (mode == std::ios_base::in) + return (pos_type)m_current_position; + else if (mode == std::ios_base::out) + return (pos_type)m_current_position; + else + return (pos_type)traits::eof(); + } - /// - /// Gets the current read or write position in the stream. - /// - /// The I/O direction to seek (see remarks) - /// The current position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual pos_type getpos(std::ios_base::openmode mode) const - { - if ( ((mode & std::ios_base::in) && !this->can_read()) || - ((mode & std::ios_base::out) && !this->can_write())) - return static_cast(traits::eof()); - - if (mode == std::ios_base::in) - return (pos_type)m_current_position; - else if (mode == std::ios_base::out) - return (pos_type)m_current_position; - else - return (pos_type)traits::eof(); - } + /// + /// Seeks to the given position. + /// + /// The offset from the beginning of the stream. + /// The I/O direction to seek (see remarks). + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. For such streams, the direction parameter + /// defines whether to move the read or the write cursor. + virtual pos_type seekpos(pos_type position, std::ios_base::openmode mode) + { + pos_type beg(0); + pos_type end(m_size); - /// - /// Seeks to the given position. - /// - /// The offset from the beginning of the stream. - /// The I/O direction to seek (see remarks). - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. For such streams, the direction parameter defines whether to move the read or the write cursor. - virtual pos_type seekpos(pos_type position, std::ios_base::openmode mode) + if (position >= beg) { - pos_type beg(0); - pos_type end(m_size); + auto pos = static_cast(position); - if (position >= beg) + // Read head + if ((mode & std::ios_base::in) && this->can_read()) { - auto pos = static_cast(position); - - // Read head - if ((mode & std::ios_base::in) && this->can_read()) + if (position <= end) { - if (position <= end) - { - // We do not allow reads to seek beyond the end or before the start position. - update_current_position(pos); - return static_cast(m_current_position); - } - } - - // Write head - if ((mode & std::ios_base::out) && this->can_write()) - { - // Update write head and satisfy read requests if any + // We do not allow reads to seek beyond the end or before the start position. update_current_position(pos); - return static_cast(m_current_position); } } - return static_cast(traits::eof()); - } - - /// - /// Seeks to a position given by a relative offset. - /// - /// The relative position to seek to - /// The starting point (beginning, end, current) for the seek. - /// The I/O direction to seek (see remarks) - /// The position. EOF if the operation fails. - /// Some streams may have separate write and read cursors. - /// For such streams, the mode parameter defines whether to move the read or the write cursor. - virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) - { - pos_type beg = 0; - pos_type cur = static_cast(m_current_position); - pos_type end = static_cast(m_size); - - switch ( way ) + // Write head + if ((mode & std::ios_base::out) && this->can_write()) { - case std::ios_base::beg: - return seekpos(beg + offset, mode); - - case std::ios_base::cur: - return seekpos(cur + offset, mode); + // Update write head and satisfy read requests if any + update_current_position(pos); - case std::ios_base::end: - return seekpos(end + offset, mode); - - default: - return static_cast(traits::eof()); + return static_cast(m_current_position); } } - private: - template friend class ::concurrency::streams::rawptr_buffer; - - /// - /// Constructor - /// - /// The address (pointer to) the memory block. - /// The memory block size, measured in number of characters. - basic_rawptr_buffer(const _CharType* data, size_t size) - : streambuf_state_manager<_CharType>(std::ios_base::in), - m_data(const_cast<_CharType*>(data)), - m_size(size), - m_current_position(0) - { - validate_mode(std::ios_base::in); - } + return static_cast(traits::eof()); + } - /// - /// Constructor - /// - /// The address (pointer to) the memory block. - /// The memory block size, measured in number of characters. - /// The stream mode (in, out, etc.). - basic_rawptr_buffer(_CharType* data, size_t size, std::ios_base::openmode mode) - : streambuf_state_manager<_CharType>(mode), - m_data(data), - m_size(size), - m_current_position(0) - { - validate_mode(mode); - } + /// + /// Seeks to a position given by a relative offset. + /// + /// The relative position to seek to + /// The starting point (beginning, end, current) for the seek. + /// The I/O direction to seek (see remarks) + /// The position. EOF if the operation fails. + /// Some streams may have separate write and read cursors. + /// For such streams, the mode parameter defines whether to move the read or the write cursor. + virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) + { + pos_type beg = 0; + pos_type cur = static_cast(m_current_position); + pos_type end = static_cast(m_size); - static void validate_mode(std::ios_base::openmode mode) + switch (way) { - // Disallow simultaneous use of the stream buffer for writing and reading. - if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) - throw std::invalid_argument("this combination of modes on raw pointer stream not supported"); - } + case std::ios_base::beg: return seekpos(beg + offset, mode); - /// - /// Determines if the request can be satisfied. - /// - bool can_satisfy(size_t) const - { - // We can always satisfy a read, at least partially, unless the - // read position is at the very end of the buffer. - return (in_avail() > 0); - } + case std::ios_base::cur: return seekpos(cur + offset, mode); - /// - /// Reads a byte from the stream and returns it as int_type. - /// Note: This routine must only be called if can_satisfy() returns true. - /// - int_type read_byte(bool advance = true) - { - _CharType value; - auto read_size = this->read(&value, 1, advance); - return read_size == 1 ? static_cast(value) : traits::eof(); + case std::ios_base::end: return seekpos(end + offset, mode); + + default: return static_cast(traits::eof()); } + } - /// - /// Reads up to count characters into ptr and returns the count of characters copied. - /// The return value (actual characters copied) could be <= count. - /// Note: This routine must only be called if can_satisfy() returns true. - /// - size_t read(_Out_writes_ (count) _CharType *ptr, _In_ size_t count, bool advance = true) - { - if (!can_satisfy(count)) - return 0; +private: + template + friend class ::concurrency::streams::rawptr_buffer; - msl::safeint3::SafeInt request_size(count); - msl::safeint3::SafeInt read_size = request_size.Min(in_avail()); + /// + /// Constructor + /// + /// The address (pointer to) the memory block. + /// The memory block size, measured in number of characters. + basic_rawptr_buffer(const _CharType* data, size_t size) + : streambuf_state_manager<_CharType>(std::ios_base::in) + , m_data(const_cast<_CharType*>(data)) + , m_size(size) + , m_current_position(0) + { + validate_mode(std::ios_base::in); + } - size_t newPos = m_current_position + read_size; + /// + /// Constructor + /// + /// The address (pointer to) the memory block. + /// The memory block size, measured in number of characters. + /// The stream mode (in, out, etc.). + basic_rawptr_buffer(_CharType* data, size_t size, std::ios_base::openmode mode) + : streambuf_state_manager<_CharType>(mode), m_data(data), m_size(size), m_current_position(0) + { + validate_mode(mode); + } - auto readBegin = m_data + m_current_position; - auto readEnd = m_data + newPos; + static void validate_mode(std::ios_base::openmode mode) + { + // Disallow simultaneous use of the stream buffer for writing and reading. + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + throw std::invalid_argument("this combination of modes on raw pointer stream not supported"); + } -#ifdef _WIN32 - // Avoid warning C4996: Use checked iterators under SECURE_SCL - std::copy(readBegin, readEnd, stdext::checked_array_iterator<_CharType *>(ptr, count)); -#else - std::copy(readBegin, readEnd, ptr); -#endif // _WIN32 + /// + /// Determines if the request can be satisfied. + /// + bool can_satisfy(size_t) const + { + // We can always satisfy a read, at least partially, unless the + // read position is at the very end of the buffer. + return (in_avail() > 0); + } - if (advance) - { - update_current_position(newPos); - } + /// + /// Reads a byte from the stream and returns it as int_type. + /// Note: This routine must only be called if can_satisfy() returns true. + /// + int_type read_byte(bool advance = true) + { + _CharType value; + auto read_size = this->read(&value, 1, advance); + return read_size == 1 ? static_cast(value) : traits::eof(); + } - return (size_t) read_size; - } + /// + /// Reads up to count characters into ptr and returns the count of characters copied. + /// The return value (actual characters copied) could be <= count. + /// Note: This routine must only be called if can_satisfy() returns true. + /// + size_t read(_Out_writes_(count) _CharType* ptr, _In_ size_t count, bool advance = true) + { + if (!can_satisfy(count)) return 0; - /// - /// Write count characters from the ptr into the stream buffer - /// - size_t write(const _CharType *ptr, size_t count) - { - if (!this->can_write() || (count == 0)) return 0; + msl::safeint3::SafeInt request_size(count); + msl::safeint3::SafeInt read_size = request_size.Min(in_avail()); - msl::safeint3::SafeInt newSize = msl::safeint3::SafeInt(count) +m_current_position; + size_t newPos = m_current_position + read_size; - if ( newSize > m_size ) - throw std::runtime_error("Writing past the end of the buffer"); + auto readBegin = m_data + m_current_position; + auto readEnd = m_data + newPos; - // Copy the data #ifdef _WIN32 - // Avoid warning C4996: Use checked iterators under SECURE_SCL - std::copy(ptr, ptr + count, stdext::checked_array_iterator<_CharType *>(m_data, m_size, m_current_position)); + // Avoid warning C4996: Use checked iterators under SECURE_SCL + std::copy(readBegin, readEnd, stdext::checked_array_iterator<_CharType*>(ptr, count)); #else - std::copy(ptr, ptr + count, m_data+m_current_position); + std::copy(readBegin, readEnd, ptr); #endif // _WIN32 - // Update write head and satisfy pending reads if any - update_current_position(newSize); - - return count; + if (advance) + { + update_current_position(newPos); } - /// - /// Updates the current read or write position - /// - void update_current_position(size_t newPos) - { - // The new write head - m_current_position = newPos; + return (size_t)read_size; + } - _ASSERTE(m_current_position <= m_size); - } + /// + /// Write count characters from the ptr into the stream buffer + /// + size_t write(const _CharType* ptr, size_t count) + { + if (!this->can_write() || (count == 0)) return 0; + + msl::safeint3::SafeInt newSize = msl::safeint3::SafeInt(count) + m_current_position; - // The actual memory block - _CharType* m_data; + if (newSize > m_size) throw std::runtime_error("Writing past the end of the buffer"); - // The size of the memory block - size_t m_size; + // Copy the data +#ifdef _WIN32 + // Avoid warning C4996: Use checked iterators under SECURE_SCL + std::copy(ptr, ptr + count, stdext::checked_array_iterator<_CharType*>(m_data, m_size, m_current_position)); +#else + std::copy(ptr, ptr + count, m_data + m_current_position); +#endif // _WIN32 - // Read/write head - size_t m_current_position; - }; + // Update write head and satisfy pending reads if any + update_current_position(newSize); - } // namespace details + return count; + } /// - /// The rawptr_buffer class serves as a memory-based stream buffer that supports reading - /// sequences of characters to or from a fixed-size block. Note that it cannot be used simultaneously for reading as well as writing. + /// Updates the current read or write position /// - /// - /// The data type of the basic element of the rawptr_buffer. - /// - template - class rawptr_buffer : public streambuf<_CharType> + void update_current_position(size_t newPos) { - public: - typedef _CharType char_type; - - /// - /// Create a rawptr_buffer given a pointer to a memory block and the size of the block. - /// - /// The address (pointer to) the memory block. - /// The memory block size, measured in number of characters. - rawptr_buffer(const char_type* data, size_t size) - : streambuf(std::shared_ptr>(new details::basic_rawptr_buffer(data, size))) - { - } + // The new write head + m_current_position = newPos; + + _ASSERTE(m_current_position <= m_size); + } + + // The actual memory block + _CharType* m_data; + + // The size of the memory block + size_t m_size; + + // Read/write head + size_t m_current_position; +}; + +} // namespace details + +/// +/// The rawptr_buffer class serves as a memory-based stream buffer that supports reading +/// sequences of characters to or from a fixed-size block. Note that it cannot be used simultaneously for reading as +/// well as writing. +/// +/// +/// The data type of the basic element of the rawptr_buffer. +/// +template +class rawptr_buffer : public streambuf<_CharType> +{ +public: + typedef _CharType char_type; - /// - /// Create a rawptr_buffer given a pointer to a memory block and the size of the block. - /// - /// The address (pointer to) the memory block. - /// The memory block size, measured in number of characters. - rawptr_buffer(char_type* data, size_t size, std::ios_base::openmode mode = std::ios::out) - : streambuf(std::shared_ptr>(new details::basic_rawptr_buffer(data, size, mode))) - { - } + /// + /// Create a rawptr_buffer given a pointer to a memory block and the size of the block. + /// + /// The address (pointer to) the memory block. + /// The memory block size, measured in number of characters. + rawptr_buffer(const char_type* data, size_t size) + : streambuf(std::shared_ptr>( + new details::basic_rawptr_buffer(data, size))) + { + } - /// - /// Default constructor. - /// - rawptr_buffer() - { - } - }; + /// + /// Create a rawptr_buffer given a pointer to a memory block and the size of the block. + /// + /// The address (pointer to) the memory block. + /// The memory block size, measured in number of characters. + rawptr_buffer(char_type* data, size_t size, std::ios_base::openmode mode = std::ios::out) + : streambuf(std::shared_ptr>( + new details::basic_rawptr_buffer(data, size, mode))) + { + } + + /// + /// Default constructor. + /// + rawptr_buffer() {} +}; + +/// +/// The rawptr_stream class is used to create memory-backed streams that support writing or reading +/// sequences of characters to / from a fixed-size block. +/// +/// +/// The data type of the basic element of the rawptr_stream. +/// +template +class rawptr_stream +{ +public: + typedef _CharType char_type; + typedef rawptr_buffer<_CharType> buffer_type; /// - /// The rawptr_stream class is used to create memory-backed streams that support writing or reading - /// sequences of characters to / from a fixed-size block. + /// Create a rawptr-stream given a pointer to a read-only memory block and the size of the block. /// - /// - /// The data type of the basic element of the rawptr_stream. - /// - template - class rawptr_stream + /// The address (pointer to) the memory block. + /// The memory block size, measured in number of characters. + /// An opened input stream. + static concurrency::streams::basic_istream open_istream(const char_type* data, size_t size) { - public: - typedef _CharType char_type; - typedef rawptr_buffer<_CharType> buffer_type; - - /// - /// Create a rawptr-stream given a pointer to a read-only memory block and the size of the block. - /// - /// The address (pointer to) the memory block. - /// The memory block size, measured in number of characters. - /// An opened input stream. - static concurrency::streams::basic_istream open_istream(const char_type* data, size_t size) - { - return concurrency::streams::basic_istream(buffer_type(data, size)); - } + return concurrency::streams::basic_istream(buffer_type(data, size)); + } - /// - /// Create a rawptr-stream given a pointer to a writable memory block and the size of the block. - /// - /// The address (pointer to) the memory block. - /// The memory block size, measured in number of characters. - /// An opened input stream. - static concurrency::streams::basic_istream open_istream(char_type* data, size_t size) - { - return concurrency::streams::basic_istream(buffer_type(data, size, std::ios::in)); - } + /// + /// Create a rawptr-stream given a pointer to a writable memory block and the size of the block. + /// + /// The address (pointer to) the memory block. + /// The memory block size, measured in number of characters. + /// An opened input stream. + static concurrency::streams::basic_istream open_istream(char_type* data, size_t size) + { + return concurrency::streams::basic_istream(buffer_type(data, size, std::ios::in)); + } - /// - /// Create a rawptr-stream given a pointer to a writable memory block and the size of the block. - /// - /// The address (pointer to) the memory block. - /// The memory block size, measured in number of characters. - /// An opened output stream. - static concurrency::streams::basic_ostream open_ostream(char_type* data, size_t size) - { - return concurrency::streams::basic_ostream(buffer_type(data, size, std::ios::out)); - } - }; + /// + /// Create a rawptr-stream given a pointer to a writable memory block and the size of the block. + /// + /// The address (pointer to) the memory block. + /// The memory block size, measured in number of characters. + /// An opened output stream. + static concurrency::streams::basic_ostream open_ostream(char_type* data, size_t size) + { + return concurrency::streams::basic_ostream(buffer_type(data, size, std::ios::out)); + } +}; -}} // namespaces +} // namespace streams +} // namespace Concurrency #endif diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index cf3ceb1140..bfeeee5885 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Asynchronous I/O: streams API, used for formatted input and output, based on unformatted I/O using stream buffers -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Asynchronous I/O: streams API, used for formatted input and output, based on unformatted I/O using stream buffers + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_STREAMS_H @@ -18,946 +18,935 @@ #include "cpprest/astreambuf.h" #include -namespace Concurrency { namespace streams +namespace Concurrency { - template class basic_ostream; - template class basic_istream; +namespace streams +{ +template +class basic_ostream; +template +class basic_istream; - namespace details { - template - class basic_ostream_helper - { - public: - basic_ostream_helper(streams::streambuf buffer) : m_buffer(buffer) { } +namespace details +{ +template +class basic_ostream_helper +{ +public: + basic_ostream_helper(streams::streambuf buffer) : m_buffer(buffer) {} - ~basic_ostream_helper() { } + ~basic_ostream_helper() {} - private: - template friend class streams::basic_ostream; +private: + template + friend class streams::basic_ostream; - concurrency::streams::streambuf m_buffer; - }; + concurrency::streams::streambuf m_buffer; +}; - template - class basic_istream_helper - { - public: - basic_istream_helper(streams::streambuf buffer) : m_buffer(buffer) { } +template +class basic_istream_helper +{ +public: + basic_istream_helper(streams::streambuf buffer) : m_buffer(buffer) {} - ~basic_istream_helper() { } + ~basic_istream_helper() {} - private: - template friend class streams::basic_istream; +private: + template + friend class streams::basic_istream; - concurrency::streams::streambuf m_buffer; - }; + concurrency::streams::streambuf m_buffer; +}; - template - struct Value2StringFormatter - { - template - static std::basic_string format(const T &val) - { - std::basic_ostringstream ss; - ss << val; - return ss.str(); - } - }; +template +struct Value2StringFormatter +{ + template + static std::basic_string format(const T& val) + { + std::basic_ostringstream ss; + ss << val; + return ss.str(); + } +}; - template <> - struct Value2StringFormatter - { - template - static std::basic_string format(const T &val) - { - std::basic_ostringstream ss; - ss << val; - return reinterpret_cast(ss.str().c_str()); - } +template<> +struct Value2StringFormatter +{ + template + static std::basic_string format(const T& val) + { + std::basic_ostringstream ss; + ss << val; + return reinterpret_cast(ss.str().c_str()); + } - static std::basic_string format(const utf16string &val) - { - return format(utility::conversions::utf16_to_utf8(val)); - } + static std::basic_string format(const utf16string& val) + { + return format(utility::conversions::utf16_to_utf8(val)); + } +}; - }; +static const char* _in_stream_msg = "stream not set up for input of data"; +static const char* _in_streambuf_msg = "stream buffer not set up for input of data"; +static const char* _out_stream_msg = "stream not set up for output of data"; +static const char* _out_streambuf_msg = "stream buffer not set up for output of data"; +} // namespace details - static const char *_in_stream_msg = "stream not set up for input of data"; - static const char *_in_streambuf_msg = "stream buffer not set up for input of data"; - static const char *_out_stream_msg = "stream not set up for output of data"; - static const char *_out_streambuf_msg = "stream buffer not set up for output of data"; +/// +/// Base interface for all asynchronous output streams. +/// +template +class basic_ostream +{ +public: + typedef char_traits traits; + typedef typename traits::int_type int_type; + typedef typename traits::pos_type pos_type; + typedef typename traits::off_type off_type; + + /// + /// Default constructor + /// + basic_ostream() {} + + /// + /// Copy constructor + /// + /// The source object + basic_ostream(const basic_ostream& other) : m_helper(other.m_helper) {} + + /// + /// Assignment operator + /// + /// The source object + /// A reference to the stream object that contains the result of the assignment. + basic_ostream& operator=(const basic_ostream& other) + { + m_helper = other.m_helper; + return *this; } /// - /// Base interface for all asynchronous output streams. + /// Constructor /// - template - class basic_ostream - { - public: - typedef char_traits traits; - typedef typename traits::int_type int_type; - typedef typename traits::pos_type pos_type; - typedef typename traits::off_type off_type; - - /// - /// Default constructor - /// - basic_ostream() {} - - /// - /// Copy constructor - /// - /// The source object - basic_ostream(const basic_ostream &other) : m_helper(other.m_helper) { } - - /// - /// Assignment operator - /// - /// The source object - /// A reference to the stream object that contains the result of the assignment. - basic_ostream & operator =(const basic_ostream &other) { m_helper = other.m_helper; return *this; } - - /// - /// Constructor - /// - /// A stream buffer. - basic_ostream(streams::streambuf buffer) : - m_helper(std::make_shared>(buffer)) - { - _verify_and_throw(details::_out_streambuf_msg); - } + /// A stream buffer. + basic_ostream(streams::streambuf buffer) + : m_helper(std::make_shared>(buffer)) + { + _verify_and_throw(details::_out_streambuf_msg); + } - /// - /// Close the stream, preventing further write operations. - /// - pplx::task close() const - { - return is_valid() ? - helper()->m_buffer.close(std::ios_base::out) : - pplx::task_from_result(); - } + /// + /// Close the stream, preventing further write operations. + /// + pplx::task close() const + { + return is_valid() ? helper()->m_buffer.close(std::ios_base::out) : pplx::task_from_result(); + } - /// - /// Close the stream with exception, preventing further write operations. - /// - /// Pointer to the exception. - pplx::task close(std::exception_ptr eptr) const - { - return is_valid() ? - helper()->m_buffer.close(std::ios_base::out, eptr) : - pplx::task_from_result(); - } + /// + /// Close the stream with exception, preventing further write operations. + /// + /// Pointer to the exception. + pplx::task close(std::exception_ptr eptr) const + { + return is_valid() ? helper()->m_buffer.close(std::ios_base::out, eptr) : pplx::task_from_result(); + } - /// - /// Put a single character into the stream. - /// - /// A character - pplx::task write(CharType ch) const - { - pplx::task result; - if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result; - return helper()->m_buffer.putc(ch); - } + /// + /// Put a single character into the stream. + /// + /// A character + pplx::task write(CharType ch) const + { + pplx::task result; + if (!_verify_and_return_task(details::_out_stream_msg, result)) return result; + return helper()->m_buffer.putc(ch); + } - /// - /// Write a single value of "blittable" type T into the stream. - /// - /// A value of type T. - /// - /// This is not a replacement for a proper binary serialization solution, but it may - /// form the foundation for one. Writing data bit-wise to a stream is a primitive - /// operation of binary serialization. - /// Currently, no attention is paid to byte order. All data is written in the platform's - /// native byte order, which means little-endian on all platforms that have been tested. - /// This function is only available for streams using a single-byte character size. - /// - template - CASABLANCA_DEPRECATED("Unsafe API that will be removed in future releases, use one of the other write overloads instead.") - pplx::task write(T value) const - { - static_assert(sizeof(CharType) == 1, "binary write is only supported for single-byte streams"); - static_assert(std::is_trivial::value, "unsafe to use with non-trivial types"); + /// + /// Write a single value of "blittable" type T into the stream. + /// + /// A value of type T. + /// + /// This is not a replacement for a proper binary serialization solution, but it may + /// form the foundation for one. Writing data bit-wise to a stream is a primitive + /// operation of binary serialization. + /// Currently, no attention is paid to byte order. All data is written in the platform's + /// native byte order, which means little-endian on all platforms that have been tested. + /// This function is only available for streams using a single-byte character size. + /// + template + CASABLANCA_DEPRECATED( + "Unsafe API that will be removed in future releases, use one of the other write overloads instead.") + pplx::task write(T value) const + { + static_assert(sizeof(CharType) == 1, "binary write is only supported for single-byte streams"); + static_assert(std::is_trivial::value, "unsafe to use with non-trivial types"); - pplx::task result; - if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result; + pplx::task result; + if (!_verify_and_return_task(details::_out_stream_msg, result)) return result; - auto copy = std::make_shared(std::move(value)); - return helper()->m_buffer.putn_nocopy((CharType*)copy.get(), sizeof(T)).then([copy](pplx::task op) -> size_t { return op.get(); }); - } + auto copy = std::make_shared(std::move(value)); + return helper() + ->m_buffer.putn_nocopy((CharType*)copy.get(), sizeof(T)) + .then([copy](pplx::task op) -> size_t { return op.get(); }); + } - /// - /// Write a number of characters from a given stream buffer into the stream. - /// - /// A source stream buffer. - /// The number of characters to write. - pplx::task write(streams::streambuf source, size_t count) const - { - pplx::task result; - if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result; - if ( !source.can_read() ) - return pplx::task_from_exception(std::make_exception_ptr(std::runtime_error("source buffer not set up for input of data"))); + /// + /// Write a number of characters from a given stream buffer into the stream. + /// + /// A source stream buffer. + /// The number of characters to write. + pplx::task write(streams::streambuf source, size_t count) const + { + pplx::task result; + if (!_verify_and_return_task(details::_out_stream_msg, result)) return result; + if (!source.can_read()) + return pplx::task_from_exception( + std::make_exception_ptr(std::runtime_error("source buffer not set up for input of data"))); + + if (count == 0) return pplx::task_from_result((size_t)0); - if (count == 0) - return pplx::task_from_result((size_t)0); + auto buffer = helper()->m_buffer; + auto data = buffer.alloc(count); - auto buffer = helper()->m_buffer; - auto data = buffer.alloc(count); + if (data != nullptr) + { + auto post_read = [buffer](pplx::task op) -> pplx::task { + auto b = buffer; + b.commit(op.get()); + return op; + }; + return source.getn(data, count).then(post_read); + } + else + { + size_t available = 0; - if ( data != nullptr ) + const bool acquired = source.acquire(data, available); + if (available >= count) { - auto post_read = - [buffer](pplx::task op)-> pplx::task - { - auto b = buffer; - b.commit(op.get()); - return op; - }; - return source.getn(data, count).then(post_read); + auto post_write = [source, data](pplx::task op) -> pplx::task { + auto s = source; + s.release(data, op.get()); + return op; + }; + return buffer.putn_nocopy(data, count).then(post_write); } else { - size_t available = 0; - - const bool acquired = source.acquire(data, available); - if (available >= count) - { - auto post_write = - [source,data](pplx::task op)-> pplx::task - { - auto s = source; - s.release(data,op.get()); - return op; - }; - return buffer.putn_nocopy(data, count).then(post_write); - } - else + // Always have to release if acquire returned true. + if (acquired) { - // Always have to release if acquire returned true. - if(acquired) - { - source.release(data, 0); - } - - std::shared_ptr buf(new CharType[count], [](CharType *buf) { delete [] buf; }); - - auto post_write = - [buf](pplx::task op)-> pplx::task - { - return op; - }; - auto post_read = - [buf,post_write,buffer](pplx::task op) -> pplx::task - { - auto b = buffer; - return b.putn_nocopy(buf.get(), op.get()).then(post_write); - }; - - return source.getn(buf.get(), count).then(post_read); + source.release(data, 0); } - } - } - /// - /// Write the specified string to the output stream. - /// - /// Input string. - pplx::task print(const std::basic_string& str) const - { - pplx::task result; - if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result; + std::shared_ptr buf(new CharType[count], [](CharType* buf) { delete[] buf; }); - if (str.empty()) - { - return pplx::task_from_result(0); - } - else - { - auto sharedStr = std::make_shared>(str); - return helper()->m_buffer.putn_nocopy(sharedStr->c_str(), sharedStr->size()).then([sharedStr](size_t size) { return size; }); + auto post_write = [buf](pplx::task op) -> pplx::task { return op; }; + auto post_read = [buf, post_write, buffer](pplx::task op) -> pplx::task { + auto b = buffer; + return b.putn_nocopy(buf.get(), op.get()).then(post_write); + }; + + return source.getn(buf.get(), count).then(post_read); } } + } - /// - /// Write a value of type T to the output stream. - /// - /// - /// The data type of the object to be written to the stream - /// - /// Input object. - template - pplx::task print(const T& val) const - { - pplx::task result; - if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result; - // TODO in the future this could be improved to have Value2StringFormatter avoid another unnecessary copy - // by putting the string on the heap before calling the print string overload. - return print(details::Value2StringFormatter::format(val)); - } + /// + /// Write the specified string to the output stream. + /// + /// Input string. + pplx::task print(const std::basic_string& str) const + { + pplx::task result; + if (!_verify_and_return_task(details::_out_stream_msg, result)) return result; - /// - /// Write a value of type T to the output stream and append a newline character. - /// - /// - /// The data type of the object to be written to the stream - /// - /// Input object. - template - pplx::task print_line(const T& val) const + if (str.empty()) { - pplx::task result; - if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result; - auto str = details::Value2StringFormatter::format(val); - str.push_back(CharType('\n')); - return print(str); + return pplx::task_from_result(0); } - - /// - /// Flush any buffered output data. - /// - pplx::task flush() const + else { - pplx::task result; - if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result; - return helper()->m_buffer.sync(); + auto sharedStr = std::make_shared>(str); + return helper()->m_buffer.putn_nocopy(sharedStr->c_str(), sharedStr->size()).then([sharedStr](size_t size) { + return size; + }); } + } - /// - /// Seeks to the specified write position. - /// - /// An offset relative to the beginning of the stream. - /// The new position in the stream. - pos_type seek(pos_type pos) const - { - _verify_and_throw(details::_out_stream_msg); - return helper()->m_buffer.seekpos(pos, std::ios_base::out); - } + /// + /// Write a value of type T to the output stream. + /// + /// + /// The data type of the object to be written to the stream + /// + /// Input object. + template + pplx::task print(const T& val) const + { + pplx::task result; + if (!_verify_and_return_task(details::_out_stream_msg, result)) return result; + // TODO in the future this could be improved to have Value2StringFormatter avoid another unnecessary copy + // by putting the string on the heap before calling the print string overload. + return print(details::Value2StringFormatter::format(val)); + } - /// - /// Seeks to the specified write position. - /// - /// An offset relative to the beginning, current write position, or the end of the stream. - /// The starting point (beginning, current, end) for the seek. - /// The new position in the stream. - pos_type seek(off_type off, std::ios_base::seekdir way) const - { - _verify_and_throw(details::_out_stream_msg); - return helper()->m_buffer.seekoff(off, way, std::ios_base::out); - } + /// + /// Write a value of type T to the output stream and append a newline character. + /// + /// + /// The data type of the object to be written to the stream + /// + /// Input object. + template + pplx::task print_line(const T& val) const + { + pplx::task result; + if (!_verify_and_return_task(details::_out_stream_msg, result)) return result; + auto str = details::Value2StringFormatter::format(val); + str.push_back(CharType('\n')); + return print(str); + } - /// - /// Get the current write position, i.e. the offset from the beginning of the stream. - /// - /// The current write position. - pos_type tell() const - { - _verify_and_throw(details::_out_stream_msg); - return helper()->m_buffer.getpos(std::ios_base::out); - } + /// + /// Flush any buffered output data. + /// + pplx::task flush() const + { + pplx::task result; + if (!_verify_and_return_task(details::_out_stream_msg, result)) return result; + return helper()->m_buffer.sync(); + } - /// - /// can_seek is used to determine whether the stream supports seeking. - /// - /// true if the stream supports seeking, false otherwise. - bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); } - - /// - /// Test whether the stream has been initialized with a valid stream buffer. - /// - /// true if the stream has been initialized with a valid stream buffer, false otherwise. - bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); } - - /// - /// Test whether the stream has been initialized or not. - /// - operator bool() const { return is_valid(); } - - /// - /// Test whether the stream is open for writing. - /// - /// true if the stream is open for writing, false otherwise. - bool is_open() const { return is_valid() && m_helper->m_buffer.can_write(); } - - /// - /// Get the underlying stream buffer. - /// - /// The underlying stream buffer. - concurrency::streams::streambuf streambuf() const - { - return helper()->m_buffer; - } + /// + /// Seeks to the specified write position. + /// + /// An offset relative to the beginning of the stream. + /// The new position in the stream. + pos_type seek(pos_type pos) const + { + _verify_and_throw(details::_out_stream_msg); + return helper()->m_buffer.seekpos(pos, std::ios_base::out); + } - protected: + /// + /// Seeks to the specified write position. + /// + /// An offset relative to the beginning, current write position, or the end of the stream. + /// The starting point (beginning, current, end) for the seek. + /// The new position in the stream. + pos_type seek(off_type off, std::ios_base::seekdir way) const + { + _verify_and_throw(details::_out_stream_msg); + return helper()->m_buffer.seekoff(off, way, std::ios_base::out); + } - void set_helper(std::shared_ptr> helper) - { - m_helper = helper; - } + /// + /// Get the current write position, i.e. the offset from the beginning of the stream. + /// + /// The current write position. + pos_type tell() const + { + _verify_and_throw(details::_out_stream_msg); + return helper()->m_buffer.getpos(std::ios_base::out); + } - private: + /// + /// can_seek is used to determine whether the stream supports seeking. + /// + /// true if the stream supports seeking, false otherwise. + bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); } - template - bool _verify_and_return_task(const char *msg, pplx::task &tsk) const - { - auto buffer = helper()->m_buffer; - if ( !(buffer.exception() == nullptr) ) - { - tsk = pplx::task_from_exception(buffer.exception()); - return false; - } - if ( !buffer.can_write() ) - { - tsk = pplx::task_from_exception(std::make_exception_ptr(std::runtime_error(msg))); - return false; - } - return true; - } + /// + /// Test whether the stream has been initialized with a valid stream buffer. + /// + /// true if the stream has been initialized with a valid stream buffer, false + /// otherwise. + bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); } + + /// + /// Test whether the stream has been initialized or not. + /// + operator bool() const { return is_valid(); } + + /// + /// Test whether the stream is open for writing. + /// + /// true if the stream is open for writing, false otherwise. + bool is_open() const { return is_valid() && m_helper->m_buffer.can_write(); } + + /// + /// Get the underlying stream buffer. + /// + /// The underlying stream buffer. + concurrency::streams::streambuf streambuf() const { return helper()->m_buffer; } + +protected: + void set_helper(std::shared_ptr> helper) { m_helper = helper; } - void _verify_and_throw(const char *msg) const +private: + template + bool _verify_and_return_task(const char* msg, pplx::task& tsk) const + { + auto buffer = helper()->m_buffer; + if (!(buffer.exception() == nullptr)) { - auto buffer = helper()->m_buffer; - if ( !(buffer.exception() == nullptr) ) - std::rethrow_exception(buffer.exception()); - if ( !buffer.can_write() ) - throw std::runtime_error(msg); + tsk = pplx::task_from_exception(buffer.exception()); + return false; } - - std::shared_ptr> helper() const + if (!buffer.can_write()) { - if ( !m_helper ) - throw std::logic_error("uninitialized stream object"); - return m_helper; + tsk = pplx::task_from_exception(std::make_exception_ptr(std::runtime_error(msg))); + return false; } + return true; + } - std::shared_ptr> m_helper; - }; + void _verify_and_throw(const char* msg) const + { + auto buffer = helper()->m_buffer; + if (!(buffer.exception() == nullptr)) std::rethrow_exception(buffer.exception()); + if (!buffer.can_write()) throw std::runtime_error(msg); + } - template - struct _type_parser_integral_traits + std::shared_ptr> helper() const { - typedef std::false_type _is_integral; - typedef std::false_type _is_unsigned; - }; + if (!m_helper) throw std::logic_error("uninitialized stream object"); + return m_helper; + } + + std::shared_ptr> m_helper; +}; + +template +struct _type_parser_integral_traits +{ + typedef std::false_type _is_integral; + typedef std::false_type _is_unsigned; +}; #ifdef _WIN32 -#define _INT_TRAIT(_t,_low,_high) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::false_type _is_unsigned;static const int64_t _min = _low;static const int64_t _max = _high;}; -#define _UINT_TRAIT(_t,_low,_high) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::true_type _is_unsigned;static const uint64_t _max = _high;}; +#define _INT_TRAIT(_t, _low, _high) \ + template<> \ + struct _type_parser_integral_traits<_t> \ + { \ + typedef std::true_type _is_integral; \ + typedef std::false_type _is_unsigned; \ + static const int64_t _min = _low; \ + static const int64_t _max = _high; \ + }; +#define _UINT_TRAIT(_t, _low, _high) \ + template<> \ + struct _type_parser_integral_traits<_t> \ + { \ + typedef std::true_type _is_integral; \ + typedef std::true_type _is_unsigned; \ + static const uint64_t _max = _high; \ + }; - _INT_TRAIT(char,INT8_MIN,INT8_MAX) - _INT_TRAIT(signed char,INT8_MIN,INT8_MAX) - _INT_TRAIT(short,INT16_MIN,INT16_MAX) +_INT_TRAIT(char, INT8_MIN, INT8_MAX) +_INT_TRAIT(signed char, INT8_MIN, INT8_MAX) +_INT_TRAIT(short, INT16_MIN, INT16_MAX) #if defined(_NATIVE_WCHAR_T_DEFINED) - _INT_TRAIT(wchar_t,WCHAR_MIN, WCHAR_MAX) +_INT_TRAIT(wchar_t, WCHAR_MIN, WCHAR_MAX) #endif - _INT_TRAIT(int,INT32_MIN,INT32_MAX) - _INT_TRAIT(long, LONG_MIN, LONG_MAX) - _INT_TRAIT(long long, LLONG_MIN, LLONG_MAX) - _UINT_TRAIT(unsigned char,UINT8_MIN,UINT8_MAX) - _UINT_TRAIT(unsigned short,UINT16_MIN,UINT16_MAX) - _UINT_TRAIT(unsigned int,UINT32_MIN,UINT32_MAX) - _UINT_TRAIT(unsigned long, ULONG_MIN, ULONG_MAX) - _UINT_TRAIT(unsigned long long, ULLONG_MIN, ULLONG_MAX) +_INT_TRAIT(int, INT32_MIN, INT32_MAX) +_INT_TRAIT(long, LONG_MIN, LONG_MAX) +_INT_TRAIT(long long, LLONG_MIN, LLONG_MAX) +_UINT_TRAIT(unsigned char, UINT8_MIN, UINT8_MAX) +_UINT_TRAIT(unsigned short, UINT16_MIN, UINT16_MAX) +_UINT_TRAIT(unsigned int, UINT32_MIN, UINT32_MAX) +_UINT_TRAIT(unsigned long, ULONG_MIN, ULONG_MAX) +_UINT_TRAIT(unsigned long long, ULLONG_MIN, ULLONG_MAX) #else -#define _INT_TRAIT(_t) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::false_type _is_unsigned;static const int64_t _min = std::numeric_limits<_t>::min();static const int64_t _max = (std::numeric_limits<_t>::max)();}; -#define _UINT_TRAIT(_t) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::true_type _is_unsigned;static const uint64_t _max = (std::numeric_limits<_t>::max)();}; - - _INT_TRAIT(char) - _INT_TRAIT(signed char) - _INT_TRAIT(short) - _INT_TRAIT(utf16char) - _INT_TRAIT(int) - _INT_TRAIT(long) - _INT_TRAIT(long long) - _UINT_TRAIT(unsigned char) - _UINT_TRAIT(unsigned short) - _UINT_TRAIT(unsigned int) - _UINT_TRAIT(unsigned long) - _UINT_TRAIT(unsigned long long) +#define _INT_TRAIT(_t) \ + template<> \ + struct _type_parser_integral_traits<_t> \ + { \ + typedef std::true_type _is_integral; \ + typedef std::false_type _is_unsigned; \ + static const int64_t _min = std::numeric_limits<_t>::min(); \ + static const int64_t _max = (std::numeric_limits<_t>::max)(); \ + }; +#define _UINT_TRAIT(_t) \ + template<> \ + struct _type_parser_integral_traits<_t> \ + { \ + typedef std::true_type _is_integral; \ + typedef std::true_type _is_unsigned; \ + static const uint64_t _max = (std::numeric_limits<_t>::max)(); \ + }; + +_INT_TRAIT(char) +_INT_TRAIT(signed char) +_INT_TRAIT(short) +_INT_TRAIT(utf16char) +_INT_TRAIT(int) +_INT_TRAIT(long) +_INT_TRAIT(long long) +_UINT_TRAIT(unsigned char) +_UINT_TRAIT(unsigned short) +_UINT_TRAIT(unsigned int) +_UINT_TRAIT(unsigned long) +_UINT_TRAIT(unsigned long long) #endif - template - class _type_parser_base - { - public: - typedef char_traits traits; - typedef typename traits::int_type int_type; +template +class _type_parser_base +{ +public: + typedef char_traits traits; + typedef typename traits::int_type int_type; - _type_parser_base() { } + _type_parser_base() {} - protected: - // Aid in parsing input: skipping whitespace characters. - static pplx::task _skip_whitespace(streams::streambuf buffer); +protected: + // Aid in parsing input: skipping whitespace characters. + static pplx::task _skip_whitespace(streams::streambuf buffer); + + // Aid in parsing input: peek at a character at a time, call type-specific code to examine, extract value when done. + // AcceptFunctor should model std::function, int_type)> + // ExtractFunctor should model std::function(std::shared_ptr)> + template + static pplx::task _parse_input(streams::streambuf buffer, + AcceptFunctor accept_character, + ExtractFunctor extract); +}; - // Aid in parsing input: peek at a character at a time, call type-specific code to examine, extract value when done. - // AcceptFunctor should model std::function, int_type)> - // ExtractFunctor should model std::function(std::shared_ptr)> - template - static pplx::task _parse_input(streams::streambuf buffer, AcceptFunctor accept_character, ExtractFunctor extract); - }; +/// +/// Class used to handle asynchronous parsing for basic_istream::extract. To support new +/// types create a new template specialization and implement the parse function. +/// +template +class type_parser +{ +public: + static pplx::task parse(streams::streambuf buffer) + { + typename _type_parser_integral_traits::_is_integral ii; + typename _type_parser_integral_traits::_is_unsigned ui; + return _parse(buffer, ii, ui); + } - /// - /// Class used to handle asynchronous parsing for basic_istream::extract. To support new - /// types create a new template specialization and implement the parse function. - /// - template - class type_parser +private: + static pplx::task _parse(streams::streambuf buffer, std::false_type, std::false_type) { - public: - static pplx::task parse(streams::streambuf buffer) - { - typename _type_parser_integral_traits::_is_integral ii; - typename _type_parser_integral_traits::_is_unsigned ui; - return _parse(buffer, ii, ui); - } - private: - static pplx::task _parse(streams::streambuf buffer, std::false_type, std::false_type) - { - _parse_floating_point(buffer); - } + _parse_floating_point(buffer); + } - static pplx::task _parse(streams::streambuf, std::false_type, std::true_type) - { + static pplx::task _parse(streams::streambuf, std::false_type, std::true_type) + { #ifdef _WIN32 - static_assert(false, "type is not supported for extraction from a stream"); + static_assert(false, "type is not supported for extraction from a stream"); #else - throw std::runtime_error("type is not supported for extraction from a stream"); + throw std::runtime_error("type is not supported for extraction from a stream"); #endif - } + } - static pplx::task _parse(streams::streambuf buffer, std::true_type, std::false_type) - { - return type_parser::parse(buffer).then( - [] (pplx::task op) -> T - { - int64_t val = op.get(); - if ( val <= _type_parser_integral_traits::_max && val >= _type_parser_integral_traits::_min ) - return (T)val; - else - throw std::range_error("input out of range for target type"); - }); - } + static pplx::task _parse(streams::streambuf buffer, std::true_type, std::false_type) + { + return type_parser::parse(buffer).then([](pplx::task op) -> T { + int64_t val = op.get(); + if (val <= _type_parser_integral_traits::_max && val >= _type_parser_integral_traits::_min) + return (T)val; + else + throw std::range_error("input out of range for target type"); + }); + } - static pplx::task _parse(streams::streambuf buffer, std::true_type, std::true_type) - { - return type_parser::parse(buffer).then( - [] (pplx::task op) -> T - { - uint64_t val = op.get(); - if ( val <= _type_parser_integral_traits::_max ) - return (T)val; - else - throw std::range_error("input out of range for target type"); - }); - } - }; + static pplx::task _parse(streams::streambuf buffer, std::true_type, std::true_type) + { + return type_parser::parse(buffer).then([](pplx::task op) -> T { + uint64_t val = op.get(); + if (val <= _type_parser_integral_traits::_max) + return (T)val; + else + throw std::range_error("input out of range for target type"); + }); + } +}; + +/// +/// Base interface for all asynchronous input streams. +/// +template +class basic_istream +{ +public: + typedef char_traits traits; + typedef typename traits::int_type int_type; + typedef typename traits::pos_type pos_type; + typedef typename traits::off_type off_type; /// - /// Base interface for all asynchronous input streams. + /// Default constructor /// - template - class basic_istream - { - public: - - typedef char_traits traits; - typedef typename traits::int_type int_type; - typedef typename traits::pos_type pos_type; - typedef typename traits::off_type off_type; - - - /// - /// Default constructor - /// - basic_istream() {} - - /// - /// Constructor - /// - /// - /// The data type of the basic element of the stream. - /// - /// A stream buffer. - template - basic_istream(streams::streambuf buffer) : m_helper(std::make_shared>(std::move(buffer))) - { - _verify_and_throw(details::_in_streambuf_msg); - } + basic_istream() {} - /// - /// Copy constructor - /// - /// The source object - basic_istream(const basic_istream &other) : m_helper(other.m_helper) { } - - /// - /// Assignment operator - /// - /// The source object - /// A reference to the stream object that contains the result of the assignment. - basic_istream & operator =(const basic_istream &other) - { - m_helper = other.m_helper; - return *this; - } + /// + /// Constructor + /// + /// + /// The data type of the basic element of the stream. + /// + /// A stream buffer. + template + basic_istream(streams::streambuf buffer) + : m_helper(std::make_shared>(std::move(buffer))) + { + _verify_and_throw(details::_in_streambuf_msg); + } - /// - /// Close the stream, preventing further read operations. - /// - pplx::task close() const - { - return is_valid() ? - helper()->m_buffer.close(std::ios_base::in) : - pplx::task_from_result(); - } + /// + /// Copy constructor + /// + /// The source object + basic_istream(const basic_istream& other) : m_helper(other.m_helper) {} + + /// + /// Assignment operator + /// + /// The source object + /// A reference to the stream object that contains the result of the assignment. + basic_istream& operator=(const basic_istream& other) + { + m_helper = other.m_helper; + return *this; + } + + /// + /// Close the stream, preventing further read operations. + /// + pplx::task close() const + { + return is_valid() ? helper()->m_buffer.close(std::ios_base::in) : pplx::task_from_result(); + } + + /// + /// Close the stream with exception, preventing further read operations. + /// + /// Pointer to the exception. + pplx::task close(std::exception_ptr eptr) const + { + return is_valid() ? m_helper->m_buffer.close(std::ios_base::in, eptr) : pplx::task_from_result(); + } + + /// + /// Tests whether last read cause the stream reach EOF. + /// + /// True if the read head has reached the end of the stream, false otherwise. + bool is_eof() const { return is_valid() ? m_helper->m_buffer.is_eof() : false; } + + /// + /// Get the next character and return it as an int_type. Advance the read position. + /// + /// A task that holds the next character as an int_type on successful completion. + pplx::task read() const + { + pplx::task result; + if (!_verify_and_return_task(details::_in_stream_msg, result)) return result; + return helper()->m_buffer.bumpc(); + } + + /// + /// Read a single value of "blittable" type T from the stream. + /// + /// A value of type T. + /// + /// This is not a replacement for a proper binary serialization solution, but it may + /// form the foundation for one. Reading data bit-wise to a stream is a primitive + /// operation of binary serialization. + /// Currently, no attention is paid to byte order. All data is read in the platform's + /// native byte order, which means little-endian on all platforms that have been tested. + /// This function is only available for streams using a single-byte character size. + /// + template + CASABLANCA_DEPRECATED( + "Unsafe API that will be removed in future releases, use one of the other read overloads instead.") + pplx::task read() const + { + static_assert(sizeof(CharType) == 1, "binary read is only supported for single-byte streams"); + static_assert(std::is_trivial::value, "unsafe to use with non-trivial types"); + + pplx::task result; + if (!_verify_and_return_task(details::_in_stream_msg, result)) return result; + + auto copy = std::make_shared(); + return helper()->m_buffer.getn((CharType*)copy.get(), sizeof(T)).then([copy](pplx::task) -> T { + return std::move(*copy); + }); + } + + /// + /// Reads up to count characters and place into the provided buffer. + /// + /// An async stream buffer supporting write operations. + /// The maximum number of characters to read + /// A task that holds the number of characters read. This number is 0 if the end of the stream is + /// reached. + pplx::task read(streams::streambuf target, size_t count) const + { + pplx::task result; + if (!_verify_and_return_task(details::_in_stream_msg, result)) return result; + if (!target.can_write()) + return pplx::task_from_exception( + std::make_exception_ptr(std::runtime_error("target not set up for output of data"))); + + // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations. + auto buffer = helper()->m_buffer; + + auto data = target.alloc(count); - /// - /// Close the stream with exception, preventing further read operations. - /// - /// Pointer to the exception. - pplx::task close(std::exception_ptr eptr) const + if (data != nullptr) { - return is_valid() ? - m_helper->m_buffer.close(std::ios_base::in, eptr) : - pplx::task_from_result(); + auto post_read = [target](pplx::task op) -> pplx::task { + auto t = target; + t.commit(op.get()); + return op; + }; + return buffer.getn(data, count).then(post_read); } - - /// - /// Tests whether last read cause the stream reach EOF. - /// - /// True if the read head has reached the end of the stream, false otherwise. - bool is_eof() const + else { - return is_valid() ? m_helper->m_buffer.is_eof() : false; + size_t available = 0; + + const bool acquired = buffer.acquire(data, available); + if (available >= count) + { + auto post_write = [buffer, data](pplx::task op) -> pplx::task { + auto b = buffer; + b.release(data, op.get()); + return op; + }; + return target.putn_nocopy(data, count).then(post_write); + } + else + { + // Always have to release if acquire returned true. + if (acquired) + { + buffer.release(data, 0); + } + + std::shared_ptr buf(new CharType[count], [](CharType* buf) { delete[] buf; }); + + auto post_write = [buf](pplx::task op) -> pplx::task { return op; }; + auto post_read = [buf, target, post_write](pplx::task op) -> pplx::task { + auto trg = target; + return trg.putn_nocopy(buf.get(), op.get()).then(post_write); + }; + + return helper()->m_buffer.getn(buf.get(), count).then(post_read); + } } + } + + /// + /// Get the next character and return it as an int_type. Do not advance the read position. + /// + /// A task that holds the character, widened to an integer. This character is EOF when the peek + /// operation fails. + pplx::task peek() const + { + pplx::task result; + if (!_verify_and_return_task(details::_in_stream_msg, result)) return result; + return helper()->m_buffer.getc(); + } + + /// + /// Read characters until a delimiter or EOF is found, and place them into the target. + /// Proceed past the delimiter, but don't include it in the target buffer. + /// + /// An async stream buffer supporting write operations. + /// The delimiting character to stop the read at. + /// A task that holds the number of characters read. + pplx::task read_to_delim(streams::streambuf target, int_type delim) const + { + pplx::task result; + if (!_verify_and_return_task(details::_in_stream_msg, result)) return result; + if (!target.can_write()) + return pplx::task_from_exception( + std::make_exception_ptr(std::runtime_error("target not set up for output of data"))); - /// - /// Get the next character and return it as an int_type. Advance the read position. - /// - /// A task that holds the next character as an int_type on successful completion. - pplx::task read() const - { - pplx::task result; - if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result; - return helper()->m_buffer.bumpc(); - } + // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations. + auto buffer = helper()->m_buffer; - /// - /// Read a single value of "blittable" type T from the stream. - /// - /// A value of type T. - /// - /// This is not a replacement for a proper binary serialization solution, but it may - /// form the foundation for one. Reading data bit-wise to a stream is a primitive - /// operation of binary serialization. - /// Currently, no attention is paid to byte order. All data is read in the platform's - /// native byte order, which means little-endian on all platforms that have been tested. - /// This function is only available for streams using a single-byte character size. - /// - template - CASABLANCA_DEPRECATED("Unsafe API that will be removed in future releases, use one of the other read overloads instead.") - pplx::task read() const - { - static_assert(sizeof(CharType) == 1, "binary read is only supported for single-byte streams"); - static_assert(std::is_trivial::value, "unsafe to use with non-trivial types"); + int_type req_async = traits::requires_async(); - pplx::task result; - if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result; + std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>(); - auto copy = std::make_shared(); - return helper()->m_buffer.getn((CharType*)copy.get(), sizeof(T)).then([copy](pplx::task) -> T - { - return std::move(*copy); + auto flush = [=]() mutable { + return target.putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](size_t wrote) mutable { + _locals->total += wrote; + _locals->write_pos = 0; + return target.sync(); }); - } - - /// - /// Reads up to count characters and place into the provided buffer. - /// - /// An async stream buffer supporting write operations. - /// The maximum number of characters to read - /// A task that holds the number of characters read. This number is 0 if the end of the stream is reached. - pplx::task read(streams::streambuf target, size_t count) const - { - pplx::task result; - if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result; - if ( !target.can_write() ) - return pplx::task_from_exception(std::make_exception_ptr(std::runtime_error("target not set up for output of data"))); + }; - // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations. - auto buffer = helper()->m_buffer; + auto update = [=](int_type ch) mutable { + if (ch == traits::eof()) return false; + if (ch == delim) return false; - auto data = target.alloc(count); + _locals->outbuf[_locals->write_pos] = static_cast(ch); + _locals->write_pos += 1; - if ( data != nullptr ) + if (_locals->is_full()) { - auto post_read = - [target](pplx::task op)-> pplx::task - { - auto t = target; - t.commit(op.get()); - return op; - }; - return buffer.getn(data, count).then(post_read); + // Flushing synchronously because performance is terrible if we + // schedule an empty task. This isn't on a user's thread. + flush().get(); } - else + + return true; + }; + + auto loop = pplx::details::_do_while([=]() mutable -> pplx::task { + while (buffer.in_avail() > 0) { - size_t available = 0; + int_type ch = buffer.sbumpc(); - const bool acquired = buffer.acquire(data, available); - if (available >= count) + if (ch == req_async) { - auto post_write = - [buffer,data](pplx::task op)-> pplx::task - { - auto b = buffer; - b.release(data, op.get()); - return op; - }; - return target.putn_nocopy(data, count).then(post_write); + break; } - else + + if (!update(ch)) { - // Always have to release if acquire returned true. - if(acquired) - { - buffer.release(data, 0); - } - - std::shared_ptr buf(new CharType[count], [](CharType *buf) { delete [] buf; }); - - auto post_write = - [buf](pplx::task op) -> pplx::task - { - return op; - }; - auto post_read = - [buf,target,post_write](pplx::task op) -> pplx::task - { - auto trg = target; - return trg.putn_nocopy(buf.get(), op.get()).then(post_write); - }; - - return helper()->m_buffer.getn(buf.get(), count).then(post_read); + return pplx::task_from_result(false); } } - } - - /// - /// Get the next character and return it as an int_type. Do not advance the read position. - /// - /// A task that holds the character, widened to an integer. This character is EOF when the peek operation fails. - pplx::task peek() const - { - pplx::task result; - if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result; - return helper()->m_buffer.getc(); - } - - /// - /// Read characters until a delimiter or EOF is found, and place them into the target. - /// Proceed past the delimiter, but don't include it in the target buffer. - /// - /// An async stream buffer supporting write operations. - /// The delimiting character to stop the read at. - /// A task that holds the number of characters read. - pplx::task read_to_delim(streams::streambuf target, int_type delim) const - { - pplx::task result; - if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result; - if ( !target.can_write() ) - return pplx::task_from_exception(std::make_exception_ptr(std::runtime_error("target not set up for output of data"))); - - // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations. - auto buffer = helper()->m_buffer; - - int_type req_async = traits::requires_async(); - - std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>(); + return buffer.bumpc().then(update); + }); - auto flush = [=]() mutable - { - return target.putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](size_t wrote) mutable - { - _locals->total += wrote; - _locals->write_pos = 0; - return target.sync(); - }); - }; + return loop.then([=](bool) mutable { return flush().then([=] { return _locals->total; }); }); + } - auto update = [=](int_type ch) mutable - { - if (ch == traits::eof()) return false; - if (ch == delim) return false; + /// + /// Read until reaching a newline character. The newline is not included in the target. + /// + /// An asynchronous stream buffer supporting write operations. + /// A task that holds the number of characters read. This number is 0 if the end of the stream is + /// reached. + pplx::task read_line(streams::streambuf target) const + { + pplx::task result; + if (!_verify_and_return_task(details::_in_stream_msg, result)) return result; + if (!target.can_write()) + return pplx::task_from_exception( + std::make_exception_ptr(std::runtime_error("target not set up for receiving data"))); - _locals->outbuf[_locals->write_pos] = static_cast(ch); - _locals->write_pos += 1; + // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations. + concurrency::streams::streambuf buffer = helper()->m_buffer; - if (_locals->is_full()) - { - // Flushing synchronously because performance is terrible if we - // schedule an empty task. This isn't on a user's thread. - flush().get(); - } + int_type req_async = traits::requires_async(); - return true; - }; + std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>(); - auto loop = pplx::details::_do_while([=]() mutable -> pplx::task - { - while (buffer.in_avail() > 0) - { - int_type ch = buffer.sbumpc(); - - if (ch == req_async) - { - break; - } - - if (!update(ch)) - { - return pplx::task_from_result(false); - } - } - return buffer.bumpc().then(update); - }); - - return loop.then([=](bool) mutable - { - return flush().then([=] { return _locals->total; }); + auto flush = [=]() mutable { + return target.putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](size_t wrote) mutable { + _locals->total += wrote; + _locals->write_pos = 0; + return target.sync(); }); - } + }; - /// - /// Read until reaching a newline character. The newline is not included in the target. - /// - /// An asynchronous stream buffer supporting write operations. - /// A task that holds the number of characters read. This number is 0 if the end of the stream is reached. - pplx::task read_line(streams::streambuf target) const - { - pplx::task result; - if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result; - if ( !target.can_write() ) - return pplx::task_from_exception(std::make_exception_ptr(std::runtime_error("target not set up for receiving data"))); + auto update = [=](int_type ch) mutable { + if (ch == traits::eof()) return false; + if (ch == '\n') return false; + if (ch == '\r') + { + _locals->saw_CR = true; + return true; + } - // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations. - concurrency::streams::streambuf buffer = helper()->m_buffer; + _locals->outbuf[_locals->write_pos] = static_cast(ch); + _locals->write_pos += 1; - int_type req_async = traits::requires_async(); + if (_locals->is_full()) + { + // Flushing synchronously because performance is terrible if we + // schedule an empty task. This isn't on a user's thread. + flush().wait(); + } - std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>(); + return true; + }; - auto flush = [=]() mutable + auto update_after_cr = [=](int_type ch) mutable -> pplx::task { + if (ch == traits::eof()) return pplx::task_from_result(false); + if (ch == '\n') { - return target.putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](size_t wrote) mutable - { - _locals->total += wrote; - _locals->write_pos = 0; - return target.sync(); - }); - }; + return buffer.bumpc().then([](int_type) { return false; }); + } + return pplx::task_from_result(false); + }; - auto update = [=](int_type ch) mutable - { - if (ch == traits::eof()) return false; - if (ch == '\n') return false; - if (ch == '\r') - { - _locals->saw_CR = true; - return true; - } - - _locals->outbuf[_locals->write_pos] = static_cast(ch); - _locals->write_pos += 1; - - if (_locals->is_full()) - { - // Flushing synchronously because performance is terrible if we - // schedule an empty task. This isn't on a user's thread. - flush().wait(); - } - - return true; - }; + auto loop = pplx::details::_do_while([=]() mutable -> pplx::task { + while (buffer.in_avail() > 0) + { + int_type ch; - auto update_after_cr = [=] (int_type ch) mutable -> pplx::task + if (_locals->saw_CR) { - if (ch == traits::eof()) return pplx::task_from_result(false); - if (ch == '\n') - { - return buffer.bumpc().then([](int_type) { return false; }); - } + ch = buffer.sgetc(); + if (ch == '\n') buffer.sbumpc(); return pplx::task_from_result(false); - }; + } - auto loop = pplx::details::_do_while([=]() mutable -> pplx::task - { - while ( buffer.in_avail() > 0 ) - { - int_type ch; - - if (_locals->saw_CR) - { - ch = buffer.sgetc(); - if (ch == '\n') - buffer.sbumpc(); - return pplx::task_from_result(false); - } - - ch = buffer.sbumpc(); - - if (ch == req_async) - break; - - if (!update(ch)) - { - return pplx::task_from_result(false); - } - } - - if (_locals->saw_CR) - { - return buffer.getc().then(update_after_cr); - } - return buffer.bumpc().then(update); - }); - - return loop.then([=](bool) mutable - { - return flush().then([=] { return _locals->total; }); - }); - } + ch = buffer.sbumpc(); - /// - /// Read until reaching the end of the stream. - /// - /// An asynchronous stream buffer supporting write operations. - /// The number of characters read. - pplx::task read_to_end(streams::streambuf target) const - { - pplx::task result; - if ( !_verify_and_return_task("stream not set up for output of data", result) ) return result; - if ( !target.can_write() ) - return pplx::task_from_exception(std::make_exception_ptr(std::runtime_error("source buffer not set up for input of data"))); + if (ch == req_async) break; - auto l_buffer = helper()->m_buffer; - auto l_buf_size = this->buf_size; - std::shared_ptr<_read_helper> l_locals = std::make_shared<_read_helper>(); + if (!update(ch)) + { + return pplx::task_from_result(false); + } + } - auto copy_to_target = [l_locals, target, l_buffer, l_buf_size]() mutable -> pplx::task + if (_locals->saw_CR) { - // We need to capture these, because the object itself may go away - // before we're done processing the data. - //auto locs = _locals; - //auto trg = target; + return buffer.getc().then(update_after_cr); + } + return buffer.bumpc().then(update); + }); - return l_buffer.getn(l_locals->outbuf, l_buf_size).then([=](size_t rd) mutable -> pplx::task - { - if (rd == 0) - return pplx::task_from_result(false); + return loop.then([=](bool) mutable { return flush().then([=] { return _locals->total; }); }); + } - // Must be nested to capture rd - return target.putn_nocopy(l_locals->outbuf, rd).then([target, l_locals, rd](size_t wr) mutable -> pplx::task - { + /// + /// Read until reaching the end of the stream. + /// + /// An asynchronous stream buffer supporting write operations. + /// The number of characters read. + pplx::task read_to_end(streams::streambuf target) const + { + pplx::task result; + if (!_verify_and_return_task("stream not set up for output of data", result)) return result; + if (!target.can_write()) + return pplx::task_from_exception( + std::make_exception_ptr(std::runtime_error("source buffer not set up for input of data"))); + + auto l_buffer = helper()->m_buffer; + auto l_buf_size = this->buf_size; + std::shared_ptr<_read_helper> l_locals = std::make_shared<_read_helper>(); + + auto copy_to_target = [l_locals, target, l_buffer, l_buf_size]() mutable -> pplx::task { + // We need to capture these, because the object itself may go away + // before we're done processing the data. + // auto locs = _locals; + // auto trg = target; + + return l_buffer.getn(l_locals->outbuf, l_buf_size).then([=](size_t rd) mutable -> pplx::task { + if (rd == 0) return pplx::task_from_result(false); + + // Must be nested to capture rd + return target.putn_nocopy(l_locals->outbuf, rd) + .then([target, l_locals, rd](size_t wr) mutable -> pplx::task { l_locals->total += wr; if (rd != wr) @@ -966,229 +955,204 @@ namespace Concurrency { namespace streams return target.sync().then([]() { return true; }); }); - }); - }; + }); + }; - auto loop = pplx::details::_do_while(copy_to_target); + auto loop = pplx::details::_do_while(copy_to_target); - return loop.then([=](bool) mutable -> size_t - { - return l_locals->total; - }); - } + return loop.then([=](bool) mutable -> size_t { return l_locals->total; }); + } - /// - /// Seeks to the specified write position. - /// - /// An offset relative to the beginning of the stream. - /// The new position in the stream. - pos_type seek(pos_type pos) const - { - _verify_and_throw(details::_in_stream_msg); - return helper()->m_buffer.seekpos(pos, std::ios_base::in); - } + /// + /// Seeks to the specified write position. + /// + /// An offset relative to the beginning of the stream. + /// The new position in the stream. + pos_type seek(pos_type pos) const + { + _verify_and_throw(details::_in_stream_msg); + return helper()->m_buffer.seekpos(pos, std::ios_base::in); + } - /// - /// Seeks to the specified write position. - /// - /// An offset relative to the beginning, current write position, or the end of the stream. - /// The starting point (beginning, current, end) for the seek. - /// The new position in the stream. - pos_type seek(off_type off, std::ios_base::seekdir way) const - { - _verify_and_throw(details::_in_stream_msg); - return helper()->m_buffer.seekoff(off, way, std::ios_base::in); - } + /// + /// Seeks to the specified write position. + /// + /// An offset relative to the beginning, current write position, or the end of the stream. + /// The starting point (beginning, current, end) for the seek. + /// The new position in the stream. + pos_type seek(off_type off, std::ios_base::seekdir way) const + { + _verify_and_throw(details::_in_stream_msg); + return helper()->m_buffer.seekoff(off, way, std::ios_base::in); + } - /// - /// Get the current write position, i.e. the offset from the beginning of the stream. - /// - /// The current write position. - pos_type tell() const - { - _verify_and_throw(details::_in_stream_msg); - return helper()->m_buffer.getpos(std::ios_base::in); - } + /// + /// Get the current write position, i.e. the offset from the beginning of the stream. + /// + /// The current write position. + pos_type tell() const + { + _verify_and_throw(details::_in_stream_msg); + return helper()->m_buffer.getpos(std::ios_base::in); + } - /// - /// can_seek is used to determine whether the stream supports seeking. - /// - /// true if the stream supports seeking, false otherwise. - bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); } - - /// - /// Test whether the stream has been initialized with a valid stream buffer. - /// - bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); } - - /// - /// Test whether the stream has been initialized or not. - /// - operator bool() const { return is_valid(); } - - /// - /// Test whether the stream is open for writing. - /// - /// true if the stream is open for writing, false otherwise. - bool is_open() const { return is_valid() && m_helper->m_buffer.can_read(); } - - /// - /// Get the underlying stream buffer. - /// - concurrency::streams::streambuf streambuf() const - { - return helper()->m_buffer; - } + /// + /// can_seek is used to determine whether the stream supports seeking. + /// + /// true if the stream supports seeking, false otherwise. + bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); } - /// - /// Read a value of type T from the stream. - /// - /// - /// Supports the C++ primitive types. Can be expanded to additional types - /// by adding template specializations for type_parser. - /// - /// - /// The data type of the element to be read from the stream. - /// - /// A task that holds the element read from the stream. - template - pplx::task extract() const - { - pplx::task result; - if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result; - return type_parser::parse(helper()->m_buffer); - } + /// + /// Test whether the stream has been initialized with a valid stream buffer. + /// + bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); } + + /// + /// Test whether the stream has been initialized or not. + /// + operator bool() const { return is_valid(); } - private: + /// + /// Test whether the stream is open for writing. + /// + /// true if the stream is open for writing, false otherwise. + bool is_open() const { return is_valid() && m_helper->m_buffer.can_read(); } - template - bool _verify_and_return_task(const char *msg, pplx::task &tsk) const - { - auto buffer = helper()->m_buffer; - if ( !(buffer.exception() == nullptr) ) - { - tsk = pplx::task_from_exception(buffer.exception()); - return false; - } - if ( !buffer.can_read() ) - { - tsk = pplx::task_from_exception(std::make_exception_ptr(std::runtime_error(msg))); - return false; - } - return true; - } + /// + /// Get the underlying stream buffer. + /// + concurrency::streams::streambuf streambuf() const { return helper()->m_buffer; } + + /// + /// Read a value of type T from the stream. + /// + /// + /// Supports the C++ primitive types. Can be expanded to additional types + /// by adding template specializations for type_parser. + /// + /// + /// The data type of the element to be read from the stream. + /// + /// A task that holds the element read from the stream. + template + pplx::task extract() const + { + pplx::task result; + if (!_verify_and_return_task(details::_in_stream_msg, result)) return result; + return type_parser::parse(helper()->m_buffer); + } - void _verify_and_throw(const char *msg) const +private: + template + bool _verify_and_return_task(const char* msg, pplx::task& tsk) const + { + auto buffer = helper()->m_buffer; + if (!(buffer.exception() == nullptr)) { - auto buffer = helper()->m_buffer; - if ( !(buffer.exception() == nullptr) ) - std::rethrow_exception(buffer.exception()); - if ( !buffer.can_read() ) - throw std::runtime_error(msg); + tsk = pplx::task_from_exception(buffer.exception()); + return false; } - - std::shared_ptr> helper() const + if (!buffer.can_read()) { - if ( !m_helper ) - throw std::logic_error("uninitialized stream object"); - return m_helper; + tsk = pplx::task_from_exception(std::make_exception_ptr(std::runtime_error(msg))); + return false; } + return true; + } - static const size_t buf_size = 16*1024; + void _verify_and_throw(const char* msg) const + { + auto buffer = helper()->m_buffer; + if (!(buffer.exception() == nullptr)) std::rethrow_exception(buffer.exception()); + if (!buffer.can_read()) throw std::runtime_error(msg); + } - struct _read_helper - { - size_t total; - CharType outbuf[buf_size]; - size_t write_pos; - bool saw_CR; + std::shared_ptr> helper() const + { + if (!m_helper) throw std::logic_error("uninitialized stream object"); + return m_helper; + } - bool is_full() const - { - return write_pos == buf_size; - } + static const size_t buf_size = 16 * 1024; - _read_helper() : total(0), write_pos(0), saw_CR(false) - { - } - }; + struct _read_helper + { + size_t total; + CharType outbuf[buf_size]; + size_t write_pos; + bool saw_CR; - std::shared_ptr> m_helper; + bool is_full() const { return write_pos == buf_size; } + + _read_helper() : total(0), write_pos(0), saw_CR(false) {} }; - typedef basic_ostream ostream; - typedef basic_istream istream; + std::shared_ptr> m_helper; +}; + +typedef basic_ostream ostream; +typedef basic_istream istream; - typedef basic_ostream wostream; - typedef basic_istream wistream; +typedef basic_ostream wostream; +typedef basic_istream wistream; template pplx::task _type_parser_base::_skip_whitespace(streams::streambuf buffer) { int_type req_async = traits::requires_async(); - auto update = [=] (int_type ch) mutable + auto update = [=](int_type ch) mutable { + if (isspace(ch)) { - if (isspace(ch)) + if (buffer.sbumpc() == req_async) { - if (buffer.sbumpc() == req_async) - { - // Synchronously because performance is terrible if we - // schedule an empty task. This isn't on a user's thread. - buffer.nextc().wait(); - } - return true; + // Synchronously because performance is terrible if we + // schedule an empty task. This isn't on a user's thread. + buffer.nextc().wait(); } + return true; + } - return false; - }; + return false; + }; - auto loop = pplx::details::_do_while([=]() mutable -> pplx::task + auto loop = pplx::details::_do_while([=]() mutable -> pplx::task { + while (buffer.in_avail() > 0) { - while (buffer.in_avail() > 0) - { - int_type ch = buffer.sgetc(); + int_type ch = buffer.sgetc(); - if (ch == req_async) - break; + if (ch == req_async) break; - if (!update(ch)) - { - return pplx::task_from_result(false); - } + if (!update(ch)) + { + return pplx::task_from_result(false); } - return buffer.getc().then(update); - }); + } + return buffer.getc().then(update); + }); - return loop.then([=](pplx::task op) - { - op.wait(); - }); + return loop.then([=](pplx::task op) { op.wait(); }); } template template -pplx::task _type_parser_base::_parse_input( - concurrency::streams::streambuf buffer, - AcceptFunctor accept_character, - ExtractFunctor extract) +pplx::task _type_parser_base::_parse_input(concurrency::streams::streambuf buffer, + AcceptFunctor accept_character, + ExtractFunctor extract) { std::shared_ptr state = std::make_shared(); - auto update = [=] (pplx::task op) -> pplx::task - { + auto update = [=](pplx::task op) -> pplx::task { int_type ch = op.get(); if (ch == traits::eof()) return pplx::task_from_result(false); bool accptd = accept_character(state, ch); - if (!accptd) - return pplx::task_from_result(false); + if (!accptd) return pplx::task_from_result(false); // We peeked earlier, so now we must advance the position. concurrency::streams::streambuf buf = buffer; return buf.bumpc().then([](int_type) { return true; }); }; - auto peek_char = [=]() -> pplx::task - { + auto peek_char = [=]() -> pplx::task { concurrency::streams::streambuf buf = buffer; // If task results are immediately available, there's little need to use ".then()," @@ -1198,8 +1162,7 @@ pplx::task _type_parser_base::_parse_input( while (get_op.is_done()) { auto condition = update(get_op); - if (!condition.is_done() || !condition.get()) - return condition; + if (!condition.is_done() || !condition.get()) return condition; get_op = buf.getc(); } @@ -1207,38 +1170,37 @@ pplx::task _type_parser_base::_parse_input( return get_op.then(update); }; - auto finish = - [=](pplx::task op) -> pplx::task - { - op.wait(); - pplx::task result = extract(state); - return result; - }; + auto finish = [=](pplx::task op) -> pplx::task { + op.wait(); + pplx::task result = extract(state); + return result; + }; - return _skip_whitespace(buffer).then([=](pplx::task op) -> pplx::task - { - op.wait(); - return pplx::details::_do_while(peek_char).then(finish); - }); + return _skip_whitespace(buffer).then([=](pplx::task op) -> pplx::task { + op.wait(); + return pplx::details::_do_while(peek_char).then(finish); + }); } template -class type_parser> : public _type_parser_base +class type_parser> : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; static pplx::task parse(streams::streambuf buffer) { - return base::template _parse_input, std::string>(buffer, _accept_char, _extract_result); + return base::template _parse_input, std::string>( + buffer, _accept_char, _extract_result); } private: static bool _accept_char(std::shared_ptr> state, int_type ch) { - if ( ch == traits::eof() || isspace(ch)) return false; + if (ch == traits::eof() || isspace(ch)) return false; state->push_back(CharType(ch)); return true; } @@ -1249,9 +1211,10 @@ class type_parser> : public _type_parser_ba }; template -class type_parser : public _type_parser_base +class type_parser : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; @@ -1260,6 +1223,7 @@ class type_parser : public _type_parser_base { return base::template _parse_input<_int64_state, int64_t>(buffer, _accept_char, _extract_result); } + private: struct _int64_state { @@ -1267,31 +1231,30 @@ class type_parser : public _type_parser_base int64_t result; bool correct; - char minus; // 0 -- no sign, 1 -- plus, 2 -- minus + char minus; // 0 -- no sign, 1 -- plus, 2 -- minus }; static bool _accept_char(std::shared_ptr<_int64_state> state, int_type ch) { - if ( ch == traits::eof()) return false; - if ( state->minus == 0 ) + if (ch == traits::eof()) return false; + if (state->minus == 0) { // OK to find a sign. - if ( !::isdigit(ch) && ch != int_type('+') && ch != int_type('-') ) - return false; + if (!::isdigit(ch) && ch != int_type('+') && ch != int_type('-')) return false; } else { - if ( !::isdigit(ch) ) return false; + if (!::isdigit(ch)) return false; } // At least one digit was found. state->correct = true; - if ( ch == int_type('+') ) + if (ch == int_type('+')) { state->minus = 1; } - else if ( ch == int_type('-') ) + else if (ch == int_type('-')) { state->minus = 2; } @@ -1303,9 +1266,9 @@ class type_parser : public _type_parser_base bool positive = state->result >= 0; state->result *= 10; - state->result += int64_t(ch-int_type('0')); + state->result += int64_t(ch - int_type('0')); - if ( (state->result >= 0) != positive ) + if ((state->result >= 0) != positive) { state->correct = false; return false; @@ -1316,30 +1279,39 @@ class type_parser : public _type_parser_base static pplx::task _extract_result(std::shared_ptr<_int64_state> state) { - if (!state->correct) - throw std::range_error("integer value is too large to fit in 64 bits"); + if (!state->correct) throw std::range_error("integer value is too large to fit in 64 bits"); int64_t result = (state->minus == 2) ? -state->result : state->result; return pplx::task_from_result(result); } }; -template +template struct _double_state { - _double_state() : result(0), minus(0), after_comma(0), exponent(false), exponent_number(0), exponent_minus(0), complete(false), p_exception_string() {} + _double_state() + : result(0) + , minus(0) + , after_comma(0) + , exponent(false) + , exponent_number(0) + , exponent_minus(0) + , complete(false) + , p_exception_string() + { + } FloatingPoint result; - char minus; // 0 -- no sign, 1 -- plus, 2 -- minus + char minus; // 0 -- no sign, 1 -- plus, 2 -- minus int after_comma; bool exponent; int exponent_number; - char exponent_minus; // 0 -- no sign, 1 -- plus, 2 -- minus + char exponent_minus; // 0 -- no sign, 1 -- plus, 2 -- minus bool complete; std::string p_exception_string; }; -template +template static std::string create_exception_message(int_type ch, bool exponent) { std::ostringstream os; @@ -1347,12 +1319,12 @@ static std::string create_exception_message(int_type ch, bool exponent) return os.str(); } -template +template static bool _accept_char(std::shared_ptr<_double_state> state, int_type ch) { - if ( state->minus == 0 ) + if (state->minus == 0) { - if ( !::isdigit(ch) && ch != int_type('.') && ch != int_type('+') && ch != int_type('-') ) + if (!::isdigit(ch) && ch != int_type('.') && ch != int_type('+') && ch != int_type('-')) { if (!state->complete) state->p_exception_string = create_exception_message(ch, false); @@ -1378,7 +1350,7 @@ static bool _accept_char(std::shared_ptr<_double_state> state, in switch (ch) { - case int_type('+') : + case int_type('+'): state->complete = false; if (state->exponent) { @@ -1394,7 +1366,7 @@ static bool _accept_char(std::shared_ptr<_double_state> state, in state->minus = 1; } break; - case int_type('-') : + case int_type('-'): state->complete = false; if (state->exponent) { @@ -1411,17 +1383,16 @@ static bool _accept_char(std::shared_ptr<_double_state> state, in state->minus = 2; } break; - case int_type('.') : + case int_type('.'): state->complete = false; - if (state->after_comma > 0) - return false; + if (state->after_comma > 0) return false; state->after_comma = 1; break; - case int_type('E') : case int_type('e') : + case int_type('E'): + case int_type('e'): state->complete = false; - if (state->exponent) - return false; + if (state->exponent) return false; state->exponent_number = 0; state->exponent = true; break; @@ -1429,51 +1400,45 @@ static bool _accept_char(std::shared_ptr<_double_state> state, in state->complete = true; if (!state->exponent) { - if (state->minus == 0) - state->minus = 1; + if (state->minus == 0) state->minus = 1; state->result *= 10; - state->result += int64_t(ch-int_type('0')); + state->result += int64_t(ch - int_type('0')); - if (state->after_comma > 0) - state->after_comma++; + if (state->after_comma > 0) state->after_comma++; } else { if (state->exponent_minus == 0) state->exponent_minus = 1; state->exponent_number *= 10; - state->exponent_number += int64_t(ch-int_type('0')); + state->exponent_number += int64_t(ch - int_type('0')); } } return true; } -template +template static pplx::task _extract_result(std::shared_ptr<_double_state> state) { - if (state->p_exception_string.length() > 0) - throw std::runtime_error(state->p_exception_string.c_str()); + if (state->p_exception_string.length() > 0) throw std::runtime_error(state->p_exception_string.c_str()); - if (!state->complete && state->exponent) - throw std::runtime_error("Incomplete exponent"); + if (!state->complete && state->exponent) throw std::runtime_error("Incomplete exponent"); FloatingPoint result = static_cast((state->minus == 2) ? -state->result : state->result); - if (state->exponent_minus == 2) - state->exponent_number = 0 - state->exponent_number; + if (state->exponent_minus == 2) state->exponent_number = 0 - state->exponent_number; - if (state->after_comma > 0) - state->exponent_number -= state->after_comma-1; + if (state->after_comma > 0) state->exponent_number -= state->after_comma - 1; if (state->exponent_number >= 0) { result *= pow(FloatingPoint(10.0), state->exponent_number); - #pragma push_macro ("max") - #undef max +#pragma push_macro("max") +#undef max if (result > std::numeric_limits::max() || result < -std::numeric_limits::max()) throw std::overflow_error("The value is too big"); - #pragma pop_macro ("max") +#pragma pop_macro("max") } else { @@ -1481,8 +1446,7 @@ static pplx::task _extract_result(std::shared_ptr<_double_stateexponent_number); - if (!is_zero && - result > -std::numeric_limits::denorm_min() && + if (!is_zero && result > -std::numeric_limits::denorm_min() && result < std::numeric_limits::denorm_min()) throw std::underflow_error("The value is too small"); } @@ -1491,47 +1455,53 @@ static pplx::task _extract_result(std::shared_ptr<_double_state -class type_parser : public _type_parser_base +class type_parser : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; static pplx::task parse(streams::streambuf buffer) { - return base::template _parse_input<_double_state, double>(buffer, _accept_char, _extract_result); + return base::template _parse_input<_double_state, double>( + buffer, _accept_char, _extract_result); } + protected: }; template -class type_parser : public _type_parser_base +class type_parser : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; static pplx::task parse(streams::streambuf buffer) { - return base::template _parse_input<_double_state, float>(buffer, _accept_char, _extract_result); + return base::template _parse_input<_double_state, float>( + buffer, _accept_char, _extract_result); } + protected: }; - template -class type_parser : public _type_parser_base +class type_parser : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; static pplx::task parse(streams::streambuf buffer) { - return base::template _parse_input<_uint64_state,uint64_t>(buffer, _accept_char, _extract_result); + return base::template _parse_input<_uint64_state, uint64_t>(buffer, _accept_char, _extract_result); } private: @@ -1544,43 +1514,45 @@ class type_parser : public _type_parser_base static bool _accept_char(std::shared_ptr<_uint64_state> state, int_type ch) { - if ( !::isdigit(ch) ) return false; + if (!::isdigit(ch)) return false; // At least one digit was found. state->correct = true; // Shift the existing value by 10, then add the new value. state->result *= 10; - state->result += uint64_t(ch-int_type('0')); + state->result += uint64_t(ch - int_type('0')); return true; } static pplx::task _extract_result(std::shared_ptr<_uint64_state> state) { - if (!state->correct) - throw std::range_error("integer value is too large to fit in 64 bits"); + if (!state->correct) throw std::range_error("integer value is too large to fit in 64 bits"); return pplx::task_from_result(state->result); } }; template -class type_parser : public _type_parser_base +class type_parser : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; static pplx::task parse(streams::streambuf buffer) { - return base::template _parse_input<_bool_state,bool>(buffer, _accept_char, _extract_result); + return base::template _parse_input<_bool_state, bool>(buffer, _accept_char, _extract_result); } + private: struct _bool_state { - _bool_state() : state(0) { } - // { 0 -- not started, 1 -- 't', 2 -- 'tr', 3 -- 'tru', 4 -- 'f', 5 -- 'fa', 6 -- 'fal', 7 -- 'fals', 8 -- 'true', 9 -- 'false' } + _bool_state() : state(0) {} + // { 0 -- not started, 1 -- 't', 2 -- 'tr', 3 -- 'tru', 4 -- 'f', 5 -- 'fa', 6 -- 'fal', 7 -- 'fals', 8 -- + // 'true', 9 -- 'false' } short state; }; @@ -1588,44 +1560,62 @@ class type_parser : public _type_parser_base { switch (state->state) { - case 0: - if ( ch == int_type('t') ) state->state = 1; - else if ( ch == int_type('f') ) state->state = 4; - else if ( ch == int_type('1') ) state->state = 8; - else if ( ch == int_type('0') ) state->state = 9; - else return false; - break; - case 1: - if ( ch == int_type('r') ) state->state = 2; - else return false; - break; - case 2: - if ( ch == int_type('u') ) state->state = 3; - else return false; - break; - case 3: - if ( ch == int_type('e') ) state->state = 8; - else return false; - break; - case 4: - if ( ch == int_type('a') ) state->state = 5; - else return false; - break; - case 5: - if ( ch == int_type('l') ) state->state = 6; - else return false; - break; - case 6: - if ( ch == int_type('s') ) state->state = 7; - else return false; - break; - case 7: - if ( ch == int_type('e') ) state->state = 9; - else return false; - break; - case 8: - case 9: - return false; + case 0: + if (ch == int_type('t')) + state->state = 1; + else if (ch == int_type('f')) + state->state = 4; + else if (ch == int_type('1')) + state->state = 8; + else if (ch == int_type('0')) + state->state = 9; + else + return false; + break; + case 1: + if (ch == int_type('r')) + state->state = 2; + else + return false; + break; + case 2: + if (ch == int_type('u')) + state->state = 3; + else + return false; + break; + case 3: + if (ch == int_type('e')) + state->state = 8; + else + return false; + break; + case 4: + if (ch == int_type('a')) + state->state = 5; + else + return false; + break; + case 5: + if (ch == int_type('l')) + state->state = 6; + else + return false; + break; + case 6: + if (ch == int_type('s')) + state->state = 7; + else + return false; + break; + case 7: + if (ch == int_type('e')) + state->state = 9; + else + return false; + break; + case 8: + case 9: return false; } return true; } @@ -1642,119 +1632,113 @@ class type_parser : public _type_parser_base }; template -class type_parser : public _type_parser_base +class type_parser : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; static pplx::task parse(streams::streambuf buffer) { - return base::_skip_whitespace(buffer).then( - [=](pplx::task op) -> pplx::task - { - op.wait(); - return type_parser::_get_char(buffer); - }); + return base::_skip_whitespace(buffer).then([=](pplx::task op) -> pplx::task { + op.wait(); + return type_parser::_get_char(buffer); + }); } + private: static pplx::task _get_char(streams::streambuf buffer) { concurrency::streams::streambuf buf = buffer; - return buf.bumpc().then( - [=](pplx::task op) -> signed char - { - int_type val = op.get(); - if (val == traits::eof()) - throw std::runtime_error("reached end-of-stream while constructing a value"); - return static_cast(val); - }); + return buf.bumpc().then([=](pplx::task op) -> signed char { + int_type val = op.get(); + if (val == traits::eof()) throw std::runtime_error("reached end-of-stream while constructing a value"); + return static_cast(val); + }); } }; template -class type_parser : public _type_parser_base +class type_parser : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; static pplx::task parse(streams::streambuf buffer) { - return base::_skip_whitespace(buffer).then( - [=](pplx::task op) -> pplx::task - { - op.wait(); - return type_parser::_get_char(buffer); - }); + return base::_skip_whitespace(buffer).then([=](pplx::task op) -> pplx::task { + op.wait(); + return type_parser::_get_char(buffer); + }); } + private: static pplx::task _get_char(streams::streambuf buffer) { concurrency::streams::streambuf buf = buffer; - return buf.bumpc().then( - [=](pplx::task op) -> unsigned char - { - int_type val = op.get(); - if (val == traits::eof()) - throw std::runtime_error("reached end-of-stream while constructing a value"); - return static_cast(val); - }); + return buf.bumpc().then([=](pplx::task op) -> unsigned char { + int_type val = op.get(); + if (val == traits::eof()) throw std::runtime_error("reached end-of-stream while constructing a value"); + return static_cast(val); + }); } }; template -class type_parser : public _type_parser_base +class type_parser : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; static pplx::task parse(streams::streambuf buffer) { - return base::_skip_whitespace(buffer).then( - [=](pplx::task op) -> pplx::task - { - op.wait(); - return _get_char(buffer); - }); + return base::_skip_whitespace(buffer).then([=](pplx::task op) -> pplx::task { + op.wait(); + return _get_char(buffer); + }); } + private: static pplx::task _get_char(streams::streambuf buffer) { concurrency::streams::streambuf buf = buffer; - return buf.bumpc().then( - [=](pplx::task op) -> char - { - int_type val = op.get(); - if (val == traits::eof()) - throw std::runtime_error("reached end-of-stream while constructing a value"); - return char(val); - }); + return buf.bumpc().then([=](pplx::task op) -> char { + int_type val = op.get(); + if (val == traits::eof()) throw std::runtime_error("reached end-of-stream while constructing a value"); + return char(val); + }); } }; #ifdef _WIN32 template -class type_parser>> : public _type_parser_base +class type_parser>> + : public _type_parser_base { typedef _type_parser_base base; + public: typedef typename base::traits traits; typedef typename base::int_type int_type; static pplx::task parse(streams::streambuf buffer) { - return base::template _parse_input,std::basic_string>(buffer, _accept_char, _extract_result); + return base::template _parse_input, std::basic_string>( + buffer, _accept_char, _extract_result); } private: - static bool _accept_char(const std::shared_ptr> &state, int_type ch) + static bool _accept_char(const std::shared_ptr>& state, int_type ch) { - if ( ch == concurrency::streams::char_traits::eof() || isspace(ch)) return false; + if (ch == concurrency::streams::char_traits::eof() || isspace(ch)) return false; state->push_back(char(ch)); return true; } @@ -1765,7 +1749,7 @@ class type_parser - #include "cpprest/base_uri.h" +#include namespace web { diff --git a/Release/include/cpprest/version.h b/Release/include/cpprest/version.h index 4abd1d45fe..c829c39a32 100644 --- a/Release/include/cpprest/version.h +++ b/Release/include/cpprest/version.h @@ -1,10 +1,10 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -*/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + */ #define CPPREST_VERSION_MINOR 10 #define CPPREST_VERSION_MAJOR 2 #define CPPREST_VERSION_REVISION 8 -#define CPPREST_VERSION (CPPREST_VERSION_MAJOR*100000+CPPREST_VERSION_MINOR*100+CPPREST_VERSION_REVISION) +#define CPPREST_VERSION (CPPREST_VERSION_MAJOR * 100000 + CPPREST_VERSION_MINOR * 100 + CPPREST_VERSION_REVISION) diff --git a/Release/include/cpprest/ws_client.h b/Release/include/cpprest/ws_client.h index 2ab1b665ff..a956731e16 100644 --- a/Release/include/cpprest/ws_client.h +++ b/Release/include/cpprest/ws_client.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Websocket client side implementation -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Websocket client side implementation + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifndef CASA_WS_CLIENT_H @@ -17,21 +17,19 @@ #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) -#include -#include -#include -#include - -#include "pplx/pplxtasks.h" -#include "cpprest/uri.h" +#include "cpprest/asyncrt_utils.h" #include "cpprest/details/web_utilities.h" #include "cpprest/http_headers.h" -#include "cpprest/asyncrt_utils.h" +#include "cpprest/uri.h" #include "cpprest/ws_msg.h" +#include "pplx/pplxtasks.h" +#include +#include +#include +#include namespace web { - // For backwards compatibility for when in the experimental namespace. // At next major release this should be deleted. namespace experimental = web; @@ -45,14 +43,13 @@ namespace websockets /// WebSocket client side library. namespace client { - /// Websocket close status values. enum class websocket_close_status { normal = 1000, going_away = 1001, protocol_error = 1002, - unsupported = 1003, //or data_mismatch + unsupported = 1003, // or data_mismatch abnormal_close = 1006, inconsistent_datatype = 1007, policy_violation = 1008, @@ -68,93 +65,64 @@ enum class websocket_close_status class websocket_client_config { public: - /// /// Creates a websocket client configuration with default settings. /// - websocket_client_config() : - m_sni_enabled(true), - m_validate_certificates(true) - { - } + websocket_client_config() : m_sni_enabled(true), m_validate_certificates(true) {} /// /// Get the web proxy object /// /// A reference to the web proxy object. - const web_proxy& proxy() const - { - return m_proxy; - } + const web_proxy& proxy() const { return m_proxy; } /// /// Set the web proxy object /// /// The web proxy object. - void set_proxy(const web_proxy &proxy) - { - m_proxy = proxy; - } + void set_proxy(const web_proxy& proxy) { m_proxy = proxy; } /// /// Get the client credentials /// /// A reference to the client credentials. - const web::credentials& credentials() const - { - return m_credentials; - } + const web::credentials& credentials() const { return m_credentials; } /// /// Set the client credentials /// /// The client credentials. - void set_credentials(const web::credentials &cred) - { - m_credentials = cred; - } + void set_credentials(const web::credentials& cred) { m_credentials = cred; } /// /// Disables Server Name Indication (SNI). Default is on. /// - void disable_sni() - { - m_sni_enabled = false; - } + void disable_sni() { m_sni_enabled = false; } /// /// Determines if Server Name Indication (SNI) is enabled. /// /// True if enabled, false otherwise. - bool is_sni_enabled() const - { - return m_sni_enabled; - } + bool is_sni_enabled() const { return m_sni_enabled; } /// /// Sets the server host name to use for TLS Server Name Indication (SNI). /// /// By default the host name is set to the websocket URI host. /// The host name to use, as a string. - void set_server_name(const utf8string &name) - { - m_sni_hostname = name; - } + void set_server_name(const utf8string& name) { m_sni_hostname = name; } /// /// Gets the server host name to use for TLS Server Name Indication (SNI). /// /// Host name as a string. - const utf8string & server_name() const - { - return m_sni_hostname; - } + const utf8string& server_name() const { return m_sni_hostname; } /// /// Sets the User Agent to be used for the connection /// /// The User Agent to use, as a string. - _ASYNCRTIMP void set_user_agent(const utf8string &user_agent); + _ASYNCRTIMP void set_user_agent(const utf8string& user_agent); /// /// Gets the headers of the HTTP request message used in the WebSocket protocol handshake. @@ -163,20 +131,20 @@ class websocket_client_config /// /// Use the to fill in desired headers. /// - web::http::http_headers &headers() { return m_headers; } + web::http::http_headers& headers() { return m_headers; } /// /// Gets a const reference to the headers of the WebSocket protocol handshake HTTP message. /// /// HTTP headers. - const web::http::http_headers &headers() const { return m_headers; } + const web::http::http_headers& headers() const { return m_headers; } /// /// Adds a subprotocol to the request headers. /// /// The name of the subprotocol. /// If additional subprotocols have already been specified, the new one will just be added. - _ASYNCRTIMP void add_subprotocol(const ::utility::string_t &name); + _ASYNCRTIMP void add_subprotocol(const ::utility::string_t& name); /// /// Gets list of the specified subprotocols. @@ -184,26 +152,21 @@ class websocket_client_config /// Vector of all the subprotocols /// If you want all the subprotocols in a comma separated string /// they can be directly looked up in the headers using 'Sec-WebSocket-Protocol'. - _ASYNCRTIMP std::vector< ::utility::string_t> subprotocols() const; - + _ASYNCRTIMP std::vector<::utility::string_t> subprotocols() const; + /// /// Gets the server certificate validation property. /// /// True if certificates are to be verified, false otherwise. - bool validate_certificates() const - { - return m_validate_certificates; - } - + bool validate_certificates() const { return m_validate_certificates; } + /// /// Sets the server certificate validation property. /// - /// False to turn ignore all server certificate validation errors, true otherwise. - /// Note ignoring certificate errors can be dangerous and should be done with caution. - void set_validate_certificates(bool validate_certs) - { - m_validate_certificates = validate_certs; - } + /// False to turn ignore all server certificate validation errors, true + /// otherwise. Note ignoring certificate errors can be dangerous and should be done with + /// caution. + void set_validate_certificates(bool validate_certs) { m_validate_certificates = validate_certs; } private: web::web_proxy m_proxy; @@ -220,13 +183,11 @@ class websocket_client_config class websocket_exception : public std::exception { public: - /// /// Creates an websocket_exception with just a string message and no error code. /// /// Error message string. - websocket_exception(const utility::string_t &whatArg) - : m_msg(utility::conversions::to_utf8string(whatArg)) {} + websocket_exception(const utility::string_t& whatArg) : m_msg(utility::conversions::to_utf8string(whatArg)) {} #ifdef _WIN32 /// @@ -241,8 +202,7 @@ class websocket_exception : public std::exception /// The message of the error code will be used as the what() string message. /// /// Error code value. - websocket_exception(int errorCode) - : m_errorCode(utility::details::create_error_code(errorCode)) + websocket_exception(int errorCode) : m_errorCode(utility::details::create_error_code(errorCode)) { m_msg = m_errorCode.message(); } @@ -252,10 +212,11 @@ class websocket_exception : public std::exception /// /// Error code value. /// Message to use in what() string. - websocket_exception(int errorCode, const utility::string_t &whatArg) - : m_errorCode(utility::details::create_error_code(errorCode)), - m_msg(utility::conversions::to_utf8string(whatArg)) - {} + websocket_exception(int errorCode, const utility::string_t& whatArg) + : m_errorCode(utility::details::create_error_code(errorCode)) + , m_msg(utility::conversions::to_utf8string(whatArg)) + { + } #ifdef _WIN32 /// @@ -264,19 +225,19 @@ class websocket_exception : public std::exception /// Error code value. /// Message to use in what() string. websocket_exception(int errorCode, std::string whatArg) - : m_errorCode(utility::details::create_error_code(errorCode)), - m_msg(std::move(whatArg)) - {} + : m_errorCode(utility::details::create_error_code(errorCode)), m_msg(std::move(whatArg)) + { + } /// /// Creates a websocket_exception from a error code and string message to use as the what() argument. /// Error code. /// Message to use in what() string. /// - websocket_exception(std::error_code code, std::string whatArg) : - m_errorCode(std::move(code)), - m_msg(std::move(whatArg)) - {} + websocket_exception(std::error_code code, std::string whatArg) + : m_errorCode(std::move(code)), m_msg(std::move(whatArg)) + { + } #endif /// @@ -285,7 +246,7 @@ class websocket_exception : public std::exception /// /// Error code value. /// Error category for the code. - websocket_exception(int errorCode, const std::error_category &cat) : m_errorCode(std::error_code(errorCode, cat)) + websocket_exception(int errorCode, const std::error_category& cat) : m_errorCode(std::error_code(errorCode, cat)) { m_msg = m_errorCode.message(); } @@ -295,28 +256,22 @@ class websocket_exception : public std::exception /// Error code. /// Message to use in what() string. /// - websocket_exception(std::error_code code, const utility::string_t &whatArg) : - m_errorCode(std::move(code)), - m_msg(utility::conversions::to_utf8string(whatArg)) - {} + websocket_exception(std::error_code code, const utility::string_t& whatArg) + : m_errorCode(std::move(code)), m_msg(utility::conversions::to_utf8string(whatArg)) + { + } /// /// Gets a string identifying the cause of the exception. /// /// A null terminated character string. - const char* what() const CPPREST_NOEXCEPT - { - return m_msg.c_str(); - } + const char* what() const CPPREST_NOEXCEPT { return m_msg.c_str(); } /// /// Gets the underlying error code for the cause of the exception. /// /// The error_code object associated with the exception. - const std::error_code & error_code() const CPPREST_NOEXCEPT - { - return m_errorCode; - } + const std::error_code& error_code() const CPPREST_NOEXCEPT { return m_errorCode; } private: std::error_code m_errorCode; @@ -325,43 +280,34 @@ class websocket_exception : public std::exception namespace details { - // Interface to be implemented by the websocket client callback implementations. class websocket_client_callback_impl { public: + websocket_client_callback_impl(websocket_client_config config) : m_config(std::move(config)) {} - websocket_client_callback_impl(websocket_client_config config) : - m_config(std::move(config)) {} - - virtual ~websocket_client_callback_impl() CPPREST_NOEXCEPT{} + virtual ~websocket_client_callback_impl() CPPREST_NOEXCEPT {} virtual pplx::task connect() = 0; - virtual pplx::task send(websocket_outgoing_message &msg) = 0; + virtual pplx::task send(websocket_outgoing_message& msg) = 0; virtual void set_message_handler(const std::function& handler) = 0; virtual pplx::task close() = 0; - virtual pplx::task close(websocket_close_status close_status, const utility::string_t &close_reason = _XPLATSTR("")) = 0; + virtual pplx::task close(websocket_close_status close_status, + const utility::string_t& close_reason = _XPLATSTR("")) = 0; - virtual void set_close_handler(const std::function& handler) = 0; + virtual void set_close_handler( + const std::function& + handler) = 0; - const web::uri& uri() const - { - return m_uri; - } + const web::uri& uri() const { return m_uri; } - void set_uri(const web::uri &uri) - { - m_uri = uri; - } + void set_uri(const web::uri& uri) { m_uri = uri; } - const websocket_client_config& config() const - { - return m_config; - } + const websocket_client_config& config() const { return m_config; } static void verify_uri(const web::uri& uri) { @@ -393,7 +339,6 @@ class websocket_client_callback_impl // Interface to be implemented by the websocket client task implementations. class websocket_client_task_impl { - public: _ASYNCRTIMP websocket_client_task_impl(websocket_client_config config); @@ -401,9 +346,9 @@ class websocket_client_task_impl _ASYNCRTIMP pplx::task receive(); - _ASYNCRTIMP void close_pending_tasks_with_error(const websocket_exception &exc); + _ASYNCRTIMP void close_pending_tasks_with_error(const websocket_exception& exc); - const std::shared_ptr & callback_client() const { return m_callback_client; }; + const std::shared_ptr& callback_client() const { return m_callback_client; }; private: void set_handler(); @@ -423,7 +368,7 @@ class websocket_client_task_impl std::shared_ptr m_callback_client; }; -} +} // namespace details /// /// Websocket client class, used to maintain a connection to a remote host for an extended session. @@ -434,31 +379,31 @@ class websocket_client /// /// Creates a new websocket_client. /// - websocket_client() : - m_client(std::make_shared(websocket_client_config())) - {} + websocket_client() : m_client(std::make_shared(websocket_client_config())) {} /// /// Creates a new websocket_client. /// - /// The client configuration object containing the possible configuration options to initialize the websocket_client. - websocket_client(websocket_client_config config) : - m_client(std::make_shared(std::move(config))) - {} + /// The client configuration object containing the possible configuration options to initialize + /// the websocket_client. + websocket_client(websocket_client_config config) + : m_client(std::make_shared(std::move(config))) + { + } /// /// Connects to the remote network destination. The connect method initiates the websocket handshake with the /// remote network destination, takes care of the protocol upgrade request. /// /// The uri address to connect. - /// An asynchronous operation that is completed once the client has successfully connected to the websocket server. - pplx::task connect(const web::uri &uri) + /// An asynchronous operation that is completed once the client has successfully connected to the websocket + /// server. + pplx::task connect(const web::uri& uri) { m_client->callback_client()->verify_uri(uri); m_client->callback_client()->set_uri(uri); auto client = m_client; - return m_client->callback_client()->connect().then([client](pplx::task result) - { + return m_client->callback_client()->connect().then([client](pplx::task result) { try { result.get(); @@ -475,36 +420,31 @@ class websocket_client /// Sends a websocket message to the server . /// /// An asynchronous operation that is completed once the message is sent. - pplx::task send(websocket_outgoing_message msg) - { - return m_client->callback_client()->send(msg); - } + pplx::task send(websocket_outgoing_message msg) { return m_client->callback_client()->send(msg); } /// /// Receive a websocket message. /// - /// An asynchronous operation that is completed when a message has been received by the client endpoint. - pplx::task receive() - { - return m_client->receive(); - } + /// An asynchronous operation that is completed when a message has been received by the client + /// endpoint. + pplx::task receive() { return m_client->receive(); } /// - /// Closes a websocket client connection, sends a close frame to the server and waits for a close message from the server. + /// Closes a websocket client connection, sends a close frame to the server and waits for a close message from the + /// server. /// /// An asynchronous operation that is completed the connection has been successfully closed. - pplx::task close() - { - return m_client->callback_client()->close(); - } + pplx::task close() { return m_client->callback_client()->close(); } /// - /// Closes a websocket client connection, sends a close frame to the server and waits for a close message from the server. + /// Closes a websocket client connection, sends a close frame to the server and waits for a close message from the + /// server. /// - /// Endpoint MAY use the following pre-defined status codes when sending a Close frame. - /// While closing an established connection, an endpoint may indicate the reason for closure. - /// An asynchronous operation that is completed the connection has been successfully closed. - pplx::task close(websocket_close_status close_status, const utility::string_t& close_reason=_XPLATSTR("")) + /// Endpoint MAY use the following pre-defined status codes when sending a Close + /// frame. While closing an established connection, an endpoint may indicate the + /// reason for closure. An asynchronous operation that is completed the connection has been + /// successfully closed. + pplx::task close(websocket_close_status close_status, const utility::string_t& close_reason = _XPLATSTR("")) { return m_client->callback_client()->close(close_status, close_reason); } @@ -513,27 +453,22 @@ class websocket_client /// Gets the websocket client URI. /// /// URI connected to. - const web::uri& uri() const - { - return m_client->callback_client()->uri(); - } + const web::uri& uri() const { return m_client->callback_client()->uri(); } /// /// Gets the websocket client config object. /// /// A reference to the client configuration object. - const websocket_client_config& config() const - { - return m_client->callback_client()->config(); - } + const websocket_client_config& config() const { return m_client->callback_client()->config(); } private: std::shared_ptr m_client; }; /// -/// Websocket client class, used to maintain a connection to a remote host for an extended session, uses callback APIs for handling receive and close event instead of async task. -/// For some scenarios would be a alternative for the websocket_client like if you want to special handling on close event. +/// Websocket client class, used to maintain a connection to a remote host for an extended session, uses callback APIs +/// for handling receive and close event instead of async task. For some scenarios would be a alternative for the +/// websocket_client like if you want to special handling on close event. /// class websocket_callback_client { @@ -546,7 +481,8 @@ class websocket_callback_client /// /// Creates a new websocket_callback_client. /// - /// The client configuration object containing the possible configuration options to initialize the websocket_client. + /// The client configuration object containing the possible configuration options to + /// initialize the websocket_client. _ASYNCRTIMP websocket_callback_client(websocket_client_config client_config); /// @@ -554,8 +490,9 @@ class websocket_callback_client /// remote network destination, takes care of the protocol upgrade request. /// /// The uri address to connect. - /// An asynchronous operation that is completed once the client has successfully connected to the websocket server. - pplx::task connect(const web::uri &uri) + /// An asynchronous operation that is completed once the client has successfully connected to the websocket + /// server. + pplx::task connect(const web::uri& uri) { m_client->verify_uri(uri); m_client->set_uri(uri); @@ -566,10 +503,7 @@ class websocket_callback_client /// Sends a websocket message to the server . /// /// An asynchronous operation that is completed once the message is sent. - pplx::task send(websocket_outgoing_message msg) - { - return m_client->send(msg); - } + pplx::task send(websocket_outgoing_message msg) { return m_client->send(msg); } /// /// Set the received handler for notification of client websocket messages. @@ -584,20 +518,20 @@ class websocket_callback_client } /// - /// Closes a websocket client connection, sends a close frame to the server and waits for a close message from the server. + /// Closes a websocket client connection, sends a close frame to the server and waits for a close message from the + /// server. /// /// An asynchronous operation that is completed the connection has been successfully closed. - pplx::task close() - { - return m_client->close(); - } + pplx::task close() { return m_client->close(); } /// - /// Closes a websocket client connection, sends a close frame to the server and waits for a close message from the server. + /// Closes a websocket client connection, sends a close frame to the server and waits for a close message from the + /// server. /// - /// Endpoint MAY use the following pre-defined status codes when sending a Close frame. - /// While closing an established connection, an endpoint may indicate the reason for closure. - /// An asynchronous operation that is completed the connection has been successfully closed. + /// Endpoint MAY use the following pre-defined status codes when sending a Close + /// frame. While closing an established connection, an endpoint may indicate the + /// reason for closure. An asynchronous operation that is completed the connection has been + /// successfully closed. pplx::task close(websocket_close_status close_status, const utility::string_t& close_reason = _XPLATSTR("")) { return m_client->close(close_status, close_reason); @@ -611,7 +545,9 @@ class websocket_callback_client /// reason: The reason string used by the endpoint when sending a Close frame. /// error: The error code if the websocket is closed with abnormal error. /// - void set_close_handler(const std::function& handler) + void set_close_handler(const std::function& handler) { m_client->set_close_handler(handler); } @@ -620,26 +556,22 @@ class websocket_callback_client /// Gets the websocket client URI. /// /// URI connected to. - const web::uri& uri() const - { - return m_client->uri(); - } + const web::uri& uri() const { return m_client->uri(); } /// /// Gets the websocket client config object. /// /// A reference to the client configuration object. - const websocket_client_config& config() const - { - return m_client->config(); - } + const websocket_client_config& config() const { return m_client->config(); } private: std::shared_ptr m_client; }; -}}} +} // namespace client +} // namespace websockets +} // namespace web #endif -#endif \ No newline at end of file +#endif diff --git a/Release/include/cpprest/ws_msg.h b/Release/include/cpprest/ws_msg.h index 326541c7a1..64cee7ae52 100644 --- a/Release/include/cpprest/ws_msg.h +++ b/Release/include/cpprest/ws_msg.h @@ -1,27 +1,26 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Websocket incoming and outgoing message definitions. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Websocket incoming and outgoing message definitions. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "cpprest/details/basic_types.h" #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) -#include -#include - -#include "pplx/pplxtasks.h" -#include "cpprest/streams.h" +#include "cpprest/asyncrt_utils.h" #include "cpprest/containerstream.h" +#include "cpprest/streams.h" #include "cpprest/uri.h" -#include "cpprest/asyncrt_utils.h" +#include "pplx/pplxtasks.h" +#include +#include namespace web { @@ -29,15 +28,14 @@ namespace websockets { namespace client { - namespace details { - class winrt_callback_client; - class wspp_callback_client; +class winrt_callback_client; +class wspp_callback_client; #if defined(__cplusplus_winrt) - ref class ReceiveContext; +ref class ReceiveContext; #endif -} +} // namespace details /// /// The different types of websocket message. @@ -60,23 +58,19 @@ enum class websocket_message_type class websocket_outgoing_message { public: - #if !defined(__cplusplus_winrt) /// /// Sets a the outgoing message to be an unsolicited pong message. /// This is useful when the client side wants to check whether the server is alive. /// - void set_pong_message() - { - this->set_message_pong(); - } + void set_pong_message() { this->set_message_pong(); } #endif /// /// Sets a UTF-8 message as the message body. /// /// UTF-8 String containing body of the message. - void set_utf8_message(std::string &&data) + void set_utf8_message(std::string&& data) { this->set_message(concurrency::streams::container_buffer(std::move(data))); } @@ -85,7 +79,7 @@ class websocket_outgoing_message /// Sets a UTF-8 message as the message body. /// /// UTF-8 String containing body of the message. - void set_utf8_message(const std::string &data) + void set_utf8_message(const std::string& data) { this->set_message(concurrency::streams::container_buffer(data)); } @@ -95,7 +89,7 @@ class websocket_outgoing_message /// /// casablanca input stream representing the body of the message. /// Upon sending, the entire stream may be buffered to determine the length. - void set_utf8_message(const concurrency::streams::istream &istream) + void set_utf8_message(const concurrency::streams::istream& istream) { this->set_message(istream, SIZE_MAX, websocket_message_type::text_message); } @@ -105,7 +99,7 @@ class websocket_outgoing_message /// /// casablanca input stream representing the body of the message. /// number of bytes to send. - void set_utf8_message(const concurrency::streams::istream &istream, size_t len) + void set_utf8_message(const concurrency::streams::istream& istream, size_t len) { this->set_message(istream, len, websocket_message_type::text_message); } @@ -115,7 +109,7 @@ class websocket_outgoing_message /// /// casablanca input stream representing the body of the message. /// number of bytes to send. - void set_binary_message(const concurrency::streams::istream &istream, size_t len) + void set_binary_message(const concurrency::streams::istream& istream, size_t len) { this->set_message(istream, len, websocket_message_type::binary_message); } @@ -125,7 +119,7 @@ class websocket_outgoing_message /// /// Input stream representing the body of the message. /// Upon sending, the entire stream may be buffered to determine the length. - void set_binary_message(const concurrency::streams::istream &istream) + void set_binary_message(const concurrency::streams::istream& istream) { this->set_message(istream, SIZE_MAX, websocket_message_type::binary_message); } @@ -139,36 +133,30 @@ class websocket_outgoing_message websocket_message_type m_msg_type; size_t m_length; - void signal_body_sent() const - { - m_body_sent.set(); - } + void signal_body_sent() const { m_body_sent.set(); } - void signal_body_sent(const std::exception_ptr &e) const - { - m_body_sent.set_exception(e); - } + void signal_body_sent(const std::exception_ptr& e) const { m_body_sent.set_exception(e); } - const pplx::task_completion_event & body_sent() const { return m_body_sent; } + const pplx::task_completion_event& body_sent() const { return m_body_sent; } #if !defined(__cplusplus_winrt) - void set_message_pong() - { + void set_message_pong() + { concurrency::streams::container_buffer buffer(""); - m_msg_type = websocket_message_type::pong; - m_length = static_cast(buffer.size()); - m_body = buffer; - } + m_msg_type = websocket_message_type::pong; + m_length = static_cast(buffer.size()); + m_body = buffer; + } #endif - void set_message(const concurrency::streams::container_buffer &buffer) + void set_message(const concurrency::streams::container_buffer& buffer) { m_msg_type = websocket_message_type::text_message; m_length = static_cast(buffer.size()); m_body = buffer; } - void set_message(const concurrency::streams::istream &istream, size_t len, websocket_message_type msg_type) + void set_message(const concurrency::streams::istream& istream, size_t len, websocket_message_type msg_type) { m_msg_type = msg_type; m_length = len; @@ -182,7 +170,6 @@ class websocket_outgoing_message class websocket_incoming_message { public: - /// /// Extracts the body of the incoming message as a string value, only if the message type is UTF-8. /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out. @@ -200,8 +187,8 @@ class websocket_incoming_message /// concurrency::streams::istream body() const { - auto to_uint8_t_stream = [](const concurrency::streams::streambuf &buf) -> concurrency::streams::istream - { + auto to_uint8_t_stream = + [](const concurrency::streams::streambuf& buf) -> concurrency::streams::istream { return buf.create_istream(); }; return to_uint8_t_stream(m_body); @@ -210,28 +197,19 @@ class websocket_incoming_message /// /// Returns the length of the received message. /// - size_t length() const - { - return static_cast(m_body.size()); - } + size_t length() const { return static_cast(m_body.size()); } /// /// Returns the type of the received message. /// CASABLANCA_DEPRECATED("Incorrectly spelled API, use message_type() instead.") - websocket_message_type messge_type() const - { - return m_msg_type; - } + websocket_message_type messge_type() const { return m_msg_type; } /// /// Returns the type of the received message, either string or binary. /// /// websocket_message_type - websocket_message_type message_type() const - { - return m_msg_type; - } + websocket_message_type message_type() const { return m_msg_type; } private: friend class details::winrt_callback_client; @@ -246,6 +224,8 @@ class websocket_incoming_message websocket_message_type m_msg_type; }; -}}} +} // namespace client +} // namespace websockets +} // namespace web #endif diff --git a/Release/include/pplx/pplx.h b/Release/include/pplx/pplx.h index 5a7c970319..d9ba9c619a 100644 --- a/Release/include/pplx/pplx.h +++ b/Release/include/pplx/pplx.h @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Parallel Patterns Library -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Parallel Patterns Library + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -56,10 +56,10 @@ // conditional expression is constant #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable: 4127) +#pragma warning(disable : 4127) #endif -#pragma pack(push,_CRT_PACKING) +#pragma pack(push, _CRT_PACKING) /// /// The pplx namespace provides classes and functions that give you access to the Concurrency Runtime, @@ -68,7 +68,6 @@ /**/ namespace pplx { - /// /// Sets the ambient scheduler to be used by the PPL constructs. /// @@ -81,137 +80,124 @@ _PPLXIMP std::shared_ptr _pplx_cdecl get_ambient_sche namespace details { - // - // An internal exception that is used for cancellation. Users do not "see" this exception except through the - // resulting stack unwind. This exception should never be intercepted by user code. It is intended - // for use by the runtime only. - // - class _Interruption_exception : public std::exception - { - public: - _Interruption_exception(){} - }; - - template - struct _AutoDeleter - { - _AutoDeleter(_T *_PPtr) : _Ptr(_PPtr) {} - ~_AutoDeleter () { delete _Ptr; } - _T *_Ptr; - }; +// +// An internal exception that is used for cancellation. Users do not "see" this exception except through the +// resulting stack unwind. This exception should never be intercepted by user code. It is intended +// for use by the runtime only. +// +class _Interruption_exception : public std::exception +{ +public: + _Interruption_exception() {} +}; - struct _TaskProcHandle - { - _TaskProcHandle() - { - } +template +struct _AutoDeleter +{ + _AutoDeleter(_T* _PPtr) : _Ptr(_PPtr) {} + ~_AutoDeleter() { delete _Ptr; } + _T* _Ptr; +}; - virtual ~_TaskProcHandle() {} - virtual void invoke() const = 0; +struct _TaskProcHandle +{ + _TaskProcHandle() {} - static void _pplx_cdecl _RunChoreBridge(void * _Parameter) - { - auto _PTaskHandle = static_cast<_TaskProcHandle *>(_Parameter); - _AutoDeleter<_TaskProcHandle> _AutoDeleter(_PTaskHandle); - _PTaskHandle->invoke(); - } - }; + virtual ~_TaskProcHandle() {} + virtual void invoke() const = 0; - enum _TaskInliningMode + static void _pplx_cdecl _RunChoreBridge(void* _Parameter) { - // Disable inline scheduling - _NoInline = 0, - // Let runtime decide whether to do inline scheduling or not - _DefaultAutoInline = 16, - // Always do inline scheduling - _ForceInline = -1, - }; - - // This is an abstraction that is built on top of the scheduler to provide these additional functionalities - // - Ability to wait on a work item - // - Ability to cancel a work item - // - Ability to inline work on invocation of RunAndWait - class _TaskCollectionImpl - { - public: + auto _PTaskHandle = static_cast<_TaskProcHandle*>(_Parameter); + _AutoDeleter<_TaskProcHandle> _AutoDeleter(_PTaskHandle); + _PTaskHandle->invoke(); + } +}; - typedef _TaskProcHandle _TaskProcHandle_t; +enum _TaskInliningMode +{ + // Disable inline scheduling + _NoInline = 0, + // Let runtime decide whether to do inline scheduling or not + _DefaultAutoInline = 16, + // Always do inline scheduling + _ForceInline = -1, +}; + +// This is an abstraction that is built on top of the scheduler to provide these additional functionalities +// - Ability to wait on a work item +// - Ability to cancel a work item +// - Ability to inline work on invocation of RunAndWait +class _TaskCollectionImpl +{ +public: + typedef _TaskProcHandle _TaskProcHandle_t; - _TaskCollectionImpl(scheduler_ptr _PScheduler) - : _M_pScheduler(_PScheduler) - { - } + _TaskCollectionImpl(scheduler_ptr _PScheduler) : _M_pScheduler(_PScheduler) {} - void _ScheduleTask(_TaskProcHandle_t* _PTaskHandle, _TaskInliningMode _InliningMode) + void _ScheduleTask(_TaskProcHandle_t* _PTaskHandle, _TaskInliningMode _InliningMode) + { + if (_InliningMode == _ForceInline) { - if (_InliningMode == _ForceInline) - { - _TaskProcHandle_t::_RunChoreBridge(_PTaskHandle); - } - else - { - _M_pScheduler->schedule(_TaskProcHandle_t::_RunChoreBridge, _PTaskHandle); - } + _TaskProcHandle_t::_RunChoreBridge(_PTaskHandle); } - - void _Cancel() + else { - // No cancellation support + _M_pScheduler->schedule(_TaskProcHandle_t::_RunChoreBridge, _PTaskHandle); } + } - void _RunAndWait() - { - // No inlining support yet - _Wait(); - } + void _Cancel() + { + // No cancellation support + } - void _Wait() - { - _M_Completed.wait(); - } + void _RunAndWait() + { + // No inlining support yet + _Wait(); + } - void _Complete() - { - _M_Completed.set(); - } + void _Wait() { _M_Completed.wait(); } - scheduler_ptr _GetScheduler() const - { - return _M_pScheduler; - } + void _Complete() { _M_Completed.set(); } - // Fire and forget - static void _RunTask(TaskProc_t _Proc, void * _Parameter, _TaskInliningMode _InliningMode) + scheduler_ptr _GetScheduler() const { return _M_pScheduler; } + + // Fire and forget + static void _RunTask(TaskProc_t _Proc, void* _Parameter, _TaskInliningMode _InliningMode) + { + if (_InliningMode == _ForceInline) { - if (_InliningMode == _ForceInline) - { - _Proc(_Parameter); - } - else - { - // Schedule the work on the ambient scheduler - get_ambient_scheduler()->schedule(_Proc, _Parameter); - } + _Proc(_Parameter); } - - static bool _pplx_cdecl _Is_cancellation_requested() + else { - // We do not yet have the ability to determine the current task. So return false always - return false; + // Schedule the work on the ambient scheduler + get_ambient_scheduler()->schedule(_Proc, _Parameter); } - private: - - extensibility::event_t _M_Completed; - scheduler_ptr _M_pScheduler; - }; + } - // For create_async lambdas that return a (non-task) result, we oversubscriber the current task for the duration of the - // lambda. - struct _Task_generator_oversubscriber {}; + static bool _pplx_cdecl _Is_cancellation_requested() + { + // We do not yet have the ability to determine the current task. So return false always + return false; + } + +private: + extensibility::event_t _M_Completed; + scheduler_ptr _M_pScheduler; +}; + +// For create_async lambdas that return a (non-task) result, we oversubscriber the current task for the duration of the +// lambda. +struct _Task_generator_oversubscriber +{ +}; - typedef _TaskCollectionImpl _TaskCollection_t; - typedef _TaskInliningMode _TaskInliningMode_t; - typedef _Task_generator_oversubscriber _Task_generator_oversubscriber_t; +typedef _TaskCollectionImpl _TaskCollection_t; +typedef _TaskInliningMode _TaskInliningMode_t; +typedef _Task_generator_oversubscriber _Task_generator_oversubscriber_t; } // namespace details diff --git a/Release/include/pplx/pplxcancellation_token.h b/Release/include/pplx/pplxcancellation_token.h index ad729809b7..b7ad1a07a2 100644 --- a/Release/include/pplx/pplxcancellation_token.h +++ b/Release/include/pplx/pplxcancellation_token.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Parallel Patterns Library : cancellation_token -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Parallel Patterns Library : cancellation_token + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -22,18 +22,17 @@ #error This file must not be included for Visual Studio 12 or later #endif +#include "pplx/pplxinterface.h" #include #include -#include "pplx/pplxinterface.h" -#pragma pack(push,_CRT_PACKING) +#pragma pack(push, _CRT_PACKING) // All header files are required to be protected from the macro new #pragma push_macro("new") #undef new namespace pplx { - /// /// This class describes an exception thrown by the PPL tasks layer in order to force the current task /// to cancel. It is also thrown by the get() method on task, for a @@ -55,26 +54,17 @@ class task_canceled : public std::exception /// A descriptive message of the error. /// /**/ - explicit task_canceled(_In_z_ const char * _Message) throw() - : _message(_Message) - { - } + explicit task_canceled(_In_z_ const char* _Message) throw() : _message(_Message) {} /// /// Constructs a task_canceled object. /// /**/ - task_canceled() throw() - : exception() - { - } + task_canceled() throw() : exception() {} - ~task_canceled() throw () {} + ~task_canceled() throw() {} - const char* what() const CPPREST_NOEXCEPT - { - return _message.c_str(); - } + const char* what() const CPPREST_NOEXCEPT { return _message.c_str(); } }; /// @@ -82,7 +72,8 @@ class task_canceled : public std::exception /// described by another exception type thrown by the Concurrency Runtime. /// /// -/// The various methods which throw this exception will generally document under what circumstances they will throw it. +/// The various methods which throw this exception will generally document under what circumstances they will throw +/// it. /// /**/ class invalid_operation : public std::exception @@ -98,334 +89,287 @@ class invalid_operation : public std::exception /// A descriptive message of the error. /// /**/ - invalid_operation(_In_z_ const char * _Message) throw() - : _message(_Message) - { - } + invalid_operation(_In_z_ const char* _Message) throw() : _message(_Message) {} /// /// Constructs an invalid_operation object. /// /**/ - invalid_operation() throw() - : exception() - { - } - - ~invalid_operation() throw () {} + invalid_operation() throw() : exception() {} - const char* what() const CPPREST_NOEXCEPT - { - return _message.c_str(); - } + ~invalid_operation() throw() {} + + const char* what() const CPPREST_NOEXCEPT { return _message.c_str(); } }; namespace details { +// Base class for all reference counted objects +class _RefCounter +{ +public: + virtual ~_RefCounter() { _ASSERTE(_M_refCount == 0); } - // Base class for all reference counted objects - class _RefCounter + // Acquires a reference + // Returns the new reference count. + long _Reference() { - public: - - virtual ~_RefCounter() - { - _ASSERTE(_M_refCount == 0); - } - - // Acquires a reference - // Returns the new reference count. - long _Reference() - { - long _Refcount = atomic_increment(_M_refCount); - - // 0 - 1 transition is illegal - _ASSERTE(_Refcount > 1); - return _Refcount; - } - - // Releases the reference - // Returns the new reference count - long _Release() - { - long _Refcount = atomic_decrement(_M_refCount); - _ASSERTE(_Refcount >= 0); - - if (_Refcount == 0) - { - _Destroy(); - } + long _Refcount = atomic_increment(_M_refCount); - return _Refcount; - } + // 0 - 1 transition is illegal + _ASSERTE(_Refcount > 1); + return _Refcount; + } - protected: + // Releases the reference + // Returns the new reference count + long _Release() + { + long _Refcount = atomic_decrement(_M_refCount); + _ASSERTE(_Refcount >= 0); - // Allow derived classes to provide their own deleter - virtual void _Destroy() + if (_Refcount == 0) { - delete this; + _Destroy(); } - // Only allow instantiation through derived class - _RefCounter(long _InitialCount = 1) : _M_refCount(_InitialCount) - { - _ASSERTE(_M_refCount > 0); - } + return _Refcount; + } - // Reference count - atomic_long _M_refCount; - }; +protected: + // Allow derived classes to provide their own deleter + virtual void _Destroy() { delete this; } - class _CancellationTokenState; + // Only allow instantiation through derived class + _RefCounter(long _InitialCount = 1) : _M_refCount(_InitialCount) { _ASSERTE(_M_refCount > 0); } - class _CancellationTokenRegistration : public _RefCounter - { - private: + // Reference count + atomic_long _M_refCount; +}; - static const long _STATE_CLEAR = 0; - static const long _STATE_DEFER_DELETE = 1; - static const long _STATE_SYNCHRONIZE = 2; - static const long _STATE_CALLED = 3; +class _CancellationTokenState; - public: +class _CancellationTokenRegistration : public _RefCounter +{ +private: + static const long _STATE_CLEAR = 0; + static const long _STATE_DEFER_DELETE = 1; + static const long _STATE_SYNCHRONIZE = 2; + static const long _STATE_CALLED = 3; - _CancellationTokenRegistration(long _InitialRefs = 1) : - _RefCounter(_InitialRefs), - _M_state(_STATE_CALLED), - _M_pTokenState(NULL) - { - } +public: + _CancellationTokenRegistration(long _InitialRefs = 1) + : _RefCounter(_InitialRefs), _M_state(_STATE_CALLED), _M_pTokenState(NULL) + { + } - _CancellationTokenState *_GetToken() const - { - return _M_pTokenState; - } + _CancellationTokenState* _GetToken() const { return _M_pTokenState; } - protected: +protected: + virtual ~_CancellationTokenRegistration() { _ASSERTE(_M_state != _STATE_CLEAR); } - virtual ~_CancellationTokenRegistration() - { - _ASSERTE(_M_state != _STATE_CLEAR); - } + virtual void _Exec() = 0; - virtual void _Exec() = 0; +private: + friend class _CancellationTokenState; - private: + void _Invoke() + { + long tid = ::pplx::details::platform::GetCurrentThreadId(); + _ASSERTE((tid & 0x3) == 0); // If this ever fires, we need a different encoding for this. - friend class _CancellationTokenState; + long result = atomic_compare_exchange(_M_state, tid, _STATE_CLEAR); - void _Invoke() + if (result == _STATE_CLEAR) { - long tid = ::pplx::details::platform::GetCurrentThreadId(); - _ASSERTE((tid & 0x3) == 0); // If this ever fires, we need a different encoding for this. + _Exec(); - long result = atomic_compare_exchange(_M_state, tid, _STATE_CLEAR); + result = atomic_compare_exchange(_M_state, _STATE_CALLED, tid); - if (result == _STATE_CLEAR) + if (result == _STATE_SYNCHRONIZE) { - _Exec(); - - result = atomic_compare_exchange(_M_state, _STATE_CALLED, tid); - - if (result == _STATE_SYNCHRONIZE) - { - _M_pSyncBlock->set(); - } + _M_pSyncBlock->set(); } - _Release(); } + _Release(); + } - atomic_long _M_state; - extensibility::event_t *_M_pSyncBlock; - _CancellationTokenState *_M_pTokenState; - }; + atomic_long _M_state; + extensibility::event_t* _M_pSyncBlock; + _CancellationTokenState* _M_pTokenState; +}; - template - class _CancellationTokenCallback : public _CancellationTokenRegistration - { - public: +template +class _CancellationTokenCallback : public _CancellationTokenRegistration +{ +public: + _CancellationTokenCallback(const _Function& _Func) : _M_function(_Func) {} - _CancellationTokenCallback(const _Function& _Func) : - _M_function(_Func) - { - } +protected: + virtual void _Exec() { _M_function(); } - protected: +private: + _Function _M_function; +}; - virtual void _Exec() - { - _M_function(); - } +class CancellationTokenRegistration_TaskProc : public _CancellationTokenRegistration +{ +public: + CancellationTokenRegistration_TaskProc(TaskProc_t proc, _In_ void* pData, int initialRefs) + : _CancellationTokenRegistration(initialRefs), m_proc(proc), m_pData(pData) + { + } - private: +protected: + virtual void _Exec() { m_proc(m_pData); } - _Function _M_function; - }; +private: + TaskProc_t m_proc; + void* m_pData; +}; - class CancellationTokenRegistration_TaskProc : public _CancellationTokenRegistration +// The base implementation of a cancellation token. +class _CancellationTokenState : public _RefCounter +{ +protected: + class TokenRegistrationContainer { + private: + typedef struct _Node + { + _CancellationTokenRegistration* _M_token; + _Node* _M_next; + } Node; + public: + TokenRegistrationContainer() : _M_begin(nullptr), _M_last(nullptr) {} - CancellationTokenRegistration_TaskProc(TaskProc_t proc, _In_ void *pData, int initialRefs) : - _CancellationTokenRegistration(initialRefs), m_proc(proc), m_pData(pData) + ~TokenRegistrationContainer() { +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 6001) +#endif + auto node = _M_begin; + while (node != nullptr) + { + Node* tmp = node; + node = node->_M_next; + ::free(tmp); + } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif } - protected: - - virtual void _Exec() + void swap(TokenRegistrationContainer& list) { - m_proc(m_pData); + std::swap(list._M_begin, _M_begin); + std::swap(list._M_last, _M_last); } - private: - - TaskProc_t m_proc; - void *m_pData; - - }; + bool empty() { return _M_begin == nullptr; } - // The base implementation of a cancellation token. - class _CancellationTokenState : public _RefCounter - { - protected: - class TokenRegistrationContainer + template + void for_each(T lambda) { - private: - typedef struct _Node { - _CancellationTokenRegistration* _M_token; - _Node *_M_next; - } Node; - - public: - TokenRegistrationContainer() : _M_begin(nullptr), _M_last(nullptr) + Node* node = _M_begin; + + while (node != nullptr) { + lambda(node->_M_token); + node = node->_M_next; } + } - ~TokenRegistrationContainer() + void push_back(_CancellationTokenRegistration* token) + { + Node* node = reinterpret_cast(::malloc(sizeof(Node))); + if (node == nullptr) { -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable: 6001) -#endif - auto node = _M_begin; - while (node != nullptr) - { - Node* tmp = node; - node = node->_M_next; - ::free(tmp); - } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif + throw ::std::bad_alloc(); } - void swap(TokenRegistrationContainer& list) + node->_M_token = token; + node->_M_next = nullptr; + + if (_M_begin == nullptr) { - std::swap(list._M_begin, _M_begin); - std::swap(list._M_last, _M_last); + _M_begin = node; } - - bool empty() + else { - return _M_begin == nullptr; + _M_last->_M_next = node; } - template - void for_each(T lambda) - { - Node* node = _M_begin; + _M_last = node; + } - while (node != nullptr) - { - lambda(node->_M_token); - node = node->_M_next; - } - } + void remove(_CancellationTokenRegistration* token) + { + Node* node = _M_begin; + Node* prev = nullptr; - void push_back(_CancellationTokenRegistration* token) + while (node != nullptr) { - Node* node = reinterpret_cast(::malloc(sizeof(Node))); - if (node == nullptr) + if (node->_M_token == token) { - throw ::std::bad_alloc(); - } + if (prev == nullptr) + { + _M_begin = node->_M_next; + } + else + { + prev->_M_next = node->_M_next; + } - node->_M_token = token; - node->_M_next = nullptr; + if (node->_M_next == nullptr) + { + _M_last = prev; + } - if (_M_begin == nullptr) - { - _M_begin = node; - } - else - { - _M_last->_M_next = node; + ::free(node); + break; } - _M_last = node; + prev = node; + node = node->_M_next; } + } - void remove(_CancellationTokenRegistration* token) - { - Node* node = _M_begin; - Node* prev = nullptr; + private: + Node* _M_begin; + Node* _M_last; + }; - while (node != nullptr) - { - if (node->_M_token == token) { - if (prev == nullptr) - { - _M_begin = node->_M_next; - } - else - { - prev->_M_next = node->_M_next; - } - - if (node->_M_next == nullptr) - { - _M_last = prev; - } - - ::free(node); - break; - } - - prev = node; - node = node->_M_next; - } - } +public: + static _CancellationTokenState* _NewTokenState() { return new _CancellationTokenState(); } - private: - Node *_M_begin; - Node *_M_last; - }; + static _CancellationTokenState* _None() { return reinterpret_cast<_CancellationTokenState*>(2); } - public: + static bool _IsValid(_In_opt_ _CancellationTokenState* _PToken) { return (_PToken != NULL && _PToken != _None()); } - static _CancellationTokenState * _NewTokenState() - { - return new _CancellationTokenState(); - } - - static _CancellationTokenState *_None() - { - return reinterpret_cast<_CancellationTokenState *>(2); - } + _CancellationTokenState() : _M_stateFlag(0) {} - static bool _IsValid(_In_opt_ _CancellationTokenState *_PToken) - { - return (_PToken != NULL && _PToken != _None()); - } - - _CancellationTokenState() : - _M_stateFlag(0) + ~_CancellationTokenState() + { + TokenRegistrationContainer rundownList; { + extensibility::scoped_critical_section_t _Lock(_M_listLock); + _M_registrations.swap(rundownList); } - ~_CancellationTokenState() + rundownList.for_each([](_CancellationTokenRegistration* pRegistration) { + pRegistration->_M_state = _CancellationTokenRegistration::_STATE_SYNCHRONIZE; + pRegistration->_Release(); + }); + } + + bool _IsCanceled() const { return (_M_stateFlag != 0); } + + void _Cancel() + { + if (atomic_compare_exchange(_M_stateFlag, 1l, 0l) == 0) { TokenRegistrationContainer rundownList; { @@ -433,198 +377,157 @@ namespace details _M_registrations.swap(rundownList); } - rundownList.for_each([](_CancellationTokenRegistration * pRegistration) - { - pRegistration->_M_state = _CancellationTokenRegistration::_STATE_SYNCHRONIZE; - pRegistration->_Release(); - }); - } + rundownList.for_each([](_CancellationTokenRegistration* pRegistration) { pRegistration->_Invoke(); }); - bool _IsCanceled() const - { - return (_M_stateFlag != 0); + _M_stateFlag = 2; + _M_cancelComplete.set(); } + } - void _Cancel() - { - if (atomic_compare_exchange(_M_stateFlag, 1l, 0l) == 0) - { - TokenRegistrationContainer rundownList; - { - extensibility::scoped_critical_section_t _Lock(_M_listLock); - _M_registrations.swap(rundownList); - } + _CancellationTokenRegistration* _RegisterCallback(TaskProc_t _PCallback, _In_ void* _PData, int _InitialRefs = 1) + { + _CancellationTokenRegistration* pRegistration = + new CancellationTokenRegistration_TaskProc(_PCallback, _PData, _InitialRefs); + _RegisterCallback(pRegistration); + return pRegistration; + } - rundownList.for_each([](_CancellationTokenRegistration * pRegistration) - { - pRegistration->_Invoke(); - }); + void _RegisterCallback(_In_ _CancellationTokenRegistration* _PRegistration) + { + _PRegistration->_M_state = _CancellationTokenRegistration::_STATE_CLEAR; + _PRegistration->_Reference(); + _PRegistration->_M_pTokenState = this; + + bool invoke = true; + + if (!_IsCanceled()) + { + extensibility::scoped_critical_section_t _Lock(_M_listLock); - _M_stateFlag = 2; - _M_cancelComplete.set(); + if (!_IsCanceled()) + { + invoke = false; + _M_registrations.push_back(_PRegistration); } } - _CancellationTokenRegistration *_RegisterCallback(TaskProc_t _PCallback, _In_ void *_PData, int _InitialRefs = 1) + if (invoke) { - _CancellationTokenRegistration *pRegistration = new CancellationTokenRegistration_TaskProc(_PCallback, _PData, _InitialRefs); - _RegisterCallback(pRegistration); - return pRegistration; + _PRegistration->_Invoke(); } + } - void _RegisterCallback(_In_ _CancellationTokenRegistration *_PRegistration) - { - _PRegistration->_M_state = _CancellationTokenRegistration::_STATE_CLEAR; - _PRegistration->_Reference(); - _PRegistration->_M_pTokenState = this; + void _DeregisterCallback(_In_ _CancellationTokenRegistration* _PRegistration) + { + bool synchronize = false; - bool invoke = true; + { + extensibility::scoped_critical_section_t _Lock(_M_listLock); - if (!_IsCanceled()) + // + // If a cancellation has occurred, the registration list is guaranteed to be empty if we've observed it + // under the auspices of the lock. In this case, we must synchronize with the canceling thread to guarantee + // that the cancellation is finished by the time we return from this method. + // + if (!_M_registrations.empty()) { - extensibility::scoped_critical_section_t _Lock(_M_listLock); - - if (!_IsCanceled()) - { - invoke = false; - _M_registrations.push_back(_PRegistration); - } + _M_registrations.remove(_PRegistration); + _PRegistration->_M_state = _CancellationTokenRegistration::_STATE_SYNCHRONIZE; + _PRegistration->_Release(); } - - if (invoke) + else { - _PRegistration->_Invoke(); + synchronize = true; } } - void _DeregisterCallback(_In_ _CancellationTokenRegistration *_PRegistration) + // + // If the list is empty, we are in one of several situations: + // + // - The callback has already been made --> do nothing + // - The callback is about to be made --> flag it so it doesn't happen and return + // - The callback is in progress elsewhere --> synchronize with it + // - The callback is in progress on this thread --> do nothing + // + if (synchronize) { - bool synchronize = false; + long result = atomic_compare_exchange(_PRegistration->_M_state, + _CancellationTokenRegistration::_STATE_DEFER_DELETE, + _CancellationTokenRegistration::_STATE_CLEAR); + switch (result) { - extensibility::scoped_critical_section_t _Lock(_M_listLock); - - // - // If a cancellation has occurred, the registration list is guaranteed to be empty if we've observed it under the auspices of the - // lock. In this case, we must synchronize with the canceling thread to guarantee that the cancellation is finished by the time - // we return from this method. - // - if (!_M_registrations.empty()) - { - _M_registrations.remove(_PRegistration); - _PRegistration->_M_state = _CancellationTokenRegistration::_STATE_SYNCHRONIZE; - _PRegistration->_Release(); - } - else + case _CancellationTokenRegistration::_STATE_CLEAR: + case _CancellationTokenRegistration::_STATE_CALLED: break; + case _CancellationTokenRegistration::_STATE_DEFER_DELETE: + case _CancellationTokenRegistration::_STATE_SYNCHRONIZE: _ASSERTE(false); break; + default: { - synchronize = true; - } - } + long tid = result; + if (tid == ::pplx::details::platform::GetCurrentThreadId()) + { + // + // It is entirely legal for a caller to Deregister during a callback instead of having to + // provide their own synchronization mechanism between the two. In this case, we do *NOT* need + // to explicitly synchronize with the callback as doing so would deadlock. If the call happens + // during, skip any extra synchronization. + // + break; + } - // - // If the list is empty, we are in one of several situations: - // - // - The callback has already been made --> do nothing - // - The callback is about to be made --> flag it so it doesn't happen and return - // - The callback is in progress elsewhere --> synchronize with it - // - The callback is in progress on this thread --> do nothing - // - if (synchronize) - { - long result = atomic_compare_exchange( - _PRegistration->_M_state, - _CancellationTokenRegistration::_STATE_DEFER_DELETE, - _CancellationTokenRegistration::_STATE_CLEAR - ); + extensibility::event_t ev; + _PRegistration->_M_pSyncBlock = &ev; - switch(result) - { - case _CancellationTokenRegistration::_STATE_CLEAR: - case _CancellationTokenRegistration::_STATE_CALLED: - break; - case _CancellationTokenRegistration::_STATE_DEFER_DELETE: - case _CancellationTokenRegistration::_STATE_SYNCHRONIZE: - _ASSERTE(false); - break; - default: - { - long tid = result; - if (tid == ::pplx::details::platform::GetCurrentThreadId()) - { - // - // It is entirely legal for a caller to Deregister during a callback instead of having to provide their own synchronization - // mechanism between the two. In this case, we do *NOT* need to explicitly synchronize with the callback as doing so would - // deadlock. If the call happens during, skip any extra synchronization. - // - break; - } - - extensibility::event_t ev; - _PRegistration->_M_pSyncBlock = &ev; - - long result_1 = atomic_exchange(_PRegistration->_M_state, _CancellationTokenRegistration::_STATE_SYNCHRONIZE); - - if (result_1 != _CancellationTokenRegistration::_STATE_CALLED) - { - _PRegistration->_M_pSyncBlock->wait(::pplx::extensibility::event_t::timeout_infinite); - } + long result_1 = + atomic_exchange(_PRegistration->_M_state, _CancellationTokenRegistration::_STATE_SYNCHRONIZE); - break; + if (result_1 != _CancellationTokenRegistration::_STATE_CALLED) + { + _PRegistration->_M_pSyncBlock->wait(::pplx::extensibility::event_t::timeout_infinite); } + + break; } } } + } - private: - - // The flag for the token state (whether it is canceled or not) - atomic_long _M_stateFlag; +private: + // The flag for the token state (whether it is canceled or not) + atomic_long _M_stateFlag; - // Notification of completion of cancellation of this token. - extensibility::event_t _M_cancelComplete; // Hmm.. where do we wait for it?? + // Notification of completion of cancellation of this token. + extensibility::event_t _M_cancelComplete; // Hmm.. where do we wait for it?? - // Lock to protect the registrations list - extensibility::critical_section_t _M_listLock; + // Lock to protect the registrations list + extensibility::critical_section_t _M_listLock; - // The protected list of registrations - TokenRegistrationContainer _M_registrations; - }; + // The protected list of registrations + TokenRegistrationContainer _M_registrations; +}; } // namespace details class cancellation_token_source; class cancellation_token; - /// -/// The cancellation_token_registration class represents a callback notification from a cancellation_token. When the register -/// method on a cancellation_token is used to receive notification of when cancellation occurs, a cancellation_token_registration -/// object is returned as a handle to the callback so that the caller can request a specific callback no longer be made through use of -/// the deregister method. +/// The cancellation_token_registration class represents a callback notification from a +/// cancellation_token. When the register method on a cancellation_token is used to receive +/// notification of when cancellation occurs, a cancellation_token_registration object is returned as a +/// handle to the callback so that the caller can request a specific callback no longer be made through use of the +/// deregister method. /// class cancellation_token_registration { public: + cancellation_token_registration() : _M_pRegistration(NULL) {} - cancellation_token_registration() : - _M_pRegistration(NULL) - { - } + ~cancellation_token_registration() { _Clear(); } - ~cancellation_token_registration() - { - _Clear(); - } + cancellation_token_registration(const cancellation_token_registration& _Src) { _Assign(_Src._M_pRegistration); } - cancellation_token_registration(const cancellation_token_registration& _Src) - { - _Assign(_Src._M_pRegistration); - } - - cancellation_token_registration(cancellation_token_registration&& _Src) - { - _Move(_Src._M_pRegistration); - } + cancellation_token_registration(cancellation_token_registration&& _Src) { _Move(_Src._M_pRegistration); } cancellation_token_registration& operator=(const cancellation_token_registration& _Src) { @@ -651,17 +554,13 @@ class cancellation_token_registration return _M_pRegistration == _Rhs._M_pRegistration; } - bool operator!=(const cancellation_token_registration& _Rhs) const - { - return !(operator==(_Rhs)); - } + bool operator!=(const cancellation_token_registration& _Rhs) const { return !(operator==(_Rhs)); } private: - friend class cancellation_token; - - cancellation_token_registration(_In_ details::_CancellationTokenRegistration *_PRegistration) : - _M_pRegistration(_PRegistration) + + cancellation_token_registration(_In_ details::_CancellationTokenRegistration* _PRegistration) + : _M_pRegistration(_PRegistration) { } @@ -674,7 +573,7 @@ class cancellation_token_registration _M_pRegistration = NULL; } - void _Assign(_In_ details::_CancellationTokenRegistration *_PRegistration) + void _Assign(_In_ details::_CancellationTokenRegistration* _PRegistration) { if (_PRegistration != NULL) { @@ -683,26 +582,25 @@ class cancellation_token_registration _M_pRegistration = _PRegistration; } - void _Move(_In_ details::_CancellationTokenRegistration *&_PRegistration) + void _Move(_In_ details::_CancellationTokenRegistration*& _PRegistration) { _M_pRegistration = _PRegistration; _PRegistration = NULL; } - details::_CancellationTokenRegistration *_M_pRegistration; + details::_CancellationTokenRegistration* _M_pRegistration; }; - /// -/// The cancellation_token class represents the ability to determine whether some operation has been requested to cancel. A given token can -/// be associated with a task_group, structured_task_group, or task to provide implicit cancellation. It can also be polled for -/// cancellation or have a callback registered for if and when the associated cancellation_token_source is canceled. +/// The cancellation_token class represents the ability to determine whether some operation has been +/// requested to cancel. A given token can be associated with a task_group, structured_task_group, or +/// task to provide implicit cancellation. It can also be polled for cancellation or have a callback +/// registered for if and when the associated cancellation_token_source is canceled. /// class cancellation_token { public: - - typedef details::_CancellationTokenState * _ImplType; + typedef details::_CancellationTokenState* _ImplType; /// /// Returns a cancellation token which can never be subject to cancellation. @@ -710,20 +608,11 @@ class cancellation_token /// /// A cancellation token that cannot be canceled. /// - static cancellation_token none() - { - return cancellation_token(); - } + static cancellation_token none() { return cancellation_token(); } - cancellation_token(const cancellation_token& _Src) - { - _Assign(_Src._M_Impl); - } + cancellation_token(const cancellation_token& _Src) { _Assign(_Src._M_Impl); } - cancellation_token(cancellation_token&& _Src) - { - _Move(_Src._M_Impl); - } + cancellation_token(cancellation_token&& _Src) { _Move(_Src._M_Impl); } cancellation_token& operator=(const cancellation_token& _Src) { @@ -745,20 +634,11 @@ class cancellation_token return *this; } - bool operator==(const cancellation_token& _Src) const - { - return _M_Impl == _Src._M_Impl; - } + bool operator==(const cancellation_token& _Src) const { return _M_Impl == _Src._M_Impl; } - bool operator!=(const cancellation_token& _Src) const - { - return !(operator==(_Src)); - } + bool operator!=(const cancellation_token& _Src) const { return !(operator==(_Src)); } - ~cancellation_token() - { - _Clear(); - } + ~cancellation_token() { _Clear(); } /// /// Returns an indication of whether this token can be canceled or not. @@ -766,10 +646,7 @@ class cancellation_token /// /// An indication of whether this token can be canceled or not. /// - bool is_cancelable() const - { - return (_M_Impl != NULL); - } + bool is_cancelable() const { return (_M_Impl != NULL); } /// /// Returns true if the token has been canceled. @@ -777,14 +654,12 @@ class cancellation_token /// /// The value true if the token has been canceled; otherwise, the value false. /// - bool is_canceled() const - { - return (_M_Impl != NULL && _M_Impl->_IsCanceled()); - } + bool is_canceled() const { return (_M_Impl != NULL && _M_Impl->_IsCanceled()); } /// - /// Registers a callback function with the token. If and when the token is canceled, the callback will be made. Note that if the token - /// is already canceled at the point where this method is called, the callback will be made immediately and synchronously. + /// Registers a callback function with the token. If and when the token is canceled, the callback will be made. + /// Note that if the token is already canceled at the point where this method is called, the callback will be + /// made immediately and synchronously. /// /// /// The type of the function object that will be called back when this cancellation_token is canceled. @@ -793,10 +668,11 @@ class cancellation_token /// The function object that will be called back when this cancellation_token is canceled. /// /// - /// A cancellation_token_registration object which can be utilized in the deregister method to deregister a previously registered - /// callback and prevent it from being made. The method will throw an invalid_operation exception if - /// it is called on a cancellation_token object that was created using the cancellation_token::none - /// method. + /// A cancellation_token_registration object which can be utilized in the deregister method to + /// deregister a previously registered callback and prevent it from being made. The method will throw an invalid_operation exception if it is called on a + /// cancellation_token object that was created using the cancellation_token::none method. /// template ::pplx::cancellation_token_registration register_callback(const _Function& _Func) const @@ -807,43 +683,37 @@ class cancellation_token throw invalid_operation(); } #if defined(_MSC_VER) -#pragma warning(suppress: 28197) +#pragma warning(suppress : 28197) #endif - details::_CancellationTokenCallback<_Function> *_PCallback = new details::_CancellationTokenCallback<_Function>(_Func); + details::_CancellationTokenCallback<_Function>* _PCallback = + new details::_CancellationTokenCallback<_Function>(_Func); _M_Impl->_RegisterCallback(_PCallback); return cancellation_token_registration(_PCallback); } /// - /// Removes a callback previously registered via the register method based on the cancellation_token_registration object returned - /// at the time of registration. + /// Removes a callback previously registered via the register method based on the + /// cancellation_token_registration object returned at the time of registration. /// /// - /// The cancellation_token_registration object corresponding to the callback to be deregistered. This token must have been previously - /// returned from a call to the register method. + /// The cancellation_token_registration object corresponding to the callback to be deregistered. This + /// token must have been previously returned from a call to the register method. /// void deregister_callback(const cancellation_token_registration& _Registration) const { _M_Impl->_DeregisterCallback(_Registration._M_pRegistration); } - _ImplType _GetImpl() const - { - return _M_Impl; - } + _ImplType _GetImpl() const { return _M_Impl; } _ImplType _GetImplValue() const { return (_M_Impl == NULL) ? ::pplx::details::_CancellationTokenState::_None() : _M_Impl; } - static cancellation_token _FromImpl(_ImplType _Impl) - { - return cancellation_token(_Impl); - } + static cancellation_token _FromImpl(_ImplType _Impl) { return cancellation_token(_Impl); } private: - friend class cancellation_token_source; _ImplType _M_Impl; @@ -866,19 +736,15 @@ class cancellation_token _M_Impl = _Impl; } - void _Move(_ImplType &_Impl) + void _Move(_ImplType& _Impl) { _M_Impl = _Impl; _Impl = NULL; } - cancellation_token() : - _M_Impl(NULL) - { - } + cancellation_token() : _M_Impl(NULL) {} - cancellation_token(_ImplType _Impl) : - _M_Impl(_Impl) + cancellation_token(_ImplType _Impl) : _M_Impl(_Impl) { if (_M_Impl == ::pplx::details::_CancellationTokenState::_None()) { @@ -898,26 +764,17 @@ class cancellation_token class cancellation_token_source { public: - - typedef ::pplx::details::_CancellationTokenState * _ImplType; + typedef ::pplx::details::_CancellationTokenState* _ImplType; /// - /// Constructs a new cancellation_token_source. The source can be used to flag cancellation of some cancelable operation. + /// Constructs a new cancellation_token_source. The source can be used to flag cancellation of some + /// cancelable operation. /// - cancellation_token_source() - { - _M_Impl = new ::pplx::details::_CancellationTokenState; - } + cancellation_token_source() { _M_Impl = new ::pplx::details::_CancellationTokenState; } - cancellation_token_source(const cancellation_token_source& _Src) - { - _Assign(_Src._M_Impl); - } + cancellation_token_source(const cancellation_token_source& _Src) { _Assign(_Src._M_Impl); } - cancellation_token_source(cancellation_token_source&& _Src) - { - _Move(_Src._M_Impl); - } + cancellation_token_source(cancellation_token_source&& _Src) { _Move(_Src._M_Impl); } cancellation_token_source& operator=(const cancellation_token_source& _Src) { @@ -939,15 +796,9 @@ class cancellation_token_source return *this; } - bool operator==(const cancellation_token_source& _Src) const - { - return _M_Impl == _Src._M_Impl; - } + bool operator==(const cancellation_token_source& _Src) const { return _M_Impl == _Src._M_Impl; } - bool operator!=(const cancellation_token_source& _Src) const - { - return !(operator==(_Src)); - } + bool operator!=(const cancellation_token_source& _Src) const { return !(operator==(_Src)); } ~cancellation_token_source() { @@ -964,31 +815,29 @@ class cancellation_token_source /// /// A cancellation token associated with this source. /// - cancellation_token get_token() const - { - return cancellation_token(_M_Impl); - } + cancellation_token get_token() const { return cancellation_token(_M_Impl); } /// /// Creates a cancellation_token_source which is canceled when the provided token is canceled. /// /// - /// A token whose cancellation will cause cancellation of the returned token source. Note that the returned token source can also be canceled - /// independently of the source contained in this parameter. + /// A token whose cancellation will cause cancellation of the returned token source. Note that the returned + /// token source can also be canceled independently of the source contained in this parameter. /// /// - /// A cancellation_token_source which is canceled when the token provided by the parameter is canceled. + /// A cancellation_token_source which is canceled when the token provided by the + /// parameter is canceled. /// - static cancellation_token_source create_linked_source(cancellation_token& _Src) + static cancellation_token_source create_linked_source(cancellation_token& _Src) { cancellation_token_source newSource; - _Src.register_callback( [newSource](){ newSource.cancel(); } ); + _Src.register_callback([newSource]() { newSource.cancel(); }); return newSource; } /// - /// Creates a cancellation_token_source which is canceled when one of a series of tokens represented by an STL iterator - /// pair is canceled. + /// Creates a cancellation_token_source which is canceled when one of a series of tokens represented by + /// an STL iterator pair is canceled. /// /// /// The STL iterator corresponding to the beginning of the range of tokens to listen for cancellation of. @@ -997,8 +846,9 @@ class cancellation_token_source /// The STL iterator corresponding to the ending of the range of tokens to listen for cancellation of. /// /// - /// A cancellation_token_source which is canceled when any of the tokens provided by the range described by the STL iterators - /// contained in the and parameters is canceled. + /// A cancellation_token_source which is canceled when any of the tokens provided by the range described + /// by the STL iterators contained in the and parameters is + /// canceled. /// template static cancellation_token_source create_linked_source(_Iter _Begin, _Iter _End) @@ -1006,32 +856,22 @@ class cancellation_token_source cancellation_token_source newSource; for (_Iter _It = _Begin; _It != _End; ++_It) { - _It->register_callback( [newSource](){ newSource.cancel(); } ); + _It->register_callback([newSource]() { newSource.cancel(); }); } return newSource; } /// - /// Cancels the token. Any task_group, structured_task_group, or task which utilizes the token will be - /// canceled upon this call and throw an exception at the next interruption point. + /// Cancels the token. Any task_group, structured_task_group, or task which utilizes the + /// token will be canceled upon this call and throw an exception at the next interruption point. /// - void cancel() const - { - _M_Impl->_Cancel(); - } + void cancel() const { _M_Impl->_Cancel(); } - _ImplType _GetImpl() const - { - return _M_Impl; - } + _ImplType _GetImpl() const { return _M_Impl; } - static cancellation_token_source _FromImpl(_ImplType _Impl) - { - return cancellation_token_source(_Impl); - } + static cancellation_token_source _FromImpl(_ImplType _Impl) { return cancellation_token_source(_Impl); } private: - _ImplType _M_Impl; void _Clear() @@ -1052,14 +892,13 @@ class cancellation_token_source _M_Impl = _Impl; } - void _Move(_ImplType &_Impl) + void _Move(_ImplType& _Impl) { _M_Impl = _Impl; _Impl = NULL; } - cancellation_token_source(_ImplType _Impl) : - _M_Impl(_Impl) + cancellation_token_source(_ImplType _Impl) : _M_Impl(_Impl) { if (_M_Impl == ::pplx::details::_CancellationTokenState::_None()) { diff --git a/Release/include/pplx/pplxconv.h b/Release/include/pplx/pplxconv.h index 9023064aed..723d42fc83 100644 --- a/Release/include/pplx/pplxconv.h +++ b/Release/include/pplx/pplxconv.h @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Utilities to convert between PPL tasks and PPLX tasks -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Utilities to convert between PPL tasks and PPLX tasks + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -22,18 +22,25 @@ #if defined(_MSC_VER) && (_MSC_VER >= 1700) && (_MSC_VER < 1800) && !CPPREST_FORCE_PPLX -#include #include "pplx/pplxtasks.h" +#include namespace pplx { namespace _Ppl_conv_helpers { template -auto _Set_value(_Tc _Tcp, const _F& _Func) -> decltype(_Tcp.set(_Func())) { return _Tcp.set(_Func()); } +auto _Set_value(_Tc _Tcp, const _F& _Func) -> decltype(_Tcp.set(_Func())) +{ + return _Tcp.set(_Func()); +} template -auto _Set_value(_Tc _Tcp, const _F& _Func, ...) -> decltype(_Tcp.set()) { _Func(); return _Tcp.set(); } +auto _Set_value(_Tc _Tcp, const _F& _Func, ...) -> decltype(_Tcp.set()) +{ + _Func(); + return _Tcp.set(); +} template _OtherTaskType _Convert_task(_TaskType _Task) @@ -42,9 +49,9 @@ _OtherTaskType _Convert_task(_TaskType _Task) _Task.then([_Tc](_TaskType _Task2) { try { - _Ppl_conv_helpers::_Set_value(_Tc, [=]{ return _Task2.get(); }); + _Ppl_conv_helpers::_Set_value(_Tc, [=] { return _Task2.get(); }); } - catch(...) + catch (...) { _Tc.set_exception(std::current_exception()); } @@ -52,18 +59,22 @@ _OtherTaskType _Convert_task(_TaskType _Task) _OtherTaskType _T_other(_Tc); return _T_other; } -} +} // namespace _Ppl_conv_helpers template concurrency::task<_TaskType> pplx_task_to_concurrency_task(pplx::task<_TaskType> _Task) { - return _Ppl_conv_helpers::_Convert_task, concurrency::task<_TaskType>, concurrency::task_completion_event<_TaskType>>(_Task); + return _Ppl_conv_helpers::_Convert_task, + concurrency::task<_TaskType>, + concurrency::task_completion_event<_TaskType>>(_Task); } template pplx::task<_TaskType> concurrency_task_to_pplx_task(concurrency::task<_TaskType> _Task) { - return _Ppl_conv_helpers::_Convert_task, pplx::task<_TaskType>, pplx::task_completion_event<_TaskType>>(_Task); + return _Ppl_conv_helpers::_Convert_task, + pplx::task<_TaskType>, + pplx::task_completion_event<_TaskType>>(_Task); } } // namespace pplx diff --git a/Release/include/pplx/pplxinterface.h b/Release/include/pplx/pplxinterface.h index 5df5777182..4e5ca5bfc6 100644 --- a/Release/include/pplx/pplxinterface.h +++ b/Release/include/pplx/pplxinterface.h @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* PPL interfaces -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * PPL interfaces + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -38,20 +38,19 @@ namespace pplx { - /// -/// An elementary abstraction for a task, defined as void (__cdecl * TaskProc_t)(void *). A TaskProc is called to -/// invoke the body of a task. +/// An elementary abstraction for a task, defined as void (__cdecl * TaskProc_t)(void *). A TaskProc +/// is called to invoke the body of a task. /// /**/ -typedef void (_pplx_cdecl * TaskProc_t)(void *); +typedef void(_pplx_cdecl* TaskProc_t)(void*); /// /// Scheduler Interface /// struct __declspec(novtable) scheduler_interface { - virtual void schedule( TaskProc_t, _In_ void* ) = 0; + virtual void schedule(TaskProc_t, _In_ void*) = 0; }; /// @@ -72,25 +71,17 @@ struct scheduler_ptr /// /// Creates a scheduler pointer from raw pointer to scheduler /// - explicit scheduler_ptr(_In_opt_ scheduler_interface * pScheduler) : m_scheduler(pScheduler) - { - } + explicit scheduler_ptr(_In_opt_ scheduler_interface* pScheduler) : m_scheduler(pScheduler) {} /// /// Behave like a pointer /// - scheduler_interface *operator->() const - { - return get(); - } + scheduler_interface* operator->() const { return get(); } /// /// Returns the raw pointer to the scheduler /// - scheduler_interface * get() const - { - return m_scheduler; - } + scheduler_interface* get() const { return m_scheduler; } /// /// Test whether the scheduler pointer is non-null @@ -98,15 +89,13 @@ struct scheduler_ptr operator bool() const { return get() != nullptr; } private: - std::shared_ptr m_sharedScheduler; - scheduler_interface * m_scheduler; + scheduler_interface* m_scheduler; }; - /// -/// Describes the execution status of a task_group or structured_task_group object. A value of this type is returned -/// by numerous methods that wait on tasks scheduled to a task group to complete. +/// Describes the execution status of a task_group or structured_task_group object. A value of this +/// type is returned by numerous methods that wait on tasks scheduled to a task group to complete. /// /// /// @@ -118,8 +107,8 @@ struct scheduler_ptr enum task_group_status { /// - /// The tasks queued to the task_group object have not completed. Note that this value is not presently returned by - /// the Concurrency Runtime. + /// The tasks queued to the task_group object have not completed. Note that this value is not presently + /// returned by the Concurrency Runtime. /// /**/ not_complete, @@ -131,7 +120,8 @@ enum task_group_status completed, /// - /// The task_group or structured_task_group object was canceled. One or more tasks may not have executed. + /// The task_group or structured_task_group object was canceled. One or more tasks may not have + /// executed. /// /**/ canceled @@ -189,54 +179,49 @@ inline T atomic_exchange(T volatile& _Target, T _Value) return _InterlockedExchange(&_Target, _Value); } -inline long atomic_increment(long volatile & _Target) -{ - return _InterlockedIncrement(&_Target); -} +inline long atomic_increment(long volatile& _Target) { return _InterlockedIncrement(&_Target); } -inline long atomic_add(long volatile & _Target, long value) -{ - return _InterlockedExchangeAdd(&_Target, value) + value; -} +inline long atomic_add(long volatile& _Target, long value) { return _InterlockedExchangeAdd(&_Target, value) + value; } -inline size_t atomic_increment(size_t volatile & _Target) +inline size_t atomic_increment(size_t volatile& _Target) { #if (defined(_M_IX86) || defined(_M_ARM)) - return static_cast(_InterlockedIncrement(reinterpret_cast(&_Target))); + return static_cast(_InterlockedIncrement(reinterpret_cast(&_Target))); #else - return static_cast(_InterlockedIncrement64(reinterpret_cast<__int64 volatile *>(&_Target))); + return static_cast(_InterlockedIncrement64(reinterpret_cast<__int64 volatile*>(&_Target))); #endif } -inline long atomic_decrement(long volatile & _Target) -{ - return _InterlockedDecrement(&_Target); -} +inline long atomic_decrement(long volatile& _Target) { return _InterlockedDecrement(&_Target); } -inline size_t atomic_decrement(size_t volatile & _Target) +inline size_t atomic_decrement(size_t volatile& _Target) { #if (defined(_M_IX86) || defined(_M_ARM)) - return static_cast(_InterlockedDecrement(reinterpret_cast(&_Target))); + return static_cast(_InterlockedDecrement(reinterpret_cast(&_Target))); #else - return static_cast(_InterlockedDecrement64(reinterpret_cast<__int64 volatile *>(&_Target))); + return static_cast(_InterlockedDecrement64(reinterpret_cast<__int64 volatile*>(&_Target))); #endif } -inline long atomic_compare_exchange(long volatile & _Target, long _Exchange, long _Comparand) +inline long atomic_compare_exchange(long volatile& _Target, long _Exchange, long _Comparand) { return _InterlockedCompareExchange(&_Target, _Exchange, _Comparand); } -inline size_t atomic_compare_exchange(size_t volatile & _Target, size_t _Exchange, size_t _Comparand) +inline size_t atomic_compare_exchange(size_t volatile& _Target, size_t _Exchange, size_t _Comparand) { #if (defined(_M_IX86) || defined(_M_ARM)) - return static_cast(_InterlockedCompareExchange(reinterpret_cast(_Target), static_cast(_Exchange), static_cast(_Comparand))); + return static_cast(_InterlockedCompareExchange( + reinterpret_cast(_Target), static_cast(_Exchange), static_cast(_Comparand))); #else - return static_cast(_InterlockedCompareExchange64(reinterpret_cast<__int64 volatile *>(_Target), static_cast<__int64>(_Exchange), static_cast<__int64>(_Comparand))); + return static_cast(_InterlockedCompareExchange64(reinterpret_cast<__int64 volatile*>(_Target), + static_cast<__int64>(_Exchange), + static_cast<__int64>(_Comparand))); #endif } #endif // _USE_REAL_ATOMICS -}} // namespace pplx +} // namespace details +} // namespace pplx #endif // _PPLXINTERFACE_H diff --git a/Release/include/pplx/pplxlinux.h b/Release/include/pplx/pplxlinux.h index fe75bc5e8a..5aca316e45 100644 --- a/Release/include/pplx/pplxlinux.h +++ b/Release/include/pplx/pplxlinux.h @@ -1,252 +1,219 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Linux specific pplx implementations -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Linux specific pplx implementations + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once - #if (defined(_MSC_VER)) #error This file must not be included for Visual Studio #endif #ifndef _WIN32 -#include -#include "pthread.h" #include "cpprest/details/cpprest_compat.h" +#include "pthread.h" +#include #if defined(__APPLE__) -#include -#include #include +#include +#include #else -#include #include #include +#include #endif #include "pplx/pplxinterface.h" - namespace pplx { #if defined(__APPLE__) - namespace cpprest_synchronization = ::boost; +namespace cpprest_synchronization = ::boost; #else - namespace cpprest_synchronization = ::std; +namespace cpprest_synchronization = ::std; #endif namespace details { namespace platform { - /// - /// Returns a unique identifier for the execution thread where this routine in invoked - /// - _PPLXIMP long _pplx_cdecl GetCurrentThreadId(); - - /// - /// Yields the execution of the current execution thread - typically when spin-waiting - /// - _PPLXIMP void _pplx_cdecl YieldExecution(); - - /// - /// Captures the callstack - /// - __declspec(noinline) inline static size_t CaptureCallstack(void **, size_t, size_t) +/// +/// Returns a unique identifier for the execution thread where this routine in invoked +/// +_PPLXIMP long _pplx_cdecl GetCurrentThreadId(); + +/// +/// Yields the execution of the current execution thread - typically when spin-waiting +/// +_PPLXIMP void _pplx_cdecl YieldExecution(); + +/// +/// Captures the callstack +/// +__declspec(noinline) inline static size_t CaptureCallstack(void**, size_t, size_t) { return 0; } +} // namespace platform + +/// +/// Manual reset event +/// +class event_impl +{ +private: + cpprest_synchronization::mutex _lock; + cpprest_synchronization::condition_variable _condition; + bool _signaled; + +public: + static const unsigned int timeout_infinite = 0xFFFFFFFF; + + event_impl() : _signaled(false) {} + + void set() { - return 0; + cpprest_synchronization::lock_guard lock(_lock); + _signaled = true; + _condition.notify_all(); } -} - - /// - /// Manual reset event - /// - class event_impl - { - private: - cpprest_synchronization::mutex _lock; - cpprest_synchronization::condition_variable _condition; - bool _signaled; - public: - static const unsigned int timeout_infinite = 0xFFFFFFFF; + void reset() + { + cpprest_synchronization::lock_guard lock(_lock); + _signaled = false; + } - event_impl() - : _signaled(false) + unsigned int wait(unsigned int timeout) + { + cpprest_synchronization::unique_lock lock(_lock); + if (timeout == event_impl::timeout_infinite) { + _condition.wait(lock, [this]() -> bool { return _signaled; }); + return 0; } - - void set() + else { - cpprest_synchronization::lock_guard lock(_lock); - _signaled = true; - _condition.notify_all(); + cpprest_synchronization::chrono::milliseconds period(timeout); + auto status = _condition.wait_for(lock, period, [this]() -> bool { return _signaled; }); + _ASSERTE(status == _signaled); + // Return 0 if the wait completed as a result of signaling the event. Otherwise, return timeout_infinite + // Note: this must be consistent with the behavior of the Windows version, which is based on + // WaitForSingleObjectEx + return status ? 0 : event_impl::timeout_infinite; } + } - void reset() - { - cpprest_synchronization::lock_guard lock(_lock); - _signaled = false; - } + unsigned int wait() { return wait(event_impl::timeout_infinite); } +}; - unsigned int wait(unsigned int timeout) - { - cpprest_synchronization::unique_lock lock(_lock); - if (timeout == event_impl::timeout_infinite) - { - _condition.wait(lock, [this]() -> bool { return _signaled; }); - return 0; - } - else - { - cpprest_synchronization::chrono::milliseconds period(timeout); - auto status = _condition.wait_for(lock, period, [this]() -> bool { return _signaled; }); - _ASSERTE(status == _signaled); - // Return 0 if the wait completed as a result of signaling the event. Otherwise, return timeout_infinite - // Note: this must be consistent with the behavior of the Windows version, which is based on WaitForSingleObjectEx - return status ? 0: event_impl::timeout_infinite; - } - } +/// +/// Reader writer lock +/// +class reader_writer_lock_impl +{ +private: + pthread_rwlock_t _M_reader_writer_lock; - unsigned int wait() +public: + class scoped_lock_read + { + public: + explicit scoped_lock_read(reader_writer_lock_impl& _Reader_writer_lock) + : _M_reader_writer_lock(_Reader_writer_lock) { - return wait(event_impl::timeout_infinite); + _M_reader_writer_lock.lock_read(); } - }; - /// - /// Reader writer lock - /// - class reader_writer_lock_impl - { + ~scoped_lock_read() { _M_reader_writer_lock.unlock(); } + private: + reader_writer_lock_impl& _M_reader_writer_lock; + scoped_lock_read(const scoped_lock_read&); // no copy constructor + scoped_lock_read const& operator=(const scoped_lock_read&); // no assignment operator + }; - pthread_rwlock_t _M_reader_writer_lock; + reader_writer_lock_impl() { pthread_rwlock_init(&_M_reader_writer_lock, nullptr); } - public: + ~reader_writer_lock_impl() { pthread_rwlock_destroy(&_M_reader_writer_lock); } - class scoped_lock_read - { - public: - explicit scoped_lock_read(reader_writer_lock_impl &_Reader_writer_lock) : _M_reader_writer_lock(_Reader_writer_lock) - { - _M_reader_writer_lock.lock_read(); - } - - ~scoped_lock_read() - { - _M_reader_writer_lock.unlock(); - } - - private: - reader_writer_lock_impl& _M_reader_writer_lock; - scoped_lock_read(const scoped_lock_read&); // no copy constructor - scoped_lock_read const & operator=(const scoped_lock_read&); // no assignment operator - }; - - reader_writer_lock_impl() - { - pthread_rwlock_init(&_M_reader_writer_lock, nullptr); - } + void lock() { pthread_rwlock_wrlock(&_M_reader_writer_lock); } - ~reader_writer_lock_impl() - { - pthread_rwlock_destroy(&_M_reader_writer_lock); - } - - void lock() - { - pthread_rwlock_wrlock(&_M_reader_writer_lock); - } + void lock_read() { pthread_rwlock_rdlock(&_M_reader_writer_lock); } - void lock_read() - { - pthread_rwlock_rdlock(&_M_reader_writer_lock); - } + void unlock() { pthread_rwlock_unlock(&_M_reader_writer_lock); } +}; - void unlock() - { - pthread_rwlock_unlock(&_M_reader_writer_lock); - } - }; +/// +/// Recursive mutex +/// +class recursive_lock_impl +{ +public: + recursive_lock_impl() : _M_owner(-1), _M_recursionCount(0) {} - /// - /// Recursive mutex - /// - class recursive_lock_impl + ~recursive_lock_impl() { - public: + _ASSERTE(_M_owner == -1); + _ASSERTE(_M_recursionCount == 0); + } - recursive_lock_impl() - : _M_owner(-1), _M_recursionCount(0) - { - } + void lock() + { + auto id = ::pplx::details::platform::GetCurrentThreadId(); - ~recursive_lock_impl() + if (_M_owner == id) { - _ASSERTE(_M_owner == -1); - _ASSERTE(_M_recursionCount == 0); + _M_recursionCount++; } - - void lock() + else { - auto id = ::pplx::details::platform::GetCurrentThreadId(); - - if ( _M_owner == id ) - { - _M_recursionCount++; - } - else - { - _M_cs.lock(); - _M_owner = id; - _M_recursionCount = 1; - } + _M_cs.lock(); + _M_owner = id; + _M_recursionCount = 1; } + } - void unlock() - { - _ASSERTE(_M_owner == ::pplx::details::platform::GetCurrentThreadId()); - _ASSERTE(_M_recursionCount >= 1); + void unlock() + { + _ASSERTE(_M_owner == ::pplx::details::platform::GetCurrentThreadId()); + _ASSERTE(_M_recursionCount >= 1); - _M_recursionCount--; + _M_recursionCount--; - if ( _M_recursionCount == 0 ) - { - _M_owner = -1; - _M_cs.unlock(); - } + if (_M_recursionCount == 0) + { + _M_owner = -1; + _M_cs.unlock(); } + } - private: - cpprest_synchronization::mutex _M_cs; - std::atomic _M_owner; - long _M_recursionCount; - }; +private: + cpprest_synchronization::mutex _M_cs; + std::atomic _M_owner; + long _M_recursionCount; +}; #if defined(__APPLE__) - class apple_scheduler : public pplx::scheduler_interface +class apple_scheduler : public pplx::scheduler_interface #else - class linux_scheduler : public pplx::scheduler_interface +class linux_scheduler : public pplx::scheduler_interface #endif - { - public: - _PPLXIMP virtual void schedule( TaskProc_t proc, _In_ void* param); +{ +public: + _PPLXIMP virtual void schedule(TaskProc_t proc, _In_ void* param); #if defined(__APPLE__) virtual ~apple_scheduler() {} #else virtual ~linux_scheduler() {} #endif - }; +}; } // namespace details @@ -263,60 +230,58 @@ class scoped_lock _M_critical_section.lock(); } - ~scoped_lock() - { - _M_critical_section.unlock(); - } + ~scoped_lock() { _M_critical_section.unlock(); } private: _Lock& _M_critical_section; - scoped_lock(const scoped_lock&); // no copy constructor - scoped_lock const & operator=(const scoped_lock&); // no assignment operator + scoped_lock(const scoped_lock&); // no copy constructor + scoped_lock const& operator=(const scoped_lock&); // no assignment operator }; // The extensibility namespace contains the type definitions that are used internally namespace extensibility { - typedef ::pplx::details::event_impl event_t; +typedef ::pplx::details::event_impl event_t; - typedef cpprest_synchronization::mutex critical_section_t; - typedef scoped_lock scoped_critical_section_t; +typedef cpprest_synchronization::mutex critical_section_t; +typedef scoped_lock scoped_critical_section_t; - typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t; - typedef scoped_lock scoped_rw_lock_t; - typedef ::pplx::extensibility::reader_writer_lock_t::scoped_lock_read scoped_read_lock_t; +typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t; +typedef scoped_lock scoped_rw_lock_t; +typedef ::pplx::extensibility::reader_writer_lock_t::scoped_lock_read scoped_read_lock_t; - typedef ::pplx::details::recursive_lock_impl recursive_lock_t; - typedef scoped_lock scoped_recursive_lock_t; -} +typedef ::pplx::details::recursive_lock_impl recursive_lock_t; +typedef scoped_lock scoped_recursive_lock_t; +} // namespace extensibility /// /// Default scheduler type /// #if defined(__APPLE__) - typedef details::apple_scheduler default_scheduler_t; +typedef details::apple_scheduler default_scheduler_t; #else - typedef details::linux_scheduler default_scheduler_t; +typedef details::linux_scheduler default_scheduler_t; #endif namespace details { - /// - /// Terminate the process due to unhandled exception - /// - #ifndef _REPORT_PPLTASK_UNOBSERVED_EXCEPTION - #define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() do { \ - raise(SIGTRAP); \ - std::terminate(); \ - } while(false) - #endif //_REPORT_PPLTASK_UNOBSERVED_EXCEPTION -} - -//see: http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html +/// +/// Terminate the process due to unhandled exception +/// +#ifndef _REPORT_PPLTASK_UNOBSERVED_EXCEPTION +#define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() \ + do \ + { \ + raise(SIGTRAP); \ + std::terminate(); \ + } while (false) +#endif //_REPORT_PPLTASK_UNOBSERVED_EXCEPTION +} // namespace details + +// see: http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html // this is critical to inline -__attribute__ ((always_inline)) -inline void* _ReturnAddress() { return __builtin_return_address(0); } +__attribute__((always_inline)) inline void* _ReturnAddress() { return __builtin_return_address(0); } } // namespace pplx diff --git a/Release/include/pplx/pplxtasks.h b/Release/include/pplx/pplxtasks.h index ab059f0c5a..63cedc4f28 100644 --- a/Release/include/pplx/pplxtasks.h +++ b/Release/include/pplx/pplxtasks.h @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Parallel Patterns Library - PPLx Tasks -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Parallel Patterns Library - PPLx Tasks + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -24,7 +24,6 @@ namespace pplx = Concurrency; namespace Concurrency { - /// /// Sets the ambient scheduler to be used by the PPL constructs. /// @@ -39,21 +38,23 @@ _ASYNCRTIMP const std::shared_ptr& __cdecl get_cpprestsdk_a #if (_MSC_VER >= 1900) #include -namespace Concurrency { - namespace extensibility { - typedef ::std::condition_variable condition_variable_t; - typedef ::std::mutex critical_section_t; - typedef ::std::unique_lock< ::std::mutex> scoped_critical_section_t; - - typedef ::Concurrency::event event_t; - typedef ::Concurrency::reader_writer_lock reader_writer_lock_t; - typedef ::Concurrency::reader_writer_lock::scoped_lock scoped_rw_lock_t; - typedef ::Concurrency::reader_writer_lock::scoped_lock_read scoped_read_lock_t; - - typedef ::Concurrency::details::_ReentrantBlockingLock recursive_lock_t; - typedef recursive_lock_t::_Scoped_lock scoped_recursive_lock_t; - } -} +namespace Concurrency +{ +namespace extensibility +{ +typedef ::std::condition_variable condition_variable_t; +typedef ::std::mutex critical_section_t; +typedef ::std::unique_lock<::std::mutex> scoped_critical_section_t; + +typedef ::Concurrency::event event_t; +typedef ::Concurrency::reader_writer_lock reader_writer_lock_t; +typedef ::Concurrency::reader_writer_lock::scoped_lock scoped_rw_lock_t; +typedef ::Concurrency::reader_writer_lock::scoped_lock_read scoped_read_lock_t; + +typedef ::Concurrency::details::_ReentrantBlockingLock recursive_lock_t; +typedef recursive_lock_t::_Scoped_lock scoped_recursive_lock_t; +} // namespace extensibility +} // namespace Concurrency #endif // _MSC_VER >= 1900 #else @@ -71,20 +72,21 @@ void cpprest_init(JavaVM*); #endif /*IFSTRIP=IGN*/ #endif /* defined(_MSC_VER) */ -#include -#include -#include -#include #include #include +#include +#include +#include +#include #if defined(_MSC_VER) #include #if defined(__cplusplus_winrt) -#include -#include #include +#include #include + +#include #ifndef _UITHREADCTXT_SUPPORT #ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/ @@ -93,36 +95,36 @@ void cpprest_init(JavaVM*); #include #if WINAPI_FAMILY == WINAPI_FAMILY_APP - // UI thread context support is not required for desktop and Windows Store apps - #define _UITHREADCTXT_SUPPORT 0 +// UI thread context support is not required for desktop and Windows Store apps +#define _UITHREADCTXT_SUPPORT 0 #elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP - // UI thread context support is not required for desktop and Windows Store apps - #define _UITHREADCTXT_SUPPORT 0 -#else /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */ - #define _UITHREADCTXT_SUPPORT 1 -#endif /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */ +// UI thread context support is not required for desktop and Windows Store apps +#define _UITHREADCTXT_SUPPORT 0 +#else /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */ +#define _UITHREADCTXT_SUPPORT 1 +#endif /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */ -#else /* WINAPI_FAMILY */ - // Not supported without a WINAPI_FAMILY setting. - #define _UITHREADCTXT_SUPPORT 0 -#endif /* WINAPI_FAMILY */ +#else /* WINAPI_FAMILY */ +// Not supported without a WINAPI_FAMILY setting. +#define _UITHREADCTXT_SUPPORT 0 +#endif /* WINAPI_FAMILY */ -#endif /* _UITHREADCTXT_SUPPORT */ +#endif /* _UITHREADCTXT_SUPPORT */ #if _UITHREADCTXT_SUPPORT - #include -#endif /* _UITHREADCTXT_SUPPORT */ +#include +#endif /* _UITHREADCTXT_SUPPORT */ - #pragma detect_mismatch("PPLXTASKS_WITH_WINRT", "1") +#pragma detect_mismatch("PPLXTASKS_WITH_WINRT", "1") #else /* defined(__cplusplus_winrt) */ - #pragma detect_mismatch("PPLXTASKS_WITH_WINRT", "0") +#pragma detect_mismatch("PPLXTASKS_WITH_WINRT", "0") #endif /* defined(__cplusplus_winrt) */ #endif /* defined(_MSC_VER) */ #ifdef _DEBUG - #define _DBG_ONLY(X) X +#define _DBG_ONLY(X) X #else - #define _DBG_ONLY(X) +#define _DBG_ONLY(X) #endif // #ifdef _DEBUG // std::copy_exception changed to std::make_exception_ptr from VS 2010 to VS 11. @@ -130,29 +132,30 @@ void cpprest_init(JavaVM*); #if _MSC_VER < 1700 /*IFSTRIP=IGN*/ namespace std { - template exception_ptr make_exception_ptr(_E _Except) - { - return copy_exception(_Except); - } +template +exception_ptr make_exception_ptr(_E _Except) +{ + return copy_exception(_Except); } -#endif /* _MSC_VER < 1700 */ +} // namespace std +#endif /* _MSC_VER < 1700 */ #ifndef PPLX_TASK_ASYNC_LOGGING - #if _MSC_VER >= 1800 && defined(__cplusplus_winrt) - #define PPLX_TASK_ASYNC_LOGGING 1 // Only enable async logging under dev12 winrt - #else - #define PPLX_TASK_ASYNC_LOGGING 0 - #endif +#if _MSC_VER >= 1800 && defined(__cplusplus_winrt) +#define PPLX_TASK_ASYNC_LOGGING 1 // Only enable async logging under dev12 winrt +#else +#define PPLX_TASK_ASYNC_LOGGING 0 +#endif #endif /* !PPLX_TASK_ASYNC_LOGGING */ #endif /* _MSC_VER */ -#pragma pack(push,_CRT_PACKING) +#pragma pack(push, _CRT_PACKING) #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable: 28197) -#pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation -#pragma warning(disable: 4127) // constant express in if condition - we use it for meta programming -#endif /* defined(_MSC_VER) */ +#pragma warning(disable : 28197) +#pragma warning(disable : 4100) // Unreferenced formal parameter - needed for document generation +#pragma warning(disable : 4127) // constant express in if condition - we use it for meta programming +#endif /* defined(_MSC_VER) */ // All CRT public header files are required to be protected from the macro new #pragma push_macro("new") @@ -163,8 +166,8 @@ namespace std // so don't blindly change it to std::declval. namespace stdx { - template - _T&& declval(); +template +_T&& declval(); } /// @@ -181,10 +184,13 @@ namespace pplx /**/ typedef task_group_status task_status; -template class task; -template <> class task; +template +class task; +template<> +class task; -// In debug builds, default to 10 frames, unless this is overridden prior to #includ'ing ppltasks.h. In retail builds, default to only one frame. +// In debug builds, default to 10 frames, unless this is overridden prior to #includ'ing ppltasks.h. In retail builds, +// default to only one frame. #ifndef PPLX_TASK_SAVE_FRAME_COUNT #ifdef _DEBUG #define PPLX_TASK_SAVE_FRAME_COUNT 10 @@ -195,24 +201,27 @@ template <> class task; /// /// Helper macro to determine how many stack frames need to be saved. When any number less or equal to 1 is specified, -/// only one frame is captured and no stackwalk will be involved. Otherwise, the number of callstack frames will be captured. +/// only one frame is captured and no stackwalk will be involved. Otherwise, the number of callstack frames will be +/// captured. /// /// -/// This needs to be defined as a macro rather than a function so that if we're only gathering one frame, _ReturnAddress() -/// will evaluate to client code, rather than a helper function inside of _TaskCreationCallstack, itself. +/// This needs to be defined as a macro rather than a function so that if we're only gathering one frame, +/// _ReturnAddress() will evaluate to client code, rather than a helper function inside of _TaskCreationCallstack, +/// itself. /// #if PPLX_TASK_SAVE_FRAME_COUNT > 1 #if defined(__cplusplus_winrt) && !defined(_DEBUG) -#pragma message ("WARNING: Redefining PPLX_TASK_SAVE_FRAME_COUNT under Release build for non-desktop applications is not supported; only one frame will be captured!") +#pragma message( \ + "WARNING: Redefining PPLX_TASK_SAVE_FRAME_COUNT under Release build for non-desktop applications is not supported; only one frame will be captured!") #define PPLX_CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress()) #else -#define PPLX_CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPLX_TASK_SAVE_FRAME_COUNT) +#define PPLX_CAPTURE_CALLSTACK() \ + ::pplx::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPLX_TASK_SAVE_FRAME_COUNT) #endif #else #define PPLX_CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress()) #endif - /// /// Returns an indication of whether the task that is currently executing has received a request to cancel its /// execution. Cancellation is requested on a task if the task was created with a cancellation token, and @@ -250,896 +259,869 @@ inline bool _pplx_cdecl is_task_cancellation_requested() /// /// /**/ -inline __declspec(noreturn) void _pplx_cdecl cancel_current_task() -{ - throw task_canceled(); -} +inline __declspec(noreturn) void _pplx_cdecl cancel_current_task() { throw task_canceled(); } namespace details { - /// - /// Callstack container, which is used to capture and preserve callstacks in ppltasks. - /// Members of this class is examined by vc debugger, thus there will be no public access methods. - /// Please note that names of this class should be kept stable for debugger examining. - /// - class _TaskCreationCallstack - { - private: - // If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame; - // otherwise, _M_Frame will store all the callstack frames. - void* _M_SingleFrame; - std::vector _M_frames; - public: - _TaskCreationCallstack() - { - _M_SingleFrame = nullptr; - } - - // Store one frame of callstack. This function works for both Debug / Release CRT. - static _TaskCreationCallstack _CaptureSingleFrameCallstack(void *_SingleFrame) - { - _TaskCreationCallstack _csc; - _csc._M_SingleFrame = _SingleFrame; - return _csc; - } - - // Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT. - __declspec(noinline) - static _TaskCreationCallstack _CaptureMultiFramesCallstack(size_t _CaptureFrames) - { - _TaskCreationCallstack _csc; - _csc._M_frames.resize(_CaptureFrames); - // skip 2 frames to make sure callstack starts from user code - _csc._M_frames.resize(::pplx::details::platform::CaptureCallstack(&_csc._M_frames[0], 2, _CaptureFrames)); - return _csc; - } - }; - typedef unsigned char _Unit_type; +/// +/// Callstack container, which is used to capture and preserve callstacks in ppltasks. +/// Members of this class is examined by vc debugger, thus there will be no public access methods. +/// Please note that names of this class should be kept stable for debugger examining. +/// +class _TaskCreationCallstack +{ +private: + // If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame; + // otherwise, _M_Frame will store all the callstack frames. + void* _M_SingleFrame; + std::vector _M_frames; - struct _TypeSelectorNoAsync {}; - struct _TypeSelectorAsyncOperationOrTask {}; - struct _TypeSelectorAsyncOperation : public _TypeSelectorAsyncOperationOrTask { }; - struct _TypeSelectorAsyncTask : public _TypeSelectorAsyncOperationOrTask { }; - struct _TypeSelectorAsyncAction {}; - struct _TypeSelectorAsyncActionWithProgress {}; - struct _TypeSelectorAsyncOperationWithProgress {}; +public: + _TaskCreationCallstack() { _M_SingleFrame = nullptr; } - template - struct _NormalizeVoidToUnitType + // Store one frame of callstack. This function works for both Debug / Release CRT. + static _TaskCreationCallstack _CaptureSingleFrameCallstack(void* _SingleFrame) { - typedef _Ty _Type; - }; + _TaskCreationCallstack _csc; + _csc._M_SingleFrame = _SingleFrame; + return _csc; + } - template<> - struct _NormalizeVoidToUnitType + // Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT. + __declspec(noinline) static _TaskCreationCallstack _CaptureMultiFramesCallstack(size_t _CaptureFrames) { - typedef _Unit_type _Type; - }; + _TaskCreationCallstack _csc; + _csc._M_frames.resize(_CaptureFrames); + // skip 2 frames to make sure callstack starts from user code + _csc._M_frames.resize(::pplx::details::platform::CaptureCallstack(&_csc._M_frames[0], 2, _CaptureFrames)); + return _csc; + } +}; +typedef unsigned char _Unit_type; - template - struct _IsUnwrappedAsyncSelector - { - static const bool _Value = true; - }; +struct _TypeSelectorNoAsync +{ +}; +struct _TypeSelectorAsyncOperationOrTask +{ +}; +struct _TypeSelectorAsyncOperation : public _TypeSelectorAsyncOperationOrTask +{ +}; +struct _TypeSelectorAsyncTask : public _TypeSelectorAsyncOperationOrTask +{ +}; +struct _TypeSelectorAsyncAction +{ +}; +struct _TypeSelectorAsyncActionWithProgress +{ +}; +struct _TypeSelectorAsyncOperationWithProgress +{ +}; - template<> - struct _IsUnwrappedAsyncSelector<_TypeSelectorNoAsync> - { - static const bool _Value = false; - }; +template +struct _NormalizeVoidToUnitType +{ + typedef _Ty _Type; +}; - template - struct _UnwrapTaskType - { - typedef _Ty _Type; - }; +template<> +struct _NormalizeVoidToUnitType +{ + typedef _Unit_type _Type; +}; - template - struct _UnwrapTaskType> - { - typedef _Ty _Type; - }; +template +struct _IsUnwrappedAsyncSelector +{ + static const bool _Value = true; +}; + +template<> +struct _IsUnwrappedAsyncSelector<_TypeSelectorNoAsync> +{ + static const bool _Value = false; +}; + +template +struct _UnwrapTaskType +{ + typedef _Ty _Type; +}; + +template +struct _UnwrapTaskType> +{ + typedef _Ty _Type; +}; - template - _TypeSelectorAsyncTask _AsyncOperationKindSelector(task<_T>); +template +_TypeSelectorAsyncTask _AsyncOperationKindSelector(task<_T>); - _TypeSelectorNoAsync _AsyncOperationKindSelector(...); +_TypeSelectorNoAsync _AsyncOperationKindSelector(...); #if defined(__cplusplus_winrt) - template - struct _Unhat - { - typedef _Type _Value; - }; +template +struct _Unhat +{ + typedef _Type _Value; +}; - template - struct _Unhat<_Type^> - { - typedef _Type _Value; - }; +template +struct _Unhat<_Type ^> +{ + typedef _Type _Value; +}; - value struct _NonUserType { public: int _Dummy; }; +value struct _NonUserType +{ +public: + int _Dummy; +}; - template - struct _ValueTypeOrRefType - { - typedef _NonUserType _Value; - }; +template +struct _ValueTypeOrRefType +{ + typedef _NonUserType _Value; +}; - template - struct _ValueTypeOrRefType<_Type, true> - { - typedef _Type _Value; - }; +template +struct _ValueTypeOrRefType<_Type, true> +{ + typedef _Type _Value; +}; - template - _T2 _ProgressTypeSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1,_T2>^); +template +_T2 _ProgressTypeSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2> ^); - template - _T1 _ProgressTypeSelector(Windows::Foundation::IAsyncActionWithProgress<_T1>^); +template +_T1 _ProgressTypeSelector(Windows::Foundation::IAsyncActionWithProgress<_T1> ^); - template - struct _GetProgressType - { - typedef decltype(_ProgressTypeSelector(stdx::declval<_Type>())) _Value; - }; +template +struct _GetProgressType +{ + typedef decltype(_ProgressTypeSelector(stdx::declval<_Type>())) _Value; +}; - template - struct _IsIAsyncInfo - { - static const bool _Value = __is_base_of(Windows::Foundation::IAsyncInfo, typename _Unhat<_Type>::_Value); - }; +template +struct _IsIAsyncInfo +{ + static const bool _Value = __is_base_of(Windows::Foundation::IAsyncInfo, typename _Unhat<_Type>::_Value); +}; - template - _TypeSelectorAsyncOperation _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperation<_T>^); +template +_TypeSelectorAsyncOperation _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperation<_T> ^); - _TypeSelectorAsyncAction _AsyncOperationKindSelector(Windows::Foundation::IAsyncAction^); +_TypeSelectorAsyncAction _AsyncOperationKindSelector(Windows::Foundation::IAsyncAction ^); - template - _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>^); +template +_TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector( + Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2> ^); - template - _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncActionWithProgress<_T>^); +template +_TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncActionWithProgress<_T> ^); - template ::_Value> - struct _TaskTypeTraits - { - typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType; - typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind; - typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType; +template::_Value> +struct _TaskTypeTraits +{ + typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType; + typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind; + typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType; - static const bool _IsAsyncTask = _IsAsync; - static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value; - }; + static const bool _IsAsyncTask = _IsAsync; + static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value; +}; - template - struct _TaskTypeTraits<_Type, true > - { - typedef decltype(((_Type)nullptr)->GetResults()) _TaskRetType; - typedef _TaskRetType _NormalizedTaskRetType; - typedef decltype(_AsyncOperationKindSelector((_Type)nullptr)) _AsyncKind; +template +struct _TaskTypeTraits<_Type, true> +{ + typedef decltype(((_Type) nullptr)->GetResults()) _TaskRetType; + typedef _TaskRetType _NormalizedTaskRetType; + typedef decltype(_AsyncOperationKindSelector((_Type) nullptr)) _AsyncKind; - static const bool _IsAsyncTask = true; - static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value; - }; + static const bool _IsAsyncTask = true; + static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value; +}; #else /* defined (__cplusplus_winrt) */ - template - struct _IsIAsyncInfo - { - static const bool _Value = false; - }; +template +struct _IsIAsyncInfo +{ + static const bool _Value = false; +}; - template - struct _TaskTypeTraits - { - typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType; - typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind; - typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType; +template +struct _TaskTypeTraits +{ + typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType; + typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind; + typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType; - static const bool _IsAsyncTask = false; - static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value; - }; -#endif /* defined (__cplusplus_winrt) */ + static const bool _IsAsyncTask = false; + static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value; +}; +#endif /* defined (__cplusplus_winrt) */ + +template +auto _IsCallable(_Function _Func, int) -> decltype(_Func(), std::true_type()) +{ + (void)(_Func); + return std::true_type(); +} +template +std::false_type _IsCallable(_Function, ...) +{ + return std::false_type(); +} - template auto _IsCallable(_Function _Func, int) -> decltype(_Func(), std::true_type()) { (void)(_Func); return std::true_type(); } - template std::false_type _IsCallable(_Function, ...) { return std::false_type(); } +template<> +struct _TaskTypeTraits +{ + typedef void _TaskRetType; + typedef _TypeSelectorNoAsync _AsyncKind; + typedef _Unit_type _NormalizedTaskRetType; - template <> - struct _TaskTypeTraits - { - typedef void _TaskRetType; - typedef _TypeSelectorNoAsync _AsyncKind; - typedef _Unit_type _NormalizedTaskRetType; + static const bool _IsAsyncTask = false; + static const bool _IsUnwrappedTaskOrAsync = false; +}; - static const bool _IsAsyncTask = false; - static const bool _IsUnwrappedTaskOrAsync = false; - }; +template +task<_Type> _To_task(_Type t); - template - task<_Type> _To_task(_Type t); +template +task _To_task_void(_Func f); - template - task _To_task_void(_Func f); +struct _BadContinuationParamType +{ +}; - struct _BadContinuationParamType{}; +template +auto _ReturnTypeHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t))); +template +auto _ReturnTypeHelper(_Type t, _Function _Func, int, ...) -> decltype(_Func(t)); +template +auto _ReturnTypeHelper(_Type t, _Function _Func, ...) -> _BadContinuationParamType; - template auto _ReturnTypeHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t))); - template auto _ReturnTypeHelper(_Type t, _Function _Func, int, ...) -> decltype(_Func(t)); - template auto _ReturnTypeHelper(_Type t, _Function _Func, ...) -> _BadContinuationParamType; +template +auto _IsTaskHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)), std::true_type()); +template +std::false_type _IsTaskHelper(_Type t, _Function _Func, int, ...); - template auto _IsTaskHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)), std::true_type()); - template std::false_type _IsTaskHelper(_Type t, _Function _Func, int, ...); +template +auto _VoidReturnTypeHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func))); +template +auto _VoidReturnTypeHelper(_Function _Func, int, ...) -> decltype(_Func()); - template auto _VoidReturnTypeHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func))); - template auto _VoidReturnTypeHelper(_Function _Func, int, ...) -> decltype(_Func()); +template +auto _VoidIsTaskHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)), std::true_type()); +template +std::false_type _VoidIsTaskHelper(_Function _Func, int, ...); - template auto _VoidIsTaskHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)), std::true_type()); - template std::false_type _VoidIsTaskHelper(_Function _Func, int, ...); +template +struct _FunctionTypeTraits +{ + typedef decltype( + _ReturnTypeHelper(stdx::declval<_ExpectedParameterType>(), stdx::declval<_Function>(), 0, 0)) _FuncRetType; + static_assert(!std::is_same<_FuncRetType, _BadContinuationParamType>::value, + "incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or " + "task<_ExpectedParameterType> (see below)"); + + typedef decltype( + _IsTaskHelper(stdx::declval<_ExpectedParameterType>(), stdx::declval<_Function>(), 0, 0)) _Takes_task; +}; - template - struct _FunctionTypeTraits - { - typedef decltype(_ReturnTypeHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _FuncRetType; - static_assert(!std::is_same<_FuncRetType,_BadContinuationParamType>::value, "incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)"); +template +struct _FunctionTypeTraits<_Function, void> +{ + typedef decltype(_VoidReturnTypeHelper(stdx::declval<_Function>(), 0, 0)) _FuncRetType; + typedef decltype(_VoidIsTaskHelper(stdx::declval<_Function>(), 0, 0)) _Takes_task; +}; - typedef decltype(_IsTaskHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _Takes_task; - }; +template +struct _ContinuationTypeTraits +{ + typedef task< + typename _TaskTypeTraits::_FuncRetType>::_TaskRetType> + _TaskOfType; +}; - template - struct _FunctionTypeTraits<_Function, void> - { - typedef decltype(_VoidReturnTypeHelper(stdx::declval<_Function>(), 0, 0)) _FuncRetType; - typedef decltype(_VoidIsTaskHelper(stdx::declval<_Function>(), 0, 0)) _Takes_task; - }; +// _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on +// how the variable is declared, the constructor may or may not perform unwrapping. For eg. +// +// This declaration SHOULD NOT cause unwrapping +// task> t1([]() -> task { +// task t2([]() {}); +// return t2; +// }); +// +// This declaration SHOULD cause unwrapping +// task> t1([]() -> task { +// task t2([]() {}); +// return t2; +// }); +// If the type of the task is the same as the return type of the function, no unwrapping should take place. Else normal +// rules apply. +template +struct _InitFunctorTypeTraits +{ + typedef typename _TaskTypeTraits<_FuncRetType>::_AsyncKind _AsyncKind; + static const bool _IsAsyncTask = _TaskTypeTraits<_FuncRetType>::_IsAsyncTask; + static const bool _IsUnwrappedTaskOrAsync = _TaskTypeTraits<_FuncRetType>::_IsUnwrappedTaskOrAsync; +}; - template - struct _ContinuationTypeTraits - { - typedef task::_FuncRetType>::_TaskRetType> _TaskOfType; - }; +template +struct _InitFunctorTypeTraits +{ + typedef _TypeSelectorNoAsync _AsyncKind; + static const bool _IsAsyncTask = false; + static const bool _IsUnwrappedTaskOrAsync = false; +}; - // _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on how the variable is - // declared, the constructor may or may not perform unwrapping. For eg. - // - // This declaration SHOULD NOT cause unwrapping - // task> t1([]() -> task { - // task t2([]() {}); - // return t2; - // }); - // - // This declaration SHOULD cause unwrapping - // task> t1([]() -> task { - // task t2([]() {}); - // return t2; - // }); - // If the type of the task is the same as the return type of the function, no unwrapping should take place. Else normal rules apply. - template - struct _InitFunctorTypeTraits - { - typedef typename _TaskTypeTraits<_FuncRetType>::_AsyncKind _AsyncKind; - static const bool _IsAsyncTask = _TaskTypeTraits<_FuncRetType>::_IsAsyncTask; - static const bool _IsUnwrappedTaskOrAsync = _TaskTypeTraits<_FuncRetType>::_IsUnwrappedTaskOrAsync; - }; +/// +/// Helper object used for LWT invocation. +/// +struct _TaskProcThunk +{ + _TaskProcThunk(const std::function& _Callback) : _M_func(_Callback) {} - template - struct _InitFunctorTypeTraits + static void _pplx_cdecl _Bridge(void* _PData) { - typedef _TypeSelectorNoAsync _AsyncKind; - static const bool _IsAsyncTask = false; - static const bool _IsUnwrappedTaskOrAsync = false; - }; + _TaskProcThunk* _PThunk = reinterpret_cast<_TaskProcThunk*>(_PData); + _Holder _ThunkHolder(_PThunk); + _PThunk->_M_func(); + } - /// - /// Helper object used for LWT invocation. - /// - struct _TaskProcThunk +private: + // RAII holder + struct _Holder { - _TaskProcThunk(const std::function & _Callback) : - _M_func(_Callback) - { - } + _Holder(_TaskProcThunk* _PThunk) : _M_pThunk(_PThunk) {} - static void _pplx_cdecl _Bridge(void *_PData) - { - _TaskProcThunk *_PThunk = reinterpret_cast<_TaskProcThunk *>(_PData); - _Holder _ThunkHolder(_PThunk); - _PThunk->_M_func(); - } - private: + ~_Holder() { delete _M_pThunk; } - // RAII holder - struct _Holder - { - _Holder(_TaskProcThunk * _PThunk) : _M_pThunk(_PThunk) - { - } + _TaskProcThunk* _M_pThunk; - ~_Holder() - { - delete _M_pThunk; - } + private: + _Holder& operator=(const _Holder&); + }; - _TaskProcThunk * _M_pThunk; + std::function _M_func; + _TaskProcThunk& operator=(const _TaskProcThunk&); +}; - private: - _Holder& operator=(const _Holder&); - }; +/// +/// Schedule a functor with automatic inlining. Note that this is "fire and forget" scheduling, which cannot be +/// waited on or canceled after scheduling. +/// This schedule method will perform automatic inlining base on . +/// +/// +/// The user functor need to be scheduled. +/// +/// +/// The inlining scheduling policy for current functor. +/// +static void _ScheduleFuncWithAutoInline(const std::function& _Func, _TaskInliningMode_t _InliningMode) +{ + _TaskCollection_t::_RunTask(&_TaskProcThunk::_Bridge, new _TaskProcThunk(_Func), _InliningMode); +} - std::function _M_func; - _TaskProcThunk& operator=(const _TaskProcThunk&); - }; +class _ContextCallback +{ + typedef std::function _CallbackFunction; - /// - /// Schedule a functor with automatic inlining. Note that this is "fire and forget" scheduling, which cannot be - /// waited on or canceled after scheduling. - /// This schedule method will perform automatic inlining base on . - /// - /// - /// The user functor need to be scheduled. - /// - /// - /// The inlining scheduling policy for current functor. - /// - static void _ScheduleFuncWithAutoInline(const std::function & _Func, _TaskInliningMode_t _InliningMode) - { - _TaskCollection_t::_RunTask(&_TaskProcThunk::_Bridge, new _TaskProcThunk(_Func), _InliningMode); - } +#if defined(__cplusplus_winrt) - class _ContextCallback +public: + static _ContextCallback _CaptureCurrent() { - typedef std::function _CallbackFunction; - -#if defined (__cplusplus_winrt) + _ContextCallback _Context; + _Context._Capture(); + return _Context; + } - public: + ~_ContextCallback() { _Reset(); } - static _ContextCallback _CaptureCurrent() + _ContextCallback(bool _DeferCapture = false) + { + if (_DeferCapture) { - _ContextCallback _Context; - _Context._Capture(); - return _Context; + _M_context._M_captureMethod = _S_captureDeferred; } - - ~_ContextCallback() + else { - _Reset(); + _M_context._M_pContextCallback = nullptr; } + } - _ContextCallback(bool _DeferCapture = false) + // Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context). + void _Resolve(bool _CaptureCurrent) + { + if (_M_context._M_captureMethod == _S_captureDeferred) { - if (_DeferCapture) - { - _M_context._M_captureMethod = _S_captureDeferred; - } - else - { - _M_context._M_pContextCallback = nullptr; - } - } + _M_context._M_pContextCallback = nullptr; - // Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context). - void _Resolve(bool _CaptureCurrent) - { - if(_M_context._M_captureMethod == _S_captureDeferred) + if (_CaptureCurrent) { - _M_context._M_pContextCallback = nullptr; - - if (_CaptureCurrent) + if (_IsCurrentOriginSTA()) { - if (_IsCurrentOriginSTA()) - { - _Capture(); - } + _Capture(); + } #if _UITHREADCTXT_SUPPORT - else + else + { + // This method will fail if not called from the UI thread. + HRESULT _Hr = CaptureUiThreadContext(&_M_context._M_pContextCallback); + if (FAILED(_Hr)) { - // This method will fail if not called from the UI thread. - HRESULT _Hr = CaptureUiThreadContext(&_M_context._M_pContextCallback); - if (FAILED(_Hr)) - { - _M_context._M_pContextCallback = nullptr; - } + _M_context._M_pContextCallback = nullptr; } -#endif /* _UITHREADCTXT_SUPPORT */ } +#endif /* _UITHREADCTXT_SUPPORT */ } } + } - void _Capture() + void _Capture() + { + HRESULT _Hr = + CoGetObjectContext(IID_IContextCallback, reinterpret_cast(&_M_context._M_pContextCallback)); + if (FAILED(_Hr)) { - HRESULT _Hr = CoGetObjectContext(IID_IContextCallback, reinterpret_cast(&_M_context._M_pContextCallback)); - if (FAILED(_Hr)) - { - _M_context._M_pContextCallback = nullptr; - } + _M_context._M_pContextCallback = nullptr; } + } + + _ContextCallback(const _ContextCallback& _Src) { _Assign(_Src._M_context._M_pContextCallback); } + + _ContextCallback(_ContextCallback&& _Src) + { + _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback; + _Src._M_context._M_pContextCallback = nullptr; + } - _ContextCallback(const _ContextCallback& _Src) + _ContextCallback& operator=(const _ContextCallback& _Src) + { + if (this != &_Src) { + _Reset(); _Assign(_Src._M_context._M_pContextCallback); } + return *this; + } - _ContextCallback(_ContextCallback&& _Src) + _ContextCallback& operator=(_ContextCallback&& _Src) + { + if (this != &_Src) { _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback; _Src._M_context._M_pContextCallback = nullptr; } + return *this; + } - _ContextCallback& operator=(const _ContextCallback& _Src) - { - if (this != &_Src) - { - _Reset(); - _Assign(_Src._M_context._M_pContextCallback); - } - return *this; - } + bool _HasCapturedContext() const + { + _ASSERTE(_M_context._M_captureMethod != _S_captureDeferred); + return (_M_context._M_pContextCallback != nullptr); + } - _ContextCallback& operator=(_ContextCallback&& _Src) + void _CallInContext(_CallbackFunction _Func) const + { + if (!_HasCapturedContext()) { - if (this != &_Src) - { - _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback; - _Src._M_context._M_pContextCallback = nullptr; - } - return *this; + _Func(); } - - bool _HasCapturedContext() const + else { - _ASSERTE(_M_context._M_captureMethod != _S_captureDeferred); - return (_M_context._M_pContextCallback != nullptr); - } + ComCallData callData; + ZeroMemory(&callData, sizeof(callData)); + callData.pUserDefined = reinterpret_cast(&_Func); - void _CallInContext(_CallbackFunction _Func) const - { - if (!_HasCapturedContext()) - { - _Func(); - } - else + HRESULT _Hr = _M_context._M_pContextCallback->ContextCallback( + &_Bridge, &callData, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr); + if (FAILED(_Hr)) { - ComCallData callData; - ZeroMemory(&callData, sizeof(callData)); - callData.pUserDefined = reinterpret_cast(&_Func); - - HRESULT _Hr = _M_context._M_pContextCallback->ContextCallback(&_Bridge, &callData, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr); - if (FAILED(_Hr)) - { - throw ::Platform::Exception::CreateException(_Hr); - } + throw ::Platform::Exception::CreateException(_Hr); } } + } - bool operator==(const _ContextCallback& _Rhs) const - { - return (_M_context._M_pContextCallback == _Rhs._M_context._M_pContextCallback); - } + bool operator==(const _ContextCallback& _Rhs) const + { + return (_M_context._M_pContextCallback == _Rhs._M_context._M_pContextCallback); + } - bool operator!=(const _ContextCallback& _Rhs) const - { - return !(operator==(_Rhs)); - } + bool operator!=(const _ContextCallback& _Rhs) const { return !(operator==(_Rhs)); } - private: - void _Reset() +private: + void _Reset() + { + if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr) { - if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr) - { - _M_context._M_pContextCallback->Release(); - } + _M_context._M_pContextCallback->Release(); } + } - void _Assign(IContextCallback *_PContextCallback) + void _Assign(IContextCallback* _PContextCallback) + { + _M_context._M_pContextCallback = _PContextCallback; + if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr) { - _M_context._M_pContextCallback = _PContextCallback; - if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr) - { - _M_context._M_pContextCallback->AddRef(); - } + _M_context._M_pContextCallback->AddRef(); } + } - static HRESULT __stdcall _Bridge(ComCallData *_PParam) - { - _CallbackFunction *pFunc = reinterpret_cast<_CallbackFunction *>(_PParam->pUserDefined); - (*pFunc)(); - return S_OK; - } + static HRESULT __stdcall _Bridge(ComCallData* _PParam) + { + _CallbackFunction* pFunc = reinterpret_cast<_CallbackFunction*>(_PParam->pUserDefined); + (*pFunc)(); + return S_OK; + } - // Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know) - static bool _IsCurrentOriginSTA() - { - APTTYPE _AptType; - APTTYPEQUALIFIER _AptTypeQualifier; + // Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations + // need know) + static bool _IsCurrentOriginSTA() + { + APTTYPE _AptType; + APTTYPEQUALIFIER _AptTypeQualifier; - HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier); - if (SUCCEEDED(hr)) + HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier); + if (SUCCEEDED(hr)) + { + // We determine the origin of a task continuation by looking at where .then is called, so we can tell + // whether to need to marshal the continuation back to the originating apartment. If an STA thread is in + // executing in a neutral apartment when it schedules a continuation, we will not marshal continuations back + // to the STA, since variables used within a neutral apartment are expected to be apartment neutral. + switch (_AptType) { - // We determine the origin of a task continuation by looking at where .then is called, so we can tell whether - // to need to marshal the continuation back to the originating apartment. If an STA thread is in executing in - // a neutral apartment when it schedules a continuation, we will not marshal continuations back to the STA, - // since variables used within a neutral apartment are expected to be apartment neutral. - switch(_AptType) - { - case APTTYPE_MAINSTA: - case APTTYPE_STA: - return true; - default: - break; - } + case APTTYPE_MAINSTA: + case APTTYPE_STA: return true; + default: break; } - return false; } + return false; + } - union - { - IContextCallback *_M_pContextCallback; - size_t _M_captureMethod; - } _M_context; + union { + IContextCallback* _M_pContextCallback; + size_t _M_captureMethod; + } _M_context; - static const size_t _S_captureDeferred = 1; + static const size_t _S_captureDeferred = 1; #else /* defined (__cplusplus_winrt) */ - public: +public: + static _ContextCallback _CaptureCurrent() { return _ContextCallback(); } - static _ContextCallback _CaptureCurrent() - { - return _ContextCallback(); - } + _ContextCallback(bool = false) {} - _ContextCallback(bool = false) - { - } + _ContextCallback(const _ContextCallback&) {} - _ContextCallback(const _ContextCallback&) - { - } + _ContextCallback(_ContextCallback&&) {} - _ContextCallback(_ContextCallback&&) - { - } + _ContextCallback& operator=(const _ContextCallback&) { return *this; } - _ContextCallback& operator=(const _ContextCallback&) - { - return *this; - } + _ContextCallback& operator=(_ContextCallback&&) { return *this; } - _ContextCallback& operator=(_ContextCallback&&) - { - return *this; - } + bool _HasCapturedContext() const { return false; } - bool _HasCapturedContext() const - { - return false; - } + void _Resolve(bool) const {} - void _Resolve(bool) const - { - } + void _CallInContext(_CallbackFunction _Func) const { _Func(); } - void _CallInContext(_CallbackFunction _Func) const - { - _Func(); - } + bool operator==(const _ContextCallback&) const { return true; } - bool operator==(const _ContextCallback&) const - { - return true; - } + bool operator!=(const _ContextCallback&) const { return false; } - bool operator!=(const _ContextCallback&) const - { - return false; - } +#endif /* defined (__cplusplus_winrt) */ +}; -#endif /* defined (__cplusplus_winrt) */ - }; +template +struct _ResultHolder +{ + void Set(const _Type& _type) { _Result = _type; } - template - struct _ResultHolder - { - void Set(const _Type& _type) - { - _Result = _type; - } + _Type Get() { return _Result; } - _Type Get() - { - return _Result; - } + _Type _Result; +}; - _Type _Result; - }; +#if defined(__cplusplus_winrt) -#if defined (__cplusplus_winrt) +template +struct _ResultHolder<_Type ^> +{ + void Set(_Type ^ const& _type) { _M_Result = _type; } - template - struct _ResultHolder<_Type^> + _Type ^ Get() { return _M_Result.Get(); } private : + // ::Platform::Agile handle specialization of all hats + // including ::Platform::String and ::Platform::Array + ::Platform::Agile<_Type ^> _M_Result; +}; + +// +// The below are for composability with tasks auto-created from when_any / when_all / && / || constructs. +// +template +struct _ResultHolder> +{ + void Set(const std::vector<_Type ^>& _type) { - void Set(_Type^ const & _type) - { - _M_Result = _type; - } + _Result.reserve(_type.size()); - _Type^ Get() + for (auto _PTask = _type.begin(); _PTask != _type.end(); ++_PTask) { - return _M_Result.Get(); + _Result.emplace_back(*_PTask); } - private: - // ::Platform::Agile handle specialization of all hats - // including ::Platform::String and ::Platform::Array - ::Platform::Agile<_Type^> _M_Result; - }; + } - // - // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs. - // - template - struct _ResultHolder> + std::vector<_Type ^> Get() { - void Set(const std::vector<_Type^>& _type) - { - _Result.reserve(_type.size()); + // Return vectory with the objects that are marshaled in the proper apartment + std::vector<_Type ^> _Return; + _Return.reserve(_Result.size()); - for (auto _PTask = _type.begin(); _PTask != _type.end(); ++_PTask) - { - _Result.emplace_back(*_PTask); - } + for (auto _PTask = _Result.begin(); _PTask != _Result.end(); ++_PTask) + { + _Return.push_back( + _PTask->Get()); // Platform::Agile will marshal the object to appropriate apartment if necessary } - std::vector<_Type^> Get() - { - // Return vectory with the objects that are marshaled in the proper apartment - std::vector<_Type^> _Return; - _Return.reserve(_Result.size()); + return _Return; + } - for (auto _PTask = _Result.begin(); _PTask != _Result.end(); ++_PTask) - { - _Return.push_back(_PTask->Get()); // Platform::Agile will marshal the object to appropriate apartment if necessary - } + std::vector<::Platform::Agile<_Type ^>> _Result; +}; - return _Return; - } +template +struct _ResultHolder> +{ + void Set(const std::pair<_Type ^, size_t>& _type) { _M_Result = _type; } - std::vector< ::Platform::Agile<_Type^> > _Result; - }; + std::pair<_Type ^, size_t> Get() { return std::make_pair(_M_Result.first.Get(), _M_Result.second); } - template - struct _ResultHolder > +private: + std::pair<::Platform::Agile<_Type ^>, size_t> _M_Result; +}; + +#endif /* defined (__cplusplus_winrt) */ + +// An exception thrown by the task body is captured in an exception holder and it is shared with all value based +// continuations rooted at the task. The exception is 'observed' if the user invokes get()/wait() on any of the tasks +// that are sharing this exception holder. If the exception is not observed by the time the internal object owned by the +// shared pointer destructs, the process will fail fast. +struct _ExceptionHolder +{ +private: + void ReportUnhandledError() { - void Set(const std::pair<_Type^, size_t>& _type) +#if _MSC_VER >= 1800 && defined(__cplusplus_winrt) + if (_M_winRTException != nullptr) { - _M_Result = _type; + ::Platform::Details::ReportUnhandledError(_M_winRTException); } +#endif /* defined (__cplusplus_winrt) */ + } - std::pair<_Type^, size_t> Get() - { - return std::make_pair(_M_Result.first.Get(), _M_Result.second); - } - private: - std::pair< ::Platform::Agile<_Type^>, size_t> _M_Result; - }; +public: + explicit _ExceptionHolder(const std::exception_ptr& _E, const _TaskCreationCallstack& _stackTrace) + : _M_exceptionObserved(0) + , _M_stdException(_E) + , _M_stackTrace(_stackTrace) +#if defined(__cplusplus_winrt) + , _M_winRTException(nullptr) +#endif /* defined (__cplusplus_winrt) */ + { + } -#endif /* defined (__cplusplus_winrt) */ +#if defined(__cplusplus_winrt) + explicit _ExceptionHolder(::Platform::Exception ^ _E, const _TaskCreationCallstack& _stackTrace) + : _M_exceptionObserved(0), _M_winRTException(_E), _M_stackTrace(_stackTrace) + { + } +#endif /* defined (__cplusplus_winrt) */ - // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task. - // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception - // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast. - struct _ExceptionHolder + __declspec(noinline) ~_ExceptionHolder() { - private: - void ReportUnhandledError() - { -#if _MSC_VER >= 1800 && defined(__cplusplus_winrt) - if (_M_winRTException != nullptr) - { - ::Platform::Details::ReportUnhandledError(_M_winRTException); - } -#endif /* defined (__cplusplus_winrt) */ - } - public: - explicit _ExceptionHolder(const std::exception_ptr& _E, const _TaskCreationCallstack &_stackTrace) : - _M_exceptionObserved(0), _M_stdException(_E), _M_stackTrace(_stackTrace) -#if defined (__cplusplus_winrt) - , _M_winRTException(nullptr) -#endif /* defined (__cplusplus_winrt) */ + if (_M_exceptionObserved == 0) { + // If you are trapped here, it means an exception thrown in task chain didn't get handled. + // Please add task-based continuation to handle all exceptions coming from tasks. + // this->_M_stackTrace keeps the creation callstack of the task generates this exception. + _REPORT_PPLTASK_UNOBSERVED_EXCEPTION(); } + } -#if defined (__cplusplus_winrt) - explicit _ExceptionHolder(::Platform::Exception^ _E, const _TaskCreationCallstack &_stackTrace) : - _M_exceptionObserved(0), _M_winRTException(_E), _M_stackTrace(_stackTrace) + void _RethrowUserException() + { + if (_M_exceptionObserved == 0) { + atomic_exchange(_M_exceptionObserved, 1l); } -#endif /* defined (__cplusplus_winrt) */ - __declspec(noinline) - ~_ExceptionHolder() +#if defined(__cplusplus_winrt) + if (_M_winRTException != nullptr) { - if (_M_exceptionObserved == 0) - { - // If you are trapped here, it means an exception thrown in task chain didn't get handled. - // Please add task-based continuation to handle all exceptions coming from tasks. - // this->_M_stackTrace keeps the creation callstack of the task generates this exception. - _REPORT_PPLTASK_UNOBSERVED_EXCEPTION(); - } + throw _M_winRTException; } +#endif /* defined (__cplusplus_winrt) */ + std::rethrow_exception(_M_stdException); + } - void _RethrowUserException() - { - if (_M_exceptionObserved == 0) - { - atomic_exchange(_M_exceptionObserved, 1l); - } + // A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). + // Exceptions that are unobserved when the exception holder is destructed will terminate the process. + atomic_long _M_exceptionObserved; -#if defined (__cplusplus_winrt) - if (_M_winRTException != nullptr) - { - throw _M_winRTException; - } -#endif /* defined (__cplusplus_winrt) */ - std::rethrow_exception(_M_stdException); - } + // Either _M_stdException or _M_winRTException is populated based on the type of exception encountered. + std::exception_ptr _M_stdException; +#if defined(__cplusplus_winrt) + ::Platform::Exception ^ _M_winRTException; +#endif /* defined (__cplusplus_winrt) */ + + // Disassembling this value will point to a source instruction right after a call instruction. If the call is to + // create_task, a task constructor or the then method, the task created by that method is the one that encountered + // this exception. If the call is to task_completion_event::set_exception, the set_exception method was the source + // of the exception. DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging. + _TaskCreationCallstack _M_stackTrace; +}; - // A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). Exceptions that - // are unobserved when the exception holder is destructed will terminate the process. - atomic_long _M_exceptionObserved; +#if defined(__cplusplus_winrt) +/// +/// Base converter class for converting asynchronous interfaces to IAsyncOperation +/// +template +ref struct _AsyncInfoImpl abstract : Windows::Foundation::IAsyncOperation<_Result> +{ + internal : + // The async action, action with progress or operation with progress that this stub forwards to. + ::Platform::Agile<_AsyncOperationType> + _M_asyncInfo; - // Either _M_stdException or _M_winRTException is populated based on the type of exception encountered. - std::exception_ptr _M_stdException; -#if defined (__cplusplus_winrt) - ::Platform::Exception^ _M_winRTException; -#endif /* defined (__cplusplus_winrt) */ + Windows::Foundation::AsyncOperationCompletedHandler<_Result> ^ _M_CompletedHandler; - // Disassembling this value will point to a source instruction right after a call instruction. If the call is to create_task, - // a task constructor or the then method, the task created by that method is the one that encountered this exception. If the call - // is to task_completion_event::set_exception, the set_exception method was the source of the exception. - // DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging. - _TaskCreationCallstack _M_stackTrace; + _AsyncInfoImpl(_AsyncOperationType _AsyncInfo) : _M_asyncInfo(_AsyncInfo) {} - }; +public: + virtual void Cancel() { _M_asyncInfo.Get()->Cancel(); } + virtual void Close() { _M_asyncInfo.Get()->Close(); } -#if defined (__cplusplus_winrt) - /// - /// Base converter class for converting asynchronous interfaces to IAsyncOperation - /// - template - ref struct _AsyncInfoImpl abstract : Windows::Foundation::IAsyncOperation<_Result> + virtual property Windows::Foundation::HResult ErrorCode { - internal: - // The async action, action with progress or operation with progress that this stub forwards to. - ::Platform::Agile<_AsyncOperationType> _M_asyncInfo; - - Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ _M_CompletedHandler; - - _AsyncInfoImpl( _AsyncOperationType _AsyncInfo ) : _M_asyncInfo(_AsyncInfo) {} - - public: - virtual void Cancel() { _M_asyncInfo.Get()->Cancel(); } - virtual void Close() { _M_asyncInfo.Get()->Close(); } + Windows::Foundation::HResult get() { return _M_asyncInfo.Get()->ErrorCode; } + } - virtual property Windows::Foundation::HResult ErrorCode - { - Windows::Foundation::HResult get() - { - return _M_asyncInfo.Get()->ErrorCode; - } - } + virtual property UINT Id + { + UINT get() { return _M_asyncInfo.Get()->Id; } + } - virtual property UINT Id - { - UINT get() - { - return _M_asyncInfo.Get()->Id; - } - } + virtual property Windows::Foundation::AsyncStatus Status + { + Windows::Foundation::AsyncStatus get() { return _M_asyncInfo.Get()->Status; } + } - virtual property Windows::Foundation::AsyncStatus Status - { - Windows::Foundation::AsyncStatus get() - { - return _M_asyncInfo.Get()->Status; - } - } + virtual _Result GetResults() { throw std::runtime_error("derived class must implement"); } - virtual _Result GetResults() { throw std::runtime_error("derived class must implement"); } + virtual property Windows::Foundation::AsyncOperationCompletedHandler<_Result> ^ Completed { + Windows::Foundation::AsyncOperationCompletedHandler<_Result> ^ get() { return _M_CompletedHandler; } - virtual property Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ Completed + void set(Windows::Foundation::AsyncOperationCompletedHandler<_Result> ^ value) { - Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ get() - { - return _M_CompletedHandler; - } - - void set(Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ value) - { - _M_CompletedHandler = value; - _M_asyncInfo.Get()->Completed = ref new _CompletionHandlerType([&](_AsyncOperationType, Windows::Foundation::AsyncStatus status) { + _M_CompletedHandler = value; + _M_asyncInfo.Get()->Completed = + ref new _CompletionHandlerType([&](_AsyncOperationType, Windows::Foundation::AsyncStatus status) { _M_CompletedHandler->Invoke(this, status); }); - } } - }; + } +}; - /// - /// Class _IAsyncOperationWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress into IAsyncOperation - /// - template - ref struct _IAsyncOperationWithProgressToAsyncOperationConverter sealed : - _AsyncInfoImpl^, - Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>, - _Result> - { - internal: - _IAsyncOperationWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^ _Operation) : - _AsyncInfoImpl^, - Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>, - _Result>(_Operation) {} - - public: - virtual _Result GetResults() override { return _M_asyncInfo.Get()->GetResults(); } - }; +/// +/// Class _IAsyncOperationWithProgressToAsyncOperationConverter is used to convert an instance of +/// IAsyncOperationWithProgress into IAsyncOperation +/// +template +ref struct _IAsyncOperationWithProgressToAsyncOperationConverter sealed + : _AsyncInfoImpl ^ + , Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result, _Progress>, _Result> +{ + internal : _IAsyncOperationWithProgressToAsyncOperationConverter( + Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress> ^ _Operation) + : _AsyncInfoImpl ^, + Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result, _Progress>, + _Result>(_Operation) + { + } - /// - /// Class _IAsyncActionToAsyncOperationConverter is used to convert an instance of IAsyncAction into IAsyncOperation<_Unit_type> - /// - ref struct _IAsyncActionToAsyncOperationConverter sealed : - _AsyncInfoImpl +public: + virtual _Result GetResults() override { return _M_asyncInfo.Get()->GetResults(); } +}; + +/// +/// Class _IAsyncActionToAsyncOperationConverter is used to convert an instance of IAsyncAction into +/// IAsyncOperation<_Unit_type> +/// +ref struct _IAsyncActionToAsyncOperationConverter sealed + : _AsyncInfoImpl +{ + internal : _IAsyncActionToAsyncOperationConverter(Windows::Foundation::IAsyncAction ^ _Operation) + : _AsyncInfoImpl(_Operation) { - internal: - _IAsyncActionToAsyncOperationConverter(Windows::Foundation::IAsyncAction^ _Operation) : - _AsyncInfoImpl(_Operation) {} + } - public: - virtual details::_Unit_type GetResults() override - { - // Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a dummy value. - _M_asyncInfo.Get()->GetResults(); - return details::_Unit_type(); - } - }; +public: + virtual details::_Unit_type GetResults() override + { + // Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a + // dummy value. + _M_asyncInfo.Get()->GetResults(); + return details::_Unit_type(); + } +}; - /// - /// Class _IAsyncActionWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncActionWithProgress into IAsyncOperation<_Unit_type> - /// - template - ref struct _IAsyncActionWithProgressToAsyncOperationConverter sealed : - _AsyncInfoImpl^, - Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>, - details::_Unit_type> - { - internal: - _IAsyncActionWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ _Action) : - _AsyncInfoImpl^, - Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>, - details::_Unit_type>(_Action) {} - public: - virtual details::_Unit_type GetResults() override - { - // Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy value. - _M_asyncInfo.Get()->GetResults(); - return details::_Unit_type(); - } - }; -#endif /* defined (__cplusplus_winrt) */ +/// +/// Class _IAsyncActionWithProgressToAsyncOperationConverter is used to convert an instance of +/// IAsyncActionWithProgress into IAsyncOperation<_Unit_type> +/// +template +ref struct _IAsyncActionWithProgressToAsyncOperationConverter sealed + : _AsyncInfoImpl ^ + , Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>, details::_Unit_type> +{ + internal + : _IAsyncActionWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncActionWithProgress<_Progress> ^ + _Action) + : _AsyncInfoImpl ^, + Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>, + details::_Unit_type>(_Action) + { + } + +public: + virtual details::_Unit_type GetResults() override + { + // Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy + // value. + _M_asyncInfo.Get()->GetResults(); + return details::_Unit_type(); + } +}; +#endif /* defined (__cplusplus_winrt) */ } // namespace details /// -/// The task_continuation_context class allows you to specify where you would like a continuation to be executed. -/// It is only useful to use this class from a Windows Store app. For non-Windows Store apps, the task continuation's -/// execution context is determined by the runtime, and not configurable. +/// The task_continuation_context class allows you to specify where you would like a continuation to be +/// executed. It is only useful to use this class from a Windows Store app. For non-Windows Store apps, the task +/// continuation's execution context is determined by the runtime, and not configurable. /// /// /**/ class task_continuation_context : public details::_ContextCallback { public: - /// /// Creates the default task continuation context. /// @@ -1147,39 +1129,42 @@ class task_continuation_context : public details::_ContextCallback /// The default continuation context. /// /// - /// The default context is used if you don't specify a continuation context when you call the then method. In Windows - /// applications for Windows 7 and below, as well as desktop applications on Windows 8 and higher, the runtime determines where - /// task continuations will execute. However, in a Windows Store app, the default continuation context for a continuation on an - /// apartment aware task is the apartment where then is invoked. - /// An apartment aware task is a task that unwraps a Windows Runtime IAsyncInfo interface, or a task that is descended from such - /// a task. Therefore, if you schedule a continuation on an apartment aware task in a Windows Runtime STA, the continuation will execute in - /// that STA. - /// A continuation on a non-apartment aware task will execute in a context the Runtime chooses. + /// The default context is used if you don't specify a continuation context when you call the then + /// method. In Windows applications for Windows 7 and below, as well as desktop applications on Windows 8 and + /// higher, the runtime determines where task continuations will execute. However, in a Windows Store app, the + /// default continuation context for a continuation on an apartment aware task is the apartment where + /// then is invoked. An apartment aware task is a task that unwraps a Windows Runtime + /// IAsyncInfo interface, or a task that is descended from such a task. Therefore, if you schedule a + /// continuation on an apartment aware task in a Windows Runtime STA, the continuation will execute in that + /// STA. A continuation on a non-apartment aware task will execute in a context the Runtime + /// chooses. /// /**/ static task_continuation_context use_default() { -#if defined (__cplusplus_winrt) - // The callback context is created with the context set to CaptureDeferred and resolved when it is used in .then() - return task_continuation_context(true); // sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle +#if defined(__cplusplus_winrt) + // The callback context is created with the context set to CaptureDeferred and resolved when it is used in + // .then() + return task_continuation_context( + true); // sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle #else /* defined (__cplusplus_winrt) */ return task_continuation_context(); -#endif /* defined (__cplusplus_winrt) */ +#endif /* defined (__cplusplus_winrt) */ } -#if defined (__cplusplus_winrt) +#if defined(__cplusplus_winrt) /// - /// Creates a task continuation context which allows the Runtime to choose the execution context for a continuation. + /// Creates a task continuation context which allows the Runtime to choose the execution context for a + /// continuation. /// /// /// A task continuation context that represents an arbitrary location. /// /// - /// When this continuation context is used the continuation will execute in a context the runtime chooses even if the antecedent task - /// is apartment aware. - /// use_arbitrary can be used to turn off the default behavior for a continuation on an apartment - /// aware task created in an STA. - /// This method is only available to Windows Store apps. + /// When this continuation context is used the continuation will execute in a context the runtime chooses even + /// if the antecedent task is apartment aware. use_arbitrary can be used to turn off the default + /// behavior for a continuation on an apartment aware task created in an STA. This method is only + /// available to Windows Store apps. /// /**/ static task_continuation_context use_arbitrary() @@ -1196,11 +1181,12 @@ class task_continuation_context : public details::_ContextCallback /// The current execution context. /// /// - /// This method captures the caller's Windows Runtime context so that continuations can be executed in the right apartment. - /// The value returned by use_current can be used to indicate to the Runtime that the continuation should execute in - /// the captured context (STA vs MTA) regardless of whether or not the antecedent task is apartment aware. An apartment aware task is - /// a task that unwraps a Windows Runtime IAsyncInfo interface, or a task that is descended from such a task. - /// This method is only available to Windows Store apps. + /// This method captures the caller's Windows Runtime context so that continuations can be executed in the right + /// apartment. The value returned by use_current can be used to indicate to the Runtime that the + /// continuation should execute in the captured context (STA vs MTA) regardless of whether or not the antecedent + /// task is apartment aware. An apartment aware task is a task that unwraps a Windows Runtime IAsyncInfo + /// interface, or a task that is descended from such a task. This method is only available to + /// Windows Store apps. /// /**/ static task_continuation_context use_current() @@ -1209,54 +1195,46 @@ class task_continuation_context : public details::_ContextCallback _Current._Resolve(true); return _Current; } -#endif /* defined (__cplusplus_winrt) */ +#endif /* defined (__cplusplus_winrt) */ private: - - task_continuation_context(bool _DeferCapture = false) : details::_ContextCallback(_DeferCapture) - { - } -}; + task_continuation_context(bool _DeferCapture = false) : details::_ContextCallback(_DeferCapture) {} +}; class task_options; namespace details { - struct _Internal_task_options - { - bool _M_hasPresetCreationCallstack; - _TaskCreationCallstack _M_presetCreationCallstack; +struct _Internal_task_options +{ + bool _M_hasPresetCreationCallstack; + _TaskCreationCallstack _M_presetCreationCallstack; - void _set_creation_callstack(const _TaskCreationCallstack &_callstack) - { - _M_hasPresetCreationCallstack = true; - _M_presetCreationCallstack = _callstack; - } - _Internal_task_options() - { - _M_hasPresetCreationCallstack = false; - } - }; + void _set_creation_callstack(const _TaskCreationCallstack& _callstack) + { + _M_hasPresetCreationCallstack = true; + _M_presetCreationCallstack = _callstack; + } + _Internal_task_options() { _M_hasPresetCreationCallstack = false; } +}; - inline _Internal_task_options &_get_internal_task_options(task_options &options); - inline const _Internal_task_options &_get_internal_task_options(const task_options &options); -} +inline _Internal_task_options& _get_internal_task_options(task_options& options); +inline const _Internal_task_options& _get_internal_task_options(const task_options& options); +} // namespace details /// /// Represents the allowed options for creating a task /// class task_options { public: - - /// /// Default list of task creation options /// task_options() - : _M_Scheduler(get_ambient_scheduler()), - _M_CancellationToken(cancellation_token::none()), - _M_ContinuationContext(task_continuation_context::use_default()), - _M_HasCancellationToken(false), - _M_HasScheduler(false) + : _M_Scheduler(get_ambient_scheduler()) + , _M_CancellationToken(cancellation_token::none()) + , _M_ContinuationContext(task_continuation_context::use_default()) + , _M_HasCancellationToken(false) + , _M_HasScheduler(false) { } @@ -1264,11 +1242,11 @@ class task_options /// Task option that specify a cancellation token /// task_options(cancellation_token _Token) - : _M_Scheduler(get_ambient_scheduler()), - _M_CancellationToken(_Token), - _M_ContinuationContext(task_continuation_context::use_default()), - _M_HasCancellationToken(true), - _M_HasScheduler(false) + : _M_Scheduler(get_ambient_scheduler()) + , _M_CancellationToken(_Token) + , _M_ContinuationContext(task_continuation_context::use_default()) + , _M_HasCancellationToken(true) + , _M_HasScheduler(false) { } @@ -1276,23 +1254,24 @@ class task_options /// Task option that specify a continuation context. This is valid only for continuations (then) /// task_options(task_continuation_context _ContinuationContext) - : _M_Scheduler(get_ambient_scheduler()), - _M_CancellationToken(cancellation_token::none()), - _M_ContinuationContext(_ContinuationContext), - _M_HasCancellationToken(false), - _M_HasScheduler(false) + : _M_Scheduler(get_ambient_scheduler()) + , _M_CancellationToken(cancellation_token::none()) + , _M_ContinuationContext(_ContinuationContext) + , _M_HasCancellationToken(false) + , _M_HasScheduler(false) { } /// - /// Task option that specify a cancellation token and a continuation context. This is valid only for continuations (then) + /// Task option that specify a cancellation token and a continuation context. This is valid only for + /// continuations (then) /// task_options(cancellation_token _Token, task_continuation_context _ContinuationContext) - : _M_Scheduler(get_ambient_scheduler()), - _M_CancellationToken(_Token), - _M_ContinuationContext(_ContinuationContext), - _M_HasCancellationToken(false), - _M_HasScheduler(false) + : _M_Scheduler(get_ambient_scheduler()) + , _M_CancellationToken(_Token) + , _M_ContinuationContext(_ContinuationContext) + , _M_HasCancellationToken(false) + , _M_HasScheduler(false) { } @@ -1301,11 +1280,11 @@ class task_options /// template task_options(std::shared_ptr<_SchedType> _Scheduler) - : _M_Scheduler(std::move(_Scheduler)), - _M_CancellationToken(cancellation_token::none()), - _M_ContinuationContext(task_continuation_context::use_default()), - _M_HasCancellationToken(false), - _M_HasScheduler(true) + : _M_Scheduler(std::move(_Scheduler)) + , _M_CancellationToken(cancellation_token::none()) + , _M_ContinuationContext(task_continuation_context::use_default()) + , _M_HasCancellationToken(false) + , _M_HasScheduler(true) { } @@ -1313,11 +1292,11 @@ class task_options /// Task option that specify a scheduler reference /// task_options(scheduler_interface& _Scheduler) - : _M_Scheduler(&_Scheduler), - _M_CancellationToken(cancellation_token::none()), - _M_ContinuationContext(task_continuation_context::use_default()), - _M_HasCancellationToken(false), - _M_HasScheduler(true) + : _M_Scheduler(&_Scheduler) + , _M_CancellationToken(cancellation_token::none()) + , _M_ContinuationContext(task_continuation_context::use_default()) + , _M_HasCancellationToken(false) + , _M_HasScheduler(true) { } @@ -1325,11 +1304,11 @@ class task_options /// Task option that specify a scheduler /// task_options(scheduler_ptr _Scheduler) - : _M_Scheduler(std::move(_Scheduler)), - _M_CancellationToken(cancellation_token::none()), - _M_ContinuationContext(task_continuation_context::use_default()), - _M_HasCancellationToken(false), - _M_HasScheduler(true) + : _M_Scheduler(std::move(_Scheduler)) + , _M_CancellationToken(cancellation_token::none()) + , _M_ContinuationContext(task_continuation_context::use_default()) + , _M_HasCancellationToken(false) + , _M_HasScheduler(true) { } @@ -1337,11 +1316,11 @@ class task_options /// Task option copy constructor /// task_options(const task_options& _TaskOptions) - : _M_Scheduler(_TaskOptions.get_scheduler()), - _M_CancellationToken(_TaskOptions.get_cancellation_token()), - _M_ContinuationContext(_TaskOptions.get_continuation_context()), - _M_HasCancellationToken(_TaskOptions.has_cancellation_token()), - _M_HasScheduler(_TaskOptions.has_scheduler()) + : _M_Scheduler(_TaskOptions.get_scheduler()) + , _M_CancellationToken(_TaskOptions.get_cancellation_token()) + , _M_ContinuationContext(_TaskOptions.get_continuation_context()) + , _M_HasCancellationToken(_TaskOptions.has_cancellation_token()) + , _M_HasScheduler(_TaskOptions.has_scheduler()) { } @@ -1351,7 +1330,7 @@ class task_options void set_cancellation_token(cancellation_token _Token) { _M_CancellationToken = _Token; - _M_HasCancellationToken = true; + _M_HasCancellationToken = true; } /// @@ -1365,48 +1344,32 @@ class task_options /// /// Indicates whether a cancellation token was specified by the user /// - bool has_cancellation_token() const - { - return _M_HasCancellationToken; - } + bool has_cancellation_token() const { return _M_HasCancellationToken; } /// /// Returns the cancellation token /// - cancellation_token get_cancellation_token() const - { - return _M_CancellationToken; - } + cancellation_token get_cancellation_token() const { return _M_CancellationToken; } /// /// Returns the continuation context /// - task_continuation_context get_continuation_context() const - { - return _M_ContinuationContext; - } + task_continuation_context get_continuation_context() const { return _M_ContinuationContext; } /// /// Indicates whether a scheduler n was specified by the user /// - bool has_scheduler() const - { - return _M_HasScheduler; - } + bool has_scheduler() const { return _M_HasScheduler; } /// /// Returns the scheduler /// - scheduler_ptr get_scheduler() const - { - return _M_Scheduler; - } + scheduler_ptr get_scheduler() const { return _M_Scheduler; } private: - task_options const& operator=(task_options const& _Right); - friend details::_Internal_task_options &details::_get_internal_task_options(task_options &); - friend const details::_Internal_task_options &details::_get_internal_task_options(const task_options &); + friend details::_Internal_task_options& details::_get_internal_task_options(task_options&); + friend const details::_Internal_task_options& details::_get_internal_task_options(const task_options&); scheduler_ptr _M_Scheduler; cancellation_token _M_CancellationToken; @@ -1418,664 +1381,677 @@ class task_options namespace details { - inline _Internal_task_options & _get_internal_task_options(task_options &options) - { - return options._M_InternalTaskOptions; - } - inline const _Internal_task_options & _get_internal_task_options(const task_options &options) - { - return options._M_InternalTaskOptions; - } +inline _Internal_task_options& _get_internal_task_options(task_options& options) +{ + return options._M_InternalTaskOptions; +} +inline const _Internal_task_options& _get_internal_task_options(const task_options& options) +{ + return options._M_InternalTaskOptions; +} - struct _Task_impl_base; - template struct _Task_impl; +struct _Task_impl_base; +template +struct _Task_impl; - template - struct _Task_ptr +template +struct _Task_ptr +{ + typedef std::shared_ptr<_Task_impl<_ReturnType>> _Type; + static _Type _Make(_CancellationTokenState* _Ct, scheduler_ptr _Scheduler_arg) { - typedef std::shared_ptr<_Task_impl<_ReturnType>> _Type; - static _Type _Make(_CancellationTokenState * _Ct, scheduler_ptr _Scheduler_arg) { return std::make_shared<_Task_impl<_ReturnType>>(_Ct, _Scheduler_arg); } - }; + return std::make_shared<_Task_impl<_ReturnType>>(_Ct, _Scheduler_arg); + } +}; - typedef _TaskCollection_t::_TaskProcHandle_t _UnrealizedChore_t; - typedef std::shared_ptr<_Task_impl_base> _Task_ptr_base; +typedef _TaskCollection_t::_TaskProcHandle_t _UnrealizedChore_t; +typedef std::shared_ptr<_Task_impl_base> _Task_ptr_base; - // The weak-typed base task handler for continuation tasks. - struct _ContinuationTaskHandleBase : _UnrealizedChore_t - { - _ContinuationTaskHandleBase * _M_next; - task_continuation_context _M_continuationContext; - bool _M_isTaskBasedContinuation; +// The weak-typed base task handler for continuation tasks. +struct _ContinuationTaskHandleBase : _UnrealizedChore_t +{ + _ContinuationTaskHandleBase* _M_next; + task_continuation_context _M_continuationContext; + bool _M_isTaskBasedContinuation; - // This field gives inlining scheduling policy for current chore. - _TaskInliningMode_t _M_inliningMode; + // This field gives inlining scheduling policy for current chore. + _TaskInliningMode_t _M_inliningMode; - virtual _Task_ptr_base _GetTaskImplBase() const = 0; + virtual _Task_ptr_base _GetTaskImplBase() const = 0; - _ContinuationTaskHandleBase() : - _M_next(nullptr), _M_continuationContext(task_continuation_context::use_default()), _M_isTaskBasedContinuation(false), _M_inliningMode(details::_NoInline) - { - } + _ContinuationTaskHandleBase() + : _M_next(nullptr) + , _M_continuationContext(task_continuation_context::use_default()) + , _M_isTaskBasedContinuation(false) + , _M_inliningMode(details::_NoInline) + { + } - virtual ~_ContinuationTaskHandleBase() {} - }; + virtual ~_ContinuationTaskHandleBase() {} +}; #if PPLX_TASK_ASYNC_LOGGING - // GUID used for identifying causality logs from PPLTask - const ::Platform::Guid _PPLTaskCausalityPlatformID(0x7A76B220, 0xA758, 0x4E6E, 0xB0, 0xE0, 0xD7, 0xC6, 0xD7, 0x4A, 0x88, 0xFE); +// GUID used for identifying causality logs from PPLTask +const ::Platform::Guid _PPLTaskCausalityPlatformID( + 0x7A76B220, 0xA758, 0x4E6E, 0xB0, 0xE0, 0xD7, 0xC6, 0xD7, 0x4A, 0x88, 0xFE); - __declspec(selectany) volatile long _isCausalitySupported = 0; +__declspec(selectany) volatile long _isCausalitySupported = 0; - inline bool _IsCausalitySupported() - { +inline bool _IsCausalitySupported() +{ #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - if (_isCausalitySupported == 0) - { - long _causality = 1; - OSVERSIONINFOEX _osvi = {}; - _osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - // The Causality is supported on Windows version higher than Windows 8 - _osvi.dwMajorVersion = 6; - _osvi.dwMinorVersion = 3; + if (_isCausalitySupported == 0) + { + long _causality = 1; + OSVERSIONINFOEX _osvi = {}; + _osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - DWORDLONG _conditionMask = 0; - VER_SET_CONDITION( _conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL ); - VER_SET_CONDITION( _conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL ); + // The Causality is supported on Windows version higher than Windows 8 + _osvi.dwMajorVersion = 6; + _osvi.dwMinorVersion = 3; - if ( ::VerifyVersionInfo(&_osvi, VER_MAJORVERSION | VER_MINORVERSION, _conditionMask)) - { - _causality = 2; - } + DWORDLONG _conditionMask = 0; + VER_SET_CONDITION(_conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(_conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); - _isCausalitySupported = _causality; - return _causality == 2; + if (::VerifyVersionInfo(&_osvi, VER_MAJORVERSION | VER_MINORVERSION, _conditionMask)) + { + _causality = 2; } - return _isCausalitySupported == 2 ? true : false; + _isCausalitySupported = _causality; + return _causality == 2; + } + + return _isCausalitySupported == 2 ? true : false; #else - return true; + return true; #endif - } +} - // Stateful logger rests inside task_impl_base. - struct _TaskEventLogger - { - _Task_impl_base *_M_task; - bool _M_scheduled; - bool _M_taskPostEventStarted; +// Stateful logger rests inside task_impl_base. +struct _TaskEventLogger +{ + _Task_impl_base* _M_task; + bool _M_scheduled; + bool _M_taskPostEventStarted; - // Log before scheduling task - void _LogScheduleTask(bool _isContinuation) + // Log before scheduling task + void _LogScheduleTask(bool _isContinuation) + { + if (details::_IsCausalitySupported()) { - if (details::_IsCausalitySupported()) - { - ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCreation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, - _PPLTaskCausalityPlatformID, reinterpret_cast(_M_task), - _isContinuation ? "pplx::PPLTask::ScheduleContinuationTask" : "pplx::PPLTask::ScheduleTask", 0); - _M_scheduled = true; - } + ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCreation( + ::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, + ::Windows::Foundation::Diagnostics::CausalitySource::Library, + _PPLTaskCausalityPlatformID, + reinterpret_cast(_M_task), + _isContinuation ? "pplx::PPLTask::ScheduleContinuationTask" : "pplx::PPLTask::ScheduleTask", + 0); + _M_scheduled = true; } + } - // It will log the cancel event but not canceled state. _LogTaskCompleted will log the terminal state, which includes cancel state. - void _LogCancelTask() + // It will log the cancel event but not canceled state. _LogTaskCompleted will log the terminal state, which + // includes cancel state. + void _LogCancelTask() + { + if (details::_IsCausalitySupported()) { - if (details::_IsCausalitySupported()) - { - ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationRelation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Important, ::Windows::Foundation::Diagnostics::CausalitySource::Library, - _PPLTaskCausalityPlatformID, reinterpret_cast(_M_task), ::Windows::Foundation::Diagnostics::CausalityRelation::Cancel); - - } + ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationRelation( + ::Windows::Foundation::Diagnostics::CausalityTraceLevel::Important, + ::Windows::Foundation::Diagnostics::CausalitySource::Library, + _PPLTaskCausalityPlatformID, + reinterpret_cast(_M_task), + ::Windows::Foundation::Diagnostics::CausalityRelation::Cancel); } + } - // Log when task reaches terminal state. Note: the task can reach a terminal state (by cancellation or exception) without having run - void _LogTaskCompleted(); + // Log when task reaches terminal state. Note: the task can reach a terminal state (by cancellation or exception) + // without having run + void _LogTaskCompleted(); - // Log when task body (which includes user lambda and other scheduling code) begin to run - void _LogTaskExecutionStarted() { } + // Log when task body (which includes user lambda and other scheduling code) begin to run + void _LogTaskExecutionStarted() {} - // Log when task body finish executing - void _LogTaskExecutionCompleted() + // Log when task body finish executing + void _LogTaskExecutionCompleted() + { + if (_M_taskPostEventStarted && details::_IsCausalitySupported()) { - if (_M_taskPostEventStarted && details::_IsCausalitySupported()) - { - ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, - ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification); - } + ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion( + ::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, + ::Windows::Foundation::Diagnostics::CausalitySource::Library, + ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification); } + } - // Log right before user lambda being invoked - void _LogWorkItemStarted() + // Log right before user lambda being invoked + void _LogWorkItemStarted() + { + if (details::_IsCausalitySupported()) { - if (details::_IsCausalitySupported()) - { - ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, - _PPLTaskCausalityPlatformID, reinterpret_cast(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution); - } + ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart( + ::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, + ::Windows::Foundation::Diagnostics::CausalitySource::Library, + _PPLTaskCausalityPlatformID, + reinterpret_cast(_M_task), + ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution); } + } - // Log right after user lambda being invoked - void _LogWorkItemCompleted() + // Log right after user lambda being invoked + void _LogWorkItemCompleted() + { + if (details::_IsCausalitySupported()) { - if (details::_IsCausalitySupported()) - { - ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, - ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution); + ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion( + ::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, + ::Windows::Foundation::Diagnostics::CausalitySource::Library, + ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution); - ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, - _PPLTaskCausalityPlatformID, reinterpret_cast(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification); - _M_taskPostEventStarted = true; - } + ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart( + ::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, + ::Windows::Foundation::Diagnostics::CausalitySource::Library, + _PPLTaskCausalityPlatformID, + reinterpret_cast(_M_task), + ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification); + _M_taskPostEventStarted = true; } + } - _TaskEventLogger(_Task_impl_base *_task): _M_task(_task) - { - _M_scheduled = false; - _M_taskPostEventStarted = false; - } - }; + _TaskEventLogger(_Task_impl_base* _task) : _M_task(_task) + { + _M_scheduled = false; + _M_taskPostEventStarted = false; + } +}; - // Exception safe logger for user lambda - struct _TaskWorkItemRAIILogger +// Exception safe logger for user lambda +struct _TaskWorkItemRAIILogger +{ + _TaskEventLogger& _M_logger; + _TaskWorkItemRAIILogger(_TaskEventLogger& _taskHandleLogger) : _M_logger(_taskHandleLogger) { - _TaskEventLogger &_M_logger; - _TaskWorkItemRAIILogger(_TaskEventLogger &_taskHandleLogger): _M_logger(_taskHandleLogger) - { - _M_logger._LogWorkItemStarted(); - } + _M_logger._LogWorkItemStarted(); + } - ~_TaskWorkItemRAIILogger() - { - _M_logger._LogWorkItemCompleted(); - } - _TaskWorkItemRAIILogger &operator =(const _TaskWorkItemRAIILogger &); // cannot be assigned - }; + ~_TaskWorkItemRAIILogger() { _M_logger._LogWorkItemCompleted(); } + _TaskWorkItemRAIILogger& operator=(const _TaskWorkItemRAIILogger&); // cannot be assigned +}; #else - inline void _LogCancelTask(_Task_impl_base *) {} - struct _TaskEventLogger - { - void _LogScheduleTask(bool) {} - void _LogCancelTask() {} - void _LogWorkItemStarted() {} - void _LogWorkItemCompleted() {} - void _LogTaskExecutionStarted() {} - void _LogTaskExecutionCompleted() {} - void _LogTaskCompleted() {} - _TaskEventLogger(_Task_impl_base *) {} - }; - struct _TaskWorkItemRAIILogger - { - _TaskWorkItemRAIILogger(_TaskEventLogger &) {} - }; +inline void _LogCancelTask(_Task_impl_base*) {} +struct _TaskEventLogger +{ + void _LogScheduleTask(bool) {} + void _LogCancelTask() {} + void _LogWorkItemStarted() {} + void _LogWorkItemCompleted() {} + void _LogTaskExecutionStarted() {} + void _LogTaskExecutionCompleted() {} + void _LogTaskCompleted() {} + _TaskEventLogger(_Task_impl_base*) {} +}; +struct _TaskWorkItemRAIILogger +{ + _TaskWorkItemRAIILogger(_TaskEventLogger&) {} +}; #endif - /// - /// The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped in this task handler - /// to be executable by PPL. By deriving from a different _BaseTaskHandle, it can be used for both initial tasks and continuation tasks. - /// For initial tasks, _PPLTaskHandle will be derived from _UnrealizedChore_t, and for continuation tasks, it will be derived from - /// _ContinuationTaskHandleBase. The life time of the _PPLTaskHandle object is be managed by runtime if task handle is scheduled. - /// - /// - /// The result type of the _Task_impl. - /// - /// - /// The derived task handle class. The operator () needs to be implemented. - /// - /// - /// The base class from which _PPLTaskHandle should be derived. This is either _UnrealizedChore_t or _ContinuationTaskHandleBase. - /// - template - struct _PPLTaskHandle : _BaseTaskHandle +/// +/// The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped in this task +/// handler to be executable by PPL. By deriving from a different _BaseTaskHandle, it can be used for both initial +/// tasks and continuation tasks. For initial tasks, _PPLTaskHandle will be derived from _UnrealizedChore_t, and for +/// continuation tasks, it will be derived from _ContinuationTaskHandleBase. The life time of the _PPLTaskHandle +/// object is be managed by runtime if task handle is scheduled. +/// +/// +/// The result type of the _Task_impl. +/// +/// +/// The derived task handle class. The operator () needs to be implemented. +/// +/// +/// The base class from which _PPLTaskHandle should be derived. This is either _UnrealizedChore_t or +/// _ContinuationTaskHandleBase. +/// +template +struct _PPLTaskHandle : _BaseTaskHandle +{ + _PPLTaskHandle(const typename _Task_ptr<_ReturnType>::_Type& _PTask) : _M_pTask(_PTask) {} + + virtual ~_PPLTaskHandle() + { + // Here is the sink of all task completion code paths + _M_pTask->_M_taskEventLogger._LogTaskCompleted(); + } + + virtual void invoke() const { - _PPLTaskHandle(const typename _Task_ptr<_ReturnType>::_Type & _PTask) : _M_pTask(_PTask) + // All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled + // by the runtime. + _ASSERTE((bool)_M_pTask); + if (!_M_pTask->_TransitionedToStarted()) { + static_cast(this)->_SyncCancelAndPropagateException(); + return; } - virtual ~_PPLTaskHandle() + _M_pTask->_M_taskEventLogger._LogTaskExecutionStarted(); + try { - // Here is the sink of all task completion code paths - _M_pTask->_M_taskEventLogger._LogTaskCompleted(); + // All derived task handle must implement this contract function. + static_cast(this)->_Perform(); } - - virtual void invoke() const + catch (const task_canceled&) { - // All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled - // by the runtime. - _ASSERTE((bool)_M_pTask); - if (!_M_pTask->_TransitionedToStarted()) - { - static_cast(this)->_SyncCancelAndPropagateException(); - return; - } - - _M_pTask->_M_taskEventLogger._LogTaskExecutionStarted(); - try - { - // All derived task handle must implement this contract function. - static_cast(this)->_Perform(); - } - catch(const task_canceled &) - { - _M_pTask->_Cancel(true); - } - catch(const _Interruption_exception &) - { - _M_pTask->_Cancel(true); - } -#if defined (__cplusplus_winrt) - catch(::Platform::Exception^ _E) - { - _M_pTask->_CancelWithException(_E); - } -#endif /* defined (__cplusplus_winrt) */ - catch(...) - { - _M_pTask->_CancelWithException(std::current_exception()); - } - _M_pTask->_M_taskEventLogger._LogTaskExecutionCompleted(); + _M_pTask->_Cancel(true); } - - // Cast _M_pTask pointer to "type-less" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase. - // The return value should be automatically optimized by R-value ref. - _Task_ptr_base _GetTaskImplBase() const + catch (const _Interruption_exception&) + { + _M_pTask->_Cancel(true); + } +#if defined(__cplusplus_winrt) + catch (::Platform::Exception ^ _E) { - return _M_pTask; + _M_pTask->_CancelWithException(_E); } +#endif /* defined (__cplusplus_winrt) */ + catch (...) + { + _M_pTask->_CancelWithException(std::current_exception()); + } + _M_pTask->_M_taskEventLogger._LogTaskExecutionCompleted(); + } - typename _Task_ptr<_ReturnType>::_Type _M_pTask; - private: - _PPLTaskHandle const & operator=(_PPLTaskHandle const&); // no assignment operator - }; + // Cast _M_pTask pointer to "type-less" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase. + // The return value should be automatically optimized by R-value ref. + _Task_ptr_base _GetTaskImplBase() const { return _M_pTask; } - /// - /// The base implementation of a first-class task. This class contains all the non-type specific - /// implementation details of the task. - /// - /**/ - struct _Task_impl_base - { - enum _TaskInternalState - { - // Tracks the state of the task, rather than the task collection on which the task is scheduled - _Created, - _Started, - _PendingCancel, - _Completed, - _Canceled - }; + typename _Task_ptr<_ReturnType>::_Type _M_pTask; + +private: + _PPLTaskHandle const& operator=(_PPLTaskHandle const&); // no assignment operator +}; + +/// +/// The base implementation of a first-class task. This class contains all the non-type specific +/// implementation details of the task. +/// +/**/ +struct _Task_impl_base +{ + enum _TaskInternalState + { + // Tracks the state of the task, rather than the task collection on which the task is scheduled + _Created, + _Started, + _PendingCancel, + _Completed, + _Canceled + }; // _M_taskEventLogger - 'this' : used in base member initializer list #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable: 4355) +#pragma warning(disable : 4355) #endif - _Task_impl_base(_CancellationTokenState * _PTokenState, scheduler_ptr _Scheduler_arg) - : _M_TaskState(_Created), - _M_fFromAsync(false), _M_fUnwrappedTask(false), - _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_TaskCollection(_Scheduler_arg), - _M_taskEventLogger(this) - { - // Set cancellation token - _M_pTokenState = _PTokenState; - _ASSERTE(_M_pTokenState != nullptr); - if (_M_pTokenState != _CancellationTokenState::_None()) - _M_pTokenState->_Reference(); - } + _Task_impl_base(_CancellationTokenState* _PTokenState, scheduler_ptr _Scheduler_arg) + : _M_TaskState(_Created) + , _M_fFromAsync(false) + , _M_fUnwrappedTask(false) + , _M_pRegistration(nullptr) + , _M_Continuations(nullptr) + , _M_TaskCollection(_Scheduler_arg) + , _M_taskEventLogger(this) + { + // Set cancellation token + _M_pTokenState = _PTokenState; + _ASSERTE(_M_pTokenState != nullptr); + if (_M_pTokenState != _CancellationTokenState::_None()) _M_pTokenState->_Reference(); + } #if defined(_MSC_VER) #pragma warning(pop) #endif - virtual ~_Task_impl_base() + virtual ~_Task_impl_base() + { + _ASSERTE(_M_pTokenState != nullptr); + if (_M_pTokenState != _CancellationTokenState::_None()) + { + _M_pTokenState->_Release(); + } + } + + task_status _Wait() + { + bool _DoWait = true; + +#if defined(__cplusplus_winrt) + if (_IsNonBlockingThread()) { - _ASSERTE(_M_pTokenState != nullptr); - if (_M_pTokenState != _CancellationTokenState::_None()) + // In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is + // illegal if task has not been completed. + if (!_IsCompleted() && !_IsCanceled()) + { + throw invalid_operation("Illegal to wait on a task in a Windows Runtime STA"); + } + else { - _M_pTokenState->_Release(); + // Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task + // group. If a continuation needs to be marshaled to a different apartment, instead of scheduling, we + // make a synchronous cross apartment COM call to execute the continuation. If it then happens to do + // something which waits on the ancestor (say it calls .get(), which task based continuations are wont + // to do), waiting on the task group results in on the chore that is making this synchronous callback, + // which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on + // if it has finished execution (which means now we are on the inline synchronous callback). + _DoWait = false; } } - - task_status _Wait() +#endif /* defined (__cplusplus_winrt) */ + if (_DoWait) { - bool _DoWait = true; - -#if defined (__cplusplus_winrt) - if (_IsNonBlockingThread()) + // If this task was created from a Windows Runtime async operation, do not attempt to inline it. The + // async operation will take place on a thread in the appropriate apartment Simply wait for the completed + // event to be set. + if (_M_fFromAsync) + { + _M_TaskCollection._Wait(); + } + else { - // In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is illegal - // if task has not been completed. - if (!_IsCompleted() && !_IsCanceled()) + // Wait on the task collection to complete. The task collection is guaranteed to still be + // valid since the task must be still within scope so that the _Task_impl_base destructor + // has not yet been called. This call to _Wait potentially inlines execution of work. + try { - throw invalid_operation("Illegal to wait on a task in a Windows Runtime STA"); + // Invoking wait on a task collection resets the state of the task collection. This means that + // if the task collection itself were canceled, or had encountered an exception, only the first + // call to wait will receive this status. However, both cancellation and exceptions flowing through + // tasks set state in the task impl itself. + + // When it returns canceled, either work chore or the cancel thread should already have set task's + // state properly -- canceled state or completed state (because there was no interruption point). + // For tasks with unwrapped tasks, we should not change the state of current task, since the + // unwrapped task are still running. + _M_TaskCollection._RunAndWait(); } - else + catch (details::_Interruption_exception&) { - // Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task group. If a continuation - // needs to be marshaled to a different apartment, instead of scheduling, we make a synchronous cross apartment COM - // call to execute the continuation. If it then happens to do something which waits on the ancestor (say it calls .get(), which - // task based continuations are wont to do), waiting on the task group results in on the chore that is making this - // synchronous callback, which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on - // if it has finished execution (which means now we are on the inline synchronous callback). - _DoWait = false; + // The _TaskCollection will never be an interruption point since it has a none token. + _ASSERTE(false); } - } -#endif /* defined (__cplusplus_winrt) */ - if (_DoWait) - { - // If this task was created from a Windows Runtime async operation, do not attempt to inline it. The - // async operation will take place on a thread in the appropriate apartment Simply wait for the completed - // event to be set. - if (_M_fFromAsync) + catch (task_canceled&) { - _M_TaskCollection._Wait(); + // task_canceled is a special exception thrown by cancel_current_task. The spec states that + // cancel_current_task must be called from code that is executed within the task (throwing it from + // parallel work created by and waited upon by the task is acceptable). We can safely assume that + // the task wrapper _PPLTaskHandle::operator() has seen the exception and canceled the task. Swallow + // the exception here. + _ASSERTE(_IsCanceled()); } - else +#if defined(__cplusplus_winrt) + catch (::Platform::Exception ^ _E) { - // Wait on the task collection to complete. The task collection is guaranteed to still be - // valid since the task must be still within scope so that the _Task_impl_base destructor - // has not yet been called. This call to _Wait potentially inlines execution of work. - try - { - // Invoking wait on a task collection resets the state of the task collection. This means that - // if the task collection itself were canceled, or had encountered an exception, only the first - // call to wait will receive this status. However, both cancellation and exceptions flowing through - // tasks set state in the task impl itself. - - // When it returns canceled, either work chore or the cancel thread should already have set task's state - // properly -- canceled state or completed state (because there was no interruption point). - // For tasks with unwrapped tasks, we should not change the state of current task, since the unwrapped task are still running. - _M_TaskCollection._RunAndWait(); - } - catch(details::_Interruption_exception&) - { - // The _TaskCollection will never be an interruption point since it has a none token. - _ASSERTE(false); - } - catch(task_canceled&) - { - // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task - // must be called from code that is executed within the task (throwing it from parallel work created by and waited - // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen - // the exception and canceled the task. Swallow the exception here. - _ASSERTE(_IsCanceled()); - } -#if defined (__cplusplus_winrt) - catch(::Platform::Exception^ _E) - { - // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here. - if(!_HasUserException()) - { - _CancelWithException(_E); - } - // Rethrow will mark the exception as observed. - _M_exceptionHolder->_RethrowUserException(); - } -#endif /* defined (__cplusplus_winrt) */ - catch(...) + // Its possible the task body hasn't seen the exception, if so we need to cancel with exception + // here. + if (!_HasUserException()) { - // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here. - if(!_HasUserException()) - { - _CancelWithException(std::current_exception()); - } - // Rethrow will mark the exception as observed. - _M_exceptionHolder->_RethrowUserException(); + _CancelWithException(_E); } - - // If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a task - // which is to be unwrapped and plumbed to the output of this task, we must not only wait on the lambda body, we must - // wait on the **INNER** body. It is in theory possible that we could inline such if we plumb a series of things through; - // however, this takes the tact of simply waiting upon the completion signal. - if (_M_fUnwrappedTask) + // Rethrow will mark the exception as observed. + _M_exceptionHolder->_RethrowUserException(); + } +#endif /* defined (__cplusplus_winrt) */ + catch (...) + { + // Its possible the task body hasn't seen the exception, if so we need to cancel with exception + // here. + if (!_HasUserException()) { - _M_TaskCollection._Wait(); + _CancelWithException(std::current_exception()); } + // Rethrow will mark the exception as observed. + _M_exceptionHolder->_RethrowUserException(); } - } - if (_HasUserException()) - { - _M_exceptionHolder->_RethrowUserException(); - } - else if (_IsCanceled()) - { - return canceled; + // If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a + // task which is to be unwrapped and plumbed to the output of this task, we must not only wait on the + // lambda body, we must wait on the **INNER** body. It is in theory possible that we could inline such + // if we plumb a series of things through; however, this takes the tact of simply waiting upon the + // completion signal. + if (_M_fUnwrappedTask) + { + _M_TaskCollection._Wait(); + } } - _ASSERTE(_IsCompleted()); - return completed; } - /// - /// Requests cancellation on the task and schedules continuations if the task can be transitioned to a terminal state. - /// - /// - /// Set to true if the cancel takes place as a result of the task body encountering an exception, or because an ancestor or task_completion_event the task - /// was registered with were canceled with an exception. A synchronous cancel is one that assures the task could not be running on a different thread at - /// the time the cancellation is in progress. An asynchronous cancel is one where the thread performing the cancel has no control over the thread that could - /// be executing the task, that is the task could execute concurrently while the cancellation is in progress. - /// - /// - /// Whether an exception other than the internal runtime cancellation exceptions caused this cancellation. - /// - /// - /// Whether this exception came from an ancestor task or a task_completion_event as opposed to an exception that was encountered by the task itself. Only valid when - /// _UserException is set to true. - /// - /// - /// The exception holder that represents the exception. Only valid when _UserException is set to true. - /// - virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder>& _ExHolder) = 0; - - bool _Cancel(bool _SynchronousCancel) + if (_HasUserException()) { - // Send in a dummy value for exception. It is not used when the first parameter is false. - return _CancelAndRunContinuations(_SynchronousCancel, false, false, _M_exceptionHolder); + _M_exceptionHolder->_RethrowUserException(); } - - bool _CancelWithExceptionHolder(const std::shared_ptr<_ExceptionHolder>& _ExHolder, bool _PropagatedFromAncestor) + else if (_IsCanceled()) { - // This task was canceled because an ancestor task encountered an exception. - return _CancelAndRunContinuations(true, true, _PropagatedFromAncestor, _ExHolder); + return canceled; } + _ASSERTE(_IsCompleted()); + return completed; + } -#if defined (__cplusplus_winrt) - bool _CancelWithException(::Platform::Exception^ _Exception) - { - // This task was canceled because the task body encountered an exception. - _ASSERTE(!_HasUserException()); - return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack())); - } -#endif /* defined (__cplusplus_winrt) */ + /// + /// Requests cancellation on the task and schedules continuations if the task can be transitioned to a terminal + /// state. + /// + /// + /// Set to true if the cancel takes place as a result of the task body encountering an exception, or because an + /// ancestor or task_completion_event the task was registered with were canceled with an exception. A + /// synchronous cancel is one that assures the task could not be running on a different thread at the time the + /// cancellation is in progress. An asynchronous cancel is one where the thread performing the cancel has no + /// control over the thread that could be executing the task, that is the task could execute concurrently while + /// the cancellation is in progress. + /// + /// + /// Whether an exception other than the internal runtime cancellation exceptions caused this cancellation. + /// + /// + /// Whether this exception came from an ancestor task or a task_completion_event as opposed to an exception that + /// was encountered by the task itself. Only valid when _UserException is set to true. + /// + /// + /// The exception holder that represents the exception. Only valid when _UserException is set to true. + /// + virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, + bool _UserException, + bool _PropagatedFromAncestor, + const std::shared_ptr<_ExceptionHolder>& _ExHolder) = 0; - bool _CancelWithException(const std::exception_ptr& _Exception) - { - // This task was canceled because the task body encountered an exception. - _ASSERTE(!_HasUserException()); - return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack())); - } + bool _Cancel(bool _SynchronousCancel) + { + // Send in a dummy value for exception. It is not used when the first parameter is false. + return _CancelAndRunContinuations(_SynchronousCancel, false, false, _M_exceptionHolder); + } - void _RegisterCancellation(std::weak_ptr<_Task_impl_base> _WeakPtr) - { - _ASSERTE(details::_CancellationTokenState::_IsValid(_M_pTokenState)); + bool _CancelWithExceptionHolder(const std::shared_ptr<_ExceptionHolder>& _ExHolder, bool _PropagatedFromAncestor) + { + // This task was canceled because an ancestor task encountered an exception. + return _CancelAndRunContinuations(true, true, _PropagatedFromAncestor, _ExHolder); + } - auto _CancellationCallback = [_WeakPtr](){ - // Taking ownership of the task prevents dead lock during destruction - // if the destructor waits for the cancellations to be finished - auto _task = _WeakPtr.lock(); - if (_task != nullptr) - _task->_Cancel(false); - }; +#if defined(__cplusplus_winrt) + bool _CancelWithException(::Platform::Exception ^ _Exception) + { + // This task was canceled because the task body encountered an exception. + _ASSERTE(!_HasUserException()); + return _CancelAndRunContinuations( + true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack())); + } +#endif /* defined (__cplusplus_winrt) */ - _M_pRegistration = new details::_CancellationTokenCallback(_CancellationCallback); - _M_pTokenState->_RegisterCallback(_M_pRegistration); - } + bool _CancelWithException(const std::exception_ptr& _Exception) + { + // This task was canceled because the task body encountered an exception. + _ASSERTE(!_HasUserException()); + return _CancelAndRunContinuations( + true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack())); + } - void _DeregisterCancellation() - { - if (_M_pRegistration != nullptr) - { - _M_pTokenState->_DeregisterCallback(_M_pRegistration); - _M_pRegistration->_Release(); - _M_pRegistration = nullptr; - } - } + void _RegisterCancellation(std::weak_ptr<_Task_impl_base> _WeakPtr) + { + _ASSERTE(details::_CancellationTokenState::_IsValid(_M_pTokenState)); - bool _IsCreated() - { - return (_M_TaskState == _Created); - } + auto _CancellationCallback = [_WeakPtr]() { + // Taking ownership of the task prevents dead lock during destruction + // if the destructor waits for the cancellations to be finished + auto _task = _WeakPtr.lock(); + if (_task != nullptr) _task->_Cancel(false); + }; - bool _IsStarted() - { - return (_M_TaskState == _Started); - } + _M_pRegistration = + new details::_CancellationTokenCallback(_CancellationCallback); + _M_pTokenState->_RegisterCallback(_M_pRegistration); + } - bool _IsPendingCancel() + void _DeregisterCancellation() + { + if (_M_pRegistration != nullptr) { - return (_M_TaskState == _PendingCancel); + _M_pTokenState->_DeregisterCallback(_M_pRegistration); + _M_pRegistration->_Release(); + _M_pRegistration = nullptr; } + } - bool _IsCompleted() - { - return (_M_TaskState == _Completed); - } + bool _IsCreated() { return (_M_TaskState == _Created); } - bool _IsCanceled() - { - return (_M_TaskState == _Canceled); - } + bool _IsStarted() { return (_M_TaskState == _Started); } - bool _HasUserException() - { - return static_cast(_M_exceptionHolder); - } + bool _IsPendingCancel() { return (_M_TaskState == _PendingCancel); } - const std::shared_ptr<_ExceptionHolder>& _GetExceptionHolder() - { - _ASSERTE(_HasUserException()); - return _M_exceptionHolder; - } + bool _IsCompleted() { return (_M_TaskState == _Completed); } - bool _IsApartmentAware() - { - return _M_fFromAsync; - } + bool _IsCanceled() { return (_M_TaskState == _Canceled); } + + bool _HasUserException() { return static_cast(_M_exceptionHolder); } + + const std::shared_ptr<_ExceptionHolder>& _GetExceptionHolder() + { + _ASSERTE(_HasUserException()); + return _M_exceptionHolder; + } + + bool _IsApartmentAware() { return _M_fFromAsync; } + + void _SetAsync(bool _Async = true) { _M_fFromAsync = _Async; } + + _TaskCreationCallstack _GetTaskCreationCallstack() { return _M_pTaskCreationCallstack; } - void _SetAsync(bool _Async = true) + void _SetTaskCreationCallstack(const _TaskCreationCallstack& _Callstack) { _M_pTaskCreationCallstack = _Callstack; } + + /// + /// Helper function to schedule the task on the Task Collection. + /// + /// + /// The task chore handle that need to be executed. + /// + /// + /// The inlining scheduling policy for current _PTaskHandle. + /// + void _ScheduleTask(_UnrealizedChore_t* _PTaskHandle, _TaskInliningMode_t _InliningMode) + { + try { - _M_fFromAsync = _Async; + _M_TaskCollection._ScheduleTask(_PTaskHandle, _InliningMode); } - - _TaskCreationCallstack _GetTaskCreationCallstack() + catch (const task_canceled&) { - return _M_pTaskCreationCallstack; + // task_canceled is a special exception thrown by cancel_current_task. The spec states that + // cancel_current_task must be called from code that is executed within the task (throwing it from parallel + // work created by and waited upon by the task is acceptable). We can safely assume that the task wrapper + // _PPLTaskHandle::operator() has seen the exception and canceled the task. Swallow the exception here. + _ASSERTE(_IsCanceled()); } - - void _SetTaskCreationCallstack(const _TaskCreationCallstack &_Callstack) + catch (const _Interruption_exception&) { - _M_pTaskCreationCallstack = _Callstack; + // The _TaskCollection will never be an interruption point since it has a none token. + _ASSERTE(false); } - - /// - /// Helper function to schedule the task on the Task Collection. - /// - /// - /// The task chore handle that need to be executed. - /// - /// - /// The inlining scheduling policy for current _PTaskHandle. - /// - void _ScheduleTask(_UnrealizedChore_t * _PTaskHandle, _TaskInliningMode_t _InliningMode) + catch (...) { - try - { - _M_TaskCollection._ScheduleTask(_PTaskHandle, _InliningMode); - } - catch(const task_canceled &) - { - // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task - // must be called from code that is executed within the task (throwing it from parallel work created by and waited - // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen - // the exception and canceled the task. Swallow the exception here. - _ASSERTE(_IsCanceled()); - } - catch(const _Interruption_exception &) - { - // The _TaskCollection will never be an interruption point since it has a none token. - _ASSERTE(false); - } - catch(...) + // The exception could have come from two places: + // 1. From the chore body, so it already should have been caught and canceled. + // In this case swallow the exception. + // 2. From trying to actually schedule the task on the scheduler. + // In this case cancel the task with the current exception, otherwise the + // task will never be signaled leading to deadlock when waiting on the task. + if (!_HasUserException()) { - // The exception could have come from two places: - // 1. From the chore body, so it already should have been caught and canceled. - // In this case swallow the exception. - // 2. From trying to actually schedule the task on the scheduler. - // In this case cancel the task with the current exception, otherwise the - // task will never be signaled leading to deadlock when waiting on the task. - if (!_HasUserException()) - { - _CancelWithException(std::current_exception()); - } + _CancelWithException(std::current_exception()); } } + } - /// - /// Function executes a continuation. This function is recorded by a parent task implementation - /// when a continuation is created in order to execute later. - /// - /// - /// The continuation task chore handle that need to be executed. - /// - /**/ - void _RunContinuation(_ContinuationTaskHandleBase * _PTaskHandle) + /// + /// Function executes a continuation. This function is recorded by a parent task implementation + /// when a continuation is created in order to execute later. + /// + /// + /// The continuation task chore handle that need to be executed. + /// + /**/ + void _RunContinuation(_ContinuationTaskHandleBase* _PTaskHandle) + { + _Task_ptr_base _ImplBase = _PTaskHandle->_GetTaskImplBase(); + if (_IsCanceled() && !_PTaskHandle->_M_isTaskBasedContinuation) { - _Task_ptr_base _ImplBase = _PTaskHandle->_GetTaskImplBase(); - if (_IsCanceled() && !_PTaskHandle->_M_isTaskBasedContinuation) + if (_HasUserException()) { - if (_HasUserException()) - { - // If the ancestor encountered an exception, transfer the exception to the continuation - // This traverses down the tree to propagate the exception. - _ImplBase->_CancelWithExceptionHolder(_GetExceptionHolder(), true); - } - else - { - // If the ancestor was canceled, then your own execution should be canceled. - // This traverses down the tree to cancel it. - _ImplBase->_Cancel(true); - } + // If the ancestor encountered an exception, transfer the exception to the continuation + // This traverses down the tree to propagate the exception. + _ImplBase->_CancelWithExceptionHolder(_GetExceptionHolder(), true); } else { - // This can only run when the ancestor has completed or it's a task based continuation that fires when a task is canceled - // (with or without a user exception). - _ASSERTE(_IsCompleted() || _PTaskHandle->_M_isTaskBasedContinuation); - _ASSERTE(!_ImplBase->_IsCanceled()); - return _ImplBase->_ScheduleContinuationTask(_PTaskHandle); + // If the ancestor was canceled, then your own execution should be canceled. + // This traverses down the tree to cancel it. + _ImplBase->_Cancel(true); } - - // If the handle is not scheduled, we need to manually delete it. - delete _PTaskHandle; } - - // Schedule a continuation to run - void _ScheduleContinuationTask(_ContinuationTaskHandleBase * _PTaskHandle) + else { + // This can only run when the ancestor has completed or it's a task based continuation that fires when a + // task is canceled (with or without a user exception). + _ASSERTE(_IsCompleted() || _PTaskHandle->_M_isTaskBasedContinuation); + _ASSERTE(!_ImplBase->_IsCanceled()); + return _ImplBase->_ScheduleContinuationTask(_PTaskHandle); + } - _M_taskEventLogger._LogScheduleTask(true); - // Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a different Windows Runtime apartment) - if (_PTaskHandle->_M_continuationContext._HasCapturedContext()) + // If the handle is not scheduled, we need to manually delete it. + delete _PTaskHandle; + } + + // Schedule a continuation to run + void _ScheduleContinuationTask(_ContinuationTaskHandleBase* _PTaskHandle) + { + _M_taskEventLogger._LogScheduleTask(true); + // Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a + // different Windows Runtime apartment) + if (_PTaskHandle->_M_continuationContext._HasCapturedContext()) + { + // For those continuations need to be scheduled inside captured context, we will try to apply automatic + // inlining to their inline modes, if they haven't been specified as _ForceInline yet. This change will + // encourage those continuations to be executed inline so that reduce the cost of marshaling. For normal + // continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl + // method. + if (_PTaskHandle->_M_inliningMode != details::_ForceInline) { - // For those continuations need to be scheduled inside captured context, we will try to apply automatic inlining to their inline modes, - // if they haven't been specified as _ForceInline yet. This change will encourage those continuations to be executed inline so that reduce - // the cost of marshaling. - // For normal continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl method. - if (_PTaskHandle->_M_inliningMode != details::_ForceInline) - { - _PTaskHandle->_M_inliningMode = details::_DefaultAutoInline; - } - _ScheduleFuncWithAutoInline([_PTaskHandle]() { - // Note that we cannot directly capture "this" pointer, instead, we should use _TaskImplPtr, a shared_ptr to the _Task_impl_base. - // Because "this" pointer will be invalid as soon as _PTaskHandle get deleted. _PTaskHandle will be deleted after being scheduled. + _PTaskHandle->_M_inliningMode = details::_DefaultAutoInline; + } + _ScheduleFuncWithAutoInline( + [_PTaskHandle]() { + // Note that we cannot directly capture "this" pointer, instead, we should use _TaskImplPtr, a + // shared_ptr to the _Task_impl_base. Because "this" pointer will be invalid as soon as _PTaskHandle + // get deleted. _PTaskHandle will be deleted after being scheduled. auto _TaskImplPtr = _PTaskHandle->_GetTaskImplBase(); if (details::_ContextCallback::_CaptureCurrent() == _PTaskHandle->_M_continuationContext) { @@ -2084,205 +2060,216 @@ namespace details else { // - // It's entirely possible that the attempt to marshal the call into a differing context will fail. In this case, we need to handle - // the exception and mark the continuation as canceled with the appropriate exception. There is one slight hitch to this: + // It's entirely possible that the attempt to marshal the call into a differing context will + // fail. In this case, we need to handle the exception and mark the continuation as canceled + // with the appropriate exception. There is one slight hitch to this: // - // NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. This will in effect turn an SEH into - // a C++ exception that gets tagged on the task. One unfortunate result of this is that various pieces of the task infrastructure will - // not be in a valid state after this in /EHsc (due to the lack of destructors running, etc...). + // NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. + // This will in effect turn an SEH into a C++ exception that gets tagged on the task. One + // unfortunate result of this is that various pieces of the task infrastructure will not be in a + // valid state after this in /EHsc (due to the lack of destructors running, etc...). // try { // Dev10 compiler needs this! auto _PTaskHandle1 = _PTaskHandle; - _PTaskHandle->_M_continuationContext._CallInContext( [_PTaskHandle1, _TaskImplPtr](){ + _PTaskHandle->_M_continuationContext._CallInContext([_PTaskHandle1, _TaskImplPtr]() { _TaskImplPtr->_ScheduleTask(_PTaskHandle1, details::_ForceInline); }); } -#if defined (__cplusplus_winrt) - catch(::Platform::Exception^ _E) +#if defined(__cplusplus_winrt) + catch (::Platform::Exception ^ _E) { _TaskImplPtr->_CancelWithException(_E); } -#endif /* defined (__cplusplus_winrt) */ - catch(...) +#endif /* defined (__cplusplus_winrt) */ + catch (...) { _TaskImplPtr->_CancelWithException(std::current_exception()); } } - }, _PTaskHandle->_M_inliningMode); - } - else - { - _ScheduleTask(_PTaskHandle, _PTaskHandle->_M_inliningMode); - } + }, + _PTaskHandle->_M_inliningMode); } + else + { + _ScheduleTask(_PTaskHandle, _PTaskHandle->_M_inliningMode); + } + } - /// - /// Schedule the actual continuation. This will either schedule the function on the continuation task's implementation - /// if the task has completed or append it to a list of functions to execute when the task actually does complete. - /// - /// - /// The input type of the task. - /// - /// - /// The output type of the task. - /// - /**/ - void _ScheduleContinuation(_ContinuationTaskHandleBase * _PTaskHandle) + /// + /// Schedule the actual continuation. This will either schedule the function on the continuation task's + /// implementation if the task has completed or append it to a list of functions to execute when the task + /// actually does complete. + /// + /// + /// The input type of the task. + /// + /// + /// The output type of the task. + /// + /**/ + void _ScheduleContinuation(_ContinuationTaskHandleBase* _PTaskHandle) + { + enum { - enum { _Nothing, _Schedule, _Cancel, _CancelWithException } _Do = _Nothing; + _Nothing, + _Schedule, + _Cancel, + _CancelWithException + } _Do = _Nothing; - // If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right away. - // Otherwise, add it to the list of pending continuations + // If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right + // away. Otherwise, add it to the list of pending continuations + { + ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec); + if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation)) { - ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec); - if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation)) - { - _Do = _Schedule; - } - else if (_IsCanceled()) + _Do = _Schedule; + } + else if (_IsCanceled()) + { + if (_HasUserException()) { - if (_HasUserException()) - { - _Do = _CancelWithException; - } - else - { - _Do = _Cancel; - } + _Do = _CancelWithException; } else { - // chain itself on the continuation chain. - _PTaskHandle->_M_next = _M_Continuations; - _M_Continuations = _PTaskHandle; + _Do = _Cancel; } } - - // Cancellation and execution of continuations should be performed after releasing the lock. Continuations off of - // async tasks may execute inline. - switch (_Do) + else { - case _Schedule: - { - _PTaskHandle->_GetTaskImplBase()->_ScheduleContinuationTask(_PTaskHandle); - break; - } - case _Cancel: - { - // If the ancestor was canceled, then your own execution should be canceled. - // This traverses down the tree to cancel it. - _PTaskHandle->_GetTaskImplBase()->_Cancel(true); - - delete _PTaskHandle; - break; - } - case _CancelWithException: - { - // If the ancestor encountered an exception, transfer the exception to the continuation - // This traverses down the tree to propagate the exception. - _PTaskHandle->_GetTaskImplBase()->_CancelWithExceptionHolder(_GetExceptionHolder(), true); - - delete _PTaskHandle; - break; - } - case _Nothing: - default: - // In this case, we have inserted continuation to continuation chain, - // nothing more need to be done, just leave. - break; + // chain itself on the continuation chain. + _PTaskHandle->_M_next = _M_Continuations; + _M_Continuations = _PTaskHandle; } } - void _RunTaskContinuations() + // Cancellation and execution of continuations should be performed after releasing the lock. Continuations off + // of async tasks may execute inline. + switch (_Do) { - // The link list can no longer be modified at this point, - // since all following up continuations will be scheduled by themselves. - _ContinuationList _Cur = _M_Continuations, _Next; - _M_Continuations = nullptr; - while (_Cur) + case _Schedule: + { + _PTaskHandle->_GetTaskImplBase()->_ScheduleContinuationTask(_PTaskHandle); + break; + } + case _Cancel: { - // Current node might be deleted after running, - // so we must fetch the next first. - _Next = _Cur->_M_next; - _RunContinuation(_Cur); - _Cur = _Next; + // If the ancestor was canceled, then your own execution should be canceled. + // This traverses down the tree to cancel it. + _PTaskHandle->_GetTaskImplBase()->_Cancel(true); + + delete _PTaskHandle; + break; + } + case _CancelWithException: + { + // If the ancestor encountered an exception, transfer the exception to the continuation + // This traverses down the tree to propagate the exception. + _PTaskHandle->_GetTaskImplBase()->_CancelWithExceptionHolder(_GetExceptionHolder(), true); + + delete _PTaskHandle; + break; } + case _Nothing: + default: + // In this case, we have inserted continuation to continuation chain, + // nothing more need to be done, just leave. + break; } + } -#if defined (__cplusplus_winrt) - static bool _IsNonBlockingThread() + void _RunTaskContinuations() + { + // The link list can no longer be modified at this point, + // since all following up continuations will be scheduled by themselves. + _ContinuationList _Cur = _M_Continuations, _Next; + _M_Continuations = nullptr; + while (_Cur) { - APTTYPE _AptType; - APTTYPEQUALIFIER _AptTypeQualifier; + // Current node might be deleted after running, + // so we must fetch the next first. + _Next = _Cur->_M_next; + _RunContinuation(_Cur); + _Cur = _Next; + } + } - HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier); - // - // If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure. - // - if (SUCCEEDED(hr)) +#if defined(__cplusplus_winrt) + static bool _IsNonBlockingThread() + { + APTTYPE _AptType; + APTTYPEQUALIFIER _AptTypeQualifier; + + HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier); + // + // If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure. + // + if (SUCCEEDED(hr)) + { + switch (_AptType) { - switch(_AptType) - { case APTTYPE_STA: - case APTTYPE_MAINSTA: - return true; - break; + case APTTYPE_MAINSTA: return true; break; case APTTYPE_NA: - switch(_AptTypeQualifier) + switch (_AptTypeQualifier) { - // A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is allowed - // to wait, we check the app qualifier. If it is an STA thread executing in a neutral apartment, waiting - // is illegal, because the thread is responsible for pumping messages and waiting on a task could take the - // thread out of circulation for a while. - case APTTYPEQUALIFIER_NA_ON_STA: - case APTTYPEQUALIFIER_NA_ON_MAINSTA: - return true; - break; + // A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is + // allowed to wait, we check the app qualifier. If it is an STA thread executing in a neutral + // apartment, waiting is illegal, because the thread is responsible for pumping messages and + // waiting on a task could take the thread out of circulation for a while. + case APTTYPEQUALIFIER_NA_ON_STA: + case APTTYPEQUALIFIER_NA_ON_MAINSTA: return true; break; } break; - } - } - -#if _UITHREADCTXT_SUPPORT - // This method is used to throw an exception in _Wait() if called within STA. We - // want the same behavior if _Wait is called on the UI thread. - if (SUCCEEDED(CaptureUiThreadContext(nullptr))) - { - return true; } -#endif /* _UITHREADCTXT_SUPPORT */ - - return false; } - template - static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type & _OuterTask, - Windows::Foundation::IAsyncOperation::_Value>^ _AsyncOp) +#if _UITHREADCTXT_SUPPORT + // This method is used to throw an exception in _Wait() if called within STA. We + // want the same behavior if _Wait is called on the UI thread. + if (SUCCEEDED(CaptureUiThreadContext(nullptr))) { - // This method is invoked either when a task is created from an existing async operation or - // when a lambda that creates an async operation executes. - - // If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM reference on - // the IAsyncInfo object will be released when all ^references to the operation go out of scope. + return true; + } +#endif /* _UITHREADCTXT_SUPPORT */ - // This assertion uses the existence of taskcollection to determine if the task was created from an event. - // That is no longer valid as even tasks created from a user lambda could have no underlying taskcollection - // when a custom scheduler is used. - // _ASSERTE((!_OuterTask->_M_TaskCollection._IsCreated() || _OuterTask->_M_fUnwrappedTask) && !_OuterTask->_IsCanceled()); + return false; + } - // Pass the shared_ptr by value into the lambda instead of using 'this'. - _AsyncOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType>( - [_OuterTask](Windows::Foundation::IAsyncOperation::_Value>^ _Operation, Windows::Foundation::AsyncStatus _Status) mutable - { + template + static void _AsyncInit( + const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, + Windows::Foundation::IAsyncOperation::_Value> ^ _AsyncOp) + { + // This method is invoked either when a task is created from an existing async operation or + // when a lambda that creates an async operation executes. + + // If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM + // reference on the IAsyncInfo object will be released when all ^references to the operation go out of scope. + + // This assertion uses the existence of taskcollection to determine if the task was created from an event. + // That is no longer valid as even tasks created from a user lambda could have no underlying taskcollection + // when a custom scheduler is used. + // _ASSERTE((!_OuterTask->_M_TaskCollection._IsCreated() || _OuterTask->_M_fUnwrappedTask) && + // !_OuterTask->_IsCanceled()); + + // Pass the shared_ptr by value into the lambda instead of using 'this'. + _AsyncOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType>( + [_OuterTask]( + Windows::Foundation::IAsyncOperation::_Value> ^ + _Operation, + Windows::Foundation::AsyncStatus _Status) mutable { if (_Status == Windows::Foundation::AsyncStatus::Canceled) { _OuterTask->_Cancel(true); } else if (_Status == Windows::Foundation::AsyncStatus::Error) { - _OuterTask->_CancelWithException(::Platform::Exception::ReCreateException(static_cast(_Operation->ErrorCode.Value))); + _OuterTask->_CancelWithException( + ::Platform::Exception::ReCreateException(static_cast(_Operation->ErrorCode.Value))); } else { @@ -2290,31 +2277,32 @@ namespace details _OuterTask->_FinalizeAndRunContinuations(_Operation->GetResults()); } - // Take away this shared pointers reference on the task instead of waiting for the delegate to be released. It could - // be released on a different thread after a delay, and not releasing the reference here could cause the tasks to hold - // on to resources longer than they should. As an example, without this reset, writing to a file followed by reading from - // it using the Windows Runtime Async APIs causes a sharing violation. - // Using const_cast is the workaround for failed mutable keywords - const_cast<_Task_ptr<_ReturnType>::_Type &>(_OuterTask).reset(); - }); - _OuterTask->_SetUnwrappedAsyncOp(_AsyncOp); - } -#endif /* defined (__cplusplus_winrt) */ - - template - static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, const task<_InternalReturnType> & _UnwrappedTask) - { - _ASSERTE(_OuterTask->_M_fUnwrappedTask && !_OuterTask->_IsCanceled()); + // Take away this shared pointers reference on the task instead of waiting for the delegate to be + // released. It could be released on a different thread after a delay, and not releasing the reference + // here could cause the tasks to hold on to resources longer than they should. As an example, without + // this reset, writing to a file followed by reading from it using the Windows Runtime Async APIs causes + // a sharing violation. Using const_cast is the workaround for failed mutable keywords + const_cast<_Task_ptr<_ReturnType>::_Type&>(_OuterTask).reset(); + }); + _OuterTask->_SetUnwrappedAsyncOp(_AsyncOp); + } +#endif /* defined (__cplusplus_winrt) */ - // - // We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in the - // presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception handling continuation - // off the inner task which does the appropriate funneling to the outer one. We use _Then instead of then to prevent - // the exception from being marked as observed by our internal continuation. This continuation must be scheduled regardless - // of whether or not the _OuterTask task is canceled. - // - _UnwrappedTask._Then([_OuterTask] (task<_InternalReturnType> _AncestorTask) { + template + static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, + const task<_InternalReturnType>& _UnwrappedTask) + { + _ASSERTE(_OuterTask->_M_fUnwrappedTask && !_OuterTask->_IsCanceled()); + // + // We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in + // the presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception + // handling continuation off the inner task which does the appropriate funneling to the outer one. We use _Then + // instead of then to prevent the exception from being marked as observed by our internal continuation. This + // continuation must be scheduled regardless of whether or not the _OuterTask task is canceled. + // + _UnwrappedTask._Then( + [_OuterTask](task<_InternalReturnType> _AncestorTask) { if (_AncestorTask._GetImpl()->_IsCompleted()) { _OuterTask->_FinalizeAndRunContinuations(_AncestorTask._GetImpl()->_GetResult()); @@ -2324,8 +2312,8 @@ namespace details _ASSERTE(_AncestorTask._GetImpl()->_IsCanceled()); if (_AncestorTask._GetImpl()->_HasUserException()) { - // Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of _UnwrappedTask. - // Instead, it is the enclosing task. + // Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of + // _UnwrappedTask. Instead, it is the enclosing task. _OuterTask->_CancelWithExceptionHolder(_AncestorTask._GetImpl()->_GetExceptionHolder(), false); } else @@ -2333,348 +2321,356 @@ namespace details _OuterTask->_Cancel(true); } } - }, nullptr, details::_DefaultAutoInline); + }, + nullptr, + details::_DefaultAutoInline); + } - } + scheduler_ptr _GetScheduler() const { return _M_TaskCollection._GetScheduler(); } - scheduler_ptr _GetScheduler() const - { - return _M_TaskCollection._GetScheduler(); - } + // Tracks the internal state of the task + std::atomic<_TaskInternalState> _M_TaskState; + // Set to true either if the ancestor task had the flag set to true, or if the lambda that does the work of this + // task returns an async operation or async action that is unwrapped by the runtime. + bool _M_fFromAsync; + // Set to true when a continuation unwraps a task or async operation. + bool _M_fUnwrappedTask; - // Tracks the internal state of the task - std::atomic<_TaskInternalState> _M_TaskState; - // Set to true either if the ancestor task had the flag set to true, or if the lambda that does the work of this task returns an - // async operation or async action that is unwrapped by the runtime. - bool _M_fFromAsync; - // Set to true when a continuation unwraps a task or async operation. - bool _M_fUnwrappedTask; + // An exception thrown by the task body is captured in an exception holder and it is shared with all value based + // continuations rooted at the task. The exception is 'observed' if the user invokes get()/wait() on any of the + // tasks that are sharing this exception holder. If the exception is not observed by the time the internal object + // owned by the shared pointer destructs, the process will fail fast. + std::shared_ptr<_ExceptionHolder> _M_exceptionHolder; - // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task. - // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception - // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast. - std::shared_ptr<_ExceptionHolder> _M_exceptionHolder; + ::pplx::extensibility::critical_section_t _M_ContinuationsCritSec; - ::pplx::extensibility::critical_section_t _M_ContinuationsCritSec; + // The cancellation token state. + _CancellationTokenState* _M_pTokenState; - // The cancellation token state. - _CancellationTokenState * _M_pTokenState; + // The registration on the token. + _CancellationTokenRegistration* _M_pRegistration; - // The registration on the token. - _CancellationTokenRegistration * _M_pRegistration; + typedef _ContinuationTaskHandleBase* _ContinuationList; + _ContinuationList _M_Continuations; - typedef _ContinuationTaskHandleBase * _ContinuationList; - _ContinuationList _M_Continuations; + // The async task collection wrapper + ::pplx::details::_TaskCollection_t _M_TaskCollection; - // The async task collection wrapper - ::pplx::details::_TaskCollection_t _M_TaskCollection; + // Callstack for function call (constructor or .then) that created this task impl. + _TaskCreationCallstack _M_pTaskCreationCallstack; - // Callstack for function call (constructor or .then) that created this task impl. - _TaskCreationCallstack _M_pTaskCreationCallstack; + _TaskEventLogger _M_taskEventLogger; - _TaskEventLogger _M_taskEventLogger; - private: - // Must not be copied by value: - _Task_impl_base(const _Task_impl_base&); - _Task_impl_base const & operator=(_Task_impl_base const&); - }; +private: + // Must not be copied by value: + _Task_impl_base(const _Task_impl_base&); + _Task_impl_base const& operator=(_Task_impl_base const&); +}; #if PPLX_TASK_ASYNC_LOGGING - inline void _TaskEventLogger::_LogTaskCompleted() +inline void _TaskEventLogger::_LogTaskCompleted() +{ + if (_M_scheduled) { - if (_M_scheduled) - { - ::Windows::Foundation::AsyncStatus _State; - if (_M_task->_IsCompleted()) - _State = ::Windows::Foundation::AsyncStatus::Completed; - else if (_M_task->_HasUserException()) - _State = ::Windows::Foundation::AsyncStatus::Error; - else - _State = ::Windows::Foundation::AsyncStatus::Canceled; + ::Windows::Foundation::AsyncStatus _State; + if (_M_task->_IsCompleted()) + _State = ::Windows::Foundation::AsyncStatus::Completed; + else if (_M_task->_HasUserException()) + _State = ::Windows::Foundation::AsyncStatus::Error; + else + _State = ::Windows::Foundation::AsyncStatus::Canceled; - if (details::_IsCausalitySupported()) - { - ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, - _PPLTaskCausalityPlatformID, reinterpret_cast(_M_task), _State); - } + if (details::_IsCausalitySupported()) + { + ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCompletion( + ::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, + ::Windows::Foundation::Diagnostics::CausalitySource::Library, + _PPLTaskCausalityPlatformID, + reinterpret_cast(_M_task), + _State); } } +} #endif - /// - /// The implementation of a first-class task. This structure contains the task group used to execute - /// the task function and handles the scheduling. The _Task_impl is created as a shared_ptr - /// member of the the public task class, so its destruction is handled automatically. - /// - /// - /// The result type of this task. - /// - /**/ - template - struct _Task_impl : public _Task_impl_base - { -#if defined (__cplusplus_winrt) - typedef Windows::Foundation::IAsyncOperation::_Value> _AsyncOperationType; +/// +/// The implementation of a first-class task. This structure contains the task group used to execute +/// the task function and handles the scheduling. The _Task_impl is created as a shared_ptr +/// member of the the public task class, so its destruction is handled automatically. +/// +/// +/// The result type of this task. +/// +/**/ +template +struct _Task_impl : public _Task_impl_base +{ +#if defined(__cplusplus_winrt) + typedef Windows::Foundation::IAsyncOperation::_Value> + _AsyncOperationType; #endif // defined(__cplusplus_winrt) - _Task_impl(_CancellationTokenState * _Ct, scheduler_ptr _Scheduler_arg) - : _Task_impl_base(_Ct, _Scheduler_arg) - { -#if defined (__cplusplus_winrt) - _M_unwrapped_async_op = nullptr; -#endif /* defined (__cplusplus_winrt) */ - } + _Task_impl(_CancellationTokenState* _Ct, scheduler_ptr _Scheduler_arg) : _Task_impl_base(_Ct, _Scheduler_arg) + { +#if defined(__cplusplus_winrt) + _M_unwrapped_async_op = nullptr; +#endif /* defined (__cplusplus_winrt) */ + } - virtual ~_Task_impl() - { - // We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class destructor could cause - // a partially initialized _Task_impl to be in the list of registrations for a cancellation token. - _DeregisterCancellation(); - } + virtual ~_Task_impl() + { + // We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class + // destructor could cause a partially initialized _Task_impl to be in the list of registrations for a + // cancellation token. + _DeregisterCancellation(); + } - virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder> & _ExceptionHolder_arg) + virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, + bool _UserException, + bool _PropagatedFromAncestor, + const std::shared_ptr<_ExceptionHolder>& _ExceptionHolder_arg) + { + bool _RunContinuations = false; { - bool _RunContinuations = false; + ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec); + if (_UserException) { - ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec); - if (_UserException) - { - _ASSERTE(_SynchronousCancel && !_IsCompleted()); - // If the state is _Canceled, the exception has to be coming from an ancestor. - _ASSERTE(!_IsCanceled() || _PropagatedFromAncestor); - - // We should not be canceled with an exception more than once. - _ASSERTE(!_HasUserException()); + _ASSERTE(_SynchronousCancel && !_IsCompleted()); + // If the state is _Canceled, the exception has to be coming from an ancestor. + _ASSERTE(!_IsCanceled() || _PropagatedFromAncestor); - // Mark _PropagatedFromAncestor as used. - (void)_PropagatedFromAncestor; + // We should not be canceled with an exception more than once. + _ASSERTE(!_HasUserException()); - if (_M_TaskState == _Canceled) - { - // If the task has finished canceling there should not be any continuation records in the array. - return false; - } - else - { - _ASSERTE(_M_TaskState != _Completed); - _M_exceptionHolder = _ExceptionHolder_arg; - } - } - else - { - // Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do better than the last async cancel - // which is to say, cancellation is already initiated, so return early. - if (_IsCompleted() || _IsCanceled() || (_IsPendingCancel() && !_SynchronousCancel)) - { - _ASSERTE(!_IsCompleted() || !_HasUserException()); - return false; - } - _ASSERTE(!_SynchronousCancel || !_HasUserException()); - } + // Mark _PropagatedFromAncestor as used. + (void)_PropagatedFromAncestor; - if (_SynchronousCancel) + if (_M_TaskState == _Canceled) { - // Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this and wait() - _M_TaskState = _Canceled; - // Cancellation completes the task, so all dependent tasks must be run to cancel them - // They are canceled when they begin running (see _RunContinuation) and see that their - // ancestor has been canceled. - _RunContinuations = true; + // If the task has finished canceling there should not be any continuation records in the array. + return false; } else { - _ASSERTE(!_UserException); - - if (_IsStarted()) - { -#if defined (__cplusplus_winrt) - if (_M_unwrapped_async_op != nullptr) - { - // We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks cannot be canceled without its token. - _M_unwrapped_async_op->Cancel(); - } -#endif /* defined (__cplusplus_winrt) */ - _M_TaskCollection._Cancel(); - } - - // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore). - // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from - // _Started to _PendingCancel before it can move to _Canceled when it is finished executing. - _M_TaskState = _PendingCancel; - - _M_taskEventLogger._LogCancelTask(); + _ASSERTE(_M_TaskState != _Completed); + _M_exceptionHolder = _ExceptionHolder_arg; } - - } - - // Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled state. - if (_RunContinuations) + else { - _M_TaskCollection._Complete(); - - if (_M_Continuations) + // Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do + // better than the last async cancel which is to say, cancellation is already initiated, so return + // early. + if (_IsCompleted() || _IsCanceled() || (_IsPendingCancel() && !_SynchronousCancel)) { - // Scheduling cancellation with automatic inlining. - _ScheduleFuncWithAutoInline([=](){ _RunTaskContinuations(); }, details::_DefaultAutoInline); + _ASSERTE(!_IsCompleted() || !_HasUserException()); + return false; } + _ASSERTE(!_SynchronousCancel || !_HasUserException()); } - return true; - } - - void _FinalizeAndRunContinuations(_ReturnType _Result) - { - _M_Result.Set(_Result); + if (_SynchronousCancel) + { + // Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this + // and wait() + _M_TaskState = _Canceled; + // Cancellation completes the task, so all dependent tasks must be run to cancel them + // They are canceled when they begin running (see _RunContinuation) and see that their + // ancestor has been canceled. + _RunContinuations = true; + } + else { - // - // Hold this lock to ensure continuations being concurrently either get added - // to the _M_Continuations vector or wait for the result - // - ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec); - - // A task could still be in the _Created state if it was created with a task_completion_event. - // It could also be in the _Canceled state for the same reason. - _ASSERTE(!_HasUserException() && !_IsCompleted()); - if (_IsCanceled()) + _ASSERTE(!_UserException); + + if (_IsStarted()) { - return; +#if defined(__cplusplus_winrt) + if (_M_unwrapped_async_op != nullptr) + { + // We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks + // cannot be canceled without its token. + _M_unwrapped_async_op->Cancel(); + } +#endif /* defined (__cplusplus_winrt) */ + _M_TaskCollection._Cancel(); } - // Always transition to "completed" state, even in the face of unacknowledged pending cancellation - _M_TaskState = _Completed; + // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not + // executing user code anymore). In the case of a synchronous cancel, this can happen immediately, + // whereas with an asynchronous cancel, the task has to move from _Started to _PendingCancel before it + // can move to _Canceled when it is finished executing. + _M_TaskState = _PendingCancel; + + _M_taskEventLogger._LogCancelTask(); } - _M_TaskCollection._Complete(); - _RunTaskContinuations(); } - // - // This method is invoked when the starts executing. The task returns early if this method returns true. - // - bool _TransitionedToStarted() + // Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled + // state. + if (_RunContinuations) { - ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec); - // Canceled state could only result from antecedent task's canceled state, but that code path will not reach here. - _ASSERTE(!_IsCanceled()); - if (_IsPendingCancel()) - return false; + _M_TaskCollection._Complete(); - _ASSERTE(_IsCreated()); - _M_TaskState = _Started; - return true; + if (_M_Continuations) + { + // Scheduling cancellation with automatic inlining. + _ScheduleFuncWithAutoInline([=]() { _RunTaskContinuations(); }, details::_DefaultAutoInline); + } } + return true; + } + + void _FinalizeAndRunContinuations(_ReturnType _Result) + { + _M_Result.Set(_Result); -#if defined (__cplusplus_winrt) - void _SetUnwrappedAsyncOp(_AsyncOperationType^ _AsyncOp) { + // + // Hold this lock to ensure continuations being concurrently either get added + // to the _M_Continuations vector or wait for the result + // ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec); - // Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it. - if (_IsPendingCancel()) + + // A task could still be in the _Created state if it was created with a task_completion_event. + // It could also be in the _Canceled state for the same reason. + _ASSERTE(!_HasUserException() && !_IsCompleted()); + if (_IsCanceled()) { - _ASSERTE(!_IsCanceled()); - _AsyncOp->Cancel(); - } - else - { - _M_unwrapped_async_op = _AsyncOp; + return; } + + // Always transition to "completed" state, even in the face of unacknowledged pending cancellation + _M_TaskState = _Completed; } -#endif /* defined (__cplusplus_winrt) */ + _M_TaskCollection._Complete(); + _RunTaskContinuations(); + } + + // + // This method is invoked when the starts executing. The task returns early if this method returns true. + // + bool _TransitionedToStarted() + { + ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec); + // Canceled state could only result from antecedent task's canceled state, but that code path will not reach + // here. + _ASSERTE(!_IsCanceled()); + if (_IsPendingCancel()) return false; + + _ASSERTE(_IsCreated()); + _M_TaskState = _Started; + return true; + } - // Return true if the task has reached a terminal state - bool _IsDone() +#if defined(__cplusplus_winrt) + void _SetUnwrappedAsyncOp(_AsyncOperationType ^ _AsyncOp) + { + ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec); + // Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it. + if (_IsPendingCancel()) { - return _IsCompleted() || _IsCanceled(); + _ASSERTE(!_IsCanceled()); + _AsyncOp->Cancel(); } - - _ReturnType _GetResult() + else { - return _M_Result.Get(); + _M_unwrapped_async_op = _AsyncOp; } + } +#endif /* defined (__cplusplus_winrt) */ - _ResultHolder<_ReturnType> _M_Result; // this means that the result type must have a public default ctor. -#if defined (__cplusplus_winrt) - _AsyncOperationType^ _M_unwrapped_async_op; -#endif /* defined (__cplusplus_winrt) */ - }; + // Return true if the task has reached a terminal state + bool _IsDone() { return _IsCompleted() || _IsCanceled(); } - template - struct _Task_completion_event_impl - { - private: - _Task_completion_event_impl(const _Task_completion_event_impl&); - _Task_completion_event_impl& operator=(const _Task_completion_event_impl&); + _ReturnType _GetResult() { return _M_Result.Get(); } + + _ResultHolder<_ReturnType> _M_Result; // this means that the result type must have a public default ctor. +#if defined(__cplusplus_winrt) + _AsyncOperationType ^ _M_unwrapped_async_op; +#endif /* defined (__cplusplus_winrt) */ +}; - public: +template +struct _Task_completion_event_impl +{ +private: + _Task_completion_event_impl(const _Task_completion_event_impl&); + _Task_completion_event_impl& operator=(const _Task_completion_event_impl&); - typedef std::vector::_Type> _TaskList; +public: + typedef std::vector::_Type> _TaskList; - _Task_completion_event_impl() : - _M_fHasValue(false), _M_fIsCanceled(false) - { - } + _Task_completion_event_impl() : _M_fHasValue(false), _M_fIsCanceled(false) {} - bool _HasUserException() - { - return _M_exceptionHolder != nullptr; - } + bool _HasUserException() { return _M_exceptionHolder != nullptr; } - ~_Task_completion_event_impl() + ~_Task_completion_event_impl() + { + for (auto _TaskIt = _M_tasks.begin(); _TaskIt != _M_tasks.end(); ++_TaskIt) { - for( auto _TaskIt = _M_tasks.begin(); _TaskIt != _M_tasks.end(); ++_TaskIt ) - { - _ASSERTE(!_M_fHasValue && !_M_fIsCanceled); - // Cancel the tasks since the event was never signaled or canceled. - (*_TaskIt)->_Cancel(true); - } + _ASSERTE(!_M_fHasValue && !_M_fIsCanceled); + // Cancel the tasks since the event was never signaled or canceled. + (*_TaskIt)->_Cancel(true); } + } - // We need to protect the loop over the array, so concurrent_vector would not have helped - _TaskList _M_tasks; - ::pplx::extensibility::critical_section_t _M_taskListCritSec; - _ResultHolder<_ResultType> _M_value; - std::shared_ptr<_ExceptionHolder> _M_exceptionHolder; - std::atomic _M_fHasValue; - std::atomic _M_fIsCanceled; - }; + // We need to protect the loop over the array, so concurrent_vector would not have helped + _TaskList _M_tasks; + ::pplx::extensibility::critical_section_t _M_taskListCritSec; + _ResultHolder<_ResultType> _M_value; + std::shared_ptr<_ExceptionHolder> _M_exceptionHolder; + std::atomic _M_fHasValue; + std::atomic _M_fIsCanceled; +}; - // Utility method for dealing with void functions - inline std::function<_Unit_type(void)> _MakeVoidToUnitFunc(const std::function& _Func) - { - return [=]() -> _Unit_type { _Func(); return _Unit_type(); }; - } +// Utility method for dealing with void functions +inline std::function<_Unit_type(void)> _MakeVoidToUnitFunc(const std::function& _Func) +{ + return [=]() -> _Unit_type { + _Func(); + return _Unit_type(); + }; +} - template - std::function<_Type(_Unit_type)> _MakeUnitToTFunc(const std::function<_Type(void)>& _Func) - { - return [=](_Unit_type) -> _Type { return _Func(); }; - } +template +std::function<_Type(_Unit_type)> _MakeUnitToTFunc(const std::function<_Type(void)>& _Func) +{ + return [=](_Unit_type) -> _Type { return _Func(); }; +} - template - std::function<_Unit_type(_Type)> _MakeTToUnitFunc(const std::function& _Func) - { - return [=](_Type t) -> _Unit_type { _Func(t); return _Unit_type(); }; - } +template +std::function<_Unit_type(_Type)> _MakeTToUnitFunc(const std::function& _Func) +{ + return [=](_Type t) -> _Unit_type { + _Func(t); + return _Unit_type(); + }; +} - inline std::function<_Unit_type(_Unit_type)> _MakeUnitToUnitFunc(const std::function& _Func) - { - return [=](_Unit_type) -> _Unit_type { _Func(); return _Unit_type(); }; - } +inline std::function<_Unit_type(_Unit_type)> _MakeUnitToUnitFunc(const std::function& _Func) +{ + return [=](_Unit_type) -> _Unit_type { + _Func(); + return _Unit_type(); + }; +} } // namespace details /// -/// The task_completion_event class allows you to delay the execution of a task until a condition is satisfied, -/// or start a task in response to an external event. +/// The task_completion_event class allows you to delay the execution of a task until a condition is +/// satisfied, or start a task in response to an external event. /// /// /// The result type of this task_completion_event class. /// /// -/// Use a task created from a task completion event when your scenario requires you to create a task that will complete, and -/// thereby have its continuations scheduled for execution, at some point in the future. The task_completion_event must -/// have the same type as the task you create, and calling the set method on the task completion event with a value of that type -/// will cause the associated task to complete, and provide that value as a result to its continuations. -/// If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed. -/// task_completion_event behaves like a smart pointer, and should be passed by value. +/// Use a task created from a task completion event when your scenario requires you to create a task that will +/// complete, and thereby have its continuations scheduled for execution, at some point in the future. The +/// task_completion_event must have the same type as the task you create, and calling the set method on the +/// task completion event with a value of that type will cause the associated task to complete, and provide that +/// value as a result to its continuations. If the task completion event is never signaled, any tasks created +/// from it will be canceled when it is destructed. task_completion_event behaves like a smart +/// pointer, and should be passed by value. /// /// /**/ @@ -2686,10 +2682,7 @@ class task_completion_event /// Constructs a task_completion_event object. /// /**/ - task_completion_event() - : _M_Impl(std::make_shared>()) - { - } + task_completion_event() : _M_Impl(std::make_shared>()) {} /// /// Sets the task completion event. @@ -2698,18 +2691,23 @@ class task_completion_event /// The result to set this event with. /// /// - /// The method returns true if it was successful in setting the event. It returns false if the event is already set. + /// The method returns true if it was successful in setting the event. It returns false if the + /// event is already set. /// /// - /// In the presence of multiple or concurrent calls to set, only the first call will succeed and its result (if any) will be stored in the - /// task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the - /// tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have - /// a other than void will pass the value to their continuations. + /// In the presence of multiple or concurrent calls to set, only the first call will succeed and its + /// result (if any) will be stored in the task completion event. The remaining sets are ignored and the method + /// will return false. When you set a task completion event, all the tasks created from that event will + /// immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have a + /// other than void will pass the value to + /// their continuations. /// /**/ - bool set(_ResultType _Result) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas + bool set(_ResultType _Result) + const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas { - // Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are ignored. + // Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are + // ignored. if (_IsTriggered()) { return false; @@ -2732,16 +2730,16 @@ class task_completion_event if (_RunContinuations) { - for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt ) + for (auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt) { // If current task was canceled by a cancellation_token, it would be in cancel pending state. if ((*_TaskIt)->_IsPendingCancel()) (*_TaskIt)->_Cancel(true); else { - // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all - // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we - // need to run continuations after the lock is released. + // Tasks created with task_completion_events can be marked as async, (we do this in when_any and + // when_all if one of the tasks involved is an async task). Since continuations of async tasks can + // execute inline, we need to run continuations after the lock is released. (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get()); } } @@ -2757,9 +2755,11 @@ class task_completion_event template __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result - bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas + bool set_exception( + _E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas { - // It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception. + // It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for + // set_exception. return _Cancel(std::make_exception_ptr(_Except), PPLX_CAPTURE_CALLSTACK()); } @@ -2771,15 +2771,17 @@ class task_completion_event /// /**/ __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK gives us the expected result - bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas + bool set_exception(std::exception_ptr _ExceptionPtr) + const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas { - // It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception. + // It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for + // set_exception. return _Cancel(_ExceptionPtr, PPLX_CAPTURE_CALLSTACK()); } /// - /// Internal method to cancel the task_completion_event. Any task created using this event will be marked as canceled if it has - /// not already been set. + /// Internal method to cancel the task_completion_event. Any task created using this event will be marked as + /// canceled if it has not already been set. /// bool _Cancel() const { @@ -2788,14 +2790,16 @@ class task_completion_event } /// - /// Internal method to cancel the task_completion_event with the exception provided. Any task created using this event will be canceled - /// with the same exception. + /// Internal method to cancel the task_completion_event with the exception provided. Any task created using this + /// event will be canceled with the same exception. /// template - bool _Cancel(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack ()) const + bool _Cancel( + _ExHolderType _ExHolder, + const details::_TaskCreationCallstack& _SetExceptionAddressHint = details::_TaskCreationCallstack()) const { bool _Canceled; - if(_StoreException(_ExHolder, _SetExceptionAddressHint)) + if (_StoreException(_ExHolder, _SetExceptionAddressHint)) { _Canceled = _CancelInternal(); _ASSERTE(_Canceled); @@ -2813,7 +2817,9 @@ class task_completion_event /// can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present. /// template - bool _StoreException(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack ()) const + bool _StoreException( + _ExHolderType _ExHolder, + const details::_TaskCreationCallstack& _SetExceptionAddressHint = details::_TaskCreationCallstack()) const { ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec); if (!_IsTriggered() && !_M_Impl->_HasUserException()) @@ -2829,26 +2835,25 @@ class task_completion_event /// /// Tests whether current event has been either Set, or Canceled. /// - bool _IsTriggered() const - { - return _M_Impl->_M_fHasValue || _M_Impl->_M_fIsCanceled; - } + bool _IsTriggered() const { return _M_Impl->_M_fHasValue || _M_Impl->_M_fIsCanceled; } private: - - static std::shared_ptr _ToExceptionHolder(const std::shared_ptr& _ExHolder, const details::_TaskCreationCallstack&) + static std::shared_ptr _ToExceptionHolder( + const std::shared_ptr& _ExHolder, const details::_TaskCreationCallstack&) { return _ExHolder; } - static std::shared_ptr _ToExceptionHolder(std::exception_ptr _ExceptionPtr, const details::_TaskCreationCallstack &_SetExceptionAddressHint) + static std::shared_ptr _ToExceptionHolder( + std::exception_ptr _ExceptionPtr, const details::_TaskCreationCallstack& _SetExceptionAddressHint) { return std::make_shared(_ExceptionPtr, _SetExceptionAddressHint); } - - template friend class task; // task can register itself with the event by calling the private _RegisterTask - template friend class task_completion_event; + template + friend class task; // task can register itself with the event by calling the private _RegisterTask + template + friend class task_completion_event; typedef typename details::_Task_completion_event_impl<_ResultType>::_TaskList _TaskList; @@ -2882,7 +2887,7 @@ class task_completion_event if (_Cancel) { - for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt ) + for (auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt) { // Need to call this after the lock is released. See comments in set(). if (_UserException) @@ -2902,12 +2907,12 @@ class task_completion_event /// Register a task with this event. This function is called when a task is constructed using /// a task_completion_event. /// - void _RegisterTask(const typename details::_Task_ptr<_ResultType>::_Type & _TaskParam) + void _RegisterTask(const typename details::_Task_ptr<_ResultType>::_Type& _TaskParam) { ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec); - //If an exception was already set on this event, then cancel the task with the stored exception. - if(_M_Impl->_HasUserException()) + // If an exception was already set on this event, then cancel the task with the stored exception. + if (_M_Impl->_HasUserException()) { _TaskParam->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true); } @@ -2925,16 +2930,17 @@ class task_completion_event }; /// -/// The task_completion_event class allows you to delay the execution of a task until a condition is satisfied, -/// or start a task in response to an external event. +/// The task_completion_event class allows you to delay the execution of a task until a condition is +/// satisfied, or start a task in response to an external event. /// /// -/// Use a task created from a task completion event when your scenario requires you to create a task that will complete, and -/// thereby have its continuations scheduled for execution, at some point in the future. The task_completion_event must -/// have the same type as the task you create, and calling the set method on the task completion event with a value of that type -/// will cause the associated task to complete, and provide that value as a result to its continuations. -/// If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed. -/// task_completion_event behaves like a smart pointer, and should be passed by value. +/// Use a task created from a task completion event when your scenario requires you to create a task that will +/// complete, and thereby have its continuations scheduled for execution, at some point in the future. The +/// task_completion_event must have the same type as the task you create, and calling the set method on the +/// task completion event with a value of that type will cause the associated task to complete, and provide that +/// value as a result to its continuations. If the task completion event is never signaled, any tasks created +/// from it will be canceled when it is destructed. task_completion_event behaves like a smart +/// pointer, and should be passed by value. /// /// /**/ @@ -2946,13 +2952,16 @@ class task_completion_event /// Sets the task completion event. /// /// - /// The method returns true if it was successful in setting the event. It returns false if the event is already set. + /// The method returns true if it was successful in setting the event. It returns false if the + /// event is already set. /// /// - /// In the presence of multiple or concurrent calls to set, only the first call will succeed and its result (if any) will be stored in the - /// task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the - /// tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have - /// a other than void will pass the value to their continuations. + /// In the presence of multiple or concurrent calls to set, only the first call will succeed and its + /// result (if any) will be stored in the task completion event. The remaining sets are ignored and the method + /// will return false. When you set a task completion event, all the tasks created from that event will + /// immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have a + /// other than void will pass the value to + /// their continuations. /// /**/ bool set() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas @@ -2962,7 +2971,8 @@ class task_completion_event template __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result - bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas + bool set_exception( + _E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas { return _M_unitEvent._Cancel(std::make_exception_ptr(_Except), PPLX_CAPTURE_CALLSTACK()); } @@ -2974,10 +2984,13 @@ class task_completion_event /// The exception_ptr that indicates the exception to set this event with. /// /**/ - __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK intrinsic gives us the expected result - bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas + __declspec( + noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK intrinsic gives us the expected result + bool set_exception(std::exception_ptr _ExceptionPtr) + const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas { - // It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception. + // It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for + // set_exception. return _M_unitEvent._Cancel(_ExceptionPtr, PPLX_CAPTURE_CALLSTACK()); } @@ -2991,13 +3004,10 @@ class task_completion_event } /// - /// Cancel the task_completion_event with the exception holder provided. Any task created using this event will be canceled - /// with the same exception. + /// Cancel the task_completion_event with the exception holder provided. Any task created using this event will + /// be canceled with the same exception. /// - void _Cancel(const std::shared_ptr& _ExHolder) const - { - _M_unitEvent._Cancel(_ExHolder); - } + void _Cancel(const std::shared_ptr& _ExHolder) const { _M_unitEvent._Cancel(_ExHolder); } /// /// Method that stores an exception in the task completion event. This is used internally by when_any. @@ -3012,13 +3022,11 @@ class task_completion_event /// /// Test whether current event has been either Set, or Canceled. /// - bool _IsTriggered() const - { - return _M_unitEvent._IsTriggered(); - } + bool _IsTriggered() const { return _M_unitEvent._IsTriggered(); } private: - template friend class task; // task can register itself with the event by calling the private _RegisterTask + template + friend class task; // task can register itself with the event by calling the private _RegisterTask /// /// Register a task with this event. This function is called when a task is constructed using @@ -3029,132 +3037,137 @@ class task_completion_event _M_unitEvent._RegisterTask(_TaskParam); } - // The void event contains an event a dummy type so common code can be used for events with void and non-void results. + // The void event contains an event a dummy type so common code can be used for events with void and non-void + // results. task_completion_event _M_unitEvent; }; namespace details { - // - // Compile-time validation helpers - // +// +// Compile-time validation helpers +// - // Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here. - // - // Anything callable is fine - template - auto _IsValidTaskCtor(_Ty _Param, int,int,int,int) -> decltype(_Param(), std::true_type()); - -#if defined (__cplusplus_winrt) - // Anything that has GetResults is fine: this covers all async operations - template - auto _IsValidTaskCtor(_Ty _Param, int, int, int,...) -> decltype(_Param->GetResults(), std::true_type()); +// Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here. +// +// Anything callable is fine +template +auto _IsValidTaskCtor(_Ty _Param, int, int, int, int) -> decltype(_Param(), std::true_type()); + +#if defined(__cplusplus_winrt) +// Anything that has GetResults is fine: this covers all async operations +template +auto _IsValidTaskCtor(_Ty _Param, int, int, int, ...) -> decltype(_Param->GetResults(), std::true_type()); #endif - // Allow parameters with set: this covers task_completion_event - template - auto _IsValidTaskCtor(_Ty _Param, int, int, ...) -> decltype(_Param.set(stdx::declval<_ReturnType>()), std::true_type()); +// Allow parameters with set: this covers task_completion_event +template +auto _IsValidTaskCtor(_Ty _Param, int, int, ...) + -> decltype(_Param.set(stdx::declval<_ReturnType>()), std::true_type()); - template - auto _IsValidTaskCtor(_Ty _Param, int, ...) -> decltype(_Param.set(), std::true_type()); +template +auto _IsValidTaskCtor(_Ty _Param, int, ...) -> decltype(_Param.set(), std::true_type()); - // All else is invalid - template - std::false_type _IsValidTaskCtor(_Ty _Param, ...); +// All else is invalid +template +std::false_type _IsValidTaskCtor(_Ty _Param, ...); - template - void _ValidateTaskConstructorArgs(_Ty _Param) - { - static_assert(std::is_same(_Param,0,0,0,0)),std::true_type>::value, -#if defined (__cplusplus_winrt) - "incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a task_completion_event" +template +void _ValidateTaskConstructorArgs(_Ty _Param) +{ + static_assert(std::is_same(_Param, 0, 0, 0, 0)), std::true_type>::value, +#if defined(__cplusplus_winrt) + "incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a " + "task_completion_event" #else /* defined (__cplusplus_winrt) */ - "incorrect argument for task constructor; can be a callable object or a task_completion_event" -#endif /* defined (__cplusplus_winrt) */ - ); -#if defined (__cplusplus_winrt) - static_assert(!(std::is_same<_Ty,_ReturnType>::value && details::_IsIAsyncInfo<_Ty>::_Value), - "incorrect template argument for task; consider using the return type of the async operation"); -#endif /* defined (__cplusplus_winrt) */ - } + "incorrect argument for task constructor; can be a callable object or a task_completion_event" +#endif /* defined (__cplusplus_winrt) */ + ); +#if defined(__cplusplus_winrt) + static_assert(!(std::is_same<_Ty, _ReturnType>::value && details::_IsIAsyncInfo<_Ty>::_Value), + "incorrect template argument for task; consider using the return type of the async operation"); +#endif /* defined (__cplusplus_winrt) */ +} -#if defined (__cplusplus_winrt) - // Helpers for create_async validation - // - // A parameter lambda taking no arguments is valid - template - static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int) -> decltype(_Param(), std::true_type()); +#if defined(__cplusplus_winrt) +// Helpers for create_async validation +// +// A parameter lambda taking no arguments is valid +template +static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int) -> decltype(_Param(), std::true_type()); - // A parameter lambda taking an cancellation_token argument is valid - template - static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) -> decltype(_Param(cancellation_token::none()), std::true_type()); +// A parameter lambda taking an cancellation_token argument is valid +template +static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) + -> decltype(_Param(cancellation_token::none()), std::true_type()); - // A parameter lambda taking a progress report argument is valid - template - static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type()); +// A parameter lambda taking a progress report argument is valid +template +static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) + -> decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type()); - // A parameter lambda taking a progress report and a cancellation_token argument is valid - template - static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType(), cancellation_token::none()), std::true_type()); +// A parameter lambda taking a progress report and a cancellation_token argument is valid +template +static auto _IsValidCreateAsync(_Ty _Param, int, ...) + -> decltype(_Param(details::_ProgressReporterCtorArgType(), cancellation_token::none()), std::true_type()); - // All else is invalid - template - static std::false_type _IsValidCreateAsync(_Ty _Param, ...); -#endif /* defined (__cplusplus_winrt) */ +// All else is invalid +template +static std::false_type _IsValidCreateAsync(_Ty _Param, ...); +#endif /* defined (__cplusplus_winrt) */ /// /// A helper class template that makes only movable functions be able to be passed to std::function /// - template - struct _NonCopyableFunctorWrapper +template +struct _NonCopyableFunctorWrapper +{ + template, typename std::decay<_Tx>::type>::value>::type> + explicit _NonCopyableFunctorWrapper(_Tx&& f) : _M_functor {std::make_shared<_Ty>(std::forward<_Tx>(f))} { - template, - typename std::decay<_Tx>::type>::value>::type> - explicit _NonCopyableFunctorWrapper(_Tx&& f) - : _M_functor{std::make_shared<_Ty>(std::forward<_Tx>(f))} - {} + } - template - auto operator()(_Args&&... args) -> decltype(std::declval<_Ty>()(std::forward<_Args>(args)...)) - { - return _M_functor->operator()(std::forward<_Args>(args)...); - } + template + auto operator()(_Args&&... args) -> decltype(std::declval<_Ty>()(std::forward<_Args>(args)...)) + { + return _M_functor->operator()(std::forward<_Args>(args)...); + } - template - auto operator()(_Args&&... args) const -> decltype(std::declval<_Ty>()(std::forward<_Args>(args)...)) - { - return _M_functor->operator()(std::forward<_Args>(args)...); - } + template + auto operator()(_Args&&... args) const -> decltype(std::declval<_Ty>()(std::forward<_Args>(args)...)) + { + return _M_functor->operator()(std::forward<_Args>(args)...); + } - std::shared_ptr<_Ty> _M_functor; - }; + std::shared_ptr<_Ty> _M_functor; +}; - template - struct _CopyableFunctor - { - typedef _Ty _Type; - }; +template +struct _CopyableFunctor +{ + typedef _Ty _Type; +}; - template - struct _CopyableFunctor<_Ty, typename std::enable_if< - std::is_move_constructible<_Ty>::value && !std::is_copy_constructible<_Ty>::value>::type> - { - typedef _NonCopyableFunctorWrapper<_Ty> _Type; - }; -} +template +struct _CopyableFunctor< + _Ty, + typename std::enable_if::value && !std::is_copy_constructible<_Ty>::value>::type> +{ + typedef _NonCopyableFunctorWrapper<_Ty> _Type; +}; +} // namespace details /// -/// A helper class template that transforms a continuation lambda that either takes or returns void, or both, into a lambda that takes and returns a -/// non-void type (details::_Unit_type is used to substitute for void). This is to minimize the special handling required for 'void'. +/// A helper class template that transforms a continuation lambda that either takes or returns void, or both, into a +/// lambda that takes and returns a non-void type (details::_Unit_type is used to substitute for void). This is to +/// minimize the special handling required for 'void'. /// template class _Continuation_func_transformer { public: - static auto _Perform(std::function<_OutType(_InpType)> _Func) -> decltype(_Func) - { - return _Func; - } + static auto _Perform(std::function<_OutType(_InpType)> _Func) -> decltype(_Func) { return _Func; } }; template @@ -3187,16 +3200,13 @@ class _Continuation_func_transformer } }; -// A helper class template that transforms an intial task lambda returns void into a lambda that returns a non-void type (details::_Unit_type is used -// to substitute for void). This is to minimize the special handling required for 'void'. +// A helper class template that transforms an intial task lambda returns void into a lambda that returns a non-void type +// (details::_Unit_type is used to substitute for void). This is to minimize the special handling required for 'void'. template class _Init_func_transformer { public: - static auto _Perform(std::function<_RetType(void)> _Func) -> decltype(_Func) - { - return _Func; - } + static auto _Perform(std::function<_RetType(void)> _Func) -> decltype(_Func) { return _Func; } }; template<> @@ -3210,11 +3220,12 @@ class _Init_func_transformer }; /// -/// The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed asynchronously, -/// and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces -/// a result of type on successful completion. Tasks of type task<void> produce no result. -/// A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using -/// continuations(then), and join(when_all) and choice(when_any) patterns. +/// The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed +/// asynchronously, and concurrently with other tasks and parallel work produced by parallel algorithms in the +/// Concurrency Runtime. It produces a result of type on successful completion. +/// Tasks of type task<void> produce no result. A task can be waited upon and canceled independently of +/// other tasks. It can also be composed with other tasks using continuations(then), and +/// join(when_all) and choice(when_any) patterns. /// /// /// The result type of this task. @@ -3237,22 +3248,23 @@ class task /// Constructs a task object. /// /// - /// The default constructor for a task is only present in order to allow tasks to be used within containers. - /// A default constructed task cannot be used until you assign a valid task to it. Methods such as get, wait or then - /// will throw an invalid_argument exception when called on a default constructed task. - /// A task that is created from a task_completion_event will complete (and have its continuations scheduled) when the task - /// completion event is set. - /// The version of the constructor that takes a cancellation token creates a task that can be canceled using the - /// cancellation_token_source the token was obtained from. Tasks created without a cancellation token are not cancelable. - /// Tasks created from a Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface - /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created - /// from a lambda that returns a task<result_type> reach their terminal state when the inner task reaches its terminal state, - /// and not when the lambda returns. - /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads - /// without the need for locks. - /// The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available - /// to Windows Store apps. - /// For more information, see . + /// The default constructor for a task is only present in order to allow tasks to be used within + /// containers. A default constructed task cannot be used until you assign a valid task to it. Methods such as + /// get, wait or then will throw an invalid_argument exception when called on a default constructed task. A task that is + /// created from a task_completion_event will complete (and have its continuations scheduled) when the + /// task completion event is set. The version of the constructor that takes a cancellation token + /// creates a task that can be canceled using the cancellation_token_source the token was obtained from. + /// Tasks created without a cancellation token are not cancelable. Tasks created from a + /// Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface + /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. + /// Similarly, tasks created from a lambda that returns a task<result_type> reach their terminal + /// state when the inner task reaches its terminal state, and not when the lambda returns. + /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by + /// multiple threads without the need for locks. The constructor overloads that take a + /// Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available to + /// Windows Store apps. For more information, see . /// /**/ task() : _M_Impl(nullptr) @@ -3268,46 +3280,49 @@ class task /// The type of the parameter from which the task is to be constructed. /// /// - /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a task_completion_event<result_type> - /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function - /// object should be a type equivalent to std::function<X(void)>, where X can be a variable of type result_type, + /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a + /// task_completion_event<result_type> object, or a Windows::Foundation::IAsyncInfo if you are + /// using tasks in your Windows Store app. The lambda or function object should be a type equivalent to + /// std::function<X(void)>, where X can be a variable of type result_type, /// task<result_type>, or a Windows::Foundation::IAsyncInfo in Windows Store apps. /// /// - /// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives - /// the token cancellation_token::none(). + /// The cancellation token to associate with this task. A task created without a cancellation token cannot be + /// canceled. It implicitly receives the token cancellation_token::none(). /// /// - /// The default constructor for a task is only present in order to allow tasks to be used within containers. - /// A default constructed task cannot be used until you assign a valid task to it. Methods such as get, wait or then - /// will throw an invalid_argument exception when called on a default constructed task. - /// A task that is created from a task_completion_event will complete (and have its continuations scheduled) when the task - /// completion event is set. - /// The version of the constructor that takes a cancellation token creates a task that can be canceled using the - /// cancellation_token_source the token was obtained from. Tasks created without a cancellation token are not cancelable. - /// Tasks created from a Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface - /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created - /// from a lambda that returns a task<result_type> reach their terminal state when the inner task reaches its terminal state, - /// and not when the lambda returns. - /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads - /// without the need for locks. - /// The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available - /// to Windows Store apps. - /// For more information, see . + /// The default constructor for a task is only present in order to allow tasks to be used within + /// containers. A default constructed task cannot be used until you assign a valid task to it. Methods such as + /// get, wait or then will throw an invalid_argument exception when called on a default constructed task. A task that is + /// created from a task_completion_event will complete (and have its continuations scheduled) when the + /// task completion event is set. The version of the constructor that takes a cancellation token + /// creates a task that can be canceled using the cancellation_token_source the token was obtained from. + /// Tasks created without a cancellation token are not cancelable. Tasks created from a + /// Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface + /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. + /// Similarly, tasks created from a lambda that returns a task<result_type> reach their terminal + /// state when the inner task reaches its terminal state, and not when the lambda returns. + /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by + /// multiple threads without the need for locks. The constructor overloads that take a + /// Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available to + /// Windows Store apps. For more information, see . /// /**/ template __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK gives us the expected result - explicit task(_Ty _Param) + explicit task(_Ty _Param) { task_options _TaskOptions; - details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param); + details::_ValidateTaskConstructorArgs<_ReturnType, _Ty>(_Param); _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler()); - // Do not move the next line out of this function. It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor. + // Do not move the next line out of this function. It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the + // the call site of the task constructor. _SetTaskCreationCallstack(PPLX_CAPTURE_CALLSTACK()); - _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0)); + _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0)); } /// @@ -3317,44 +3332,49 @@ class task /// The type of the parameter from which the task is to be constructed. /// /// - /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a task_completion_event<result_type> - /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function - /// object should be a type equivalent to std::function<X(void)>, where X can be a variable of type result_type, + /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a + /// task_completion_event<result_type> object, or a Windows::Foundation::IAsyncInfo if you are + /// using tasks in your Windows Store app. The lambda or function object should be a type equivalent to + /// std::function<X(void)>, where X can be a variable of type result_type, /// task<result_type>, or a Windows::Foundation::IAsyncInfo in Windows Store apps. /// /// /// The task options include cancellation token, scheduler etc /// /// - /// The default constructor for a task is only present in order to allow tasks to be used within containers. - /// A default constructed task cannot be used until you assign a valid task to it. Methods such as get, wait or then - /// will throw an invalid_argument exception when called on a default constructed task. - /// A task that is created from a task_completion_event will complete (and have its continuations scheduled) when the task - /// completion event is set. - /// The version of the constructor that takes a cancellation token creates a task that can be canceled using the - /// cancellation_token_source the token was obtained from. Tasks created without a cancellation token are not cancelable. - /// Tasks created from a Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface - /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created - /// from a lambda that returns a task<result_type> reach their terminal state when the inner task reaches its terminal state, - /// and not when the lambda returns. - /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads - /// without the need for locks. - /// The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available - /// to Windows Store apps. - /// For more information, see . + /// The default constructor for a task is only present in order to allow tasks to be used within + /// containers. A default constructed task cannot be used until you assign a valid task to it. Methods such as + /// get, wait or then will throw an invalid_argument exception when called on a default constructed task. A task that is + /// created from a task_completion_event will complete (and have its continuations scheduled) when the + /// task completion event is set. The version of the constructor that takes a cancellation token + /// creates a task that can be canceled using the cancellation_token_source the token was obtained from. + /// Tasks created without a cancellation token are not cancelable. Tasks created from a + /// Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface + /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. + /// Similarly, tasks created from a lambda that returns a task<result_type> reach their terminal + /// state when the inner task reaches its terminal state, and not when the lambda returns. + /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by + /// multiple threads without the need for locks. The constructor overloads that take a + /// Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available to + /// Windows Store apps. For more information, see . /// /**/ template __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK gives us the expected result - explicit task(_Ty _Param, const task_options &_TaskOptions) + explicit task(_Ty _Param, const task_options& _TaskOptions) { - details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param); + details::_ValidateTaskConstructorArgs<_ReturnType, _Ty>(_Param); _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler()); - // Do not move the next line out of this function. It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor. - _SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : PPLX_CAPTURE_CALLSTACK()); + // Do not move the next line out of this function. It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the + // the call site of the task constructor. + _SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack + ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack + : PPLX_CAPTURE_CALLSTACK()); - _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0)); + _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0)); } /// @@ -3364,25 +3384,26 @@ class task /// The source task object. /// /// - /// The default constructor for a task is only present in order to allow tasks to be used within containers. - /// A default constructed task cannot be used until you assign a valid task to it. Methods such as get, wait or then - /// will throw an invalid_argument exception when called on a default constructed task. - /// A task that is created from a task_completion_event will complete (and have its continuations scheduled) when the task - /// completion event is set. - /// The version of the constructor that takes a cancellation token creates a task that can be canceled using the - /// cancellation_token_source the token was obtained from. Tasks created without a cancellation token are not cancelable. - /// Tasks created from a Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface - /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created - /// from a lambda that returns a task<result_type> reach their terminal state when the inner task reaches its terminal state, - /// and not when the lambda returns. - /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads - /// without the need for locks. - /// The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available - /// to Windows Store apps. - /// For more information, see . + /// The default constructor for a task is only present in order to allow tasks to be used within + /// containers. A default constructed task cannot be used until you assign a valid task to it. Methods such as + /// get, wait or then will throw an invalid_argument exception when called on a default constructed task. A task that is + /// created from a task_completion_event will complete (and have its continuations scheduled) when the + /// task completion event is set. The version of the constructor that takes a cancellation token + /// creates a task that can be canceled using the cancellation_token_source the token was obtained from. + /// Tasks created without a cancellation token are not cancelable. Tasks created from a + /// Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface + /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. + /// Similarly, tasks created from a lambda that returns a task<result_type> reach their terminal + /// state when the inner task reaches its terminal state, and not when the lambda returns. + /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by + /// multiple threads without the need for locks. The constructor overloads that take a + /// Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available to + /// Windows Store apps. For more information, see . /// /**/ - task(const task& _Other): _M_Impl(_Other._M_Impl) {} + task(const task& _Other) : _M_Impl(_Other._M_Impl) {} /// /// Constructs a task object. @@ -3391,25 +3412,26 @@ class task /// The source task object. /// /// - /// The default constructor for a task is only present in order to allow tasks to be used within containers. - /// A default constructed task cannot be used until you assign a valid task to it. Methods such as get, wait or then - /// will throw an invalid_argument exception when called on a default constructed task. - /// A task that is created from a task_completion_event will complete (and have its continuations scheduled) when the task - /// completion event is set. - /// The version of the constructor that takes a cancellation token creates a task that can be canceled using the - /// cancellation_token_source the token was obtained from. Tasks created without a cancellation token are not cancelable. - /// Tasks created from a Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface - /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created - /// from a lambda that returns a task<result_type> reach their terminal state when the inner task reaches its terminal state, - /// and not when the lambda returns. - /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads - /// without the need for locks. - /// The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available - /// to Windows Store apps. - /// For more information, see . + /// The default constructor for a task is only present in order to allow tasks to be used within + /// containers. A default constructed task cannot be used until you assign a valid task to it. Methods such as + /// get, wait or then will throw an invalid_argument exception when called on a default constructed task. A task that is + /// created from a task_completion_event will complete (and have its continuations scheduled) when the + /// task completion event is set. The version of the constructor that takes a cancellation token + /// creates a task that can be canceled using the cancellation_token_source the token was obtained from. + /// Tasks created without a cancellation token are not cancelable. Tasks created from a + /// Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface + /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. + /// Similarly, tasks created from a lambda that returns a task<result_type> reach their terminal + /// state when the inner task reaches its terminal state, and not when the lambda returns. + /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by + /// multiple threads without the need for locks. The constructor overloads that take a + /// Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available to + /// Windows Store apps. For more information, see . /// /**/ - task(task&& _Other): _M_Impl(std::move(_Other._M_Impl)) {} + task(task&& _Other) : _M_Impl(std::move(_Other._M_Impl)) {} /// /// Replaces the contents of one task object with another. @@ -3418,8 +3440,8 @@ class task /// The source task object. /// /// - /// As task behaves like a smart pointer, after a copy assignment, this task objects represents the same - /// actual task as does. + /// As task behaves like a smart pointer, after a copy assignment, this task objects represents + /// the same actual task as does. /// /**/ task& operator=(const task& _Other) @@ -3438,8 +3460,8 @@ class task /// The source task object. /// /// - /// As task behaves like a smart pointer, after a copy assignment, this task objects represents the same - /// actual task as does. + /// As task behaves like a smart pointer, after a copy assignment, this task objects represents + /// the same actual task as does. /// /**/ task& operator=(task&& _Other) @@ -3459,21 +3481,23 @@ class task /// /// /// The continuation function to execute when this task completes. This continuation function must take as input - /// a variable of either result_type or task<result_type>, where result_type is the type - /// of the result this task produces. + /// a variable of either result_type or task<result_type>, where result_type is the + /// type of the result this task produces. /// /// - /// The newly created continuation task. The result type of the returned task is determined by what returns. + /// The newly created continuation task. The result type of the returned task is determined by what returns. /// /// - /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available - /// to Windows Store apps. - /// For more information on how to use task continuations to compose asynchronous work, see . + /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo + /// interface, are only available to Windows Store apps. For more information on how to use task + /// continuations to compose asynchronous work, see . /// /**/ template __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK gives us the expected result - auto then(_Function&& _Func) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType + auto then(_Function&& _Func) const -> + typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType { task_options _TaskOptions; details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(PPLX_CAPTURE_CALLSTACK()); @@ -3488,25 +3512,27 @@ class task /// /// /// The continuation function to execute when this task completes. This continuation function must take as input - /// a variable of either result_type or task<result_type>, where result_type is the type - /// of the result this task produces. + /// a variable of either result_type or task<result_type>, where result_type is the + /// type of the result this task produces. /// /// /// The task options include cancellation token, scheduler and continuation context. By default the former 3 /// options are inherited from the antecedent task /// /// - /// The newly created continuation task. The result type of the returned task is determined by what returns. + /// The newly created continuation task. The result type of the returned task is determined by what returns. /// /// - /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available - /// to Windows Store apps. - /// For more information on how to use task continuations to compose asynchronous work, see . + /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo + /// interface, are only available to Windows Store apps. For more information on how to use task + /// continuations to compose asynchronous work, see . /// /**/ template __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK gives us the expected result - auto then(_Function&& _Func, task_options _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType + auto then(_Function&& _Func, task_options _TaskOptions) const -> + typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType { details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(PPLX_CAPTURE_CALLSTACK()); return _ThenImpl<_ReturnType, _Function>(std::forward<_Function>(_Func), _TaskOptions); @@ -3520,29 +3546,34 @@ class task /// /// /// The continuation function to execute when this task completes. This continuation function must take as input - /// a variable of either result_type or task<result_type>, where result_type is the type - /// of the result this task produces. + /// a variable of either result_type or task<result_type>, where result_type is the + /// type of the result this task produces. /// /// - /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit - /// the token of its antecedent task. + /// The cancellation token to associate with the continuation task. A continuation task that is created without + /// a cancellation token will inherit the token of its antecedent task. /// /// - /// A variable that specifies where the continuation should execute. This variable is only useful when used in a Windows Store - /// style app. For more information, see task_continuation_context + /// A variable that specifies where the continuation should execute. This variable is only useful when used in a + /// Windows Store style app. For more information, see task_continuation_context /// /// - /// The newly created continuation task. The result type of the returned task is determined by what returns. + /// The newly created continuation task. The result type of the returned task is determined by what returns. /// /// - /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available - /// to Windows Store apps. - /// For more information on how to use task continuations to compose asynchronous work, see . + /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo + /// interface, are only available to Windows Store apps. For more information on how to use task + /// continuations to compose asynchronous work, see . /// /**/ template __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK gives us the expected result - auto then(_Function&& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType + auto then(_Function&& _Func, + cancellation_token _CancellationToken, + task_continuation_context _ContinuationContext) const -> + typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType { task_options _TaskOptions(_CancellationToken, _ContinuationContext); details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(PPLX_CAPTURE_CALLSTACK()); @@ -3550,12 +3581,14 @@ class task } /// - /// Waits for this task to reach a terminal state. It is possible for wait to execute the task inline, if all of the tasks - /// dependencies are satisfied, and it has not already been picked up for execution by a background worker. + /// Waits for this task to reach a terminal state. It is possible for wait to execute the task inline, if + /// all of the tasks dependencies are satisfied, and it has not already been picked up for execution by a + /// background worker. /// /// - /// A task_status value which could be either completed or canceled. If the task encountered an exception - /// during execution, or an exception was propagated to it from an antecedent task, wait will throw that exception. + /// A task_status value which could be either completed or canceled. If the task + /// encountered an exception during execution, or an exception was propagated to it from an antecedent task, + /// wait will throw that exception. /// /**/ task_status wait() const @@ -3569,15 +3602,17 @@ class task } /// - /// Returns the result this task produced. If the task is not in a terminal state, a call to get will wait for the task to - /// finish. This method does not return a value when called on a task with a result_type of void. + /// Returns the result this task produced. If the task is not in a terminal state, a call to get will + /// wait for the task to finish. This method does not return a value when called on a task with a + /// result_type of void. /// /// /// The result of the task. /// /// - /// If the task is canceled, a call to get will throw a task_canceled exception. If the task - /// encountered an different exception or an exception was propagated to it from an antecedent task, a call to get will throw that exception. + /// If the task is canceled, a call to get will throw a task_canceled exception. If the task encountered an different exception or an exception was + /// propagated to it from an antecedent task, a call to get will throw that exception. /// /**/ _ReturnType get() const @@ -3631,10 +3666,12 @@ class task } /// - /// Determines whether the task unwraps a Windows Runtime IAsyncInfo interface or is descended from such a task. + /// Determines whether the task unwraps a Windows Runtime IAsyncInfo interface or is descended from such + /// a task. /// /// - /// true if the task unwraps an IAsyncInfo interface or is descended from such a task, false otherwise. + /// true if the task unwraps an IAsyncInfo interface or is descended from such a task, + /// false otherwise. /// /**/ bool is_apartment_aware() const @@ -3653,10 +3690,7 @@ class task /// true if the objects refer to the same underlying task, and false otherwise. /// /**/ - bool operator==(const task<_ReturnType>& _Rhs) const - { - return (_M_Impl == _Rhs._M_Impl); - } + bool operator==(const task<_ReturnType>& _Rhs) const { return (_M_Impl == _Rhs._M_Impl); } /// /// Determines whether two task objects represent different internal tasks. @@ -3665,15 +3699,12 @@ class task /// true if the objects refer to different underlying tasks, and false otherwise. /// /**/ - bool operator!=(const task<_ReturnType>& _Rhs) const - { - return !operator==(_Rhs); - } + bool operator!=(const task<_ReturnType>& _Rhs) const { return !operator==(_Rhs); } /// /// Create an underlying task implementation. /// - void _CreateImpl(details::_CancellationTokenState * _Ct, scheduler_ptr _Scheduler) + void _CreateImpl(details::_CancellationTokenState* _Ct, scheduler_ptr _Scheduler) { _ASSERTE(_Ct != nullptr); _M_Impl = details::_Task_ptr<_ReturnType>::_Make(_Ct, _Scheduler); @@ -3686,15 +3717,12 @@ class task /// /// Return the underlying implementation for this task. /// - const typename details::_Task_ptr<_ReturnType>::_Type & _GetImpl() const - { - return _M_Impl; - } + const typename details::_Task_ptr<_ReturnType>::_Type& _GetImpl() const { return _M_Impl; } /// /// Set the implementation of the task to be the supplied implementation. /// - void _SetImpl(const typename details::_Task_ptr<_ReturnType>::_Type & _Impl) + void _SetImpl(const typename details::_Task_ptr<_ReturnType>::_Type& _Impl) { _ASSERTE(!_M_Impl); _M_Impl = _Impl; @@ -3703,7 +3731,7 @@ class task /// /// Set the implementation of the task to be the supplied implementation using a move instead of a copy. /// - void _SetImpl(typename details::_Task_ptr<_ReturnType>::_Type && _Impl) + void _SetImpl(typename details::_Task_ptr<_ReturnType>::_Type&& _Impl) { _ASSERTE(!_M_Impl); _M_Impl = std::move(_Impl); @@ -3712,69 +3740,72 @@ class task /// /// Sets a property determining whether the task is apartment aware. /// - void _SetAsync(bool _Async = true) - { - _GetImpl()->_SetAsync(_Async); - } + void _SetAsync(bool _Async = true) { _GetImpl()->_SetAsync(_Async); } /// - /// Sets a field in the task impl to the return callstack for calls to the task constructors and the then method. + /// Sets a field in the task impl to the return callstack for calls to the task constructors and the then + /// method. /// - void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack) + void _SetTaskCreationCallstack(const details::_TaskCreationCallstack& _callstack) { _GetImpl()->_SetTaskCreationCallstack(_callstack); } /// - /// An internal version of then that takes additional flags and always execute the continuation inline by default. - /// When _ForceInline is set to false, continuations inlining will be limited to default _DefaultAutoInline. - /// This function is Used for runtime internal continuations only. + /// An internal version of then that takes additional flags and always execute the continuation inline by + /// default. When _ForceInline is set to false, continuations inlining will be limited to default + /// _DefaultAutoInline. This function is Used for runtime internal continuations only. /// template - auto _Then(_Function&& _Func, details::_CancellationTokenState *_PTokenState, - details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType + auto _Then(_Function&& _Func, + details::_CancellationTokenState* _PTokenState, + details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> + typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType { // inherit from antecedent auto _Scheduler = _GetImpl()->_GetScheduler(); - return _ThenImpl<_ReturnType, _Function>(std::forward<_Function>(_Func), _PTokenState, task_continuation_context::use_default(), _Scheduler, PPLX_CAPTURE_CALLSTACK(), _InliningMode); + return _ThenImpl<_ReturnType, _Function>(std::forward<_Function>(_Func), + _PTokenState, + task_continuation_context::use_default(), + _Scheduler, + PPLX_CAPTURE_CALLSTACK(), + _InliningMode); } private: - template friend class task; - + template + friend class task; // The task handle type used to construct an 'initial task' - a task with no dependents. - template - struct _InitialTaskHandle : - details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t> + template + struct _InitialTaskHandle + : details::_PPLTaskHandle<_ReturnType, + _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, + details::_UnrealizedChore_t> { _Function _M_function; - _InitialTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _TaskImpl, const _Function & _func) - : details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t>::_PPLTaskHandle(_TaskImpl) + _InitialTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type& _TaskImpl, const _Function& _func) + : details::_PPLTaskHandle<_ReturnType, + _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, + details::_UnrealizedChore_t>::_PPLTaskHandle(_TaskImpl) , _M_function(_func) { } virtual ~_InitialTaskHandle() {} - template - auto _LogWorkItemAndInvokeUserLambda(_Func && _func) const -> decltype(_func()) + template + auto _LogWorkItemAndInvokeUserLambda(_Func&& _func) const -> decltype(_func()) { details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger); CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem); return _func(); } - void _Perform() const - { - _Init(_TypeSelection()); - } + void _Perform() const { _Init(_TypeSelection()); } - void _SyncCancelAndPropagateException() const - { - this->_M_pTask->_Cancel(true); - } + void _SyncCancelAndPropagateException() const { this->_M_pTask->_Cancel(true); } // // Overload 0: returns _InternalReturnType @@ -3783,7 +3814,8 @@ class task // void _Init(details::_TypeSelectorNoAsync) const { - this->_M_pTask->_FinalizeAndRunContinuations(_LogWorkItemAndInvokeUserLambda(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function))); + this->_M_pTask->_FinalizeAndRunContinuations( + _LogWorkItemAndInvokeUserLambda(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function))); } // @@ -3796,10 +3828,11 @@ class task // void _Init(details::_TypeSelectorAsyncOperationOrTask) const { - details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, _LogWorkItemAndInvokeUserLambda(_M_function)); + details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>( + this->_M_pTask, _LogWorkItemAndInvokeUserLambda(_M_function)); } -#if defined (__cplusplus_winrt) +#if defined(__cplusplus_winrt) // // Overload 2: returns IAsyncAction^ // @@ -3807,7 +3840,9 @@ class task // void _Init(details::_TypeSelectorAsyncAction) const { - details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function))); + details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>( + this->_M_pTask, + ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function))); } // @@ -3819,8 +3854,11 @@ class task { typedef details::_GetProgressType::_Value _ProgressType; - details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, - ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType,_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function))); + details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>( + this->_M_pTask, + ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType, + _ProgressType>( + _LogWorkItemAndInvokeUserLambda(_M_function))); } // @@ -3832,35 +3870,53 @@ class task { typedef details::_GetProgressType::_Value _ProgressType; - details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, - ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function))); + details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>( + this->_M_pTask, + ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>( + _LogWorkItemAndInvokeUserLambda(_M_function))); } -#endif /* defined (__cplusplus_winrt) */ +#endif /* defined (__cplusplus_winrt) */ }; - /// /// The task handle type used to create a 'continuation task'. /// - template - struct _ContinuationTaskHandle : - details::_PPLTaskHandle::_Type, - _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase> - { - typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type _NormalizedContinuationReturnType; + template + struct _ContinuationTaskHandle + : details::_PPLTaskHandle::_Type, + _ContinuationTaskHandle<_InternalReturnType, + _ContinuationReturnType, + _Function, + _IsTaskBased, + _TypeSelection>, + details::_ContinuationTaskHandleBase> + { + typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type + _NormalizedContinuationReturnType; typename details::_Task_ptr<_ReturnType>::_Type _M_ancestorTaskImpl; - typename details::_CopyableFunctor::type >::_Type _M_function; - - template - _ContinuationTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _AncestorImpl, - const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type & _ContinuationImpl, - _ForwardedFunction&& _Func, const task_continuation_context & _Context, details::_TaskInliningMode_t _InliningMode) - : details::_PPLTaskHandle::_Type, - _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase> - ::_PPLTaskHandle(_ContinuationImpl) - , _M_ancestorTaskImpl(_AncestorImpl) - , _M_function(std::forward<_ForwardedFunction>(_Func)) + typename details::_CopyableFunctor::type>::_Type _M_function; + + template + _ContinuationTaskHandle( + const typename details::_Task_ptr<_ReturnType>::_Type& _AncestorImpl, + const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type& _ContinuationImpl, + _ForwardedFunction&& _Func, + const task_continuation_context& _Context, + details::_TaskInliningMode_t _InliningMode) + : details::_PPLTaskHandle::_Type, + _ContinuationTaskHandle<_InternalReturnType, + _ContinuationReturnType, + _Function, + _IsTaskBased, + _TypeSelection>, + details::_ContinuationTaskHandleBase>::_PPLTaskHandle(_ContinuationImpl) + , _M_ancestorTaskImpl(_AncestorImpl) + , _M_function(std::forward<_ForwardedFunction>(_Func)) { this->_M_isTaskBasedContinuation = _IsTaskBased::value; this->_M_continuationContext = _Context; @@ -3870,18 +3926,16 @@ class task virtual ~_ContinuationTaskHandle() {} - template - auto _LogWorkItemAndInvokeUserLambda(_Func && _func, _Arg && _value) const -> decltype(_func(std::forward<_Arg>(_value))) + template + auto _LogWorkItemAndInvokeUserLambda(_Func&& _func, _Arg&& _value) const + -> decltype(_func(std::forward<_Arg>(_value))) { details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger); CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem); return _func(std::forward<_Arg>(_value)); } - void _Perform() const - { - _Continue(_IsTaskBased(), _TypeSelection()); - } + void _Perform() const { _Continue(_IsTaskBased(), _TypeSelection()); } void _SyncCancelAndPropagateException() const { @@ -3906,8 +3960,9 @@ class task // void _Continue(std::false_type, details::_TypeSelectorNoAsync) const { - this->_M_pTask->_FinalizeAndRunContinuations( - _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult())); + this->_M_pTask->_FinalizeAndRunContinuations(_LogWorkItemAndInvokeUserLambda( + _Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function), + _M_ancestorTaskImpl->_GetResult())); } // @@ -3915,8 +3970,8 @@ class task // or // _InternalReturnType -> task<_TaskType> // - // This is a straight task continuation which returns an async operation or a task which will be unwrapped for continuation - // Depending on the output type, the right _AsyncInit gets invoked + // This is a straight task continuation which returns an async operation or a task which will be unwrapped for + // continuation Depending on the output type, the right _AsyncInit gets invoked // void _Continue(std::false_type, details::_TypeSelectorAsyncOperationOrTask) const { @@ -3924,11 +3979,12 @@ class task details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( this->_M_pTask, - _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult()) - ); + _LogWorkItemAndInvokeUserLambda( + _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), + _M_ancestorTaskImpl->_GetResult())); } -#if defined (__cplusplus_winrt) +#if defined(__cplusplus_winrt) // // Overload 0-2: _InternalReturnType -> IAsyncAction^ // @@ -3940,37 +3996,45 @@ class task details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( this->_M_pTask, - ref new details::_IAsyncActionToAsyncOperationConverter( - _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult()))); + ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda( + _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), + _M_ancestorTaskImpl->_GetResult()))); } // // Overload 0-3: _InternalReturnType -> IAsyncOperationWithProgress<_TaskType, _ProgressType>^ // - // This is a straight task continuation which returns an async operation with progress which will be unwrapped for continuation + // This is a straight task continuation which returns an async operation with progress which will be unwrapped + // for continuation // void _Continue(std::false_type, details::_TypeSelectorAsyncOperationWithProgress) const { typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType; - auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult()); + auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda( + _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), + _M_ancestorTaskImpl->_GetResult()); typedef details::_GetProgressType::_Value _ProgressType; details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( this->_M_pTask, - ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>(_OpWithProgress)); + ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, + _ProgressType>(_OpWithProgress)); } // // Overload 0-4: _InternalReturnType -> IAsyncActionWithProgress<_ProgressType>^ // - // This is a straight task continuation which returns an async action with progress which will be unwrapped for continuation + // This is a straight task continuation which returns an async action with progress which will be unwrapped for + // continuation // void _Continue(std::false_type, details::_TypeSelectorAsyncActionWithProgress) const { typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType; - auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult()); + auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda( + _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), + _M_ancestorTaskImpl->_GetResult()); typedef details::_GetProgressType::_Value _ProgressType; details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( @@ -3978,7 +4042,7 @@ class task ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_OpWithProgress)); } -#endif /* defined (__cplusplus_winrt) */ +#endif /* defined (__cplusplus_winrt) */ // // Overload 1-0: task<_InternalReturnType> -> _TaskType @@ -3990,8 +4054,9 @@ class task typedef task<_InternalReturnType> _FuncInputType; task<_InternalReturnType> _ResultTask; _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl)); - this->_M_pTask->_FinalizeAndRunContinuations( - _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function), std::move(_ResultTask))); + this->_M_pTask->_FinalizeAndRunContinuations(_LogWorkItemAndInvokeUserLambda( + _Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function), + std::move(_ResultTask))); } // @@ -4008,11 +4073,11 @@ class task // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task. task<_InternalReturnType> _ResultTask; _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl)); - details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask, - _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))); + details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( + this->_M_pTask, _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))); } -#if defined (__cplusplus_winrt) +#if defined(__cplusplus_winrt) // // Overload 1-2: task<_InternalReturnType> -> IAsyncAction^ @@ -4025,8 +4090,10 @@ class task // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task. task<_InternalReturnType> _ResultTask; _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl)); - details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask, - ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask)))); + details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( + this->_M_pTask, + ref new details::_IAsyncActionToAsyncOperationConverter( + _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask)))); } // @@ -4044,8 +4111,10 @@ class task typedef details::_GetProgressType::_Value _ProgressType; - details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask, - ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>( + details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( + this->_M_pTask, + ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, + _ProgressType>( _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask)))); } @@ -4064,11 +4133,12 @@ class task typedef details::_GetProgressType::_Value _ProgressType; - details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask, - ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>( + details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( + this->_M_pTask, + ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>( _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask)))); } -#endif /* defined (__cplusplus_winrt) */ +#endif /* defined (__cplusplus_winrt) */ }; /// @@ -4082,27 +4152,29 @@ class task _M_Impl->_M_fFromAsync = _Async_type_traits::_IsAsyncTask; _M_Impl->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync; _M_Impl->_M_taskEventLogger._LogScheduleTask(false); - _M_Impl->_ScheduleTask(new _InitialTaskHandle<_InternalReturnType, _Function, typename _Async_type_traits::_AsyncKind>(_GetImpl(), _Func), details::_NoInline); + _M_Impl->_ScheduleTask( + new _InitialTaskHandle<_InternalReturnType, _Function, typename _Async_type_traits::_AsyncKind>(_GetImpl(), + _Func), + details::_NoInline); } /// /// Initializes a task using a task completion event. /// - void _TaskInitNoFunctor(task_completion_event<_ReturnType>& _Event) - { - _Event._RegisterTask(_M_Impl); - } + void _TaskInitNoFunctor(task_completion_event<_ReturnType>& _Event) { _Event._RegisterTask(_M_Impl); } -#if defined (__cplusplus_winrt) +#if defined(__cplusplus_winrt) /// /// Initializes a task using an asynchronous operation IAsyncOperation^ /// - void _TaskInitAsyncOp(Windows::Foundation::IAsyncOperation::_Value>^ _AsyncOp) + void _TaskInitAsyncOp( + Windows::Foundation::IAsyncOperation::_Value> ^ _AsyncOp) { _M_Impl->_M_fFromAsync = true; - // Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once _AsyncInit - // returns a completion could execute concurrently and the task must be fully initialized before that happens. + // Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once + // _AsyncInit returns a completion could execute concurrently and the task must be fully initialized before that + // happens. _M_Impl->_M_TaskState = details::_Task_impl_base::_Started; // Pass the shared pointer into _AsyncInit for storage in the Async Callback. details::_Task_impl_base::_AsyncInit<_ReturnType, _ReturnType>(_M_Impl, _AsyncOp); @@ -4111,7 +4183,8 @@ class task /// /// Initializes a task using an asynchronous operation IAsyncOperation^ /// - void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperation::_Value>^ _AsyncOp) + void _TaskInitNoFunctor( + Windows::Foundation::IAsyncOperation::_Value> ^ _AsyncOp) { _TaskInitAsyncOp(_AsyncOp); } @@ -4120,17 +4193,22 @@ class task /// Initializes a task using an asynchronous operation with progress IAsyncOperationWithProgress^ /// template - void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperationWithProgress::_Value, _Progress>^ _AsyncOp) - { - _TaskInitAsyncOp(ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter::_Value, _Progress>(_AsyncOp)); + void _TaskInitNoFunctor( + Windows::Foundation::IAsyncOperationWithProgress::_Value, + _Progress> ^ + _AsyncOp) + { + _TaskInitAsyncOp(ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter< + typename details::_ValueTypeOrRefType<_ReturnType>::_Value, + _Progress>(_AsyncOp)); } -#endif /* defined (__cplusplus_winrt) */ +#endif /* defined (__cplusplus_winrt) */ /// /// Initializes a task using a callable object. /// template - void _TaskInitMaybeFunctor(_Function & _Func, std::true_type) + void _TaskInitMaybeFunctor(_Function& _Func, std::true_type) { _TaskInitWithFunctor<_ReturnType, _Function>(_Func); } @@ -4139,31 +4217,44 @@ class task /// Initializes a task using a non-callable object. /// template - void _TaskInitMaybeFunctor(_Ty & _Param, std::false_type) + void _TaskInitMaybeFunctor(_Ty& _Param, std::false_type) { _TaskInitNoFunctor(_Param); } template - auto _ThenImpl(_Function&& _Func, const task_options& _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType + auto _ThenImpl(_Function&& _Func, const task_options& _TaskOptions) const -> + typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType { if (!_M_Impl) { throw invalid_operation("then() cannot be called on a default constructed task."); } - details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; + details::_CancellationTokenState* _PTokenState = + _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; auto _Scheduler = _TaskOptions.has_scheduler() ? _TaskOptions.get_scheduler() : _GetImpl()->_GetScheduler(); - auto _CreationStack = details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : details::_TaskCreationCallstack(); - return _ThenImpl<_InternalReturnType, _Function>(std::forward<_Function>(_Func), _PTokenState, _TaskOptions.get_continuation_context(), _Scheduler, _CreationStack); + auto _CreationStack = details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack + ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack + : details::_TaskCreationCallstack(); + return _ThenImpl<_InternalReturnType, _Function>(std::forward<_Function>(_Func), + _PTokenState, + _TaskOptions.get_continuation_context(), + _Scheduler, + _CreationStack); } /// /// The one and only implementation of then for void and non-void tasks. /// template - auto _ThenImpl(_Function&& _Func, details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext, scheduler_ptr _Scheduler, details::_TaskCreationCallstack _CreationStack, - details::_TaskInliningMode_t _InliningMode = details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType + auto _ThenImpl(_Function&& _Func, + details::_CancellationTokenState* _PTokenState, + const task_continuation_context& _ContinuationContext, + scheduler_ptr _Scheduler, + details::_TaskCreationCallstack _CreationStack, + details::_TaskInliningMode_t _InliningMode = details::_NoInline) const -> + typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType { if (!_M_Impl) { @@ -4175,9 +4266,9 @@ class task typedef typename _Async_type_traits::_TaskRetType _TaskType; // - // A **nullptr** token state indicates that it was not provided by the user. In this case, we inherit the antecedent's token UNLESS this is a - // an exception handling continuation. In that case, we break the chain with a _None. That continuation is never canceled unless the user - // explicitly passes the same token. + // A **nullptr** token state indicates that it was not provided by the user. In this case, we inherit the + // antecedent's token UNLESS this is a an exception handling continuation. In that case, we break the chain with + // a _None. That continuation is never canceled unless the user explicitly passes the same token. // if (_PTokenState == nullptr) { @@ -4198,8 +4289,16 @@ class task _ContinuationTask._GetImpl()->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync; _ContinuationTask._SetTaskCreationCallstack(_CreationStack); - _GetImpl()->_ScheduleContinuation(new _ContinuationTaskHandle<_InternalReturnType, _TaskType, _Function, typename _Function_type_traits::_Takes_task, typename _Async_type_traits::_AsyncKind>( - _GetImpl(), _ContinuationTask._GetImpl(), std::forward<_Function>(_Func), _ContinuationContext, _InliningMode)); + _GetImpl()->_ScheduleContinuation( + new _ContinuationTaskHandle<_InternalReturnType, + _TaskType, + _Function, + typename _Function_type_traits::_Takes_task, + typename _Async_type_traits::_AsyncKind>(_GetImpl(), + _ContinuationTask._GetImpl(), + std::forward<_Function>(_Func), + _ContinuationContext, + _InliningMode)); return _ContinuationTask; } @@ -4209,11 +4308,12 @@ class task }; /// -/// The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed asynchronously, -/// and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces -/// a result of type on successful completion. Tasks of type task<void> produce no result. -/// A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using -/// continuations(then), and join(when_all) and choice(when_any) patterns. +/// The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed +/// asynchronously, and concurrently with other tasks and parallel work produced by parallel algorithms in the +/// Concurrency Runtime. It produces a result of type on successful completion. +/// Tasks of type task<void> produce no result. A task can be waited upon and canceled independently of +/// other tasks. It can also be composed with other tasks using continuations(then), and +/// join(when_all) and choice(when_any) patterns. /// /// /// For more information, see . @@ -4233,22 +4333,23 @@ class task /// Constructs a task object. /// /// - /// The default constructor for a task is only present in order to allow tasks to be used within containers. - /// A default constructed task cannot be used until you assign a valid task to it. Methods such as get, wait or then - /// will throw an invalid_argument exception when called on a default constructed task. - /// A task that is created from a task_completion_event will complete (and have its continuations scheduled) when the task - /// completion event is set. - /// The version of the constructor that takes a cancellation token creates a task that can be canceled using the - /// cancellation_token_source the token was obtained from. Tasks created without a cancellation token are not cancelable. - /// Tasks created from a Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface - /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created - /// from a lambda that returns a task<result_type> reach their terminal state when the inner task reaches its terminal state, - /// and not when the lambda returns. - /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads - /// without the need for locks. - /// The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available - /// to Windows Store apps. - /// For more information, see . + /// The default constructor for a task is only present in order to allow tasks to be used within + /// containers. A default constructed task cannot be used until you assign a valid task to it. Methods such as + /// get, wait or then will throw an invalid_argument exception when called on a default constructed task. A task that is + /// created from a task_completion_event will complete (and have its continuations scheduled) when the + /// task completion event is set. The version of the constructor that takes a cancellation token + /// creates a task that can be canceled using the cancellation_token_source the token was obtained from. + /// Tasks created without a cancellation token are not cancelable. Tasks created from a + /// Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface + /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. + /// Similarly, tasks created from a lambda that returns a task<result_type> reach their terminal + /// state when the inner task reaches its terminal state, and not when the lambda returns. + /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by + /// multiple threads without the need for locks. The constructor overloads that take a + /// Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available to + /// Windows Store apps. For more information, see . /// /**/ task() : _M_unitTask() @@ -4264,41 +4365,47 @@ class task /// The type of the parameter from which the task is to be constructed. /// /// - /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a task_completion_event<result_type> - /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function - /// object should be a type equivalent to std::function<X(void)>, where X can be a variable of type result_type, + /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a + /// task_completion_event<result_type> object, or a Windows::Foundation::IAsyncInfo if you are + /// using tasks in your Windows Store app. The lambda or function object should be a type equivalent to + /// std::function<X(void)>, where X can be a variable of type result_type, /// task<result_type>, or a Windows::Foundation::IAsyncInfo in Windows Store apps. /// /// - /// The default constructor for a task is only present in order to allow tasks to be used within containers. - /// A default constructed task cannot be used until you assign a valid task to it. Methods such as get, wait or then - /// will throw an invalid_argument exception when called on a default constructed task. - /// A task that is created from a task_completion_event will complete (and have its continuations scheduled) when the task - /// completion event is set. - /// The version of the constructor that takes a cancellation token creates a task that can be canceled using the - /// cancellation_token_source the token was obtained from. Tasks created without a cancellation token are not cancelable. - /// Tasks created from a Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface - /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created - /// from a lambda that returns a task<result_type> reach their terminal state when the inner task reaches its terminal state, - /// and not when the lambda returns. - /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads - /// without the need for locks. - /// The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available - /// to Windows Store apps. - /// For more information, see . + /// The default constructor for a task is only present in order to allow tasks to be used within + /// containers. A default constructed task cannot be used until you assign a valid task to it. Methods such as + /// get, wait or then will throw an invalid_argument exception when called on a default constructed task. A task that is + /// created from a task_completion_event will complete (and have its continuations scheduled) when the + /// task completion event is set. The version of the constructor that takes a cancellation token + /// creates a task that can be canceled using the cancellation_token_source the token was obtained from. + /// Tasks created without a cancellation token are not cancelable. Tasks created from a + /// Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface + /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. + /// Similarly, tasks created from a lambda that returns a task<result_type> reach their terminal + /// state when the inner task reaches its terminal state, and not when the lambda returns. + /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by + /// multiple threads without the need for locks. The constructor overloads that take a + /// Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available to + /// Windows Store apps. For more information, see . /// /**/ template __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK gives us the expected result - explicit task(_Ty _Param, const task_options& _TaskOptions = task_options()) + explicit task(_Ty _Param, const task_options& _TaskOptions = task_options()) { - details::_ValidateTaskConstructorArgs(_Param); + details::_ValidateTaskConstructorArgs(_Param); _M_unitTask._CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler()); - // Do not move the next line out of this function. It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor. - _M_unitTask._SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : PPLX_CAPTURE_CALLSTACK()); - - _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0)); + // Do not move the next line out of this function. It is important that PPLX_CAPTURE_CALLSTACK() evaluate to the + // the call site of the task constructor. + _M_unitTask._SetTaskCreationCallstack( + details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack + ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack + : PPLX_CAPTURE_CALLSTACK()); + + _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0)); } /// @@ -4308,25 +4415,26 @@ class task /// The source task object. /// /// - /// The default constructor for a task is only present in order to allow tasks to be used within containers. - /// A default constructed task cannot be used until you assign a valid task to it. Methods such as get, wait or then - /// will throw an invalid_argument exception when called on a default constructed task. - /// A task that is created from a task_completion_event will complete (and have its continuations scheduled) when the task - /// completion event is set. - /// The version of the constructor that takes a cancellation token creates a task that can be canceled using the - /// cancellation_token_source the token was obtained from. Tasks created without a cancellation token are not cancelable. - /// Tasks created from a Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface - /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created - /// from a lambda that returns a task<result_type> reach their terminal state when the inner task reaches its terminal state, - /// and not when the lambda returns. - /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads - /// without the need for locks. - /// The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available - /// to Windows Store apps. - /// For more information, see . + /// The default constructor for a task is only present in order to allow tasks to be used within + /// containers. A default constructed task cannot be used until you assign a valid task to it. Methods such as + /// get, wait or then will throw an invalid_argument exception when called on a default constructed task. A task that is + /// created from a task_completion_event will complete (and have its continuations scheduled) when the + /// task completion event is set. The version of the constructor that takes a cancellation token + /// creates a task that can be canceled using the cancellation_token_source the token was obtained from. + /// Tasks created without a cancellation token are not cancelable. Tasks created from a + /// Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface + /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. + /// Similarly, tasks created from a lambda that returns a task<result_type> reach their terminal + /// state when the inner task reaches its terminal state, and not when the lambda returns. + /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by + /// multiple threads without the need for locks. The constructor overloads that take a + /// Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available to + /// Windows Store apps. For more information, see . /// /**/ - task(const task& _Other): _M_unitTask(_Other._M_unitTask){} + task(const task& _Other) : _M_unitTask(_Other._M_unitTask) {} /// /// Constructs a task object. @@ -4335,22 +4443,23 @@ class task /// The source task object. /// /// - /// The default constructor for a task is only present in order to allow tasks to be used within containers. - /// A default constructed task cannot be used until you assign a valid task to it. Methods such as get, wait or then - /// will throw an invalid_argument exception when called on a default constructed task. - /// A task that is created from a task_completion_event will complete (and have its continuations scheduled) when the task - /// completion event is set. - /// The version of the constructor that takes a cancellation token creates a task that can be canceled using the - /// cancellation_token_source the token was obtained from. Tasks created without a cancellation token are not cancelable. - /// Tasks created from a Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface - /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created - /// from a lambda that returns a task<result_type> reach their terminal state when the inner task reaches its terminal state, - /// and not when the lambda returns. - /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads - /// without the need for locks. - /// The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available - /// to Windows Store apps. - /// For more information, see . + /// The default constructor for a task is only present in order to allow tasks to be used within + /// containers. A default constructed task cannot be used until you assign a valid task to it. Methods such as + /// get, wait or then will throw an invalid_argument exception when called on a default constructed task. A task that is + /// created from a task_completion_event will complete (and have its continuations scheduled) when the + /// task completion event is set. The version of the constructor that takes a cancellation token + /// creates a task that can be canceled using the cancellation_token_source the token was obtained from. + /// Tasks created without a cancellation token are not cancelable. Tasks created from a + /// Windows::Foundation::IAsyncInfo interface or a lambda that returns an IAsyncInfo interface + /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. + /// Similarly, tasks created from a lambda that returns a task<result_type> reach their terminal + /// state when the inner task reaches its terminal state, and not when the lambda returns. + /// task behaves like a smart pointer and is safe to pass around by value. It can be accessed by + /// multiple threads without the need for locks. The constructor overloads that take a + /// Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available to + /// Windows Store apps. For more information, see . /// /**/ task(task&& _Other) : _M_unitTask(std::move(_Other._M_unitTask)) {} @@ -4362,8 +4471,8 @@ class task /// The source task object. /// /// - /// As task behaves like a smart pointer, after a copy assignment, this task objects represents the same - /// actual task as does. + /// As task behaves like a smart pointer, after a copy assignment, this task objects represents + /// the same actual task as does. /// /**/ task& operator=(const task& _Other) @@ -4382,8 +4491,8 @@ class task /// The source task object. /// /// - /// As task behaves like a smart pointer, after a copy assignment, this task objects represents the same - /// actual task as does. + /// As task behaves like a smart pointer, after a copy assignment, this task objects represents + /// the same actual task as does. /// /**/ task& operator=(task&& _Other) @@ -4403,25 +4512,27 @@ class task /// /// /// The continuation function to execute when this task completes. This continuation function must take as input - /// a variable of either result_type or task<result_type>, where result_type is the type - /// of the result this task produces. + /// a variable of either result_type or task<result_type>, where result_type is the + /// type of the result this task produces. /// /// - /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit - /// the token of its antecedent task. + /// The cancellation token to associate with the continuation task. A continuation task that is created without + /// a cancellation token will inherit the token of its antecedent task. /// /// - /// The newly created continuation task. The result type of the returned task is determined by what returns. + /// The newly created continuation task. The result type of the returned task is determined by what returns. /// /// - /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available - /// to Windows Store apps. - /// For more information on how to use task continuations to compose asynchronous work, see . + /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo + /// interface, are only available to Windows Store apps. For more information on how to use task + /// continuations to compose asynchronous work, see . /// /**/ template __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK gives us the expected result - auto then(_Function&& _Func, task_options _TaskOptions = task_options()) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType + auto then(_Function&& _Func, task_options _TaskOptions = task_options()) const -> + typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType { details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(PPLX_CAPTURE_CALLSTACK()); return _M_unitTask._ThenImpl(std::forward<_Function>(_Func), _TaskOptions); @@ -4435,29 +4546,34 @@ class task /// /// /// The continuation function to execute when this task completes. This continuation function must take as input - /// a variable of either result_type or task<result_type>, where result_type is the type - /// of the result this task produces. + /// a variable of either result_type or task<result_type>, where result_type is the + /// type of the result this task produces. /// /// - /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit - /// the token of its antecedent task. + /// The cancellation token to associate with the continuation task. A continuation task that is created without + /// a cancellation token will inherit the token of its antecedent task. /// /// - /// A variable that specifies where the continuation should execute. This variable is only useful when used in a Windows Store - /// style app. For more information, see task_continuation_context + /// A variable that specifies where the continuation should execute. This variable is only useful when used in a + /// Windows Store style app. For more information, see task_continuation_context /// /// - /// The newly created continuation task. The result type of the returned task is determined by what returns. + /// The newly created continuation task. The result type of the returned task is determined by what returns. /// /// - /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available - /// to Windows Store apps. - /// For more information on how to use task continuations to compose asynchronous work, see . + /// The overloads of then that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo + /// interface, are only available to Windows Store apps. For more information on how to use task + /// continuations to compose asynchronous work, see . /// /**/ template __declspec(noinline) // Ask for no inlining so that the PPLX_CAPTURE_CALLSTACK gives us the expected result - auto then(_Function&& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType + auto then(_Function&& _Func, + cancellation_token _CancellationToken, + task_continuation_context _ContinuationContext) const -> + typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType { task_options _TaskOptions(_CancellationToken, _ContinuationContext); details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(PPLX_CAPTURE_CALLSTACK()); @@ -4465,32 +4581,30 @@ class task } /// - /// Waits for this task to reach a terminal state. It is possible for wait to execute the task inline, if all of the tasks - /// dependencies are satisfied, and it has not already been picked up for execution by a background worker. + /// Waits for this task to reach a terminal state. It is possible for wait to execute the task inline, if + /// all of the tasks dependencies are satisfied, and it has not already been picked up for execution by a + /// background worker. /// /// - /// A task_status value which could be either completed or canceled. If the task encountered an exception - /// during execution, or an exception was propagated to it from an antecedent task, wait will throw that exception. + /// A task_status value which could be either completed or canceled. If the task + /// encountered an exception during execution, or an exception was propagated to it from an antecedent task, + /// wait will throw that exception. /// /**/ - task_status wait() const - { - return _M_unitTask.wait(); - } + task_status wait() const { return _M_unitTask.wait(); } /// - /// Returns the result this task produced. If the task is not in a terminal state, a call to get will wait for the task to - /// finish. This method does not return a value when called on a task with a result_type of void. + /// Returns the result this task produced. If the task is not in a terminal state, a call to get will + /// wait for the task to finish. This method does not return a value when called on a task with a + /// result_type of void. /// /// - /// If the task is canceled, a call to get will throw a task_canceled exception. If the task - /// encountered an different exception or an exception was propagated to it from an antecedent task, a call to get will throw that exception. + /// If the task is canceled, a call to get will throw a task_canceled exception. If the task encountered an different exception or an exception was + /// propagated to it from an antecedent task, a call to get will throw that exception. /// /**/ - void get() const - { - _M_unitTask.get(); - } + void get() const { _M_unitTask.get(); } /// /// Determines if the task is completed. @@ -4501,10 +4615,7 @@ class task /// /// The function returns true if the task is completed or canceled (with or without user exception). /// - bool is_done() const - { - return _M_unitTask.is_done(); - } + bool is_done() const { return _M_unitTask.is_done(); } /// /// Returns the scheduler for this task @@ -4512,22 +4623,18 @@ class task /// /// A pointer to the scheduler /// - scheduler_ptr scheduler() const - { - return _M_unitTask.scheduler(); - } + scheduler_ptr scheduler() const { return _M_unitTask.scheduler(); } /// - /// Determines whether the task unwraps a Windows Runtime IAsyncInfo interface or is descended from such a task. + /// Determines whether the task unwraps a Windows Runtime IAsyncInfo interface or is descended from such + /// a task. /// /// - /// true if the task unwraps an IAsyncInfo interface or is descended from such a task, false otherwise. + /// true if the task unwraps an IAsyncInfo interface or is descended from such a task, + /// false otherwise. /// /**/ - bool is_apartment_aware() const - { - return _M_unitTask.is_apartment_aware(); - } + bool is_apartment_aware() const { return _M_unitTask.is_apartment_aware(); } /// /// Determines whether two task objects represent the same internal task. @@ -4536,10 +4643,7 @@ class task /// true if the objects refer to the same underlying task, and false otherwise. /// /**/ - bool operator==(const task& _Rhs) const - { - return (_M_unitTask == _Rhs._M_unitTask); - } + bool operator==(const task& _Rhs) const { return (_M_unitTask == _Rhs._M_unitTask); } /// /// Determines whether two task objects represent different internal tasks. @@ -4548,15 +4652,12 @@ class task /// true if the objects refer to different underlying tasks, and false otherwise. /// /**/ - bool operator!=(const task& _Rhs) const - { - return !operator==(_Rhs); - } + bool operator!=(const task& _Rhs) const { return !operator==(_Rhs); } /// /// Create an underlying task implementation. /// - void _CreateImpl(details::_CancellationTokenState * _Ct, scheduler_ptr _Scheduler) + void _CreateImpl(details::_CancellationTokenState* _Ct, scheduler_ptr _Scheduler) { _M_unitTask._CreateImpl(_Ct, _Scheduler); } @@ -4564,59 +4665,58 @@ class task /// /// Return the underlying implementation for this task. /// - const details::_Task_ptr::_Type & _GetImpl() const - { - return _M_unitTask._M_Impl; - } + const details::_Task_ptr::_Type& _GetImpl() const { return _M_unitTask._M_Impl; } /// /// Set the implementation of the task to be the supplied implementation. /// - void _SetImpl(const details::_Task_ptr::_Type & _Impl) - { - _M_unitTask._SetImpl(_Impl); - } + void _SetImpl(const details::_Task_ptr::_Type& _Impl) { _M_unitTask._SetImpl(_Impl); } /// /// Set the implementation of the task to be the supplied implementation using a move instead of a copy. /// - void _SetImpl(details::_Task_ptr::_Type && _Impl) - { - _M_unitTask._SetImpl(std::move(_Impl)); - } + void _SetImpl(details::_Task_ptr::_Type&& _Impl) { _M_unitTask._SetImpl(std::move(_Impl)); } /// /// Sets a property determining whether the task is apartment aware. /// - void _SetAsync(bool _Async = true) - { - _M_unitTask._SetAsync(_Async); - } + void _SetAsync(bool _Async = true) { _M_unitTask._SetAsync(_Async); } /// - /// Sets a field in the task impl to the return callstack for calls to the task constructors and the then method. + /// Sets a field in the task impl to the return callstack for calls to the task constructors and the then + /// method. /// - void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack) + void _SetTaskCreationCallstack(const details::_TaskCreationCallstack& _callstack) { _M_unitTask._SetTaskCreationCallstack(_callstack); } /// - /// An internal version of then that takes additional flags and executes the continuation inline. Used for runtime internal continuations only. + /// An internal version of then that takes additional flags and executes the continuation inline. Used for + /// runtime internal continuations only. /// template - auto _Then(_Function&& _Func, details::_CancellationTokenState *_PTokenState, - details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType + auto _Then(_Function&& _Func, + details::_CancellationTokenState* _PTokenState, + details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> + typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType { // inherit from antecedent auto _Scheduler = _GetImpl()->_GetScheduler(); - return _M_unitTask._ThenImpl(std::forward<_Function>(_Func), _PTokenState, task_continuation_context::use_default(), _Scheduler, PPLX_CAPTURE_CALLSTACK(), _InliningMode); + return _M_unitTask._ThenImpl(std::forward<_Function>(_Func), + _PTokenState, + task_continuation_context::use_default(), + _Scheduler, + PPLX_CAPTURE_CALLSTACK(), + _InliningMode); } private: - template friend class task; - template friend class task_completion_event; + template + friend class task; + template + friend class task_completion_event; /// /// Initializes a task using a task completion event. @@ -4626,30 +4726,31 @@ class task _M_unitTask._TaskInitNoFunctor(_Event._M_unitEvent); } -#if defined (__cplusplus_winrt) +#if defined(__cplusplus_winrt) /// /// Initializes a task using an asynchronous action IAsyncAction^ /// - void _TaskInitNoFunctor(Windows::Foundation::IAsyncAction^ _AsyncAction) + void _TaskInitNoFunctor(Windows::Foundation::IAsyncAction ^ _AsyncAction) { - _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionToAsyncOperationConverter(_AsyncAction)); + _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionToAsyncOperationConverter(_AsyncAction)); } /// /// Initializes a task using an asynchronous action with progress IAsyncActionWithProgress<_P>^ /// template - void _TaskInitNoFunctor(Windows::Foundation::IAsyncActionWithProgress<_P>^ _AsyncActionWithProgress) + void _TaskInitNoFunctor(Windows::Foundation::IAsyncActionWithProgress<_P> ^ _AsyncActionWithProgress) { - _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>(_AsyncActionWithProgress)); + _M_unitTask._TaskInitAsyncOp( + ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>(_AsyncActionWithProgress)); } -#endif /* defined (__cplusplus_winrt) */ +#endif /* defined (__cplusplus_winrt) */ /// /// Initializes a task using a callable object. /// template - void _TaskInitMaybeFunctor(_Function & _Func, std::true_type) + void _TaskInitMaybeFunctor(_Function& _Func, std::true_type) { _M_unitTask._TaskInitWithFunctor(_Func); } @@ -4658,119 +4759,128 @@ class task /// Initializes a task using a non-callable object. /// template - void _TaskInitMaybeFunctor(_T & _Param, std::false_type) + void _TaskInitMaybeFunctor(_T& _Param, std::false_type) { _TaskInitNoFunctor(_Param); } - // The void task contains a task of a dummy type so common code can be used for tasks with void and non-void results. + // The void task contains a task of a dummy type so common code can be used for tasks with void and non-void + // results. task _M_unitTask; }; namespace details { - /// - /// The following type traits are used for the create_task function. - /// +/// +/// The following type traits are used for the create_task function. +/// -#if defined (__cplusplus_winrt) - // Unwrap functions for asyncOperations - template - _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperation<_Ty>^); +#if defined(__cplusplus_winrt) +// Unwrap functions for asyncOperations +template +_Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperation<_Ty> ^); - void _GetUnwrappedType(Windows::Foundation::IAsyncAction^); +void _GetUnwrappedType(Windows::Foundation::IAsyncAction ^); - template - _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress>^); +template +_Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress> ^); - template - void _GetUnwrappedType(Windows::Foundation::IAsyncActionWithProgress<_Progress>^); -#endif /* defined (__cplusplus_winrt) */ +template +void _GetUnwrappedType(Windows::Foundation::IAsyncActionWithProgress<_Progress> ^); +#endif /* defined (__cplusplus_winrt) */ - // Unwrap task - template - _Ty _GetUnwrappedType(task<_Ty>); +// Unwrap task +template +_Ty _GetUnwrappedType(task<_Ty>); - // Unwrap all supported types - template - auto _GetUnwrappedReturnType(_Ty _Arg, int) -> decltype(_GetUnwrappedType(_Arg)); - // fallback - template - _Ty _GetUnwrappedReturnType(_Ty, ...); +// Unwrap all supported types +template +auto _GetUnwrappedReturnType(_Ty _Arg, int) -> decltype(_GetUnwrappedType(_Arg)); +// fallback +template +_Ty _GetUnwrappedReturnType(_Ty, ...); - /// - /// _GetTaskType functions will retrieve task type T in task[T](Arg), - /// for given constructor argument Arg and its property "callable". - /// It will automatically unwrap argument to get the final return type if necessary. - /// +/// +/// _GetTaskType functions will retrieve task type T in task[T](Arg), +/// for given constructor argument Arg and its property "callable". +/// It will automatically unwrap argument to get the final return type if necessary. +/// - // Non-Callable - template - _Ty _GetTaskType(task_completion_event<_Ty>, std::false_type); +// Non-Callable +template +_Ty _GetTaskType(task_completion_event<_Ty>, std::false_type); - // Non-Callable - template - auto _GetTaskType(_Ty _NonFunc, std::false_type) -> decltype(_GetUnwrappedType(_NonFunc)); +// Non-Callable +template +auto _GetTaskType(_Ty _NonFunc, std::false_type) -> decltype(_GetUnwrappedType(_NonFunc)); - // Callable - template - auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(_Func(), 0)); +// Callable +template +auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(_Func(), 0)); - // Special callable returns void - void _GetTaskType(std::function, std::true_type); - struct _BadArgType{}; +// Special callable returns void +void _GetTaskType(std::function, std::true_type); +struct _BadArgType +{ +}; - template - auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable(_Param, 0))); +template +auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable(_Param, 0))); - template - _BadArgType _FilterValidTaskType(_Ty _Param, ...); +template +_BadArgType _FilterValidTaskType(_Ty _Param, ...); - template - struct _TaskTypeFromParam - { - typedef decltype(_FilterValidTaskType(stdx::declval<_Ty>(), 0)) _Type; - }; +template +struct _TaskTypeFromParam +{ + typedef decltype(_FilterValidTaskType(stdx::declval<_Ty>(), 0)) _Type; +}; } // namespace details /// -/// Creates a PPL task object. create_task can be used anywhere you would have used a task constructor. -/// It is provided mainly for convenience, because it allows use of the auto keyword while creating tasks. +/// Creates a PPL task object. create_task can be used anywhere you would have +/// used a task constructor. It is provided mainly for convenience, because it allows use of the auto keyword +/// while creating tasks. /// /// /// The type of the parameter from which the task is to be constructed. /// /// -/// The parameter from which the task is to be constructed. This could be a lambda or function object, a task_completion_event -/// object, a different task object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app. +/// The parameter from which the task is to be constructed. This could be a lambda or function object, a +/// task_completion_event object, a different task object, or a Windows::Foundation::IAsyncInfo +/// interface if you are using tasks in your Windows Store app. /// /// /// A new task of type T, that is inferred from . /// /// /// The first overload behaves like a task constructor that takes a single parameter. -/// The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not -/// allowed to pass in a different task object as the first parameter. -/// The type of the returned task is inferred from the first parameter to the function. If is a task_completion_event<T>, -/// a task<T>, or a functor that returns either type T or task<T>, the type of the created task is task<T>. -/// In a Windows Store app, if is of type Windows::Foundation::IAsyncOperation<T>^ or -/// Windows::Foundation::IAsyncOperationWithProgress<T,P>^, or a functor that returns either of those types, the created task will be of type task<T>. -/// If is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor -/// that returns either of those types, the created task will have type task<void>. +/// The second overload associates the cancellation token provided with the newly created task. If you use +/// this overload you are not allowed to pass in a different task object as the first parameter. +/// The type of the returned task is inferred from the first parameter to the function. If is a task_completion_event<T>, a task<T>, or a functor that returns +/// either type T or task<T>, the type of the created task is task<T>. +/// In a Windows Store app, if is of type +/// Windows::Foundation::IAsyncOperation<T>^ or Windows::Foundation::IAsyncOperationWithProgress<T,P>^, +/// or a functor that returns either of those types, the created task will be of type task<T>. If +/// is of type Windows::Foundation::IAsyncAction^ or +/// Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor that returns either of those types, the +/// created task will have type task<void>. /// /// /// /**/ template -__declspec(noinline) -auto create_task(_Ty _Param, task_options _TaskOptions = task_options()) -> task::_Type> +__declspec(noinline) auto create_task(_Ty _Param, task_options _TaskOptions = task_options()) + -> task::_Type> { - static_assert(!std::is_same::_Type,details::_BadArgType>::value, -#if defined (__cplusplus_winrt) - "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event" + static_assert(!std::is_same::_Type, details::_BadArgType>::value, +#if defined(__cplusplus_winrt) + "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a " + "task_completion_event" #else /* defined (__cplusplus_winrt) */ - "incorrect argument for create_task; can be a callable object or a task_completion_event" -#endif /* defined (__cplusplus_winrt) */ + "incorrect argument for create_task; can be a callable object or a task_completion_event" +#endif /* defined (__cplusplus_winrt) */ ); details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(PPLX_CAPTURE_CALLSTACK()); task::_Type> _CreatedTask(_Param, _TaskOptions); @@ -4778,110 +4888,102 @@ auto create_task(_Ty _Param, task_options _TaskOptions = task_options()) -> task } /// -/// Creates a PPL task object. create_task can be used anywhere you would have used a task constructor. -/// It is provided mainly for convenience, because it allows use of the auto keyword while creating tasks. +/// Creates a PPL task object. create_task can be used anywhere you would have +/// used a task constructor. It is provided mainly for convenience, because it allows use of the auto keyword +/// while creating tasks. /// /// /// The type of the parameter from which the task is to be constructed. /// /// -/// The parameter from which the task is to be constructed. This could be a lambda or function object, a task_completion_event -/// object, a different task object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app. +/// The parameter from which the task is to be constructed. This could be a lambda or function object, a +/// task_completion_event object, a different task object, or a Windows::Foundation::IAsyncInfo +/// interface if you are using tasks in your Windows Store app. /// /// -/// The cancellation token to associate with the task. When the source for this token is canceled, cancellation will be requested on the task. +/// The cancellation token to associate with the task. When the source for this token is canceled, cancellation will +/// be requested on the task. /// /// /// A new task of type T, that is inferred from . /// /// /// The first overload behaves like a task constructor that takes a single parameter. -/// The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not -/// allowed to pass in a different task object as the first parameter. -/// The type of the returned task is inferred from the first parameter to the function. If is a task_completion_event<T>, -/// a task<T>, or a functor that returns either type T or task<T>, the type of the created task is task<T>. -/// In a Windows Store app, if is of type Windows::Foundation::IAsyncOperation<T>^ or -/// Windows::Foundation::IAsyncOperationWithProgress<T,P>^, or a functor that returns either of those types, the created task will be of type task<T>. -/// If is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor -/// that returns either of those types, the created task will have type task<void>. +/// The second overload associates the cancellation token provided with the newly created task. If you use +/// this overload you are not allowed to pass in a different task object as the first parameter. +/// The type of the returned task is inferred from the first parameter to the function. If is a task_completion_event<T>, a task<T>, or a functor that returns +/// either type T or task<T>, the type of the created task is task<T>. +/// In a Windows Store app, if is of type +/// Windows::Foundation::IAsyncOperation<T>^ or Windows::Foundation::IAsyncOperationWithProgress<T,P>^, +/// or a functor that returns either of those types, the created task will be of type task<T>. If +/// is of type Windows::Foundation::IAsyncAction^ or +/// Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor that returns either of those types, the +/// created task will have type task<void>. /// /// /// /**/ template -__declspec(noinline) -task<_ReturnType> create_task(const task<_ReturnType>& _Task) +__declspec(noinline) task<_ReturnType> create_task(const task<_ReturnType>& _Task) { task<_ReturnType> _CreatedTask(_Task); return _CreatedTask; } -#if defined (__cplusplus_winrt) +#if defined(__cplusplus_winrt) namespace details { - template - task<_T> _To_task_helper(Windows::Foundation::IAsyncOperation<_T>^ op) - { - return task<_T>(op); - } - - template - task<_T> _To_task_helper(Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress>^ op) - { - return task<_T>(op); - } - - inline task _To_task_helper(Windows::Foundation::IAsyncAction^ op) - { - return task(op); - } +template +task<_T> _To_task_helper(Windows::Foundation::IAsyncOperation<_T> ^ op) +{ + return task<_T>(op); +} - template - task _To_task_helper(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ op) - { - return task(op); - } +template +task<_T> _To_task_helper(Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress> ^ op) +{ + return task<_T>(op); +} - template - class _ProgressDispatcherBase - { - public: +inline task _To_task_helper(Windows::Foundation::IAsyncAction ^ op) { return task(op); } - virtual ~_ProgressDispatcherBase() - { - } - - virtual void _Report(const _ProgressType& _Val) = 0; - }; +template +task _To_task_helper(Windows::Foundation::IAsyncActionWithProgress<_Progress> ^ op) +{ + return task(op); +} - template - class _ProgressDispatcher : public _ProgressDispatcherBase<_ProgressType> - { - public: +template +class _ProgressDispatcherBase +{ +public: + virtual ~_ProgressDispatcherBase() {} - virtual ~_ProgressDispatcher() - { - } + virtual void _Report(const _ProgressType& _Val) = 0; +}; - _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr) - { - } +template +class _ProgressDispatcher : public _ProgressDispatcherBase<_ProgressType> +{ +public: + virtual ~_ProgressDispatcher() {} - virtual void _Report(const _ProgressType& _Val) - { - _M_ptr->_FireProgress(_Val); - } + _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr) {} - private: + virtual void _Report(const _ProgressType& _Val) { _M_ptr->_FireProgress(_Val); } - _ClassPtrType _M_ptr; - }; - class _ProgressReporterCtorArgType{}; +private: + _ClassPtrType _M_ptr; +}; +class _ProgressReporterCtorArgType +{ +}; } // namespace details /// -/// The progress reporter class allows reporting progress notifications of a specific type. Each progress_reporter object is bound -/// to a particular asynchronous action or operation. +/// The progress reporter class allows reporting progress notifications of a specific type. Each progress_reporter +/// object is bound to a particular asynchronous action or operation. /// /// /// The payload type of each progress notification reported through the progress reporter. @@ -4897,7 +4999,6 @@ class progress_reporter typedef std::shared_ptr> _PtrType; public: - /// /// Sends a progress report to the asynchronous action or operation to which this progress reporter is bound. /// @@ -4905,16 +5006,14 @@ class progress_reporter /// The payload to report through a progress notification. /// /**/ - void report(const _ProgressType& _Val) const - { - _M_dispatcher->_Report(_Val); - } + void report(const _ProgressType& _Val) const { _M_dispatcher->_Report(_Val); } template static progress_reporter _CreateReporter(_ClassPtrType _Ptr) { progress_reporter _Reporter; - details::_ProgressDispatcherBase<_ProgressType> *_PDispatcher = new details::_ProgressDispatcher<_ProgressType, _ClassPtrType>(_Ptr); + details::_ProgressDispatcherBase<_ProgressType>* _PDispatcher = + new details::_ProgressDispatcher<_ProgressType, _ClassPtrType>(_Ptr); _Reporter._M_dispatcher = _PtrType(_PDispatcher); return _Reporter; } @@ -4928,875 +5027,989 @@ class progress_reporter namespace details { - // - // maps internal definitions for AsyncStatus and defines states that are not client visible - // - enum _AsyncStatusInternal - { - _AsyncCreated = -1, // externally invisible - // client visible states (must match AsyncStatus exactly) - _AsyncStarted = 0, // Windows::Foundation::AsyncStatus::Started, - _AsyncCompleted = 1, // Windows::Foundation::AsyncStatus::Completed, - _AsyncCanceled = 2, // Windows::Foundation::AsyncStatus::Canceled, - _AsyncError = 3, // Windows::Foundation::AsyncStatus::Error, - // non-client visible internal states - _AsyncCancelPending, - _AsyncClosed, - _AsyncUndefined - }; - - // - // designates whether the "GetResults" method returns a single result (after complete fires) or multiple results - // (which are progressively consumable between Start state and before Close is called) - // - enum _AsyncResultType - { - SingleResult = 0x0001, - MultipleResults = 0x0002 - }; - - // *************************************************************************** - // Template type traits and helpers for async production APIs: - // - - struct _ZeroArgumentFunctor { }; - struct _OneArgumentFunctor { }; - struct _TwoArgumentFunctor { }; +// +// maps internal definitions for AsyncStatus and defines states that are not client visible +// +enum _AsyncStatusInternal +{ + _AsyncCreated = -1, // externally invisible + // client visible states (must match AsyncStatus exactly) + _AsyncStarted = 0, // Windows::Foundation::AsyncStatus::Started, + _AsyncCompleted = 1, // Windows::Foundation::AsyncStatus::Completed, + _AsyncCanceled = 2, // Windows::Foundation::AsyncStatus::Canceled, + _AsyncError = 3, // Windows::Foundation::AsyncStatus::Error, + // non-client visible internal states + _AsyncCancelPending, + _AsyncClosed, + _AsyncUndefined +}; - // **************************************** - // CLASS TYPES: +// +// designates whether the "GetResults" method returns a single result (after complete fires) or multiple results +// (which are progressively consumable between Start state and before Close is called) +// +enum _AsyncResultType +{ + SingleResult = 0x0001, + MultipleResults = 0x0002 +}; - // ******************** - // TWO ARGUMENTS: +// *************************************************************************** +// Template type traits and helpers for async production APIs: +// - // non-void arg: - template - _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const); +struct _ZeroArgumentFunctor +{ +}; +struct _OneArgumentFunctor +{ +}; +struct _TwoArgumentFunctor +{ +}; - // non-void arg: - template - _Arg2 _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const); +// **************************************** +// CLASS TYPES: - template - _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const); +// ******************** +// TWO ARGUMENTS: - template - _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1, _Arg2) const); +// non-void arg: +template +_Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const); - // ******************** - // ONE ARGUMENT: +// non-void arg: +template +_Arg2 _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const); - // non-void arg: - template - _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const); +template +_ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const); - // non-void arg: - template - void _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const); +template +_TwoArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1, _Arg2) const); - template - _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const); +// ******************** +// ONE ARGUMENT: - template - _OneArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1) const); +// non-void arg: +template +_Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const); - // ******************** - // ZERO ARGUMENT: +// non-void arg: +template +void _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const); - // void arg: - template - void _Arg1ClassHelperThunk(_ReturnType (_Class::*)() const); +template +_ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const); - // void arg: - template - void _Arg2ClassHelperThunk(_ReturnType (_Class::*)() const); +template +_OneArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1) const); - // void arg: - template - _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)() const); +// ******************** +// ZERO ARGUMENT: - template - _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)() const); +// void arg: +template +void _Arg1ClassHelperThunk(_ReturnType (_Class::*)() const); - // **************************************** - // POINTER TYPES: +// void arg: +template +void _Arg2ClassHelperThunk(_ReturnType (_Class::*)() const); - // ******************** - // TWO ARGUMENTS: +// void arg: +template +_ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)() const); - template - _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2)); +template +_ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)() const); - template - _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2)); +// **************************************** +// POINTER TYPES: - template - _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2)); +// ******************** +// TWO ARGUMENTS: - template - _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2)); +template +_Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl*)(_Arg1, _Arg2)); - template - _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2)); +template +_Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl*)(_Arg1, _Arg2)); - template - _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2)); +template +_ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl*)(_Arg1, _Arg2)); - template - _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2)); +template +_TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl*)(_Arg1, _Arg2)); - template - _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2)); +template +_Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall*)(_Arg1, _Arg2)); - template - _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2)); +template +_Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall*)(_Arg1, _Arg2)); - template - _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2)); +template +_ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall*)(_Arg1, _Arg2)); - template - _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2)); +template +_TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall*)(_Arg1, _Arg2)); - template - _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2)); +template +_Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall*)(_Arg1, _Arg2)); - // ******************** - // ONE ARGUMENT: +template +_Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall*)(_Arg1, _Arg2)); - template - _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1)); +template +_ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall*)(_Arg1, _Arg2)); - template - void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1)); +template +_TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall*)(_Arg1, _Arg2)); - template - _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1)); +// ******************** +// ONE ARGUMENT: - template - _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1)); +template +_Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl*)(_Arg1)); - template - _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1)); +template +void _Arg2PFNHelperThunk(_ReturnType(__cdecl*)(_Arg1)); - template - void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1)); +template +_ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl*)(_Arg1)); - template - _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1)); +template +_OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl*)(_Arg1)); - template - _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1)); +template +_Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall*)(_Arg1)); - template - _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1)); +template +void _Arg2PFNHelperThunk(_ReturnType(__stdcall*)(_Arg1)); - template - void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1)); +template +_ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall*)(_Arg1)); - template - _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1)); +template +_OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall*)(_Arg1)); - template - _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1)); +template +_Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall*)(_Arg1)); - // ******************** - // ZERO ARGUMENT: +template +void _Arg2PFNHelperThunk(_ReturnType(__fastcall*)(_Arg1)); - template - void _Arg1PFNHelperThunk(_ReturnType(__cdecl *)()); +template +_ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall*)(_Arg1)); - template - void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)()); +template +_OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall*)(_Arg1)); - template - _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)()); +// ******************** +// ZERO ARGUMENT: - template - _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)()); +template +void _Arg1PFNHelperThunk(_ReturnType(__cdecl*)()); - template - void _Arg1PFNHelperThunk(_ReturnType(__stdcall *)()); +template +void _Arg2PFNHelperThunk(_ReturnType(__cdecl*)()); - template - void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)()); +template +_ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl*)()); - template - _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)()); +template +_ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl*)()); - template - _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)()); +template +void _Arg1PFNHelperThunk(_ReturnType(__stdcall*)()); - template - void _Arg1PFNHelperThunk(_ReturnType(__fastcall *)()); +template +void _Arg2PFNHelperThunk(_ReturnType(__stdcall*)()); - template - void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)()); +template +_ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall*)()); - template - _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)()); +template +_ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall*)()); - template - _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)()); +template +void _Arg1PFNHelperThunk(_ReturnType(__fastcall*)()); - template - struct _FunctorArguments - { - static const size_t _Count = 0; - }; +template +void _Arg2PFNHelperThunk(_ReturnType(__fastcall*)()); - template<> - struct _FunctorArguments<_OneArgumentFunctor> - { - static const size_t _Count = 1; - }; +template +_ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall*)()); - template<> - struct _FunctorArguments<_TwoArgumentFunctor> - { - static const size_t _Count = 2; - }; +template +_ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall*)()); - template - struct _FunctorTypeTraits - { - typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType; - static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count; +template +struct _FunctorArguments +{ + static const size_t _Count = 0; +}; - typedef decltype(_ReturnTypeClassHelperThunk(&(_T::operator()))) _ReturnType; - typedef decltype(_Arg1ClassHelperThunk(&(_T::operator()))) _Argument1Type; - typedef decltype(_Arg2ClassHelperThunk(&(_T::operator()))) _Argument2Type; - }; +template<> +struct _FunctorArguments<_OneArgumentFunctor> +{ + static const size_t _Count = 1; +}; - template - struct _FunctorTypeTraits<_T *> - { - typedef decltype(_ArgumentCountHelper(stdx::declval<_T*>())) _ArgumentCountType; - static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count; +template<> +struct _FunctorArguments<_TwoArgumentFunctor> +{ + static const size_t _Count = 2; +}; - typedef decltype(_ReturnTypePFNHelperThunk(stdx::declval<_T*>())) _ReturnType; - typedef decltype(_Arg1PFNHelperThunk(stdx::declval<_T*>())) _Argument1Type; - typedef decltype(_Arg2PFNHelperThunk(stdx::declval<_T*>())) _Argument2Type; - }; +template +struct _FunctorTypeTraits +{ + typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType; + static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count; - template - struct _ProgressTypeTraits - { - static const bool _TakesProgress = false; - typedef void _ProgressType; - }; + typedef decltype(_ReturnTypeClassHelperThunk(&(_T::operator()))) _ReturnType; + typedef decltype(_Arg1ClassHelperThunk(&(_T::operator()))) _Argument1Type; + typedef decltype(_Arg2ClassHelperThunk(&(_T::operator()))) _Argument2Type; +}; - template - struct _ProgressTypeTraits> - { - static const bool _TakesProgress = true; - typedef typename _T _ProgressType; - }; +template +struct _FunctorTypeTraits<_T*> +{ + typedef decltype(_ArgumentCountHelper(stdx::declval<_T*>())) _ArgumentCountType; + static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count; + typedef decltype(_ReturnTypePFNHelperThunk(stdx::declval<_T*>())) _ReturnType; + typedef decltype(_Arg1PFNHelperThunk(stdx::declval<_T*>())) _Argument1Type; + typedef decltype(_Arg2PFNHelperThunk(stdx::declval<_T*>())) _Argument2Type; +}; - template::_ArgumentCount> - struct _CAFunctorOptions - { - static const bool _TakesProgress = false; - static const bool _TakesToken = false; - typedef void _ProgressType; - }; +template +struct _ProgressTypeTraits +{ + static const bool _TakesProgress = false; + typedef void _ProgressType; +}; - template - struct _CAFunctorOptions<_T, 1> - { - private: +template +struct _ProgressTypeTraits> +{ + static const bool _TakesProgress = true; + typedef typename _T _ProgressType; +}; - typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type; +template::_ArgumentCount> +struct _CAFunctorOptions +{ + static const bool _TakesProgress = false; + static const bool _TakesToken = false; + typedef void _ProgressType; +}; - public: +template +struct _CAFunctorOptions<_T, 1> +{ +private: + typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type; - static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress; - static const bool _TakesToken = !_TakesProgress; - typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType; - }; +public: + static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress; + static const bool _TakesToken = !_TakesProgress; + typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType; +}; - template - struct _CAFunctorOptions<_T, 2> - { - private: +template +struct _CAFunctorOptions<_T, 2> +{ +private: + typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type; - typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type; +public: + static const bool _TakesProgress = true; + static const bool _TakesToken = true; + typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType; +}; - public: +ref class _Zip +{ +}; - static const bool _TakesProgress = true; - static const bool _TakesToken = true; - typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType; - }; +// *************************************************************************** +// Async Operation Task Generators +// - ref class _Zip +// +// Functor returns an IAsyncInfo - result needs to be wrapped in a task: +// +template +struct _SelectorTaskGenerator +{ + template + static task<_ReturnType> _GenerateTask_0(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - }; - - // *************************************************************************** - // Async Operation Task Generators - // + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task<_ReturnType>(_Func(), _taskOptinos); + } - // - // Functor returns an IAsyncInfo - result needs to be wrapped in a task: - // - template - struct _SelectorTaskGenerator + template + static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - template - static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task<_ReturnType>(_Func(), _taskOptinos); - } - - template - static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task<_ReturnType>(_Func(_Cts.get_token()), _taskOptinos); - } - - template - static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task<_ReturnType>(_Func(_Progress), _taskOptinos); - } + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task<_ReturnType>(_Func(_Cts.get_token()), _taskOptinos); + } - template - static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task<_ReturnType>(_Func(_Progress, _Cts.get_token()), _taskOptinos); - } - }; + template + static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task<_ReturnType>(_Func(_Progress), _taskOptinos); + } - template - struct _SelectorTaskGenerator<_AsyncSelector, void> + template + static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - template - static task _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task(_Func(), _taskOptinos); - } + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task<_ReturnType>(_Func(_Progress, _Cts.get_token()), _taskOptinos); + } +}; - template - static task _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task(_Func(_Cts.get_token()), _taskOptinos); - } +template +struct _SelectorTaskGenerator<_AsyncSelector, void> +{ + template + static task _GenerateTask_0(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task(_Func(), _taskOptinos); + } - template - static task _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task(_Func(_Progress), _taskOptinos); - } + template + static task _GenerateTask_1C(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task(_Func(_Cts.get_token()), _taskOptinos); + } - template - static task _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task(_Func(_Progress, _Cts.get_token()), _taskOptinos); - } - }; + template + static task _GenerateTask_1P(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task(_Func(_Progress), _taskOptinos); + } - // - // Functor returns a result - it needs to be wrapped in a task: - // - template - struct _SelectorTaskGenerator<_TypeSelectorNoAsync, _ReturnType> + template + static task _GenerateTask_2PC(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task(_Func(_Progress, _Cts.get_token()), _taskOptinos); + } +}; + +// +// Functor returns a result - it needs to be wrapped in a task: +// +template +struct _SelectorTaskGenerator<_TypeSelectorNoAsync, _ReturnType> +{ #pragma warning(push) -#pragma warning(disable: 4702) - template - static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task<_ReturnType>( [=]() -> _ReturnType { +#pragma warning(disable : 4702) + template + static task<_ReturnType> _GenerateTask_0(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task<_ReturnType>( + [=]() -> _ReturnType { _Task_generator_oversubscriber_t _Oversubscriber; (_Oversubscriber); return _Func(); - }, _taskOptinos); - } + }, + _taskOptinos); + } #pragma warning(pop) - template - static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task<_ReturnType>( [=]() -> _ReturnType { + template + static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task<_ReturnType>( + [=]() -> _ReturnType { _Task_generator_oversubscriber_t _Oversubscriber; (_Oversubscriber); return _Func(_Cts.get_token()); - }, _taskOptinos); - } + }, + _taskOptinos); + } - template - static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task<_ReturnType>( [=]() -> _ReturnType { + template + static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task<_ReturnType>( + [=]() -> _ReturnType { _Task_generator_oversubscriber_t _Oversubscriber; (_Oversubscriber); return _Func(_Progress); - }, _taskOptinos); - } - - template - static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task<_ReturnType>( [=]() -> _ReturnType { - _Task_generator_oversubscriber_t _Oversubscriber; - (_Oversubscriber); - return _Func(_Progress, _Cts.get_token()); - }, _taskOptinos); - } - }; + }, + _taskOptinos); + } - template<> - struct _SelectorTaskGenerator<_TypeSelectorNoAsync, void> + template + static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - template - static task _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task( [=]() { - _Task_generator_oversubscriber_t _Oversubscriber; - (_Oversubscriber); - _Func(); - }, _taskOptinos); - } - - template - static task _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task( [=]() { - _Task_generator_oversubscriber_t _Oversubscriber; - (_Oversubscriber); - _Func(_Cts.get_token()); - }, _taskOptinos); - } - - template - static task _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task( [=]() { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task<_ReturnType>( + [=]() -> _ReturnType { _Task_generator_oversubscriber_t _Oversubscriber; (_Oversubscriber); - _Func(_Progress); - }, _taskOptinos); - } - - template - static task _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - task_options _taskOptinos(_Cts.get_token()); - details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); - return task( [=]() { - _Task_generator_oversubscriber_t _Oversubscriber; - (_Oversubscriber); - _Func(_Progress, _Cts.get_token()); - }, _taskOptinos); - } - }; - - // - // Functor returns a task - the task can directly be returned: - // - template - struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, _ReturnType> - { - template - static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _Func(); - } - - template - static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _Func(_Cts.get_token()); - } - - template - static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _Func(_Progress); - } - - template - static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _Func(_Progress, _Cts.get_token()); - } - }; - - template<> - struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, void> - { - template - static task _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _Func(); - } + return _Func(_Progress, _Cts.get_token()); + }, + _taskOptinos); + } +}; - template - static task _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _Func(_Cts.get_token()); - } +template<> +struct _SelectorTaskGenerator<_TypeSelectorNoAsync, void> +{ + template + static task _GenerateTask_0(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task( + [=]() { + _Task_generator_oversubscriber_t _Oversubscriber; + (_Oversubscriber); + _Func(); + }, + _taskOptinos); + } - template - static task _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _Func(_Progress); - } + template + static task _GenerateTask_1C(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task( + [=]() { + _Task_generator_oversubscriber_t _Oversubscriber; + (_Oversubscriber); + _Func(_Cts.get_token()); + }, + _taskOptinos); + } - template - static task _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _Func(_Progress, _Cts.get_token()); - } - }; + template + static task _GenerateTask_1P(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task( + [=]() { + _Task_generator_oversubscriber_t _Oversubscriber; + (_Oversubscriber); + _Func(_Progress); + }, + _taskOptinos); + } - template - struct _TaskGenerator + template + static task _GenerateTask_2PC(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - }; + task_options _taskOptinos(_Cts.get_token()); + details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); + return task( + [=]() { + _Task_generator_oversubscriber_t _Oversubscriber; + (_Oversubscriber); + _Func(_Progress, _Cts.get_token()); + }, + _taskOptinos); + } +}; - template - struct _TaskGenerator<_Generator, false, false> +// +// Functor returns a task - the task can directly be returned: +// +template +struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, _ReturnType> +{ + template + static task<_ReturnType> _GenerateTask_0(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - template - static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) - { - return _Generator::_GenerateTask_0(_Func, _Cts, _callstack); - } - }; + return _Func(); + } - template - struct _TaskGenerator<_Generator, true, false> + template + static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - template - static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) - { - return _Generator::_GenerateTask_1C(_Func, _Cts, _callstack); - } - }; + return _Func(_Cts.get_token()); + } - template - struct _TaskGenerator<_Generator, false, true> + template + static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - template - static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) - { - return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack); - } - }; + return _Func(_Progress); + } - template - struct _TaskGenerator<_Generator, true, true> + template + static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - template - static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) - { - return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack); - } - }; + return _Func(_Progress, _Cts.get_token()); + } +}; - // *************************************************************************** - // Async Operation Attributes Classes - // - // These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given async construct in - // a single container. An attribute class must define: - // - // Mandatory: - // ------------------------- - // - // _AsyncBaseType : The Windows Runtime interface which is being implemented. - // _CompletionDelegateType : The Windows Runtime completion delegate type for the interface. - // _ProgressDelegateType : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. If it is false, an empty Windows Runtime type. - // _ReturnType : The return type of the async construct (void for actions / non-void for operations) - // - // _TakesProgress : An indication as to whether or not - // - // _Generate_Task : A function adapting the user's function into what's necessary to produce the appropriate task - // - // Optional: - // ------------------------- - // +template<> +struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, void> +{ + template + static task _GenerateTask_0(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + return _Func(); + } - template - struct _AsyncAttributes + template + static task _GenerateTask_1C(const _Function& _Func, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - }; + return _Func(_Cts.get_token()); + } - template - struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, true> + template + static task _GenerateTask_1P(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) { - typedef typename Windows::Foundation::IAsyncOperationWithProgress<_ReturnType, _ProgressType> _AsyncBaseType; - typedef typename Windows::Foundation::AsyncOperationProgressHandler<_ReturnType, _ProgressType> _ProgressDelegateType; - typedef typename Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_ReturnType, _ProgressType> _CompletionDelegateType; - typedef typename _ReturnType _ReturnType; - typedef typename _ProgressType _ProgressType; - typedef typename _TaskTraits::_AsyncKind _AsyncKind; - typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; - typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator; + return _Func(_Progress); + } - static const bool _TakesProgress = true; - static const bool _TakesToken = _TakesToken; + template + static task _GenerateTask_2PC(const _Function& _Func, + const _ProgressObject& _Progress, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + return _Func(_Progress, _Cts.get_token()); + } +}; - template - static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack); - } - }; +template +struct _TaskGenerator +{ +}; - template - struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false> - { - typedef typename Windows::Foundation::IAsyncOperation<_ReturnType> _AsyncBaseType; - typedef _Zip _ProgressDelegateType; - typedef typename Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType> _CompletionDelegateType; - typedef typename _ReturnType _ReturnType; - typedef typename _TaskTraits::_AsyncKind _AsyncKind; - typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; - typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator; +template +struct _TaskGenerator<_Generator, false, false> +{ + template + static auto _GenerateTask(const _Function& _Func, + _ClassPtr _Ptr, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) + { + return _Generator::_GenerateTask_0(_Func, _Cts, _callstack); + } +}; - static const bool _TakesProgress = false; - static const bool _TakesToken = _TakesToken; +template +struct _TaskGenerator<_Generator, true, false> +{ + template + static auto _GenerateTask(const _Function& _Func, + _ClassPtr _Ptr, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) + { + return _Generator::_GenerateTask_1C(_Func, _Cts, _callstack); + } +}; - template - static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack); - } - }; +template +struct _TaskGenerator<_Generator, false, true> +{ + template + static auto _GenerateTask(const _Function& _Func, + _ClassPtr _Ptr, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) + { + return _Generator::_GenerateTask_1P( + _Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack); + } +}; - template - struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true> - { - typedef typename Windows::Foundation::IAsyncActionWithProgress<_ProgressType> _AsyncBaseType; - typedef typename Windows::Foundation::AsyncActionProgressHandler<_ProgressType> _ProgressDelegateType; - typedef typename Windows::Foundation::AsyncActionWithProgressCompletedHandler<_ProgressType> _CompletionDelegateType; - typedef void _ReturnType; - typedef typename _ProgressType _ProgressType; - typedef typename _TaskTraits::_AsyncKind _AsyncKind; - typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; - typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator; +template +struct _TaskGenerator<_Generator, true, true> +{ + template + static auto _GenerateTask(const _Function& _Func, + _ClassPtr _Ptr, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) + { + return _Generator::_GenerateTask_2PC( + _Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack); + } +}; - static const bool _TakesProgress = true; - static const bool _TakesToken = _TakesToken; +// *************************************************************************** +// Async Operation Attributes Classes +// +// These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given +// async construct in a single container. An attribute class must define: +// +// Mandatory: +// ------------------------- +// +// _AsyncBaseType : The Windows Runtime interface which is being implemented. +// _CompletionDelegateType : The Windows Runtime completion delegate type for the interface. +// _ProgressDelegateType : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. +// If it is false, an empty Windows Runtime type. _ReturnType : The return type of the async construct +// (void for actions / non-void for operations) +// +// _TakesProgress : An indication as to whether or not +// +// _Generate_Task : A function adapting the user's function into what's necessary to produce the appropriate +// task +// +// Optional: +// ------------------------- +// + +template +struct _AsyncAttributes +{ +}; - template - static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack); - } - }; +template +struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, true> +{ + typedef typename Windows::Foundation::IAsyncOperationWithProgress<_ReturnType, _ProgressType> _AsyncBaseType; + typedef typename Windows::Foundation::AsyncOperationProgressHandler<_ReturnType, _ProgressType> + _ProgressDelegateType; + typedef typename Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_ReturnType, _ProgressType> + _CompletionDelegateType; + typedef typename _ReturnType _ReturnType; + typedef typename _ProgressType _ProgressType; + typedef typename _TaskTraits::_AsyncKind _AsyncKind; + typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; + typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator; + + static const bool _TakesProgress = true; + static const bool _TakesToken = _TakesToken; + + template + static task<_ReturnType> _Generate_Task(const _Function& _Func, + _ClassPtr _Ptr, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack); + } +}; - template - struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false> - { - typedef typename Windows::Foundation::IAsyncAction _AsyncBaseType; - typedef _Zip _ProgressDelegateType; - typedef typename Windows::Foundation::AsyncActionCompletedHandler _CompletionDelegateType; - typedef void _ReturnType; - typedef typename _TaskTraits::_AsyncKind _AsyncKind; - typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; - typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator; +template +struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false> +{ + typedef typename Windows::Foundation::IAsyncOperation<_ReturnType> _AsyncBaseType; + typedef _Zip _ProgressDelegateType; + typedef typename Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType> _CompletionDelegateType; + typedef typename _ReturnType _ReturnType; + typedef typename _TaskTraits::_AsyncKind _AsyncKind; + typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; + typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator; + + static const bool _TakesProgress = false; + static const bool _TakesToken = _TakesToken; + + template + static task<_ReturnType> _Generate_Task(const _Function& _Func, + _ClassPtr _Ptr, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack); + } +}; - static const bool _TakesProgress = false; - static const bool _TakesToken = _TakesToken; +template +struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true> +{ + typedef typename Windows::Foundation::IAsyncActionWithProgress<_ProgressType> _AsyncBaseType; + typedef typename Windows::Foundation::AsyncActionProgressHandler<_ProgressType> _ProgressDelegateType; + typedef typename Windows::Foundation::AsyncActionWithProgressCompletedHandler<_ProgressType> + _CompletionDelegateType; + typedef void _ReturnType; + typedef typename _ProgressType _ProgressType; + typedef typename _TaskTraits::_AsyncKind _AsyncKind; + typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; + typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator; + + static const bool _TakesProgress = true; + static const bool _TakesToken = _TakesToken; + + template + static task<_ReturnType> _Generate_Task(const _Function& _Func, + _ClassPtr _Ptr, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack); + } +}; - template - static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) - { - return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack); - } - }; +template +struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false> +{ + typedef typename Windows::Foundation::IAsyncAction _AsyncBaseType; + typedef _Zip _ProgressDelegateType; + typedef typename Windows::Foundation::AsyncActionCompletedHandler _CompletionDelegateType; + typedef void _ReturnType; + typedef typename _TaskTraits::_AsyncKind _AsyncKind; + typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; + typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator; + + static const bool _TakesProgress = false; + static const bool _TakesToken = _TakesToken; + + template + static task<_ReturnType> _Generate_Task(const _Function& _Func, + _ClassPtr _Ptr, + cancellation_token_source _Cts, + const _TaskCreationCallstack& _callstack) + { + return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack); + } +}; - template - struct _AsyncLambdaTypeTraits - { - typedef typename _FunctorTypeTraits<_Function>::_ReturnType _ReturnType; - typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type; - typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType; +template +struct _AsyncLambdaTypeTraits +{ + typedef typename _FunctorTypeTraits<_Function>::_ReturnType _ReturnType; + typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type; + typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType; + + static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress; + static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken; + + typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits; + typedef typename _AsyncAttributes<_Function, + _ProgressType, + typename _TaskTraits::_TaskRetType, + _TaskTraits, + _TakesToken, + _TakesProgress> + _AsyncAttributes; +}; - static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress; - static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken; +// *************************************************************************** +// AsyncInfo (and completion) Layer: +// - typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits; - typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes; - }; +// +// Internal base class implementation for async operations (based on internal Windows representation for ABI level async +// operations) +// +template +ref class _AsyncInfoBase abstract : _Attributes::_AsyncBaseType +{ + internal : - // *************************************************************************** - // AsyncInfo (and completion) Layer: - // + _AsyncInfoBase() + : _M_currentStatus(_AsyncStatusInternal::_AsyncCreated) + , _M_errorCode(S_OK) + , _M_completeDelegate(nullptr) + , _M_CompleteDelegateAssigned(0) + , _M_CallbackMade(0) + { + _M_id = ::pplx::details::platform::GetNextAsyncId(); + } - // - // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations) - // - template < typename _Attributes, _AsyncResultType resultType = SingleResult > - ref class _AsyncInfoBase abstract : _Attributes::_AsyncBaseType +public: + virtual typename _Attributes::_ReturnType GetResults() { - internal: + throw ::Platform::Exception::CreateException(E_UNEXPECTED); + } - _AsyncInfoBase() : - _M_currentStatus(_AsyncStatusInternal::_AsyncCreated), - _M_errorCode(S_OK), - _M_completeDelegate(nullptr), - _M_CompleteDelegateAssigned(0), - _M_CallbackMade(0) + virtual property unsigned int Id + { + unsigned int get() { - _M_id = ::pplx::details::platform::GetNextAsyncId(); - } + _CheckValidStateForAsyncInfoCall(); - public: - virtual typename _Attributes::_ReturnType GetResults() - { - throw ::Platform::Exception::CreateException(E_UNEXPECTED); + return _M_id; } - virtual property unsigned int Id + void set(unsigned int id) { - unsigned int get() - { - _CheckValidStateForAsyncInfoCall(); + _CheckValidStateForAsyncInfoCall(); - return _M_id; + if (id == 0) + { + throw ::Platform::Exception::CreateException(E_INVALIDARG); } - - void set(unsigned int id) + else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated) { - _CheckValidStateForAsyncInfoCall(); - - if (id == 0) - { - throw ::Platform::Exception::CreateException(E_INVALIDARG); - } - else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated) - { - throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL); - } - - _M_id = id; + throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL); } + + _M_id = id; } + } - virtual property Windows::Foundation::AsyncStatus Status + virtual property Windows::Foundation::AsyncStatus Status + { + Windows::Foundation::AsyncStatus get() { - Windows::Foundation::AsyncStatus get() - { - _CheckValidStateForAsyncInfoCall(); - - _AsyncStatusInternal _Current = _M_currentStatus; + _CheckValidStateForAsyncInfoCall(); - // - // Map our internal cancel pending to canceled. This way "pending canceled" looks to the outside as "canceled" but - // can still transition to "completed" if the operation completes without acknowledging the cancellation request - // - switch(_Current) - { - case _AsyncCancelPending: - _Current = _AsyncCanceled; - break; - case _AsyncCreated: - _Current = _AsyncStarted; - break; - default: - break; - } + _AsyncStatusInternal _Current = _M_currentStatus; - return static_cast(_Current); + // + // Map our internal cancel pending to canceled. This way "pending canceled" looks to the outside as + // "canceled" but can still transition to "completed" if the operation completes without acknowledging the + // cancellation request + // + switch (_Current) + { + case _AsyncCancelPending: _Current = _AsyncCanceled; break; + case _AsyncCreated: _Current = _AsyncStarted; break; + default: break; } + + return static_cast(_Current); } + } - virtual property Windows::Foundation::HResult ErrorCode + virtual property Windows::Foundation::HResult ErrorCode + { + Windows::Foundation::HResult get() { - Windows::Foundation::HResult get() - { - _CheckValidStateForAsyncInfoCall(); + _CheckValidStateForAsyncInfoCall(); - Windows::Foundation::HResult _Hr; - _Hr.Value = _M_errorCode; - return _Hr; - } + Windows::Foundation::HResult _Hr; + _Hr.Value = _M_errorCode; + return _Hr; } + } - virtual property typename _Attributes::_ProgressDelegateType^ Progress - { - typename typename _Attributes::_ProgressDelegateType^ get() - { - return _GetOnProgress(); - } + virtual property typename _Attributes::_ProgressDelegateType ^ + Progress { + typename typename _Attributes::_ProgressDelegateType ^ get() { return _GetOnProgress(); } - void set(typename _Attributes::_ProgressDelegateType^ _ProgressHandler) + void set(typename _Attributes::_ProgressDelegateType ^ _ProgressHandler) { _PutOnProgress(_ProgressHandler); } } - virtual void Cancel() + virtual void + Cancel() + { + if (_TransitionToState(_AsyncCancelPending)) { - if (_TransitionToState(_AsyncCancelPending)) - { - _OnCancel(); - } + _OnCancel(); } + } - virtual void Close() + virtual void Close() + { + if (_TransitionToState(_AsyncClosed)) { - if (_TransitionToState(_AsyncClosed)) - { - _OnClose(); - } - else - { - if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored - { - throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE); - } - } + _OnClose(); } - - virtual property typename _Attributes::_CompletionDelegateType^ Completed + else { - typename _Attributes::_CompletionDelegateType^ get() + if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored { - _CheckValidStateForDelegateCall(); - return _M_completeDelegate; + throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE); } + } + } + + virtual property typename _Attributes::_CompletionDelegateType ^ + Completed { + typename _Attributes::_CompletionDelegateType ^ + get() { + _CheckValidStateForDelegateCall(); + return _M_completeDelegate; + } - void set(typename _Attributes::_CompletionDelegateType^ _CompleteHandler) + void set(typename _Attributes::_CompletionDelegateType ^ _CompleteHandler) { _CheckValidStateForDelegateCall(); // this delegate property is "write once" @@ -5804,8 +6017,8 @@ namespace details { _M_completeDelegateContext = _ContextCallback::_CaptureCurrent(); _M_completeDelegate = _CompleteHandler; - // Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state below - // as perceived from _FireCompletion on another thread. + // Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state + // below as perceived from _FireCompletion on another thread. MemoryBarrier(); if (_IsTerminalState()) { @@ -5819,149 +6032,133 @@ namespace details } } - - protected private: + protected private : // _Start - this is not externally visible since async operations "hot start" before returning to the caller - void _Start() + void + _Start() + { + if (_TransitionToState(_AsyncStarted)) { - if (_TransitionToState(_AsyncStarted)) - { - _OnStart(); - } - else - { - throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE); - } + _OnStart(); } - - - void _FireCompletion() + else { - _TryTransitionToCompleted(); - - // we guarantee that completion can only ever be fired once - if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1) - { - _M_completeDelegateContext._CallInContext([=] { - _M_completeDelegate((_Attributes::_AsyncBaseType^)this, this->Status); - _M_completeDelegate = nullptr; - }); - } + throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE); } + } - virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress() - { - throw ::Platform::Exception::CreateException(E_UNEXPECTED); - } + void _FireCompletion() + { + _TryTransitionToCompleted(); - virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler) + // we guarantee that completion can only ever be fired once + if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1) { - throw ::Platform::Exception::CreateException(E_UNEXPECTED); + _M_completeDelegateContext._CallInContext([=] { + _M_completeDelegate((_Attributes::_AsyncBaseType ^) this, this->Status); + _M_completeDelegate = nullptr; + }); } + } - bool _TryTransitionToCompleted() - { - return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted); - } + virtual typename _Attributes::_ProgressDelegateType ^ + _GetOnProgress() { throw ::Platform::Exception::CreateException(E_UNEXPECTED); } - bool _TryTransitionToCancelled() - { - return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled); - } + virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType ^ _ProgressHandler) + { + throw ::Platform::Exception::CreateException(E_UNEXPECTED); + } - bool _TryTransitionToError(const HRESULT error) - { - _InterlockedCompareExchange(reinterpret_cast(&_M_errorCode), error, S_OK); - return _TransitionToState(_AsyncStatusInternal::_AsyncError); - } + bool _TryTransitionToCompleted() { return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted); } + + bool _TryTransitionToCancelled() { return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled); } + + bool _TryTransitionToError(const HRESULT error) + { + _InterlockedCompareExchange(reinterpret_cast(&_M_errorCode), error, S_OK); + return _TransitionToState(_AsyncStatusInternal::_AsyncError); + } - // This method checks to see if the delegate properties can be - // modified in the current state and generates the appropriate - // error hr in the case of violation. - inline void _CheckValidStateForDelegateCall() + // This method checks to see if the delegate properties can be + // modified in the current state and generates the appropriate + // error hr in the case of violation. + inline void _CheckValidStateForDelegateCall() + { + if (_M_currentStatus == _AsyncClosed) { - if (_M_currentStatus == _AsyncClosed) - { - throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL); - } + throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL); } + } - // This method checks to see if results can be collected in the - // current state and generates the appropriate error hr in - // the case of a violation. - inline void _CheckValidStateForResultsCall() - { - _AsyncStatusInternal _Current = _M_currentStatus; + // This method checks to see if results can be collected in the + // current state and generates the appropriate error hr in + // the case of a violation. + inline void _CheckValidStateForResultsCall() + { + _AsyncStatusInternal _Current = _M_currentStatus; - if (_Current == _AsyncError) - { - throw ::Platform::Exception::CreateException(_M_errorCode); - } + if (_Current == _AsyncError) + { + throw ::Platform::Exception::CreateException(_M_errorCode); + } #pragma warning(push) -#pragma warning(disable: 4127) // Conditional expression is constant - // single result illegal before transition to Completed or Cancelled state - if (resultType == SingleResult) +#pragma warning(disable : 4127) // Conditional expression is constant + // single result illegal before transition to Completed or Cancelled state + if (resultType == SingleResult) #pragma warning(pop) - { - if (_Current != _AsyncCompleted) - { - throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL); - } - } - // multiple results can be called after Start has been called and before/after Completed - else if (_Current != _AsyncStarted && - _Current != _AsyncCancelPending && - _Current != _AsyncCanceled && - _Current != _AsyncCompleted) + { + if (_Current != _AsyncCompleted) { throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL); } } - - // This method can be called by derived classes periodically to determine - // whether the asynchronous operation should continue processing or should - // be halted. - inline bool _ContinueAsyncOperation() + // multiple results can be called after Start has been called and before/after Completed + else if (_Current != _AsyncStarted && _Current != _AsyncCancelPending && _Current != _AsyncCanceled && + _Current != _AsyncCompleted) { - return (_M_currentStatus == _AsyncStarted); + throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL); } + } - // These two methods are used to allow the async worker implementation do work on - // state transitions. No real "work" should be done in these methods. In other words - // they should not block for a long time on UI timescales. - virtual void _OnStart() = 0; - virtual void _OnClose() = 0; - virtual void _OnCancel() = 0; + // This method can be called by derived classes periodically to determine + // whether the asynchronous operation should continue processing or should + // be halted. + inline bool _ContinueAsyncOperation() { return (_M_currentStatus == _AsyncStarted); } - private: + // These two methods are used to allow the async worker implementation do work on + // state transitions. No real "work" should be done in these methods. In other words + // they should not block for a long time on UI timescales. + virtual void _OnStart() = 0; + virtual void _OnClose() = 0; + virtual void _OnCancel() = 0; - // This method is used to check if calls to the AsyncInfo properties - // (id, status, errorcode) are legal in the current state. It also - // generates the appropriate error hr to return in the case of an - // illegal call. - inline void _CheckValidStateForAsyncInfoCall() +private: + // This method is used to check if calls to the AsyncInfo properties + // (id, status, errorcode) are legal in the current state. It also + // generates the appropriate error hr to return in the case of an + // illegal call. + inline void _CheckValidStateForAsyncInfoCall() + { + _AsyncStatusInternal _Current = _M_currentStatus; + if (_Current == _AsyncClosed) { - _AsyncStatusInternal _Current = _M_currentStatus; - if (_Current == _AsyncClosed) - { - throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL); - } - else if (_Current == _AsyncCreated) - { - throw ::Platform::Exception::CreateException(E_ASYNC_OPERATION_NOT_STARTED); - } - + throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL); } - - inline bool _TransitionToState(const _AsyncStatusInternal _NewState) + else if (_Current == _AsyncCreated) { - _AsyncStatusInternal _Current = _M_currentStatus; + throw ::Platform::Exception::CreateException(E_ASYNC_OPERATION_NOT_STARTED); + } + } - // This enforces the valid state transitions of the asynchronous worker object - // state machine. - switch(_NewState) - { + inline bool _TransitionToState(const _AsyncStatusInternal _NewState) + { + _AsyncStatusInternal _Current = _M_currentStatus; + + // This enforces the valid state transitions of the asynchronous worker object + // state machine. + switch (_NewState) + { case _AsyncStatusInternal::_AsyncStarted: if (_Current != _AsyncCreated) { @@ -5998,296 +6195,271 @@ namespace details return false; } break; - default: - return false; - break; - } - - // attempt the transition to the new state - // Note: if currentStatus_ == _Current, then there was no intervening write - // by the async work object and the swap succeeded. - _AsyncStatusInternal _RetState = static_cast<_AsyncStatusInternal>( - _InterlockedCompareExchange(reinterpret_cast(&_M_currentStatus), - _NewState, - static_cast(_Current))); - - // ICE returns the former state, if the returned state and the - // state we captured at the beginning of this method are the same, - // the swap succeeded. - return (_RetState == _Current); - } - - inline bool _IsTerminalState() - { - return _IsTerminalState(_M_currentStatus); - } - - inline bool _IsTerminalState(_AsyncStatusInternal status) - { - return (status == _AsyncError || - status == _AsyncCanceled || - status == _AsyncCompleted || - status == _AsyncClosed); + default: return false; break; } - private: - - _ContextCallback _M_completeDelegateContext; - typename _Attributes::_CompletionDelegateType^ volatile _M_completeDelegate; - _AsyncStatusInternal volatile _M_currentStatus; - HRESULT volatile _M_errorCode; - unsigned int _M_id; - long volatile _M_CompleteDelegateAssigned; - long volatile _M_CallbackMade; - }; + // attempt the transition to the new state + // Note: if currentStatus_ == _Current, then there was no intervening write + // by the async work object and the swap succeeded. + _AsyncStatusInternal _RetState = static_cast<_AsyncStatusInternal>(_InterlockedCompareExchange( + reinterpret_cast(&_M_currentStatus), _NewState, static_cast(_Current))); - // *************************************************************************** - // Progress Layer (optional): - // + // ICE returns the former state, if the returned state and the + // state we captured at the beginning of this method are the same, + // the swap succeeded. + return (_RetState == _Current); + } - template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult > - ref class _AsyncProgressBase abstract : _AsyncInfoBase<_Attributes, _ResultType> - { - }; + inline bool _IsTerminalState() { return _IsTerminalState(_M_currentStatus); } - template< typename _Attributes, _AsyncResultType _ResultType> - ref class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : _AsyncInfoBase<_Attributes, _ResultType> + inline bool _IsTerminalState(_AsyncStatusInternal status) { - internal: - - _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(), - _M_progressDelegate(nullptr) - { - } - - virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress() override - { - _CheckValidStateForDelegateCall(); - return _M_progressDelegate; - } + return (status == _AsyncError || status == _AsyncCanceled || status == _AsyncCompleted || + status == _AsyncClosed); + } - virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler) override - { - _CheckValidStateForDelegateCall(); - _M_progressDelegate = _ProgressHandler; - _M_progressDelegateContext = _ContextCallback::_CaptureCurrent(); - } +private: + _ContextCallback _M_completeDelegateContext; + typename _Attributes::_CompletionDelegateType ^ volatile _M_completeDelegate; + _AsyncStatusInternal volatile _M_currentStatus; + HRESULT volatile _M_errorCode; + unsigned int _M_id; + long volatile _M_CompleteDelegateAssigned; + long volatile _M_CallbackMade; +}; - void _FireProgress(const typename _Attributes::_ProgressType& _ProgressValue) - { - if (_M_progressDelegate != nullptr) - { - _M_progressDelegateContext._CallInContext([=] { - _M_progressDelegate((_Attributes::_AsyncBaseType^)this, _ProgressValue); - }); - } - } +// *************************************************************************** +// Progress Layer (optional): +// - private: +template +ref class _AsyncProgressBase abstract : _AsyncInfoBase<_Attributes, _ResultType> +{ +}; - _ContextCallback _M_progressDelegateContext; - typename _Attributes::_ProgressDelegateType^ _M_progressDelegate; - }; +template +ref class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : _AsyncInfoBase<_Attributes, _ResultType> +{ + internal : - template - ref class _AsyncBaseProgressLayer abstract : _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType> + _AsyncProgressBase() + : _AsyncInfoBase<_Attributes, _ResultType>(), _M_progressDelegate(nullptr) { - }; + } - // *************************************************************************** - // Task Adaptation Layer: - // + virtual typename _Attributes::_ProgressDelegateType ^ _GetOnProgress() override + { + _CheckValidStateForDelegateCall(); + return _M_progressDelegate; + } - // - // _AsyncTaskThunkBase provides a bridge between IAsync and task. - // - template - ref class _AsyncTaskThunkBase abstract : _AsyncBaseProgressLayer<_Attributes> + virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType ^ _ProgressHandler) override { - public: + _CheckValidStateForDelegateCall(); + _M_progressDelegate = _ProgressHandler; + _M_progressDelegateContext = _ContextCallback::_CaptureCurrent(); + } - virtual _ReturnType GetResults() override + void _FireProgress(const typename _Attributes::_ProgressType& _ProgressValue) + { + if (_M_progressDelegate != nullptr) { - _CheckValidStateForResultsCall(); - return _M_task.get(); + _M_progressDelegateContext._CallInContext( + [=] { _M_progressDelegate((_Attributes::_AsyncBaseType ^) this, _ProgressValue); }); } + } - internal: +private: + _ContextCallback _M_progressDelegateContext; + typename _Attributes::_ProgressDelegateType ^ _M_progressDelegate; +}; - typedef task<_ReturnType> _TaskType; +template +ref class _AsyncBaseProgressLayer abstract : _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType> +{ +}; - _AsyncTaskThunkBase(const _TaskType& _Task) - : _M_task(_Task) - { - } +// *************************************************************************** +// Task Adaptation Layer: +// - _AsyncTaskThunkBase() - { - } +// +// _AsyncTaskThunkBase provides a bridge between IAsync and task. +// +template +ref class _AsyncTaskThunkBase abstract : _AsyncBaseProgressLayer<_Attributes> +{ +public: + virtual _ReturnType GetResults() override + { + _CheckValidStateForResultsCall(); + return _M_task.get(); + } - protected: + internal : - virtual void _OnStart() override - { - _M_task.then( [=](_TaskType _Antecedent) { - try - { - _Antecedent.get(); - } - catch(task_canceled&) - { - _TryTransitionToCancelled(); - } - catch(::Platform::Exception^ _Ex) - { - _TryTransitionToError(_Ex->HResult); - } - catch(...) - { - _TryTransitionToError(E_FAIL); - } - _FireCompletion(); - }); - } + typedef task<_ReturnType> + _TaskType; - internal: + _AsyncTaskThunkBase(const _TaskType& _Task) : _M_task(_Task) {} - _TaskType _M_task; - cancellation_token_source _M_cts; - }; + _AsyncTaskThunkBase() {} - template - ref class _AsyncTaskThunk : _AsyncTaskThunkBase<_Attributes, typename _Attributes::_ReturnType> +protected: + virtual void _OnStart() override { - internal: + _M_task.then([=](_TaskType _Antecedent) { + try + { + _Antecedent.get(); + } + catch (task_canceled&) + { + _TryTransitionToCancelled(); + } + catch (::Platform::Exception ^ _Ex) + { + _TryTransitionToError(_Ex->HResult); + } + catch (...) + { + _TryTransitionToError(E_FAIL); + } + _FireCompletion(); + }); + } - _AsyncTaskThunk(const _TaskType& _Task) : - _AsyncTaskThunkBase(_Task) - { - } + internal : - _AsyncTaskThunk() - { - } + _TaskType _M_task; + cancellation_token_source _M_cts; +}; - protected: +template +ref class _AsyncTaskThunk : _AsyncTaskThunkBase<_Attributes, typename _Attributes::_ReturnType> +{ + internal : - virtual void _OnClose() override - { - } + _AsyncTaskThunk(const _TaskType& _Task) + : _AsyncTaskThunkBase(_Task) + { + } - virtual void _OnCancel() override - { - _M_cts.cancel(); - } - }; + _AsyncTaskThunk() {} - // *************************************************************************** - // Async Creation Layer: - // - template - ref class _AsyncTaskGeneratorThunk sealed : _AsyncTaskThunk::_AsyncAttributes> - { - internal: +protected: + virtual void _OnClose() override {} + + virtual void _OnCancel() override { _M_cts.cancel(); } +}; + +// *************************************************************************** +// Async Creation Layer: +// +template +ref class _AsyncTaskGeneratorThunk sealed + : _AsyncTaskThunk::_AsyncAttributes> +{ + internal : typedef typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes _Attributes; - typedef typename _AsyncTaskThunk<_Attributes> _Base; - typedef typename _Attributes::_AsyncBaseType _AsyncBaseType; + typedef typename _AsyncTaskThunk<_Attributes> _Base; + typedef typename _Attributes::_AsyncBaseType _AsyncBaseType; - _AsyncTaskGeneratorThunk(const _Function& _Func, const _TaskCreationCallstack &_callstack) : _M_func(_Func), _M_creationCallstack(_callstack) - { - // Virtual call here is safe as the class is declared 'sealed' - _Start(); - } + _AsyncTaskGeneratorThunk(const _Function& _Func, const _TaskCreationCallstack& _callstack) + : _M_func(_Func), _M_creationCallstack(_callstack) + { + // Virtual call here is safe as the class is declared 'sealed' + _Start(); + } - protected: +protected: + // + // The only thing we must do different from the base class is we must spin the hot task on transition from + // Created->Started. Otherwise, let the base thunk handle everything. + // + virtual void _OnStart() override + { // - // The only thing we must do different from the base class is we must spin the hot task on transition from Created->Started. Otherwise, - // let the base thunk handle everything. + // Call the appropriate task generator to actually produce a task of the expected type. This might adapt the + // user lambda for progress reports, wrap the return result in a task, or allow for direct return of a task + // depending on the form of the lambda. // + _M_task = _Attributes::_Generate_Task(_M_func, this, _M_cts, _M_creationCallstack); + _Base::_OnStart(); + } - virtual void _OnStart() override - { - // - // Call the appropriate task generator to actually produce a task of the expected type. This might adapt the user lambda for progress reports, - // wrap the return result in a task, or allow for direct return of a task depending on the form of the lambda. - // - _M_task = _Attributes::_Generate_Task(_M_func, this, _M_cts, _M_creationCallstack); - _Base::_OnStart(); - } - - virtual void _OnCancel() override - { - _Base::_OnCancel(); - } + virtual void _OnCancel() override { _Base::_OnCancel(); } - private: - _TaskCreationCallstack _M_creationCallstack; - _Function _M_func; - }; +private: + _TaskCreationCallstack _M_creationCallstack; + _Function _M_func; +}; } // namespace details /// -/// Creates a Windows Runtime asynchronous construct based on a user supplied lambda or function object. The return type of create_async is -/// one of either IAsyncAction^, IAsyncActionWithProgress<TProgress>^, IAsyncOperation<TResult>^, or -/// IAsyncOperationWithProgress<TResult, TProgress>^ based on the signature of the lambda passed to the method. +/// Creates a Windows Runtime asynchronous construct based on a user supplied lambda or function object. The return +/// type of create_async is one of either IAsyncAction^, +/// IAsyncActionWithProgress<TProgress>^, IAsyncOperation<TResult>^, or +/// IAsyncOperationWithProgress<TResult, TProgress>^ based on the signature of the lambda passed to the +/// method. /// /// /// The lambda or function object from which to create a Windows Runtime asynchronous construct. /// /// -/// An asynchronous construct represented by an IAsyncAction^, IAsyncActionWithProgress<TProgress>^, IAsyncOperation<TResult>^, or an -/// IAsyncOperationWithProgress<TResult, TProgress>^. The interface returned depends on the signature of the lambda passed into the function. +/// An asynchronous construct represented by an IAsyncAction^, IAsyncActionWithProgress<TProgress>^, +/// IAsyncOperation<TResult>^, or an IAsyncOperationWithProgress<TResult, TProgress>^. The interface +/// returned depends on the signature of the lambda passed into the function. /// /// /// The return type of the lambda determines whether the construct is an action or an operation. -/// Lambdas that return void cause the creation of actions. Lambdas that return a result of type TResult cause the creation of -/// operations of TResult. -/// The lambda may also return a task<TResult> which encapsulates the asynchronous work within itself or is the continuation of -/// a chain of tasks that represent the asynchronous work. In this case, the lambda itself is executed inline, since the tasks are the ones that -/// execute asynchronously, and the return type of the lambda is unwrapped to produce the asynchronous construct returned by create_async. -/// This implies that a lambda that returns a task<void> will cause the creation of actions, and a lambda that returns a task<TResult> will -/// cause the creation of operations of TResult. -/// The lambda may take either zero, one or two arguments. The valid arguments are progress_reporter<TProgress> and -/// cancellation_token, in that order if both are used. A lambda without arguments causes the creation of an asynchronous construct without -/// the capability for progress reporting. A lambda that takes a progress_reporter<TProgress> will cause create_async to return an asynchronous -/// construct which reports progress of type TProgress each time the report method of the progress_reporter object is called. A lambda that -/// takes a cancellation_token may use that token to check for cancellation, or pass it to tasks that it creates so that cancellation of the +/// Lambdas that return void cause the creation of actions. Lambdas that return a result of type +/// TResult cause the creation of operations of TResult. The lambda may also return a +/// task<TResult> which encapsulates the asynchronous work within itself or is the continuation of a +/// chain of tasks that represent the asynchronous work. In this case, the lambda itself is executed inline, since +/// the tasks are the ones that execute asynchronously, and the return type of the lambda is unwrapped to produce +/// the asynchronous construct returned by create_async. This implies that a lambda that returns a +/// task<void> will cause the creation of actions, and a lambda that returns a task<TResult> will cause +/// the creation of operations of TResult. The lambda may take either zero, one or two arguments. The +/// valid arguments are progress_reporter<TProgress> and cancellation_token, in that order if +/// both are used. A lambda without arguments causes the creation of an asynchronous construct without the +/// capability for progress reporting. A lambda that takes a progress_reporter<TProgress> will cause +/// create_async to return an asynchronous construct which reports progress of type TProgress each time the +/// report method of the progress_reporter object is called. A lambda that takes a cancellation_token may use +/// that token to check for cancellation, or pass it to tasks that it creates so that cancellation of the /// asynchronous construct causes cancellation of those tasks. -/// If the body of the lambda or function object returns a result (and not a task<TResult>), the lambda will be executed -/// asynchronously within the process MTA in the context of a task the Runtime implicitly creates for it. The IAsyncInfo::Cancel method will -/// cause cancellation of the implicit task. -/// If the body of the lambda returns a task, the lambda executes inline, and by declaring the lambda to take an argument of type -/// cancellation_token you can trigger cancellation of any tasks you create within the lambda by passing that token in when you create them. -/// You may also use the register_callback method on the token to cause the Runtime to invoke a callback when you call IAsyncInfo::Cancel on -/// the async operation or action produced.. -/// This function is only available to Windows Store apps. +/// If the body of the lambda or function object returns a result (and not a task<TResult>), the lambda +/// will be executed asynchronously within the process MTA in the context of a task the Runtime implicitly creates +/// for it. The IAsyncInfo::Cancel method will cause cancellation of the implicit task. If the +/// body of the lambda returns a task, the lambda executes inline, and by declaring the lambda to take an argument +/// of type cancellation_token you can trigger cancellation of any tasks you create within the lambda by +/// passing that token in when you create them. You may also use the register_callback method on the token to +/// cause the Runtime to invoke a callback when you call IAsyncInfo::Cancel on the async operation or action +/// produced.. This function is only available to Windows Store apps. /// /// /// /// /**/ template -__declspec(noinline) -details::_AsyncTaskGeneratorThunk<_Function> ^create_async(const _Function& _Func) -{ - static_assert(std::is_same::value, - "argument to create_async must be a callable object taking zero, one or two arguments"); - return ref new details::_AsyncTaskGeneratorThunk<_Function>(_Func, PPLX_CAPTURE_CALLSTACK()); -} + __declspec(noinline) details::_AsyncTaskGeneratorThunk<_Function> ^ + create_async(const _Function& _Func) { + static_assert(std::is_same::value, + "argument to create_async must be a callable object taking zero, one or two arguments"); + return ref new details::_AsyncTaskGeneratorThunk<_Function>(_Func, PPLX_CAPTURE_CALLSTACK()); + } -#endif /* defined (__cplusplus_winrt) */ +#endif /* defined (__cplusplus_winrt) */ -namespace details + namespace details { // Helper struct for when_all operators to know when tasks have completed template struct _RunAllParam { - _RunAllParam() : _M_completeCount(0), _M_numTasks(0) - { - } + _RunAllParam() : _M_completeCount(0), _M_numTasks(0) {} void _Resize(size_t _Len, bool _SkipVector = false) { @@ -6298,19 +6470,17 @@ namespace details } } - task_completion_event<_Unit_type> _M_completed; - _ResultHolder > _M_vector; - _ResultHolder<_Type> _M_mergeVal; - atomic_size_t _M_completeCount; - size_t _M_numTasks; + task_completion_event<_Unit_type> _M_completed; + _ResultHolder> _M_vector; + _ResultHolder<_Type> _M_mergeVal; + atomic_size_t _M_completeCount; + size_t _M_numTasks; }; template - struct _RunAllParam > + struct _RunAllParam> { - _RunAllParam() : _M_completeCount(0), _M_numTasks(0) - { - } + _RunAllParam() : _M_completeCount(0), _M_numTasks(0) {} void _Resize(size_t _Len, bool _SkipVector = false) { @@ -6322,43 +6492,37 @@ namespace details } } - task_completion_event<_Unit_type> _M_completed; - std::vector<_ResultHolder > > _M_vector; - atomic_size_t _M_completeCount; - size_t _M_numTasks; + task_completion_event<_Unit_type> _M_completed; + std::vector<_ResultHolder>> _M_vector; + atomic_size_t _M_completeCount; + size_t _M_numTasks; }; // Helper struct specialization for void template<> struct _RunAllParam<_Unit_type> { - _RunAllParam() : _M_completeCount(0), _M_numTasks(0) - { - } + _RunAllParam() : _M_completeCount(0), _M_numTasks(0) {} - void _Resize(size_t _Len) - { - _M_numTasks = _Len; - } + void _Resize(size_t _Len) { _M_numTasks = _Len; } task_completion_event<_Unit_type> _M_completed; atomic_size_t _M_completeCount; size_t _M_numTasks; }; - inline void _JoinAllTokens_Add(const cancellation_token_source& _MergedSrc, _CancellationTokenState *_PJoinedTokenState) + inline void _JoinAllTokens_Add(const cancellation_token_source& _MergedSrc, + _CancellationTokenState* _PJoinedTokenState) { if (_PJoinedTokenState != nullptr && _PJoinedTokenState != _CancellationTokenState::_None()) { cancellation_token _T = cancellation_token::_FromImpl(_PJoinedTokenState); - _T.register_callback( [=](){ - _MergedSrc.cancel(); - }); + _T.register_callback([=]() { _MergedSrc.cancel(); }); } } template - void _WhenAllContinuationWrapper(_RunAllParam<_ElementType>* _PParam, _Function _Func, task<_TaskType>& _Task) + void _WhenAllContinuationWrapper(_RunAllParam<_ElementType> * _PParam, _Function _Func, task<_TaskType> & _Task) { if (_Task._GetImpl()->_IsCompleted()) { @@ -6394,9 +6558,12 @@ namespace details template struct _WhenAllImpl { - static task> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) + static task> _Perform(const task_options& _TaskOptions, + _Iterator _Begin, + _Iterator _End) { - _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; + _CancellationTokenState* _PTokenState = + _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; auto _PParam = new _RunAllParam<_ElementType>(); cancellation_token_source _MergedSource; @@ -6406,9 +6573,8 @@ namespace details _Options.set_cancellation_token(_MergedSource.get_token()); task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options); // The return task must be created before step 3 to enforce inline execution. - auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> { - return _PParam->_M_vector.Get(); - }, nullptr); + auto _ReturnTask = _All_tasks_completed._Then( + [=](_Unit_type) -> std::vector<_ElementType> { return _PParam->_M_vector.Get(); }, nullptr); // Step2: Combine and check tokens, and count elements in range. if (_PTokenState) @@ -6428,7 +6594,7 @@ namespace details } // Step3: Check states of previous tasks. - if( _Begin == _End ) + if (_Begin == _End) { _PParam->_M_completed.set(_Unit_type()); delete _PParam; @@ -6443,16 +6609,17 @@ namespace details _ReturnTask._SetAsync(); } - _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) { - - auto _PParamCopy = _PParam; - auto _IndexCopy = _Index; - auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask](){ - _PParamCopy->_M_vector._Result[_IndexCopy] = _ResultTask._GetImpl()->_GetResult(); - }; + _PTask->_Then( + [_PParam, _Index](task<_ElementType> _ResultTask) { + auto _PParamCopy = _PParam; + auto _IndexCopy = _Index; + auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask]() { + _PParamCopy->_M_vector._Result[_IndexCopy] = _ResultTask._GetImpl()->_GetResult(); + }; - _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); - }, _CancellationTokenState::_None()); + _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); + }, + _CancellationTokenState::_None()); _Index++; } @@ -6465,9 +6632,12 @@ namespace details template struct _WhenAllImpl, _Iterator> { - static task> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) + static task> _Perform(const task_options& _TaskOptions, + _Iterator _Begin, + _Iterator _End) { - _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; + _CancellationTokenState* _PTokenState = + _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; auto _PParam = new _RunAllParam>(); cancellation_token_source _MergedSource; @@ -6477,16 +6647,18 @@ namespace details _Options.set_cancellation_token(_MergedSource.get_token()); task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options); // The return task must be created before step 3 to enforce inline execution. - auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> { - _ASSERTE(_PParam->_M_completeCount == _PParam->_M_numTasks); - std::vector<_ElementType> _Result; - for(size_t _I = 0; _I < _PParam->_M_numTasks; _I++) - { - const std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I].Get(); - _Result.insert(_Result.end(), _Vec.begin(), _Vec.end()); - } - return _Result; - }, nullptr); + auto _ReturnTask = _All_tasks_completed._Then( + [=](_Unit_type) -> std::vector<_ElementType> { + _ASSERTE(_PParam->_M_completeCount == _PParam->_M_numTasks); + std::vector<_ElementType> _Result; + for (size_t _I = 0; _I < _PParam->_M_numTasks; _I++) + { + const std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I].Get(); + _Result.insert(_Result.end(), _Vec.begin(), _Vec.end()); + } + return _Result; + }, + nullptr); // Step2: Combine and check tokens, and count elements in range. if (_PTokenState) @@ -6506,7 +6678,7 @@ namespace details } // Step3: Check states of previous tasks. - if( _Begin == _End ) + if (_Begin == _End) { _PParam->_M_completed.set(_Unit_type()); delete _PParam; @@ -6521,22 +6693,23 @@ namespace details _ReturnTask._SetAsync(); } - _PTask->_Then([_PParam, _Index](task> _ResultTask) { - - auto _PParamCopy = _PParam; - auto _IndexCopy = _Index; - auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask]() { - _PParamCopy->_M_vector[_IndexCopy].Set(_ResultTask._GetImpl()->_GetResult()); - }; + _PTask->_Then( + [_PParam, _Index](task> _ResultTask) { + auto _PParamCopy = _PParam; + auto _IndexCopy = _Index; + auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask]() { + _PParamCopy->_M_vector[_IndexCopy].Set(_ResultTask._GetImpl()->_GetResult()); + }; - _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); - }, _CancellationTokenState::_None()); + _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); + }, + _CancellationTokenState::_None()); _Index++; } } - return _ReturnTask; + return _ReturnTask; } }; @@ -6545,7 +6718,8 @@ namespace details { static task _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) { - _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; + _CancellationTokenState* _PTokenState = + _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; auto _PParam = new _RunAllParam<_Unit_type>(); cancellation_token_source _MergedSource; @@ -6555,8 +6729,7 @@ namespace details _Options.set_cancellation_token(_MergedSource.get_token()); task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options); // The return task must be created before step 3 to enforce inline execution. - auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) { - }, nullptr); + auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) {}, nullptr); // Step2: Combine and check tokens, and count elements in range. if (_PTokenState) @@ -6576,7 +6749,7 @@ namespace details } // Step3: Check states of previous tasks. - if( _Begin == _End ) + if (_Begin == _End) { _PParam->_M_completed.set(_Unit_type()); delete _PParam; @@ -6590,10 +6763,12 @@ namespace details _ReturnTask._SetAsync(); } - _PTask->_Then([_PParam](task _ResultTask) { - auto _Func = [](){}; - _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); - }, _CancellationTokenState::_None()); + _PTask->_Then( + [_PParam](task _ResultTask) { + auto _Func = []() {}; + _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); + }, + _CancellationTokenState::_None()); } } @@ -6602,8 +6777,8 @@ namespace details }; template - task> _WhenAllVectorAndValue(const task>& _VectorTask, const task<_ReturnType>& _ValueTask, - bool _OutputVectorFirst) + task> _WhenAllVectorAndValue( + const task>& _VectorTask, const task<_ReturnType>& _ValueTask, bool _OutputVectorFirst) { auto _PParam = new _RunAllParam<_ReturnType>(); cancellation_token_source _MergedSource; @@ -6611,21 +6786,23 @@ namespace details // Step1: Create task completion event. task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token()); // The return task must be created before step 3 to enforce inline execution. - auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ReturnType> { - _ASSERTE(_PParam->_M_completeCount == 2); - auto _Result = _PParam->_M_vector.Get(); // copy by value - auto _mergeVal = _PParam->_M_mergeVal.Get(); + auto _ReturnTask = _All_tasks_completed._Then( + [=](_Unit_type) -> std::vector<_ReturnType> { + _ASSERTE(_PParam->_M_completeCount == 2); + auto _Result = _PParam->_M_vector.Get(); // copy by value + auto _mergeVal = _PParam->_M_mergeVal.Get(); - if (_OutputVectorFirst == true) - { - _Result.push_back(_mergeVal); - } - else - { - _Result.insert(_Result.begin(), _mergeVal); - } - return _Result; - }, nullptr); + if (_OutputVectorFirst == true) + { + _Result.push_back(_mergeVal); + } + else + { + _Result.insert(_Result.begin(), _mergeVal); + } + return _Result; + }, + nullptr); // Step2: Combine and check tokens. _JoinAllTokens_Add(_MergedSource, _VectorTask._GetImpl()->_M_pTokenState); @@ -6638,31 +6815,36 @@ namespace details { _ReturnTask._SetAsync(); } - _VectorTask._Then([_PParam](task> _ResultTask) { - auto _PParamCopy = _PParam; - auto _Func = [_PParamCopy, &_ResultTask]() { - auto _ResultLocal = _ResultTask._GetImpl()->_GetResult(); - _PParamCopy->_M_vector.Set(_ResultLocal); - }; - - _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); - }, _CancellationTokenState::_None()); - _ValueTask._Then([_PParam](task<_ReturnType> _ResultTask) { - auto _PParamCopy = _PParam; - auto _Func = [_PParamCopy, &_ResultTask]() { - auto _ResultLocal = _ResultTask._GetImpl()->_GetResult(); - _PParamCopy->_M_mergeVal.Set(_ResultLocal); - }; - - _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); - }, _CancellationTokenState::_None()); + _VectorTask._Then( + [_PParam](task> _ResultTask) { + auto _PParamCopy = _PParam; + auto _Func = [_PParamCopy, &_ResultTask]() { + auto _ResultLocal = _ResultTask._GetImpl()->_GetResult(); + _PParamCopy->_M_vector.Set(_ResultLocal); + }; + + _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); + }, + _CancellationTokenState::_None()); + _ValueTask._Then( + [_PParam](task<_ReturnType> _ResultTask) { + auto _PParamCopy = _PParam; + auto _Func = [_PParamCopy, &_ResultTask]() { + auto _ResultLocal = _ResultTask._GetImpl()->_GetResult(); + _PParamCopy->_M_mergeVal.Set(_ResultLocal); + }; + + _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); + }, + _CancellationTokenState::_None()); return _ReturnTask; } } // namespace details /// -/// Creates a task that will complete successfully when all of the tasks supplied as arguments complete successfully. +/// Creates a task that will complete successfully when all of the tasks supplied as arguments complete +/// successfully. /// /// /// The type of the input iterator. @@ -6674,26 +6856,29 @@ namespace details /// The position of the first element beyond the range of elements to be combined into the resulting task. /// /// -/// A task that completes successfully when all of the input tasks have completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>>. If the input tasks are of type void the output -/// task will also be a task<void>. +/// A task that completes successfully when all of the input tasks have completed successfully. If the input tasks +/// are of type T, the output of this function will be a task<std::vector<T>>. If the +/// input tasks are of type void the output task will also be a task<void>. /// /// -/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, -/// if one is encountered, will be thrown if you call get() or wait() on that task. +/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled +/// state, and the exception, if one is encountered, will be thrown if you call get() or wait() on +/// that task. /// /// /**/ -template +template auto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options()) - -> decltype (details::_WhenAllImpl::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End)) + -> decltype(details::_WhenAllImpl::value_type::result_type, + _Iterator>::_Perform(_TaskOptions, _Begin, _End)) { typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType; return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End); } /// -/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully. +/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete +/// successfully. /// /// /// The type of the returned task. @@ -6705,27 +6890,30 @@ auto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions /// The second task to combine into the resulting task. /// /// -/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>>. If the input tasks are of type void the output -/// task will also be a task<void>. -/// To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator -/// produces a task<std::vector<T>> if either one or both of the tasks are of type task<std::vector<T>>. +/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks +/// are of type T, the output of this function will be a task<std::vector<T>>. If the +/// input tasks are of type void the output task will also be a task<void>. To allow for +/// a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && +/// operator produces a task<std::vector<T>> if either one or both of the tasks are of type +/// task<std::vector<T>>. /// /// -/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, -/// if one is encountered, will be thrown if you call get() or wait() on that task. +/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled +/// state, and the exception, if one is encountered, will be thrown if you call get() or wait() on +/// that task. /// /// /**/ template -auto operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) -> decltype(when_all(&_Lhs, &_Lhs)) +auto operator&&(const task<_ReturnType>& _Lhs, const task<_ReturnType>& _Rhs) -> decltype(when_all(&_Lhs, &_Lhs)) { task<_ReturnType> _PTasks[2] = {_Lhs, _Rhs}; - return when_all(_PTasks, _PTasks+2); + return when_all(_PTasks, _PTasks + 2); } /// -/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully. +/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete +/// successfully. /// /// /// The type of the returned task. @@ -6737,26 +6925,30 @@ auto operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) /// The second task to combine into the resulting task. /// /// -/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>>. If the input tasks are of type void the output -/// task will also be a task<void>. -/// To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator -/// produces a task<std::vector<T>> if either one or both of the tasks are of type task<std::vector<T>>. +/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks +/// are of type T, the output of this function will be a task<std::vector<T>>. If the +/// input tasks are of type void the output task will also be a task<void>. To allow for +/// a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && +/// operator produces a task<std::vector<T>> if either one or both of the tasks are of type +/// task<std::vector<T>>. /// /// -/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, -/// if one is encountered, will be thrown if you call get() or wait() on that task. +/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled +/// state, and the exception, if one is encountered, will be thrown if you call get() or wait() on +/// that task. /// /// /**/ template -auto operator&&(const task> & _Lhs, const task<_ReturnType> & _Rhs) -> decltype(details::_WhenAllVectorAndValue(_Lhs, _Rhs, true)) +auto operator&&(const task>& _Lhs, const task<_ReturnType>& _Rhs) + -> decltype(details::_WhenAllVectorAndValue(_Lhs, _Rhs, true)) { return details::_WhenAllVectorAndValue(_Lhs, _Rhs, true); } /// -/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully. +/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete +/// successfully. /// /// /// The type of the returned task. @@ -6768,26 +6960,30 @@ auto operator&&(const task> & _Lhs, const task<_ReturnT /// The second task to combine into the resulting task. /// /// -/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>>. If the input tasks are of type void the output -/// task will also be a task<void>. -/// To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator -/// produces a task<std::vector<T>> if either one or both of the tasks are of type task<std::vector<T>>. +/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks +/// are of type T, the output of this function will be a task<std::vector<T>>. If the +/// input tasks are of type void the output task will also be a task<void>. To allow for +/// a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && +/// operator produces a task<std::vector<T>> if either one or both of the tasks are of type +/// task<std::vector<T>>. /// /// -/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, -/// if one is encountered, will be thrown if you call get() or wait() on that task. +/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled +/// state, and the exception, if one is encountered, will be thrown if you call get() or wait() on +/// that task. /// /// /**/ template -auto operator&&(const task<_ReturnType> & _Lhs, const task> & _Rhs) -> decltype(details::_WhenAllVectorAndValue(_Rhs, _Lhs, false)) +auto operator&&(const task<_ReturnType>& _Lhs, const task>& _Rhs) + -> decltype(details::_WhenAllVectorAndValue(_Rhs, _Lhs, false)) { return details::_WhenAllVectorAndValue(_Rhs, _Lhs, false); } /// -/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully. +/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete +/// successfully. /// /// /// The type of the returned task. @@ -6799,225 +6995,247 @@ auto operator&&(const task<_ReturnType> & _Lhs, const task /// -/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>>. If the input tasks are of type void the output -/// task will also be a task<void>. -/// To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator -/// produces a task<std::vector<T>> if either one or both of the tasks are of type task<std::vector<T>>. +/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks +/// are of type T, the output of this function will be a task<std::vector<T>>. If the +/// input tasks are of type void the output task will also be a task<void>. To allow for +/// a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && +/// operator produces a task<std::vector<T>> if either one or both of the tasks are of type +/// task<std::vector<T>>. /// /// -/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, -/// if one is encountered, will be thrown if you call get() or wait() on that task. +/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled +/// state, and the exception, if one is encountered, will be thrown if you call get() or wait() on +/// that task. /// /// /**/ template -auto operator&&(const task> & _Lhs, const task> & _Rhs) -> decltype(when_all(&_Lhs, &_Lhs)) +auto operator&&(const task>& _Lhs, const task>& _Rhs) + -> decltype(when_all(&_Lhs, &_Lhs)) { task> _PTasks[2] = {_Lhs, _Rhs}; - return when_all(_PTasks, _PTasks+2); + return when_all(_PTasks, _PTasks + 2); } namespace details { - // Helper struct for when_any operators to know when tasks have completed - template - struct _RunAnyParam +// Helper struct for when_any operators to know when tasks have completed +template +struct _RunAnyParam +{ + _RunAnyParam() : _M_exceptionRelatedToken(nullptr), _M_completeCount(0), _M_numTasks(0), _M_fHasExplicitToken(false) { - _RunAnyParam() : _M_exceptionRelatedToken(nullptr), _M_completeCount(0), _M_numTasks(0), _M_fHasExplicitToken(false) - { - } - ~_RunAnyParam() - { - if (_CancellationTokenState::_IsValid(_M_exceptionRelatedToken)) - _M_exceptionRelatedToken->_Release(); - } - task_completion_event<_CompletionType> _M_Completed; - cancellation_token_source _M_cancellationSource; - _CancellationTokenState * _M_exceptionRelatedToken; - atomic_size_t _M_completeCount; - size_t _M_numTasks; - bool _M_fHasExplicitToken; - }; + } + ~_RunAnyParam() + { + if (_CancellationTokenState::_IsValid(_M_exceptionRelatedToken)) _M_exceptionRelatedToken->_Release(); + } + task_completion_event<_CompletionType> _M_Completed; + cancellation_token_source _M_cancellationSource; + _CancellationTokenState* _M_exceptionRelatedToken; + atomic_size_t _M_completeCount; + size_t _M_numTasks; + bool _M_fHasExplicitToken; +}; - template - void _WhenAnyContinuationWrapper(_RunAnyParam<_CompletionType> * _PParam, const _Function & _Func, task<_TaskType>& _Task) +template +void _WhenAnyContinuationWrapper(_RunAnyParam<_CompletionType>* _PParam, const _Function& _Func, task<_TaskType>& _Task) +{ + bool _IsTokenCancled = !_PParam->_M_fHasExplicitToken && + _Task._GetImpl()->_M_pTokenState != _CancellationTokenState::_None() && + _Task._GetImpl()->_M_pTokenState->_IsCanceled(); + if (_Task._GetImpl()->_IsCompleted() && !_IsTokenCancled) { - bool _IsTokenCancled = !_PParam->_M_fHasExplicitToken && _Task._GetImpl()->_M_pTokenState != _CancellationTokenState::_None() && _Task._GetImpl()->_M_pTokenState->_IsCanceled(); - if (_Task._GetImpl()->_IsCompleted() && !_IsTokenCancled) + _Func(); + if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks) { - _Func(); - if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks) - { - delete _PParam; - } + delete _PParam; } - else + } + else + { + _ASSERTE(_Task._GetImpl()->_IsCanceled() || _IsTokenCancled); + if (_Task._GetImpl()->_HasUserException() && !_IsTokenCancled) { - _ASSERTE(_Task._GetImpl()->_IsCanceled() || _IsTokenCancled); - if (_Task._GetImpl()->_HasUserException() && !_IsTokenCancled) + if (_PParam->_M_Completed._StoreException(_Task._GetImpl()->_GetExceptionHolder())) { - if (_PParam->_M_Completed._StoreException(_Task._GetImpl()->_GetExceptionHolder())) + // This can only enter once. + _PParam->_M_exceptionRelatedToken = _Task._GetImpl()->_M_pTokenState; + _ASSERTE(_PParam->_M_exceptionRelatedToken); + // Deref token will be done in the _PParam destructor. + if (_PParam->_M_exceptionRelatedToken != _CancellationTokenState::_None()) { - // This can only enter once. - _PParam->_M_exceptionRelatedToken = _Task._GetImpl()->_M_pTokenState; - _ASSERTE(_PParam->_M_exceptionRelatedToken); - // Deref token will be done in the _PParam destructor. - if (_PParam->_M_exceptionRelatedToken != _CancellationTokenState::_None()) - { - _PParam->_M_exceptionRelatedToken->_Reference(); - } + _PParam->_M_exceptionRelatedToken->_Reference(); } } + } - if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks) + if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks) + { + // If no one has be completed so far, we need to make some final cancellation decision. + if (!_PParam->_M_Completed._IsTriggered()) { - // If no one has be completed so far, we need to make some final cancellation decision. - if (!_PParam->_M_Completed._IsTriggered()) + // If we already explicit token, we can skip the token join part. + if (!_PParam->_M_fHasExplicitToken) { - // If we already explicit token, we can skip the token join part. - if (!_PParam->_M_fHasExplicitToken) + if (_PParam->_M_exceptionRelatedToken) { - if (_PParam->_M_exceptionRelatedToken) - { - _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PParam->_M_exceptionRelatedToken); - } - else - { - // If haven't captured any exception token yet, there was no exception for all those tasks, - // so just pick a random token (current one) for normal cancellation. - _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Task._GetImpl()->_M_pTokenState); - } + _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PParam->_M_exceptionRelatedToken); + } + else + { + // If haven't captured any exception token yet, there was no exception for all those tasks, + // so just pick a random token (current one) for normal cancellation. + _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Task._GetImpl()->_M_pTokenState); } - // Do exception cancellation or normal cancellation based on whether it has stored exception. - _PParam->_M_Completed._Cancel(); } - delete _PParam; + // Do exception cancellation or normal cancellation based on whether it has stored exception. + _PParam->_M_Completed._Cancel(); } + delete _PParam; } } +} - template - struct _WhenAnyImpl +template +struct _WhenAnyImpl +{ + static task> _Perform(const task_options& _TaskOptions, + _Iterator _Begin, + _Iterator _End) { - static task> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) + if (_Begin == _End) { - if( _Begin == _End ) - { - throw invalid_operation("when_any(begin, end) cannot be called on an empty container."); - } - _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; - auto _PParam = new _RunAnyParam, _CancellationTokenState *>>(); + throw invalid_operation("when_any(begin, end) cannot be called on an empty container."); + } + _CancellationTokenState* _PTokenState = + _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; + auto _PParam = new _RunAnyParam, _CancellationTokenState*>>(); - if (_PTokenState) - { - _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState); - _PParam->_M_fHasExplicitToken = true; - } + if (_PTokenState) + { + _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState); + _PParam->_M_fHasExplicitToken = true; + } - task_options _Options(_TaskOptions); - _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token()); - task, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options); + task_options _Options(_TaskOptions); + _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token()); + task, _CancellationTokenState*>> _Any_tasks_completed( + _PParam->_M_Completed, _Options); - // Keep a copy ref to the token source - auto _CancellationSource = _PParam->_M_cancellationSource; + // Keep a copy ref to the token source + auto _CancellationSource = _PParam->_M_cancellationSource; - _PParam->_M_numTasks = static_cast(std::distance(_Begin, _End)); - size_t _Index = 0; - for (auto _PTask = _Begin; _PTask != _End; ++_PTask) + _PParam->_M_numTasks = static_cast(std::distance(_Begin, _End)); + size_t _Index = 0; + for (auto _PTask = _Begin; _PTask != _End; ++_PTask) + { + if (_PTask->is_apartment_aware()) { - if (_PTask->is_apartment_aware()) - { - _Any_tasks_completed._SetAsync(); - } + _Any_tasks_completed._SetAsync(); + } - _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) { + _PTask->_Then( + [_PParam, _Index](task<_ElementType> _ResultTask) { auto _PParamCopy = _PParam; // Dev10 - auto _IndexCopy = _Index; // Dev10 + auto _IndexCopy = _Index; // Dev10 auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() { - _PParamCopy->_M_Completed.set(std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _IndexCopy), _ResultTask._GetImpl()->_M_pTokenState)); + _PParamCopy->_M_Completed.set( + std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _IndexCopy), + _ResultTask._GetImpl()->_M_pTokenState)); }; _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); - }, _CancellationTokenState::_None()); + }, + _CancellationTokenState::_None()); - _Index++; - } + _Index++; + } - // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created. - return _Any_tasks_completed._Then([=](std::pair, _CancellationTokenState *> _Result) -> std::pair<_ElementType, size_t> { + // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created. + return _Any_tasks_completed._Then( + [=](std::pair, _CancellationTokenState*> _Result) + -> std::pair<_ElementType, size_t> { _ASSERTE(_Result.second); if (!_PTokenState) { _JoinAllTokens_Add(_CancellationSource, _Result.second); } return _Result.first; - }, nullptr); - } - }; + }, + nullptr); + } +}; - template - struct _WhenAnyImpl +template +struct _WhenAnyImpl +{ + static task _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) { - static task _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) + if (_Begin == _End) { - if( _Begin == _End ) - { - throw invalid_operation("when_any(begin, end) cannot be called on an empty container."); - } + throw invalid_operation("when_any(begin, end) cannot be called on an empty container."); + } - _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; - auto _PParam = new _RunAnyParam>(); + _CancellationTokenState* _PTokenState = + _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; + auto _PParam = new _RunAnyParam>(); - if (_PTokenState) - { - _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState); - _PParam->_M_fHasExplicitToken = true; - } + if (_PTokenState) + { + _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState); + _PParam->_M_fHasExplicitToken = true; + } - task_options _Options(_TaskOptions); - _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token()); - task> _Any_tasks_completed(_PParam->_M_Completed, _Options); + task_options _Options(_TaskOptions); + _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token()); + task> _Any_tasks_completed(_PParam->_M_Completed, _Options); - // Keep a copy ref to the token source - auto _CancellationSource = _PParam->_M_cancellationSource; + // Keep a copy ref to the token source + auto _CancellationSource = _PParam->_M_cancellationSource; - _PParam->_M_numTasks = static_cast(std::distance(_Begin, _End)); - size_t _Index = 0; - for (auto _PTask = _Begin; _PTask != _End; ++_PTask) + _PParam->_M_numTasks = static_cast(std::distance(_Begin, _End)); + size_t _Index = 0; + for (auto _PTask = _Begin; _PTask != _End; ++_PTask) + { + if (_PTask->is_apartment_aware()) { - if (_PTask->is_apartment_aware()) - { - _Any_tasks_completed._SetAsync(); - } + _Any_tasks_completed._SetAsync(); + } - _PTask->_Then([_PParam, _Index](task _ResultTask) { + _PTask->_Then( + [_PParam, _Index](task _ResultTask) { auto _PParamCopy = _PParam; // Dev10 - auto _IndexCopy = _Index; // Dev10 + auto _IndexCopy = _Index; // Dev10 auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() { - _PParamCopy->_M_Completed.set(std::make_pair(_IndexCopy, _ResultTask._GetImpl()->_M_pTokenState)); + _PParamCopy->_M_Completed.set( + std::make_pair(_IndexCopy, _ResultTask._GetImpl()->_M_pTokenState)); }; _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); - }, _CancellationTokenState::_None()); + }, + _CancellationTokenState::_None()); - _Index++; - } + _Index++; + } - // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created. - return _Any_tasks_completed._Then([=](std::pair _Result) -> size_t { + // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created. + return _Any_tasks_completed._Then( + [=](std::pair _Result) -> size_t { _ASSERTE(_Result.second); if (!_PTokenState) { _JoinAllTokens_Add(_CancellationSource, _Result.second); } return _Result.first; - }, nullptr); - } - }; + }, + nullptr); + } +}; } // namespace details /// -/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. +/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes +/// successfully. /// /// /// The type of the input iterator. @@ -7029,23 +7247,26 @@ namespace details /// The position of the first element beyond the range of elements to be combined into the resulting task. /// /// -/// A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::pair<T, size_t>>>, where the first element of the pair is the result -/// of the completing task, and the second element is the index of the task that finished. If the input tasks are of type void -/// the output is a task<size_t>, where the result is the index of the completing task. +/// A task that completes successfully when any one of the input tasks has completed successfully. If the input +/// tasks are of type T, the output of this function will be a task<std::pair<T, +/// size_t>>>, where the first element of the pair is the result of the completing task, and the second +/// element is the index of the task that finished. If the input tasks are of type void the output is a +/// task<size_t>, where the result is the index of the completing task. /// /// /**/ template auto when_any(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options()) - -> decltype (details::_WhenAnyImpl::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End)) + -> decltype(details::_WhenAnyImpl::value_type::result_type, + _Iterator>::_Perform(_TaskOptions, _Begin, _End)) { typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType; return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End); } /// -/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. +/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes +/// successfully. /// /// /// The type of the input iterator. @@ -7057,27 +7278,30 @@ auto when_any(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions /// The position of the first element beyond the range of elements to be combined into the resulting task. /// /// -/// The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token, the resulting -/// task will receive the cancellation token of the task that causes it to complete. +/// The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation +/// token, the resulting task will receive the cancellation token of the task that causes it to complete. /// /// -/// A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::pair<T, size_t>>>, where the first element of the pair is the result -/// of the completing task, and the second element is the index of the task that finished. If the input tasks are of type void -/// the output is a task<size_t>, where the result is the index of the completing task. +/// A task that completes successfully when any one of the input tasks has completed successfully. If the input +/// tasks are of type T, the output of this function will be a task<std::pair<T, +/// size_t>>>, where the first element of the pair is the result of the completing task, and the second +/// element is the index of the task that finished. If the input tasks are of type void the output is a +/// task<size_t>, where the result is the index of the completing task. /// /// /**/ template auto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken) - -> decltype (details::_WhenAnyImpl::value_type::result_type, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End)) + -> decltype(details::_WhenAnyImpl::value_type::result_type, + _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End)) { typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType; return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End); } /// -/// Creates a task that will complete successfully when either of the tasks supplied as arguments completes successfully. +/// Creates a task that will complete successfully when either of the tasks supplied as arguments completes +/// successfully. /// /// /// The type of the returned task. @@ -7089,32 +7313,37 @@ auto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _Cancellation /// The second task to combine into the resulting task. /// /// -/// A task that completes successfully when either of the input tasks has completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>. If the input tasks are of type void the output task -/// will also be a task<void>. -/// To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence -/// over ||, the operator|| produces a task<std::vector<T>> if one of the tasks is of type task<std::vector<T>> -/// and the other one is of type task<T>. +/// A task that completes successfully when either of the input tasks has completed successfully. If the input tasks +/// are of type T, the output of this function will be a task<std::vector<T>. If the input +/// tasks are of type void the output task will also be a task<void>. To allow for a +/// construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking +/// precedence over ||, the operator|| produces a task<std::vector<T>> if one of the tasks is of +/// type task<std::vector<T>> and the other one is of type task<T>. /// /// -/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions, -/// if any are encountered, will be thrown when you call get() or wait() on that task. +/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, +/// and one of the exceptions, if any are encountered, will be thrown when you call get() or wait() on +/// that task. /// /// /**/ template -task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) +task<_ReturnType> operator||(const task<_ReturnType>& _Lhs, const task<_ReturnType>& _Rhs) { auto _PParam = new details::_RunAnyParam>(); - task> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); + task> _Any_tasks_completed(_PParam->_M_Completed, + _PParam->_M_cancellationSource.get_token()); // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called, // So that _PParam can be used before it getting deleted. - auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<_ReturnType, size_t> _Ret) -> _ReturnType { - _ASSERTE(_Ret.second); - _JoinAllTokens_Add(_PParam->_M_cancellationSource, reinterpret_cast(_Ret.second)); - return _Ret.first; - }, nullptr); + auto _ReturnTask = _Any_tasks_completed._Then( + [=](std::pair<_ReturnType, size_t> _Ret) -> _ReturnType { + _ASSERTE(_Ret.second); + _JoinAllTokens_Add(_PParam->_M_cancellationSource, + reinterpret_cast(_Ret.second)); + return _Ret.first; + }, + nullptr); if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware()) { @@ -7126,7 +7355,9 @@ task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnT // Dev10 compiler bug auto _PParamCopy = _PParam; auto _Func = [&_ResultTask, _PParamCopy]() { - _PParamCopy->_M_Completed.set(std::make_pair(_ResultTask._GetImpl()->_GetResult(), reinterpret_cast(_ResultTask._GetImpl()->_M_pTokenState))); + _PParamCopy->_M_Completed.set( + std::make_pair(_ResultTask._GetImpl()->_GetResult(), + reinterpret_cast(_ResultTask._GetImpl()->_M_pTokenState))); }; _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); }; @@ -7138,7 +7369,8 @@ task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnT } /// -/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. +/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes +/// successfully. /// /// /// The type of the returned task. @@ -7150,33 +7382,37 @@ task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnT /// The second task to combine into the resulting task. /// /// -/// A task that completes successfully when either of the input tasks has completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>. If the input tasks are of type void the output task -/// will also be a task<void>. -/// To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence -/// over ||, the operator|| produces a task<std::vector<T>> if one of the tasks is of type task<std::vector<T>> -/// and the other one is of type task<T>. +/// A task that completes successfully when either of the input tasks has completed successfully. If the input tasks +/// are of type T, the output of this function will be a task<std::vector<T>. If the input +/// tasks are of type void the output task will also be a task<void>. To allow for a +/// construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking +/// precedence over ||, the operator|| produces a task<std::vector<T>> if one of the tasks is of +/// type task<std::vector<T>> and the other one is of type task<T>. /// /// -/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions, -/// if any are encountered, will be thrown when you call get() or wait() on that task. +/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, +/// and one of the exceptions, if any are encountered, will be thrown when you call get() or wait() on +/// that task. /// /// /**/ template -task> operator||(const task> & _Lhs, const task<_ReturnType> & _Rhs) +task> operator||(const task>& _Lhs, const task<_ReturnType>& _Rhs) { - auto _PParam = new details::_RunAnyParam, details::_CancellationTokenState *>>(); + auto _PParam = new details::_RunAnyParam, details::_CancellationTokenState*>>(); - task, details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); + task, details::_CancellationTokenState*>> _Any_tasks_completed( + _PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called, // So that _PParam can be used before it getting deleted. - auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair, details::_CancellationTokenState *> _Ret) -> std::vector<_ReturnType> { - _ASSERTE(_Ret.second); - _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second); - return _Ret.first; - }, nullptr); + auto _ReturnTask = _Any_tasks_completed._Then( + [=](std::pair, details::_CancellationTokenState*> _Ret) -> std::vector<_ReturnType> { + _ASSERTE(_Ret.second); + _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second); + return _Ret.first; + }, + nullptr); if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware()) { @@ -7184,35 +7420,38 @@ task> operator||(const task> & } _PParam->_M_numTasks = 2; - _Lhs._Then([_PParam](task> _ResultTask) { - // Dev10 compiler bug - auto _PParamCopy = _PParam; - auto _Func = [&_ResultTask, _PParamCopy]() { - auto _Result = _ResultTask._GetImpl()->_GetResult(); - _PParamCopy->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState)); - }; - _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); - }, details::_CancellationTokenState::_None()); - + _Lhs._Then( + [_PParam](task> _ResultTask) { + // Dev10 compiler bug + auto _PParamCopy = _PParam; + auto _Func = [&_ResultTask, _PParamCopy]() { + auto _Result = _ResultTask._GetImpl()->_GetResult(); + _PParamCopy->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState)); + }; + _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); + }, + details::_CancellationTokenState::_None()); - _Rhs._Then([_PParam](task<_ReturnType> _ResultTask) - { - auto _PParamCopy = _PParam; - auto _Func = [&_ResultTask, _PParamCopy]() { - auto _Result = _ResultTask._GetImpl()->_GetResult(); + _Rhs._Then( + [_PParam](task<_ReturnType> _ResultTask) { + auto _PParamCopy = _PParam; + auto _Func = [&_ResultTask, _PParamCopy]() { + auto _Result = _ResultTask._GetImpl()->_GetResult(); - std::vector<_ReturnType> _Vec; - _Vec.push_back(_Result); - _PParamCopy->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState)); - }; - _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); - }, details::_CancellationTokenState::_None()); + std::vector<_ReturnType> _Vec; + _Vec.push_back(_Result); + _PParamCopy->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState)); + }; + _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); + }, + details::_CancellationTokenState::_None()); return _ReturnTask; } /// -/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. +/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes +/// successfully. /// /// /// The type of the returned task. @@ -7224,27 +7463,29 @@ task> operator||(const task> & /// The second task to combine into the resulting task. /// /// -/// A task that completes successfully when either of the input tasks has completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>. If the input tasks are of type void the output task -/// will also be a task<void>. -/// To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence -/// over ||, the operator|| produces a task<std::vector<T>> if one of the tasks is of type task<std::vector<T>> -/// and the other one is of type task<T>. +/// A task that completes successfully when either of the input tasks has completed successfully. If the input tasks +/// are of type T, the output of this function will be a task<std::vector<T>. If the input +/// tasks are of type void the output task will also be a task<void>. To allow for a +/// construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking +/// precedence over ||, the operator|| produces a task<std::vector<T>> if one of the tasks is of +/// type task<std::vector<T>> and the other one is of type task<T>. /// /// -/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions, -/// if any are encountered, will be thrown when you call get() or wait() on that task. +/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, +/// and one of the exceptions, if any are encountered, will be thrown when you call get() or wait() on +/// that task. /// /// /**/ template -auto operator||(const task<_ReturnType> & _Lhs, const task> & _Rhs) -> decltype(_Rhs || _Lhs) +auto operator||(const task<_ReturnType>& _Lhs, const task>& _Rhs) -> decltype(_Rhs || _Lhs) { return _Rhs || _Lhs; } /// -/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. +/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes +/// successfully. /// /// /// The type of the returned task. @@ -7256,33 +7497,37 @@ auto operator||(const task<_ReturnType> & _Lhs, const task /// -/// A task that completes successfully when either of the input tasks has completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>. If the input tasks are of type void the output task -/// will also be a task<void>. -/// To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence -/// over ||, the operator|| produces a task<std::vector<T>> if one of the tasks is of type task<std::vector<T>> -/// and the other one is of type task<T>. +/// A task that completes successfully when either of the input tasks has completed successfully. If the input tasks +/// are of type T, the output of this function will be a task<std::vector<T>. If the input +/// tasks are of type void the output task will also be a task<void>. To allow for a +/// construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking +/// precedence over ||, the operator|| produces a task<std::vector<T>> if one of the tasks is of +/// type task<std::vector<T>> and the other one is of type task<T>. /// /// -/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions, -/// if any are encountered, will be thrown when you call get() or wait() on that task. +/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, +/// and one of the exceptions, if any are encountered, will be thrown when you call get() or wait() on +/// that task. /// /// /**/ -template, typename _Pair = std::pair> -_Ty operator||(const task & _Lhs_arg, const task & _Rhs_arg) +template, typename _Pair = std::pair> +_Ty operator||(const task& _Lhs_arg, const task& _Rhs_arg) { const _Ty& _Lhs = _Lhs_arg; const _Ty& _Rhs = _Rhs_arg; auto _PParam = new details::_RunAnyParam<_Pair>(); - task> _Any_task_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); + task> _Any_task_completed( + _PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called, // So that _PParam can be used before it getting deleted. - auto _ReturnTask = _Any_task_completed._Then([=](_Pair _Ret) { - _ASSERTE(_Ret.second); - details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second); - }, nullptr); + auto _ReturnTask = _Any_task_completed._Then( + [=](_Pair _Ret) { + _ASSERTE(_Ret.second); + details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second); + }, + nullptr); if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware()) { @@ -7329,7 +7574,7 @@ task<_TaskType> task_from_exception(_ExType _Exception, const task_options& _Tas return create_task(_Tce, _TaskOptions); } -} // namespace Concurrency +} // namespace pplx #pragma pop_macro("new") @@ -7345,7 +7590,9 @@ task<_TaskType> task_from_exception(_ExType _Exception, const task_options& _Tas #define _LWRCASE_CNCRRNCY // Note to reader: we're using lower-case namespace names everywhere, but the 'Concurrency' namespace // is capitalized for historical reasons. The alias let's us pretend that style issue doesn't exist. -namespace Concurrency {} +namespace Concurrency +{ +} namespace concurrency = Concurrency; #endif #endif diff --git a/Release/include/pplx/pplxwin.h b/Release/include/pplx/pplxwin.h index faa49a59df..95a23b3158 100644 --- a/Release/include/pplx/pplxwin.h +++ b/Release/include/pplx/pplxwin.h @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Windows specific pplx implementations -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Windows specific pplx implementations + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -20,199 +20,184 @@ namespace pplx { - namespace details { - namespace platform - { - /// - /// Returns a unique identifier for the execution thread where this routine in invoked - /// - _PPLXIMP long __cdecl GetCurrentThreadId(); +namespace platform +{ +/// +/// Returns a unique identifier for the execution thread where this routine in invoked +/// +_PPLXIMP long __cdecl GetCurrentThreadId(); - /// - /// Yields the execution of the current execution thread - typically when spin-waiting - /// - _PPLXIMP void __cdecl YieldExecution(); +/// +/// Yields the execution of the current execution thread - typically when spin-waiting +/// +_PPLXIMP void __cdecl YieldExecution(); - /// - /// Captures the callstack - /// - __declspec(noinline) _PPLXIMP size_t __cdecl CaptureCallstack(void **, size_t, size_t); +/// +/// Captures the callstack +/// +__declspec(noinline) _PPLXIMP size_t __cdecl CaptureCallstack(void**, size_t, size_t); #if defined(__cplusplus_winrt) - /// - // Internal API which retrieves the next async id. - /// - _PPLXIMP unsigned int __cdecl GetNextAsyncId(); +/// +// Internal API which retrieves the next async id. +/// +_PPLXIMP unsigned int __cdecl GetNextAsyncId(); #endif - } - - /// - /// Manual reset event - /// - class event_impl - { - public: +} // namespace platform - static const unsigned int timeout_infinite = 0xFFFFFFFF; - - _PPLXIMP event_impl(); - - _PPLXIMP ~event_impl(); +/// +/// Manual reset event +/// +class event_impl +{ +public: + static const unsigned int timeout_infinite = 0xFFFFFFFF; - _PPLXIMP void set(); + _PPLXIMP event_impl(); - _PPLXIMP void reset(); + _PPLXIMP ~event_impl(); - _PPLXIMP unsigned int wait(unsigned int timeout); + _PPLXIMP void set(); - unsigned int wait() - { - return wait(event_impl::timeout_infinite); - } + _PPLXIMP void reset(); - private: - // Windows events - void * _M_impl; + _PPLXIMP unsigned int wait(unsigned int timeout); - event_impl(const event_impl&); // no copy constructor - event_impl const & operator=(const event_impl&); // no assignment operator - }; + unsigned int wait() { return wait(event_impl::timeout_infinite); } - /// - /// Mutex - lock for mutual exclusion - /// - class critical_section_impl - { - public: +private: + // Windows events + void* _M_impl; - _PPLXIMP critical_section_impl(); + event_impl(const event_impl&); // no copy constructor + event_impl const& operator=(const event_impl&); // no assignment operator +}; - _PPLXIMP ~critical_section_impl(); +/// +/// Mutex - lock for mutual exclusion +/// +class critical_section_impl +{ +public: + _PPLXIMP critical_section_impl(); - _PPLXIMP void lock(); + _PPLXIMP ~critical_section_impl(); - _PPLXIMP void unlock(); + _PPLXIMP void lock(); - private: + _PPLXIMP void unlock(); - typedef void * _PPLX_BUFFER; +private: + typedef void* _PPLX_BUFFER; - // Windows critical section - _PPLX_BUFFER _M_impl[8]; + // Windows critical section + _PPLX_BUFFER _M_impl[8]; - critical_section_impl(const critical_section_impl&); // no copy constructor - critical_section_impl const & operator=(const critical_section_impl&); // no assignment operator - }; + critical_section_impl(const critical_section_impl&); // no copy constructor + critical_section_impl const& operator=(const critical_section_impl&); // no assignment operator +}; -#if _WIN32_WINNT >= _WIN32_WINNT_VISTA - /// - /// Reader writer lock - /// - class reader_writer_lock_impl +#if _WIN32_WINNT >= _WIN32_WINNT_VISTA +/// +/// Reader writer lock +/// +class reader_writer_lock_impl +{ +public: + class scoped_lock_read { public: - - class scoped_lock_read + explicit scoped_lock_read(reader_writer_lock_impl& _Reader_writer_lock) + : _M_reader_writer_lock(_Reader_writer_lock) { - public: - explicit scoped_lock_read(reader_writer_lock_impl &_Reader_writer_lock) : _M_reader_writer_lock(_Reader_writer_lock) - { - _M_reader_writer_lock.lock_read(); - } + _M_reader_writer_lock.lock_read(); + } - ~scoped_lock_read() - { - _M_reader_writer_lock.unlock(); - } + ~scoped_lock_read() { _M_reader_writer_lock.unlock(); } + + private: + reader_writer_lock_impl& _M_reader_writer_lock; + scoped_lock_read(const scoped_lock_read&); // no copy constructor + scoped_lock_read const& operator=(const scoped_lock_read&); // no assignment operator + }; - private: - reader_writer_lock_impl& _M_reader_writer_lock; - scoped_lock_read(const scoped_lock_read&); // no copy constructor - scoped_lock_read const & operator=(const scoped_lock_read&); // no assignment operator - }; + _PPLXIMP reader_writer_lock_impl(); - _PPLXIMP reader_writer_lock_impl(); + _PPLXIMP void lock(); - _PPLXIMP void lock(); + _PPLXIMP void lock_read(); - _PPLXIMP void lock_read(); + _PPLXIMP void unlock(); - _PPLXIMP void unlock(); +private: + // Windows slim reader writer lock + void* _M_impl; + + // Slim reader writer lock doesn't have a general 'unlock' method. + // We need to track how it was acquired and release accordingly. + // true - lock exclusive + // false - lock shared + bool m_locked_exclusive; +}; +#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA - private: +/// +/// Recursive mutex +/// +class recursive_lock_impl +{ +public: + recursive_lock_impl() : _M_owner(-1), _M_recursionCount(0) {} - // Windows slim reader writer lock - void * _M_impl; - - // Slim reader writer lock doesn't have a general 'unlock' method. - // We need to track how it was acquired and release accordingly. - // true - lock exclusive - // false - lock shared - bool m_locked_exclusive; - }; -#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA - - /// - /// Recursive mutex - /// - class recursive_lock_impl + ~recursive_lock_impl() { - public: + _ASSERTE(_M_owner == -1); + _ASSERTE(_M_recursionCount == 0); + } - recursive_lock_impl() - : _M_owner(-1), _M_recursionCount(0) - { - } + void lock() + { + auto id = ::pplx::details::platform::GetCurrentThreadId(); - ~recursive_lock_impl() + if (_M_owner == id) { - _ASSERTE(_M_owner == -1); - _ASSERTE(_M_recursionCount == 0); + _M_recursionCount++; } - - void lock() + else { - auto id = ::pplx::details::platform::GetCurrentThreadId(); - - if ( _M_owner == id ) - { - _M_recursionCount++; - } - else - { - _M_cs.lock(); - _M_owner = id; - _M_recursionCount = 1; - } + _M_cs.lock(); + _M_owner = id; + _M_recursionCount = 1; } + } - void unlock() - { - _ASSERTE(_M_owner == ::pplx::details::platform::GetCurrentThreadId()); - _ASSERTE(_M_recursionCount >= 1); + void unlock() + { + _ASSERTE(_M_owner == ::pplx::details::platform::GetCurrentThreadId()); + _ASSERTE(_M_recursionCount >= 1); - _M_recursionCount--; + _M_recursionCount--; - if ( _M_recursionCount == 0 ) - { - _M_owner = -1; - _M_cs.unlock(); - } + if (_M_recursionCount == 0) + { + _M_owner = -1; + _M_cs.unlock(); } + } - private: - pplx::details::critical_section_impl _M_cs; - long _M_recursionCount; - volatile long _M_owner; - }; +private: + pplx::details::critical_section_impl _M_cs; + long _M_recursionCount; + volatile long _M_owner; +}; - class windows_scheduler : public pplx::scheduler_interface - { - public: - _PPLXIMP virtual void schedule( TaskProc_t proc, _In_ void* param); - }; +class windows_scheduler : public pplx::scheduler_interface +{ +public: + _PPLXIMP virtual void schedule(TaskProc_t proc, _In_ void* param); +}; } // namespace details @@ -229,36 +214,32 @@ class scoped_lock _M_critical_section.lock(); } - ~scoped_lock() - { - _M_critical_section.unlock(); - } + ~scoped_lock() { _M_critical_section.unlock(); } private: _Lock& _M_critical_section; - scoped_lock(const scoped_lock&); // no copy constructor - scoped_lock const & operator=(const scoped_lock&); // no assignment operator + scoped_lock(const scoped_lock&); // no copy constructor + scoped_lock const& operator=(const scoped_lock&); // no assignment operator }; // The extensibility namespace contains the type definitions that are used internally namespace extensibility { - typedef ::pplx::details::event_impl event_t; - - typedef ::pplx::details::critical_section_impl critical_section_t; - typedef scoped_lock scoped_critical_section_t; +typedef ::pplx::details::event_impl event_t; -#if _WIN32_WINNT >= _WIN32_WINNT_VISTA - typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t; - typedef scoped_lock scoped_rw_lock_t; - typedef reader_writer_lock_t::scoped_lock_read scoped_read_lock_t; -#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA +typedef ::pplx::details::critical_section_impl critical_section_t; +typedef scoped_lock scoped_critical_section_t; +#if _WIN32_WINNT >= _WIN32_WINNT_VISTA +typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t; +typedef scoped_lock scoped_rw_lock_t; +typedef reader_writer_lock_t::scoped_lock_read scoped_read_lock_t; +#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA - typedef ::pplx::details::recursive_lock_impl recursive_lock_t; - typedef scoped_lock scoped_recursive_lock_t; -} +typedef ::pplx::details::recursive_lock_impl recursive_lock_t; +typedef scoped_lock scoped_recursive_lock_t; +} // namespace extensibility /// /// Default scheduler type @@ -267,19 +248,21 @@ typedef details::windows_scheduler default_scheduler_t; namespace details { - /// - /// Terminate the process due to unhandled exception - /// +/// +/// Terminate the process due to unhandled exception +/// - #ifndef _REPORT_PPLTASK_UNOBSERVED_EXCEPTION - #define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() do { \ - __debugbreak(); \ - std::terminate(); \ - } while(false) - #endif // _REPORT_PPLTASK_UNOBSERVED_EXCEPTION +#ifndef _REPORT_PPLTASK_UNOBSERVED_EXCEPTION +#define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() \ + do \ + { \ + __debugbreak(); \ + std::terminate(); \ + } while (false) +#endif // _REPORT_PPLTASK_UNOBSERVED_EXCEPTION } // namespace details } // namespace pplx -#endif \ No newline at end of file +#endif diff --git a/Release/include/pplx/threadpool.h b/Release/include/pplx/threadpool.h index dfa3344db8..b297ff6bc8 100644 --- a/Release/include/pplx/threadpool.h +++ b/Release/include/pplx/threadpool.h @@ -1,14 +1,14 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* -* Simple Linux implementation of a static thread pool. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -***/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * + * Simple Linux implementation of a static thread pool. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + ***/ #pragma once #if defined(__clang__) @@ -23,15 +23,15 @@ #endif #if defined(__ANDROID__) +#include "pplx/pplx.h" #include #include -#include "pplx/pplx.h" #endif #include "cpprest/details/cpprest_compat.h" -namespace crossplat { - +namespace crossplat +{ #if defined(__ANDROID__) // IDEA: Break this section into a separate android/jni header extern std::atomic JVM; @@ -39,10 +39,7 @@ JNIEnv* get_jvm_env(); struct java_local_ref_deleter { - void operator()(jobject lref) const - { - crossplat::get_jvm_env()->DeleteLocalRef(lref); - } + void operator()(jobject lref) const { crossplat::get_jvm_env()->DeleteLocalRef(lref); } }; template @@ -83,4 +80,4 @@ class threadpool boost::asio::io_service m_service; }; -} +} // namespace crossplat diff --git a/Release/samples/BingRequest/bingrequest.cpp b/Release/samples/BingRequest/bingrequest.cpp index 726d6d194a..22625d790d 100644 --- a/Release/samples/BingRequest/bingrequest.cpp +++ b/Release/samples/BingRequest/bingrequest.cpp @@ -1,17 +1,17 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* bingrequest.cpp - Simple cmd line application that makes an HTTP GET request to bing searching and outputting -* the resulting HTML response body into a file. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * bingrequest.cpp - Simple cmd line application that makes an HTTP GET request to bing searching and outputting + * the resulting HTML response body into a file. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ -#include #include +#include using namespace utility; using namespace web::http; @@ -27,15 +27,16 @@ web::http::client::http_client_config client_config_for_proxy() web::http::client::http_client_config client_config; #ifdef _WIN32 wchar_t* pValue = nullptr; - std::unique_ptr holder(nullptr, [](wchar_t* p) { free(p); }); + std::unique_ptr holder(nullptr, [](wchar_t* p) { free(p); }); size_t len = 0; auto err = _wdupenv_s(&pValue, &len, L"http_proxy"); - if (pValue) - holder.reset(pValue); - if (!err && pValue && len) { + if (pValue) holder.reset(pValue); + if (!err && pValue && len) + { std::wstring env_http_proxy_string(pValue, len - 1); #else - if(const char* env_http_proxy = std::getenv("http_proxy")) { + if (const char* env_http_proxy = std::getenv("http_proxy")) + { std::string env_http_proxy_string(env_http_proxy); #endif if (env_http_proxy_string == U("auto")) @@ -47,14 +48,13 @@ web::http::client::http_client_config client_config_for_proxy() return client_config; } - #ifdef _WIN32 -int wmain(int argc, wchar_t *args[]) +int wmain(int argc, wchar_t* args[]) #else -int main(int argc, char *args[]) +int main(int argc, char* args[]) #endif { - if(argc != 3) + if (argc != 3) { printf("Usage: BingRequest.exe search_term output_file\n"); return -1; @@ -64,32 +64,28 @@ int main(int argc, char *args[]) // Open a stream to the file to write the HTTP response body into. auto fileBuffer = std::make_shared>(); - file_buffer::open(outputFileName, std::ios::out).then([=](streambuf outFile) -> pplx::task - { - *fileBuffer = outFile; + file_buffer::open(outputFileName, std::ios::out) + .then([=](streambuf outFile) -> pplx::task { + *fileBuffer = outFile; - // Create an HTTP request. - // Encode the URI query since it could contain special characters like spaces. - http_client client(U("http://www.bing.com/"), client_config_for_proxy()); - return client.request(methods::GET, uri_builder(U("/search")).append_query(U("q"), searchTerm).to_string()); - }) + // Create an HTTP request. + // Encode the URI query since it could contain special characters like spaces. + http_client client(U("http://www.bing.com/"), client_config_for_proxy()); + return client.request(methods::GET, uri_builder(U("/search")).append_query(U("q"), searchTerm).to_string()); + }) - // Write the response body into the file buffer. - .then([=](http_response response) -> pplx::task - { - printf("Response status code %u returned.\n", response.status_code()); + // Write the response body into the file buffer. + .then([=](http_response response) -> pplx::task { + printf("Response status code %u returned.\n", response.status_code()); - return response.body().read_to_end(*fileBuffer); - }) + return response.body().read_to_end(*fileBuffer); + }) - // Close the file buffer. - .then([=](size_t) - { - return fileBuffer->close(); - }) + // Close the file buffer. + .then([=](size_t) { return fileBuffer->close(); }) - // Wait for the entire response body to be written into the file. - .wait(); + // Wait for the entire response body to be written into the file. + .wait(); return 0; } diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp b/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp index 9a17d8983d..5c9b1fc4b1 100644 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp +++ b/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp @@ -1,17 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* BlackJackClient.cpp : Defines the entry point for the console application -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * BlackJackClient.cpp : Defines the entry point for the console application + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #ifdef _WIN32 #include - #include #include @@ -19,10 +18,11 @@ #define WIN32_LEAN_AND_MEAN #endif #define NOMINMAX -#include #include #include +#include + // ws2tcpip.h - isn't warning clean. #pragma warning(push) #pragma warning(disable : 6386) @@ -32,19 +32,17 @@ #include #endif -#include -#include -#include -#include - +#include "../BlackJack_Server/messagetypes.h" #include "cpprest/http_client.h" - +#include +#include #include -#include -#include #include -#include -#include "../BlackJack_Server/messagetypes.h" +#include +#include +#include +#include +#include using namespace std; using namespace web; @@ -52,13 +50,13 @@ using namespace utility; using namespace http; using namespace http::client; -http_response CheckResponse(const std::string &url, const http_response &response) +http_response CheckResponse(const std::string& url, const http_response& response) { ucout << response.to_string() << endl; return response; } -http_response CheckResponse(const std::string &url, const http_response &response, bool &refresh) +http_response CheckResponse(const std::string& url, const http_response& response, bool& refresh) { ucout << response.to_string() << endl; BJPutResponse answer = BJPutResponse::FromJSON(response.extract_json().get()); @@ -70,57 +68,58 @@ void PrintResult(BJHandResult result) { switch (result) { - case HR_PlayerBlackJack: ucout << "Black Jack"; break; - case HR_PlayerWin: ucout << "Player wins"; break; - case HR_ComputerWin: ucout << "Computer Wins"; break; - case HR_Push:ucout << "Push"; break; + case HR_PlayerBlackJack: ucout << "Black Jack"; break; + case HR_PlayerWin: ucout << "Player wins"; break; + case HR_ComputerWin: ucout << "Computer Wins"; break; + case HR_Push: ucout << "Push"; break; } } -void PrintCard(const Card &card) +void PrintCard(const Card& card) { switch (card.value) { - case CV_King: ucout << "K"; break; - case CV_Queen: ucout << "Q"; break; - case CV_Jack: ucout << "J"; break; - case CV_Ace: ucout << "A"; break; - default: ucout << (int)card.value; break; + case CV_King: ucout << "K"; break; + case CV_Queen: ucout << "Q"; break; + case CV_Jack: ucout << "J"; break; + case CV_Ace: ucout << "A"; break; + default: ucout << (int)card.value; break; } switch (card.suit) { - case CS_Club: ucout << "C"; break; - case CS_Spade: ucout << "S"; break; - case CS_Heart: ucout << "H"; break; - case CS_Diamond: ucout << "D"; break; + case CS_Club: ucout << "C"; break; + case CS_Spade: ucout << "S"; break; + case CS_Heart: ucout << "H"; break; + case CS_Diamond: ucout << "D"; break; } } -void PrintHand(bool suppress_bet, const BJHand &hand) +void PrintHand(bool suppress_bet, const BJHand& hand) { if (!suppress_bet) { - if ( hand.insurance > 0 ) + if (hand.insurance > 0) ucout << "Bet: " << hand.bet << "Insurance: " << hand.insurance << " Hand: "; else ucout << "Bet: " << hand.bet << " Hand: "; } for (auto iter = hand.cards.begin(); iter != hand.cards.end(); iter++) { - PrintCard(*iter); ucout << " "; + PrintCard(*iter); + ucout << " "; } PrintResult(hand.result); } -void PrintTable(const http_response &response, bool &refresh) +void PrintTable(const http_response& response, bool& refresh) { BJHand hand; refresh = false; - if ( response.status_code() == status_codes::OK ) + if (response.status_code() == status_codes::OK) { - if ( response.headers().content_type() == U("application/json") ) + if (response.headers().content_type() == U("application/json")) { BJPutResponse answer = BJPutResponse::FromJSON(response.extract_json().get()); json::value players = answer.Data[PLAYERS]; @@ -132,12 +131,12 @@ void PrintTable(const http_response &response, bool &refresh) auto& player = *iter; json::value name = player[NAME]; - json::value bet = player[BALANCE]; + json::value bet = player[BALANCE]; bool suppressMoney = iter == players.as_array().begin(); - if ( suppressMoney ) - ucout << "'" << name.as_string() << "'" ; + if (suppressMoney) + ucout << "'" << name.as_string() << "'"; else ucout << "'" << name.as_string() << "' Balance = $" << bet.as_double() << " "; @@ -145,14 +144,10 @@ void PrintTable(const http_response &response, bool &refresh) ucout << std::endl; } - switch ( answer.Status ) + switch (answer.Status) { - case ST_PlaceBet: - ucout << "Place your bet!\n"; - break; - case ST_YourTurn: - ucout << "Your turn!\n"; - break; + case ST_PlaceBet: ucout << "Place your bet!\n"; break; + case ST_YourTurn: ucout << "Your turn!\n"; break; } } } @@ -164,13 +159,13 @@ void PrintTable(const http_response &response, bool &refresh) // If port is not specified, client will assume that the server is listening on port 34568 // #ifdef _WIN32 -int wmain(int argc, wchar_t *argv[]) +int wmain(int argc, wchar_t* argv[]) #else -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) #endif { utility::string_t port = U("34568"); - if(argc == 2) + if (argc == 2) { port = argv[1]; } @@ -191,7 +186,7 @@ int main(int argc, char *argv[]) while (true) { - while ( was_refresh ) + while (was_refresh) { was_refresh = false; utility::ostringstream_t buf; @@ -209,7 +204,7 @@ int main(int argc, char *argv[]) if (method == "quit") { - if ( !userName.empty() && !table.empty() ) + if (!userName.empty() && !table.empty()) { utility::ostringstream_t buf; buf << table << U("?name=") << userName; @@ -228,31 +223,37 @@ int main(int argc, char *argv[]) ucout << "Enter table name:"; ucin >> table; - if ( userName.empty() ) { ucout << "Must have a name first!\n"; continue; } + if (userName.empty()) + { + ucout << "Must have a name first!\n"; + continue; + } utility::ostringstream_t buf; buf << table << U("?name=") << userName; CheckResponse("blackjack/dealer", bjDealer.request(methods::POST, buf.str()).get(), was_refresh); } - else if (method == "hit" - || method == "stay" - || method == "double") + else if (method == "hit" || method == "stay" || method == "double") { utility::ostringstream_t buf; buf << table << U("?request=") << utility::conversions::to_string_t(method) << U("&name=") << userName; PrintTable(CheckResponse("blackjack/dealer", bjDealer.request(methods::PUT, buf.str()).get()), was_refresh); } - else if (method == "bet" - ||method == "insure") + else if (method == "bet" || method == "insure") { utility::string_t bet; ucout << "Enter bet:"; ucin >> bet; - if ( userName.empty() ) { ucout << "Must have a name first!\n"; continue; } + if (userName.empty()) + { + ucout << "Must have a name first!\n"; + continue; + } utility::ostringstream_t buf; - buf << table << U("?request=") << utility::conversions::to_string_t(method) << U("&name=") << userName << U("&amount=") << bet; + buf << table << U("?request=") << utility::conversions::to_string_t(method) << U("&name=") << userName + << U("&amount=") << bet; PrintTable(CheckResponse("blackjack/dealer", bjDealer.request(methods::PUT, buf.str()).get()), was_refresh); } else if (method == "newtbl") @@ -264,7 +265,11 @@ int main(int argc, char *argv[]) ucout << "Enter table:"; ucin >> table; - if ( userName.empty() ) { ucout << "Must have a name first!\n"; continue; } + if (userName.empty()) + { + ucout << "Must have a name first!\n"; + continue; + } utility::ostringstream_t buf; buf << table << U("?name=") << userName; @@ -275,7 +280,7 @@ int main(int argc, char *argv[]) was_refresh = false; http_response response = CheckResponse("blackjack/dealer", bjDealer.request(methods::GET).get()); - if ( response.status_code() == status_codes::OK ) + if (response.status_code() == status_codes::OK) { availableTables = response.extract_json().get(); for (auto iter = availableTables.as_array().begin(); iter != availableTables.as_array().end(); ++iter) @@ -283,7 +288,8 @@ int main(int argc, char *argv[]) BJTable bj_table = BJTable::FromJSON(iter->as_object()); json::value id = json::value::number(bj_table.Id); - ucout << "table " << bj_table.Id << ": {capacity: " << (long unsigned int)bj_table.Capacity << " no. players: " << (long unsigned int)bj_table.Players.size() << " }\n"; + ucout << "table " << bj_table.Id << ": {capacity: " << (long unsigned int)bj_table.Capacity + << " no. players: " << (long unsigned int)bj_table.Players.size() << " }\n"; } ucout << std::endl; } diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server.cpp b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server.cpp index 351d3dc65c..72918ead67 100644 --- a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server.cpp +++ b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* BlackJack_Servr.cpp - Simple server application for blackjack -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * BlackJack_Servr.cpp - Simple server application for blackjack + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -26,13 +26,12 @@ class BlackJackDealer pplx::task close() { return m_listener.close(); } private: - void handle_get(http_request message); void handle_put(http_request message); void handle_post(http_request message); void handle_delete(http_request message); - http_listener m_listener; + http_listener m_listener; }; std::unique_ptr g_httpDealer; @@ -47,7 +46,7 @@ void on_initialize(const string_t& address) auto addr = uri.to_uri().to_string(); g_httpDealer = std::unique_ptr(new BlackJackDealer(addr)); g_httpDealer->open().wait(); - + ucout << utility::string_t(U("Listening for requests at: ")) << addr << std::endl; return; @@ -65,13 +64,13 @@ void on_shutdown() // If port is not specified, will listen on 34568 // #ifdef _WIN32 -int wmain(int argc, wchar_t *argv[]) +int wmain(int argc, wchar_t* argv[]) #else -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) #endif { utility::string_t port = U("34568"); - if(argc == 2) + if (argc == 2) { port = argv[1]; } @@ -87,4 +86,4 @@ int main(int argc, char *argv[]) on_shutdown(); return 0; -} \ No newline at end of file +} diff --git a/Release/samples/BlackJack/BlackJack_Server/Dealer.cpp b/Release/samples/BlackJack/BlackJack_Server/Dealer.cpp index 7cb81d5bc2..2fce239fdc 100644 --- a/Release/samples/BlackJack/BlackJack_Server/Dealer.cpp +++ b/Release/samples/BlackJack/BlackJack_Server/Dealer.cpp @@ -1,20 +1,21 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Dealer.cpp : Contains the main logic of the black jack dealer -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Dealer.cpp : Contains the main logic of the black jack dealer + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include "messagetypes.h" + #include "Table.h" +#include "messagetypes.h" using namespace std; -using namespace web; +using namespace web; using namespace utility; using namespace http; using namespace web::http::experimental::listener; @@ -25,20 +26,19 @@ int nextId = 1; class BlackJackDealer { public: - BlackJackDealer() { } + BlackJackDealer() {} BlackJackDealer(utility::string_t url); pplx::task open() { return m_listener.open(); } pplx::task close() { return m_listener.close(); } private: - void handle_get(http_request message); void handle_put(http_request message); void handle_post(http_request message); void handle_delete(http_request message); - - http_listener m_listener; + + http_listener m_listener; }; BlackJackDealer::BlackJackDealer(utility::string_t url) : m_listener(url) @@ -55,10 +55,10 @@ BlackJackDealer::BlackJackDealer(utility::string_t url) : m_listener(url) // // A GET of the dealer resource produces a list of existing tables. -// +// void BlackJackDealer::handle_get(http_request message) { - ucout << message.to_string() << endl; + ucout << message.to_string() << endl; auto paths = http::uri::split_path(http::uri::decode(message.relative_uri().path())); if (paths.empty()) @@ -85,13 +85,13 @@ void BlackJackDealer::handle_get(http_request message) // // A POST of the dealer resource creates a new table and returns a resource for // that table. -// +// void BlackJackDealer::handle_post(http_request message) { - ucout << message.to_string() << endl; + ucout << message.to_string() << endl; auto paths = uri::split_path(uri::decode(message.relative_uri().path())); - + if (paths.empty()) { utility::ostringstream_t nextIdString; @@ -117,9 +117,10 @@ void BlackJackDealer::handle_post(http_request message) auto table = std::static_pointer_cast(found->second); - if ( table->Players.size() < table->Capacity ) + if (table->Players.size() < table->Capacity) { - std::map query = uri::split_query(uri::decode(message.request_uri().query())); + std::map query = + uri::split_query(uri::decode(message.request_uri().query())); auto cntEntry = query.find(QUERY_NAME); @@ -143,13 +144,13 @@ void BlackJackDealer::handle_post(http_request message) // // A DELETE of the player resource leaves the table. -// +// void BlackJackDealer::handle_delete(http_request message) { - ucout << message.to_string() << endl; + ucout << message.to_string() << endl; auto paths = uri::split_path(uri::decode(message.relative_uri().path())); - + if (paths.empty()) { message.reply(status_codes::Forbidden, U("TableId is required.")); @@ -173,9 +174,9 @@ void BlackJackDealer::handle_delete(http_request message) auto cntEntry = query.find(QUERY_NAME); - if ( cntEntry != query.end() ) + if (cntEntry != query.end()) { - if ( table->RemovePlayer(cntEntry->second) ) + if (table->RemovePlayer(cntEntry->second)) { message.reply(status_codes::OK); } @@ -190,13 +191,12 @@ void BlackJackDealer::handle_delete(http_request message) } }; - // // A PUT to a table resource makes a card request (hit / stay). -// +// void BlackJackDealer::handle_put(http_request message) { - ucout << message.to_string() << endl; + ucout << message.to_string() << endl; auto paths = uri::split_path(uri::decode(message.relative_uri().path())); auto query = uri::split_query(uri::decode(message.relative_uri().query())); @@ -211,38 +211,38 @@ void BlackJackDealer::handle_put(http_request message) // Get information on a specific table. auto found = s_tables.find(table_id); - if ( found == s_tables.end() ) + if (found == s_tables.end()) { message.reply(status_codes::NotFound); } auto table = std::static_pointer_cast(found->second); - if ( request == BET ) + if (request == BET) { table->Bet(message); } - else if ( request == DOUBLE ) + else if (request == DOUBLE) { table->DoubleDown(message); } - else if ( request == INSURE ) + else if (request == INSURE) { table->Insure(message); } - else if ( request == HIT ) + else if (request == HIT) { table->Hit(message); } - else if ( request == STAY ) + else if (request == STAY) { table->Stay(message); } - else if ( request == REFRESH ) + else if (request == REFRESH) { table->Wait(message); } - else + else { message.reply(status_codes::Forbidden, U("Unrecognized request")); } diff --git a/Release/samples/BlackJack/BlackJack_Server/Table.cpp b/Release/samples/BlackJack/BlackJack_Server/Table.cpp index af54397889..588f8e68ee 100644 --- a/Release/samples/BlackJack/BlackJack_Server/Table.cpp +++ b/Release/samples/BlackJack/BlackJack_Server/Table.cpp @@ -1,20 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Table.cpp : Contains the main logic of game -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Table.cpp : Contains the main logic of game + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include "messagetypes.h" + #include "Table.h" +#include "messagetypes.h" + using namespace std; -using namespace web; +using namespace web; using namespace utility; using namespace web::http; using namespace web::http::experimental::listener; @@ -31,31 +33,32 @@ void DealerTable::Deal() for (size_t i = 0; i < Players.size(); i++) { Players[i].Hand.Clear(); - if ( i == 0 || Players[i].Hand.bet > 0 ) + if (i == 0 || Players[i].Hand.bet > 0) { - Card card = m_shoe.front(); m_shoe.pop(); + Card card = m_shoe.front(); + m_shoe.pop(); Players[i].Hand.cards.push_back(card); } } for (size_t i = 0; i < Players.size(); i++) { - if ( i == 0 || Players[i].Hand.bet > 0 ) + if (i == 0 || Players[i].Hand.bet > 0) { - Card card = m_shoe.front(); m_shoe.pop(); + Card card = m_shoe.front(); + m_shoe.pop(); Players[i].Hand.AddCard(card); } } pplx::extensibility::scoped_critical_section_t lck(m_resplock); - for (size_t player = m_currentPlayer+1; player < Players.size(); player++) + for (size_t player = m_currentPlayer + 1; player < Players.size(); player++) { m_currentPlayer = (int)player; - if ( Players[player].Hand.bet == 0 ) - continue; + if (Players[player].Hand.bet == 0) continue; - if ( Players[player].Hand.state == HR_Active ) + if (Players[player].Hand.state == HR_Active) { m_responses[player]->reply(status_codes::OK, BJPutResponse(ST_YourTurn, this->AsJSON()).AsJSON()); m_responses[player].reset(); @@ -65,9 +68,9 @@ void DealerTable::Deal() for (size_t i = 1; i < Players.size(); i++) { - if ( i != m_currentPlayer ) + if (i != m_currentPlayer) { - if ( m_responses[i] ) + if (m_responses[i]) { m_responses[i]->reply(status_codes::OK, BJPutResponse(ST_Refresh, this->AsJSON()).AsJSON()); m_responses[i].reset(); @@ -82,10 +85,11 @@ void DealerTable::Deal() void DealerTable::Hit(http_request message) { - Card card = m_shoe.front(); m_shoe.pop(); + Card card = m_shoe.front(); + m_shoe.pop(); Players[m_currentPlayer].Hand.AddCard(card); - if ( Players[m_currentPlayer].Hand.state == HR_BlackJack || Players[m_currentPlayer].Hand.state == HR_Busted ) + if (Players[m_currentPlayer].Hand.state == HR_BlackJack || Players[m_currentPlayer].Hand.state == HR_Busted) { Stay(message); } @@ -97,9 +101,9 @@ void DealerTable::Hit(http_request message) for (size_t i = 1; i < Players.size(); i++) { - if ( i != m_currentPlayer ) + if (i != m_currentPlayer) { - if ( m_responses[i] ) + if (m_responses[i]) { m_responses[i]->reply(status_codes::OK, BJPutResponse(ST_Refresh, this->AsJSON()).AsJSON()); m_responses[i].reset(); @@ -115,16 +119,24 @@ void DealerTable::Hit(http_request message) void DealerTable::DoubleDown(http_request message) { - if ( m_currentPlayer == 0 || Players[m_currentPlayer].Hand.state != HR_Active ) + if (m_currentPlayer == 0 || Players[m_currentPlayer].Hand.state != HR_Active) { message.reply(status_codes::Forbidden, U("Not your turn")); - return; + return; } - Player ¤t = Players[m_currentPlayer]; + Player& current = Players[m_currentPlayer]; - if ( current.Balance < current.Hand.bet ) { message.reply(status_codes::Forbidden, U("Not enough money")); return; } - if ( current.Hand.cards.size() > 2 ) { message.reply(status_codes::Forbidden, U("Too many cards")); return; } + if (current.Balance < current.Hand.bet) + { + message.reply(status_codes::Forbidden, U("Not enough money")); + return; + } + if (current.Hand.cards.size() > 2) + { + message.reply(status_codes::Forbidden, U("Too many cards")); + return; + } // Double the bet @@ -133,7 +145,8 @@ void DealerTable::DoubleDown(http_request message) // Take one card and then stay - Card card = m_shoe.front(); m_shoe.pop(); + Card card = m_shoe.front(); + m_shoe.pop(); Players[m_currentPlayer].Hand.AddCard(card); Stay(message); @@ -145,7 +158,7 @@ void DealerTable::Wait(http_request message) auto query = http::uri::split_query(http::uri::decode(message.relative_uri().query())); auto itr = query.find(QUERY_NAME); - if ( itr == query.end() ) + if (itr == query.end()) { message.reply(status_codes::Forbidden, U("name and amount are required in query")); return; @@ -155,11 +168,11 @@ void DealerTable::Wait(http_request message) int playerIdx = FindPlayer(name); - if ( playerIdx > 0 ) + if (playerIdx > 0) { pplx::extensibility::scoped_critical_section_t lck(m_resplock); - if ( m_pendingrefresh[playerIdx] != ST_None ) + if (m_pendingrefresh[playerIdx] != ST_None) { message.reply(status_codes::OK, BJPutResponse(m_pendingrefresh[playerIdx], this->AsJSON()).AsJSON()); m_pendingrefresh[playerIdx] = ST_None; @@ -179,7 +192,7 @@ void DealerTable::Bet(http_request message) auto query = http::uri::split_query(http::uri::decode(message.relative_uri().query())); auto itrAmount = query.find(AMOUNT), itrName = query.find(QUERY_NAME); - if ( itrAmount == query.end() || itrName == query.end() ) + if (itrAmount == query.end() || itrName == query.end()) { message.reply(status_codes::Forbidden, U("name and amount are required in query")); return; @@ -190,7 +203,7 @@ void DealerTable::Bet(http_request message) int playerIdx = FindPlayer(name); - if ( playerIdx > 0 ) + if (playerIdx > 0) { Players[playerIdx].Balance -= amount; Players[playerIdx].Hand.bet += amount; @@ -200,7 +213,7 @@ void DealerTable::Bet(http_request message) m_responses[playerIdx] = message_wrapper(new http_request(message)); - if ( m_betsMade == Players.size() - 1 ) + if (m_betsMade == Players.size() - 1) { Deal(); } @@ -209,7 +222,7 @@ void DealerTable::Bet(http_request message) // the round is over. It's especially likely when there's only one // player at the table. - if ( m_currentPlayer == Players.size() ) + if (m_currentPlayer == Players.size()) { m_currentPlayer = 0; DealerDeal(); @@ -224,7 +237,7 @@ void DealerTable::Insure(http_request message) auto query = http::uri::split_query(http::uri::decode(message.relative_uri().query())); auto itrAmount = query.find(AMOUNT), itrName = query.find(QUERY_NAME); - if ( itrAmount == query.end() || itrName == query.end() ) + if (itrAmount == query.end() || itrName == query.end()) { message.reply(status_codes::Forbidden, U("name and amount are required in query")); return; @@ -234,19 +247,19 @@ void DealerTable::Insure(http_request message) name = itrName->second; int playerIdx = FindPlayer(name); - if ( playerIdx > 0 ) + if (playerIdx > 0) { - const BJHand &dealer = Players[0].Hand; - if ( Players[playerIdx].Hand.insurance > 0.0 ) + const BJHand& dealer = Players[0].Hand; + if (Players[playerIdx].Hand.insurance > 0.0) { - message.reply(status_codes::Forbidden, U("Already insured")); - return; + message.reply(status_codes::Forbidden, U("Already insured")); + return; } - if ( dealer.cards.size() < 1 || dealer.revealBoth || dealer.cards[0].value != CV_Ace ) + if (dealer.cards.size() < 1 || dealer.revealBoth || dealer.cards[0].value != CV_Ace) { - message.reply(status_codes::Forbidden, U("Dealer is not showing an Ace")); - return; + message.reply(status_codes::Forbidden, U("Dealer is not showing an Ace")); + return; } Players[playerIdx].Balance -= amount; @@ -258,12 +271,11 @@ void DealerTable::Insure(http_request message) void DealerTable::Stay(http_request message) { - if ( m_currentPlayer == 0 ) return; + if (m_currentPlayer == 0) return; - if ( Players[m_currentPlayer].Hand.state == HR_Active ) - Players[m_currentPlayer].Hand.state = HR_Held; + if (Players[m_currentPlayer].Hand.state == HR_Active) Players[m_currentPlayer].Hand.state = HR_Held; - //int idx = m_currentPlayer; + // int idx = m_currentPlayer; message.reply(status_codes::OK, BJPutResponse(ST_Refresh, this->AsJSON()).AsJSON()); @@ -272,16 +284,15 @@ void DealerTable::Stay(http_request message) void DealerTable::NextPlayer(http_request message) { - size_t player = m_currentPlayer+1; + size_t player = m_currentPlayer + 1; for (; player < Players.size(); player++) { pplx::extensibility::scoped_critical_section_t lck(m_resplock); - if ( Players[player].Hand.bet > 0 && - Players[player].Hand.state == HR_Active ) + if (Players[player].Hand.bet > 0 && Players[player].Hand.state == HR_Active) { - m_responses[player]->reply(status_codes::OK, BJPutResponse(ST_YourTurn, this->AsJSON()).AsJSON()); + m_responses[player]->reply(status_codes::OK, BJPutResponse(ST_YourTurn, this->AsJSON()).AsJSON()); m_responses[player].reset(); break; } @@ -289,31 +300,29 @@ void DealerTable::NextPlayer(http_request message) m_currentPlayer = (int)player; - if ( m_currentPlayer == Players.size() ) - m_currentPlayer = 0; + if (m_currentPlayer == Players.size()) m_currentPlayer = 0; - if ( m_currentPlayer == 0 ) - DealerDeal(); + if (m_currentPlayer == 0) DealerDeal(); } void DealerTable::PayUp(size_t idx) { - Player &player = Players[idx]; - if ( player.Hand.result == HR_PlayerWin ) + Player& player = Players[idx]; + if (player.Hand.result == HR_PlayerWin) { - player.Balance += player.Hand.bet*2; + player.Balance += player.Hand.bet * 2; player.Hand.bet = 0.0; } - else if ( player.Hand.result == HR_ComputerWin ) + else if (player.Hand.result == HR_ComputerWin) { player.Hand.bet = 0.0; } - else if ( player.Hand.result == HR_PlayerBlackJack ) + else if (player.Hand.result == HR_PlayerBlackJack) { - player.Balance += player.Hand.bet*2.5; + player.Balance += player.Hand.bet * 2.5; player.Hand.bet = 0.0; } - else if ( player.Hand.result == HR_Push ) + else if (player.Hand.result == HR_Push) { player.Balance += player.Hand.bet; player.Hand.bet = 0.0; @@ -321,15 +330,15 @@ void DealerTable::PayUp(size_t idx) // Handle insurance - if ( player.Hand.insurance > 0 && Players[0].Hand.state == HR_PlayerBlackJack ) + if (player.Hand.insurance > 0 && Players[0].Hand.state == HR_PlayerBlackJack) { - player.Balance += player.Hand.insurance*3; + player.Balance += player.Hand.insurance * 3; } player.Hand.insurance = 0; pplx::extensibility::scoped_critical_section_t lck(m_resplock); - if ( m_responses[idx] ) + if (m_responses[idx]) { m_responses[idx]->reply(status_codes::OK, BJPutResponse(ST_PlaceBet, this->AsJSON()).AsJSON()); m_responses[idx].reset(); @@ -342,59 +351,60 @@ void DealerTable::PayUp(size_t idx) void DealerTable::DealerDeal() { - BJHand &dealersHand = Players[0].Hand; + BJHand& dealersHand = Players[0].Hand; dealersHand.revealBoth = true; NumericHandValues handValue = dealersHand.GetNumericValues(); - while ( handValue.high < 17 || (handValue.high > 21 && handValue.low < 17) ) + while (handValue.high < 17 || (handValue.high > 21 && handValue.low < 17)) { - Card card = m_shoe.front(); m_shoe.pop(); + Card card = m_shoe.front(); + m_shoe.pop(); dealersHand.AddCard(card); - if ( dealersHand.state == HR_BlackJack || Players[m_currentPlayer].Hand.state == HR_Busted ) - break; + if (dealersHand.state == HR_BlackJack || Players[m_currentPlayer].Hand.state == HR_Busted) break; handValue = dealersHand.GetNumericValues(); } for (size_t i = 1; i < Players.size(); i++) { - Player &player = Players[i]; + Player& player = Players[i]; - if ( player.Hand.bet == 0.0 ) + if (player.Hand.bet == 0.0) { player.Hand.result = HR_None; continue; } - if ( player.Hand.state == HR_Busted ) + if (player.Hand.state == HR_Busted) { player.Hand.result = HR_ComputerWin; continue; } - if ( player.Hand.state == HR_BlackJack ) + if (player.Hand.state == HR_BlackJack) { player.Hand.result = (dealersHand.state == HR_BlackJack) ? HR_Push : HR_PlayerBlackJack; continue; } - if ( dealersHand.state == HR_Busted ) + if (dealersHand.state == HR_Busted) { player.Hand.result = HR_PlayerWin; continue; } - if ( dealersHand.state == HR_BlackJack ) + if (dealersHand.state == HR_BlackJack) { player.Hand.result = HR_ComputerWin; continue; } NumericHandValues value = player.Hand.GetNumericValues(); - player.Hand.result = - (value.Best() < handValue.Best()) ? HR_ComputerWin : ((value.Best() == handValue.Best()) ? HR_Push : HR_PlayerWin); + player.Hand.result = (value.Best() < handValue.Best()) + ? HR_ComputerWin + : ((value.Best() == handValue.Best()) ? HR_Push : HR_PlayerWin); } m_betting = true; @@ -410,14 +420,13 @@ void DealerTable::DealerDeal() // TODO: Right now, players must make sure to get in when the dealer is taking bets. // Change the logic to anticipate that a new player may come to the table at // any point, and wait until the next round. -bool DealerTable::AddPlayer(const Player &player) +bool DealerTable::AddPlayer(const Player& player) { pplx::extensibility::scoped_critical_section_t lck(m_resplock); int idx = FindPlayer(player.Name); - if ( idx > 0 ) - return false; + if (idx > 0) return false; Players.push_back(player); m_responses.push_back(message_wrapper()); @@ -426,7 +435,7 @@ bool DealerTable::AddPlayer(const Player &player) return true; } -bool DealerTable::RemovePlayer(const utility::string_t &name) +bool DealerTable::RemovePlayer(const utility::string_t& name) { pplx::extensibility::scoped_critical_section_t lck(m_resplock); @@ -435,7 +444,7 @@ bool DealerTable::RemovePlayer(const utility::string_t &name) for (auto iter = Players.begin(); iter != Players.end(); iter++, evnts++, pends++) { - if ( iter->Name == name ) + if (iter->Name == name) { Players.erase(iter); m_responses.erase(evnts); @@ -446,7 +455,6 @@ bool DealerTable::RemovePlayer(const utility::string_t &name) return false; } - void DealerTable::FillShoe(size_t decks) { // @@ -458,13 +466,13 @@ void DealerTable::FillShoe(size_t decks) // std::vector shoe(decks * 52); - for (size_t d = 0; d < decks ; d++) + for (size_t d = 0; d < decks; d++) { for (int suit = 0; suit < 4; suit++) { for (int fv = 0; fv < 13; fv++) { - shoe[d*52+suit*13+fv] = suit*16+(fv+1); + shoe[d * 52 + suit * 13 + fv] = suit * 16 + (fv + 1); } } } @@ -480,23 +488,23 @@ void DealerTable::FillShoe(size_t decks) gettimeofday(&val, nullptr); mt19937 eng(val.tv_usec); #endif - uniform_int_distribution dist(0,(int)(decks*52-1)); + uniform_int_distribution dist(0, (int)(decks * 52 - 1)); #define ITER 4 for (size_t r = 0; r < ITER; r++) { - for (size_t i = 0; i < decks*52; i++) + for (size_t i = 0; i < decks * 52; i++) { int other = dist(eng); - swap(shoe[i],shoe[other]); + swap(shoe[i], shoe[other]); } } // // Convert to the other format // - for (size_t i = 0; i < decks*52; i++) + for (size_t i = 0; i < decks * 52; i++) { Card card; card.suit = (CardSuit)(shoe[i] / 16); @@ -504,15 +512,15 @@ void DealerTable::FillShoe(size_t decks) m_shoe.push(card); } - m_stopAt = uniform_int_distribution(26,52)(eng); + m_stopAt = uniform_int_distribution(26, 52)(eng); } -int DealerTable::FindPlayer(const utility::string_t &name) +int DealerTable::FindPlayer(const utility::string_t& name) { int idx = 0; for (auto iter = Players.begin(); iter != Players.end(); iter++, idx++) { - if ( iter->Name == name ) + if (iter->Name == name) { return idx; } diff --git a/Release/samples/BlackJack/BlackJack_Server/Table.h b/Release/samples/BlackJack/BlackJack_Server/Table.h index 856a27c5f0..69f1d11cfa 100644 --- a/Release/samples/BlackJack/BlackJack_Server/Table.h +++ b/Release/samples/BlackJack/BlackJack_Server/Table.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Table.h -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Table.h + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "stdafx.h" @@ -15,22 +15,24 @@ #ifdef _WIN32 #include #endif +#include "messagetypes.h" +#include #include #include -#include class DealerTable : public BJTable { public: - DealerTable() : m_currentPlayer(0),m_betsMade(0),m_betting(true) - { + DealerTable() : m_currentPlayer(0), m_betsMade(0), m_betting(true) + { _init(); - FillShoe(6); + FillShoe(6); } - DealerTable(int id, size_t capacity, int decks) : BJTable(id, capacity), m_currentPlayer(0), m_betsMade(0),m_betting(true) - { - _init(); - FillShoe(decks); + DealerTable(int id, size_t capacity, int decks) + : BJTable(id, capacity), m_currentPlayer(0), m_betsMade(0), m_betting(true) + { + _init(); + FillShoe(decks); } void Deal(); @@ -43,8 +45,8 @@ class DealerTable : public BJTable void Wait(web::http::http_request); - bool AddPlayer(const Player &player); - bool RemovePlayer(const utility::string_t &name); + bool AddPlayer(const Player& player); + bool RemovePlayer(const utility::string_t& name); private: void FillShoe(size_t decks); @@ -52,7 +54,7 @@ class DealerTable : public BJTable void PayUp(size_t playerId); void NextPlayer(web::http::http_request); - int FindPlayer(const utility::string_t &name); + int FindPlayer(const utility::string_t& name); void _init() { @@ -69,7 +71,7 @@ class DealerTable : public BJTable typedef std::shared_ptr message_wrapper; - std::vector m_pendingrefresh; + std::vector m_pendingrefresh; std::vector m_responses; int m_currentPlayer; diff --git a/Release/samples/BlackJack/BlackJack_Server/messagetypes.h b/Release/samples/BlackJack/BlackJack_Server/messagetypes.h index b48fcfde0d..91c633984e 100644 --- a/Release/samples/BlackJack/BlackJack_Server/messagetypes.h +++ b/Release/samples/BlackJack/BlackJack_Server/messagetypes.h @@ -1,28 +1,77 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* messagetypes.h -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * messagetypes.h + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "stdafx.h" -enum BJHandResult { HR_None, HR_PlayerBlackJack, HR_PlayerWin, HR_ComputerWin, HR_Push }; +enum BJHandResult +{ + HR_None, + HR_PlayerBlackJack, + HR_PlayerWin, + HR_ComputerWin, + HR_Push +}; -enum BJHandState { HR_Empty, HR_BlackJack, HR_Active, HR_Held, HR_Busted }; +enum BJHandState +{ + HR_Empty, + HR_BlackJack, + HR_Active, + HR_Held, + HR_Busted +}; -enum BJPossibleMoves { PM_None = 0x0, PM_Hit = 0x1, PM_DoubleDown = 0x2, PM_Split = 0x4, PM_All = 0x7 }; +enum BJPossibleMoves +{ + PM_None = 0x0, + PM_Hit = 0x1, + PM_DoubleDown = 0x2, + PM_Split = 0x4, + PM_All = 0x7 +}; -enum CardSuit { CS_Heart, CS_Diamond, CS_Club, CS_Spade }; +enum CardSuit +{ + CS_Heart, + CS_Diamond, + CS_Club, + CS_Spade +}; -enum CardValue { CV_None, CV_Ace, CV_Two, CV_Three, CV_Four, CV_Five, CV_Six, CV_Seven, CV_Eight, CV_Nine, CV_Ten, CV_Jack, CV_Queen, CV_King }; +enum CardValue +{ + CV_None, + CV_Ace, + CV_Two, + CV_Three, + CV_Four, + CV_Five, + CV_Six, + CV_Seven, + CV_Eight, + CV_Nine, + CV_Ten, + CV_Jack, + CV_Queen, + CV_King +}; -enum BJStatus { ST_PlaceBet, ST_Refresh, ST_YourTurn, ST_None }; +enum BJStatus +{ + ST_PlaceBet, + ST_Refresh, + ST_YourTurn, + ST_None +}; #define STATE U("state") #define BET U("bet") @@ -54,7 +103,7 @@ struct Card CardSuit suit; CardValue value; - static Card FromJSON(const web::json::object & object) + static Card FromJSON(const web::json::object& object) { Card result; result.suit = (CardSuit)object.at(SUIT).as_integer(); @@ -62,7 +111,7 @@ struct Card return result; } - web::json::value AsJSON() const + web::json::value AsJSON() const { web::json::value result = web::json::value::object(); result[SUIT] = web::json::value::number(suit); @@ -91,18 +140,24 @@ struct BJHand BJHand() : state(HR_Empty), result(HR_None), bet(0.0), insurance(0), revealBoth(true) {} - void Clear() { cards.clear(); state = HR_Empty; result = HR_None; insurance = 0.0; } + void Clear() + { + cards.clear(); + state = HR_Empty; + result = HR_None; + insurance = 0.0; + } void AddCard(Card card) - { - cards.push_back(card); + { + cards.push_back(card); NumericHandValues value = GetNumericValues(); - if ( cards.size() == 2 && value.high == 21 ) + if (cards.size() == 2 && value.high == 21) { state = HR_BlackJack; } - else if ( value.low > 21 ) + else if (value.low > 21) { state = HR_Busted; } @@ -122,7 +177,7 @@ struct BJHand for (auto iter = cards.begin(); iter != cards.end(); ++iter) { - if ( iter->value == CV_Ace ) hasAces = true; + if (iter->value == CV_Ace) hasAces = true; res.low += std::min((int)iter->value, 10); } @@ -130,7 +185,7 @@ struct BJHand return res; } - static BJHand FromJSON(const web::json::object &object) + static BJHand FromJSON(const web::json::object& object) { BJHand res; @@ -138,7 +193,7 @@ struct BJHand for (auto iter = cs.as_array().begin(); iter != cs.as_array().end(); ++iter) { - if ( !iter->is_null() ) + if (!iter->is_null()) { Card card; card = Card::FromJSON(iter->as_object()); @@ -146,13 +201,12 @@ struct BJHand } } - auto iState = object.find(STATE); if (iState == object.end()) { throw web::json::json_exception(U("STATE key not found")); } - res.state = (BJHandState)iState->second.as_integer(); + res.state = (BJHandState)iState->second.as_integer(); auto iBet = object.find(BET); if (iBet == object.end()) { @@ -174,7 +228,7 @@ struct BJHand return res; } - web::json::value AsJSON() const + web::json::value AsJSON() const { web::json::value res = web::json::value::object(); res[STATE] = web::json::value::number(state); @@ -184,7 +238,7 @@ struct BJHand web::json::value jCards = web::json::value::array(cards.size()); - if ( revealBoth ) + if (revealBoth) { int idx = 0; for (auto iter = cards.begin(); iter != cards.end(); ++iter) @@ -213,9 +267,9 @@ struct Player double Balance; Player() {} - Player(const utility::string_t &name) : Name(name), Balance(1000.0) {} + Player(const utility::string_t& name) : Name(name), Balance(1000.0) {} - static Player FromJSON(const web::json::object &object) + static Player FromJSON(const web::json::object& object) { Player result(U("")); @@ -224,19 +278,19 @@ struct Player { throw web::json::json_exception(U("NAME key not found")); } - const web::json::value &name = iName->second; + const web::json::value& name = iName->second; auto iBalance = object.find(BALANCE); if (iBalance == object.end()) { throw web::json::json_exception(U("BALANCE key not found")); } - const web::json::value &balance = iBalance->second; + const web::json::value& balance = iBalance->second; auto iHand = object.find(HAND); if (iHand == object.end()) { throw web::json::json_exception(U("HAND key not found")); } - const web::json::value &hand = iHand->second; + const web::json::value& hand = iHand->second; result.Name = name.as_string(); result.Balance = balance.as_double(); @@ -244,7 +298,7 @@ struct Player return result; } - web::json::value AsJSON() const + web::json::value AsJSON() const { web::json::value result = web::json::value::object(); result[NAME] = web::json::value::string(Name); @@ -263,7 +317,7 @@ struct BJTable BJTable() : Capacity(0) {} BJTable(int id, size_t capacity) : Id(id), Capacity(capacity) { Players.push_back(Player(DEALER)); } - static BJTable FromJSON(const web::json::object &object) + static BJTable FromJSON(const web::json::object& object) { BJTable result; auto iID = object.find(ID); @@ -279,7 +333,6 @@ struct BJTable } result.Capacity = (size_t)iCapacity->second.as_double(); - auto iPlayers = object.find(PLAYERS); if (iPlayers == object.end()) { @@ -296,7 +349,7 @@ struct BJTable return result; } - web::json::value AsJSON() const + web::json::value AsJSON() const { web::json::value result = web::json::value::object(); result[ID] = web::json::value::number((double)Id); @@ -316,18 +369,18 @@ struct BJTable struct BJPutResponse { - BJStatus Status; + BJStatus Status; web::json::value Data; BJPutResponse() {} - BJPutResponse(BJStatus status, web::json::value data) : Status(status), Data(data) { } + BJPutResponse(BJStatus status, web::json::value data) : Status(status), Data(data) {} static BJPutResponse FromJSON(web::json::value object) { return BJPutResponse((BJStatus)(int)object[STATUS].as_double(), object[DATA]); } - web::json::value AsJSON() const + web::json::value AsJSON() const { web::json::value result = web::json::value::object(); result[STATUS] = web::json::value::number((double)Status); @@ -336,7 +389,8 @@ struct BJPutResponse } }; -inline web::json::value TablesAsJSON(const utility::string_t &name, const std::map> &tables) +inline web::json::value TablesAsJSON(const utility::string_t& name, + const std::map>& tables) { web::json::value result = web::json::value::array(); @@ -347,4 +401,3 @@ inline web::json::value TablesAsJSON(const utility::string_t &name, const std::m } return result; } - diff --git a/Release/samples/BlackJack/BlackJack_Server/stdafx.cpp b/Release/samples/BlackJack/BlackJack_Server/stdafx.cpp index 283f636882..516f368ef0 100644 --- a/Release/samples/BlackJack/BlackJack_Server/stdafx.cpp +++ b/Release/samples/BlackJack/BlackJack_Server/stdafx.cpp @@ -1,12 +1,12 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.cpp : source file that includes just the standard includes -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.cpp : source file that includes just the standard includes + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" diff --git a/Release/samples/BlackJack/BlackJack_Server/stdafx.h b/Release/samples/BlackJack/BlackJack_Server/stdafx.h index c91d64d219..ae59ac7dbd 100644 --- a/Release/samples/BlackJack/BlackJack_Server/stdafx.h +++ b/Release/samples/BlackJack/BlackJack_Server/stdafx.h @@ -1,31 +1,29 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h : include file for standard system include files, -* or project specific include files that are used frequently, -* but are changed infrequently -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.h : include file for standard system include files, + * or project specific include files that are used frequently, + * but are changed infrequently + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include -#include +#include "cpprest/asyncrt_utils.h" +#include "cpprest/http_listener.h" +#include "cpprest/json.h" +#include "cpprest/uri.h" #include -#include -#include #include +#include #include - -#include "cpprest/json.h" -#include "cpprest/http_listener.h" -#include "cpprest/uri.h" -#include "cpprest/asyncrt_utils.h" +#include +#include +#include #ifdef _WIN32 #ifndef NOMINMAX @@ -33,5 +31,5 @@ #endif #include #else -# include +#include #endif diff --git a/Release/samples/BlackJack/BlackJack_UIClient/App.xaml.cpp b/Release/samples/BlackJack/BlackJack_UIClient/App.xaml.cpp index 7ec9f8da64..648d7789f5 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/App.xaml.cpp +++ b/Release/samples/BlackJack/BlackJack_UIClient/App.xaml.cpp @@ -1,15 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* App.xaml.cpp - Implementation of the App class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * App.xaml.cpp - Implementation of the App class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "pch.h" + #include "PlayingTable.xaml.h" using namespace BlackjackClient; @@ -36,8 +37,8 @@ using namespace Windows::UI::Xaml::Navigation; /// App::App() { - InitializeComponent(); - Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); + InitializeComponent(); + Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); } /// @@ -46,55 +47,54 @@ App::App() /// search results, and so forth. /// /// Details about the launch request and process. -void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args) +void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ args) { - auto rootFrame = dynamic_cast(Window::Current->Content); - - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (rootFrame == nullptr) - { - // Create a Frame to act as the navigation context and associate it with - // a SuspensionManager key - rootFrame = ref new Frame(); + auto rootFrame = dynamic_cast(Window::Current->Content); - if (args->PreviousExecutionState == ApplicationExecutionState::Terminated) - { - // TODO: Restore the saved session state only when appropriate, scheduling the - // final launch steps after the restore is complete + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == nullptr) + { + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + rootFrame = ref new Frame(); - } + if (args->PreviousExecutionState == ApplicationExecutionState::Terminated) + { + // TODO: Restore the saved session state only when appropriate, scheduling the + // final launch steps after the restore is complete + } - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - if (!rootFrame->Navigate(TypeName(PlayingTable::typeid), args->Arguments)) - { - throw ref new FailureException("Failed to create initial page"); - } - } - // Place the frame in the current Window - Window::Current->Content = rootFrame; - // Ensure the current window is active - Window::Current->Activate(); - } - else - { - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - if (!rootFrame->Navigate(TypeName(PlayingTable::typeid), args->Arguments)) - { - throw ref new FailureException("Failed to create initial page"); - } - } - // Ensure the current window is active - Window::Current->Activate(); - } + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (!rootFrame->Navigate(TypeName(PlayingTable::typeid), args->Arguments)) + { + throw ref new FailureException("Failed to create initial page"); + } + } + // Place the frame in the current Window + Window::Current->Content = rootFrame; + // Ensure the current window is active + Window::Current->Activate(); + } + else + { + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (!rootFrame->Navigate(TypeName(PlayingTable::typeid), args->Arguments)) + { + throw ref new FailureException("Failed to create initial page"); + } + } + // Ensure the current window is active + Window::Current->Activate(); + } } /// @@ -104,10 +104,10 @@ void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEvent /// /// The source of the suspend request. /// Details about the suspend request. -void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) +void App::OnSuspending(Object ^ sender, SuspendingEventArgs ^ e) { - (void) sender; // Unused parameter - (void) e; // Unused parameter + (void)sender; // Unused parameter + (void)e; // Unused parameter - //TODO: Save application state and stop any background activity + // TODO: Save application state and stop any background activity } diff --git a/Release/samples/BlackJack/BlackJack_UIClient/App.xaml.h b/Release/samples/BlackJack/BlackJack_UIClient/App.xaml.h index f5492ebfcb..df0bbb416b 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/App.xaml.h +++ b/Release/samples/BlackJack/BlackJack_UIClient/App.xaml.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* App.xaml.h - Declaration of the App class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * App.xaml.h - Declaration of the App class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -15,16 +15,16 @@ namespace BlackjackClient { - /// - /// Provides application-specific behavior to supplement the default Application class. - /// - ref class App sealed - { - public: - App(); - virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args) override; +/// +/// Provides application-specific behavior to supplement the default Application class. +/// +ref class App sealed +{ +public: + App(); + virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ args) override; - private: - void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); - }; -} +private: + void OnSuspending(Platform::Object ^ sender, Windows::ApplicationModel::SuspendingEventArgs ^ e); +}; +} // namespace BlackjackClient diff --git a/Release/samples/BlackJack/BlackJack_UIClient/CardShape.xaml.cpp b/Release/samples/BlackJack/BlackJack_UIClient/CardShape.xaml.cpp index 3e20598bb7..188583dbfb 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/CardShape.xaml.cpp +++ b/Release/samples/BlackJack/BlackJack_UIClient/CardShape.xaml.cpp @@ -1,15 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* CardShape.xaml.cpp - Implementation of the CardShape class -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * CardShape.xaml.cpp - Implementation of the CardShape class + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "pch.h" + #include "CardShape.xaml.h" using namespace Windows::UI::Xaml; @@ -18,61 +19,56 @@ using namespace Windows::UI::Xaml::Data; using namespace Windows::UI::Xaml::Media; using namespace BlackjackClient; -CardShape::CardShape() : _suit(CS_Heart), _value(CV_Ace), _visible(true) -{ - InitializeComponent(); -} +CardShape::CardShape() : _suit(CS_Heart), _value(CV_Ace), _visible(true) { InitializeComponent(); } void CardShape::adjust() { - //Adjust the clipping of the cards image to reflect the current card + // Adjust the clipping of the cards image to reflect the current card double x = 0; double y = 0; if (_visible) { - x = (double)(int)(_value-1); + x = (double)(int)(_value - 1); y = (double)(int)_suit; } else { - //Show back of the card + // Show back of the card x = 0; y = 4; } - RectangleGeometry^ clip = imgCard->Clip; + RectangleGeometry ^ clip = imgCard->Clip; Windows::Foundation::Rect rect = clip->Rect; rect.X = float(x * CardWidthRect); rect.Y = float(y * CardHeightRect); clip->Rect = rect; - TransformGroup ^ group = dynamic_cast(imgCard->RenderTransform); + TransformGroup ^ group = dynamic_cast(imgCard->RenderTransform); - if ( group != nullptr ) + if (group != nullptr) { for (unsigned int idx = 0; idx < group->Children->Size; idx++) - { - TranslateTransform^ tfrm = dynamic_cast(group->Children->GetAt(idx)); - if ( tfrm != nullptr ) + { + TranslateTransform ^ tfrm = dynamic_cast(group->Children->GetAt(idx)); + if (tfrm != nullptr) { tfrm->X = -x * CardWidthRect * SCALE_FACTOR; tfrm->Y = -y * CardHeightRect * SCALE_FACTOR; } - ScaleTransform ^scale = dynamic_cast(group->Children->GetAt(idx)); - if ( scale != nullptr ) + ScaleTransform ^ scale = dynamic_cast(group->Children->GetAt(idx)); + if (scale != nullptr) { scale->ScaleX = SCALE_FACTOR; scale->ScaleY = SCALE_FACTOR; - scale->CenterX = - CardWidthRect / SCALE_FACTOR; - scale->CenterY = - CardHeightRect / SCALE_FACTOR; + scale->CenterX = -CardWidthRect / SCALE_FACTOR; + scale->CenterY = -CardHeightRect / SCALE_FACTOR; } } } } -CardShape::~CardShape() -{ -} +CardShape::~CardShape() {} diff --git a/Release/samples/BlackJack/BlackJack_UIClient/CardShape.xaml.h b/Release/samples/BlackJack/BlackJack_UIClient/CardShape.xaml.h index 8a54c43d33..db77540291 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/CardShape.xaml.h +++ b/Release/samples/BlackJack/BlackJack_UIClient/CardShape.xaml.h @@ -1,17 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* CardShape.xaml.h - Declaration of the CardShape class -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * CardShape.xaml.h - Declaration of the CardShape class + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "pch.h" + #include "CardShape.g.h" #define CardWidth 71 @@ -23,20 +24,21 @@ namespace BlackjackClient { - public ref class CardShape sealed - { - public: - CardShape(); - virtual ~CardShape(); - - private: - friend ref class PlayingTable; - friend ref class PlayerSpace; - - void adjust(); - - int _suit; - int _value; - Platform::Boolean _visible; - }; -} +public +ref class CardShape sealed +{ +public: + CardShape(); + virtual ~CardShape(); + +private: + friend ref class PlayingTable; + friend ref class PlayerSpace; + + void adjust(); + + int _suit; + int _value; + Platform::Boolean _visible; +}; +} // namespace BlackjackClient diff --git a/Release/samples/BlackJack/BlackJack_UIClient/Player.xaml.cpp b/Release/samples/BlackJack/BlackJack_UIClient/Player.xaml.cpp index 5245c22749..e32a766883 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/Player.xaml.cpp +++ b/Release/samples/BlackJack/BlackJack_UIClient/Player.xaml.cpp @@ -1,16 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Player.xaml.cpp: Implementation of the Player class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Player.xaml.cpp: Implementation of the Player class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "pch.h" + #include "Player.xaml.h" + #include "CardShape.xaml.h" #include "cpprest/uri.h" @@ -83,11 +85,23 @@ void PlayerSpace::ShowResult(BJHandResult result) { switch (result) { - case BJHandResult::HR_ComputerWin: playerInsurance->Text = L"Dealer Wins"; playerBet->Text = L""; break; - case BJHandResult::HR_PlayerWin: playerInsurance->Text = L"Player Wins"; playerBet->Text = L""; break; - case BJHandResult::HR_Push: playerInsurance->Text = L"Push"; playerBet->Text = L""; break; - case BJHandResult::HR_PlayerBlackJack: playerInsurance->Text = L"Blackjack!"; playerBet->Text = L""; break; - default: break; + case BJHandResult::HR_ComputerWin: + playerInsurance->Text = L"Dealer Wins"; + playerBet->Text = L""; + break; + case BJHandResult::HR_PlayerWin: + playerInsurance->Text = L"Player Wins"; + playerBet->Text = L""; + break; + case BJHandResult::HR_Push: + playerInsurance->Text = L"Push"; + playerBet->Text = L""; + break; + case BJHandResult::HR_PlayerBlackJack: + playerInsurance->Text = L"Blackjack!"; + playerBet->Text = L""; + break; + default: break; } UpdateLayout(); } diff --git a/Release/samples/BlackJack/BlackJack_UIClient/Player.xaml.h b/Release/samples/BlackJack/BlackJack_UIClient/Player.xaml.h index a8d4fdb3fc..429d5e38c3 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/Player.xaml.h +++ b/Release/samples/BlackJack/BlackJack_UIClient/Player.xaml.h @@ -1,48 +1,50 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Player.xaml.h: Declaration of the Player class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Player.xaml.h: Declaration of the Player class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "pch.h" + #include "Player.g.h" namespace BlackjackClient { - public ref class PlayerSpace sealed - { - public: - PlayerSpace() { _init(); } +public +ref class PlayerSpace sealed +{ +public: + PlayerSpace() { _init(); } - void Clear() - { - playerBalance->Text = L""; - playerBet->Text = L""; - playerName->Text = L""; - playerInsurance->Text = L""; - m_cards.clear(); - playerCardGrid->Children->Clear(); - } + void Clear() + { + playerBalance->Text = L""; + playerBet->Text = L""; + playerName->Text = L""; + playerInsurance->Text = L""; + m_cards.clear(); + playerCardGrid->Children->Clear(); + } - int CardsHeld() { return int(m_cards.size()); } + int CardsHeld() { return int(m_cards.size()); } - private: - friend ref class PlayingTable; +private: + friend ref class PlayingTable; - void AddCard(Card card); - void Update(Player player); + void AddCard(Card card); + void Update(Player player); - void ShowResult(BJHandResult result); + void ShowResult(BJHandResult result); - void _init(); + void _init(); - std::vector m_cards; - }; -} + std::vector m_cards; +}; +} // namespace BlackjackClient diff --git a/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.cpp b/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.cpp index a6bd90995e..64fd0adae6 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.cpp +++ b/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.cpp @@ -1,16 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Table.xaml.cpp: Implementation of the Table.xaml class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Table.xaml.cpp: Implementation of the Table.xaml class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "pch.h" + #include "PlayingTable.xaml.h" + #include "cpprest/asyncrt_utils.h" using namespace BlackjackClient; @@ -29,15 +31,16 @@ using namespace Windows::UI::Xaml::Navigation; using namespace Windows::Networking; #include "CardShape.xaml.h" -#include #include "cpprest/json.h" +#include using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Data; using namespace BlackjackClient; -PlayingTable::PlayingTable() : m_dealerResource(L"dealer"), m_alreadyInsured(false), m_client(L"http://localhost:34568/blackjack/") +PlayingTable::PlayingTable() + : m_dealerResource(L"dealer"), m_alreadyInsured(false), m_client(L"http://localhost:34568/blackjack/") { InitializeComponent(); @@ -63,9 +66,7 @@ PlayingTable::PlayingTable() : m_dealerResource(L"dealer"), m_alreadyInsured(fal DisableInsurance(); } -PlayingTable::~PlayingTable() -{ -} +PlayingTable::~PlayingTable() {} void BlackjackClient::PlayingTable::AddDealerCard(Card card) { @@ -91,16 +92,12 @@ void BlackjackClient::PlayingTable::AddDealerCard(Card card) bool BlackjackClient::PlayingTable::InterpretError(HRESULT hr) { - if ( hr == S_OK ) return false; + if (hr == S_OK) return false; - switch(hr) + switch (hr) { - case 0x800C0005: - this->resultLabel->Text = L"Error communicating with server"; - break; - default: - this->resultLabel->Text = L"Internal error"; - break; + case 0x800C0005: this->resultLabel->Text = L"Error communicating with server"; break; + default: this->resultLabel->Text = L"Internal error"; break; } return true; @@ -111,43 +108,44 @@ void BlackjackClient::PlayingTable::Refresh() this->resultLabel->Text = L"Waiting for other players"; std::wostringstream buf; - buf << _tableId << L"?request=refresh&name=" << uri::encode_uri(m_name,uri::components::path); - + buf << _tableId << L"?request=refresh&name=" << uri::encode_uri(m_name, uri::components::path); + auto request = m_client.request(methods::PUT, buf.str()); auto ctx = pplx::task_continuation_context::use_current(); - request.then([this](pplx::task tsk) { - - this->resultLabel->Text = L""; + request.then( + [this](pplx::task tsk) { + this->resultLabel->Text = L""; - try - { - auto response = tsk.get(); - InterpretResponse(response); - } - catch (const http_exception &exc) - { - InterpretError(exc.error_code().value()); - this->resultLabel->Text = L"Waiting for other players"; - Refresh(); - } - }, ctx); + try + { + auto response = tsk.get(); + InterpretResponse(response); + } + catch (const http_exception& exc) + { + InterpretError(exc.error_code().value()); + this->resultLabel->Text = L"Waiting for other players"; + Refresh(); + } + }, + ctx); } -void BlackjackClient::PlayingTable::InterpretResponse(http_response &response) +void BlackjackClient::PlayingTable::InterpretResponse(http_response& response) { - if ( response.headers().content_type() != L"application/json" ) return; + if (response.headers().content_type() != L"application/json") return; this->resultLabel->Text = L""; response.extract_json().then( - [this,response](json::value jsonResponse) - { - BlackjackClient::PlayingTable ^_this = this; + [this, response](json::value jsonResponse) { + BlackjackClient::PlayingTable ^ _this = this; http_response r = response; _this->InterpretResponse(jsonResponse); - }, pplx::task_continuation_context::use_current()); + }, + pplx::task_continuation_context::use_current()); } void BlackjackClient::PlayingTable::InterpretResponse(json::value jsonResponse) @@ -160,13 +158,14 @@ void BlackjackClient::PlayingTable::InterpretResponse(json::value jsonResponse) size_t i = 0; - for (auto iter = players.as_array().begin(); iter != players.as_array().end() && i < _playerSpaces.size(); ++iter,i++) + for (auto iter = players.as_array().begin(); iter != players.as_array().end() && i < _playerSpaces.size(); + ++iter, i++) { Player player = Player::FromJSON(*iter); - if ( player.Name == DEALER ) + if (player.Name == DEALER) { - if ( player.Hand.cards.size() == 1 && _dealerCards.size() == 2) + if (player.Hand.cards.size() == 1 && _dealerCards.size() == 2) { // The cards are already shown. continue; @@ -179,68 +178,71 @@ void BlackjackClient::PlayingTable::InterpretResponse(json::value jsonResponse) AddDealerCard(player.Hand.cards[j]); } - if ( player.Hand.cards.size() == 1 ) + if (player.Hand.cards.size() == 1) { // Add a dummy card that isn't shown. AddDealerCard(Card(CardSuit::CS_Club, CardValue::CV_Ace, false)); - if ( player.Hand.cards[0].value == CardValue::CV_Ace && !m_alreadyInsured ) - allow_insurance = true; + if (player.Hand.cards[0].value == CardValue::CV_Ace && !m_alreadyInsured) allow_insurance = true; } continue; } - if ( uri::decode(player.Name) == m_name ) + if (uri::decode(player.Name) == m_name) { allow_double = (player.Hand.cards.size() == 2); } - _playerSpaces[i-1]->Update(player); + _playerSpaces[i - 1]->Update(player); - for (size_t j = _playerSpaces[i-1]->CardsHeld(); j < player.Hand.cards.size(); j++) + for (size_t j = _playerSpaces[i - 1]->CardsHeld(); j < player.Hand.cards.size(); j++) { - _playerSpaces[i-1]->AddCard(player.Hand.cards[j]); + _playerSpaces[i - 1]->AddCard(player.Hand.cards[j]); } if (player.Hand.result != BJHandResult::HR_None) { - _playerSpaces[i-1]->ShowResult(player.Hand.result); + _playerSpaces[i - 1]->ShowResult(player.Hand.result); } } switch (answer.Status) { - case ST_PlaceBet: - this->resultLabel->Text = L"Place your bet!"; - EnableBetting(); - DisableHit(); - DisableInsurance(); - EnableExit(); - EnableDisconnecting(); - break; - case ST_YourTurn: - this->resultLabel->Text = L"Your turn!"; - DisableExit(); - DisableDisconnecting(); - DisableBetting(); - EnableHit(); - doubleButton->Visibility = allow_double ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed; - if (allow_insurance) EnableInsurance(); else DisableInsurance(); - break; - case ST_Refresh: - this->resultLabel->Text = L"Waiting for other players"; - DisableExit(); - DisableDisconnecting(); - DisableHit(); - DisableBetting(); - Refresh(); - break; + case ST_PlaceBet: + this->resultLabel->Text = L"Place your bet!"; + EnableBetting(); + DisableHit(); + DisableInsurance(); + EnableExit(); + EnableDisconnecting(); + break; + case ST_YourTurn: + this->resultLabel->Text = L"Your turn!"; + DisableExit(); + DisableDisconnecting(); + DisableBetting(); + EnableHit(); + doubleButton->Visibility = + allow_double ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed; + if (allow_insurance) + EnableInsurance(); + else + DisableInsurance(); + break; + case ST_Refresh: + this->resultLabel->Text = L"Waiting for other players"; + DisableExit(); + DisableDisconnecting(); + DisableHit(); + DisableBetting(); + Refresh(); + break; } } -void BlackjackClient::PlayingTable::BetButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e) +void BlackjackClient::PlayingTable::BetButton_Click(Platform::Object ^ sender, + Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e) { - if ( _tableId.empty() || m_name.empty() ) - return; + if (_tableId.empty() || m_name.empty()) return; ClearPlayerCards(); ClearDealerCards(); @@ -254,35 +256,37 @@ void BlackjackClient::PlayingTable::BetButton_Click(Platform::Object^ sender, Wi this->resultLabel->Text = L"Waiting for a response"; std::wostringstream buf; - buf << _tableId << L"?request=bet&amount=" << betText << "&name=" << uri::encode_uri(m_name,uri::components::query); - + buf << _tableId << L"?request=bet&amount=" << betText + << "&name=" << uri::encode_uri(m_name, uri::components::query); + auto request = m_client.request(methods::PUT, buf.str()); auto ctx = pplx::task_continuation_context::use_current(); - request.then([this](pplx::task tsk) { - - this->resultLabel->Text = L""; + request.then( + [this](pplx::task tsk) { + this->resultLabel->Text = L""; - try - { - auto response = tsk.get(); - InterpretResponse(response); - } - catch (const http_exception &exc) - { - InterpretError(exc.error_code().value()); - EnableExit(); - EnableDisconnecting(); - EnableBetting(); - } - }, ctx); + try + { + auto response = tsk.get(); + InterpretResponse(response); + } + catch (const http_exception& exc) + { + InterpretError(exc.error_code().value()); + EnableExit(); + EnableDisconnecting(); + EnableBetting(); + } + }, + ctx); } -void BlackjackClient::PlayingTable::InsuranceButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e) +void BlackjackClient::PlayingTable::InsuranceButton_Click(Platform::Object ^ sender, + Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e) { - if ( _tableId.empty() || m_name.empty() ) - return; + if (_tableId.empty() || m_name.empty()) return; ClearTable(); DisableHit(); @@ -294,35 +298,36 @@ void BlackjackClient::PlayingTable::InsuranceButton_Click(Platform::Object^ send this->resultLabel->Text = L"Waiting for a response"; std::wostringstream buf; - buf << _tableId << L"?request=insure&amount=" << betText << "&name=" << uri::encode_uri(m_name,uri::components::query); - + buf << _tableId << L"?request=insure&amount=" << betText + << "&name=" << uri::encode_uri(m_name, uri::components::query); + auto request = m_client.request(methods::PUT, buf.str()); auto ctx = pplx::task_continuation_context::use_current(); - request.then([this](pplx::task tsk) { - - this->resultLabel->Text = L""; + request.then( + [this](pplx::task tsk) { + this->resultLabel->Text = L""; - try - { - auto response = tsk.get(); - InterpretResponse(response); - } - catch (const http_exception &exc) - { - InterpretError(exc.error_code().value()); - EnableHit(); - EnableInsurance(); - } - }, ctx); + try + { + auto response = tsk.get(); + InterpretResponse(response); + } + catch (const http_exception& exc) + { + InterpretError(exc.error_code().value()); + EnableHit(); + EnableInsurance(); + } + }, + ctx); } - -void BlackjackClient::PlayingTable::DoubleButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e) +void BlackjackClient::PlayingTable::DoubleButton_Click(Platform::Object ^ sender, + Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e) { - if ( _tableId.empty() || m_name.empty() ) - return; + if (_tableId.empty() || m_name.empty()) return; DisableHit(); DisableInsurance(); @@ -330,34 +335,34 @@ void BlackjackClient::PlayingTable::DoubleButton_Click(Platform::Object^ sender, this->resultLabel->Text = L"Waiting for a response"; std::wostringstream buf; - buf << _tableId << L"?request=double&name=" << uri::encode_uri(m_name,uri::components::query); - + buf << _tableId << L"?request=double&name=" << uri::encode_uri(m_name, uri::components::query); + auto request = m_client.request(methods::PUT, buf.str()); auto ctx = pplx::task_continuation_context::use_current(); - request.then([this](pplx::task tsk) { - - this->resultLabel->Text = L""; + request.then( + [this](pplx::task tsk) { + this->resultLabel->Text = L""; - try - { - auto response = tsk.get(); - InterpretResponse(response); - } - catch (const http_exception &exc) - { - InterpretError(exc.error_code().value()); - EnableHit(); - } - }, ctx); + try + { + auto response = tsk.get(); + InterpretResponse(response); + } + catch (const http_exception& exc) + { + InterpretError(exc.error_code().value()); + EnableHit(); + } + }, + ctx); } - -void BlackjackClient::PlayingTable::StayButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e) +void BlackjackClient::PlayingTable::StayButton_Click(Platform::Object ^ sender, + Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e) { - if ( _tableId.empty() || m_name.empty() ) - return; + if (_tableId.empty() || m_name.empty()) return; DisableHit(); DisableInsurance(); @@ -365,66 +370,66 @@ void BlackjackClient::PlayingTable::StayButton_Click(Platform::Object^ sender, W this->resultLabel->Text = L"Waiting for a response"; std::wostringstream buf; - buf << _tableId << L"?request=stay&name=" << uri::encode_uri(m_name,uri::components::query); - + buf << _tableId << L"?request=stay&name=" << uri::encode_uri(m_name, uri::components::query); + auto request = m_client.request(methods::PUT, buf.str()); auto ctx = pplx::task_continuation_context::use_current(); - request.then([this](pplx::task tsk) { - - this->resultLabel->Text = L""; + request.then( + [this](pplx::task tsk) { + this->resultLabel->Text = L""; - try - { - auto response = tsk.get(); - InterpretResponse(response); - } - catch (const http_exception &exc) - { - InterpretError(exc.error_code().value()); - EnableHit(); - } - }, ctx); + try + { + auto response = tsk.get(); + InterpretResponse(response); + } + catch (const http_exception& exc) + { + InterpretError(exc.error_code().value()); + EnableHit(); + } + }, + ctx); } - -void BlackjackClient::PlayingTable::HitButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e) +void BlackjackClient::PlayingTable::HitButton_Click(Platform::Object ^ sender, + Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e) { - if ( _tableId.empty() || m_name.empty() ) - return; + if (_tableId.empty() || m_name.empty()) return; DisableInsurance(); this->resultLabel->Text = L"Waiting for a response"; std::wostringstream buf; - buf << _tableId << L"?request=hit&name=" << uri::encode_uri(m_name,uri::components::query); - + buf << _tableId << L"?request=hit&name=" << uri::encode_uri(m_name, uri::components::query); + auto request = m_client.request(methods::PUT, buf.str()); auto ctx = pplx::task_continuation_context::use_current(); - request.then([this](pplx::task tsk) { - - this->resultLabel->Text = L""; + request.then( + [this](pplx::task tsk) { + this->resultLabel->Text = L""; - try - { - auto response = tsk.get(); - InterpretResponse(response); - } - catch (const http_exception &exc) - { - InterpretError(exc.error_code().value()); - } - }, ctx); + try + { + auto response = tsk.get(); + InterpretResponse(response); + } + catch (const http_exception& exc) + { + InterpretError(exc.error_code().value()); + } + }, + ctx); } - -void BlackjackClient::PlayingTable::ExitButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void BlackjackClient::PlayingTable::ExitButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { - if ( _tableId.empty() || m_name.empty() ) + if (_tableId.empty() || m_name.empty()) { Windows::ApplicationModel::Core::CoreApplication::Exit(); } @@ -436,36 +441,37 @@ void BlackjackClient::PlayingTable::ExitButton_Click(Platform::Object^ sender, W auto ctx = pplx::task_continuation_context::use_current(); std::wostringstream buf; - buf << _tableId << L"?name=" << uri::encode_uri(m_name,uri::components::query); - - auto request = m_client.request(methods::DEL, buf.str()); + buf << _tableId << L"?name=" << uri::encode_uri(m_name, uri::components::query); - request.then([this](pplx::task tsk) { - - EnableExit(); - - this->resultLabel->Text = L""; + auto request = m_client.request(methods::DEL, buf.str()); - try - { - auto response = tsk.get(); - } - catch (const http_exception &exc) - { - InterpretError(exc.error_code().value()); + request.then( + [this](pplx::task tsk) { EnableExit(); - } - Windows::ApplicationModel::Core::CoreApplication::Exit(); - }, ctx); + this->resultLabel->Text = L""; + + try + { + auto response = tsk.get(); + } + catch (const http_exception& exc) + { + InterpretError(exc.error_code().value()); + EnableExit(); + } + + Windows::ApplicationModel::Core::CoreApplication::Exit(); + }, + ctx); } } -void BlackjackClient::PlayingTable::JoinButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void BlackjackClient::PlayingTable::JoinButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { m_name = this->playerName->Text->Data(); - if ( m_name.size() == 0 ) + if (m_name.size() == 0) { this->resultLabel->Text = L"Please state your name!"; return; @@ -483,40 +489,40 @@ void BlackjackClient::PlayingTable::JoinButton_Click(Platform::Object^ sender, W m_client = http_client(bldr.to_string()); std::wostringstream buf; - buf << _tableId << L"?name=" << uri::encode_uri(m_name,uri::components::query); - + buf << _tableId << L"?name=" << uri::encode_uri(m_name, uri::components::query); + auto request = m_client.request(methods::POST, buf.str()); auto ctx = pplx::task_continuation_context::use_current(); - request.then([this](pplx::task tsk) { - - EnableExit(); + request.then( + [this](pplx::task tsk) { + EnableExit(); - this->resultLabel->Text = L""; + this->resultLabel->Text = L""; - try - { - auto response = tsk.get(); + try + { + auto response = tsk.get(); - this->resultLabel->Text = L"Place your bet!"; + this->resultLabel->Text = L"Place your bet!"; - EnableDisconnecting(); - EnableBetting(); + EnableDisconnecting(); + EnableBetting(); - InterpretResponse(response); - } - catch (const http_exception &exc) - { - InterpretError(exc.error_code().value()); - EnableConnecting(); - _tableId = L""; - } - }, ctx); + InterpretResponse(response); + } + catch (const http_exception& exc) + { + InterpretError(exc.error_code().value()); + EnableConnecting(); + _tableId = L""; + } + }, + ctx); } - -void BlackjackClient::PlayingTable::LeaveButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void BlackjackClient::PlayingTable::LeaveButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { this->resultLabel->Text = L"Leaving table"; @@ -527,35 +533,34 @@ void BlackjackClient::PlayingTable::LeaveButton_Click(Platform::Object^ sender, auto ctx = pplx::task_continuation_context::use_current(); std::wostringstream buf; - buf << _tableId << L"?name=" << uri::encode_uri(m_name,uri::components::query); - - auto request = m_client.request(methods::DEL, buf.str()); + buf << _tableId << L"?name=" << uri::encode_uri(m_name, uri::components::query); - request.then([this](pplx::task tsk) { + auto request = m_client.request(methods::DEL, buf.str()); - EnableExit(); + request.then( + [this](pplx::task tsk) { + EnableExit(); - try - { - auto response = tsk.get(); + try + { + auto response = tsk.get(); - EnableConnecting(); - ClearDealerCards(); - ClearTable(); + EnableConnecting(); + ClearDealerCards(); + ClearTable(); - this->resultLabel->Text = L"Thanks for playing!"; + this->resultLabel->Text = L"Thanks for playing!"; - _tableId = L""; - } - catch (const http_exception &exc) - { - InterpretError(exc.error_code().value()); - EnableBetting(); - EnableDisconnecting(); - } - }, ctx); + _tableId = L""; + } + catch (const http_exception& exc) + { + InterpretError(exc.error_code().value()); + EnableBetting(); + EnableDisconnecting(); + } + }, + ctx); } -void PlayingTable::OnNavigatedTo(NavigationEventArgs^ e) -{ -} +void PlayingTable::OnNavigatedTo(NavigationEventArgs ^ e) {} diff --git a/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.h b/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.h index f1fe3e28be..589c1f9e6c 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.h +++ b/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.h @@ -1,168 +1,159 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Table.xaml.h: Declaration of the Table.xaml class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Table.xaml.h: Declaration of the Table.xaml class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "pch.h" + +#include "Player.xaml.h" #include "PlayingTable.g.h" #include "cpprest/http_client.h" -#include "Player.xaml.h" using namespace Platform; using namespace Windows::UI::Xaml::Controls; -using namespace web; using namespace utility; +using namespace web; +using namespace utility; using namespace http; using namespace http::client; namespace BlackjackClient { - public ref class PlayingTable sealed - { - public: - PlayingTable(); - virtual ~PlayingTable(); +public +ref class PlayingTable sealed +{ +public: + PlayingTable(); + virtual ~PlayingTable(); - protected: - virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; +protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e) override; - private: - void JoinButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void LeaveButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); +private: + void JoinButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + void LeaveButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); - void InsuranceButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void DoubleButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void StayButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void HitButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void BetButton_Click(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void ExitButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void InsuranceButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e); + void DoubleButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e); + void StayButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e); + void HitButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e); + void BetButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e); + void ExitButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); - void Refresh(); + void Refresh(); - http_client m_client; + http_client m_client; - std::wstring _tableId; + std::wstring _tableId; - bool m_alreadyInsured; - - std::wstring m_dealerResource; + bool m_alreadyInsured; - std::wstring m_name; + std::wstring m_dealerResource; - pplx::cancellation_token_source _cancellationTokenSource; + std::wstring m_name; - std::vector _dealerCards; + pplx::cancellation_token_source _cancellationTokenSource; - std::vector _playerSpaces; + std::vector _dealerCards; - void AddPlayerCard(int idx, Card card); - void AddDealerCard(Card card); + std::vector _playerSpaces; - void ShowResult(int playerIdx, Player player); + void AddPlayerCard(int idx, Card card); + void AddDealerCard(Card card); - bool InterpretError(HRESULT hr); + void ShowResult(int playerIdx, Player player); - void InterpretResponse(http_response &response); - void InterpretResponse(json::value response); + bool InterpretError(HRESULT hr); - void ClearPlayerCards() - { - for (size_t i = 0; i < _playerSpaces.size(); i++) - { - _playerSpaces[i]->Clear(); - } - } + void InterpretResponse(http_response& response); + void InterpretResponse(json::value response); - void ClearDealerCards() + void ClearPlayerCards() + { + for (size_t i = 0; i < _playerSpaces.size(); i++) { - _dealerCards.clear(); - dealerGrid->Children->Clear(); + _playerSpaces[i]->Clear(); } + } - void ClearTable() - { - ClearDealerCards(); - ClearPlayerCards(); - resultLabel->Text = ""; - } + void ClearDealerCards() + { + _dealerCards.clear(); + dealerGrid->Children->Clear(); + } - void EnableBetting() - { - button1->Visibility = Windows::UI::Xaml::Visibility::Visible; - betBox->Visibility = Windows::UI::Xaml::Visibility::Visible; - label1->Visibility = Windows::UI::Xaml::Visibility::Visible; - betBox->IsEnabled = true; - } - void DisableBetting() - { - button1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - betBox->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - label1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - } + void ClearTable() + { + ClearDealerCards(); + ClearPlayerCards(); + resultLabel->Text = ""; + } - void EnableInsurance() - { - buyInsuranceLabel->Visibility = Windows::UI::Xaml::Visibility::Visible; - buyInsuranceTextBox->Visibility = Windows::UI::Xaml::Visibility::Visible; - buyInsuranceButton->Visibility = Windows::UI::Xaml::Visibility::Visible; - m_alreadyInsured = true; - } - void DisableInsurance() - { - buyInsuranceLabel->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - buyInsuranceTextBox->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - buyInsuranceButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - } + void EnableBetting() + { + button1->Visibility = Windows::UI::Xaml::Visibility::Visible; + betBox->Visibility = Windows::UI::Xaml::Visibility::Visible; + label1->Visibility = Windows::UI::Xaml::Visibility::Visible; + betBox->IsEnabled = true; + } + void DisableBetting() + { + button1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + betBox->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + label1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + } - void EnableHit() - { - hitButton->Visibility = Windows::UI::Xaml::Visibility::Visible; - stayButton->Visibility = Windows::UI::Xaml::Visibility::Visible; - } - void DisableHit() - { - hitButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - stayButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - doubleButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - } + void EnableInsurance() + { + buyInsuranceLabel->Visibility = Windows::UI::Xaml::Visibility::Visible; + buyInsuranceTextBox->Visibility = Windows::UI::Xaml::Visibility::Visible; + buyInsuranceButton->Visibility = Windows::UI::Xaml::Visibility::Visible; + m_alreadyInsured = true; + } + void DisableInsurance() + { + buyInsuranceLabel->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + buyInsuranceTextBox->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + buyInsuranceButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + } - void EnableConnecting() - { - joinButton->Visibility = Windows::UI::Xaml::Visibility::Visible; - TopBar->IsEnabled = true; - } + void EnableHit() + { + hitButton->Visibility = Windows::UI::Xaml::Visibility::Visible; + stayButton->Visibility = Windows::UI::Xaml::Visibility::Visible; + } + void DisableHit() + { + hitButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + stayButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + doubleButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + } - void DisableConnecting() - { - joinButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - TopBar->IsEnabled = false; - } + void EnableConnecting() + { + joinButton->Visibility = Windows::UI::Xaml::Visibility::Visible; + TopBar->IsEnabled = true; + } - void EnableDisconnecting() - { - leaveButton->Visibility = Windows::UI::Xaml::Visibility::Visible; - } + void DisableConnecting() + { + joinButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + TopBar->IsEnabled = false; + } - void DisableDisconnecting() - { - leaveButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - } + void EnableDisconnecting() { leaveButton->Visibility = Windows::UI::Xaml::Visibility::Visible; } - void EnableExit() - { - exitButton->Visibility = Windows::UI::Xaml::Visibility::Visible; - } + void DisableDisconnecting() { leaveButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; } - void DisableExit() - { - exitButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - } - }; -} + void EnableExit() { exitButton->Visibility = Windows::UI::Xaml::Visibility::Visible; } + + void DisableExit() { exitButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; } +}; +} // namespace BlackjackClient diff --git a/Release/samples/BlackJack/BlackJack_UIClient/messagetypes.h b/Release/samples/BlackJack/BlackJack_UIClient/messagetypes.h index 325b915c2f..d7eff9e191 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/messagetypes.h +++ b/Release/samples/BlackJack/BlackJack_UIClient/messagetypes.h @@ -1,28 +1,77 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* messagetypes.h -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * messagetypes.h + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "cpprest/json.h" -enum BJHandResult { HR_None, HR_PlayerBlackJack, HR_PlayerWin, HR_ComputerWin, HR_Push }; +enum BJHandResult +{ + HR_None, + HR_PlayerBlackJack, + HR_PlayerWin, + HR_ComputerWin, + HR_Push +}; -enum BJHandState { HR_Empty, HR_BlackJack, HR_Active, HR_Held, HR_Busted }; +enum BJHandState +{ + HR_Empty, + HR_BlackJack, + HR_Active, + HR_Held, + HR_Busted +}; -enum BJPossibleMoves { PM_None = 0x0, PM_Hit = 0x1, PM_DoubleDown = 0x2, PM_Split = 0x4, PM_All = 0x7 }; +enum BJPossibleMoves +{ + PM_None = 0x0, + PM_Hit = 0x1, + PM_DoubleDown = 0x2, + PM_Split = 0x4, + PM_All = 0x7 +}; -enum CardSuit { CS_Heart, CS_Diamond, CS_Club, CS_Spade }; - -enum CardValue { CV_None, CV_Ace, CV_Two, CV_Three, CV_Four, CV_Five, CV_Six, CV_Seven, CV_Eight, CV_Nine, CV_Ten, CV_Jack, CV_Queen, CV_King }; +enum CardSuit +{ + CS_Heart, + CS_Diamond, + CS_Club, + CS_Spade +}; + +enum CardValue +{ + CV_None, + CV_Ace, + CV_Two, + CV_Three, + CV_Four, + CV_Five, + CV_Six, + CV_Seven, + CV_Eight, + CV_Nine, + CV_Ten, + CV_Jack, + CV_Queen, + CV_King +}; -enum BJStatus { ST_PlaceBet, ST_Refresh, ST_YourTurn, ST_None }; +enum BJStatus +{ + ST_PlaceBet, + ST_Refresh, + ST_YourTurn, + ST_None +}; #define STATE L"state" #define BET L"bet" @@ -53,12 +102,12 @@ struct Card { CardSuit suit; CardValue value; - bool visible; + bool visible; - Card(CardSuit suit, CardValue value, bool show = true) : suit(suit), value(value), visible(show) {} - Card(const Card &other) : suit(other.suit), value(other.value), visible(other.visible) {} + Card(CardSuit suit, CardValue value, bool show = true) : suit(suit), value(value), visible(show) {} + Card(const Card& other) : suit(other.suit), value(other.value), visible(other.visible) {} - Card(web::json::value object) : visible(true) + Card(web::json::value object) : visible(true) { suit = (CardSuit)(int)object[SUIT].as_double(); value = (CardValue)(int)object[VALUE].as_double(); @@ -85,18 +134,24 @@ struct BJHand BJHand() : state(HR_Empty), result(HR_None), bet(0.0), insurance(0), revealBoth(true) {} - void Clear() { cards.clear(); state = HR_Empty; result = HR_None; insurance = 0.0; } + void Clear() + { + cards.clear(); + state = HR_Empty; + result = HR_None; + insurance = 0.0; + } void AddCard(Card card) - { - cards.push_back(card); + { + cards.push_back(card); NumericHandValues value = GetNumericValues(); - if ( cards.size() == 2 && value.high == 21 ) + if (cards.size() == 2 && value.high == 21) { state = HR_BlackJack; } - else if ( value.low > 21 ) + else if (value.low > 21) { state = HR_Busted; } @@ -116,7 +171,7 @@ struct BJHand for (auto iter = cards.begin(); iter != cards.end(); ++iter) { - if ( iter->value == CV_Ace ) hasAces = true; + if (iter->value == CV_Ace) hasAces = true; r.low += (iter->value < 10) ? iter->value : 10; } @@ -124,23 +179,23 @@ struct BJHand return r; } - BJHand(web::json::value object) + BJHand(web::json::value object) { web::json::value l_cards = object[CARDS]; for (auto iter = l_cards.as_array().begin(); iter != l_cards.as_array().end(); ++iter) { - if ( !iter->is_null() ) + if (!iter->is_null()) { Card card(*iter); this->cards.push_back(card); } } - - state = (BJHandState)(int)object[STATE].as_double(); - bet = object[BET].as_double(); + + state = (BJHandState)(int)object[STATE].as_double(); + bet = object[BET].as_double(); insurance = object[INSURANCE].as_double(); - result = (BJHandResult)(int)object[RESULT].as_double(); + result = (BJHandResult)(int)object[RESULT].as_double(); } }; @@ -151,23 +206,22 @@ struct Player double Balance; Player() {} - Player(const std::wstring &name) : Name(name), Balance(1000.0) {} + Player(const std::wstring& name) : Name(name), Balance(1000.0) {} - static Player FromJSON(web::json::value object) + static Player FromJSON(web::json::value object) { - Player result; + Player result; - const web::json::value &name = object[NAME]; - const web::json::value &balance = object[BALANCE]; - const web::json::value &hand = object[HAND]; + const web::json::value& name = object[NAME]; + const web::json::value& balance = object[BALANCE]; + const web::json::value& hand = object[HAND]; result.Name = name.as_string(); result.Balance = balance.as_double(); result.Hand = BJHand(hand); - return result; + return result; } - }; struct BJTable @@ -177,7 +231,11 @@ struct BJTable std::vector Players; BJTable() : Capacity(0) {} - BJTable(int id, size_t capacity) : Id(id), Capacity(capacity) { Player tmp(DEALER); Players.push_back(tmp); } + BJTable(int id, size_t capacity) : Id(id), Capacity(capacity) + { + Player tmp(DEALER); + Players.push_back(tmp); + } BJTable(web::json::value object) { @@ -195,19 +253,19 @@ struct BJTable struct BJPutResponse { - BJStatus Status; + BJStatus Status; web::json::value Data; BJPutResponse() {} - BJPutResponse(BJStatus status, web::json::value data) : Status(status), Data(data) { } + BJPutResponse(BJStatus status, web::json::value data) : Status(status), Data(data) {} static BJPutResponse FromJSON(web::json::value object) { BJPutResponse result((BJStatus)(int)object[STATUS].as_double(), object[DATA]); - return result; + return result; } - web::json::value AsJSON() const + web::json::value AsJSON() const { web::json::value result = web::json::value::object(); result[STATUS] = web::json::value::number((double)Status); diff --git a/Release/samples/BlackJack/BlackJack_UIClient/pch.cpp b/Release/samples/BlackJack/BlackJack_UIClient/pch.cpp index dfd959aa19..74bfcf953a 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/pch.cpp +++ b/Release/samples/BlackJack/BlackJack_UIClient/pch.cpp @@ -1,12 +1,12 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* pch.cpp: Include the standard header and generate the precompiled header. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * pch.cpp: Include the standard header and generate the precompiled header. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "pch.h" diff --git a/Release/samples/BlackJack/BlackJack_UIClient/pch.h b/Release/samples/BlackJack/BlackJack_UIClient/pch.h index 65fb42f8fc..427ba8774d 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/pch.h +++ b/Release/samples/BlackJack/BlackJack_UIClient/pch.h @@ -1,16 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* pch.h: Header for standard system include files. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * pch.h: Header for standard system include files. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include #include "App.xaml.h" -#include "messagetypes.h" \ No newline at end of file +#include "messagetypes.h" +#include diff --git a/Release/samples/CasaLens/casalens.cpp b/Release/samples/CasaLens/casalens.cpp index 4caac60d46..c98e926abf 100644 --- a/Release/samples/CasaLens/casalens.cpp +++ b/Release/samples/CasaLens/casalens.cpp @@ -1,16 +1,17 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* casalens.cpp: Listener code: Given a location/postal code, the listener queries different services -* for weather, things to do: events, movie and pictures and returns it to the client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * casalens.cpp: Listener code: Given a location/postal code, the listener queries different services + * for weather, things to do: events, movie and pictures and returns it to the client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "casalens.h" using namespace web; @@ -18,29 +19,30 @@ using namespace http; using namespace utility; using namespace http::experimental::listener; -const utility::string_t casalens_creds::events_url=U("http://api.eventful.com/json/events/search?...&location="); -const utility::string_t casalens_creds::movies_url=U("http://data.tmsapi.com/v1/movies/showings?"); -const utility::string_t casalens_creds::images_url=U("https://api.datamarket.azure.com/Bing/Search/Image?$format=json"); -const utility::string_t casalens_creds::bmaps_url=U("http://dev.virtualearth.net/REST/v1/Locations"); -const utility::string_t casalens_creds::gmaps_url=U("http://maps.googleapis.com/maps/api/geocode/json"); -const utility::string_t casalens_creds::weather_url=U("http://api.openweathermap.org/data/2.1/find/name?q="); +const utility::string_t casalens_creds::events_url = U("http://api.eventful.com/json/events/search?...&location="); +const utility::string_t casalens_creds::movies_url = U("http://data.tmsapi.com/v1/movies/showings?"); +const utility::string_t casalens_creds::images_url = + U("https://api.datamarket.azure.com/Bing/Search/Image?$format=json"); +const utility::string_t casalens_creds::bmaps_url = U("http://dev.virtualearth.net/REST/v1/Locations"); +const utility::string_t casalens_creds::gmaps_url = U("http://maps.googleapis.com/maps/api/geocode/json"); +const utility::string_t casalens_creds::weather_url = U("http://api.openweathermap.org/data/2.1/find/name?q="); -// FILL IN THE API KEYS FOR THE DIFFERENT SERVICES HERE. +// FILL IN THE API KEYS FOR THE DIFFERENT SERVICES HERE. // Refer Readme.txt for details on how to obtain the key for the services. -const utility::string_t casalens_creds::events_keyname=U("app_key"); -const utility::string_t casalens_creds::events_key=U(""); -const utility::string_t casalens_creds::movies_keyname=U("api_key"); -const utility::string_t casalens_creds::movies_key=U(""); -const utility::string_t casalens_creds::images_keyname=U("username"); -const utility::string_t casalens_creds::images_key=U(""); -const utility::string_t casalens_creds::bmaps_keyname=U("key"); -const utility::string_t casalens_creds::bmaps_key=U(""); - -const utility::string_t CasaLens::events_json_key=U("events"); -const utility::string_t CasaLens::movies_json_key=U("movies"); -const utility::string_t CasaLens::weather_json_key=U("weather"); -const utility::string_t CasaLens::images_json_key=U("images"); -const utility::string_t CasaLens::error_json_key=U("error"); +const utility::string_t casalens_creds::events_keyname = U("app_key"); +const utility::string_t casalens_creds::events_key = U(""); +const utility::string_t casalens_creds::movies_keyname = U("api_key"); +const utility::string_t casalens_creds::movies_key = U(""); +const utility::string_t casalens_creds::images_keyname = U("username"); +const utility::string_t casalens_creds::images_key = U(""); +const utility::string_t casalens_creds::bmaps_keyname = U("key"); +const utility::string_t casalens_creds::bmaps_key = U(""); + +const utility::string_t CasaLens::events_json_key = U("events"); +const utility::string_t CasaLens::movies_json_key = U("movies"); +const utility::string_t CasaLens::weather_json_key = U("weather"); +const utility::string_t CasaLens::images_json_key = U("images"); +const utility::string_t CasaLens::error_json_key = U("error"); CasaLens::CasaLens(utility::string_t url) : m_listener(url) { @@ -51,25 +53,26 @@ CasaLens::CasaLens(utility::string_t url) : m_listener(url) m_htmlcontentmap[U("/js/default.js")] = std::make_tuple(U("js/default.js"), U("application/javascript")); m_htmlcontentmap[U("/css/default.css")] = std::make_tuple(U("css/default.css"), U("text/css")); m_htmlcontentmap[U("/image/logo.png")] = std::make_tuple(U("image/logo.png"), U("application/octet-stream")); - m_htmlcontentmap[U("/image/bing-logo.jpg")] = std::make_tuple(U("image/bing-logo.jpg"), U("application/octet-stream")); + m_htmlcontentmap[U("/image/bing-logo.jpg")] = + std::make_tuple(U("image/bing-logo.jpg"), U("application/octet-stream")); m_htmlcontentmap[U("/image/wall.jpg")] = std::make_tuple(U("image/wall.jpg"), U("application/octet-stream")); } void CasaLens::handle_error(pplx::task& t) -{ +{ try { t.get(); } - catch(...) + catch (...) { - // Ignore the error, Log it if a logger is available + // Ignore the error, Log it if a logger is available } } pplx::task CasaLens::open() { - return m_listener.open().then([](pplx::task t) { handle_error(t); }); + return m_listener.open().then([](pplx::task t) { handle_error(t); }); } pplx::task CasaLens::close() @@ -80,7 +83,7 @@ pplx::task CasaLens::close() // Handler to process HTTP::GET requests. // Replies to the request with data. void CasaLens::handle_get(http_request message) -{ +{ auto path = message.relative_uri().path(); auto content_data = m_htmlcontentmap.find(path); if (content_data == m_htmlcontentmap.end()) @@ -91,36 +94,35 @@ void CasaLens::handle_get(http_request message) auto file_name = std::get<0>(content_data->second); auto content_type = std::get<1>(content_data->second); - concurrency::streams::fstream::open_istream(file_name, std::ios::in).then([=](concurrency::streams::istream is) - { - message.reply(status_codes::OK, is, content_type).then([](pplx::task t) { handle_error(t); }); - }).then([=](pplx::task t) - { - try - { - t.get(); - } - catch(...) - { - // opening the file (open_istream) failed. - // Reply with an error. - message.reply(status_codes::InternalError).then([](pplx::task t) { handle_error(t); }); - } - }); + concurrency::streams::fstream::open_istream(file_name, std::ios::in) + .then([=](concurrency::streams::istream is) { + message.reply(status_codes::OK, is, content_type).then([](pplx::task t) { handle_error(t); }); + }) + .then([=](pplx::task t) { + try + { + t.get(); + } + catch (...) + { + // opening the file (open_istream) failed. + // Reply with an error. + message.reply(status_codes::InternalError).then([](pplx::task t) { handle_error(t); }); + } + }); } // Respond to HTTP::POST messages // Post data will contain the postal code or location string. // Aggregate location data from different services and reply to the POST request. void CasaLens::handle_post(http_request message) -{ +{ auto path = message.relative_uri().path(); if (0 == path.compare(U("/"))) { - message.extract_string().then([=](const utility::string_t& location) - { - get_data(message, location); - }).then([](pplx::task t) { handle_error(t); }); + message.extract_string() + .then([=](const utility::string_t& location) { get_data(message, location); }) + .then([](pplx::task t) { handle_error(t); }); } else { @@ -129,12 +131,12 @@ void CasaLens::handle_post(http_request message) } #ifdef _WIN32 -int wmain(int argc, wchar_t *args[]) +int wmain(int argc, wchar_t* args[]) #else -int main(int argc, char *args[]) +int main(int argc, char* args[]) #endif { - if(argc != 2) + if (argc != 2) { wprintf(U("Usage: casalens.exe port\n")); return -1; @@ -155,4 +157,4 @@ int main(int argc, char *args[]) listener.close().wait(); return 0; -} \ No newline at end of file +} diff --git a/Release/samples/CasaLens/casalens.h b/Release/samples/CasaLens/casalens.h index 7d75f14cae..655a9d1830 100644 --- a/Release/samples/CasaLens/casalens.h +++ b/Release/samples/CasaLens/casalens.h @@ -1,30 +1,31 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* casalens.h: Listener code: Given a location/postal code, the listener queries different services -* for weather, things to do: events, movie and pictures and returns it to the client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * casalens.h: Listener code: Given a location/postal code, the listener queries different services + * for weather, things to do: events, movie and pictures and returns it to the client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "stdafx.h" -#include "cpprest\http_listener.h" -#include "cpprest/json.h" -#include "cpprest/filestream.h" + #include "cpprest/containerstream.h" -#include "cpprest/producerconsumerstream.h" -#include "cpprest/http_listener.h" +#include "cpprest/filestream.h" #include "cpprest/http_client.h" -#pragma warning ( push ) -#pragma warning ( disable : 4457 ) +#include "cpprest/http_listener.h" +#include "cpprest/json.h" +#include "cpprest/producerconsumerstream.h" +#include "cpprest\http_listener.h" +#pragma warning(push) +#pragma warning(disable : 4457) #include -#pragma warning ( pop ) -#include +#pragma warning(pop) #include +#include // // Credentials class to manage the service URLs, key name and api-keys. @@ -52,7 +53,7 @@ class casalens_creds // // This class implements the CasaLens server functionality. // It maintains a http_listener, registers to listen for requests. -// Also implements the handlers to respond to requests and methods to fetch +// Also implements the handlers to respond to requests and methods to fetch // and aggregate data from different services. // class CasaLens @@ -68,7 +69,6 @@ class CasaLens void handle_post(web::http::http_request message); private: - // Error handlers static void handle_error(pplx::task& t); pplx::task handle_exception(pplx::task& t, const utility::string_t& field_name); @@ -109,8 +109,8 @@ class CasaLens // value: Tuple where: // Element1: relative path on the disk of the file being requested // Element2: Mime type/content type of the file - std::map> m_htmlcontentmap; + std::map> m_htmlcontentmap; - // HTTP listener - web::http::experimental::listener::http_listener m_listener; -}; \ No newline at end of file + // HTTP listener + web::http::experimental::listener::http_listener m_listener; +}; diff --git a/Release/samples/CasaLens/datafetcher.cpp b/Release/samples/CasaLens/datafetcher.cpp index 7f5c55d1c5..604e5b3a45 100644 --- a/Release/samples/CasaLens/datafetcher.cpp +++ b/Release/samples/CasaLens/datafetcher.cpp @@ -1,16 +1,17 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* datafetcher.cpp: Listener code: Given a location/postal code, the listener queries different services -* for weather, things to do: events, movie and pictures and returns it to the client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * datafetcher.cpp: Listener code: Given a location/postal code, the listener queries different services + * for weather, things to do: events, movie and pictures and returns it to the client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "casalens.h" using namespace utility; @@ -23,7 +24,7 @@ using namespace web::http::client; using namespace web::http::experimental; using namespace web::http::experimental::listener; -// In case of any failure to fetch data from a service, +// In case of any failure to fetch data from a service, // create a json object with "error" key and value containing the exception details. pplx::task CasaLens::handle_exception(pplx::task& t, const utility::string_t& field_name) { @@ -31,7 +32,7 @@ pplx::task CasaLens::handle_exception(pplx::task& t, c { t.get(); } - catch(const std::exception& ex) + catch (const std::exception& ex) { json::value error_json = json::value::object(); error_json[field_name] = json::value::object(); @@ -54,73 +55,69 @@ pplx::task CasaLens::get_events(const utility::string_t& postal_cod auto event_url = ub.to_string(); http_client ev_client(event_url); - return ev_client.request(methods::GET, event_url).then([](http_response resp) - { - return resp.extract_json(); - }).then([](json::value event_json) - { - json::value event_result_node = json::value::object(); + return ev_client.request(methods::GET, event_url) + .then([](http_response resp) { return resp.extract_json(); }) + .then([](json::value event_json) { + json::value event_result_node = json::value::object(); - if (!event_json[U("events")][U("event")].is_null()) - { - event_result_node[U("events")] = json::value::array(); - - int i = 0; - for(auto& iter : event_json[U("events")][U("event")].as_array()) + if (!event_json[U("events")][U("event")].is_null()) { - const auto &event = iter; - auto iTitle = event.as_object().find(U("title")); - if (iTitle == event.as_object().end()) - { - throw web::json::json_exception(U("title key not found")); - } - event_result_node[events_json_key][i][U("title")] = iTitle->second; - auto iUrl = event.as_object().find(U("url")); - if (iUrl == event.as_object().end()) - { - throw web::json::json_exception(U("url key not found")); - } - event_result_node[events_json_key][i][U("url")] = iUrl->second; - auto iStartTime = event.as_object().find(U("start_time")); - if (iStartTime == event.as_object().end()) - { - throw web::json::json_exception(U("start_time key not found")); - } - event_result_node[events_json_key][i][U("starttime")] = iStartTime->second; - auto iDescription = event.as_object().find(U("description")); - if (iDescription == event.as_object().end()) - { - throw web::json::json_exception(U("descriotion key not found")); - } - event_result_node[events_json_key][i][U("description")] = iDescription->second; - auto iVenueAddress = event.as_object().find(U("venue_address")); - if (iVenueAddress == event.as_object().end()) - { - throw web::json::json_exception(U("venue_address key not found")); - } - auto iCityName = event.as_object().find(U("city_name")); - if (iCityName == event.as_object().end()) + event_result_node[U("events")] = json::value::array(); + + int i = 0; + for (auto& iter : event_json[U("events")][U("event")].as_array()) { - throw web::json::json_exception(U("city_name key not found")); - } - event_result_node[events_json_key][i][U("venue_address")] = json::value::string(iVenueAddress->second.as_string() + U(" ") + iCityName->second.as_string()); + const auto& event = iter; + auto iTitle = event.as_object().find(U("title")); + if (iTitle == event.as_object().end()) + { + throw web::json::json_exception(U("title key not found")); + } + event_result_node[events_json_key][i][U("title")] = iTitle->second; + auto iUrl = event.as_object().find(U("url")); + if (iUrl == event.as_object().end()) + { + throw web::json::json_exception(U("url key not found")); + } + event_result_node[events_json_key][i][U("url")] = iUrl->second; + auto iStartTime = event.as_object().find(U("start_time")); + if (iStartTime == event.as_object().end()) + { + throw web::json::json_exception(U("start_time key not found")); + } + event_result_node[events_json_key][i][U("starttime")] = iStartTime->second; + auto iDescription = event.as_object().find(U("description")); + if (iDescription == event.as_object().end()) + { + throw web::json::json_exception(U("descriotion key not found")); + } + event_result_node[events_json_key][i][U("description")] = iDescription->second; + auto iVenueAddress = event.as_object().find(U("venue_address")); + if (iVenueAddress == event.as_object().end()) + { + throw web::json::json_exception(U("venue_address key not found")); + } + auto iCityName = event.as_object().find(U("city_name")); + if (iCityName == event.as_object().end()) + { + throw web::json::json_exception(U("city_name key not found")); + } + event_result_node[events_json_key][i][U("venue_address")] = + json::value::string(iVenueAddress->second.as_string() + U(" ") + iCityName->second.as_string()); - if (i++ > num_events) - break; + if (i++ > num_events) break; + } + } + else + { + // Event data is null, we hit an error. + event_result_node[events_json_key] = json::value::object(); + event_result_node[events_json_key][error_json_key] = event_json[U("events")][U("description")]; } - } - else - { - // Event data is null, we hit an error. - event_result_node[events_json_key] = json::value::object(); - event_result_node[events_json_key][error_json_key] = event_json[U("events")][U("description")]; - } - return event_result_node; - }).then([=](pplx::task t) - { - return handle_exception(t, events_json_key); - }); + return event_result_node; + }) + .then([=](pplx::task t) { return handle_exception(t, events_json_key); }); } // Query openweathermap API and obtain weather information at the given location. @@ -135,29 +132,27 @@ pplx::task CasaLens::get_weather(const utility::string_t& postal_co ub_weather.append_query(U("units"), U("imperial")); http_client weather_client(ub_weather.to_string()); - return weather_client.request(methods::GET).then([](http_response resp) - { - return resp.extract_string(); - }).then([](utility::string_t weather_str) - { - json::value weather_json = json::value::parse(weather_str); - - auto& j = weather_json[U("list")][0][U("main")]; - - json::value weather_result_node = json::value::object(); - weather_result_node[weather_json_key] = json::value::object(); - auto& w = weather_result_node[U("weather")]; - w[U("temperature")] = j[U("temp")]; - w[U("pressure")] = j[U("pressure")]; - w[U("temp_min")] = j[U("temp_min")]; - w[U("temp_max")] = j[U("temp_max")]; - w[U("image")] = json::value::string(U("http://openweathermap.org/img/w/") + weather_json[U("list")][0][U("weather")][0][U("icon")].as_string() + U(".png")); - w[U("description")] = weather_json[U("list")][0][U("weather")][0][U("description")]; - return weather_result_node; - }).then([=](pplx::task t) - { - return handle_exception(t, weather_json_key); - }); + return weather_client.request(methods::GET) + .then([](http_response resp) { return resp.extract_string(); }) + .then([](utility::string_t weather_str) { + json::value weather_json = json::value::parse(weather_str); + + auto& j = weather_json[U("list")][0][U("main")]; + + json::value weather_result_node = json::value::object(); + weather_result_node[weather_json_key] = json::value::object(); + auto& w = weather_result_node[U("weather")]; + w[U("temperature")] = j[U("temp")]; + w[U("pressure")] = j[U("pressure")]; + w[U("temp_min")] = j[U("temp_min")]; + w[U("temp_max")] = j[U("temp_max")]; + w[U("image")] = + json::value::string(U("http://openweathermap.org/img/w/") + + weather_json[U("list")][0][U("weather")][0][U("icon")].as_string() + U(".png")); + w[U("description")] = weather_json[U("list")][0][U("weather")][0][U("description")]; + return weather_result_node; + }) + .then([=](pplx::task t) { return handle_exception(t, weather_json_key); }); } // Query bing images to fetch some image URLs of the given location @@ -176,32 +171,27 @@ pplx::task CasaLens::get_pictures(const utility::string_t& location ub_bing.append_query(U("ImageFilters"), U("'Size:Medium'")); http_client bing_client(ub_bing.to_string(), config); - return bing_client.request(methods::GET).then([](http_response resp) - { - return resp.extract_json(); - }).then([](json::value image_json) - { - json::value image_result_node = json::value::object(); - image_result_node[images_json_key] = json::value::array(); + return bing_client.request(methods::GET) + .then([](http_response resp) { return resp.extract_json(); }) + .then([](json::value image_json) { + json::value image_result_node = json::value::object(); + image_result_node[images_json_key] = json::value::array(); - int i = 0; - for(auto& val : image_json[U("d")][U("results")].as_object()) - { - const json::object &image = val.second.as_object(); - auto iMediaUrl = image.find(U("MediaUrl")); - if (iMediaUrl == image.end()) + int i = 0; + for (auto& val : image_json[U("d")][U("results")].as_object()) { - throw web::json::json_exception(U("MediaUrl key not found")); + const json::object& image = val.second.as_object(); + auto iMediaUrl = image.find(U("MediaUrl")); + if (iMediaUrl == image.end()) + { + throw web::json::json_exception(U("MediaUrl key not found")); + } + image_result_node[images_json_key][i] = iMediaUrl->second; + if (i++ > num_images) break; } - image_result_node[images_json_key][i] = iMediaUrl->second; - if (i++ > num_images) - break; - } - return image_result_node; - }).then([=](pplx::task t) - { - return handle_exception(t, images_json_key); - }); + return image_result_node; + }) + .then([=](pplx::task t) { return handle_exception(t, images_json_key); }); } // Get the current date @@ -212,17 +202,15 @@ std::wstring CasaLens::get_date() std::wostringstream date; if (0 == localtime_s(&now, &t)) { - date << (now.tm_year + 1900) << '-' - << (now.tm_mon + 1) << '-' - << now.tm_mday; + date << (now.tm_year + 1900) << '-' << (now.tm_mon + 1) << '-' << now.tm_mday; } return date.str(); } // Query tmsapi and fetch current movie showtimes at local theaters, for the given postal code -// Also quert bing images for movie posters +// Also quert bing images for movie posters // Returns a task of JSON value -// JSON result format: +// JSON result format: // "movies":[{"title":"abc","theatre":[{"name":"theater1","datetime":["dd-mm-yyThh:mm"]},{"name":"theater2","datetime":["ddmmyy"]}],"poster":"img-url"}}]}.. pplx::task CasaLens::get_movies(const utility::string_t& postal_code) { @@ -234,118 +222,120 @@ pplx::task CasaLens::get_movies(const utility::string_t& postal_cod ub_movie.append_query(U("imageSize"), U("Sm")); http_client tms_client(ub_movie.to_string()); - return tms_client.request(methods::GET).then([](http_response resp) - { - return resp.extract_json(); - }).then([](json::value movie_json) - { - // From the data obtained from tmsapi, construct movie JSON value to be sent to the client - // We will collect data for 5 movies, and 5 showtime info per movie. - json::value movie_result_node = json::value::object(); - - if (movie_json.size()) - { - auto temp = json::value::array(); - int i = 0; - for(auto iter = movie_json.as_array().cbegin(); iter != movie_json.as_array().cend() && i < num_movies; iter++, i++) + return tms_client.request(methods::GET) + .then([](http_response resp) { return resp.extract_json(); }) + .then([](json::value movie_json) { + // From the data obtained from tmsapi, construct movie JSON value to be sent to the client + // We will collect data for 5 movies, and 5 showtime info per movie. + json::value movie_result_node = json::value::object(); + + if (movie_json.size()) { - auto iShowTimes = iter->as_object().find(U("showtimes")); - if (iShowTimes == iter->as_object().end()) - { - throw web::json::json_exception(U("showtimes key not found")); - } - auto& showtimes = iShowTimes->second; - - int j = 0; - int showtime_index = 0; - int theater_index = -1; - utility::string_t current_theater; - auto iTitle = iter->as_object().find(U("title")); - if (iTitle == iter->as_object().end()) + auto temp = json::value::array(); + int i = 0; + for (auto iter = movie_json.as_array().cbegin(); iter != movie_json.as_array().cend() && i < num_movies; + iter++, i++) { - throw web::json::json_exception(U("title key not found")); - } - temp[i][U("title")] = iTitle->second; - for (auto iter2 = showtimes.as_array().cbegin(); iter2 != showtimes.as_array().cend() && j < num_movies; iter2++,j++) - { - auto iTheatre = iter2->as_object().find(U("theatre")); - if (iTheatre == iter2->as_object().end()) - { - throw web::json::json_exception(U("theatre key not found")); - } - auto iName = iTheatre->second.as_object().find(U("name")); - if (iName == iTheatre->second.as_object().end()) + auto iShowTimes = iter->as_object().find(U("showtimes")); + if (iShowTimes == iter->as_object().end()) { - throw web::json::json_exception(U("name key not found")); + throw web::json::json_exception(U("showtimes key not found")); } - auto theater = iName->second.as_string(); - if (0 != theater.compare(current_theater)) // new theater + auto& showtimes = iShowTimes->second; + + int j = 0; + int showtime_index = 0; + int theater_index = -1; + utility::string_t current_theater; + auto iTitle = iter->as_object().find(U("title")); + if (iTitle == iter->as_object().end()) { - temp[i][U("theatre")][++theater_index][U("name")] = json::value::string(theater); // Add theater entry - showtime_index = 0; - current_theater = theater; + throw web::json::json_exception(U("title key not found")); } - auto iDateTime = iter2->as_object().find(U("dateTime")); - if (iDateTime == iter2->as_object().end()) + temp[i][U("title")] = iTitle->second; + for (auto iter2 = showtimes.as_array().cbegin(); + iter2 != showtimes.as_array().cend() && j < num_movies; + iter2++, j++) { - throw web::json::json_exception(U("dateTime key not found")); + auto iTheatre = iter2->as_object().find(U("theatre")); + if (iTheatre == iter2->as_object().end()) + { + throw web::json::json_exception(U("theatre key not found")); + } + auto iName = iTheatre->second.as_object().find(U("name")); + if (iName == iTheatre->second.as_object().end()) + { + throw web::json::json_exception(U("name key not found")); + } + auto theater = iName->second.as_string(); + if (0 != theater.compare(current_theater)) // new theater + { + temp[i][U("theatre")][++theater_index][U("name")] = + json::value::string(theater); // Add theater entry + showtime_index = 0; + current_theater = theater; + } + auto iDateTime = iter2->as_object().find(U("dateTime")); + if (iDateTime == iter2->as_object().end()) + { + throw web::json::json_exception(U("dateTime key not found")); + } + temp[i][U("theatre")][theater_index][U("datetime")][showtime_index++] = + iDateTime->second; // Update the showtime for same theater } - temp[i][U("theatre")][theater_index][U("datetime")][showtime_index++] = iDateTime->second; // Update the showtime for same theater } + movie_result_node[movies_json_key] = std::move(temp); } - movie_result_node[movies_json_key] = std::move(temp); - } - else - { - movie_result_node[movies_json_key] = json::value::object(); - movie_result_node[movies_json_key][error_json_key] = json::value::string(U("Failed to fetch movie data")); - } - - return pplx::task_from_result(movie_result_node); - }).then([=](json::value movie_result) - { - try - { - // For every movie, obtain movie poster URL from bing - std::vector movie_list; - std::vector> poster_tasks; - auto date = get_date(); - std::wstring year = date.substr(0, date.find(U("-"))); - - for(auto& iter : movie_result[movies_json_key].as_object()) + else { - auto title = iter.second[U("title")].as_string(); - auto searchStr = title + U(" ") + year + U(" new movie poster"); - poster_tasks.push_back(get_pictures(searchStr, U("1"))); - movie_list.push_back(title); + movie_result_node[movies_json_key] = json::value::object(); + movie_result_node[movies_json_key][error_json_key] = + json::value::string(U("Failed to fetch movie data")); } - pplx::when_all(poster_tasks.begin(), poster_tasks.end()).wait(); - json::value resp_data = json::value::object(); + return pplx::task_from_result(movie_result_node); + }) + .then([=](json::value movie_result) { + try + { + // For every movie, obtain movie poster URL from bing + std::vector movie_list; + std::vector> poster_tasks; + auto date = get_date(); + std::wstring year = date.substr(0, date.find(U("-"))); - for(unsigned int i = 0; i < poster_tasks.size(); i++) + for (auto& iter : movie_result[movies_json_key].as_object()) + { + auto title = iter.second[U("title")].as_string(); + auto searchStr = title + U(" ") + year + U(" new movie poster"); + poster_tasks.push_back(get_pictures(searchStr, U("1"))); + movie_list.push_back(title); + } + + pplx::when_all(poster_tasks.begin(), poster_tasks.end()).wait(); + json::value resp_data = json::value::object(); + + for (unsigned int i = 0; i < poster_tasks.size(); i++) + { + auto jval = poster_tasks[i].get(); + auto poster_url = jval.as_array().begin()[0]; + movie_result[movies_json_key][i][U("poster")] = poster_url; + } + } + catch (...) { - auto jval = poster_tasks[i].get(); - auto poster_url = jval.as_array().begin()[0]; - movie_result[movies_json_key][i][U("poster")] = poster_url; + // Ignore any failure in fetching movie posters. Just return + // the movie data to the client. } - } - catch(...) - { - // Ignore any failure in fetching movie posters. Just return - // the movie data to the client. - } - return pplx::task_from_result(movie_result); - }).then([=](pplx::task t) - { - return handle_exception(t, movies_json_key); - }); + return pplx::task_from_result(movie_result); + }) + .then([=](pplx::task t) { return handle_exception(t, movies_json_key); }); } bool CasaLens::is_number(const std::string& s) { - return !s.empty() && std::find_if(s.begin(), - s.end(), [](char c) { return !std::isdigit(c, std::locale()); }) == s.end(); + return !s.empty() && + std::find_if(s.begin(), s.end(), [](char c) { return !std::isdigit(c, std::locale()); }) == s.end(); } void CasaLens::fetch_data(http_request message, const std::wstring& postal_code, const std::wstring& location) @@ -370,7 +360,7 @@ void CasaLens::fetch_data(http_request message, const std::wstring& postal_code, pplx::when_all(tasks.begin(), tasks.end()).wait(); resp_data = json::value::object(); - for(auto& iter:tasks) + for (auto& iter : tasks) { auto jval = iter.get(); auto key = jval.as_object().begin()->first; @@ -385,7 +375,7 @@ void CasaLens::fetch_data(http_request message, const std::wstring& postal_code, // Reply with the aggregated JSON data message.reply(status_codes::OK, resp_data).then([](pplx::task t) { handle_error(t); }); } - catch(...) + catch (...) { message.reply(status_codes::InternalError).then([](pplx::task t) { handle_error(t); }); } @@ -394,7 +384,8 @@ void CasaLens::fetch_data(http_request message, const std::wstring& postal_code, // Check if the input text is a number or string. // If string => city name, use bing maps API to obtain the postal code for that city // number => postal code, use google maps API to obtain city name (location data) for that postal code. -// then call fetch_data to query different services, aggregate movie, images, events, weather etc for that city and respond to the request. +// then call fetch_data to query different services, aggregate movie, images, events, weather etc for that city and +// respond to the request. void CasaLens::get_data(http_request message, const std::wstring& input_text) { if (!is_number(utility::conversions::to_utf8string(input_text))) @@ -405,36 +396,34 @@ void CasaLens::get_data(http_request message, const std::wstring& input_text) maps_builder.append_query(casalens_creds::bmaps_keyname, casalens_creds::bmaps_key); auto s = maps_builder.to_string(); http_client bing_client(bing_maps_url); - bing_client.request(methods::GET, s).then([=](http_response resp) - { - return resp.extract_json(); - }).then([=](json::value maps_result) mutable - { - auto coordinates = maps_result[U("resourceSets")][0][U("resources")][0][U("point")]; - auto lattitude = coordinates[U("coordinates")][0].serialize(); - auto longitude = coordinates[U("coordinates")][1].serialize(); - uri_builder ub; - ub.append_path(lattitude + U(",") + longitude).append_query(casalens_creds::bmaps_keyname, casalens_creds::bmaps_key); - auto s2 = ub.to_string(); - return bing_client.request(methods::GET, s2); - }).then([](http_response resp) - { - return resp.extract_json(); - }).then([=](json::value maps_result) - { - auto postal_code = maps_result[U("resourceSets")][0][U("resources")][0][U("address")][U("postalCode")].as_string(); - fetch_data(message, postal_code, input_text); - }).then([=](pplx::task t) - { - try - { - t.get(); - } - catch(...) - { - message.reply(status_codes::InternalError, U("Failed to fetch the postal code")); - } - }); + bing_client.request(methods::GET, s) + .then([=](http_response resp) { return resp.extract_json(); }) + .then([=](json::value maps_result) mutable { + auto coordinates = maps_result[U("resourceSets")][0][U("resources")][0][U("point")]; + auto lattitude = coordinates[U("coordinates")][0].serialize(); + auto longitude = coordinates[U("coordinates")][1].serialize(); + uri_builder ub; + ub.append_path(lattitude + U(",") + longitude) + .append_query(casalens_creds::bmaps_keyname, casalens_creds::bmaps_key); + auto s2 = ub.to_string(); + return bing_client.request(methods::GET, s2); + }) + .then([](http_response resp) { return resp.extract_json(); }) + .then([=](json::value maps_result) { + auto postal_code = + maps_result[U("resourceSets")][0][U("resources")][0][U("address")][U("postalCode")].as_string(); + fetch_data(message, postal_code, input_text); + }) + .then([=](pplx::task t) { + try + { + t.get(); + } + catch (...) + { + message.reply(status_codes::InternalError, U("Failed to fetch the postal code")); + } + }); } else // get location from postal code { @@ -444,24 +433,22 @@ void CasaLens::get_data(http_request message, const std::wstring& input_text) ub.append_query(U("address"), input_text); ub.append_query(U("sensor"), U("false")); - client.request(methods::GET, ub.to_string()).then([](http_response resp) - { - return resp.extract_json(); - }).then([=](json::value jval) - { - auto locationstr = jval[U("results")][0][U("address_components")][1][U("long_name")].as_string(); - fetch_data(message, input_text, locationstr); - }).then([=](pplx::task t) - { - try - { - t.get(); - } - catch(...) - { - message.reply(status_codes::InternalError, U("Failed to fetch the location from postal code")); - } - }); + client.request(methods::GET, ub.to_string()) + .then([](http_response resp) { return resp.extract_json(); }) + .then([=](json::value jval) { + auto locationstr = jval[U("results")][0][U("address_components")][1][U("long_name")].as_string(); + fetch_data(message, input_text, locationstr); + }) + .then([=](pplx::task t) { + try + { + t.get(); + } + catch (...) + { + message.reply(status_codes::InternalError, U("Failed to fetch the location from postal code")); + } + }); } return; } diff --git a/Release/samples/CasaLens/stdafx.cpp b/Release/samples/CasaLens/stdafx.cpp index 96f92dea02..abaab743eb 100644 --- a/Release/samples/CasaLens/stdafx.cpp +++ b/Release/samples/CasaLens/stdafx.cpp @@ -1,12 +1,12 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.cpp -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.cpp + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" diff --git a/Release/samples/CasaLens/stdafx.h b/Release/samples/CasaLens/stdafx.h index 7b1debc1db..99ebd10aa2 100644 --- a/Release/samples/CasaLens/stdafx.h +++ b/Release/samples/CasaLens/stdafx.h @@ -1,22 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h : include file for standard system include files, -* or project specific include files that are used frequently, but -* are changed infrequently -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.h : include file for standard system include files, + * or project specific include files that are used frequently, but + * are changed infrequently + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once +#include "cpprest/http_client.h" +#include +#include #include +#include #include -#include #include -#include -#include -#include "cpprest/http_client.h" diff --git a/Release/samples/FacebookDemo/App.xaml b/Release/samples/FacebookDemo/App.xaml index fa7eb1060b..d68af66203 100644 --- a/Release/samples/FacebookDemo/App.xaml +++ b/Release/samples/FacebookDemo/App.xaml @@ -2,11 +2,11 @@ Copyright (C) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. - =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ App.xaml - Default application xaml file from blank project. - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- --> - + - diff --git a/Release/samples/FacebookDemo/App.xaml.cpp b/Release/samples/FacebookDemo/App.xaml.cpp index c9fe47f1bc..c458f9094e 100644 --- a/Release/samples/FacebookDemo/App.xaml.cpp +++ b/Release/samples/FacebookDemo/App.xaml.cpp @@ -1,14 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* App.xaml.cpp - Implementation of the App class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * App.xaml.cpp - Implementation of the App class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "pch.h" + #include "MainPage.xaml.h" using namespace FacebookDemo; @@ -35,8 +36,8 @@ using namespace Windows::UI::Xaml::Navigation; /// App::App() { - InitializeComponent(); - Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); + InitializeComponent(); + Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); } /// @@ -45,55 +46,54 @@ App::App() /// search results, and so forth. /// /// Details about the launch request and process. -void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args) +void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ args) { - auto rootFrame = dynamic_cast(Window::Current->Content); - - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (rootFrame == nullptr) - { - // Create a Frame to act as the navigation context and associate it with - // a SuspensionManager key - rootFrame = ref new Frame(); + auto rootFrame = dynamic_cast(Window::Current->Content); - if (args->PreviousExecutionState == ApplicationExecutionState::Terminated) - { - // TODO: Restore the saved session state only when appropriate, scheduling the - // final launch steps after the restore is complete + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == nullptr) + { + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + rootFrame = ref new Frame(); - } + if (args->PreviousExecutionState == ApplicationExecutionState::Terminated) + { + // TODO: Restore the saved session state only when appropriate, scheduling the + // final launch steps after the restore is complete + } - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) - { - throw ref new FailureException("Failed to create initial page"); - } - } - // Place the frame in the current Window - Window::Current->Content = rootFrame; - // Ensure the current window is active - Window::Current->Activate(); - } - else - { - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) - { - throw ref new FailureException("Failed to create initial page"); - } - } - // Ensure the current window is active - Window::Current->Activate(); - } + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) + { + throw ref new FailureException("Failed to create initial page"); + } + } + // Place the frame in the current Window + Window::Current->Content = rootFrame; + // Ensure the current window is active + Window::Current->Activate(); + } + else + { + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) + { + throw ref new FailureException("Failed to create initial page"); + } + } + // Ensure the current window is active + Window::Current->Activate(); + } } /// @@ -103,10 +103,10 @@ void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEvent /// /// The source of the suspend request. /// Details about the suspend request. -void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) +void App::OnSuspending(Object ^ sender, SuspendingEventArgs ^ e) { - (void) sender; // Unused parameter - (void) e; // Unused parameter + (void)sender; // Unused parameter + (void)e; // Unused parameter - //TODO: Save application state and stop any background activity + // TODO: Save application state and stop any background activity } diff --git a/Release/samples/FacebookDemo/App.xaml.h b/Release/samples/FacebookDemo/App.xaml.h index fba3ffa10e..45afa68298 100644 --- a/Release/samples/FacebookDemo/App.xaml.h +++ b/Release/samples/FacebookDemo/App.xaml.h @@ -1,29 +1,29 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* App.xaml.h - Declaration of the App class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * App.xaml.h - Declaration of the App class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "App.g.h" namespace FacebookDemo { - /// - /// Provides application-specific behavior to supplement the default Application class. - /// - ref class App sealed - { - public: - App(); - virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args) override; +/// +/// Provides application-specific behavior to supplement the default Application class. +/// +ref class App sealed +{ +public: + App(); + virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ args) override; - private: - void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); - }; -} +private: + void OnSuspending(Platform::Object ^ sender, Windows::ApplicationModel::SuspendingEventArgs ^ e); +}; +} // namespace FacebookDemo diff --git a/Release/samples/FacebookDemo/Common/StandardStyles.xaml b/Release/samples/FacebookDemo/Common/StandardStyles.xaml index 7884dbfa79..2bde471967 100644 --- a/Release/samples/FacebookDemo/Common/StandardStyles.xaml +++ b/Release/samples/FacebookDemo/Common/StandardStyles.xaml @@ -2,7 +2,7 @@ Copyright (C) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. - =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ StandardStyles.xaml This file contains XAML styles that simplify application development. @@ -12,7 +12,7 @@ does not build, or that will not build once additional pages are added. If variations on these styles are desired it is recommended that you copy the content under a new name and modify your private copy. - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- --> - + - diff --git a/Release/samples/FacebookDemo/Facebook.cpp b/Release/samples/FacebookDemo/Facebook.cpp index e6013ab585..978996809b 100644 --- a/Release/samples/FacebookDemo/Facebook.cpp +++ b/Release/samples/FacebookDemo/Facebook.cpp @@ -1,16 +1,17 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Facebook.cpp - Implementation file for simple facebook client. -* Note: this implementation will not work until you replace the placeholder -* strings below with tokens obtained from facebook. -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Facebook.cpp - Implementation file for simple facebook client. + * Note: this implementation will not work until you replace the placeholder + * strings below with tokens obtained from facebook. + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "pch.h" + #include "facebook.h" using namespace pplx; @@ -28,109 +29,110 @@ const std::wstring application_token(L"insert your application token"); facebook_client& facebook_client::instance() { - static facebook_client c; - return c; + static facebook_client c; + return c; } pplx::task facebook_client::login(std::wstring scopes) { - // Look in the Local Settings for previously-stored login credentials - auto ls = ApplicationData::Current->LocalSettings->CreateContainer("LoginDetailsCache", - ApplicationDataCreateDisposition::Always); - - if(ls->Values->HasKey("facebookToken")) { - token_ = dynamic_cast(ls->Values->Lookup("facebookToken"))->Data(); - } - - if(!token_.empty()) { - // Check if the token is still valid - using namespace http; - - uri_builder tokendbg_uri(L"/debug_token"); - tokendbg_uri.append_query(L"input_token", token_); - tokendbg_uri.append_query(L"access_token", application_token); - - http_request request(methods::GET); - request.set_request_uri(tokendbg_uri.to_string()); - request.headers().add(header_names::accept, L"application/json"); - - return raw_client.request(request) - .then([](http_response response){ - return response.extract_json(); - }).then([=](json::value v) -> task { - auto obj = v[L"data"]; - - if(obj[L"is_valid"].as_bool()) { - // Currently cached access token is valid - signed_in = true; - return create_task([](){}); // Return an empty task to match the function's return value - } - - // If the token was invalid, go through full login - return full_login(scopes); - }, task_continuation_context::use_current()); - } - - // If no token was found, go through full login - return full_login(scopes); + // Look in the Local Settings for previously-stored login credentials + auto ls = ApplicationData::Current->LocalSettings->CreateContainer("LoginDetailsCache", + ApplicationDataCreateDisposition::Always); + + if (ls->Values->HasKey("facebookToken")) + { + token_ = dynamic_cast(ls->Values->Lookup("facebookToken"))->Data(); + } + + if (!token_.empty()) + { + // Check if the token is still valid + using namespace http; + + uri_builder tokendbg_uri(L"/debug_token"); + tokendbg_uri.append_query(L"input_token", token_); + tokendbg_uri.append_query(L"access_token", application_token); + + http_request request(methods::GET); + request.set_request_uri(tokendbg_uri.to_string()); + request.headers().add(header_names::accept, L"application/json"); + + return raw_client.request(request) + .then([](http_response response) { return response.extract_json(); }) + .then( + [=](json::value v) -> task { + auto obj = v[L"data"]; + + if (obj[L"is_valid"].as_bool()) + { + // Currently cached access token is valid + signed_in = true; + return create_task([]() {}); // Return an empty task to match the function's return value + } + + // If the token was invalid, go through full login + return full_login(scopes); + }, + task_continuation_context::use_current()); + } + + // If no token was found, go through full login + return full_login(scopes); } -pplx::task facebook_client::full_login(std::wstring scopes) +pplx::task facebook_client::full_login(std::wstring scopes) { - // Create uri for OAuth login on Facebook - http::uri_builder login_uri(L"https://www.facebook.com/dialog/oauth"); - login_uri.append_query(L"client_id", application_id); // App id - login_uri.append_query(L"redirect_uri", L"https://www.facebook.com/connect/login_success.html"); - login_uri.append_query(L"scope", scopes); - login_uri.append_query(L"display", L"popup"); - login_uri.append_query(L"response_type", L"token"); - - return create_task(WebAuthenticationBroker::AuthenticateAsync( - WebAuthenticationOptions::None, ref new Uri(ref new String(login_uri.to_string().c_str())), - ref new Uri("https://www.facebook.com/connect/login_success.html"))) - .then([=](WebAuthenticationResult^ result) { - if(result->ResponseStatus == WebAuthenticationStatus::Success) - { - signed_in = true; - - std::wstring response(result->ResponseData->Data()); // Save authentication token - auto start = response.find(L"access_token="); - start += 13; - auto end = response.find('&'); - - token_ = response.substr(start, end-start); - - // Add token to Local Settings for future login attempts - auto ls = ApplicationData::Current->LocalSettings->CreateContainer("LoginDetailsCache", - ApplicationDataCreateDisposition::Always); - - ls->Values->Insert("facebookToken", ref new String(token_.c_str())); - } - }); + // Create uri for OAuth login on Facebook + http::uri_builder login_uri(L"https://www.facebook.com/dialog/oauth"); + login_uri.append_query(L"client_id", application_id); // App id + login_uri.append_query(L"redirect_uri", L"https://www.facebook.com/connect/login_success.html"); + login_uri.append_query(L"scope", scopes); + login_uri.append_query(L"display", L"popup"); + login_uri.append_query(L"response_type", L"token"); + + return create_task(WebAuthenticationBroker::AuthenticateAsync( + WebAuthenticationOptions::None, + ref new Uri(ref new String(login_uri.to_string().c_str())), + ref new Uri("https://www.facebook.com/connect/login_success.html"))) + .then([=](WebAuthenticationResult ^ result) { + if (result->ResponseStatus == WebAuthenticationStatus::Success) + { + signed_in = true; + + std::wstring response(result->ResponseData->Data()); // Save authentication token + auto start = response.find(L"access_token="); + start += 13; + auto end = response.find('&'); + + token_ = response.substr(start, end - start); + + // Add token to Local Settings for future login attempts + auto ls = ApplicationData::Current->LocalSettings->CreateContainer( + "LoginDetailsCache", ApplicationDataCreateDisposition::Always); + + ls->Values->Insert("facebookToken", ref new String(token_.c_str())); + } + }); } task facebook_client::get(std::wstring path) { - using namespace http; - - http_request request(methods::GET); + using namespace http; + + http_request request(methods::GET); - request.set_request_uri(base_uri().append_path(path).to_uri()); - request.headers().add(header_names::accept, L"application/json"); + request.set_request_uri(base_uri().append_path(path).to_uri()); + request.headers().add(header_names::accept, L"application/json"); - return raw_client.request(request) - .then([](http_response response) { - return response.extract_json(); - }); + return raw_client.request(request).then([](http_response response) { return response.extract_json(); }); } http::uri_builder facebook_client::base_uri(bool absolute) { - http::uri_builder ret; + http::uri_builder ret; - if(absolute) - ret.set_path(L"https://graph.facebook.com"); + if (absolute) ret.set_path(L"https://graph.facebook.com"); - ret.append_query(L"access_token", token_); - return ret; -} \ No newline at end of file + ret.append_query(L"access_token", token_); + return ret; +} diff --git a/Release/samples/FacebookDemo/Facebook.h b/Release/samples/FacebookDemo/Facebook.h index ecc41765b3..7da645e447 100644 --- a/Release/samples/FacebookDemo/Facebook.h +++ b/Release/samples/FacebookDemo/Facebook.h @@ -1,33 +1,32 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Facebook.h - Simple client for connecting to facebook. See blog post -* at http://aka.ms/FacebookCppRest for a detailed walkthrough of this sample -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Facebook.h - Simple client for connecting to facebook. See blog post + * at http://aka.ms/FacebookCppRest for a detailed walkthrough of this sample + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include #include +#include -class facebook_client { +class facebook_client +{ public: - static facebook_client& instance(); // Singleton - pplx::task login(std::wstring scopes); - pplx::task get(std::wstring path); - web::http::uri_builder base_uri(bool absolute = false); + static facebook_client& instance(); // Singleton + pplx::task login(std::wstring scopes); + pplx::task get(std::wstring path); + web::http::uri_builder base_uri(bool absolute = false); private: - facebook_client(): - raw_client(L"https://graph.facebook.com/"), - signed_in(false) {} + facebook_client() : raw_client(L"https://graph.facebook.com/"), signed_in(false) {} - pplx::task full_login(std::wstring scopes); + pplx::task full_login(std::wstring scopes); - std::wstring token_; - bool signed_in; - web::http::client::http_client raw_client; + std::wstring token_; + bool signed_in; + web::http::client::http_client raw_client; }; diff --git a/Release/samples/FacebookDemo/MainPage.xaml b/Release/samples/FacebookDemo/MainPage.xaml index 4547d63238..ab036dcb9b 100644 --- a/Release/samples/FacebookDemo/MainPage.xaml +++ b/Release/samples/FacebookDemo/MainPage.xaml @@ -2,13 +2,13 @@ Copyright (C) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. - =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ MainPage.xaml - Primary application page. Contains two buttons for logging into and fetching albums from Facebook, and a GridView - control for displaying the downloaded album data. - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ---> - + control for displaying the downloaded album data. + =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +--> + + #include "MainPage.xaml.h" + #include "Facebook.h" +#include using namespace FacebookDemo; @@ -28,77 +30,70 @@ using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Navigation; -MainPage::MainPage() -{ - InitializeComponent(); -} +MainPage::MainPage() { InitializeComponent(); } /// /// Invoked when this page is about to be displayed in a Frame. /// /// Event data that describes how this page was reached. The Parameter /// property is typically used to configure the page. -void MainPage::OnNavigatedTo(NavigationEventArgs^ e) +void MainPage::OnNavigatedTo(NavigationEventArgs ^ e) { - (void) e; // Unused parameter + (void)e; // Unused parameter } -void MainPage::LoginButton_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void MainPage::LoginButton_Click_1(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { - LoginButton->IsEnabled = false; // Disable button to prevent double-login + LoginButton->IsEnabled = false; // Disable button to prevent double-login - facebook_client::instance().login(L"user_photos") - .then([=](){ - AlbumButton->IsEnabled = true; - }, pplx::task_continuation_context::use_current()); + facebook_client::instance() + .login(L"user_photos") + .then([=]() { AlbumButton->IsEnabled = true; }, pplx::task_continuation_context::use_current()); } - -void MainPage::AlbumButton_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void MainPage::AlbumButton_Click_1(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { - using namespace pplx; - AlbumButton->IsEnabled = false; - - facebook_client::instance().get(L"/me/albums") - .then([](web::json::value v){ - web::json::object& obj = v.as_object(); - std::vector albums; - - for(auto& elem : obj[L"data"].as_array()){ - albums.push_back(ref new FacebookAlbum( - elem[L"name"].as_string(), - elem[L"count"].as_integer(), - elem[L"id"].as_string(), - elem[L"cover_photo"].as_string() - )); - } - - return task_from_result(std::move(albums)); - }).then([=](std::vector albums){ - AlbumGrid->ItemsSource = ref new Vector(std::move(albums)); - }, task_continuation_context::use_current()); + using namespace pplx; + AlbumButton->IsEnabled = false; + + facebook_client::instance() + .get(L"/me/albums") + .then([](web::json::value v) { + web::json::object& obj = v.as_object(); + std::vector albums; + + for (auto& elem : obj[L"data"].as_array()) + { + albums.push_back(ref new FacebookAlbum(elem[L"name"].as_string(), + elem[L"count"].as_integer(), + elem[L"id"].as_string(), + elem[L"cover_photo"].as_string())); + } + + return task_from_result(std::move(albums)); + }) + .then( + [=](std::vector albums) { + AlbumGrid->ItemsSource = ref new Vector(std::move(albums)); + }, + task_continuation_context::use_current()); } -String^ FacebookAlbum::Title::get() -{ - return ref new String(title_.c_str()); -} +String ^ FacebookAlbum::Title::get() { return ref new String(title_.c_str()); } -int FacebookAlbum::Count::get() -{ - return count_; -} +int FacebookAlbum::Count::get() { return count_; } -ImageSource^ FacebookAlbum::Preview::get() +ImageSource ^ FacebookAlbum::Preview::get() { - if(preview_ == nullptr) { - auto preview_uri = facebook_client::instance().base_uri(true); + if (preview_ == nullptr) + { + auto preview_uri = facebook_client::instance().base_uri(true); - preview_uri.append_path(photo_id_); - preview_uri.append_path(L"/picture"); + preview_uri.append_path(photo_id_); + preview_uri.append_path(L"/picture"); - preview_ = ref new Imaging::BitmapImage(ref new Uri(StringReference(preview_uri.to_string().c_str()))); - } + preview_ = ref new Imaging::BitmapImage(ref new Uri(StringReference(preview_uri.to_string().c_str()))); + } - return preview_; + return preview_; } diff --git a/Release/samples/FacebookDemo/MainPage.xaml.h b/Release/samples/FacebookDemo/MainPage.xaml.h index 298d57f6f3..aaaf2e9330 100644 --- a/Release/samples/FacebookDemo/MainPage.xaml.h +++ b/Release/samples/FacebookDemo/MainPage.xaml.h @@ -2,11 +2,11 @@ * Copyright (C) Microsoft. All rights reserved. * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * MainPage.xaml.h - Declaration of the MainPage class. Also includes * the declaration for the FacebookAlbum class that the GridView databinds to. -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #pragma once @@ -50,7 +50,7 @@ namespace FacebookDemo property Windows::UI::Xaml::Media::ImageSource^ Preview { Windows::UI::Xaml::Media::ImageSource^ get(); } - + private: std::wstring id_; std::wstring title_; diff --git a/Release/samples/FacebookDemo/pch.cpp b/Release/samples/FacebookDemo/pch.cpp index 3d0d44a00d..bfbd45c828 100644 --- a/Release/samples/FacebookDemo/pch.cpp +++ b/Release/samples/FacebookDemo/pch.cpp @@ -1,11 +1,11 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* pch.cpp - Source file to generate pre-compiled header. -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * pch.cpp - Source file to generate pre-compiled header. + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "pch.h" diff --git a/Release/samples/FacebookDemo/pch.h b/Release/samples/FacebookDemo/pch.h index 16128d2415..b81db69294 100644 --- a/Release/samples/FacebookDemo/pch.h +++ b/Release/samples/FacebookDemo/pch.h @@ -1,14 +1,14 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* pch.h - Pre-compiled header standard include file -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * pch.h - Pre-compiled header standard include file + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include #include "App.xaml.h" +#include diff --git a/Release/samples/OAuth2Live/App.xaml.cpp b/Release/samples/OAuth2Live/App.xaml.cpp index 5c1b548905..853f6eec1a 100644 --- a/Release/samples/OAuth2Live/App.xaml.cpp +++ b/Release/samples/OAuth2Live/App.xaml.cpp @@ -4,6 +4,7 @@ // #include "pch.h" + #include "MainPage.xaml.h" using namespace OAuth2Live; @@ -30,8 +31,8 @@ using namespace Windows::UI::Xaml::Navigation; /// App::App() { - InitializeComponent(); - Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); + InitializeComponent(); + Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); } /// @@ -40,54 +41,54 @@ App::App() /// search results, and so forth. /// /// Details about the launch request and process. -void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args) +void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ args) { - auto rootFrame = dynamic_cast(Window::Current->Content); + auto rootFrame = dynamic_cast(Window::Current->Content); - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (rootFrame == nullptr) - { - // Create a Frame to act as the navigation context and associate it with - // a SuspensionManager key - rootFrame = ref new Frame(); + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == nullptr) + { + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + rootFrame = ref new Frame(); - if (args->PreviousExecutionState == ApplicationExecutionState::Terminated) - { - // TODO: Restore the saved session state only when appropriate, scheduling the - // final launch steps after the restore is complete - } + if (args->PreviousExecutionState == ApplicationExecutionState::Terminated) + { + // TODO: Restore the saved session state only when appropriate, scheduling the + // final launch steps after the restore is complete + } - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) - { - throw ref new FailureException("Failed to create initial page"); - } - } - // Place the frame in the current Window - Window::Current->Content = rootFrame; - // Ensure the current window is active - Window::Current->Activate(); - } - else - { - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) - { - throw ref new FailureException("Failed to create initial page"); - } - } - // Ensure the current window is active - Window::Current->Activate(); - } + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) + { + throw ref new FailureException("Failed to create initial page"); + } + } + // Place the frame in the current Window + Window::Current->Content = rootFrame; + // Ensure the current window is active + Window::Current->Activate(); + } + else + { + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) + { + throw ref new FailureException("Failed to create initial page"); + } + } + // Ensure the current window is active + Window::Current->Activate(); + } } /// @@ -97,10 +98,10 @@ void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEvent /// /// The source of the suspend request. /// Details about the suspend request. -void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) +void App::OnSuspending(Object ^ sender, SuspendingEventArgs ^ e) { - (void) sender; // Unused parameter - (void) e; // Unused parameter + (void)sender; // Unused parameter + (void)e; // Unused parameter - //TODO: Save application state and stop any background activity + // TODO: Save application state and stop any background activity } diff --git a/Release/samples/OAuth2Live/App.xaml.h b/Release/samples/OAuth2Live/App.xaml.h index ff9f14753d..1875325ad1 100644 --- a/Release/samples/OAuth2Live/App.xaml.h +++ b/Release/samples/OAuth2Live/App.xaml.h @@ -9,16 +9,16 @@ namespace OAuth2Live { - /// - /// Provides application-specific behavior to supplement the default Application class. - /// - ref class App sealed - { - public: - App(); - virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args) override; +/// +/// Provides application-specific behavior to supplement the default Application class. +/// +ref class App sealed +{ +public: + App(); + virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ args) override; - private: - void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); - }; -} +private: + void OnSuspending(Platform::Object ^ sender, Windows::ApplicationModel::SuspendingEventArgs ^ e); +}; +} // namespace OAuth2Live diff --git a/Release/samples/OAuth2Live/MainPage.xaml.cpp b/Release/samples/OAuth2Live/MainPage.xaml.cpp index eac9a34d93..acdc7ba4e3 100644 --- a/Release/samples/OAuth2Live/MainPage.xaml.cpp +++ b/Release/samples/OAuth2Live/MainPage.xaml.cpp @@ -4,6 +4,7 @@ // #include "pch.h" + #include "MainPage.xaml.h" using namespace OAuth2Live; @@ -25,20 +26,18 @@ using namespace web::http; using namespace web::http::client; using namespace web::http::oauth2::experimental; -// -// NOTE: You must set this Live key and secret for app to work. // -static const utility::string_t s_live_key(U("")); +// NOTE: You must set this Live key and secret for app to work. +// +static const utility::string_t s_live_key(U("")); static const utility::string_t s_live_secret(U("")); - MainPage::MainPage() - : m_live_oauth2_config( - s_live_key, - s_live_secret, - L"https://login.live.com/oauth20_authorize.srf", - L"https://login.live.com/oauth20_token.srf", - L"https://login.live.com/oauth20_desktop.srf") + : m_live_oauth2_config(s_live_key, + s_live_secret, + L"https://login.live.com/oauth20_authorize.srf", + L"https://login.live.com/oauth20_token.srf", + L"https://login.live.com/oauth20_desktop.srf") { InitializeComponent(); } @@ -48,9 +47,9 @@ MainPage::MainPage() /// /// Event data that describes how this page was reached. The Parameter /// property is typically used to configure the page. -void MainPage::OnNavigatedTo(NavigationEventArgs^ e) +void MainPage::OnNavigatedTo(NavigationEventArgs ^ e) { - (void) e; // Unused parameter + (void)e; // Unused parameter } void OAuth2Live::MainPage::_UpdateButtonState() @@ -73,9 +72,9 @@ void OAuth2Live::MainPage::_GetToken() AccessToken->Text = ""; _UpdateButtonState(); - String^ authURI = ref new String(m_live_oauth2_config.build_authorization_uri(true).c_str()); + String ^ authURI = ref new String(m_live_oauth2_config.build_authorization_uri(true).c_str()); auto startURI = ref new Uri(authURI); - String^ redirectURI = ref new String(m_live_oauth2_config.redirect_uri().c_str()); + String ^ redirectURI = ref new String(m_live_oauth2_config.redirect_uri().c_str()); auto endURI = ref new Uri(redirectURI); try @@ -83,65 +82,70 @@ void OAuth2Live::MainPage::_GetToken() DebugArea->Text += "> Navigating WebAuthenticationBroker to " + authURI + "\n"; #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - WebAuthenticationBroker::AuthenticateAndContinue(startURI, endURI, nullptr, WebAuthenticationOptions::None); + WebAuthenticationBroker::AuthenticateAndContinue(startURI, endURI, nullptr, WebAuthenticationOptions::None); #else - concurrency::create_task(WebAuthenticationBroker::AuthenticateAsync(WebAuthenticationOptions::None, startURI, endURI)) - .then([this](WebAuthenticationResult^ result) - { - String^ statusString; + concurrency::create_task( + WebAuthenticationBroker::AuthenticateAsync(WebAuthenticationOptions::None, startURI, endURI)) + .then([this](WebAuthenticationResult ^ result) { + String ^ statusString; - DebugArea->Text += "< WebAuthenticationBroker returned: "; - switch (result->ResponseStatus) - { - case WebAuthenticationStatus::ErrorHttp: - { - DebugArea->Text += "ErrorHttp: " + result->ResponseErrorDetail + "\n"; - break; - } - case WebAuthenticationStatus::Success: + DebugArea->Text += "< WebAuthenticationBroker returned: "; + switch (result->ResponseStatus) { - DebugArea->Text += "Success\n"; - utility::string_t data = result->ResponseData->Data(); - DebugArea->Text += "Redirected URI:\n" + result->ResponseData + "\n"; - DebugArea->Text += "> Obtaining token using the redirected URI\n"; - m_live_oauth2_config.token_from_redirected_uri(data).then([this](pplx::task token_task) + case WebAuthenticationStatus::ErrorHttp: { - try - { - token_task.wait(); - DebugArea->Text += "< Got token\n"; - AccessToken->Text = ref new String(m_live_oauth2_config.token().access_token().c_str()); - } - catch (const oauth2_exception& e) - { - DebugArea->Text += "< Failed to get token\n"; - String^ error = ref new String(utility::conversions::to_string_t(e.what()).c_str()); - DebugArea->Text += "Error: " + error + "\n"; - } - }, pplx::task_continuation_context::use_current()); - break; - } - default: - case WebAuthenticationStatus::UserCancel: - { - DebugArea->Text += "UserCancel\n"; - break; + DebugArea->Text += "ErrorHttp: " + result->ResponseErrorDetail + "\n"; + break; + } + case WebAuthenticationStatus::Success: + { + DebugArea->Text += "Success\n"; + utility::string_t data = result->ResponseData->Data(); + DebugArea->Text += "Redirected URI:\n" + result->ResponseData + "\n"; + DebugArea->Text += "> Obtaining token using the redirected URI\n"; + m_live_oauth2_config.token_from_redirected_uri(data).then( + [this](pplx::task token_task) { + try + { + token_task.wait(); + DebugArea->Text += "< Got token\n"; + AccessToken->Text = + ref new String(m_live_oauth2_config.token().access_token().c_str()); + } + catch (const oauth2_exception& e) + { + DebugArea->Text += "< Failed to get token\n"; + String ^ error = + ref new String(utility::conversions::to_string_t(e.what()).c_str()); + DebugArea->Text += "Error: " + error + "\n"; + } + }, + pplx::task_continuation_context::use_current()); + break; + } + default: + case WebAuthenticationStatus::UserCancel: + { + DebugArea->Text += "UserCancel\n"; + break; + } } - } - }); + }); #endif } - catch (Exception^ ex) + catch (Exception ^ ex) { DebugArea->Text += "< Error launching WebAuthenticationBroker: " + ex->Message + "\n"; } } -void OAuth2Live::MainPage::GetTokenButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) +void OAuth2Live::MainPage::GetTokenButtonClick(Platform::Object ^ sender, + Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e) { if (m_live_oauth2_config.client_key().empty() || m_live_oauth2_config.client_secret().empty()) { - DebugArea->Text += "Error: Cannot get token because Live app key or secret is empty. Please see instructions.\n"; + DebugArea->Text += + "Error: Cannot get token because Live app key or secret is empty. Please see instructions.\n"; } else { @@ -149,52 +153,50 @@ void OAuth2Live::MainPage::GetTokenButtonClick(Platform::Object^ sender, Windows } } -void OAuth2Live::MainPage::GetInfoButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) +void OAuth2Live::MainPage::GetInfoButtonClick(Platform::Object ^ sender, + Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e) { DebugArea->Text += "> Get user info\n"; m_live_client->request(methods::GET, U("me")) - .then([](http_response resp) - { - return resp.extract_json(); - }) - .then([this](web::json::value j) -> void - { - String^ json_code = ref new String(j.serialize().c_str()); - DebugArea->Text += "< User info (JSON): " + json_code + "\n"; - }, pplx::task_continuation_context::use_current()); + .then([](http_response resp) { return resp.extract_json(); }) + .then( + [this](web::json::value j) -> void { + String ^ json_code = ref new String(j.serialize().c_str()); + DebugArea->Text += "< User info (JSON): " + json_code + "\n"; + }, + pplx::task_continuation_context::use_current()); } -void OAuth2Live::MainPage::GetContactsButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) +void OAuth2Live::MainPage::GetContactsButtonClick(Platform::Object ^ sender, + Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e) { DebugArea->Text += "> Get user contacts\n"; m_live_client->request(methods::GET, U("me/contacts")) - .then([](http_response resp) - { - return resp.extract_json(); - }) - .then([this](web::json::value j) -> void - { - String^ json_code = ref new String(j.serialize().c_str()); - DebugArea->Text += "< User contacts (JSON): " + json_code + "\n"; - }, pplx::task_continuation_context::use_current()); + .then([](http_response resp) { return resp.extract_json(); }) + .then( + [this](web::json::value j) -> void { + String ^ json_code = ref new String(j.serialize().c_str()); + DebugArea->Text += "< User contacts (JSON): " + json_code + "\n"; + }, + pplx::task_continuation_context::use_current()); } -void OAuth2Live::MainPage::GetEventsButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) +void OAuth2Live::MainPage::GetEventsButtonClick(Platform::Object ^ sender, + Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e) { DebugArea->Text += "> Get user events\n"; m_live_client->request(methods::GET, U("me/events")) - .then([](http_response resp) - { - return resp.extract_json(); - }) - .then([this](web::json::value j) -> void - { - String^ json_code = ref new String(j.serialize().c_str()); - DebugArea->Text += "< User calendar events (JSON): " + json_code + "\n"; - }, pplx::task_continuation_context::use_current()); + .then([](http_response resp) { return resp.extract_json(); }) + .then( + [this](web::json::value j) -> void { + String ^ json_code = ref new String(j.serialize().c_str()); + DebugArea->Text += "< User calendar events (JSON): " + json_code + "\n"; + }, + pplx::task_continuation_context::use_current()); } -void OAuth2Live::MainPage::AccessTokenTextChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::TextChangedEventArgs^ e) +void OAuth2Live::MainPage::AccessTokenTextChanged(Platform::Object ^ sender, + Windows::UI::Xaml::Controls::TextChangedEventArgs ^ e) { http_client_config http_config; http_config.set_oauth2(m_live_oauth2_config); @@ -202,34 +204,34 @@ void OAuth2Live::MainPage::AccessTokenTextChanged(Platform::Object^ sender, Wind _UpdateButtonState(); } -void OAuth2Live::MainPage::ImplicitGrantUnchecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void OAuth2Live::MainPage::ImplicitGrantUnchecked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { m_live_oauth2_config.set_implicit_grant(false); } -void OAuth2Live::MainPage::ImplicitGrantChecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void OAuth2Live::MainPage::ImplicitGrantChecked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { m_live_oauth2_config.set_implicit_grant(true); } - -void OAuth2Live::MainPage::RefreshTokenButtonClick(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void OAuth2Live::MainPage::RefreshTokenButtonClick(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { DebugArea->Text += "> Refreshing token\n"; - m_live_oauth2_config.token_from_refresh().then([this](pplx::task refresh_task) - { - try - { - refresh_task.wait(); - DebugArea->Text += "< Got token\n"; - AccessToken->Text = ref new String(m_live_oauth2_config.token().access_token().c_str()); - } - catch (const oauth2_exception& e) - { - DebugArea->Text += "< Failed to get token\n"; - String^ error = ref new String(utility::conversions::to_string_t(e.what()).c_str()); - DebugArea->Text += "Error: " + error + "\n"; - } - }, pplx::task_continuation_context::use_current()); + m_live_oauth2_config.token_from_refresh().then( + [this](pplx::task refresh_task) { + try + { + refresh_task.wait(); + DebugArea->Text += "< Got token\n"; + AccessToken->Text = ref new String(m_live_oauth2_config.token().access_token().c_str()); + } + catch (const oauth2_exception& e) + { + DebugArea->Text += "< Failed to get token\n"; + String ^ error = ref new String(utility::conversions::to_string_t(e.what()).c_str()); + DebugArea->Text += "Error: " + error + "\n"; + } + }, + pplx::task_continuation_context::use_current()); } diff --git a/Release/samples/OAuth2Live/MainPage.xaml.h b/Release/samples/OAuth2Live/MainPage.xaml.h index 4cc8abaf0a..1b4cbb4db6 100644 --- a/Release/samples/OAuth2Live/MainPage.xaml.h +++ b/Release/samples/OAuth2Live/MainPage.xaml.h @@ -12,32 +12,34 @@ using web::http::oauth2::experimental::oauth2_config; namespace OAuth2Live { - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - public ref class MainPage sealed - { - public: - MainPage(); - - protected: - virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; - private: - oauth2_config m_live_oauth2_config; - std::unique_ptr m_live_client; - - void _UpdateButtonState(); - void _GetToken(); - - void GetTokenButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e); - void RefreshTokenButtonClick(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void ImplicitGrantUnchecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void ImplicitGrantChecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - - void GetInfoButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e); - void GetContactsButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e); - void GetEventsButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e); - - void AccessTokenTextChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::TextChangedEventArgs^ e); - }; -} +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +public +ref class MainPage sealed +{ +public: + MainPage(); + +protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e) override; + +private: + oauth2_config m_live_oauth2_config; + std::unique_ptr m_live_client; + + void _UpdateButtonState(); + void _GetToken(); + + void GetTokenButtonClick(Platform::Object ^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e); + void RefreshTokenButtonClick(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + void ImplicitGrantUnchecked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + void ImplicitGrantChecked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + + void GetInfoButtonClick(Platform::Object ^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e); + void GetContactsButtonClick(Platform::Object ^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e); + void GetEventsButtonClick(Platform::Object ^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e); + + void AccessTokenTextChanged(Platform::Object ^ sender, Windows::UI::Xaml::Controls::TextChangedEventArgs ^ e); +}; +} // namespace OAuth2Live diff --git a/Release/samples/OAuth2Live/pch.h b/Release/samples/OAuth2Live/pch.h index 1ad8bcbd9f..8aae530e02 100644 --- a/Release/samples/OAuth2Live/pch.h +++ b/Release/samples/OAuth2Live/pch.h @@ -1,15 +1,15 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -****/ - -#pragma once - +/*** + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + ****/ + +#pragma once + +#include "App.xaml.h" +#include "MainPage.xaml.h" #include -#include -#include #include #include -#include "App.xaml.h" -#include "MainPage.xaml.h" +#include +#include diff --git a/Release/samples/Oauth1Client/Oauth1Client.cpp b/Release/samples/Oauth1Client/Oauth1Client.cpp index 8c27ef2f4e..da09fda29f 100644 --- a/Release/samples/Oauth1Client/Oauth1Client.cpp +++ b/Release/samples/Oauth1Client/Oauth1Client.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Oauth1Client.cpp : Defines the entry point for the console application -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Oauth1Client.cpp : Defines the entry point for the console application + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ /* @@ -26,17 +26,18 @@ Set following entry in the hosts file: 127.0.0.1 testhost.local */ -#include #include "cpprest/http_client.h" +#include #if defined(_WIN32) && !defined(__cplusplus_winrt) // Extra includes for Windows desktop. #include + #include #endif -#include "cpprest/http_listener.h" #include "cpprest/http_client.h" +#include "cpprest/http_listener.h" using namespace utility; using namespace web; @@ -81,31 +82,27 @@ static void open_browser(utility::string_t auth_uri) class oauth1_code_listener { public: - oauth1_code_listener( - uri listen_uri, - oauth1_config& config) : - m_listener(new http_listener(listen_uri)), - m_config(config) + oauth1_code_listener(uri listen_uri, oauth1_config& config) + : m_listener(new http_listener(listen_uri)), m_config(config) { - m_listener->support([this](http::http_request request) -> void - { + m_listener->support([this](http::http_request request) -> void { if (request.request_uri().path() == U("/") && request.request_uri().query() != U("")) { m_resplock.lock(); - m_config.token_from_redirected_uri(request.request_uri()).then([this,request](pplx::task token_task) -> void - { - try - { - token_task.wait(); - m_tce.set(true); - } - catch (const oauth1_exception& e) - { - ucout << "Error: " << e.what() << std::endl; - m_tce.set(false); - } - }); + m_config.token_from_redirected_uri(request.request_uri()) + .then([this, request](pplx::task token_task) -> void { + try + { + token_task.wait(); + m_tce.set(true); + } + catch (const oauth1_exception& e) + { + ucout << "Error: " << e.what() << std::endl; + m_tce.set(false); + } + }); request.reply(status_codes::OK, U("Ok.")); @@ -120,15 +117,9 @@ class oauth1_code_listener m_listener->open().wait(); } - ~oauth1_code_listener() - { - m_listener->close().wait(); - } + ~oauth1_code_listener() { m_listener->close().wait(); } - pplx::task listen_for_code() - { - return pplx::create_task(m_tce); - } + pplx::task listen_for_code() { return pplx::create_task(m_tce); } private: std::unique_ptr m_listener; @@ -144,22 +135,23 @@ class oauth1_session_sample { public: oauth1_session_sample(utility::string_t name, - utility::string_t consumer_key, - utility::string_t consumer_secret, - utility::string_t temp_endpoint, - utility::string_t auth_endpoint, - utility::string_t token_endpoint, - utility::string_t callback_uri) : - m_oauth1_config(consumer_key, - consumer_secret, - temp_endpoint, - auth_endpoint, - token_endpoint, - callback_uri, - oauth1_methods::hmac_sha1), - m_name(name), - m_listener(new oauth1_code_listener(callback_uri, m_oauth1_config)) - {} + utility::string_t consumer_key, + utility::string_t consumer_secret, + utility::string_t temp_endpoint, + utility::string_t auth_endpoint, + utility::string_t token_endpoint, + utility::string_t callback_uri) + : m_oauth1_config(consumer_key, + consumer_secret, + temp_endpoint, + auth_endpoint, + token_endpoint, + callback_uri, + oauth1_methods::hmac_sha1) + , m_name(name) + , m_listener(new oauth1_code_listener(callback_uri, m_oauth1_config)) + { + } void run() { @@ -183,7 +175,8 @@ class oauth1_session_sample } else { - ucout << "Skipped " << m_name.c_str() << " session sample because app key or secret is empty. Please see instructions." << std::endl; + ucout << "Skipped " << m_name.c_str() + << " session sample because app key or secret is empty. Please see instructions." << std::endl; } } @@ -198,7 +191,7 @@ class oauth1_session_sample } else { - return pplx::create_task([](){return false;}); + return pplx::create_task([]() { return false; }); } } @@ -222,7 +215,7 @@ class oauth1_session_sample open_browser(auth_uri); return true; } - catch (const oauth1_exception &e) + catch (const oauth1_exception& e) { ucout << "Error: " << e.what() << std::endl; return false; @@ -239,24 +232,25 @@ class oauth1_session_sample class linkedin_session_sample : public oauth1_session_sample { public: - linkedin_session_sample() : - oauth1_session_sample(U("LinkedIn"), - s_linkedin_key, - s_linkedin_secret, - U("https://api.linkedin.com/uas/oauth/requestToken"), - U("https://www.linkedin.com/uas/oauth/authenticate"), - U("https://api.linkedin.com/uas/oauth/accessToken"), - U("http://localhost:8888/")) - {} + linkedin_session_sample() + : oauth1_session_sample(U("LinkedIn"), + s_linkedin_key, + s_linkedin_secret, + U("https://api.linkedin.com/uas/oauth/requestToken"), + U("https://www.linkedin.com/uas/oauth/authenticate"), + U("https://api.linkedin.com/uas/oauth/accessToken"), + U("http://localhost:8888/")) + { + } protected: void run_internal() override { http_client api(U("https://api.linkedin.com/v1/people/"), m_http_config); ucout << "Requesting user information:" << std::endl; - ucout << "Information: " << api.request(methods::GET, U("~?format=json")).get().extract_json().get() << std::endl; + ucout << "Information: " << api.request(methods::GET, U("~?format=json")).get().extract_json().get() + << std::endl; } - }; // @@ -265,15 +259,16 @@ class linkedin_session_sample : public oauth1_session_sample class twitter_session_sample : public oauth1_session_sample { public: - twitter_session_sample() : - oauth1_session_sample(U("Twitter"), - s_twitter_key, - s_twitter_secret, - U("https://api.twitter.com/oauth/request_token"), - U("https://api.twitter.com/oauth/authorize"), - U("https://api.twitter.com/oauth/access_token"), - U("http://testhost.local:8890/")) - {} + twitter_session_sample() + : oauth1_session_sample(U("Twitter"), + s_twitter_key, + s_twitter_secret, + U("https://api.twitter.com/oauth/request_token"), + U("https://api.twitter.com/oauth/authorize"), + U("https://api.twitter.com/oauth/access_token"), + U("http://testhost.local:8890/")) + { + } protected: void run_internal() override @@ -284,11 +279,10 @@ class twitter_session_sample : public oauth1_session_sample } }; - #ifdef _WIN32 -int wmain(int argc, wchar_t *argv[]) +int wmain(int argc, wchar_t* argv[]) #else -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) #endif { ucout << "Running OAuth 1.0 client sample..." << std::endl; diff --git a/Release/samples/Oauth2Client/Oauth2Client.cpp b/Release/samples/Oauth2Client/Oauth2Client.cpp index 8d62b89cda..2d82a70f18 100644 --- a/Release/samples/Oauth2Client/Oauth2Client.cpp +++ b/Release/samples/Oauth2Client/Oauth2Client.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Oauth2Client.cpp : Defines the entry point for the console application -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Oauth2Client.cpp : Defines the entry point for the console application + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ /* @@ -26,17 +26,18 @@ Set following entry in the hosts file: 127.0.0.1 testhost.local */ -#include #include "cpprest/http_client.h" +#include #if defined(_WIN32) && !defined(__cplusplus_winrt) // Extra includes for Windows desktop. #include + #include #endif -#include "cpprest/http_listener.h" #include "cpprest/http_client.h" +#include "cpprest/http_listener.h" using namespace utility; using namespace web; @@ -84,31 +85,27 @@ static void open_browser(utility::string_t auth_uri) class oauth2_code_listener { public: - oauth2_code_listener( - uri listen_uri, - oauth2_config& config) : - m_listener(new http_listener(listen_uri)), - m_config(config) + oauth2_code_listener(uri listen_uri, oauth2_config& config) + : m_listener(new http_listener(listen_uri)), m_config(config) { - m_listener->support([this](http::http_request request) -> void - { + m_listener->support([this](http::http_request request) -> void { if (request.request_uri().path() == U("/") && request.request_uri().query() != U("")) { m_resplock.lock(); - m_config.token_from_redirected_uri(request.request_uri()).then([this,request](pplx::task token_task) -> void - { - try - { - token_task.wait(); - m_tce.set(true); - } - catch (const oauth2_exception& e) - { - ucout << "Error: " << e.what() << std::endl; - m_tce.set(false); - } - }); + m_config.token_from_redirected_uri(request.request_uri()) + .then([this, request](pplx::task token_task) -> void { + try + { + token_task.wait(); + m_tce.set(true); + } + catch (const oauth2_exception& e) + { + ucout << "Error: " << e.what() << std::endl; + m_tce.set(false); + } + }); request.reply(status_codes::OK, U("Ok.")); @@ -123,15 +120,9 @@ class oauth2_code_listener m_listener->open().wait(); } - ~oauth2_code_listener() - { - m_listener->close().wait(); - } + ~oauth2_code_listener() { m_listener->close().wait(); } - pplx::task listen_for_code() - { - return pplx::create_task(m_tce); - } + pplx::task listen_for_code() { return pplx::create_task(m_tce); } private: std::unique_ptr m_listener; @@ -147,19 +138,16 @@ class oauth2_session_sample { public: oauth2_session_sample(utility::string_t name, - utility::string_t client_key, - utility::string_t client_secret, - utility::string_t auth_endpoint, - utility::string_t token_endpoint, - utility::string_t redirect_uri) : - m_oauth2_config(client_key, - client_secret, - auth_endpoint, - token_endpoint, - redirect_uri), - m_name(name), - m_listener(new oauth2_code_listener(redirect_uri, m_oauth2_config)) - {} + utility::string_t client_key, + utility::string_t client_secret, + utility::string_t auth_endpoint, + utility::string_t token_endpoint, + utility::string_t redirect_uri) + : m_oauth2_config(client_key, client_secret, auth_endpoint, token_endpoint, redirect_uri) + , m_name(name) + , m_listener(new oauth2_code_listener(redirect_uri, m_oauth2_config)) + { + } void run() { @@ -183,7 +171,8 @@ class oauth2_session_sample } else { - ucout << "Skipped " << m_name.c_str() << " session sample because app key or secret is empty. Please see instructions." << std::endl; + ucout << "Skipped " << m_name.c_str() + << " session sample because app key or secret is empty. Please see instructions." << std::endl; } } @@ -223,13 +212,13 @@ class oauth2_session_sample class dropbox_session_sample : public oauth2_session_sample { public: - dropbox_session_sample() : - oauth2_session_sample(U("Dropbox"), - s_dropbox_key, - s_dropbox_secret, - U("https://www.dropbox.com/1/oauth2/authorize"), - U("https://api.dropbox.com/1/oauth2/token"), - U("http://localhost:8889/")) + dropbox_session_sample() + : oauth2_session_sample(U("Dropbox"), + s_dropbox_key, + s_dropbox_secret, + U("https://www.dropbox.com/1/oauth2/authorize"), + U("https://api.dropbox.com/1/oauth2/token"), + U("http://localhost:8889/")) { // Dropbox uses "default" OAuth 2.0 settings. } @@ -239,7 +228,8 @@ class dropbox_session_sample : public oauth2_session_sample { http_client api(U("https://api.dropbox.com/1/"), m_http_config); ucout << "Requesting account information:" << std::endl; - ucout << "Information: " << api.request(methods::GET, U("account/info")).get().extract_json().get() << std::endl; + ucout << "Information: " << api.request(methods::GET, U("account/info")).get().extract_json().get() + << std::endl; } }; @@ -249,13 +239,13 @@ class dropbox_session_sample : public oauth2_session_sample class linkedin_session_sample : public oauth2_session_sample { public: - linkedin_session_sample() : - oauth2_session_sample(U("LinkedIn"), - s_linkedin_key, - s_linkedin_secret, - U("https://www.linkedin.com/uas/oauth2/authorization"), - U("https://www.linkedin.com/uas/oauth2/accessToken"), - U("http://localhost:8888/")) + linkedin_session_sample() + : oauth2_session_sample(U("LinkedIn"), + s_linkedin_key, + s_linkedin_secret, + U("https://www.linkedin.com/uas/oauth2/authorization"), + U("https://www.linkedin.com/uas/oauth2/accessToken"), + U("http://localhost:8888/")) { // LinkedIn doesn't use bearer auth. m_oauth2_config.set_bearer_auth(false); @@ -270,9 +260,9 @@ class linkedin_session_sample : public oauth2_session_sample { http_client api(U("https://api.linkedin.com/v1/people/"), m_http_config); ucout << "Requesting account information:" << std::endl; - ucout << "Information: " << api.request(methods::GET, U("~?format=json")).get().extract_json().get() << std::endl; + ucout << "Information: " << api.request(methods::GET, U("~?format=json")).get().extract_json().get() + << std::endl; } - }; // @@ -281,13 +271,13 @@ class linkedin_session_sample : public oauth2_session_sample class live_session_sample : public oauth2_session_sample { public: - live_session_sample() : - oauth2_session_sample(U("Live"), - s_live_key, - s_live_secret, - U("https://login.live.com/oauth20_authorize.srf"), - U("https://login.live.com/oauth20_token.srf"), - U("http://testhost.local:8890/")) + live_session_sample() + : oauth2_session_sample(U("Live"), + s_live_key, + s_live_secret, + U("https://login.live.com/oauth20_authorize.srf"), + U("https://login.live.com/oauth20_token.srf"), + U("http://testhost.local:8890/")) { // Scope "wl.basic" allows fetching user information. m_oauth2_config.set_scope(U("wl.basic")); @@ -302,18 +292,17 @@ class live_session_sample : public oauth2_session_sample } }; - #ifdef _WIN32 -int wmain(int argc, wchar_t *argv[]) +int wmain(int argc, wchar_t* argv[]) #else -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) #endif { ucout << "Running OAuth 2.0 client sample..." << std::endl; linkedin_session_sample linkedin; - dropbox_session_sample dropbox; - live_session_sample live; + dropbox_session_sample dropbox; + live_session_sample live; linkedin.run(); dropbox.run(); diff --git a/Release/samples/SearchFile/searchfile.cpp b/Release/samples/SearchFile/searchfile.cpp index d2e0d71f37..dfcc38bc2c 100644 --- a/Release/samples/SearchFile/searchfile.cpp +++ b/Release/samples/SearchFile/searchfile.cpp @@ -1,17 +1,17 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* searchfile.cpp - Simple cmd line application that uses a variety of streams features to search a file, -* store the results, and write results back to a new file. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * searchfile.cpp - Simple cmd line application that uses a variety of streams features to search a file, + * store the results, and write results back to a new file. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ -#include "cpprest/filestream.h" #include "cpprest/containerstream.h" +#include "cpprest/filestream.h" #include "cpprest/producerconsumerstream.h" using namespace utility; @@ -23,17 +23,13 @@ using namespace concurrency::streams; pplx::task _do_while_iteration(std::function(void)> func) { pplx::task_completion_event ev; - func().then([=](bool guard) - { - ev.set(guard); - }); + func().then([=](bool guard) { ev.set(guard); }); return pplx::create_task(ev); } pplx::task _do_while_impl(std::function(void)> func) { - return _do_while_iteration(func).then([=](bool guard) -> pplx::task - { - if(guard) + return _do_while_iteration(func).then([=](bool guard) -> pplx::task { + if (guard) { return ::_do_while_impl(func); } @@ -45,18 +41,21 @@ pplx::task _do_while_impl(std::function(void)> func) } pplx::task do_while(std::function(void)> func) { - return _do_while_impl(func).then([](bool){}); + return _do_while_impl(func).then([](bool) {}); } /// /// Structure used to store individual line results. /// typedef std::vector matched_lines; -namespace Concurrency { namespace streams { +namespace Concurrency +{ +namespace streams +{ /// /// Parser implementation for 'matched_lines' type. /// -template +template class type_parser { public: @@ -64,115 +63,101 @@ class type_parser { basic_istream in(buffer); auto lines = std::make_shared(); - return do_while([=]() - { - container_buffer line; - return in.read_line(line).then([=](const size_t bytesRead) - { - if(bytesRead == 0 && in.is_eof()) - { - return false; - } - else - { - lines->push_back(std::move(line.collection())); - return true; - } - }); - }).then([=]() - { - return matched_lines(std::move(*lines)); - }); + return do_while([=]() { + container_buffer line; + return in.read_line(line).then([=](const size_t bytesRead) { + if (bytesRead == 0 && in.is_eof()) + { + return false; + } + else + { + lines->push_back(std::move(line.collection())); + return true; + } + }); + }) + .then([=]() { return matched_lines(std::move(*lines)); }); } }; -}} +} // namespace streams +} // namespace Concurrency /// -/// Function to create in data from a file and search for a given string writing all lines containing the string to memory_buffer. +/// Function to create in data from a file and search for a given string writing all lines containing the string to +/// memory_buffer. /// -static pplx::task find_matches_in_file(const string_t &fileName, const std::string &searchString, basic_ostream results) +static pplx::task find_matches_in_file(const string_t& fileName, + const std::string& searchString, + basic_ostream results) { - return file_stream::open_istream(fileName).then([=](basic_istream inFile) - { + return file_stream::open_istream(fileName).then([=](basic_istream inFile) { auto lineNumber = std::make_shared(1); - return ::do_while([=]() - { - container_buffer inLine; - return inFile.read_line(inLine).then([=](size_t bytesRead) - { - if(bytesRead == 0 && inFile.is_eof()) - { - return pplx::task_from_result(false); - } + return ::do_while([=]() { + container_buffer inLine; + return inFile.read_line(inLine).then([=](size_t bytesRead) { + if (bytesRead == 0 && inFile.is_eof()) + { + return pplx::task_from_result(false); + } - else if(inLine.collection().find(searchString) != std::string::npos) - { - results.print("line "); - results.print((*lineNumber)++); - return results.print(":").then([=](size_t) - { - container_buffer outLine(std::move(inLine.collection())); - return results.write(outLine, outLine.collection().size()); - }).then([=](size_t) - { - return results.print("\r\n"); - }).then([=](size_t) - { - return true; - }); - } + else if (inLine.collection().find(searchString) != std::string::npos) + { + results.print("line "); + results.print((*lineNumber)++); + return results.print(":") + .then([=](size_t) { + container_buffer outLine(std::move(inLine.collection())); + return results.write(outLine, outLine.collection().size()); + }) + .then([=](size_t) { return results.print("\r\n"); }) + .then([=](size_t) { return true; }); + } - else - { - ++(*lineNumber); - return pplx::task_from_result(true); - } + else + { + ++(*lineNumber); + return pplx::task_from_result(true); + } + }); + }) + .then([=]() { + // Close the file and results stream. + return inFile.close() && results.close(); }); - }).then([=]() - { - // Close the file and results stream. - return inFile.close() && results.close(); - }); }); } /// /// Function to write out results from matched_lines type to file /// -static pplx::task write_matches_to_file(const string_t &fileName, matched_lines results) +static pplx::task write_matches_to_file(const string_t& fileName, matched_lines results) { // Create a shared pointer to the matched_lines structure to copying repeatedly. auto sharedResults = std::make_shared(std::move(results)); - return file_stream::open_ostream(fileName, std::ios::trunc).then([=](basic_ostream outFile) - { + return file_stream::open_ostream(fileName, std::ios::trunc).then([=](basic_ostream outFile) { auto currentIndex = std::make_shared(0); - return ::do_while([=]() - { - if(*currentIndex >= sharedResults->size()) - { - return pplx::task_from_result(false); - } + return ::do_while([=]() { + if (*currentIndex >= sharedResults->size()) + { + return pplx::task_from_result(false); + } - container_buffer lineData((*sharedResults)[(*currentIndex)++]); - outFile.write(lineData, lineData.collection().size()); - return outFile.print("\r\n").then([](size_t) - { - return true; - }); - }).then([=]() - { - return outFile.close(); - }); + container_buffer lineData((*sharedResults)[(*currentIndex)++]); + outFile.write(lineData, lineData.collection().size()); + return outFile.print("\r\n").then([](size_t) { return true; }); + }) + .then([=]() { return outFile.close(); }); }); } #ifdef _WIN32 -int wmain(int argc, wchar_t *args[]) +int wmain(int argc, wchar_t* args[]) #else -int main(int argc, char *args[]) +int main(int argc, char* args[]) #endif { - if(argc != 4) + if (argc != 4) { printf("Usage: SearchFile.exe input_file search_string output_file\n"); return -1; @@ -181,26 +166,22 @@ int main(int argc, char *args[]) const std::string searchString = utility::conversions::to_utf8string(args[2]); const string_t outFileName = args[3]; producer_consumer_buffer lineResultsBuffer; - + // Find all matches in file. basic_ostream outLineResults(lineResultsBuffer); find_matches_in_file(inFileName, searchString, outLineResults) - // Write matches into custom data structure. - .then([&]() - { - basic_istream inLineResults(lineResultsBuffer); - return inLineResults.extract(); - }) - - // Write out stored match data to a new file. - .then([&](matched_lines lines) - { - return write_matches_to_file(outFileName, std::move(lines)); - }) + // Write matches into custom data structure. + .then([&]() { + basic_istream inLineResults(lineResultsBuffer); + return inLineResults.extract(); + }) - // Wait for everything to complete. - .wait(); + // Write out stored match data to a new file. + .then([&](matched_lines lines) { return write_matches_to_file(outFileName, std::move(lines)); }) + + // Wait for everything to complete. + .wait(); return 0; -} \ No newline at end of file +} diff --git a/Release/samples/WindowsLiveAuth/App.xaml.cpp b/Release/samples/WindowsLiveAuth/App.xaml.cpp index 397cc832cb..8d41c7458f 100644 --- a/Release/samples/WindowsLiveAuth/App.xaml.cpp +++ b/Release/samples/WindowsLiveAuth/App.xaml.cpp @@ -1,9 +1,10 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + ****/ #include "pch.h" + #include "MainPage.xaml.h" using namespace WindowsLiveAuth; @@ -30,8 +31,8 @@ using namespace Windows::UI::Xaml::Navigation; /// App::App() { - InitializeComponent(); - Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); + InitializeComponent(); + Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); } /// @@ -40,55 +41,54 @@ App::App() /// search results, and so forth. /// /// Details about the launch request and process. -void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args) +void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ args) { - auto rootFrame = dynamic_cast(Window::Current->Content); - - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (rootFrame == nullptr) - { - // Create a Frame to act as the navigation context and associate it with - // a SuspensionManager key - rootFrame = ref new Frame(); + auto rootFrame = dynamic_cast(Window::Current->Content); - if (args->PreviousExecutionState == ApplicationExecutionState::Terminated) - { - // TODO: Restore the saved session state only when appropriate, scheduling the - // final launch steps after the restore is complete + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == nullptr) + { + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + rootFrame = ref new Frame(); - } + if (args->PreviousExecutionState == ApplicationExecutionState::Terminated) + { + // TODO: Restore the saved session state only when appropriate, scheduling the + // final launch steps after the restore is complete + } - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) - { - throw ref new FailureException("Failed to create initial page"); - } - } - // Place the frame in the current Window - Window::Current->Content = rootFrame; - // Ensure the current window is active - Window::Current->Activate(); - } - else - { - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) - { - throw ref new FailureException("Failed to create initial page"); - } - } - // Ensure the current window is active - Window::Current->Activate(); - } + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) + { + throw ref new FailureException("Failed to create initial page"); + } + } + // Place the frame in the current Window + Window::Current->Content = rootFrame; + // Ensure the current window is active + Window::Current->Activate(); + } + else + { + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (!rootFrame->Navigate(TypeName(MainPage::typeid), args->Arguments)) + { + throw ref new FailureException("Failed to create initial page"); + } + } + // Ensure the current window is active + Window::Current->Activate(); + } } /// @@ -98,10 +98,10 @@ void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEvent /// /// The source of the suspend request. /// Details about the suspend request. -void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) +void App::OnSuspending(Object ^ sender, SuspendingEventArgs ^ e) { - (void) sender; // Unused parameter - (void) e; // Unused parameter + (void)sender; // Unused parameter + (void)e; // Unused parameter - //TODO: Save application state and stop any background activity + // TODO: Save application state and stop any background activity } diff --git a/Release/samples/WindowsLiveAuth/App.xaml.h b/Release/samples/WindowsLiveAuth/App.xaml.h index a7ef6b0805..dd871c9be8 100644 --- a/Release/samples/WindowsLiveAuth/App.xaml.h +++ b/Release/samples/WindowsLiveAuth/App.xaml.h @@ -1,7 +1,7 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + ****/ #pragma once @@ -9,16 +9,16 @@ namespace WindowsLiveAuth { - /// - /// Provides application-specific behavior to supplement the default Application class. - /// - ref class App sealed - { - public: - App(); - virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args) override; +/// +/// Provides application-specific behavior to supplement the default Application class. +/// +ref class App sealed +{ +public: + App(); + virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ args) override; - private: - void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); - }; -} +private: + void OnSuspending(Platform::Object ^ sender, Windows::ApplicationModel::SuspendingEventArgs ^ e); +}; +} // namespace WindowsLiveAuth diff --git a/Release/samples/WindowsLiveAuth/MainPage.xaml.cpp b/Release/samples/WindowsLiveAuth/MainPage.xaml.cpp index 91e2a13f9a..c7280bfee8 100644 --- a/Release/samples/WindowsLiveAuth/MainPage.xaml.cpp +++ b/Release/samples/WindowsLiveAuth/MainPage.xaml.cpp @@ -1,10 +1,12 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + ****/ #include "pch.h" + #include "MainPage.xaml.h" + #include "cpprest/filestream.h" using namespace WindowsLiveAuth; @@ -20,29 +22,26 @@ using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Navigation; -using namespace Platform::Collections; -using namespace Windows::Security::Authentication::OnlineId; +using namespace Platform::Collections; +using namespace Windows::Security::Authentication::OnlineId; // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 -MainPage::MainPage() -{ - InitializeComponent(); -} +MainPage::MainPage() { InitializeComponent(); } /// /// Invoked when this page is about to be displayed in a Frame. /// /// Event data that describes how this page was reached. The Parameter /// property is typically used to configure the page. -void MainPage::OnNavigatedTo(NavigationEventArgs^ e) +void MainPage::OnNavigatedTo(NavigationEventArgs ^ e) { - (void) e; // Unused parameter + (void)e; // Unused parameter } static web::live::live_client lv_client; -void MainPage::Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void MainPage::Button_Click_1(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { try { @@ -52,31 +51,35 @@ void MainPage::Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::Route scopes.push_back(web::live::scopes::wl_basic); scopes.push_back(web::live::scopes::wl_skydrive); scopes.push_back(web::live::scopes::wl_skydrive_update); - lv_client.login(std::begin(scopes), std::end(scopes)).then([this](bool ok) - { - if (ok) - { - this->LogOutButton->Visibility = Windows::UI::Xaml::Visibility::Visible; - this->LogInButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - - this->Block1->Text = ref new Platform::String((L"access_token = \n" + lv_client.access_token()).c_str()); - } - }, ui_ctx); + lv_client.login(std::begin(scopes), std::end(scopes)) + .then( + [this](bool ok) { + if (ok) + { + this->LogOutButton->Visibility = Windows::UI::Xaml::Visibility::Visible; + this->LogInButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + + this->Block1->Text = + ref new Platform::String((L"access_token = \n" + lv_client.access_token()).c_str()); + } + }, + ui_ctx); } - catch(...) + catch (...) { } } -void MainPage::LogOutButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void MainPage::LogOutButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { auto ui_ctx = pplx::task_continuation_context::use_current(); - lv_client.logout().then([this](bool) - { - this->LogOutButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - this->LogInButton->Visibility = Windows::UI::Xaml::Visibility::Visible; - }, ui_ctx); + lv_client.logout().then( + [this](bool) { + this->LogOutButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + this->LogInButton->Visibility = Windows::UI::Xaml::Visibility::Visible; + }, + ui_ctx); } // The following functions let you get information for an arbitrary WL resource, upload a file, or download a file. @@ -89,28 +92,28 @@ void MainPage::LogOutButton_Click(Platform::Object^ sender, Windows::UI::Xaml::R // create a contact using lv_client.post() // modify a calendar event using lv_client.put() // -void MainPage::Button_Click_2(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void MainPage::Button_Click_2(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { auto ui_ctx = pplx::task_continuation_context::use_current(); - lv_client.get(this->Box1->Text->Data()).then( - [this](pplx::task value) - { - try - { - auto str = value.get().serialize(); - this->Block1->Text = ref new Platform::String(str.c_str()); - } - catch(std::exception& exc) - { - this->Block1->Text = ref new Platform::String(utility::conversions::to_string_t(exc.what()).c_str()); - } - }, ui_ctx); - + lv_client.get(this->Box1->Text->Data()) + .then( + [this](pplx::task value) { + try + { + auto str = value.get().serialize(); + this->Block1->Text = ref new Platform::String(str.c_str()); + } + catch (std::exception& exc) + { + this->Block1->Text = + ref new Platform::String(utility::conversions::to_string_t(exc.what()).c_str()); + } + }, + ui_ctx); } - -void MainPage::UploadButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void MainPage::UploadButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { this->Block1->Text = ref new Platform::String(L"Processing request..."); @@ -129,9 +132,8 @@ void MainPage::UploadButton_Click(Platform::Object^ sender, Windows::UI::Xaml::R utility::string_t path = this->Box1->Text->Data(); pplx::create_task(file) - .then([path](Windows::Storage::StorageFile^ file) - { - if ( file == nullptr ) + .then([path](Windows::Storage::StorageFile ^ file) { + if (file == nullptr) { throw std::exception("No file was picked"); } @@ -140,22 +142,23 @@ void MainPage::UploadButton_Click(Platform::Object^ sender, Windows::UI::Xaml::R return lv_client.upload(full_path, file); }) - .then([this](pplx::task response) - { - try - { - auto message = response.get().serialize(); - this->Block1->Text = ref new Platform::String(message.c_str()); - } - catch(std::exception& exc) - { - this->Block1->Text = ref new Platform::String(utility::conversions::to_string_t(exc.what()).c_str()); - } - }, ui_ctx); + .then( + [this](pplx::task response) { + try + { + auto message = response.get().serialize(); + this->Block1->Text = ref new Platform::String(message.c_str()); + } + catch (std::exception& exc) + { + this->Block1->Text = + ref new Platform::String(utility::conversions::to_string_t(exc.what()).c_str()); + } + }, + ui_ctx); } - -void MainPage::DownloadButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +void MainPage::DownloadButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) { this->Block1->Text = ref new Platform::String(L"Processing request..."); @@ -164,38 +167,34 @@ void MainPage::DownloadButton_Click(Platform::Object^ sender, Windows::UI::Xaml: // Start by getting the file metadata from OneDrive. We need the file name. lv_client.get(path) - .then([this](web::json::value file_info) - { - if (!file_info.is_object()) - throw std::exception("unexpected file info response format"); - - auto name = file_info[L"name"].as_string(); - - // Once we have the name, we can create a storage file in the downloads folder. - - return pplx::create_task( - Windows::Storage::DownloadsFolder::CreateFileAsync( - ref new Platform::String(name.c_str()), - Windows::Storage::CreationCollisionOption::GenerateUniqueName)); - }) - .then([path,ui_ctx,this](Windows::Storage::StorageFile^ file) - { - if ( file == nullptr ) - throw std::exception("unexpected file info response format"); - auto name = file->Name; - // With a file reference in hand, we download the file. - return lv_client.download(path, file); - }) - .then([this](pplx::task response) - { - try - { - response.wait(); - this->Block1->Text = ref new Platform::String(L"Download complete."); - } - catch(std::exception& exc) - { - this->Block1->Text = ref new Platform::String(utility::conversions::to_string_t(exc.what()).c_str()); - } - }, ui_ctx); + .then([this](web::json::value file_info) { + if (!file_info.is_object()) throw std::exception("unexpected file info response format"); + + auto name = file_info[L"name"].as_string(); + + // Once we have the name, we can create a storage file in the downloads folder. + + return pplx::create_task(Windows::Storage::DownloadsFolder::CreateFileAsync( + ref new Platform::String(name.c_str()), Windows::Storage::CreationCollisionOption::GenerateUniqueName)); + }) + .then([path, ui_ctx, this](Windows::Storage::StorageFile ^ file) { + if (file == nullptr) throw std::exception("unexpected file info response format"); + auto name = file->Name; + // With a file reference in hand, we download the file. + return lv_client.download(path, file); + }) + .then( + [this](pplx::task response) { + try + { + response.wait(); + this->Block1->Text = ref new Platform::String(L"Download complete."); + } + catch (std::exception& exc) + { + this->Block1->Text = + ref new Platform::String(utility::conversions::to_string_t(exc.what()).c_str()); + } + }, + ui_ctx); } diff --git a/Release/samples/WindowsLiveAuth/MainPage.xaml.h b/Release/samples/WindowsLiveAuth/MainPage.xaml.h index 03a1788e3e..092d513aa4 100644 --- a/Release/samples/WindowsLiveAuth/MainPage.xaml.h +++ b/Release/samples/WindowsLiveAuth/MainPage.xaml.h @@ -1,28 +1,30 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + ****/ #pragma once #include "MainPage.g.h" namespace WindowsLiveAuth { - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - public ref class MainPage sealed - { - public: - MainPage(); +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +public +ref class MainPage sealed +{ +public: + MainPage(); + +protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs ^ e) override; - protected: - virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; - private: - void Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void Button_Click_2(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void LogOutButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void UploadButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void DownloadButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - }; -} +private: + void Button_Click_1(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + void Button_Click_2(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + void LogOutButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + void UploadButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + void DownloadButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); +}; +} // namespace WindowsLiveAuth diff --git a/Release/samples/WindowsLiveAuth/live_connect.h b/Release/samples/WindowsLiveAuth/live_connect.h index d3ec04883d..c8381df046 100644 --- a/Release/samples/WindowsLiveAuth/live_connect.h +++ b/Release/samples/WindowsLiveAuth/live_connect.h @@ -1,462 +1,452 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* live_connect.h -* -* Simple API for connecting to Windows Live services, such as OneDrive and Hotmail. -* Only supported for App Store apps. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * live_connect.h + * + * Simple API for connecting to Windows Live services, such as OneDrive and Hotmail. + * Only supported for App Store apps. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include +#include "cpprest/filestream.h" #include "cpprest/http_client.h" #include "cpprest/streams.h" -#include "cpprest/filestream.h" - -namespace web { namespace live { +#include +namespace web +{ +namespace live +{ #if defined(__cplusplus_winrt) +/// +/// This namespace contains symbols for the standard Windows Live permission scopes, which +/// determine what privileges the application has to access data. What operations are allowed +/// and what details are returned will depend on privileges requested and granted. +/// +/// See MSDN documentation for Live Connect at http://msdn.microsoft.com/en-us/live/ for details +/// on the precise meaning of these scopes. +/// +namespace scopes +{ +static const utility::string_t wl_birthday = U("wl.birthday"); +static const utility::string_t wl_basic = U("wl.basic"); +static const utility::string_t wl_calendars = U("wl.calendars"); +static const utility::string_t wl_calendars_update = U("wl.calendars_update"); +static const utility::string_t wl_contacts_birthday = U("wl.contacts_birthday"); +static const utility::string_t wl_contacts_create = U("wl.contacts_create"); +static const utility::string_t wl_contacts_calendars = U("wl.contacts_calendars"); +static const utility::string_t wl_contacts_photos = U("wl.contacts_photos"); +static const utility::string_t wl_contacts_skydrive = U("wl.contacts_skydrive"); +static const utility::string_t wl_emails = U("wl.emails"); +static const utility::string_t wl_events_create = U("wl.events_create"); +static const utility::string_t wl_messenger = U("wl.messenger"); +static const utility::string_t wl_offline_access = U("wl.offline_access"); +static const utility::string_t wl_phone_numbers = U("wl.phone_numbers"); +static const utility::string_t wl_photos = U("wl.photos"); +static const utility::string_t wl_postal_addresses = U("wl.postal_addresses"); +static const utility::string_t wl_share = U("wl.share"); +static const utility::string_t wl_signin = U("wl.signin"); +static const utility::string_t wl_skydrive = U("wl.skydrive"); +static const utility::string_t wl_skydrive_update = U("wl.skydrive_update"); +static const utility::string_t wl_work_profile = U("wl.work_profile"); +} // namespace scopes + +/// +/// Represents a session connected to Windows Live services like Calendar, Contacts, OneDrive, and the +/// user profile, by using the Live Connect REST API. It is a thin layer on top of the Casablanca HTTP +/// library, tailored to the usage scenarios for Windows Live clients. +/// +/// +/// See http://msdn.microsoft.com/onedrive/ for details on using the OneDrive REST API. +/// +/// Note: when passing resource paths into the functions in this class, it is not necessary to add the +/// leading '/' path character. It will be added automatically when constructing the HTTP request. +/// +/// Most Windows Live requests will return data in the form of plain text or JSON. The APIs in this +/// class will typically return data as JSON. The most significant exception to this is download(), +/// which will not return any data to be extracted, it will place the result in the stream or file +/// passed into it. Also, remove() will return data only to provide error information: for non-error +/// cases, the JSON value will be null. +/// +/// This class relies on PPL tasks to represent asynchrony: the examples contained within the comments +/// show synchronous forms of invoking these APIs. In real use, applications should be relying on +/// .then() instead of .get() or .wait(). +/// +class live_client +{ +public: /// - /// This namespace contains symbols for the standard Windows Live permission scopes, which - /// determine what privileges the application has to access data. What operations are allowed - /// and what details are returned will depend on privileges requested and granted. - /// - /// See MSDN documentation for Live Connect at http://msdn.microsoft.com/en-us/live/ for details - /// on the precise meaning of these scopes. + /// Constructs a new Windows Live client /// - namespace scopes + live_client() + : m_client(L"https://apis.live.net/v5.0/") + , m_authenticator(ref new Windows::Security::Authentication::OnlineId::OnlineIdAuthenticator) { - static const utility::string_t wl_birthday = U("wl.birthday"); - static const utility::string_t wl_basic = U("wl.basic"); - static const utility::string_t wl_calendars = U("wl.calendars"); - static const utility::string_t wl_calendars_update = U("wl.calendars_update"); - static const utility::string_t wl_contacts_birthday = U("wl.contacts_birthday"); - static const utility::string_t wl_contacts_create = U("wl.contacts_create"); - static const utility::string_t wl_contacts_calendars = U("wl.contacts_calendars"); - static const utility::string_t wl_contacts_photos = U("wl.contacts_photos"); - static const utility::string_t wl_contacts_skydrive = U("wl.contacts_skydrive"); - static const utility::string_t wl_emails = U("wl.emails"); - static const utility::string_t wl_events_create = U("wl.events_create"); - static const utility::string_t wl_messenger = U("wl.messenger"); - static const utility::string_t wl_offline_access = U("wl.offline_access"); - static const utility::string_t wl_phone_numbers = U("wl.phone_numbers"); - static const utility::string_t wl_photos = U("wl.photos"); - static const utility::string_t wl_postal_addresses = U("wl.postal_addresses"); - static const utility::string_t wl_share = U("wl.share"); - static const utility::string_t wl_signin = U("wl.signin"); - static const utility::string_t wl_skydrive = U("wl.skydrive"); - static const utility::string_t wl_skydrive_update = U("wl.skydrive_update"); - static const utility::string_t wl_work_profile = U("wl.work_profile"); } /// - /// Represents a session connected to Windows Live services like Calendar, Contacts, OneDrive, and the - /// user profile, by using the Live Connect REST API. It is a thin layer on top of the Casablanca HTTP - /// library, tailored to the usage scenarios for Windows Live clients. + /// Authenticates the current user and requests permission to access a listed Live services. /// - /// - /// See http://msdn.microsoft.com/onedrive/ for details on using the OneDrive REST API. - /// - /// Note: when passing resource paths into the functions in this class, it is not necessary to add the - /// leading '/' path character. It will be added automatically when constructing the HTTP request. - /// - /// Most Windows Live requests will return data in the form of plain text or JSON. The APIs in this - /// class will typically return data as JSON. The most significant exception to this is download(), - /// which will not return any data to be extracted, it will place the result in the stream or file - /// passed into it. Also, remove() will return data only to provide error information: for non-error - /// cases, the JSON value will be null. - /// - /// This class relies on PPL tasks to represent asynchrony: the examples contained within the comments - /// show synchronous forms of invoking these APIs. In real use, applications should be relying on - /// .then() instead of .get() or .wait(). - /// - class live_client + /// A string containing a space-separated list of access scopes to request + /// true if authentication succeeded, false otherwise. + pplx::task login(utility::string_t scopes) { - public: - /// - /// Constructs a new Windows Live client - /// - live_client() : - m_client(L"https://apis.live.net/v5.0/"), - m_authenticator(ref new Windows::Security::Authentication::OnlineId::OnlineIdAuthenticator) - { - } + this->m_token.clear(); - /// - /// Authenticates the current user and requests permission to access a listed Live services. - /// - /// A string containing a space-separated list of access scopes to request - /// true if authentication succeeded, false otherwise. - pplx::task login(utility::string_t scopes) - { - this->m_token.clear(); - - auto request = ref new Windows::Security::Authentication::OnlineId::OnlineIdServiceTicketRequest(ref new Platform::String(scopes.c_str()), "DELEGATION"); + auto request = ref new Windows::Security::Authentication::OnlineId::OnlineIdServiceTicketRequest( + ref new Platform::String(scopes.c_str()), "DELEGATION"); - return pplx::create_task(m_authenticator->AuthenticateUserAsync(request)) - .then([this](Windows::Security::Authentication::OnlineId::UserIdentity^ ident) - { - if ( ident->Tickets->Size > 0 ) + return pplx::create_task(m_authenticator->AuthenticateUserAsync(request)) + .then([this](Windows::Security::Authentication::OnlineId::UserIdentity ^ ident) { + if (ident->Tickets->Size > 0) { auto ticket = ident->Tickets->GetAt(0); - + m_token = std::wstring(ticket->Value->Data()); return true; } return false; }); - } + } - /// - /// Authenticates the current user and requests permission to access a listed Live services. - /// - /// - /// The starting point of an iterator over a std::string collection, (for example a vector of - /// strings), holding the names of scopes to get permission for. - /// - /// The end point for the same collection. - /// true if authentication succeeded, false otherwise. - template - pplx::task login(Iter begin, Iter end) - { - utility::string_t services; - - for (Iter iter = begin; iter != end; ++iter) - { - services.append(*iter); - services.append(utility::string_t(L" ")); - } + /// + /// Authenticates the current user and requests permission to access a listed Live services. + /// + /// + /// The starting point of an iterator over a std::string collection, (for example a vector of + /// strings), holding the names of scopes to get permission for. + /// + /// The end point for the same collection. + /// true if authentication succeeded, false otherwise. + template + pplx::task login(Iter begin, Iter end) + { + utility::string_t services; - return login(services); + for (Iter iter = begin; iter != end; ++iter) + { + services.append(*iter); + services.append(utility::string_t(L" ")); } - /// - /// Dismisses any and all permissions that have been granted to the user. - /// - /// true if logout succeeded, false otherwise. - /// - /// Whether the logout attempt was successful or not, the application will - /// be required to log in again, since the access token will be cleared. - /// - pplx::task logout() - { - this->m_token.clear(); + return login(services); + } - if (!m_authenticator->CanSignOut) - return pplx::task_from_result(false); + /// + /// Dismisses any and all permissions that have been granted to the user. + /// + /// true if logout succeeded, false otherwise. + /// + /// Whether the logout attempt was successful or not, the application will + /// be required to log in again, since the access token will be cleared. + /// + pplx::task logout() + { + this->m_token.clear(); - return pplx::create_task(m_authenticator->SignOutUserAsync()).then([this] - { - return true; - }); - } + if (!m_authenticator->CanSignOut) return pplx::task_from_result(false); - /// - /// Retrieves the access token in use by this client instance. - /// - /// The current token: a string. An invalid token is indicated by an empty string. - const utility::string_t& access_token() const - { - return m_token; - } + return pplx::create_task(m_authenticator->SignOutUserAsync()).then([this] { return true; }); + } - /// - /// Retrieves data from Windows Live. - /// - /// The Windows Live resource to retrieve. - /// The JSON value resulting from the request. - /// To get the current user profile: json::value profile = live_clnt.get(L"me").get().extract_json().get(); - pplx::task get(const utility::string_t& resource) - { - return _make_request(web::http::methods::GET, resource).then([](web::http::http_response response) { return _json_extract(response); }); - } + /// + /// Retrieves the access token in use by this client instance. + /// + /// The current token: a string. An invalid token is indicated by an empty string. + const utility::string_t& access_token() const { return m_token; } - /// - /// Deletes data from Windows Live. - /// - /// The Windows Live resource to delete. - /// The JSON value resulting from the request. - /// To delete a file: live_clnt.remove(L"file.NNNNNNNNNNNN").wait();, where file.NNNNNNNNNNNN is a file identifier. - pplx::task remove(const utility::string_t& resource) - { - return _make_request(web::http::methods::DEL, resource).then([](web::http::http_response response) { return _json_extract(response); }); - } + /// + /// Retrieves data from Windows Live. + /// + /// The Windows Live resource to retrieve. + /// The JSON value resulting from the request. + /// To get the current user profile: json::value profile = + /// live_clnt.get(L"me").get().extract_json().get(); + pplx::task get(const utility::string_t& resource) + { + return _make_request(web::http::methods::GET, resource).then([](web::http::http_response response) { + return _json_extract(response); + }); + } - /// - /// Modifies data in Windows Live. - /// - /// The Windows Live resource to modify. - /// The JSON value resulting from the request. - /// In most cases, the response will contain data about the modified resource. - pplx::task put(const utility::string_t& resource, const web::json::value& data) - { - return _make_request(web::http::methods::PUT, resource, data).then([](web::http::http_response response) { return _json_extract(response); }); - } + /// + /// Deletes data from Windows Live. + /// + /// The Windows Live resource to delete. + /// The JSON value resulting from the request. + /// To delete a file: live_clnt.remove(L"file.NNNNNNNNNNNN").wait();, where file.NNNNNNNNNNNN + /// is a file identifier. + pplx::task remove(const utility::string_t& resource) + { + return _make_request(web::http::methods::DEL, resource).then([](web::http::http_response response) { + return _json_extract(response); + }); + } - /// - /// Adds data to Windows Live. - /// - /// The Windows Live resource (such as a folder) where data should be added. - /// The JSON value resulting from the request. - /// In most cases, the response will contain data about the added resource. - /// To add a contact: json::value contact = ...; live_clnt.post(L"me/contacts", contact).wait(); - pplx::task post(const utility::string_t& resource, const web::json::value& data) - { - return _make_request(web::http::methods::POST, resource, data).then([](web::http::http_response response) { return _json_extract(response); }); - } + /// + /// Modifies data in Windows Live. + /// + /// The Windows Live resource to modify. + /// The JSON value resulting from the request. + /// In most cases, the response will contain data about the modified resource. + pplx::task put(const utility::string_t& resource, const web::json::value& data) + { + return _make_request(web::http::methods::PUT, resource, data).then([](web::http::http_response response) { + return _json_extract(response); + }); + } - /// - /// Copies data in Windows Live. - /// - /// The Windows Live resource to copy. - /// The location where the resource copy should be placed. - /// The JSON value resulting from the request. - /// In most cases, the response will contain data about the added resource. - /// To copy a file: live_clnt.copy(L"file.NNNNNNNNNNNN", L"folder.MMMMMMMMMMMM").wait(); - pplx::task copy(const utility::string_t& resource, const utility::string_t& destination) - { - return _make_request(U("COPY"), resource, destination).then([](web::http::http_response response) { return _json_extract(response); }); - } + /// + /// Adds data to Windows Live. + /// + /// The Windows Live resource (such as a folder) where data should be added. + /// The JSON value resulting from the request. + /// In most cases, the response will contain data about the added resource. + /// To add a contact: json::value contact = ...; live_clnt.post(L"me/contacts", + /// contact).wait(); + pplx::task post(const utility::string_t& resource, const web::json::value& data) + { + return _make_request(web::http::methods::POST, resource, data).then([](web::http::http_response response) { + return _json_extract(response); + }); + } - /// - /// Moves data in Windows Live. - /// - /// The Windows Live resource to move. - /// The location where the resource should be placed. - /// The JSON value resulting from the request. - /// In most cases, the response will contain data about the resource in its new location. - /// To copy a file: live_clnt.copy(L"file.NNNNNNNNNNNN", L"folder.MMMMMMMMMMMM").wait(); - pplx::task move(const utility::string_t& resource, const utility::string_t& destination) - { - return _make_request(U("MOVE"), resource, destination).then([](web::http::http_response response) { return _json_extract(response); }); - } + /// + /// Copies data in Windows Live. + /// + /// The Windows Live resource to copy. + /// The location where the resource copy should be placed. + /// The JSON value resulting from the request. + /// In most cases, the response will contain data about the added resource. + /// To copy a file: live_clnt.copy(L"file.NNNNNNNNNNNN", + /// L"folder.MMMMMMMMMMMM").wait(); + pplx::task copy(const utility::string_t& resource, const utility::string_t& destination) + { + return _make_request(U("COPY"), resource, destination).then([](web::http::http_response response) { + return _json_extract(response); + }); + } - /// - /// Download a file from OneDrive. - /// - /// The OneDrive file id to download. - /// A stream into which the contents of the file should be placed. - /// The size of the downloaded resource. - /// - /// To download a file: ostream stream = ...; live_clnt.download(L"file.NNNNNNNNNNNN", ostream).get().content_ready().wait(); - pplx::task download(const utility::string_t& file_id, concurrency::streams::ostream stream) - { - web::http::uri_builder bldr; - bldr.append(file_id); - bldr.append_path(U("content")); + /// + /// Moves data in Windows Live. + /// + /// The Windows Live resource to move. + /// The location where the resource should be placed. + /// The JSON value resulting from the request. + /// In most cases, the response will contain data about the resource in its new location. + /// To copy a file: live_clnt.copy(L"file.NNNNNNNNNNNN", + /// L"folder.MMMMMMMMMMMM").wait(); + pplx::task move(const utility::string_t& resource, const utility::string_t& destination) + { + return _make_request(U("MOVE"), resource, destination).then([](web::http::http_response response) { + return _json_extract(response); + }); + } - web::http::http_request req(web::http::methods::GET); - req.set_request_uri(bldr.to_string()); + /// + /// Download a file from OneDrive. + /// + /// The OneDrive file id to download. + /// A stream into which the contents of the file should be placed. + /// The size of the downloaded resource. + /// + /// To download a file: ostream stream = ...; live_clnt.download(L"file.NNNNNNNNNNNN", + /// ostream).get().content_ready().wait(); + pplx::task download(const utility::string_t& file_id, concurrency::streams::ostream stream) + { + web::http::uri_builder bldr; + bldr.append(file_id); + bldr.append_path(U("content")); - return _make_request(req) - .then([stream](web::http::http_response response) -> pplx::task - { - if ( response.status_code() >= 400 ) - { - return response.extract_string().then( - [](utility::string_t message) -> pplx::task - { - return pplx::task_from_exception(std::exception(utility::conversions::to_utf8string(message).c_str())); - }); - } - return response.body().read_to_end(stream.streambuf()); + web::http::http_request req(web::http::methods::GET); + req.set_request_uri(bldr.to_string()); + + return _make_request(req).then([stream](web::http::http_response response) -> pplx::task { + if (response.status_code() >= 400) + { + return response.extract_string().then([](utility::string_t message) -> pplx::task { + return pplx::task_from_exception( + std::exception(utility::conversions::to_utf8string(message).c_str())); }); - } + } + return response.body().read_to_end(stream.streambuf()); + }); + } - /// - /// Download a file from OneDrive. - /// - /// The OneDrive file id to download. - /// A StorageFile reference identifying the target for the downloaded data. - /// The size of the downloaded resource. - /// - pplx::task download(const utility::string_t& file_id, Windows::Storage::StorageFile^ file) - { - if ( file == nullptr ) - throw std::invalid_argument("file reference cannot be null"); + /// + /// Download a file from OneDrive. + /// + /// The OneDrive file id to download. + /// A StorageFile reference identifying the target for the downloaded data. + /// The size of the downloaded resource. + /// + pplx::task download(const utility::string_t& file_id, Windows::Storage::StorageFile ^ file) + { + if (file == nullptr) throw std::invalid_argument("file reference cannot be null"); - return concurrency::streams::file_stream::open_ostream(file).then( - [file_id,this](concurrency::streams::ostream stream) - { - web::http::uri_builder bldr; - bldr.append(file_id); - bldr.append_path(U("content")); + return concurrency::streams::file_stream::open_ostream(file).then( + [file_id, this](concurrency::streams::ostream stream) { + web::http::uri_builder bldr; + bldr.append(file_id); + bldr.append_path(U("content")); - web::http::http_request req(web::http::methods::GET); - req.set_request_uri(bldr.to_string()); + web::http::http_request req(web::http::methods::GET); + req.set_request_uri(bldr.to_string()); - return _make_request(req) - .then([stream](web::http::http_response response) -> pplx::task + return _make_request(req) + .then([stream](web::http::http_response response) -> pplx::task { + if (response.status_code() >= 400) { - if ( response.status_code() >= 400 ) - { - return response.extract_string().then( - [](utility::string_t message) -> pplx::task - { - return pplx::task_from_exception(std::exception(utility::conversions::to_utf8string(message).c_str())); - }); - } - return response.body().read_to_end(stream.streambuf()); - }) - .then([stream](pplx::task ret_task) - { - return stream.flush().then([stream, ret_task]() - { - return stream.close(); - }).then([ret_task]() - { - return ret_task; + return response.extract_string().then([](utility::string_t message) -> pplx::task { + return pplx::task_from_exception( + std::exception(utility::conversions::to_utf8string(message).c_str())); }); + } + return response.body().read_to_end(stream.streambuf()); + }) + .then([stream](pplx::task ret_task) { + return stream.flush().then([stream, ret_task]() { return stream.close(); }).then([ret_task]() { + return ret_task; }); - }); - } - - /// - /// Upload a file to OneDrive. - /// - /// The path of the file location in OneDrive. It should be of the form "folder.NNNNNNNNNN/files/file_name.ext" - /// A stream from which data for the file will be read. - /// The size of the data to upload. - /// The JSON value resulting from the request, containing metadata about the uploaded file. - /// - /// The stream must contain at least as many bytes as indicated by 'content_length', starting from its current read position. - /// - pplx::task upload(const utility::string_t& path, concurrency::streams::istream stream, size_t content_length) - { - web::http::uri_builder bldr; - bldr.append(path); - - web::http::http_request req(web::http::methods::PUT); - req.set_request_uri(bldr.to_string()); - req.set_body(stream, content_length, U("")); + }); + }); + } - return _make_request(req) - .then([](web::http::http_response response) - { - return _json_extract(response); - }); - } + /// + /// Upload a file to OneDrive. + /// + /// The path of the file location in OneDrive. It should be of the form + /// "folder.NNNNNNNNNN/files/file_name.ext" A stream from which data for the file will + /// be read. The size of the data to upload. The JSON value + /// resulting from the request, containing metadata about the uploaded file. + /// The stream must contain at least as many bytes as indicated by 'content_length', starting from its current + /// read position. + /// + pplx::task upload(const utility::string_t& path, + concurrency::streams::istream stream, + size_t content_length) + { + web::http::uri_builder bldr; + bldr.append(path); - /// - /// Upload a file to OneDrive. - /// - /// The path of the file location in OneDrive. It should be of the form "folder.NNNNNNNNNN/files/file_name.ext" - /// A StorageFile reference identifying the source of the uploaded data. - /// The size of the data to upload. - /// The JSON value resulting from the request, containing metadata about the uploaded file. - /// The entire file will be uploaded. - pplx::task upload(const utility::string_t& path, Windows::Storage::StorageFile^ file) - { - if ( file == nullptr ) - throw std::invalid_argument("file reference cannot be null"); + web::http::http_request req(web::http::methods::PUT); + req.set_request_uri(bldr.to_string()); + req.set_body(stream, content_length, U("")); - return pplx::create_task(file->GetBasicPropertiesAsync()).then( - [path,this,file](Windows::Storage::FileProperties::BasicProperties^ props) - { - if (props == nullptr) - throw std::exception("failed to retrieve file properties; cannot determine its size"); - size_t size = (size_t)props->Size; - - return concurrency::streams::file_stream::open_istream(file).then( - [path,this,size](concurrency::streams::istream stream) - { - web::http::uri_builder bldr; - bldr.append(path); - - web::http::http_request req(web::http::methods::PUT); - req.set_request_uri(bldr.to_string()); - req.set_body(stream, size, U("")); - - return _make_request(req) - .then([](web::http::http_response response) - { - return response.content_ready(); - }) - .then([stream](pplx::task response) - { - return stream.close().then([response]() - { - return _json_extract(response.get()); - }); - }); - }); - }); - } + return _make_request(req).then([](web::http::http_response response) { return _json_extract(response); }); + } - private: + /// + /// Upload a file to OneDrive. + /// + /// The path of the file location in OneDrive. It should be of the form + /// "folder.NNNNNNNNNN/files/file_name.ext" A StorageFile reference identifying the + /// source of the uploaded data. The size of the data to upload. + /// The JSON value resulting from the request, containing metadata about the uploaded file. + /// The entire file will be uploaded. + pplx::task upload(const utility::string_t& path, Windows::Storage::StorageFile ^ file) + { + if (file == nullptr) throw std::invalid_argument("file reference cannot be null"); + + return pplx::create_task(file->GetBasicPropertiesAsync()) + .then([path, this, file](Windows::Storage::FileProperties::BasicProperties ^ props) { + if (props == nullptr) + throw std::exception("failed to retrieve file properties; cannot determine its size"); + size_t size = (size_t)props->Size; + + return concurrency::streams::file_stream::open_istream(file).then( + [path, this, size](concurrency::streams::istream stream) { + web::http::uri_builder bldr; + bldr.append(path); + + web::http::http_request req(web::http::methods::PUT); + req.set_request_uri(bldr.to_string()); + req.set_body(stream, size, U("")); + + return _make_request(req) + .then([](web::http::http_response response) { return response.content_ready(); }) + .then([stream](pplx::task response) { + return stream.close().then([response]() { return _json_extract(response.get()); }); + }); + }); + }); + } - static pplx::task _json_extract(web::http::http_response response) +private: + static pplx::task _json_extract(web::http::http_response response) + { + switch (response.status_code()) { - switch(response.status_code()) - { - case web::http::status_codes::NoContent: - return pplx::task_from_result(web::json::value::null()); + case web::http::status_codes::NoContent: return pplx::task_from_result(web::json::value::null()); default: - if ( response.status_code() >= 400 ) + if (response.status_code() >= 400) { return response.extract_string().then( - [](utility::string_t message) -> pplx::task - { - return pplx::task_from_exception(std::exception(utility::conversions::to_utf8string(message).c_str())); + [](utility::string_t message) -> pplx::task { + return pplx::task_from_exception( + std::exception(utility::conversions::to_utf8string(message).c_str())); }); } return response.extract_json(); - } } + } - pplx::task _make_request(web::http::method method, const utility::string_t& path) - { - web::http::uri_builder bldr; - bldr.append(path); - - web::http::http_request req(method); - req.set_request_uri(bldr.to_string()); - return _make_request(req); - } + pplx::task _make_request(web::http::method method, const utility::string_t& path) + { + web::http::uri_builder bldr; + bldr.append(path); + web::http::http_request req(method); + req.set_request_uri(bldr.to_string()); + return _make_request(req); + } - pplx::task _make_request(web::http::method method, const utility::string_t& path, const web::json::value& data) - { - web::http::uri_builder bldr; - bldr.append(path); + pplx::task _make_request(web::http::method method, + const utility::string_t& path, + const web::json::value& data) + { + web::http::uri_builder bldr; + bldr.append(path); - web::http::http_request req(method); - req.set_request_uri(bldr.to_string()); - req.set_body(data); - return _make_request(req); - } + web::http::http_request req(method); + req.set_request_uri(bldr.to_string()); + req.set_body(data); + return _make_request(req); + } - pplx::task _make_request(web::http::method method, const utility::string_t& path, const utility::string_t& destination) - { - web::http::uri_builder bldr; - bldr.append(path); + pplx::task _make_request(web::http::method method, + const utility::string_t& path, + const utility::string_t& destination) + { + web::http::uri_builder bldr; + bldr.append(path); - web::json::value data; - data[U("destination")] = web::json::value::string(destination); + web::json::value data; + data[U("destination")] = web::json::value::string(destination); - web::http::http_request req(method); - req.set_request_uri(bldr.to_string()); - req.set_body(data); - return _make_request(req); - } + web::http::http_request req(method); + req.set_request_uri(bldr.to_string()); + req.set_body(data); + return _make_request(req); + } - pplx::task _make_request(web::http::http_request req) - { - if (!m_token.empty()) - req.headers().add(U("Authorization"), U("Bearer ")+m_token); - return m_client.request(req); - } + pplx::task _make_request(web::http::http_request req) + { + if (!m_token.empty()) req.headers().add(U("Authorization"), U("Bearer ") + m_token); + return m_client.request(req); + } - Windows::Security::Authentication::OnlineId::OnlineIdAuthenticator^ m_authenticator; - web::http::client::http_client m_client; - utility::string_t m_token; - }; + Windows::Security::Authentication::OnlineId::OnlineIdAuthenticator ^ m_authenticator; + web::http::client::http_client m_client; + utility::string_t m_token; +}; #endif -}} \ No newline at end of file +} // namespace live +} // namespace web diff --git a/Release/samples/WindowsLiveAuth/pch.cpp b/Release/samples/WindowsLiveAuth/pch.cpp index 1b4680ffde..abe1fd5d75 100644 --- a/Release/samples/WindowsLiveAuth/pch.cpp +++ b/Release/samples/WindowsLiveAuth/pch.cpp @@ -1,6 +1,6 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + ****/ #include "pch.h" diff --git a/Release/samples/WindowsLiveAuth/pch.h b/Release/samples/WindowsLiveAuth/pch.h index 67f70ff41f..9835464d5b 100644 --- a/Release/samples/WindowsLiveAuth/pch.h +++ b/Release/samples/WindowsLiveAuth/pch.h @@ -1,11 +1,11 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + ****/ #pragma once -#include #include "App.xaml.h" #include "MainPage.xaml.h" -#include "live_connect.h" \ No newline at end of file +#include "live_connect.h" +#include \ No newline at end of file diff --git a/Release/src/http/client/http_client.cpp b/Release/src/http/client/http_client.cpp index 89eaa4941a..41230ea517 100644 --- a/Release/src/http/client/http_client.cpp +++ b/Release/src/http/client/http_client.cpp @@ -1,26 +1,30 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Client-side APIs. -* -* This file contains shared code across all http_client implementations. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Client-side APIs. + * + * This file contains shared code across all http_client implementations. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" #include "http_client_impl.h" -namespace web { namespace http { namespace client { - +namespace web +{ +namespace http +{ +namespace client +{ // Helper function to check to make sure the uri is valid. -static void verify_uri(const uri &uri) +static void verify_uri(const uri& uri) { // Some things like proper URI schema are verified by the URI class. // We only need to check certain things specific to HTTP. @@ -37,9 +41,9 @@ static void verify_uri(const uri &uri) namespace details { - #if defined(_WIN32) - extern const utility::char_t * get_with_body_err_msg = _XPLATSTR("A GET or HEAD request should not have an entity body."); +extern const utility::char_t* get_with_body_err_msg = + _XPLATSTR("A GET or HEAD request should not have an entity body."); #endif void request_context::complete_headers() @@ -58,13 +62,13 @@ void request_context::complete_request(utility::size64_t body_size) finish(); } -void request_context::report_error(unsigned long error_code, const std::string &errorMessage) +void request_context::report_error(unsigned long error_code, const std::string& errorMessage) { report_exception(http_exception(static_cast(error_code), errorMessage)); } #if defined(_WIN32) -void request_context::report_error(unsigned long error_code, const std::wstring &errorMessage) +void request_context::report_error(unsigned long error_code, const std::wstring& errorMessage) { report_exception(http_exception(static_cast(error_code), errorMessage)); } @@ -77,7 +81,8 @@ void request_context::report_exception(std::exception_ptr exceptionPtr) // If cancellation has been triggered then ignore any errors. if (m_request._cancellation_token().is_canceled()) { - exceptionPtr = std::make_exception_ptr(http_exception((int)std::errc::operation_canceled, std::generic_category())); + exceptionPtr = + std::make_exception_ptr(http_exception((int)std::errc::operation_canceled, std::generic_category())); } // First try to complete the headers with an exception. @@ -98,22 +103,27 @@ void request_context::report_exception(std::exception_ptr exceptionPtr) bool request_context::handle_compression() { - // If the response body is compressed we will read the encoding header and create a decompressor object which will later decompress the body + // If the response body is compressed we will read the encoding header and create a decompressor object which will + // later decompress the body try { utility::string_t encoding; - http_headers &headers = m_response.headers(); + http_headers& headers = m_response.headers(); // Note that some headers, for example "Transfer-Encoding: chunked", may legitimately not produce a decompressor - if (m_http_client->client_config().request_compressed_response() && headers.match(web::http::header_names::content_encoding, encoding)) + if (m_http_client->client_config().request_compressed_response() && + headers.match(web::http::header_names::content_encoding, encoding)) { // Note that, while Transfer-Encoding (chunked only) is valid with Content-Encoding, // we don't need to look for it here because winhttp de-chunks for us in that case - m_decompressor = compression::details::get_decompressor_from_header(encoding, compression::details::header_types::content_encoding, m_request.decompress_factories()); + m_decompressor = compression::details::get_decompressor_from_header( + encoding, compression::details::header_types::content_encoding, m_request.decompress_factories()); } - else if (!m_request.decompress_factories().empty() && headers.match(web::http::header_names::transfer_encoding, encoding)) + else if (!m_request.decompress_factories().empty() && + headers.match(web::http::header_names::transfer_encoding, encoding)) { - m_decompressor = compression::details::get_decompressor_from_header(encoding, compression::details::header_types::transfer_encoding, m_request.decompress_factories()); + m_decompressor = compression::details::get_decompressor_from_header( + encoding, compression::details::header_types::transfer_encoding, m_request.decompress_factories()); } } catch (...) @@ -137,16 +147,18 @@ utility::string_t request_context::get_compression_header() const { // Accept-Encoding -- request Content-Encoding from the server headers.append(header_names::accept_encoding + U(": ")); - headers.append(compression::details::build_supported_header(compression::details::header_types::accept_encoding, m_request.decompress_factories())); + headers.append(compression::details::build_supported_header( + compression::details::header_types::accept_encoding, m_request.decompress_factories())); headers.append(U("\r\n")); } } else if (!m_request.decompress_factories().empty()) { // TE -- request Transfer-Encoding from the server - headers.append(header_names::connection + U(": TE\r\n") + // Required by Section 4.3 of RFC-7230 + headers.append(header_names::connection + U(": TE\r\n") + // Required by Section 4.3 of RFC-7230 header_names::te + U(": ")); - headers.append(compression::details::build_supported_header(compression::details::header_types::te, m_request.decompress_factories())); + headers.append(compression::details::build_supported_header(compression::details::header_types::te, + m_request.decompress_factories())); headers.append(U("\r\n")); } @@ -169,11 +181,8 @@ concurrency::streams::streambuf request_context::_get_writebuffer() return outstream.streambuf(); } -request_context::request_context(const std::shared_ptr<_http_client_communicator> &client, const http_request &request) - : m_http_client(client), - m_request(request), - m_uploaded(0), - m_downloaded(0) +request_context::request_context(const std::shared_ptr<_http_client_communicator>& client, const http_request& request) + : m_http_client(client), m_request(request), m_uploaded(0), m_downloaded(0) { auto responseImpl = m_response._get_impl(); @@ -186,12 +195,11 @@ request_context::request_context(const std::shared_ptr<_http_client_communicator responseImpl->_prepare_to_receive_data(); } -void _http_client_communicator::async_send_request_impl(const std::shared_ptr &request) +void _http_client_communicator::async_send_request_impl(const std::shared_ptr& request) { auto self = std::static_pointer_cast<_http_client_communicator>(this->shared_from_this()); // Schedule a task to start sending. - pplx::create_task([self, request] - { + pplx::create_task([self, request] { try { self->send_request(request); @@ -203,7 +211,7 @@ void _http_client_communicator::async_send_request_impl(const std::shared_ptr &request) +void _http_client_communicator::async_send_request(const std::shared_ptr& request) { if (m_client_config.guarantee_order()) { @@ -246,15 +254,9 @@ void _http_client_communicator::finish_request() } } -const http_client_config& _http_client_communicator::client_config() const -{ - return m_client_config; -} +const http_client_config& _http_client_communicator::client_config() const { return m_client_config; } -const uri & _http_client_communicator::base_uri() const -{ - return m_uri; -} +const uri& _http_client_communicator::base_uri() const { return m_uri; } _http_client_communicator::_http_client_communicator(http::uri&& address, http_client_config&& client_config) : m_uri(std::move(address)), m_client_config(std::move(client_config)), m_outstanding(false) @@ -281,14 +283,13 @@ inline void request_context::finish() class http_pipeline { public: - http_pipeline(std::shared_ptr last) : m_last_stage(std::move(last)) - {} + http_pipeline(std::shared_ptr last) : m_last_stage(std::move(last)) {} // pplx::extensibility::recursive_lock_t does not support move/copy, but does not delete the functions either. - http_pipeline(const http_pipeline &) = delete; - http_pipeline(http_pipeline &&) = delete; - http_pipeline & operator=(const http_pipeline &) = delete; - http_pipeline & operator=(http_pipeline &&) = delete; + http_pipeline(const http_pipeline&) = delete; + http_pipeline(http_pipeline&&) = delete; + http_pipeline& operator=(const http_pipeline&) = delete; + http_pipeline& operator=(http_pipeline&&) = delete; /// /// Initiate an http request into the pipeline @@ -308,7 +309,7 @@ class http_pipeline /// Adds an HTTP pipeline stage to the pipeline. /// /// A pipeline stage. - void append(const std::shared_ptr &stage) + void append(const std::shared_ptr& stage) { pplx::extensibility::scoped_recursive_lock_t l(m_lock); @@ -328,19 +329,22 @@ class http_pipeline const std::shared_ptr m_last_stage; private: - // The vector of pipeline stages. std::vector> m_stages; pplx::extensibility::recursive_lock_t m_lock; }; -void http_client::add_handler(const std::function __cdecl(http_request, std::shared_ptr)> &handler) +void http_client::add_handler( + const std::function __cdecl(http_request, std::shared_ptr)>& + handler) { class function_pipeline_wrapper : public http::http_pipeline_stage { public: - function_pipeline_wrapper(const std::function __cdecl(http_request, std::shared_ptr)> &handler) : m_handler(handler) + function_pipeline_wrapper(const std::function __cdecl( + http_request, std::shared_ptr)>& handler) + : m_handler(handler) { } @@ -348,23 +352,19 @@ void http_client::add_handler(const std::function __cd { return m_handler(std::move(request), next_stage()); } - private: + private: std::function(http_request, std::shared_ptr)> m_handler; }; m_pipeline->append(std::make_shared(handler)); } -void http_client::add_handler(const std::shared_ptr &stage) -{ - m_pipeline->append(stage); -} +void http_client::add_handler(const std::shared_ptr& stage) { m_pipeline->append(stage); } -http_client::http_client(const uri &base_uri) : http_client(base_uri, http_client_config()) -{} +http_client::http_client(const uri& base_uri) : http_client(base_uri, http_client_config()) {} -http_client::http_client(const uri &base_uri, const http_client_config &client_config) +http_client::http_client(const uri& base_uri, const http_client_config& client_config) { std::shared_ptr final_pipeline_stage; @@ -374,12 +374,14 @@ http_client::http_client(const uri &base_uri, const http_client_config &client_c uribuilder.set_scheme(_XPLATSTR("http")); uri uriWithScheme = uribuilder.to_uri(); verify_uri(uriWithScheme); - final_pipeline_stage = details::create_platform_final_pipeline_stage(std::move(uriWithScheme), http_client_config(client_config)); + final_pipeline_stage = + details::create_platform_final_pipeline_stage(std::move(uriWithScheme), http_client_config(client_config)); } else { verify_uri(base_uri); - final_pipeline_stage = details::create_platform_final_pipeline_stage(uri(base_uri), http_client_config(client_config)); + final_pipeline_stage = + details::create_platform_final_pipeline_stage(uri(base_uri), http_client_config(client_config)); } m_pipeline = std::make_shared(std::move(final_pipeline_stage)); @@ -395,22 +397,19 @@ http_client::http_client(const uri &base_uri, const http_client_config &client_c http_client::~http_client() CPPREST_NOEXCEPT {} -const http_client_config & http_client::client_config() const -{ - return m_pipeline->m_last_stage->client_config(); -} +const http_client_config& http_client::client_config() const { return m_pipeline->m_last_stage->client_config(); } -const uri & http_client::base_uri() const -{ - return m_pipeline->m_last_stage->base_uri(); -} +const uri& http_client::base_uri() const { return m_pipeline->m_last_stage->base_uri(); } // Macros to help build string at compile time and avoid overhead. #define STRINGIFY(x) _XPLATSTR(#x) #define TOSTRING(x) STRINGIFY(x) -#define USERAGENT _XPLATSTR("cpprestsdk/") TOSTRING(CPPREST_VERSION_MAJOR) _XPLATSTR(".") TOSTRING(CPPREST_VERSION_MINOR) _XPLATSTR(".") TOSTRING(CPPREST_VERSION_REVISION) +#define USERAGENT \ + _XPLATSTR("cpprestsdk/") \ + TOSTRING(CPPREST_VERSION_MAJOR) \ + _XPLATSTR(".") TOSTRING(CPPREST_VERSION_MINOR) _XPLATSTR(".") TOSTRING(CPPREST_VERSION_REVISION) -pplx::task http_client::request(http_request request, const pplx::cancellation_token &token) +pplx::task http_client::request(http_request request, const pplx::cancellation_token& token) { if (!request.headers().has(header_names::user_agent)) { @@ -422,5 +421,6 @@ pplx::task http_client::request(http_request request, const pplx: return m_pipeline->propagate(request); } - -}}} +} // namespace client +} // namespace http +} // namespace web diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 0ef90695a5..3292447061 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -2,7 +2,7 @@ * Copyright (C) Microsoft. All rights reserved. * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * - * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * HTTP Library: Client-side APIs. * @@ -10,15 +10,15 @@ * * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk * - * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" -#include -#include "../common/internal_http_helpers.h" #include "../common/connection_pool_helpers.h" +#include "../common/internal_http_helpers.h" #include "cpprest/asyncrt_utils.h" +#include #if defined(__clang__) #pragma clang diagnostic push @@ -39,9 +39,9 @@ #error "Cpp rest SDK requires c++11 smart pointer support from boost" #endif +#include "../common/x509_cert_utilities.h" #include "cpprest/base_uri.h" #include "cpprest/details/http_helpers.h" -#include "../common/x509_cert_utilities.h" #include "http_client_impl.h" #include "pplx/threadpool.h" #include @@ -1906,7 +1906,7 @@ pplx::task asio_client::propagate(http_request request) return result_task; } -} -} -} -} // namespaces +} // namespace details +} // namespace client +} // namespace http +} // namespace web diff --git a/Release/src/http/client/http_client_impl.h b/Release/src/http/client/http_client_impl.h index 067233ab63..384c9b2de6 100644 --- a/Release/src/http/client/http_client_impl.h +++ b/Release/src/http/client/http_client_impl.h @@ -1,49 +1,60 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Client-side APIs. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Client-side APIs. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include "cpprest/details/basic_types.h" #include "cpprest/astreambuf.h" +#include "cpprest/details/basic_types.h" #include "cpprest/http_client.h" #include "cpprest/http_msg.h" +#include #include #include -#include - -namespace web { namespace http { namespace details { +namespace web +{ +namespace http +{ +namespace details +{ /// /// Serialize the http_headers into name:value pairs separated by a carriage return and line feed. /// -utility::string_t flatten_http_headers(const http_headers &headers); +utility::string_t flatten_http_headers(const http_headers& headers); #if defined(_WIN32) /// /// Parses a string containing Http headers. /// -void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers); +void parse_headers_string(_Inout_z_ utf16char* headersStr, http_headers& headers); #endif -}}} - -namespace web { namespace http { namespace client { namespace details { +} // namespace details +} // namespace http +} // namespace web +namespace web +{ +namespace http +{ +namespace client +{ +namespace details +{ class _http_client_communicator; // Request context encapsulating everything necessary for creating and responding to a request. class request_context { public: - // Destructor to clean up any held resources. virtual ~request_context() {} @@ -58,14 +69,14 @@ class request_context /// void complete_request(utility::size64_t body_size); - void report_error(unsigned long error_code, const std::string &errorMessage); + void report_error(unsigned long error_code, const std::string& errorMessage); #ifdef _WIN32 - void report_error(unsigned long error_code, const std::wstring &errorMessage); + void report_error(unsigned long error_code, const std::wstring& errorMessage); #endif template - void report_exception(const _ExceptionType &e) + void report_exception(const _ExceptionType& e) { report_exception(std::make_exception_ptr(e)); } @@ -98,8 +109,7 @@ class request_context std::unique_ptr m_decompressor; protected: - - request_context(const std::shared_ptr<_http_client_communicator> &client, const http_request &request); + request_context(const std::shared_ptr<_http_client_communicator>& client, const http_request& request); virtual void finish(); }; @@ -111,34 +121,33 @@ class request_context class _http_client_communicator : public http_pipeline_stage { public: - virtual ~_http_client_communicator() override = default; // Asynchronously send a HTTP request and process the response. - void async_send_request(const std::shared_ptr &request); + void async_send_request(const std::shared_ptr& request); void finish_request(); const http_client_config& client_config() const; - const uri & base_uri() const; + const uri& base_uri() const; protected: _http_client_communicator(http::uri&& address, http_client_config&& client_config); // HTTP client implementations must implement send_request. - virtual void send_request(_In_ const std::shared_ptr &request) = 0; + virtual void send_request(_In_ const std::shared_ptr& request) = 0; // URI to connect to. const http::uri m_uri; pplx::extensibility::critical_section_t m_client_lock; -private: +private: http_client_config m_client_config; // Wraps opening the client around sending a request. - void async_send_request_impl(const std::shared_ptr &request); + void async_send_request_impl(const std::shared_ptr& request); // Queue used to guarantee ordering of requests, when applicable. std::queue> m_requests_queue; @@ -148,6 +157,10 @@ class _http_client_communicator : public http_pipeline_stage /// /// Factory function implemented by the separate platforms to construct their subclasses of _http_client_communicator /// -std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, http_client_config&& client_config); +std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, + http_client_config&& client_config); -}}}} +} // namespace details +} // namespace client +} // namespace http +} // namespace web diff --git a/Release/src/http/client/http_client_msg.cpp b/Release/src/http/client/http_client_msg.cpp index dd7f3dc5c5..4ed3be82de 100644 --- a/Release/src/http/client/http_client_msg.cpp +++ b/Release/src/http/client/http_client_msg.cpp @@ -1,33 +1,35 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Request and reply message definitions (client side). -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Request and reply message definitions (client side). + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "../common/internal_http_helpers.h" #include "cpprest/asyncrt_utils.h" -namespace web { namespace http +namespace web +{ +namespace http { - uri details::_http_request::relative_uri() const { // If the listener path is empty, then just return the request URI. - if(m_listener_path.empty() || m_listener_path == _XPLATSTR("/")) + if (m_listener_path.empty() || m_listener_path == _XPLATSTR("/")) { return m_uri.resource(); } utility::string_t prefix = uri::decode(m_listener_path); utility::string_t path = uri::decode(m_uri.resource().to_string()); - if(path.empty()) + if (path.empty()) { path = _XPLATSTR("/"); } @@ -55,10 +57,7 @@ uri details::_http_request::absolute_uri() const } } -void details::_http_request::set_request_uri(const uri& relative) -{ - m_uri = relative; -} +void details::_http_request::set_request_uri(const uri& relative) { m_uri = relative; } utility::string_t details::_http_request::to_string() const { @@ -99,4 +98,5 @@ utility::string_t details::_http_response::to_string() const return result; } -}} // namespace web::http +} // namespace http +} // namespace web diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index e960058fd9..70cf9f7257 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -1,25 +1,24 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Client-side APIs. -* -* This file contains the implementation for Windows Desktop, based on WinHTTP. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Client-side APIs. + * + * This file contains the implementation for Windows Desktop, based on WinHTTP. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include -#include - -#include "cpprest/http_headers.h" #include "../common/x509_cert_utilities.h" +#include "cpprest/http_headers.h" #include "http_client_impl.h" +#include +#include #ifndef CPPREST_TARGET_XP #include @@ -30,31 +29,32 @@ namespace struct security_failure_message { std::uint32_t flag; - const char * text; + const char* text; }; CPPREST_CONSTEXPR security_failure_message g_security_failure_messages[] = { - { WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED, - "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED failed to check revocation status."}, - { WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT, - "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT SSL certificate is invalid."}, - { WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED, - "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED SSL certificate was revoked."}, - { WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA, - "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA SSL invalid CA."}, - { WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID, - "WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID SSL common name does not match."}, - { WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID, - "WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID SLL certificate is expired."}, - { WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR, - "WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR internal error."}, + {WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED, + "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED failed to check revocation status."}, + {WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT, + "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT SSL certificate is invalid."}, + {WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED, + "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED SSL certificate was revoked."}, + {WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA, "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA SSL invalid CA."}, + {WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID, + "WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID SSL common name does not match."}, + {WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID, + "WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID SLL certificate is expired."}, + {WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR, + "WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR internal error."}, }; std::string generate_security_failure_message(std::uint32_t flags) { std::string result("SSL Error:"); - for (const auto& message : g_security_failure_messages) { - if (flags & message.flag) { + for (const auto& message : g_security_failure_messages) + { + if (flags & message.flag) + { result.push_back(' '); result.append(message.text); } @@ -63,7 +63,7 @@ std::string generate_security_failure_message(std::uint32_t flags) return result; } -} // unnamed namespace +} // unnamed namespace namespace web { namespace http @@ -72,17 +72,15 @@ namespace client { namespace details { - // Helper function to query for the size of header values. -static void query_header_length(HINTERNET request_handle, DWORD header, DWORD &length) +static void query_header_length(HINTERNET request_handle, DWORD header, DWORD& length) { - WinHttpQueryHeaders( - request_handle, - header, - WINHTTP_HEADER_NAME_BY_INDEX, - WINHTTP_NO_OUTPUT_BUFFER, - &length, - WINHTTP_NO_HEADER_INDEX); + WinHttpQueryHeaders(request_handle, + header, + WINHTTP_HEADER_NAME_BY_INDEX, + WINHTTP_NO_OUTPUT_BUFFER, + &length, + WINHTTP_NO_HEADER_INDEX); } // Helper function to get the status code from a WinHTTP response. @@ -92,23 +90,24 @@ static http::status_code parse_status_code(HINTERNET request_handle) query_header_length(request_handle, WINHTTP_QUERY_STATUS_CODE, length); utility::string_t buffer; buffer.resize(length); - WinHttpQueryHeaders( - request_handle, - WINHTTP_QUERY_STATUS_CODE, - WINHTTP_HEADER_NAME_BY_INDEX, - &buffer[0], - &length, - WINHTTP_NO_HEADER_INDEX); + WinHttpQueryHeaders(request_handle, + WINHTTP_QUERY_STATUS_CODE, + WINHTTP_HEADER_NAME_BY_INDEX, + &buffer[0], + &length, + WINHTTP_NO_HEADER_INDEX); return (unsigned short)_wtoi(buffer.c_str()); } // Helper function to trim leading and trailing null characters from a string. -static void trim_nulls(utility::string_t &str) +static void trim_nulls(utility::string_t& str) { size_t index; - for (index = 0; index < str.size() && str[index] == 0; ++index); + for (index = 0; index < str.size() && str[index] == 0; ++index) + ; str.erase(0, index); - for (index = str.size(); index > 0 && str[index - 1] == 0; --index); + for (index = str.size(); index > 0 && str[index - 1] == 0; --index) + ; str.erase(index); } @@ -120,13 +119,12 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle) query_header_length(request_handle, WINHTTP_QUERY_STATUS_TEXT, length); phrase.resize(length); - WinHttpQueryHeaders( - request_handle, - WINHTTP_QUERY_STATUS_TEXT, - WINHTTP_HEADER_NAME_BY_INDEX, - &phrase[0], - &length, - WINHTTP_NO_HEADER_INDEX); + WinHttpQueryHeaders(request_handle, + WINHTTP_QUERY_STATUS_TEXT, + WINHTTP_HEADER_NAME_BY_INDEX, + &phrase[0], + &length, + WINHTTP_NO_HEADER_INDEX); // WinHTTP reports back the wrong length, trim any null characters. trim_nulls(phrase); return phrase; @@ -135,9 +133,9 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle) /// /// Parses a string containing HTTP headers. /// -static void parse_winhttp_headers(HINTERNET request_handle, _In_z_ utf16char *headersStr, http_response &response) +static void parse_winhttp_headers(HINTERNET request_handle, _In_z_ utf16char* headersStr, http_response& response) { - //Clear the header map for each new response; otherwise, the header values will be combined. + // Clear the header map for each new response; otherwise, the header values will be combined. response.headers().clear(); // Status code and reason phrase. @@ -148,7 +146,7 @@ static void parse_winhttp_headers(HINTERNET request_handle, _In_z_ utf16char *he } // Helper function to build error messages. -static std::string build_error_msg(unsigned long code, const std::string &location) +static std::string build_error_msg(unsigned long code, const std::string& location) { std::string msg(location); msg.append(": "); @@ -159,22 +157,16 @@ static std::string build_error_msg(unsigned long code, const std::string &locati } // Helper function to build an error message from a WinHTTP async result. -static std::string build_error_msg(_In_ WINHTTP_ASYNC_RESULT *error_result) +static std::string build_error_msg(_In_ WINHTTP_ASYNC_RESULT* error_result) { - switch(error_result->dwResult) + switch (error_result->dwResult) { - case API_RECEIVE_RESPONSE: - return build_error_msg(error_result->dwError, "WinHttpReceiveResponse"); - case API_QUERY_DATA_AVAILABLE: - return build_error_msg(error_result->dwError, "WinHttpQueryDataAvaliable"); - case API_READ_DATA: - return build_error_msg(error_result->dwError, "WinHttpReadData"); - case API_WRITE_DATA: - return build_error_msg(error_result->dwError, "WinHttpWriteData"); - case API_SEND_REQUEST: - return build_error_msg(error_result->dwError, "WinHttpSendRequest"); - default: - return build_error_msg(error_result->dwError, "Unknown WinHTTP Function"); + case API_RECEIVE_RESPONSE: return build_error_msg(error_result->dwError, "WinHttpReceiveResponse"); + case API_QUERY_DATA_AVAILABLE: return build_error_msg(error_result->dwError, "WinHttpQueryDataAvaliable"); + case API_READ_DATA: return build_error_msg(error_result->dwError, "WinHttpReadData"); + case API_WRITE_DATA: return build_error_msg(error_result->dwError, "WinHttpWriteData"); + case API_SEND_REQUEST: return build_error_msg(error_result->dwError, "WinHttpSendRequest"); + default: return build_error_msg(error_result->dwError, "Unknown WinHTTP Function"); } } @@ -185,9 +177,7 @@ class memory_holder size_t m_size; public: - memory_holder() : m_externalData(nullptr), m_size(0) - { - } + memory_holder() : m_externalData(nullptr), m_size(0) {} void allocate_space(size_t length) { @@ -198,27 +188,18 @@ class memory_holder m_externalData = nullptr; } - inline void reassign_to(_In_opt_ uint8_t *block, size_t length) + inline void reassign_to(_In_opt_ uint8_t* block, size_t length) { assert(block != nullptr); m_externalData = block; m_size = length; } - inline bool is_internally_allocated() const - { - return m_externalData == nullptr; - } + inline bool is_internally_allocated() const { return m_externalData == nullptr; } - inline uint8_t* get() - { - return is_internally_allocated() ? &m_internalData[0] : m_externalData ; - } + inline uint8_t* get() { return is_internally_allocated() ? &m_internalData[0] : m_externalData; } - inline size_t size() const - { - return is_internally_allocated() ? m_internalData.size() : m_size; - } + inline size_t size() const { return is_internally_allocated() ? m_internalData.size() : m_size; } }; // Possible ways a message body can be sent/received. @@ -233,21 +214,18 @@ enum msg_body_type class winhttp_request_context final : public request_context { public: - // Factory function to create requests on the heap. - static std::shared_ptr create_request_context(const std::shared_ptr<_http_client_communicator> &client, const http_request &request) + static std::shared_ptr create_request_context( + const std::shared_ptr<_http_client_communicator>& client, const http_request& request) { std::shared_ptr ret(new winhttp_request_context(client, request)); ret->m_self_reference = ret; return std::move(ret); } - ~winhttp_request_context() - { - cleanup(); - } + ~winhttp_request_context() { cleanup(); } - void allocate_request_space(_In_opt_ uint8_t *block, size_t length) + void allocate_request_space(_In_opt_ uint8_t* block, size_t length) { if (block == nullptr) m_body_data.allocate_space(length); @@ -255,7 +233,7 @@ class winhttp_request_context final : public request_context m_body_data.reassign_to(block, length); } - void allocate_reply_space(_In_opt_ uint8_t *block, size_t length) + void allocate_reply_space(_In_opt_ uint8_t* block, size_t length) { if (block == nullptr) m_body_data.allocate_space(length); @@ -263,10 +241,7 @@ class winhttp_request_context final : public request_context m_body_data.reassign_to(block, length); } - bool is_externally_allocated() const - { - return !m_body_data.is_internally_allocated(); - } + bool is_externally_allocated() const { return !m_body_data.is_internally_allocated(); } HINTERNET m_request_handle; std::weak_ptr* m_request_context; @@ -280,14 +255,12 @@ class winhttp_request_context final : public request_context std::char_traits::pos_type m_startingPosition; - // If the user specified that to guarantee data buffering of request data, in case of challenged authentication requests, etc... - // Then if the request stream buffer doesn't support seeking we need to copy the body chunks as it is sent. + // If the user specified that to guarantee data buffering of request data, in case of challenged authentication + // requests, etc... Then if the request stream buffer doesn't support seeking we need to copy the body chunks as it + // is sent. concurrency::streams::istream m_readStream; std::unique_ptr>> m_readBufferCopy; - virtual concurrency::streams::streambuf _get_readbuffer() - { - return m_readStream.streambuf(); - } + virtual concurrency::streams::streambuf _get_readbuffer() { return m_readStream.streambuf(); } // This self reference will keep us alive until finish() is called. std::shared_ptr m_self_reference; @@ -298,7 +271,13 @@ class winhttp_request_context final : public request_context { public: compression_state() - : m_acquired(nullptr), m_bytes_read(0), m_bytes_processed(0), m_needs_flush(false), m_started(false), m_done(false), m_chunked(false) + : m_acquired(nullptr) + , m_bytes_read(0) + , m_bytes_processed(0) + , m_needs_flush(false) + , m_started(false) + , m_done(false) + , m_chunked(false) { } @@ -315,9 +294,11 @@ class winhttp_request_context final : public request_context , m_chunked(other.m_chunked) , m_chunk_bytes(other.m_chunk_bytes) , m_chunk(std::move(other.m_chunk)) - {} + { + } compression_state& operator=(const compression_state&) = delete; - compression_state& operator=(compression_state&& other) { + compression_state& operator=(compression_state&& other) + { m_buffer = std::move(other.m_buffer); m_acquired = other.m_acquired; m_bytes_read = other.m_bytes_read; @@ -337,7 +318,12 @@ class winhttp_request_context final : public request_context { public: _chunk_helper() - : m_bytes_remaining(0), m_chunk_size(true), m_chunk_delim(false), m_expect_linefeed(false), m_ignore(false), m_trailer(false) + : m_bytes_remaining(0) + , m_chunk_size(true) + , m_chunk_delim(false) + , m_expect_linefeed(false) + , m_ignore(false) + , m_trailer(false) { } @@ -345,7 +331,7 @@ class winhttp_request_context final : public request_context // chunk and its trailing delimiter has been processed. Otherwise, offset and length bound the // portion of buffer that represents a contiguous (and possibly partial) chunk of consumable // data; offset+length is the total number of bytes processed from the buffer on this pass. - bool process_buffer(uint8_t *buffer, size_t buffer_size, size_t &offset, size_t &length) + bool process_buffer(uint8_t* buffer, size_t buffer_size, size_t& offset, size_t& length) { bool done = false; size_t n = 0; @@ -375,8 +361,8 @@ class winhttp_request_context final : public request_context // We're at the end of the data we need to ignore _ASSERTE(m_chunk_size || m_chunk_delim); m_ignore = false; - m_chunk_delim = false; // this is only set if we're at the end of the message - } // else we're at the end of a trailer field + m_chunk_delim = false; // this is only set if we're at the end of the message + } // else we're at the end of a trailer field m_expect_linefeed = true; } else if (m_chunk_delim) @@ -429,7 +415,8 @@ class winhttp_request_context final : public request_context if (buffer[n] != '\r') { // The data stream does not conform to "chunked" encoding - throw http_exception(status_codes::BadRequest, "Transfer-Encoding malformed chunk delimiter"); + throw http_exception(status_codes::BadRequest, + "Transfer-Encoding malformed chunk delimiter"); } // We found the carriage return; look for the linefeed @@ -467,7 +454,8 @@ class winhttp_request_context final : public request_context else { // The data stream does not conform to "chunked" encoding - throw http_exception(status_codes::BadRequest, "Transfer-Encoding malformed chunk size or extension"); + throw http_exception(status_codes::BadRequest, + "Transfer-Encoding malformed chunk size or extension"); } } else @@ -475,7 +463,7 @@ class winhttp_request_context final : public request_context if (m_bytes_remaining) { // We're at the offset of a chunk of consumable data; let the caller process it - l = std::min(m_bytes_remaining, buffer_size-n); + l = std::min(m_bytes_remaining, buffer_size - n); m_bytes_remaining -= l; if (!m_bytes_remaining) { @@ -505,23 +493,24 @@ class winhttp_request_context final : public request_context } private: - size_t m_bytes_remaining; // the number of bytes remaining in the chunk we're currently processing - bool m_chunk_size; // if true, we're processing a chunk size or its trailing delimiter - bool m_chunk_delim; // if true, we're processing a delimiter between a chunk and the next chunk's size - bool m_expect_linefeed; // if true, we're processing a delimiter, and we've already seen its carriage return - bool m_ignore; // if true, we're processing a chunk extension or trailer, which we don't support - bool m_trailer; // if true, we're processing (and ignoring) a trailer field; m_ignore is also true + size_t m_bytes_remaining; // the number of bytes remaining in the chunk we're currently processing + bool m_chunk_size; // if true, we're processing a chunk size or its trailing delimiter + bool m_chunk_delim; // if true, we're processing a delimiter between a chunk and the next chunk's size + bool m_expect_linefeed; // if true, we're processing a delimiter, and we've already seen its carriage return + bool m_ignore; // if true, we're processing a chunk extension or trailer, which we don't support + bool m_trailer; // if true, we're processing (and ignoring) a trailer field; m_ignore is also true }; - std::vector m_buffer; // we read data from the stream into this before compressing - uint8_t *m_acquired; // we use this in place of m_buffer if the stream has directly-accessible data available - size_t m_bytes_read; // we most recently read this many bytes, which may be less than m_buffer.size() - size_t m_bytes_processed; // we've compressed this many bytes of m_bytes_read so far - bool m_needs_flush; // we've read and compressed all bytes, but the compressor still has compressed bytes to give us - bool m_started; // we've sent at least some number of bytes to m_decompressor - bool m_done; // we've read, compressed, and consumed all bytes - bool m_chunked; // if true, we need to decode and decompress a transfer-encoded message - size_t m_chunk_bytes; // un-decompressed bytes remaining in the most-recently-obtained data from m_chunk + std::vector m_buffer; // we read data from the stream into this before compressing + uint8_t* m_acquired; // we use this in place of m_buffer if the stream has directly-accessible data available + size_t m_bytes_read; // we most recently read this many bytes, which may be less than m_buffer.size() + size_t m_bytes_processed; // we've compressed this many bytes of m_bytes_read so far + bool m_needs_flush; // we've read and compressed all bytes, but the compressor still has compressed bytes to + // give us + bool m_started; // we've sent at least some number of bytes to m_decompressor + bool m_done; // we've read, compressed, and consumed all bytes + bool m_chunked; // if true, we need to decode and decompress a transfer-encoded message + size_t m_chunk_bytes; // un-decompressed bytes remaining in the most-recently-obtained data from m_chunk std::unique_ptr<_chunk_helper> m_chunk; } m_compression_state; @@ -541,7 +530,7 @@ class winhttp_request_context final : public request_context m_compression_state.m_acquired = nullptr; } - if(m_request_handle != nullptr) + if (m_request_handle != nullptr) { auto tmp_handle = m_request_handle; m_request_handle = nullptr; @@ -566,11 +555,7 @@ class winhttp_request_context final : public request_context winhttp_cert_context certContext; DWORD bufferSize = sizeof(certContext.raw); - if (!WinHttpQueryOption( - m_request_handle, - WINHTTP_OPTION_SERVER_CERT_CONTEXT, - &certContext.raw, - &bufferSize)) + if (!WinHttpQueryOption(m_request_handle, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &certContext.raw, &bufferSize)) { auto errorCode = GetLastError(); if (errorCode == HRESULT_CODE(WININET_E_INCORRECT_HANDLE_STATE)) @@ -579,16 +564,16 @@ class winhttp_request_context final : public request_context return; } - report_error(errorCode, build_error_msg(errorCode, - "WinHttpQueryOption WINHTTP_OPTION_SERVER_CERT_CONTEXT")); + report_error(errorCode, + build_error_msg(errorCode, "WinHttpQueryOption WINHTTP_OPTION_SERVER_CERT_CONTEXT")); cleanup(); return; } const auto encodedFirst = certContext.raw->pbCertEncoded; const auto encodedLast = encodedFirst + certContext.raw->cbCertEncoded; - if (certContext.raw->cbCertEncoded == m_cachedEncodedCert.size() - && std::equal(encodedFirst, encodedLast, m_cachedEncodedCert.begin())) + if (certContext.raw->cbCertEncoded == m_cachedEncodedCert.size() && + std::equal(encodedFirst, encodedLast, m_cachedEncodedCert.begin())) { // already validated OK return; @@ -597,7 +582,7 @@ class winhttp_request_context final : public request_context char oidPkixKpServerAuth[] = szOID_PKIX_KP_SERVER_AUTH; char oidServerGatedCrypto[] = szOID_SERVER_GATED_CRYPTO; char oidSgcNetscape[] = szOID_SGC_NETSCAPE; - char *chainUses[] = { + char* chainUses[] = { oidPkixKpServerAuth, oidServerGatedCrypto, oidSgcNetscape, @@ -606,25 +591,22 @@ class winhttp_request_context final : public request_context winhttp_cert_chain_context chainContext; CERT_CHAIN_PARA chainPara = {sizeof(chainPara)}; chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; - chainPara.RequestedUsage.Usage.cUsageIdentifier = - sizeof(chainUses) / sizeof(char *); + chainPara.RequestedUsage.Usage.cUsageIdentifier = sizeof(chainUses) / sizeof(char*); chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = chainUses; // note that the following chain only checks the end certificate; we // assume WinHTTP already validated everything but the common name. - if (!CertGetCertificateChain( - NULL, - certContext.raw, - nullptr, - certContext.raw->hCertStore, - &chainPara, - CERT_CHAIN_CACHE_END_CERT, - NULL, - &chainContext.raw)) + if (!CertGetCertificateChain(NULL, + certContext.raw, + nullptr, + certContext.raw->hCertStore, + &chainPara, + CERT_CHAIN_CACHE_END_CERT, + NULL, + &chainContext.raw)) { auto errorCode = GetLastError(); - report_error(errorCode, build_error_msg(errorCode, - "CertGetCertificateChain")); + report_error(errorCode, build_error_msg(errorCode, "CertGetCertificateChain")); cleanup(); return; } @@ -633,33 +615,27 @@ class winhttp_request_context final : public request_context {sizeof(policyData)}, AUTHTYPE_SERVER, // we assume WinHTTP already checked these: - 0x00000080 /* SECURITY_FLAG_IGNORE_REVOCATION */ + 0x00000080 /* SECURITY_FLAG_IGNORE_REVOCATION */ | 0x00000100 /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */ | 0x00000200 /* SECURITY_FLAG_IGNORE_WRONG_USAGE */ | 0x00002000 /* SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */, &m_customCnCheck[0], - }; + }; CERT_CHAIN_POLICY_PARA policyPara = {sizeof(policyPara)}; policyPara.pvExtraPolicyPara = &policyData; CERT_CHAIN_POLICY_STATUS policyStatus = {sizeof(policyStatus)}; - if (!CertVerifyCertificateChainPolicy( - CERT_CHAIN_POLICY_SSL, - chainContext.raw, - &policyPara, - &policyStatus)) + if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext.raw, &policyPara, &policyStatus)) { auto errorCode = GetLastError(); - report_error(errorCode, build_error_msg(errorCode, - "CertVerifyCertificateChainPolicy")); + report_error(errorCode, build_error_msg(errorCode, "CertVerifyCertificateChainPolicy")); cleanup(); return; } if (policyStatus.dwError) { - report_error(policyStatus.dwError, - build_error_msg(policyStatus.dwError, "Incorrect common name")); + report_error(policyStatus.dwError, build_error_msg(policyStatus.dwError, "Incorrect common name")); cleanup(); return; } @@ -668,7 +644,6 @@ class winhttp_request_context final : public request_context } protected: - virtual void finish() override { request_context::finish(); @@ -678,27 +653,26 @@ class winhttp_request_context final : public request_context } private: - utility::string_t m_customCnCheck; std::vector m_cachedEncodedCert; // Can only create on the heap using factory function. - winhttp_request_context(const std::shared_ptr<_http_client_communicator> &client, const http_request &request) - : request_context(client, request), - m_request_handle(nullptr), - m_request_context(nullptr), - m_bodyType(no_body), - m_startingPosition(std::char_traits::eof()), - m_body_data(), - m_remaining_to_write(0), - m_proxy_authentication_tried(false), - m_server_authentication_tried(false), - m_readStream(request.body()) + winhttp_request_context(const std::shared_ptr<_http_client_communicator>& client, const http_request& request) + : request_context(client, request) + , m_request_handle(nullptr) + , m_request_context(nullptr) + , m_bodyType(no_body) + , m_startingPosition(std::char_traits::eof()) + , m_body_data() + , m_remaining_to_write(0) + , m_proxy_authentication_tried(false) + , m_server_authentication_tried(false) + , m_readStream(request.body()) { } }; -static DWORD ChooseAuthScheme( DWORD dwSupportedSchemes ) +static DWORD ChooseAuthScheme(DWORD dwSupportedSchemes) { // It is the server's responsibility only to accept // authentication schemes that provide a sufficient @@ -707,15 +681,15 @@ static DWORD ChooseAuthScheme( DWORD dwSupportedSchemes ) // The client is also obligated only to use an authentication // scheme that adequately protects its username and password. // - if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NEGOTIATE ) + if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NEGOTIATE) return WINHTTP_AUTH_SCHEME_NEGOTIATE; - else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NTLM ) + else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NTLM) return WINHTTP_AUTH_SCHEME_NTLM; - else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_PASSPORT ) + else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_PASSPORT) return WINHTTP_AUTH_SCHEME_PASSPORT; - else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_DIGEST ) + else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_DIGEST) return WINHTTP_AUTH_SCHEME_DIGEST; - else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_BASIC ) + else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_BASIC) return WINHTTP_AUTH_SCHEME_BASIC; else return 0; @@ -725,36 +699,25 @@ static DWORD ChooseAuthScheme( DWORD dwSupportedSchemes ) // properly freed. struct proxy_info : WINHTTP_PROXY_INFO { - proxy_info() - { - memset( this, 0, sizeof(WINHTTP_PROXY_INFO) ); - } + proxy_info() { memset(this, 0, sizeof(WINHTTP_PROXY_INFO)); } ~proxy_info() { - if ( lpszProxy ) - ::GlobalFree(lpszProxy); - if ( lpszProxyBypass ) - ::GlobalFree(lpszProxyBypass); + if (lpszProxy) ::GlobalFree(lpszProxy); + if (lpszProxyBypass) ::GlobalFree(lpszProxyBypass); } }; struct ie_proxy_config : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG { - ie_proxy_config() - { - memset( this, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG) ); - } - - ~ie_proxy_config() - { - if ( lpszAutoConfigUrl ) - ::GlobalFree(lpszAutoConfigUrl); - if ( lpszProxy ) - ::GlobalFree(lpszProxy); - if ( lpszProxyBypass ) - ::GlobalFree(lpszProxyBypass); - } + ie_proxy_config() { memset(this, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG)); } + + ~ie_proxy_config() + { + if (lpszAutoConfigUrl) ::GlobalFree(lpszAutoConfigUrl); + if (lpszProxy) ::GlobalFree(lpszProxy); + if (lpszProxyBypass) ::GlobalFree(lpszProxyBypass); + } }; // WinHTTP client. @@ -766,27 +729,25 @@ class winhttp_client final : public _http_client_communicator , m_secure(m_uri.scheme() == _XPLATSTR("https")) , m_opened(false) , m_hSession(nullptr) - , m_hConnection(nullptr) { } + , m_hConnection(nullptr) + { + } winhttp_client(const winhttp_client&) = delete; - winhttp_client &operator=(const winhttp_client&) = delete; + winhttp_client& operator=(const winhttp_client&) = delete; // Closes session. ~winhttp_client() { - if(m_hConnection != nullptr) + if (m_hConnection != nullptr) { WinHttpCloseHandle(m_hConnection); } - if(m_hSession != nullptr) + if (m_hSession != nullptr) { // Unregister the callback. - WinHttpSetStatusCallback( - m_hSession, - nullptr, - WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, - NULL); + WinHttpSetStatusCallback(m_hSession, nullptr, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL); WinHttpCloseHandle(m_hSession); } @@ -807,7 +768,6 @@ class winhttp_client final : public _http_client_communicator } protected: - // Open session and connection with the server. unsigned long open() { @@ -834,12 +794,12 @@ class winhttp_client final : public _http_client_communicator const auto& config = client_config(); - if(config.proxy().is_disabled()) + if (config.proxy().is_disabled()) { access_type = WINHTTP_ACCESS_TYPE_NO_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; } - else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) + else if (config.proxy().is_default() || config.proxy().is_auto_discovery()) { // Use the default WinHTTP proxy by default. access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; @@ -897,10 +857,11 @@ class winhttp_client final : public _http_client_communicator { _ASSERTE(config.proxy().is_specified()); access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - // WinHttpOpen cannot handle trailing slash in the name, so here is some string gymnastics to keep WinHttpOpen happy - // proxy_str is intentionally declared at the function level to avoid pointing to the string in the destructed object + // WinHttpOpen cannot handle trailing slash in the name, so here is some string gymnastics to keep + // WinHttpOpen happy proxy_str is intentionally declared at the function level to avoid pointing to the + // string in the destructed object uri = config.proxy().address(); - if(uri.is_port_default()) + if (uri.is_port_default()) { proxy_name = uri.host().c_str(); } @@ -918,13 +879,8 @@ class winhttp_client final : public _http_client_communicator } // Open session. - m_hSession = WinHttpOpen( - NULL, - access_type, - proxy_name, - proxy_bypass, - WINHTTP_FLAG_ASYNC); - if(!m_hSession) + m_hSession = WinHttpOpen(NULL, access_type, proxy_name, proxy_bypass, WINHTTP_FLAG_ASYNC); + if (!m_hSession) { return GetLastError(); } @@ -932,32 +888,31 @@ class winhttp_client final : public _http_client_communicator // Set timeouts. int milliseconds = static_cast(config.timeout().count()); milliseconds = std::max(milliseconds, 1); - if (!WinHttpSetTimeouts(m_hSession, - milliseconds, - milliseconds, - milliseconds, - milliseconds)) + if (!WinHttpSetTimeouts(m_hSession, milliseconds, milliseconds, milliseconds, milliseconds)) { return GetLastError(); } - if(config.guarantee_order()) + if (config.guarantee_order()) { // Set max connection to use per server to 1. DWORD maxConnections = 1; - if(!WinHttpSetOption(m_hSession, WINHTTP_OPTION_MAX_CONNS_PER_SERVER, &maxConnections, sizeof(maxConnections))) + if (!WinHttpSetOption( + m_hSession, WINHTTP_OPTION_MAX_CONNS_PER_SERVER, &maxConnections, sizeof(maxConnections))) { return GetLastError(); } } - //Enable TLS 1.1 and 1.2 + // Enable TLS 1.1 and 1.2 #if !defined(CPPREST_TARGET_XP) BOOL win32_result(FALSE); - DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2); - win32_result = ::WinHttpSetOption(m_hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols)); - if(FALSE == win32_result) + DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | + WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2); + win32_result = ::WinHttpSetOption( + m_hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols)); + if (FALSE == win32_result) { return GetLastError(); } @@ -966,27 +921,23 @@ class winhttp_client final : public _http_client_communicator config._invoke_nativesessionhandle_options(m_hSession); // Register asynchronous callback. - if(WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback( - m_hSession, - &winhttp_client::completion_callback, - WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS - | WINHTTP_CALLBACK_FLAG_HANDLES - | WINHTTP_CALLBACK_FLAG_SECURE_FAILURE - | WINHTTP_CALLBACK_FLAG_SEND_REQUEST, - 0)) + if (WINHTTP_INVALID_STATUS_CALLBACK == + WinHttpSetStatusCallback(m_hSession, + &winhttp_client::completion_callback, + WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | WINHTTP_CALLBACK_FLAG_HANDLES | + WINHTTP_CALLBACK_FLAG_SECURE_FAILURE | WINHTTP_CALLBACK_FLAG_SEND_REQUEST, + 0)) { return GetLastError(); } // Open connection. - unsigned int port = m_uri.is_port_default() ? (m_secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT) : m_uri.port(); - m_hConnection = WinHttpConnect( - m_hSession, - m_uri.host().c_str(), - (INTERNET_PORT)port, - 0); + unsigned int port = m_uri.is_port_default() + ? (m_secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT) + : m_uri.port(); + m_hConnection = WinHttpConnect(m_hSession, m_uri.host().c_str(), (INTERNET_PORT)port, 0); - if(m_hConnection == nullptr) + if (m_hConnection == nullptr) { return GetLastError(); } @@ -996,7 +947,7 @@ class winhttp_client final : public _http_client_communicator } // Start sending request. - void send_request(_In_ const std::shared_ptr &request) + void send_request(_In_ const std::shared_ptr& request) { // First see if we need to be opened. unsigned long error = open(); @@ -1009,20 +960,21 @@ class winhttp_client final : public _http_client_communicator return; } - http_request &msg = request->m_request; - http_headers &headers = msg.headers(); - std::shared_ptr winhttp_context = std::static_pointer_cast(request); + http_request& msg = request->m_request; + http_headers& headers = msg.headers(); + std::shared_ptr winhttp_context = + std::static_pointer_cast(request); std::weak_ptr weak_winhttp_context = winhttp_context; proxy_info info; bool proxy_info_required = false; - if(m_proxy_auto_config) + if (m_proxy_auto_config) { WINHTTP_AUTOPROXY_OPTIONS autoproxy_options; - memset( &autoproxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS) ); + memset(&autoproxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS)); - if(m_proxy_auto_config_url.empty()) + if (m_proxy_auto_config_url.empty()) { autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; @@ -1035,12 +987,8 @@ class winhttp_client final : public _http_client_communicator autoproxy_options.fAutoLogonIfChallenged = TRUE; - auto result = WinHttpGetProxyForUrl( - m_hSession, - m_uri.to_string().c_str(), - &autoproxy_options, - &info ); - if(result) + auto result = WinHttpGetProxyForUrl(m_hSession, m_uri.to_string().c_str(), &autoproxy_options, &info); + if (result) { proxy_info_required = true; } @@ -1052,32 +1000,30 @@ class winhttp_client final : public _http_client_communicator // Need to form uri path, query, and fragment for this request. // Make sure to keep any path that was specified with the uri when the http_client was created. - const utility::string_t encoded_resource = http::uri_builder(m_uri).append(msg.relative_uri()).to_uri().resource().to_string(); + const utility::string_t encoded_resource = + http::uri_builder(m_uri).append(msg.relative_uri()).to_uri().resource().to_string(); // Open the request. - winhttp_context->m_request_handle = WinHttpOpenRequest( - m_hConnection, - msg.method().c_str(), - encoded_resource.c_str(), - nullptr, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_ESCAPE_DISABLE | (m_secure ? WINHTTP_FLAG_SECURE : 0)); - if(winhttp_context->m_request_handle == nullptr) + winhttp_context->m_request_handle = + WinHttpOpenRequest(m_hConnection, + msg.method().c_str(), + encoded_resource.c_str(), + nullptr, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_ESCAPE_DISABLE | (m_secure ? WINHTTP_FLAG_SECURE : 0)); + if (winhttp_context->m_request_handle == nullptr) { auto errorCode = GetLastError(); request->report_error(errorCode, build_error_msg(errorCode, "WinHttpOpenRequest")); return; } - if(proxy_info_required) + if (proxy_info_required) { auto result = WinHttpSetOption( - winhttp_context->m_request_handle, - WINHTTP_OPTION_PROXY, - &info, - sizeof(WINHTTP_PROXY_INFO) ); - if(!result) + winhttp_context->m_request_handle, WINHTTP_OPTION_PROXY, &info, sizeof(WINHTTP_PROXY_INFO)); + if (!result) { auto errorCode = GetLastError(); request->report_error(errorCode, build_error_msg(errorCode, "Setting proxy options")); @@ -1093,14 +1039,13 @@ class winhttp_client final : public _http_client_communicator DWORD data = WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH; auto result = WinHttpSetOption( - winhttp_context->m_request_handle, - WINHTTP_OPTION_AUTOLOGON_POLICY, - &data, - sizeof(data)); - if(!result) + winhttp_context->m_request_handle, WINHTTP_OPTION_AUTOLOGON_POLICY, &data, sizeof(data)); + if (!result) { auto errorCode = GetLastError(); - request->report_error(errorCode, build_error_msg(errorCode, "Setting autologon policy to WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH")); + request->report_error( + errorCode, + build_error_msg(errorCode, "Setting autologon policy to WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH")); return; } } @@ -1111,8 +1056,10 @@ class winhttp_client final : public _http_client_communicator { // if we are validating certificates, also turn on revocation checking DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; - if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, - &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) + if (!WinHttpSetOption(winhttp_context->m_request_handle, + WINHTTP_OPTION_ENABLE_FEATURE, + &dwEnableSSLRevocOpt, + sizeof(dwEnableSSLRevocOpt))) { auto errorCode = GetLastError(); request->report_error(errorCode, build_error_msg(errorCode, "Error enabling SSL revocation check")); @@ -1133,21 +1080,19 @@ class winhttp_client final : public _http_client_communicator } else { - ignoredCertificateValidationSteps = SECURITY_FLAG_IGNORE_UNKNOWN_CA - | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID - | SECURITY_FLAG_IGNORE_CERT_CN_INVALID - | SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; + ignoredCertificateValidationSteps = + SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; } - if(ignoredCertificateValidationSteps - && !WinHttpSetOption( - winhttp_context->m_request_handle, - WINHTTP_OPTION_SECURITY_FLAGS, - &ignoredCertificateValidationSteps, - sizeof(ignoredCertificateValidationSteps))) + if (ignoredCertificateValidationSteps && !WinHttpSetOption(winhttp_context->m_request_handle, + WINHTTP_OPTION_SECURITY_FLAGS, + &ignoredCertificateValidationSteps, + sizeof(ignoredCertificateValidationSteps))) { auto errorCode = GetLastError(); - request->report_error(errorCode, build_error_msg(errorCode, "Setting ignore server certificate verification")); + request->report_error(errorCode, + build_error_msg(errorCode, "Setting ignore server certificate verification")); return; } @@ -1163,7 +1108,7 @@ class winhttp_client final : public _http_client_communicator } if (content_length > 0) { - if ( msg.method() == http::methods::GET || msg.method() == http::methods::HEAD ) + if (msg.method() == http::methods::GET || msg.method() == http::methods::HEAD) { request->report_exception(http_exception(get_with_body_err_msg)); return; @@ -1194,13 +1139,12 @@ class winhttp_client final : public _http_client_communicator } // Add headers. - if(!flattened_headers.empty()) + if (!flattened_headers.empty()) { - if(!WinHttpAddRequestHeaders( - winhttp_context->m_request_handle, - flattened_headers.c_str(), - static_cast(flattened_headers.length()), - WINHTTP_ADDREQ_FLAG_ADD)) + if (!WinHttpAddRequestHeaders(winhttp_context->m_request_handle, + flattened_headers.c_str(), + static_cast(flattened_headers.length()), + WINHTTP_ADDREQ_FLAG_ADD)) { auto errorCode = GetLastError(); request->report_error(errorCode, build_error_msg(errorCode, "WinHttpAddRequestHeaders")); @@ -1209,17 +1153,18 @@ class winhttp_client final : public _http_client_communicator } // Register for notification on cancellation to abort this request. - if(msg._cancellation_token() != pplx::cancellation_token::none()) + if (msg._cancellation_token() != pplx::cancellation_token::none()) { // cancellation callback is unregistered when request is completed. - winhttp_context->m_cancellationRegistration = msg._cancellation_token().register_callback([weak_winhttp_context]() - { - // Call the WinHttpSendRequest API after WinHttpCloseHandle will give invalid handle error and we throw this exception. - // Call the cleanup to make the m_request_handle as nullptr, otherwise, Application Verifier will give AV exception on m_request_handle. - auto lock = weak_winhttp_context.lock(); - if (!lock) return; - lock->cleanup(); - }); + winhttp_context->m_cancellationRegistration = + msg._cancellation_token().register_callback([weak_winhttp_context]() { + // Call the WinHttpSendRequest API after WinHttpCloseHandle will give invalid handle error and we + // throw this exception. Call the cleanup to make the m_request_handle as nullptr, otherwise, + // Application Verifier will give AV exception on m_request_handle. + auto lock = weak_winhttp_context.lock(); + if (!lock) return; + lock->cleanup(); + }); } // Call the callback function of user customized options. @@ -1234,9 +1179,11 @@ class winhttp_client final : public _http_client_communicator } // Only need to cache the request body if user specified and the request stream doesn't support seeking. - if (winhttp_context->m_bodyType != no_body && client_config().buffer_request() && !winhttp_context->_get_readbuffer().can_seek()) + if (winhttp_context->m_bodyType != no_body && client_config().buffer_request() && + !winhttp_context->_get_readbuffer().can_seek()) { - winhttp_context->m_readBufferCopy = ::utility::details::make_unique<::concurrency::streams::container_buffer>>(); + winhttp_context->m_readBufferCopy = + ::utility::details::make_unique<::concurrency::streams::container_buffer>>(); } _start_request_send(winhttp_context, content_length); @@ -1245,10 +1192,10 @@ class winhttp_client final : public _http_client_communicator } private: - void _start_request_send(const std::shared_ptr& winhttp_context, size_t content_length) { - // WinHttp takes a context object as a void*. We therefore heap allocate a std::weak_ptr to the request context which will be destroyed during the final callback. + // WinHttp takes a context object as a void*. We therefore heap allocate a std::weak_ptr to the request context + // which will be destroyed during the final callback. std::unique_ptr> weak_context_holder; if (winhttp_context->m_request_context == nullptr) { @@ -1258,24 +1205,23 @@ class winhttp_client final : public _http_client_communicator if (winhttp_context->m_bodyType == no_body) { - if(!WinHttpSendRequest( - winhttp_context->m_request_handle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - nullptr, - 0, - 0, - (DWORD_PTR)winhttp_context->m_request_context)) + if (!WinHttpSendRequest(winhttp_context->m_request_handle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + nullptr, + 0, + 0, + (DWORD_PTR)winhttp_context->m_request_context)) { - if (weak_context_holder) - winhttp_context->m_request_context = nullptr; + if (weak_context_holder) winhttp_context->m_request_context = nullptr; auto errorCode = GetLastError(); winhttp_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpSendRequest")); } else { - // Ownership of the weak_context_holder was accepted by the callback, so release the pointer without freeing. + // Ownership of the weak_context_holder was accepted by the callback, so release the pointer without + // freeing. weak_context_holder.release(); } @@ -1291,30 +1237,31 @@ class winhttp_client final : public _http_client_communicator // If we find ourselves here, we either don't know how large the message // body is, or it is larger than our threshold. - if(!WinHttpSendRequest( - winhttp_context->m_request_handle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - nullptr, - 0, - winhttp_context->m_bodyType == content_length_chunked ? (DWORD)content_length : WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - (DWORD_PTR)winhttp_context->m_request_context)) - { - if (weak_context_holder) - winhttp_context->m_request_context = nullptr; + if (!WinHttpSendRequest(winhttp_context->m_request_handle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + nullptr, + 0, + winhttp_context->m_bodyType == content_length_chunked + ? (DWORD)content_length + : WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, + (DWORD_PTR)winhttp_context->m_request_context)) + { + if (weak_context_holder) winhttp_context->m_request_context = nullptr; auto errorCode = GetLastError(); winhttp_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpSendRequest chunked")); } else { - // Ownership of the weak_context_holder was accepted by the callback, so release the pointer without freeing. + // Ownership of the weak_context_holder was accepted by the callback, so release the pointer without + // freeing. weak_context_holder.release(); } } // Helper function to query/read next part of response data from winhttp. - static void read_next_response_chunk(winhttp_request_context *pContext, DWORD bytesRead, bool firstRead=false) + static void read_next_response_chunk(winhttp_request_context* pContext, DWORD bytesRead, bool firstRead = false) { const bool defaultChunkSize = pContext->m_http_client->client_config().is_default_chunksize(); @@ -1332,14 +1279,14 @@ class winhttp_client final : public _http_client_communicator // If bytes read is less than the chunk size this request is done. // Is it really, though? The WinHttpReadData docs suggest that less can be returned regardless... const size_t chunkSize = pContext->m_http_client->client_config().chunksize(); - std::unique_ptr &decompressor = pContext->m_decompressor; + std::unique_ptr& decompressor = pContext->m_decompressor; if (!decompressor && bytesRead < chunkSize && !firstRead) { pContext->complete_request(pContext->m_downloaded); } else { - uint8_t *buffer; + uint8_t* buffer; if (decompressor) { @@ -1357,11 +1304,7 @@ class winhttp_client final : public _http_client_communicator buffer = pContext->m_body_data.get(); } - if (!WinHttpReadData( - pContext->m_request_handle, - buffer, - static_cast(chunkSize), - nullptr)) + if (!WinHttpReadData(pContext->m_request_handle, buffer, static_cast(chunkSize), nullptr)) { auto errorCode = GetLastError(); pContext->report_error(errorCode, build_error_msg(errorCode, "WinHttpReadData")); @@ -1370,10 +1313,10 @@ class winhttp_client final : public _http_client_communicator } } - static void _transfer_encoding_chunked_write_data(_In_ winhttp_request_context * p_request_context) + static void _transfer_encoding_chunked_write_data(_In_ winhttp_request_context* p_request_context) { size_t chunk_size; - std::unique_ptr &compressor = p_request_context->m_request.compressor(); + std::unique_ptr& compressor = p_request_context->m_request.compressor(); // Set the chunk size up front; we need it before the lambda functions come into scope if (compressor) @@ -1383,12 +1326,14 @@ class winhttp_client final : public _http_client_communicator if (p_request_context->m_body_data.size() > http::details::chunked_encoding::additional_encoding_space) { // If we've previously allocated space for the compressed data, don't reduce it - chunk_size = p_request_context->m_body_data.size() - http::details::chunked_encoding::additional_encoding_space; + chunk_size = + p_request_context->m_body_data.size() - http::details::chunked_encoding::additional_encoding_space; } else if (p_request_context->m_remaining_to_write != std::numeric_limits::max()) { // Choose a semi-intelligent size based on how much total data is left to compress - chunk_size = std::min(static_cast(p_request_context->m_remaining_to_write)+128, p_request_context->m_http_client->client_config().chunksize()); + chunk_size = std::min(static_cast(p_request_context->m_remaining_to_write) + 128, + p_request_context->m_http_client->client_config().chunksize()); } else { @@ -1398,13 +1343,15 @@ class winhttp_client final : public _http_client_communicator } else { - // We're not compressing; use the smaller of the remaining data (if known) and the configured (or default) chunk size - chunk_size = std::min(static_cast(p_request_context->m_remaining_to_write), p_request_context->m_http_client->client_config().chunksize()); + // We're not compressing; use the smaller of the remaining data (if known) and the configured (or default) + // chunk size + chunk_size = std::min(static_cast(p_request_context->m_remaining_to_write), + p_request_context->m_http_client->client_config().chunksize()); } - p_request_context->allocate_request_space(nullptr, chunk_size + http::details::chunked_encoding::additional_encoding_space); + p_request_context->allocate_request_space( + nullptr, chunk_size + http::details::chunked_encoding::additional_encoding_space); - auto after_read = [p_request_context, chunk_size, &compressor](pplx::task op) - { + auto after_read = [p_request_context, chunk_size, &compressor](pplx::task op) { size_t bytes_read; try { @@ -1416,7 +1363,11 @@ class winhttp_client final : public _http_client_communicator // since it will always be non-blocking. if (!compressor) { - p_request_context->m_readBufferCopy->putn_nocopy(&p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], bytes_read).wait(); + p_request_context->m_readBufferCopy + ->putn_nocopy( + &p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], + bytes_read) + .wait(); } } } @@ -1428,14 +1379,18 @@ class winhttp_client final : public _http_client_communicator _ASSERTE(bytes_read != static_cast(-1)); - size_t offset = http::details::chunked_encoding::add_chunked_delimiters(p_request_context->m_body_data.get(), chunk_size + http::details::chunked_encoding::additional_encoding_space, bytes_read); + size_t offset = http::details::chunked_encoding::add_chunked_delimiters( + p_request_context->m_body_data.get(), + chunk_size + http::details::chunked_encoding::additional_encoding_space, + bytes_read); if (!compressor && p_request_context->m_remaining_to_write != std::numeric_limits::max()) { if (bytes_read == 0 && p_request_context->m_remaining_to_write) { // The stream ended earlier than we detected it should - http_exception ex(U("Unexpected end of request body stream encountered before expected length met.")); + http_exception ex( + U("Unexpected end of request body stream encountered before expected length met.")); p_request_context->report_exception(ex); return; } @@ -1451,18 +1406,19 @@ class winhttp_client final : public _http_client_communicator if (p_request_context->m_readBufferCopy) { // Move the saved buffer into the read buffer, which now supports seeking. - p_request_context->m_readStream = concurrency::streams::container_stream>::open_istream(std::move(p_request_context->m_readBufferCopy->collection())); + p_request_context->m_readStream = + concurrency::streams::container_stream>::open_istream( + std::move(p_request_context->m_readBufferCopy->collection())); p_request_context->m_readBufferCopy.reset(); } } const auto length = bytes_read + (http::details::chunked_encoding::additional_encoding_space - offset); - if (!WinHttpWriteData( - p_request_context->m_request_handle, - &p_request_context->m_body_data.get()[offset], - static_cast(length), - nullptr)) + if (!WinHttpWriteData(p_request_context->m_request_handle, + &p_request_context->m_body_data.get()[offset], + static_cast(length), + nullptr)) { auto errorCode = GetLastError(); p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpWriteData")); @@ -1471,8 +1427,8 @@ class winhttp_client final : public _http_client_communicator if (compressor) { - auto do_compress = [p_request_context, chunk_size, &compressor](pplx::task op) -> pplx::task - { + auto do_compress = + [p_request_context, chunk_size, &compressor](pplx::task op) -> pplx::task { size_t bytes_read; try @@ -1485,7 +1441,7 @@ class winhttp_client final : public _http_client_communicator } _ASSERTE(bytes_read >= 0); - uint8_t *buffer = p_request_context->m_compression_state.m_acquired; + uint8_t* buffer = p_request_context->m_compression_state.m_acquired; if (buffer == nullptr) { buffer = p_request_context->m_compression_state.m_buffer.data(); @@ -1496,7 +1452,8 @@ class winhttp_client final : public _http_client_communicator if (bytes_read) { // An actual read always resets compression state for the next chunk - _ASSERTE(p_request_context->m_compression_state.m_bytes_processed == p_request_context->m_compression_state.m_bytes_read); + _ASSERTE(p_request_context->m_compression_state.m_bytes_processed == + p_request_context->m_compression_state.m_bytes_read); _ASSERTE(!p_request_context->m_compression_state.m_needs_flush); p_request_context->m_compression_state.m_bytes_read = bytes_read; p_request_context->m_compression_state.m_bytes_processed = 0; @@ -1518,27 +1475,38 @@ class winhttp_client final : public _http_client_communicator // this is done (in theory it can be multiple times) as a finalizing operation hint = web::http::compression::operation_hint::is_last; } - else if (p_request_context->m_compression_state.m_bytes_processed == p_request_context->m_compression_state.m_bytes_read) + else if (p_request_context->m_compression_state.m_bytes_processed == + p_request_context->m_compression_state.m_bytes_read) { - if (p_request_context->m_remaining_to_write && p_request_context->m_remaining_to_write != std::numeric_limits::max()) + if (p_request_context->m_remaining_to_write && + p_request_context->m_remaining_to_write != std::numeric_limits::max()) { // The stream ended earlier than we detected it should - return pplx::task_from_exception(http_exception(U("Unexpected end of request body stream encountered before expected length met."))); + return pplx::task_from_exception(http_exception( + U("Unexpected end of request body stream encountered before expected length met."))); } - // We think we're done; inform the compression library so it can finalize and/or give us any pending compressed bytes. - // Note that we may end up here multiple times if m_needs_flush is set, until all compressed bytes are drained. + // We think we're done; inform the compression library so it can finalize and/or give us any pending + // compressed bytes. Note that we may end up here multiple times if m_needs_flush is set, until all + // compressed bytes are drained. hint = web::http::compression::operation_hint::is_last; } // else we're still compressing bytes from the previous read - _ASSERTE(p_request_context->m_compression_state.m_bytes_processed <= p_request_context->m_compression_state.m_bytes_read); - - uint8_t *in = buffer + p_request_context->m_compression_state.m_bytes_processed; - size_t inbytes = p_request_context->m_compression_state.m_bytes_read - p_request_context->m_compression_state.m_bytes_processed; - return compressor->compress(in, inbytes, &p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], chunk_size, hint) - .then([p_request_context, bytes_read, hint, chunk_size](pplx::task op) -> pplx::task - { + _ASSERTE(p_request_context->m_compression_state.m_bytes_processed <= + p_request_context->m_compression_state.m_bytes_read); + + uint8_t* in = buffer + p_request_context->m_compression_state.m_bytes_processed; + size_t inbytes = p_request_context->m_compression_state.m_bytes_read - + p_request_context->m_compression_state.m_bytes_processed; + return compressor + ->compress(in, + inbytes, + &p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], + chunk_size, + hint) + .then([p_request_context, bytes_read, hint, chunk_size]( + pplx::task op) -> pplx::task { http::compression::operation_result r; try @@ -1552,7 +1520,8 @@ class winhttp_client final : public _http_client_communicator if (hint == web::http::compression::operation_hint::is_last) { - // We're done reading all chunks, but the compressor may still have compressed bytes to drain from previous reads + // We're done reading all chunks, but the compressor may still have compressed bytes to + // drain from previous reads _ASSERTE(r.done || r.output_bytes_produced == chunk_size); p_request_context->m_compression_state.m_needs_flush = !r.done; p_request_context->m_compression_state.m_done = r.done; @@ -1561,17 +1530,22 @@ class winhttp_client final : public _http_client_communicator // Update the number of bytes compressed in this read chunk; if it's been fully compressed, // we'll reset m_bytes_processed and m_bytes_read after reading the next chunk p_request_context->m_compression_state.m_bytes_processed += r.input_bytes_processed; - _ASSERTE(p_request_context->m_compression_state.m_bytes_processed <= p_request_context->m_compression_state.m_bytes_read); + _ASSERTE(p_request_context->m_compression_state.m_bytes_processed <= + p_request_context->m_compression_state.m_bytes_read); if (p_request_context->m_remaining_to_write != std::numeric_limits::max()) { _ASSERTE(p_request_context->m_remaining_to_write >= r.input_bytes_processed); p_request_context->m_remaining_to_write -= r.input_bytes_processed; } - if (p_request_context->m_compression_state.m_acquired != nullptr && p_request_context->m_compression_state.m_bytes_processed == p_request_context->m_compression_state.m_bytes_read) + if (p_request_context->m_compression_state.m_acquired != nullptr && + p_request_context->m_compression_state.m_bytes_processed == + p_request_context->m_compression_state.m_bytes_read) { // Release the acquired buffer back to the streambuf at the earliest possible point - p_request_context->_get_readbuffer().release(p_request_context->m_compression_state.m_acquired, p_request_context->m_compression_state.m_bytes_processed); + p_request_context->_get_readbuffer().release( + p_request_context->m_compression_state.m_acquired, + p_request_context->m_compression_state.m_bytes_processed); p_request_context->m_compression_state.m_acquired = nullptr; } @@ -1579,14 +1553,17 @@ class winhttp_client final : public _http_client_communicator }); }; - if (p_request_context->m_compression_state.m_bytes_processed < p_request_context->m_compression_state.m_bytes_read || p_request_context->m_compression_state.m_needs_flush) + if (p_request_context->m_compression_state.m_bytes_processed < + p_request_context->m_compression_state.m_bytes_read || + p_request_context->m_compression_state.m_needs_flush) { // We're still working on data from a previous read; continue compression without reading new data do_compress(pplx::task_from_result(0)).then(after_read); } else if (p_request_context->m_compression_state.m_done) { - // We just need to send the last (zero-length) chunk; there's no sense in going through the compression path + // We just need to send the last (zero-length) chunk; there's no sense in going through the compression + // path after_read(pplx::task_from_result(0)); } else @@ -1594,7 +1571,8 @@ class winhttp_client final : public _http_client_communicator size_t length; // We need to read from the input stream, then compress before sending - if (p_request_context->_get_readbuffer().acquire(p_request_context->m_compression_state.m_acquired, length)) + if (p_request_context->_get_readbuffer().acquire(p_request_context->m_compression_state.m_acquired, + length)) { if (length == 0) { @@ -1603,10 +1581,12 @@ class winhttp_client final : public _http_client_communicator p_request_context->report_exception(p_request_context->_get_readbuffer().exception()); return; } - else if (p_request_context->m_remaining_to_write && p_request_context->m_remaining_to_write != std::numeric_limits::max()) + else if (p_request_context->m_remaining_to_write && + p_request_context->m_remaining_to_write != std::numeric_limits::max()) { // Unexpected end-of-stream. - p_request_context->report_error(GetLastError(), _XPLATSTR("Outgoing HTTP body stream ended early.")); + p_request_context->report_error(GetLastError(), + _XPLATSTR("Outgoing HTTP body stream ended early.")); return; } } @@ -1620,29 +1600,35 @@ class winhttp_client final : public _http_client_communicator } else { - length = std::min(static_cast(p_request_context->m_remaining_to_write), p_request_context->m_http_client->client_config().chunksize()); + length = std::min(static_cast(p_request_context->m_remaining_to_write), + p_request_context->m_http_client->client_config().chunksize()); if (p_request_context->m_compression_state.m_buffer.capacity() < length) { p_request_context->m_compression_state.m_buffer.reserve(length); } - p_request_context->_get_readbuffer().getn(p_request_context->m_compression_state.m_buffer.data(), length).then(do_compress).then(after_read); + p_request_context->_get_readbuffer() + .getn(p_request_context->m_compression_state.m_buffer.data(), length) + .then(do_compress) + .then(after_read); } } } else { // We're not compressing; just read and chunk - p_request_context->_get_readbuffer().getn(&p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], chunk_size).then(after_read); + p_request_context->_get_readbuffer() + .getn(&p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], chunk_size) + .then(after_read); } } - static void _multiple_segment_write_data(_In_ winhttp_request_context * p_request_context) + static void _multiple_segment_write_data(_In_ winhttp_request_context* p_request_context) { auto rbuf = p_request_context->_get_readbuffer(); msl::safeint3::SafeInt safeCount = p_request_context->m_remaining_to_write; safeCount = safeCount.Min(p_request_context->m_http_client->client_config().chunksize()); - uint8_t* block = nullptr; + uint8_t* block = nullptr; size_t length = 0; if (rbuf.acquire(block, length)) { @@ -1651,7 +1637,8 @@ class winhttp_client final : public _http_client_communicator // Unexpected end-of-stream. if (rbuf.exception() == nullptr) { - p_request_context->report_error(GetLastError(), _XPLATSTR("Error reading outgoing HTTP body from its stream.")); + p_request_context->report_error(GetLastError(), + _XPLATSTR("Error reading outgoing HTTP body from its stream.")); } else { @@ -1666,16 +1653,15 @@ class winhttp_client final : public _http_client_communicator // Stop writing chunks after this one if no more data. p_request_context->m_remaining_to_write -= to_write; - if ( p_request_context->m_remaining_to_write == 0 ) + if (p_request_context->m_remaining_to_write == 0) { p_request_context->m_bodyType = no_body; } - if( !WinHttpWriteData( - p_request_context->m_request_handle, - p_request_context->m_body_data.get(), - static_cast(to_write), - nullptr)) + if (!WinHttpWriteData(p_request_context->m_request_handle, + p_request_context->m_body_data.get(), + static_cast(to_write), + nullptr)) { auto errorCode = GetLastError(); p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpWriteData")); @@ -1685,41 +1671,44 @@ class winhttp_client final : public _http_client_communicator { p_request_context->allocate_request_space(nullptr, safeCount); - rbuf.getn(p_request_context->m_body_data.get(), safeCount).then( - [p_request_context, rbuf](pplx::task op) - { - size_t read; - try { read = op.get(); } catch (...) - { - p_request_context->report_exception(std::current_exception()); - return; - } - _ASSERTE(read != static_cast(-1)); + rbuf.getn(p_request_context->m_body_data.get(), safeCount) + .then([p_request_context, rbuf](pplx::task op) { + size_t read; + try + { + read = op.get(); + } + catch (...) + { + p_request_context->report_exception(std::current_exception()); + return; + } + _ASSERTE(read != static_cast(-1)); - if (read == 0) - { - p_request_context->report_exception(http_exception(U("Unexpected end of request body stream encountered before Content-Length met."))); - return; - } + if (read == 0) + { + p_request_context->report_exception(http_exception( + U("Unexpected end of request body stream encountered before Content-Length met."))); + return; + } - p_request_context->m_remaining_to_write -= read; + p_request_context->m_remaining_to_write -= read; - // Stop writing chunks after this one if no more data. - if (p_request_context->m_remaining_to_write == 0) - { - p_request_context->m_bodyType = no_body; - } + // Stop writing chunks after this one if no more data. + if (p_request_context->m_remaining_to_write == 0) + { + p_request_context->m_bodyType = no_body; + } - if(!WinHttpWriteData( - p_request_context->m_request_handle, - p_request_context->m_body_data.get(), - static_cast(read), - nullptr)) - { - auto errorCode = GetLastError(); - p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpWriteData")); - } - }); + if (!WinHttpWriteData(p_request_context->m_request_handle, + p_request_context->m_body_data.get(), + static_cast(read), + nullptr)) + { + auto errorCode = GetLastError(); + p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpWriteData")); + } + }); } } @@ -1748,16 +1737,15 @@ class winhttp_client final : public _http_client_communicator // Returns true if we handle successfully and resending the request // or false if we fail to handle. - static bool handle_authentication_failure( - HINTERNET hRequestHandle, - const std::shared_ptr& p_request_context, - _In_ DWORD error = 0) + static bool handle_authentication_failure(HINTERNET hRequestHandle, + const std::shared_ptr& p_request_context, + _In_ DWORD error = 0) { - http_request & request = p_request_context->m_request; + http_request& request = p_request_context->m_request; - _ASSERTE(p_request_context->m_response.status_code() == status_codes::Unauthorized - || p_request_context->m_response.status_code() == status_codes::ProxyAuthRequired - || error == ERROR_WINHTTP_RESEND_REQUEST); + _ASSERTE(p_request_context->m_response.status_code() == status_codes::Unauthorized || + p_request_context->m_response.status_code() == status_codes::ProxyAuthRequired || + error == ERROR_WINHTTP_RESEND_REQUEST); // Check if the saved read position is valid auto rdpos = p_request_context->m_startingPosition; @@ -1793,18 +1781,14 @@ class winhttp_client final : public _http_client_communicator DWORD dwSupportedSchemes; DWORD dwFirstScheme; DWORD dwAuthTarget; - if(!WinHttpQueryAuthSchemes( - hRequestHandle, - &dwSupportedSchemes, - &dwFirstScheme, - &dwAuthTarget)) + if (!WinHttpQueryAuthSchemes(hRequestHandle, &dwSupportedSchemes, &dwFirstScheme, &dwAuthTarget)) { // This will return the authentication failure to the user, without reporting fatal errors return false; } DWORD dwSelectedScheme = ChooseAuthScheme(dwSupportedSchemes); - if(dwSelectedScheme == 0) + if (dwSelectedScheme == 0) { // This will return the authentication failure to the user, without reporting fatal errors return false; @@ -1824,9 +1808,12 @@ class winhttp_client final : public _http_client_communicator web::uri current_uri(get_request_url(hRequestHandle)); is_redirect = p_request_context->m_request.absolute_uri().to_string() != current_uri.to_string(); } - catch (const std::exception&) {} + catch (const std::exception&) + { + } - // If we have been redirected, then WinHttp needs the proxy credentials again to make the next request leg (which may be on a different server) + // If we have been redirected, then WinHttp needs the proxy credentials again to make the next request + // leg (which may be on a different server) if (is_redirect || !p_request_context->m_proxy_authentication_tried) { cred = p_request_context->m_http_client->client_config().proxy().credentials(); @@ -1843,13 +1830,12 @@ class winhttp_client final : public _http_client_communicator // New scope to ensure plaintext password is cleared as soon as possible. { auto password = cred._internal_decrypt(); - if (!WinHttpSetCredentials( - hRequestHandle, - dwAuthTarget, - dwSelectedScheme, - cred.username().c_str(), - password->c_str(), - nullptr)) + if (!WinHttpSetCredentials(hRequestHandle, + dwAuthTarget, + dwSelectedScheme, + cred.username().c_str(), + password->c_str(), + nullptr)) { return false; } @@ -1899,15 +1885,12 @@ class winhttp_client final : public _http_client_communicator // Callback used with WinHTTP to listen for async completions. static void CALLBACK completion_callback( - HINTERNET hRequestHandle, - DWORD_PTR context, - DWORD statusCode, - _In_ void* statusInfo, - DWORD statusInfoLength) + HINTERNET hRequestHandle, DWORD_PTR context, DWORD statusCode, _In_ void* statusInfo, DWORD statusInfoLength) { CASABLANCA_UNREFERENCED_PARAMETER(statusInfoLength); - std::weak_ptr* p_weak_request_context = reinterpret_cast *>(context); + std::weak_ptr* p_weak_request_context = + reinterpret_cast*>(context); if (p_weak_request_context == nullptr) { @@ -1917,7 +1900,8 @@ class winhttp_client final : public _http_client_communicator if (statusCode == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) { // This callback is responsible for freeing the type-erased context. - // This particular status code indicates that this is the final callback call, suitable for context destruction. + // This particular status code indicates that this is the final callback call, suitable for context + // destruction. delete p_weak_request_context; return; } @@ -1931,18 +1915,19 @@ class winhttp_client final : public _http_client_communicator switch (statusCode) { - case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR : + case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: { - WINHTTP_ASYNC_RESULT *error_result = reinterpret_cast(statusInfo); + WINHTTP_ASYNC_RESULT* error_result = reinterpret_cast(statusInfo); const DWORD errorCode = error_result->dwError; // Some authentication schemes require multiple transactions. // When ERROR_WINHTTP_RESEND_REQUEST is encountered, - // we should continue to resend the request until a response is received that does not contain a 401 or 407 status code. + // we should continue to resend the request until a response is received that does not contain a 401 or + // 407 status code. if (errorCode == ERROR_WINHTTP_RESEND_REQUEST) { bool resending = handle_authentication_failure(hRequestHandle, p_request_context, errorCode); - if(resending) + if (resending) { // The request is resending. Wait until we get a new response. return; @@ -1952,15 +1937,19 @@ class winhttp_client final : public _http_client_communicator p_request_context->report_error(errorCode, build_error_msg(error_result)); return; } - case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE : + case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: { if (!p_request_context->m_request.body()) { // Report progress finished uploading with no message body. auto progress = p_request_context->m_request._get_impl()->_progress_handler(); - if ( progress ) + if (progress) { - try { (*progress)(message_direction::upload, 0); } catch(...) + try + { + (*progress)(message_direction::upload, 0); + } + catch (...) { p_request_context->report_exception(std::current_exception()); return; @@ -1968,43 +1957,46 @@ class winhttp_client final : public _http_client_communicator } } - if ( p_request_context->m_bodyType == transfer_encoding_chunked ) + if (p_request_context->m_bodyType == transfer_encoding_chunked) { _transfer_encoding_chunked_write_data(p_request_context.get()); } - else if ( p_request_context->m_bodyType == content_length_chunked ) + else if (p_request_context->m_bodyType == content_length_chunked) { _multiple_segment_write_data(p_request_context.get()); } else { - if(!WinHttpReceiveResponse(hRequestHandle, nullptr)) + if (!WinHttpReceiveResponse(hRequestHandle, nullptr)) { auto errorCode = GetLastError(); - p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse")); + p_request_context->report_error(errorCode, + build_error_msg(errorCode, "WinHttpReceiveResponse")); } } return; } - case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: - p_request_context->on_send_request_validate_cn(); - return; - case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: - p_request_context->report_exception(web::http::http_exception( - generate_security_failure_message(*reinterpret_cast(statusInfo)))); - return; - case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE : + case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: p_request_context->on_send_request_validate_cn(); return; + case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: + p_request_context->report_exception(web::http::http_exception( + generate_security_failure_message(*reinterpret_cast(statusInfo)))); + return; + case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: { - DWORD bytesWritten = *((DWORD *)statusInfo); + DWORD bytesWritten = *((DWORD*)statusInfo); _ASSERTE(statusInfoLength == sizeof(DWORD)); - if ( bytesWritten > 0 ) + if (bytesWritten > 0) { auto progress = p_request_context->m_request._get_impl()->_progress_handler(); - if ( progress ) + if (progress) { p_request_context->m_uploaded += bytesWritten; - try { (*progress)(message_direction::upload, p_request_context->m_uploaded); } catch(...) + try + { + (*progress)(message_direction::upload, p_request_context->m_uploaded); + } + catch (...) { p_request_context->report_exception(std::current_exception()); return; @@ -2012,30 +2004,31 @@ class winhttp_client final : public _http_client_communicator } } - if ( p_request_context->is_externally_allocated() ) + if (p_request_context->is_externally_allocated()) { p_request_context->_get_readbuffer().release(p_request_context->m_body_data.get(), bytesWritten); } - if ( p_request_context->m_bodyType == transfer_encoding_chunked ) + if (p_request_context->m_bodyType == transfer_encoding_chunked) { _transfer_encoding_chunked_write_data(p_request_context.get()); } - else if ( p_request_context->m_bodyType == content_length_chunked ) + else if (p_request_context->m_bodyType == content_length_chunked) { _multiple_segment_write_data(p_request_context.get()); } else { - if(!WinHttpReceiveResponse(hRequestHandle, nullptr)) + if (!WinHttpReceiveResponse(hRequestHandle, nullptr)) { auto errorCode = GetLastError(); - p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse")); + p_request_context->report_error(errorCode, + build_error_msg(errorCode, "WinHttpReceiveResponse")); } } return; } - case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE : + case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: { // First need to query to see what the headers size is. DWORD headerBufferLength = 0; @@ -2044,28 +2037,28 @@ class winhttp_client final : public _http_client_communicator // Now allocate buffer for headers and query for them. std::vector header_raw_buffer; header_raw_buffer.resize(headerBufferLength); - utf16char * header_buffer = reinterpret_cast(&header_raw_buffer[0]); - if(!WinHttpQueryHeaders( - hRequestHandle, - WINHTTP_QUERY_RAW_HEADERS_CRLF, - WINHTTP_HEADER_NAME_BY_INDEX, - header_buffer, - &headerBufferLength, - WINHTTP_NO_HEADER_INDEX)) + utf16char* header_buffer = reinterpret_cast(&header_raw_buffer[0]); + if (!WinHttpQueryHeaders(hRequestHandle, + WINHTTP_QUERY_RAW_HEADERS_CRLF, + WINHTTP_HEADER_NAME_BY_INDEX, + header_buffer, + &headerBufferLength, + WINHTTP_NO_HEADER_INDEX)) { auto errorCode = GetLastError(); - p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpQueryHeaders"));; + p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpQueryHeaders")); + ; return; } - http_response & response = p_request_context->m_response; + http_response& response = p_request_context->m_response; parse_winhttp_headers(hRequestHandle, header_buffer, response); - if(response.status_code() == status_codes::Unauthorized /*401*/ || + if (response.status_code() == status_codes::Unauthorized /*401*/ || response.status_code() == status_codes::ProxyAuthRequired /*407*/) { bool resending = handle_authentication_failure(hRequestHandle, p_request_context); - if(resending) + if (resending) { // The request was not completed but resent with credentials. Wait until we get a new response return; @@ -2078,9 +2071,11 @@ class winhttp_client final : public _http_client_communicator // false indicates report_exception was called return; } - if (p_request_context->m_decompressor && !p_request_context->m_http_client->client_config().request_compressed_response()) + if (p_request_context->m_decompressor && + !p_request_context->m_http_client->client_config().request_compressed_response()) { - p_request_context->m_compression_state.m_chunk = std::make_unique(); + p_request_context->m_compression_state.m_chunk = + std::make_unique(); p_request_context->m_compression_state.m_chunked = true; } @@ -2089,7 +2084,7 @@ class winhttp_client final : public _http_client_communicator // If the method was 'HEAD,' the body of the message is by definition empty. No need to // read it. Any headers that suggest the presence of a body can safely be ignored. - if (p_request_context->m_request.method() == methods::HEAD ) + if (p_request_context->m_request.method() == methods::HEAD) { p_request_context->allocate_request_space(nullptr, 0); p_request_context->complete_request(0); @@ -2099,23 +2094,24 @@ class winhttp_client final : public _http_client_communicator // HTTP Specification states: // If a message is received with both a Transfer-Encoding header field // and a Content-Length header field, the latter MUST be ignored. - // If none of them is specified, the message length should be determined by the server closing the connection. - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 + // If none of them is specified, the message length should be determined by the server closing the + // connection. http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 read_next_response_chunk(p_request_context.get(), 0, true); return; } - case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE : + case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: { // Status information contains pointer to DWORD containing number of bytes available. const DWORD num_bytes = *(PDWORD)statusInfo; - uint8_t *buffer; + uint8_t* buffer; if (num_bytes > 0) { if (p_request_context->m_decompressor) { - // Allocate space for the compressed data; we'll decompress it into the caller stream once it's been filled in + // Allocate space for the compressed data; we'll decompress it into the caller stream once it's + // been filled in if (p_request_context->m_compression_state.m_buffer.capacity() < num_bytes) { p_request_context->m_compression_state.m_buffer.reserve(num_bytes); @@ -2130,11 +2126,7 @@ class winhttp_client final : public _http_client_communicator } // Read in available body data all at once. - if(!WinHttpReadData( - hRequestHandle, - buffer, - num_bytes, - nullptr)) + if (!WinHttpReadData(hRequestHandle, buffer, num_bytes, nullptr)) { auto errorCode = GetLastError(); p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReadData")); @@ -2146,13 +2138,17 @@ class winhttp_client final : public _http_client_communicator { if (p_request_context->m_compression_state.m_chunked) { - // We haven't seen the 0-length chunk and/or trailing delimiter that indicate the end of chunked input - p_request_context->report_exception(http_exception("Chunked response stream ended unexpectedly")); + // We haven't seen the 0-length chunk and/or trailing delimiter that indicate the end of + // chunked input + p_request_context->report_exception( + http_exception("Chunked response stream ended unexpectedly")); return; } - if (p_request_context->m_compression_state.m_started && !p_request_context->m_compression_state.m_done) + if (p_request_context->m_compression_state.m_started && + !p_request_context->m_compression_state.m_done) { - p_request_context->report_exception(http_exception("Received incomplete compressed stream")); + p_request_context->report_exception( + http_exception("Received incomplete compressed stream")); return; } } @@ -2161,7 +2157,10 @@ class winhttp_client final : public _http_client_communicator auto progress = p_request_context->m_request._get_impl()->_progress_handler(); if (progress) { - try { (*progress)(message_direction::download, p_request_context->m_downloaded); } + try + { + (*progress)(message_direction::download, p_request_context->m_downloaded); + } catch (...) { p_request_context->report_exception(std::current_exception()); @@ -2173,7 +2172,7 @@ class winhttp_client final : public _http_client_communicator } return; } - case WINHTTP_CALLBACK_STATUS_READ_COMPLETE : + case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: { // Status information length contains the number of bytes read. DWORD bytesRead = statusInfoLength; @@ -2183,7 +2182,10 @@ class winhttp_client final : public _http_client_communicator p_request_context->m_downloaded += statusInfoLength; if (progress) { - try { (*progress)(message_direction::download, p_request_context->m_downloaded); } + try + { + (*progress)(message_direction::download, p_request_context->m_downloaded); + } catch (...) { p_request_context->report_exception(std::current_exception()); @@ -2198,13 +2200,17 @@ class winhttp_client final : public _http_client_communicator { if (p_request_context->m_compression_state.m_chunked) { - // We haven't seen the 0-length chunk and/or trailing delimiter that indicate the end of chunked input - p_request_context->report_exception(http_exception("Chunked response stream ended unexpectedly")); + // We haven't seen the 0-length chunk and/or trailing delimiter that indicate the end of + // chunked input + p_request_context->report_exception( + http_exception("Chunked response stream ended unexpectedly")); return; } - if (p_request_context->m_compression_state.m_started && !p_request_context->m_compression_state.m_done) + if (p_request_context->m_compression_state.m_started && + !p_request_context->m_compression_state.m_done) { - p_request_context->report_exception(http_exception("Received incomplete compressed stream")); + p_request_context->report_exception( + http_exception("Received incomplete compressed stream")); return; } } @@ -2216,7 +2222,8 @@ class winhttp_client final : public _http_client_communicator if (p_request_context->m_decompressor) { - size_t chunk_size = std::max(static_cast(bytesRead), p_request_context->m_http_client->client_config().chunksize()); + size_t chunk_size = std::max(static_cast(bytesRead), + p_request_context->m_http_client->client_config().chunksize()); p_request_context->m_compression_state.m_bytes_read = static_cast(bytesRead); p_request_context->m_compression_state.m_chunk_bytes = 0; @@ -2226,8 +2233,8 @@ class winhttp_client final : public _http_client_communicator // Oddly enough, WinHttp doesn't de-chunk for us if "chunked" isn't the only // encoding, so we need to do so on the fly as we process the received data - auto process_buffer = [chunk_size](winhttp_request_context *c, size_t bytes_produced, bool outer) -> bool - { + auto process_buffer = + [chunk_size](winhttp_request_context* c, size_t bytes_produced, bool outer) -> bool { if (!c->m_compression_state.m_chunk_bytes) { if (c->m_compression_state.m_chunked) @@ -2236,10 +2243,15 @@ class winhttp_client final : public _http_client_communicator bool done; // Process the next portion of this piece of the transfer-encoded message - done = c->m_compression_state.m_chunk->process_buffer(c->m_compression_state.m_buffer.data()+c->m_compression_state.m_bytes_processed, c->m_compression_state.m_bytes_read-c->m_compression_state.m_bytes_processed, offset, c->m_compression_state.m_chunk_bytes); + done = c->m_compression_state.m_chunk->process_buffer( + c->m_compression_state.m_buffer.data() + c->m_compression_state.m_bytes_processed, + c->m_compression_state.m_bytes_read - c->m_compression_state.m_bytes_processed, + offset, + c->m_compression_state.m_chunk_bytes); // Skip chunk-related metadata; it isn't relevant to decompression - _ASSERTE(c->m_compression_state.m_bytes_processed+offset <= c->m_compression_state.m_bytes_read); + _ASSERTE(c->m_compression_state.m_bytes_processed + offset <= + c->m_compression_state.m_bytes_read); c->m_compression_state.m_bytes_processed += offset; if (!c->m_compression_state.m_chunk_bytes) @@ -2247,7 +2259,9 @@ class winhttp_client final : public _http_client_communicator if (done) { // We've processed/validated all bytes in this transfer-encoded message. - // Note that we currently ignore "extra" trailing bytes, i.e. c->m_compression_state.m_bytes_processed < c->m_compression_state.m_bytes_read + // Note that we currently ignore "extra" trailing bytes, i.e. + // c->m_compression_state.m_bytes_processed < + // c->m_compression_state.m_bytes_read if (c->m_compression_state.m_done) { c->complete_request(c->m_downloaded); @@ -2262,34 +2276,41 @@ class winhttp_client final : public _http_client_communicator { // There should be more data to receive; look for it c->m_compression_state.m_bytes_processed = 0; - read_next_response_chunk(c, static_cast(c->m_compression_state.m_bytes_read)); + read_next_response_chunk( + c, static_cast(c->m_compression_state.m_bytes_read)); return false; } } } else { - _ASSERTE(!c->m_compression_state.m_bytes_processed || c->m_compression_state.m_bytes_processed == c->m_compression_state.m_bytes_read); + _ASSERTE(!c->m_compression_state.m_bytes_processed || + c->m_compression_state.m_bytes_processed == + c->m_compression_state.m_bytes_read); if (c->m_compression_state.m_done) { // Decompression is done; complete the request c->complete_request(c->m_downloaded); return false; } - else if (c->m_compression_state.m_bytes_processed != c->m_compression_state.m_bytes_read) + else if (c->m_compression_state.m_bytes_processed != + c->m_compression_state.m_bytes_read) { // We still have more data to process in the current buffer - c->m_compression_state.m_chunk_bytes = c->m_compression_state.m_bytes_read - c->m_compression_state.m_bytes_processed; + c->m_compression_state.m_chunk_bytes = + c->m_compression_state.m_bytes_read - c->m_compression_state.m_bytes_processed; } else if (!outer && bytes_produced != chunk_size) { // There should be more data to receive; look for it c->m_compression_state.m_bytes_processed = 0; - read_next_response_chunk(c, static_cast(c->m_compression_state.m_bytes_read)); + read_next_response_chunk(c, + static_cast(c->m_compression_state.m_bytes_read)); return false; } - // Otherwise, we've processed all bytes in the input buffer, but there's a good chance that - // there are still decompressed bytes to emit; we'll do so before reading the next chunk + // Otherwise, we've processed all bytes in the input buffer, but there's a good chance + // that there are still decompressed bytes to emit; we'll do so before reading the next + // chunk } } @@ -2297,15 +2318,15 @@ class winhttp_client final : public _http_client_communicator return true; }; - pplx::details::_do_while([p_request_context, chunk_size, process_buffer]() -> pplx::task - { - uint8_t *buffer; + pplx::details::_do_while([p_request_context, chunk_size, process_buffer]() -> pplx::task { + uint8_t* buffer; try { if (!process_buffer(p_request_context.get(), 0, true)) { - // The chunked request has been completely processed (or contains no data in the first place) + // The chunked request has been completely processed (or contains no data in the first + // place) return pplx::task_from_result(false); } } @@ -2315,9 +2336,11 @@ class winhttp_client final : public _http_client_communicator return pplx::task_from_exception(std::current_exception()); } - // If it's possible to know how much post-compression data we're expecting (for instance if we can discern how - // much total data the ostream can support, we could allocate (or at least attempt to acquire) based on that - p_request_context->m_compression_state.m_acquired = p_request_context->_get_writebuffer().alloc(chunk_size); + // If it's possible to know how much post-compression data we're expecting (for instance if we + // can discern how much total data the ostream can support, we could allocate (or at least + // attempt to acquire) based on that + p_request_context->m_compression_state.m_acquired = + p_request_context->_get_writebuffer().alloc(chunk_size); if (p_request_context->m_compression_state.m_acquired) { buffer = p_request_context->m_compression_state.m_acquired; @@ -2330,70 +2353,81 @@ class winhttp_client final : public _http_client_communicator buffer = p_request_context->m_body_data.get(); } - uint8_t *in = p_request_context->m_compression_state.m_buffer.data() + p_request_context->m_compression_state.m_bytes_processed; + uint8_t* in = p_request_context->m_compression_state.m_buffer.data() + + p_request_context->m_compression_state.m_bytes_processed; size_t inbytes = p_request_context->m_compression_state.m_chunk_bytes; if (inbytes) { p_request_context->m_compression_state.m_started = true; } - return p_request_context->m_decompressor->decompress(in, inbytes, buffer, chunk_size, web::http::compression::operation_hint::has_more).then( - [p_request_context, buffer, chunk_size, process_buffer] (pplx::task op) - { - auto r = op.get(); - auto keep_going = [&r, process_buffer](winhttp_request_context *c) -> pplx::task - { - _ASSERTE(r.input_bytes_processed <= c->m_compression_state.m_chunk_bytes); - c->m_compression_state.m_chunk_bytes -= r.input_bytes_processed; - c->m_compression_state.m_bytes_processed += r.input_bytes_processed; - c->m_compression_state.m_done = r.done; + return p_request_context->m_decompressor + ->decompress( + in, inbytes, buffer, chunk_size, web::http::compression::operation_hint::has_more) + .then([p_request_context, buffer, chunk_size, process_buffer]( + pplx::task op) { + auto r = op.get(); + auto keep_going = [&r, process_buffer](winhttp_request_context* c) -> pplx::task { + _ASSERTE(r.input_bytes_processed <= c->m_compression_state.m_chunk_bytes); + c->m_compression_state.m_chunk_bytes -= r.input_bytes_processed; + c->m_compression_state.m_bytes_processed += r.input_bytes_processed; + c->m_compression_state.m_done = r.done; + + try + { + // See if we still have more work to do for this section and/or for the response + // in general + return pplx::task_from_result( + process_buffer(c, r.output_bytes_produced, false)); + } + catch (...) + { + return pplx::task_from_exception(std::current_exception()); + } + }; - try - { - // See if we still have more work to do for this section and/or for the response in general - return pplx::task_from_result(process_buffer(c, r.output_bytes_produced, false)); - } - catch (...) + _ASSERTE(p_request_context->m_compression_state.m_bytes_processed + + r.input_bytes_processed <= + p_request_context->m_compression_state.m_bytes_read); + + if (p_request_context->m_compression_state.m_acquired != nullptr) { - return pplx::task_from_exception(std::current_exception()); + // We decompressed directly into the output stream + p_request_context->m_compression_state.m_acquired = nullptr; + p_request_context->_get_writebuffer().commit(r.output_bytes_produced); + return keep_going(p_request_context.get()); } - }; - _ASSERTE(p_request_context->m_compression_state.m_bytes_processed+r.input_bytes_processed <= p_request_context->m_compression_state.m_bytes_read); - - if (p_request_context->m_compression_state.m_acquired != nullptr) + // We decompressed into our own buffer; let the stream copy the data + return p_request_context->_get_writebuffer() + .putn_nocopy(buffer, r.output_bytes_produced) + .then([p_request_context, r, keep_going](pplx::task op) { + if (op.get() != r.output_bytes_produced) + { + return pplx::task_from_exception( + std::runtime_error("Response stream unexpectedly failed to write the " + "requested number of bytes")); + } + return keep_going(p_request_context.get()); + }); + }); + }) + .then([p_request_context](pplx::task op) { + try { - // We decompressed directly into the output stream - p_request_context->m_compression_state.m_acquired = nullptr; - p_request_context->_get_writebuffer().commit(r.output_bytes_produced); - return keep_going(p_request_context.get()); + bool ignored = op.get(); } - - // We decompressed into our own buffer; let the stream copy the data - return p_request_context->_get_writebuffer().putn_nocopy(buffer, r.output_bytes_produced).then([p_request_context, r, keep_going](pplx::task op) { - if (op.get() != r.output_bytes_produced) + catch (...) + { + // We're only here to pick up any exception that may have been thrown, and to clean up + // if needed + if (p_request_context->m_compression_state.m_acquired) { - return pplx::task_from_exception(std::runtime_error("Response stream unexpectedly failed to write the requested number of bytes")); + p_request_context->_get_writebuffer().commit(0); + p_request_context->m_compression_state.m_acquired = nullptr; } - return keep_going(p_request_context.get()); - }); - }); - }).then([p_request_context](pplx::task op) - { - try - { - bool ignored = op.get(); - } - catch (...) - { - // We're only here to pick up any exception that may have been thrown, and to clean up if needed - if (p_request_context->m_compression_state.m_acquired) - { - p_request_context->_get_writebuffer().commit(0); - p_request_context->m_compression_state.m_acquired = nullptr; + p_request_context->report_exception(std::current_exception()); } - p_request_context->report_exception(std::current_exception()); - } - }); + }); } else { @@ -2406,26 +2440,29 @@ class winhttp_client final : public _http_client_communicator } else { - writebuf.putn_nocopy(p_request_context->m_body_data.get(), bytesRead).then( - [hRequestHandle, p_request_context, bytesRead] (pplx::task op) - { - size_t written = 0; - try { written = op.get(); } - catch (...) - { - p_request_context->report_exception(std::current_exception()); - return; - } + writebuf.putn_nocopy(p_request_context->m_body_data.get(), bytesRead) + .then([hRequestHandle, p_request_context, bytesRead](pplx::task op) { + size_t written = 0; + try + { + written = op.get(); + } + catch (...) + { + p_request_context->report_exception(std::current_exception()); + return; + } - // If we couldn't write everything, it's time to exit. - if (written != bytesRead) - { - p_request_context->report_exception(std::runtime_error("response stream unexpectedly failed to write the requested number of bytes")); - return; - } + // If we couldn't write everything, it's time to exit. + if (written != bytesRead) + { + p_request_context->report_exception(std::runtime_error( + "response stream unexpectedly failed to write the requested number of bytes")); + return; + } - read_next_response_chunk(p_request_context.get(), bytesRead); - }); + read_next_response_chunk(p_request_context.get(), bytesRead); + }); } } return; @@ -2438,18 +2475,22 @@ class winhttp_client final : public _http_client_communicator // WinHTTP session and connection HINTERNET m_hSession; HINTERNET m_hConnection; - bool m_secure; + bool m_secure; // If auto config is true, dynamically find the proxy for each URL using // the proxy configuration script at the given URL if it's not empty or // using WPAD otherwise. - bool m_proxy_auto_config{false}; - utility::string_t m_proxy_auto_config_url; + bool m_proxy_auto_config {false}; + utility::string_t m_proxy_auto_config_url; }; -std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, http_client_config&& client_config) +std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, + http_client_config&& client_config) { return std::make_shared(std::move(base_uri), std::move(client_config)); } -}}}} +} // namespace details +} // namespace client +} // namespace http +} // namespace web diff --git a/Release/src/http/client/http_client_winrt.cpp b/Release/src/http/client/http_client_winrt.cpp index 79f682ec50..294227512d 100644 --- a/Release/src/http/client/http_client_winrt.cpp +++ b/Release/src/http/client/http_client_winrt.cpp @@ -1,29 +1,28 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Client-side APIs. -* -* This file contains the implementation for the Windows Runtime, using XML HTTP Extended Request. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Client-side APIs. + * + * This file contains the implementation for the Windows Runtime, using XML HTTP Extended Request. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include "http_client_impl.h" #include "../common/internal_http_helpers.h" - +#include "http_client_impl.h" #include // Important for WP8 #if !defined(__WRL_NO_DEFAULT_LIB__) #define __WRL_NO_DEFAULT_LIB__ #endif -#include #include +#include using namespace std; using namespace Platform; using namespace Microsoft::WRL; @@ -36,14 +35,13 @@ namespace client { namespace details { - // Additional information necessary to track a WinRT request. class winrt_request_context final : public request_context { public: - // Factory function to create requests on the heap. - static std::shared_ptr create_request_context(const std::shared_ptr<_http_client_communicator> &client, http_request &request) + static std::shared_ptr create_request_context( + const std::shared_ptr<_http_client_communicator>& client, http_request& request) { return std::make_shared(client, request); } @@ -53,35 +51,31 @@ class winrt_request_context final : public request_context // Request contexts must be created through factory function. // But constructor needs to be public for make_shared to access. - winrt_request_context(const std::shared_ptr<_http_client_communicator> &client, http_request &request) + winrt_request_context(const std::shared_ptr<_http_client_communicator>& client, http_request& request) : request_context(client, request), m_hRequest(nullptr), m_exceptionPtr() { } }; // Implementation of IXMLHTTPRequest2Callback. -class HttpRequestCallback final : - public RuntimeClass, IXMLHTTPRequest2Callback, FtmBase> +class HttpRequestCallback final : public RuntimeClass, IXMLHTTPRequest2Callback, FtmBase> { public: - HttpRequestCallback(const std::shared_ptr &request) - : m_request(request) - { - } + HttpRequestCallback(const std::shared_ptr& request) : m_request(request) {} // Called when the HTTP request is being redirected to a new URL. - HRESULT STDMETHODCALLTYPE OnRedirect(_In_opt_ IXMLHTTPRequest2*, __RPC__in_string const WCHAR*) { - return S_OK; - } + HRESULT STDMETHODCALLTYPE OnRedirect(_In_opt_ IXMLHTTPRequest2*, __RPC__in_string const WCHAR*) { return S_OK; } // Called when HTTP headers have been received and processed. - HRESULT STDMETHODCALLTYPE OnHeadersAvailable(_In_ IXMLHTTPRequest2* xmlReq, DWORD dw, __RPC__in_string const WCHAR* phrase) + HRESULT STDMETHODCALLTYPE OnHeadersAvailable(_In_ IXMLHTTPRequest2* xmlReq, + DWORD dw, + __RPC__in_string const WCHAR* phrase) { - http_response &response = m_request->m_response; + http_response& response = m_request->m_response; response.set_status_code((http::status_code)dw); response.set_reason_phrase(phrase); - utf16char *hdrStr = nullptr; + utf16char* hdrStr = nullptr; HRESULT hr = xmlReq->GetAllResponseHeaders(&hdrStr); if (SUCCEEDED(hr)) { @@ -113,17 +107,19 @@ class HttpRequestCallback final : } // Called when a portion of the entity body has been received. - HRESULT STDMETHODCALLTYPE OnDataAvailable(_In_opt_ IXMLHTTPRequest2*, _In_opt_ ISequentialStream* ) { - return S_OK; - } + HRESULT STDMETHODCALLTYPE OnDataAvailable(_In_opt_ IXMLHTTPRequest2*, _In_opt_ ISequentialStream*) { return S_OK; } // Called when the entire entity response has been received. - HRESULT STDMETHODCALLTYPE OnResponseReceived(_In_opt_ IXMLHTTPRequest2*, _In_opt_ ISequentialStream* ) + HRESULT STDMETHODCALLTYPE OnResponseReceived(_In_opt_ IXMLHTTPRequest2*, _In_opt_ ISequentialStream*) { auto progress = m_request->m_request._get_impl()->_progress_handler(); - if ( progress && m_request->m_downloaded == 0) + if (progress && m_request->m_downloaded == 0) { - try { (*progress)(message_direction::download, 0); } catch(...) + try + { + (*progress)(message_direction::download, 0); + } + catch (...) { m_request->m_exceptionPtr = std::current_exception(); } @@ -160,8 +156,7 @@ class HttpRequestCallback final : std::wstring msg(L"IXMLHttpRequest2Callback::OnError: "); msg.append(std::to_wstring(hrError)); msg.append(L": "); - msg.append(utility::conversions::to_string_t( - utility::details::windows_category().message(hrError))); + msg.append(utility::conversions::to_string_t(utility::details::windows_category().message(hrError))); m_request->report_error(hrError, msg); } else @@ -192,9 +187,9 @@ class IRequestStream final : public Microsoft::WRL::RuntimeClass, ISequentialStream> { public: - IRequestStream(const std::weak_ptr &context, size_t read_length = std::numeric_limits::max()) - : m_context(context), - m_read_length(read_length) + IRequestStream(const std::weak_ptr& context, + size_t read_length = std::numeric_limits::max()) + : m_context(context), m_read_length(read_length) { // read_length is the initial length of the ISequentialStream that is available for read // This is required because IXHR2 attempts to read more data that what is specified by @@ -202,10 +197,10 @@ class IRequestStream final // the content_length specified). } - virtual HRESULT STDMETHODCALLTYPE Read(_Out_writes_ (cb) void *pv, _In_ ULONG cb, _Out_ ULONG *pcbRead) + virtual HRESULT STDMETHODCALLTYPE Read(_Out_writes_(cb) void* pv, _In_ ULONG cb, _Out_ ULONG* pcbRead) { auto context = m_context.lock(); - if(context == nullptr) + if (context == nullptr) { // OnError has already been called so just error out return STG_E_READFAULT; @@ -219,7 +214,7 @@ class IRequestStream final msl::safeint3::SafeInt safe_count = static_cast(cb); size_t size_to_read = safe_count.Min(m_read_length); - const size_t count = buffer.getn((uint8_t *)pv, size_to_read).get(); + const size_t count = buffer.getn((uint8_t*)pv, size_to_read).get(); *pcbRead = (ULONG)count; if (count == 0 && size_to_read != 0) { @@ -231,10 +226,14 @@ class IRequestStream final m_read_length -= count; auto progress = context->m_request._get_impl()->_progress_handler(); - if ( progress && count > 0 ) + if (progress && count > 0) { context->m_uploaded += count; - try { (*progress)(message_direction::upload, context->m_uploaded); } catch(...) + try + { + (*progress)(message_direction::upload, context->m_uploaded); + } + catch (...) { context->m_exceptionPtr = std::current_exception(); return STG_E_READFAULT; @@ -243,14 +242,16 @@ class IRequestStream final return S_OK; } - catch(...) + catch (...) { context->m_exceptionPtr = std::current_exception(); return STG_E_READFAULT; } } - virtual HRESULT STDMETHODCALLTYPE Write(_In_reads_bytes_(cb) const void *pv, _In_ ULONG cb, _Out_opt_ ULONG *pcbWritten) + virtual HRESULT STDMETHODCALLTYPE Write(_In_reads_bytes_(cb) const void* pv, + _In_ ULONG cb, + _Out_opt_ ULONG* pcbWritten) { CASABLANCA_UNREFERENCED_PARAMETER(pv); CASABLANCA_UNREFERENCED_PARAMETER(cb); @@ -259,7 +260,6 @@ class IRequestStream final } private: - // The request context controls the lifetime of this class so we only hold a weak_ptr. std::weak_ptr m_context; @@ -281,14 +281,14 @@ class IResponseStream final : public Microsoft::WRL::RuntimeClass, ISequentialStream> { public: - IResponseStream(const std::weak_ptr &context) - : m_context(context) - { } + IResponseStream(const std::weak_ptr& context) : m_context(context) {} - virtual HRESULT STDMETHODCALLTYPE Write(_In_reads_bytes_(cb) const void *pv, _In_ ULONG cb, _Out_opt_ ULONG *pcbWritten) + virtual HRESULT STDMETHODCALLTYPE Write(_In_reads_bytes_(cb) const void* pv, + _In_ ULONG cb, + _Out_opt_ ULONG* pcbWritten) { auto context = m_context.lock(); - if(context == nullptr) + if (context == nullptr) { // OnError has already been called so just error out return STG_E_CANTSAVE; @@ -307,20 +307,25 @@ class IResponseStream final try { auto buffer = context->_get_writebuffer(); - const size_t count = buffer.putn_nocopy(reinterpret_cast(pv), static_cast(cb)).get(); + const size_t count = + buffer.putn_nocopy(reinterpret_cast(pv), static_cast(cb)).get(); _ASSERTE(count != static_cast(-1)); _ASSERTE(count <= static_cast(ULONG_MAX)); if (pcbWritten != nullptr) { - *pcbWritten = (ULONG) count; + *pcbWritten = (ULONG)count; } context->m_downloaded += count; auto progress = context->m_request._get_impl()->_progress_handler(); if (progress && count > 0) { - try { (*progress)(message_direction::download, context->m_downloaded); } catch(...) + try + { + (*progress)(message_direction::download, context->m_downloaded); + } + catch (...) { context->m_exceptionPtr = std::current_exception(); return STG_E_CANTSAVE; @@ -329,14 +334,16 @@ class IResponseStream final return S_OK; } - catch(...) + catch (...) { context->m_exceptionPtr = std::current_exception(); return STG_E_CANTSAVE; } } - virtual HRESULT STDMETHODCALLTYPE Read(_Out_writes_bytes_to_(cb, *pcbRead) void *pv, _In_ ULONG cb, _Out_ ULONG *pcbRead) + virtual HRESULT STDMETHODCALLTYPE Read(_Out_writes_bytes_to_(cb, *pcbRead) void* pv, + _In_ ULONG cb, + _Out_ ULONG* pcbRead) { CASABLANCA_UNREFERENCED_PARAMETER(pv); CASABLANCA_UNREFERENCED_PARAMETER(cb); @@ -345,7 +352,6 @@ class IResponseStream final } private: - // The request context controls the lifetime of this class so we only hold a weak_ptr. std::weak_ptr m_context; }; @@ -355,10 +361,12 @@ class winrt_client final : public _http_client_communicator { public: winrt_client(http::uri&& address, http_client_config&& client_config) - : _http_client_communicator(std::move(address), std::move(client_config)) { } + : _http_client_communicator(std::move(address), std::move(client_config)) + { + } winrt_client(const winrt_client&) = delete; - winrt_client &operator=(const winrt_client&) = delete; + winrt_client& operator=(const winrt_client&) = delete; virtual pplx::task propagate(http_request request) override { @@ -375,11 +383,10 @@ class winrt_client final : public _http_client_communicator } protected: - // Start sending request. - virtual void send_request(_In_ const std::shared_ptr &request) override + virtual void send_request(_In_ const std::shared_ptr& request) override { - http_request &msg = request->m_request; + http_request& msg = request->m_request; auto winrt_context = std::static_pointer_cast(request); if (!web::http::details::validate_method(msg.method())) @@ -404,12 +411,11 @@ class winrt_client final : public _http_client_communicator } // Start sending HTTP request. - HRESULT hr = CoCreateInstance( - __uuidof(FreeThreadedXMLHTTP60), - nullptr, - CLSCTX_INPROC, - __uuidof(IXMLHTTPRequest2), - reinterpret_cast(winrt_context->m_hRequest.GetAddressOf())); + HRESULT hr = CoCreateInstance(__uuidof(FreeThreadedXMLHTTP60), + nullptr, + CLSCTX_INPROC, + __uuidof(IXMLHTTPRequest2), + reinterpret_cast(winrt_context->m_hRequest.GetAddressOf())); if (FAILED(hr)) { request->report_error(hr, L"Failure to create IXMLHTTPRequest2 instance"); @@ -418,10 +424,10 @@ class winrt_client final : public _http_client_communicator utility::string_t encoded_resource = http::uri_builder(m_uri).append(msg.relative_uri()).to_string(); - const auto &config = client_config(); - const auto &client_cred = config.credentials(); - const auto &proxy = config.proxy(); - const auto &proxy_cred = proxy.credentials(); + const auto& config = client_config(); + const auto& client_cred = config.credentials(); + const auto& proxy = config.proxy(); + const auto& proxy_cred = proxy.credentials(); if (!proxy.is_default()) { request->report_exception(http_exception(L"Only a default proxy server is supported")); @@ -431,8 +437,8 @@ class winrt_client final : public _http_client_communicator // New scope to ensure plain text password is cleared as soon as possible. { utility::string_t username, proxy_username; - const utility::char_t *password = nullptr; - const utility::char_t *proxy_password = nullptr; + const utility::char_t* password = nullptr; + const utility::char_t* proxy_password = nullptr; ::web::details::plaintext_string password_plaintext, proxy_password_plaintext; if (client_cred.is_set()) @@ -448,14 +454,13 @@ class winrt_client final : public _http_client_communicator proxy_password = proxy_password_plaintext->c_str(); } - hr = winrt_context->m_hRequest->Open( - msg.method().c_str(), - encoded_resource.c_str(), - Make(winrt_context).Get(), - username.c_str(), - password, - proxy_username.c_str(), - proxy_password); + hr = winrt_context->m_hRequest->Open(msg.method().c_str(), + encoded_resource.c_str(), + Make(winrt_context).Get(), + username.c_str(), + password, + proxy_username.c_str(), + proxy_password); } if (FAILED(hr)) { @@ -493,7 +498,7 @@ class winrt_client final : public _http_client_communicator #endif // Add headers. - for (const auto &hdr : msg.headers()) + for (const auto& hdr : msg.headers()) { winrt_context->m_hRequest->SetRequestHeader(hdr.first.c_str(), hdr.second.c_str()); } @@ -523,38 +528,41 @@ class winrt_client final : public _http_client_communicator } else { - if ( msg.method() == http::methods::GET || msg.method() == http::methods::HEAD ) + if (msg.method() == http::methods::GET || msg.method() == http::methods::HEAD) { request->report_exception(http_exception(get_with_body_err_msg)); return; } - hr = winrt_context->m_hRequest->Send(Make(winrt_context, content_length).Get(), content_length); + hr = winrt_context->m_hRequest->Send(Make(winrt_context, content_length).Get(), + content_length); } - if ( FAILED(hr) ) + if (FAILED(hr)) { request->report_error(hr, L"Failure to send HTTP request"); return; } // Register for notification on cancellation to abort this request. - if(msg._cancellation_token() != pplx::cancellation_token::none()) + if (msg._cancellation_token() != pplx::cancellation_token::none()) { auto requestHandle = winrt_context->m_hRequest; // cancellation callback is unregistered when request is completed. - winrt_context->m_cancellationRegistration = msg._cancellation_token().register_callback([requestHandle]() - { - requestHandle->Abort(); - }); + winrt_context->m_cancellationRegistration = + msg._cancellation_token().register_callback([requestHandle]() { requestHandle->Abort(); }); } } }; -std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, http_client_config&& client_config) +std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, + http_client_config&& client_config) { return std::make_shared(std::move(base_uri), std::move(client_config)); } -}}}} +} // namespace details +} // namespace client +} // namespace http +} // namespace web diff --git a/Release/src/http/client/x509_cert_utilities.cpp b/Release/src/http/client/x509_cert_utilities.cpp index 21b12110ce..67fc5ac47b 100644 --- a/Release/src/http/client/x509_cert_utilities.cpp +++ b/Release/src/http/client/x509_cert_utilities.cpp @@ -2,16 +2,17 @@ * Copyright (C) Microsoft. All rights reserved. * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * - * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * Contains utility functions for helping to verify server certificates in OS X/iOS. * * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk * - * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" + #include "../common/x509_cert_utilities.h" #ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE @@ -53,10 +54,10 @@ bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context& verif #if (OPENSSL_VERSION_NUMBER < 0x10100000L) STACK_OF(X509)* certStack = X509_STORE_CTX_get_chain(storeContext); -#else +#else STACK_OF(X509)* certStack = X509_STORE_CTX_get0_chain(storeContext); #endif - + const int numCerts = sk_X509_num(certStack); if (numCerts < 0) { @@ -313,7 +314,7 @@ class cf_ref cf_ref& operator=(const cf_ref&); T value; }; -} +} // namespace bool verify_X509_cert_chain(const std::vector& certChain, const std::string& hostName) { @@ -443,9 +444,9 @@ bool verify_X509_cert_chain(const std::vector& certChain, const std return true; } #endif -} -} -} -} +} // namespace details +} // namespace client +} // namespace http +} // namespace web #endif diff --git a/Release/src/http/common/connection_pool_helpers.h b/Release/src/http/common/connection_pool_helpers.h index 580b82af23..df6877a69a 100644 --- a/Release/src/http/common/connection_pool_helpers.h +++ b/Release/src/http/common/connection_pool_helpers.h @@ -1,8 +1,8 @@ #pragma once #include "cpprest/details/cpprest_compat.h" -#include #include +#include #include namespace web @@ -13,7 +13,6 @@ namespace client { namespace details { - template class connection_pool_stack { @@ -41,10 +40,7 @@ class connection_pool_stack } // releases `released` back to the connection pool - void release(std::shared_ptr&& released) - { - m_connections.push_back(std::move(released)); - } + void release(std::shared_ptr&& released) { m_connections.push_back(std::move(released)); } bool free_stale_connections() CPPREST_NOEXCEPT { @@ -60,7 +56,7 @@ class connection_pool_stack size_t m_staleBefore = 0; }; -} // details -} // client -} // http -} // web +} // namespace details +} // namespace client +} // namespace http +} // namespace web diff --git a/Release/src/http/common/http_compression.cpp b/Release/src/http/common/http_compression.cpp index b814093d1b..202a1b92bf 100644 --- a/Release/src/http/common/http_compression.cpp +++ b/Release/src/http/common/http_compression.cpp @@ -2,13 +2,13 @@ * Copyright (C) Microsoft. All rights reserved. * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * - * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * HTTP Library: Compression and decompression interfaces * * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk * - * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" @@ -92,11 +92,11 @@ class zlib_compressor_base : public compress_provider #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-constant-compare" -#endif // __clang__ +#endif // __clang__ if (input_size > std::numeric_limits::max() || output_size > std::numeric_limits::max()) #if defined(__clang__) #pragma clang diagnostic pop -#endif // __clang__ +#endif // __clang__ { throw std::runtime_error("Compression input or output size out of range"); } @@ -150,8 +150,8 @@ class zlib_compressor_base : public compress_provider ~zlib_compressor_base() { (void)deflateEnd(&m_stream); } private: - int m_state{Z_BUF_ERROR}; - z_stream m_stream{}; + int m_state {Z_BUF_ERROR}; + z_stream m_stream {}; const utility::string_t& m_algorithm; }; @@ -193,11 +193,11 @@ class zlib_decompressor_base : public decompress_provider #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-constant-compare" -#endif // __clang__ +#endif // __clang__ if (input_size > std::numeric_limits::max() || output_size > std::numeric_limits::max()) #if defined(__clang__) #pragma clang diagnostic pop -#endif // __clang__ +#endif // __clang__ { throw std::runtime_error("Compression input or output size out of range"); } @@ -252,8 +252,8 @@ class zlib_decompressor_base : public decompress_provider ~zlib_decompressor_base() { (void)inflateEnd(&m_stream); } private: - int m_state{Z_BUF_ERROR}; - z_stream m_stream{}; + int m_state {Z_BUF_ERROR}; + z_stream m_stream {}; const utility::string_t& m_algorithm; }; @@ -472,9 +472,9 @@ class brotli_compressor : public compress_provider } private: - BROTLI_BOOL m_state{BROTLI_FALSE}; - BrotliEncoderState* m_stream{nullptr}; - bool m_done{false}; + BROTLI_BOOL m_state {BROTLI_FALSE}; + BrotliEncoderState* m_stream {nullptr}; + bool m_done {false}; uint32_t m_window; uint32_t m_quality; uint32_t m_mode; @@ -589,8 +589,8 @@ class brotli_decompressor : public decompress_provider } private: - BrotliDecoderResult m_state{BROTLI_DECODER_RESULT_ERROR}; - BrotliDecoderState* m_stream{nullptr}; + BrotliDecoderResult m_state {BROTLI_DECODER_RESULT_ERROR}; + BrotliDecoderState* m_stream {nullptr}; const utility::string_t& m_algorithm; }; #endif // CPPREST_BROTLI_COMPRESSION diff --git a/Release/src/http/common/http_helpers.cpp b/Release/src/http/common/http_helpers.cpp index 0d17c569eb..9ffbd20dd0 100644 --- a/Release/src/http/common/http_helpers.cpp +++ b/Release/src/http/common/http_helpers.cpp @@ -1,33 +1,35 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Implementation Details of the http.h layer of messaging -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Implementation Details of the http.h layer of messaging + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "internal_http_helpers.h" using namespace web; using namespace utility; using namespace utility::conversions; -namespace web { namespace http +namespace web +{ +namespace http { namespace details { - // Remove once VS 2013 is no longer supported. #if defined(_WIN32) && _MSC_VER < 1900 -static const http_status_to_phrase idToPhraseMap [] = { +static const http_status_to_phrase idToPhraseMap[] = { #define _PHRASES -#define DAT(a,b,c) {status_codes::a, c}, +#define DAT(a, b, c) {status_codes::a, c}, #include "cpprest/details/http_constants.dat" #undef _PHRASES #undef DAT @@ -39,9 +41,9 @@ utility::string_t get_default_reason_phrase(status_code code) // Future improvement: why is this stored as an array of structs instead of a map // indexed on the status code for faster lookup? // Not a big deal because it is uncommon to not include a reason phrase. - static const http_status_to_phrase idToPhraseMap [] = { + static const http_status_to_phrase idToPhraseMap[] = { #define _PHRASES -#define DAT(a,b,c) {status_codes::a, c}, +#define DAT(a, b, c) {status_codes::a, c}, #include "cpprest/details/http_constants.dat" #undef _PHRASES #undef DAT @@ -49,7 +51,7 @@ utility::string_t get_default_reason_phrase(status_code code) #endif utility::string_t phrase; - for (const auto &elm : idToPhraseMap) + for (const auto& elm : idToPhraseMap) { if (elm.id == code) { @@ -60,7 +62,9 @@ utility::string_t get_default_reason_phrase(status_code code) return phrase; } -size_t chunked_encoding::add_chunked_delimiters(_Out_writes_(buffer_size) uint8_t *data, _In_ size_t buffer_size, size_t bytes_read) +size_t chunked_encoding::add_chunked_delimiters(_Out_writes_(buffer_size) uint8_t* data, + _In_ size_t buffer_size, + size_t bytes_read) { size_t offset = 0; @@ -73,8 +77,10 @@ size_t chunked_encoding::add_chunked_delimiters(_Out_writes_(buffer_size) uint8_ { offset = 7; data[7] = '0'; - data[8] = '\r'; data[9] = '\n'; // The end of the size. - data[10] = '\r'; data[11] = '\n'; // The end of the message. + data[8] = '\r'; + data[9] = '\n'; // The end of the size. + data[10] = '\r'; + data[11] = '\n'; // The end of the message. } else { @@ -85,41 +91,42 @@ size_t chunked_encoding::add_chunked_delimiters(_Out_writes_(buffer_size) uint8_ snprintf(buffer, sizeof(buffer), "%8zX", bytes_read); #endif memcpy(&data[0], buffer, 8); - while (data[offset] == ' ') ++offset; - data[8] = '\r'; data[9] = '\n'; // The end of the size. - data[10 + bytes_read] = '\r'; data[11 + bytes_read] = '\n'; // The end of the chunk. + while (data[offset] == ' ') + ++offset; + data[8] = '\r'; + data[9] = '\n'; // The end of the size. + data[10 + bytes_read] = '\r'; + data[11 + bytes_read] = '\n'; // The end of the chunk. } return offset; } -static const std::array valid_chars = -{{ +static const std::array valid_chars = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //16-31 - 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, //32-47 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, //48-63 - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //64-79 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, //80-95 - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //96-111 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 //112-127 - }}; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32-47 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48-63 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64-79 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 80-95 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96-111 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112-127 +}}; // Checks if the method contains any invalid characters bool validate_method(const utility::string_t& method) { - for (const auto &ch : method) + for (const auto& ch : method) { size_t ch_sz = static_cast(ch); - if (ch_sz >= 128) - return false; + if (ch_sz >= 128) return false; - if (!valid_chars[ch_sz]) - return false; + if (!valid_chars[ch_sz]) return false; } return true; } } // namespace details -}} // namespace web::http +} // namespace http +} // namespace web diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 7c8a6713f6..acc84fa54f 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -1,19 +1,20 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Request and reply message definitions. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Request and reply message definitions. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include + #include "../common/internal_http_helpers.h" #include "cpprest/producerconsumerstream.h" +#include using namespace web; using namespace utility; @@ -21,9 +22,10 @@ using namespace concurrency; using namespace utility::conversions; using namespace http::details; -namespace web { namespace http +namespace web +{ +namespace http { - #define CRLF _XPLATSTR("\r\n") utility::string_t http_headers::content_type() const @@ -33,145 +35,139 @@ utility::string_t http_headers::content_type() const return result; } - - /// Helper functions to convert a series of bytes from a charset to utf-8 or utf-16. /// These APIs deal with checking for and handling byte order marker (BOM). -namespace { - enum endianness - { - little_endian, - big_endian, - unknown - }; - endianness check_byte_order_mark(const utf16string &str) +namespace +{ +enum endianness +{ + little_endian, + big_endian, + unknown +}; +endianness check_byte_order_mark(const utf16string& str) +{ + if (str.empty()) { - if (str.empty()) - { - return unknown; - } - const unsigned char *src = reinterpret_cast(str.data()); - - // little endian - if (src[0] == 0xFF && src[1] == 0xFE) - { - return little_endian; - } - - // big endian - else if (src[0] == 0xFE && src[1] == 0xFF) - { - return big_endian; - } - return unknown; } + const unsigned char* src = reinterpret_cast(str.data()); - std::string convert_utf16le_to_utf8(utf16string src, bool erase_bom) + // little endian + if (src[0] == 0xFF && src[1] == 0xFE) { - if (erase_bom && !src.empty()) - { - src.erase(0, 1); - } - return utf16_to_utf8(std::move(src)); + return little_endian; } - utility::string_t convert_utf16le_to_string_t(utf16string src, bool erase_bom) + // big endian + else if (src[0] == 0xFE && src[1] == 0xFF) { - if (erase_bom && !src.empty()) - { - src.erase(0, 1); - } - #ifdef _UTF16_STRINGS - return src; - #else - return utf16_to_utf8(std::move(src)); - #endif + return big_endian; } - // Helper function to change endian ness from big endian to little endian - utf16string big_endian_to_little_endian(utf16string src, bool erase_bom) - { - if (erase_bom && !src.empty()) - { - src.erase(0, 1); - } - if (src.empty()) - { - return src; - } - - const size_t size = src.size(); - for (size_t i = 0; i < size; ++i) - { - utf16char ch = src[i]; - src[i] = static_cast(ch << 8); - src[i] = static_cast(src[i] | ch >> 8); - } + return unknown; +} - return src; +std::string convert_utf16le_to_utf8(utf16string src, bool erase_bom) +{ + if (erase_bom && !src.empty()) + { + src.erase(0, 1); } + return utf16_to_utf8(std::move(src)); +} - std::string convert_utf16be_to_utf8(utf16string src, bool erase_bom) +utility::string_t convert_utf16le_to_string_t(utf16string src, bool erase_bom) +{ + if (erase_bom && !src.empty()) { - return utf16_to_utf8(big_endian_to_little_endian(std::move(src), erase_bom)); + src.erase(0, 1); } +#ifdef _UTF16_STRINGS + return src; +#else + return utf16_to_utf8(std::move(src)); +#endif +} - utf16string convert_utf16be_to_utf16le(utf16string src, bool erase_bom) +// Helper function to change endian ness from big endian to little endian +utf16string big_endian_to_little_endian(utf16string src, bool erase_bom) +{ + if (erase_bom && !src.empty()) + { + src.erase(0, 1); + } + if (src.empty()) { - return big_endian_to_little_endian(std::move(src), erase_bom); + return src; } - utility::string_t convert_utf16be_to_string_t(utf16string src, bool erase_bom) + const size_t size = src.size(); + for (size_t i = 0; i < size; ++i) { - #ifdef _UTF16_STRINGS - return convert_utf16be_to_utf16le(std::move(src), erase_bom); - #else - return convert_utf16be_to_utf8(std::move(src), erase_bom); - #endif + utf16char ch = src[i]; + src[i] = static_cast(ch << 8); + src[i] = static_cast(src[i] | ch >> 8); } - std::string convert_utf16_to_utf8(utf16string src) + return src; +} + +std::string convert_utf16be_to_utf8(utf16string src, bool erase_bom) +{ + return utf16_to_utf8(big_endian_to_little_endian(std::move(src), erase_bom)); +} + +utf16string convert_utf16be_to_utf16le(utf16string src, bool erase_bom) +{ + return big_endian_to_little_endian(std::move(src), erase_bom); +} + +utility::string_t convert_utf16be_to_string_t(utf16string src, bool erase_bom) +{ +#ifdef _UTF16_STRINGS + return convert_utf16be_to_utf16le(std::move(src), erase_bom); +#else + return convert_utf16be_to_utf8(std::move(src), erase_bom); +#endif +} + +std::string convert_utf16_to_utf8(utf16string src) +{ + const endianness endian = check_byte_order_mark(src); + switch (endian) { - const endianness endian = check_byte_order_mark(src); - switch (endian) - { - case little_endian: - return convert_utf16le_to_utf8(std::move(src), true); - case big_endian: - return convert_utf16be_to_utf8(std::move(src), true); + case little_endian: return convert_utf16le_to_utf8(std::move(src), true); + case big_endian: return convert_utf16be_to_utf8(std::move(src), true); case unknown: // unknown defaults to big endian. return convert_utf16be_to_utf8(std::move(src), false); - } - __assume(0); } + __assume(0); +} - utf16string convert_utf16_to_utf16(utf16string src) +utf16string convert_utf16_to_utf16(utf16string src) +{ + const endianness endian = check_byte_order_mark(src); + switch (endian) { - const endianness endian = check_byte_order_mark(src); - switch (endian) - { - case little_endian: - src.erase(0, 1); - return src; - case big_endian: - return convert_utf16be_to_utf16le(std::move(src), true); + case little_endian: src.erase(0, 1); return src; + case big_endian: return convert_utf16be_to_utf16le(std::move(src), true); case unknown: // unknown defaults to big endian. return convert_utf16be_to_utf16le(std::move(src), false); - } - __assume(0); - } - utility::string_t convert_utf16_to_string_t(utf16string src) - { - #ifdef _UTF16_STRINGS - return convert_utf16_to_utf16(std::move(src)); - #else - return convert_utf16_to_utf8(std::move(src)); - #endif } + __assume(0); } +utility::string_t convert_utf16_to_string_t(utf16string src) +{ +#ifdef _UTF16_STRINGS + return convert_utf16_to_utf16(std::move(src)); +#else + return convert_utf16_to_utf8(std::move(src)); +#endif +} +} // namespace void http_headers::set_content_type(utility::string_t type) { @@ -214,9 +210,9 @@ void http_headers::set_content_length(utility::size64_t length) m_headers[http::header_names::content_length] = utility::conversions::details::to_string_t(length); } -namespace details { - -utility::string_t flatten_http_headers(const http_headers &headers) +namespace details +{ +utility::string_t flatten_http_headers(const http_headers& headers) { utility::string_t flattened_headers; for (auto iter = headers.begin(); iter != headers.end(); ++iter) @@ -230,10 +226,10 @@ utility::string_t flatten_http_headers(const http_headers &headers) } #if defined(_WIN32) -void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers) +void parse_headers_string(_Inout_z_ utf16char* headersStr, http_headers& headers) { - utf16char *context = nullptr; - utf16char *line = wcstok_s(headersStr, CRLF, &context); + utf16char* context = nullptr; + utf16char* line = wcstok_s(headersStr, CRLF, &context); while (line != nullptr) { const utility::string_t header_line(line); @@ -251,24 +247,28 @@ void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers } #endif -} +} // namespace details http_version __cdecl http_version::from_string(const std::string& http_version_string) { std::istringstream str(http_version_string); str.imbue(std::locale::classic()); - std::string http; std::getline(str, http, '/'); - unsigned int major = 0; str >> major; - char dot = '\0'; str >> dot; - unsigned int minor = 0; str >> minor; + std::string http; + std::getline(str, http, '/'); + unsigned int major = 0; + str >> major; + char dot = '\0'; + str >> dot; + unsigned int minor = 0; + str >> minor; // check no failure, fully consumed, and correct fixed text if (!str.fail() && str.eof() && "HTTP" == http && '.' == dot) { - return{ (uint8_t)major, (uint8_t)minor }; + return {(uint8_t)major, (uint8_t)minor}; } - return{ 0, 0 }; + return {0, 0}; } std::string http_version::to_utf8string() const @@ -282,14 +282,12 @@ std::string http_version::to_utf8string() const return ret; } -static const utility::char_t * stream_was_set_explicitly = _XPLATSTR("A stream was set on the message and extraction is not possible"); -static const utility::char_t * unsupported_charset = _XPLATSTR("Charset must be iso-8859-1, utf-8, utf-16, utf-16le, or utf-16be to be extracted."); +static const utility::char_t* stream_was_set_explicitly = + _XPLATSTR("A stream was set on the message and extraction is not possible"); +static const utility::char_t* unsupported_charset = + _XPLATSTR("Charset must be iso-8859-1, utf-8, utf-16, utf-16le, or utf-16be to be extracted."); -http_msg_base::http_msg_base() - : m_headers(), - m_default_outstream(false) -{ -} +http_msg_base::http_msg_base() : m_headers(), m_default_outstream(false) {} void http_msg_base::_prepare_to_receive_data() { @@ -314,7 +312,7 @@ void http_msg_base::_prepare_to_receive_data() size_t http_msg_base::_get_stream_length() { - auto &stream = instream(); + auto& stream = instream(); if (stream.can_seek()) { @@ -391,20 +389,17 @@ size_t http_msg_base::_get_content_length(bool honor_compression) return 0; } -size_t http_msg_base::_get_content_length_and_set_compression() -{ - return _get_content_length(true); -} +size_t http_msg_base::_get_content_length_and_set_compression() { return _get_content_length(true); } -size_t http_msg_base::_get_content_length() -{ - return _get_content_length(false); -} +size_t http_msg_base::_get_content_length() { return _get_content_length(false); } // Helper function to inline continuation if possible. struct inline_continuation { - inline_continuation(pplx::task &prev, const std::function)> &next) : m_prev(prev), m_next(next) {} + inline_continuation(pplx::task& prev, const std::function)>& next) + : m_prev(prev), m_next(next) + { + } ~inline_continuation() { if (m_prev.is_done()) @@ -416,16 +411,17 @@ struct inline_continuation m_prev.then(m_next); } } - pplx::task & m_prev; + pplx::task& m_prev; std::function)> m_next; + private: - inline_continuation(const inline_continuation &); - inline_continuation &operator=(const inline_continuation &); + inline_continuation(const inline_continuation&); + inline_continuation& operator=(const inline_continuation&); }; -void http_msg_base::_complete(utility::size64_t body_size, const std::exception_ptr &exceptionPtr) +void http_msg_base::_complete(utility::size64_t body_size, const std::exception_ptr& exceptionPtr) { - const auto &completionEvent = _get_data_available(); + const auto& completionEvent = _get_data_available(); auto closeTask = pplx::task_from_result(); if (exceptionPtr == std::exception_ptr()) @@ -435,8 +431,7 @@ void http_msg_base::_complete(utility::size64_t body_size, const std::exception_ closeTask = outstream().close(); } - inline_continuation(closeTask, [completionEvent, body_size](pplx::task t) - { + inline_continuation(closeTask, [completionEvent, body_size](pplx::task t) { try { t.get(); @@ -446,10 +441,14 @@ void http_msg_base::_complete(utility::size64_t body_size, const std::exception_ { // If close throws an exception report back to user. completionEvent.set_exception(std::current_exception()); - pplx::create_task(completionEvent).then([](pplx::task t) - { - try { t.get(); } - catch (...) {} + pplx::create_task(completionEvent).then([](pplx::task t) { + try + { + t.get(); + } + catch (...) + { + } }); } }); @@ -461,22 +460,32 @@ void http_msg_base::_complete(utility::size64_t body_size, const std::exception_ closeTask = outstream().close(exceptionPtr); } - inline_continuation(closeTask, [completionEvent, exceptionPtr](pplx::task t) - { + inline_continuation(closeTask, [completionEvent, exceptionPtr](pplx::task t) { // If closing stream throws an exception ignore since we already have an error. - try { t.get(); } - catch (...) {} - completionEvent.set_exception(exceptionPtr); - pplx::create_task(completionEvent).then([](pplx::task t) + try + { + t.get(); + } + catch (...) { - try { t.get(); } - catch (...) {} + } + completionEvent.set_exception(exceptionPtr); + pplx::create_task(completionEvent).then([](pplx::task t) { + try + { + t.get(); + } + catch (...) + { + } }); }); } } -static bool is_content_type_one_of(const utility::string_t *first, const utility::string_t *last, const utility::string_t &value) +static bool is_content_type_one_of(const utility::string_t* first, + const utility::string_t* last, + const utility::string_t& value) { while (first != last) { @@ -492,30 +501,26 @@ static bool is_content_type_one_of(const utility::string_t *first, const utility // Remove once VS 2013 is no longer supported. #if defined(_WIN32) && _MSC_VER < 1900 // Not referring to mime_types to avoid static initialization order fiasco. -static const utility::string_t textual_types [] = { - U("message/http"), - U("application/json"), - U("application/xml"), - U("application/atom+xml"), - U("application/http"), - U("application/x-www-form-urlencoded") -}; +static const utility::string_t textual_types[] = {U("message/http"), + U("application/json"), + U("application/xml"), + U("application/atom+xml"), + U("application/http"), + U("application/x-www-form-urlencoded")}; #endif /// /// Determines whether or not the given content type is 'textual' according the feature specifications. /// -static bool is_content_type_textual(const utility::string_t &content_type) +static bool is_content_type_textual(const utility::string_t& content_type) { #if !defined(_WIN32) || _MSC_VER >= 1900 - static const utility::string_t textual_types [] = { - mime_types::message_http, - mime_types::application_json, - mime_types::application_xml, - mime_types::application_atom_xml, - mime_types::application_http, - mime_types::application_x_www_form_urlencoded - }; + static const utility::string_t textual_types[] = {mime_types::message_http, + mime_types::application_json, + mime_types::application_xml, + mime_types::application_atom_xml, + mime_types::application_http, + mime_types::application_x_www_form_urlencoded}; #endif if (content_type.size() >= 4 && utility::details::str_iequal(content_type.substr(0, 4), _XPLATSTR("text"))) @@ -528,43 +533,40 @@ static bool is_content_type_textual(const utility::string_t &content_type) // Remove once VS 2013 is no longer supported. #if defined(_WIN32) && _MSC_VER < 1900 // Not referring to mime_types to avoid static initialization order fiasco. -static const utility::string_t json_types [] = { - U("application/json"), - U("application/x-json"), - U("text/json"), - U("text/x-json"), - U("text/javascript"), - U("text/x-javascript"), - U("application/javascript"), - U("application/x-javascript") -}; +static const utility::string_t json_types[] = {U("application/json"), + U("application/x-json"), + U("text/json"), + U("text/x-json"), + U("text/javascript"), + U("text/x-javascript"), + U("application/javascript"), + U("application/x-javascript")}; #endif /// /// Determines whether or not the given content type is JSON according the feature specifications. /// -static bool is_content_type_json(const utility::string_t &content_type) +static bool is_content_type_json(const utility::string_t& content_type) { #if !defined(_WIN32) || _MSC_VER >= 1900 - static const utility::string_t json_types [] = { - mime_types::application_json, - mime_types::application_xjson, - mime_types::text_json, - mime_types::text_xjson, - mime_types::text_javascript, - mime_types::text_xjavascript, - mime_types::application_javascript, - mime_types::application_xjavascript - }; + static const utility::string_t json_types[] = {mime_types::application_json, + mime_types::application_xjson, + mime_types::text_json, + mime_types::text_xjson, + mime_types::text_javascript, + mime_types::text_xjavascript, + mime_types::application_javascript, + mime_types::application_xjavascript}; #endif return (is_content_type_one_of(std::begin(json_types), std::end(json_types), content_type)); } /// -/// Gets the default charset for given content type. If the MIME type is not textual or recognized Latin1 will be returned. +/// Gets the default charset for given content type. If the MIME type is not textual or recognized Latin1 will be +/// returned. /// -static utility::string_t get_default_charset(const utility::string_t &content_type) +static utility::string_t get_default_charset(const utility::string_t& content_type) { // We are defaulting everything to Latin1 except JSON which is utf-8. if (is_content_type_json(content_type)) @@ -577,12 +579,13 @@ static utility::string_t get_default_charset(const utility::string_t &content_ty } } - /// /// Parses the given Content-Type header value to get out actual content type and charset. /// If the charset isn't specified the default charset for the content type will be set. /// -static void parse_content_type_and_charset(const utility::string_t &content_type, utility::string_t &content, utility::string_t &charset) +static void parse_content_type_and_charset(const utility::string_t& content_type, + utility::string_t& content, + utility::string_t& charset) { const size_t semi_colon_index = content_type.find_first_of(_XPLATSTR(";")); @@ -631,7 +634,8 @@ static void parse_content_type_and_charset(const utility::string_t &content_type } } -utility::string_t details::http_msg_base::parse_and_check_content_type(bool ignore_content_type, const std::function &check_content_type) +utility::string_t details::http_msg_base::parse_and_check_content_type( + bool ignore_content_type, const std::function& check_content_type) { if (!instream()) { @@ -651,7 +655,8 @@ utility::string_t details::http_msg_base::parse_and_check_content_type(bool igno if (!check_content_type(content)) { - throw http_exception(_XPLATSTR("Incorrect Content-Type: must be textual to extract_string, JSON to extract_json.")); + throw http_exception( + _XPLATSTR("Incorrect Content-Type: must be textual to extract_string, JSON to extract_json.")); } } return charset; @@ -659,7 +664,7 @@ utility::string_t details::http_msg_base::parse_and_check_content_type(bool igno utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) { - const auto &charset = parse_and_check_content_type(ignore_content_type, is_content_type_textual); + const auto& charset = parse_and_check_content_type(ignore_content_type, is_content_type_textual); if (charset.empty()) { return utf8string(); @@ -667,13 +672,14 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) auto buf_r = instream().streambuf(); // Perform the correct character set conversion if one is necessary. - if (utility::details::str_iequal(charset, charset_types::utf8) - || utility::details::str_iequal(charset, charset_types::usascii) - || utility::details::str_iequal(charset, charset_types::ascii)) + if (utility::details::str_iequal(charset, charset_types::utf8) || + utility::details::str_iequal(charset, charset_types::usascii) || + utility::details::str_iequal(charset, charset_types::ascii)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()) + .get(); // There is no risk of blocking. return body; } @@ -682,7 +688,8 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()) + .get(); // There is no risk of blocking. return latin1_to_utf8(std::move(body)); } @@ -691,7 +698,8 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return convert_utf16_to_utf8(std::move(body)); } @@ -700,7 +708,8 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return utility::conversions::utf16_to_utf8(std::move(body)); } @@ -709,7 +718,8 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return convert_utf16be_to_utf8(std::move(body), false); } @@ -721,7 +731,7 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type) { - const auto &charset = parse_and_check_content_type(ignore_content_type, is_content_type_textual); + const auto& charset = parse_and_check_content_type(ignore_content_type, is_content_type_textual); if (charset.empty()) { return utf16string(); @@ -733,18 +743,20 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return body; } // utf-8, ascii - else if (utility::details::str_iequal(charset, charset_types::utf8) - || utility::details::str_iequal(charset, charset_types::usascii) - || utility::details::str_iequal(charset, charset_types::ascii)) + else if (utility::details::str_iequal(charset, charset_types::utf8) || + utility::details::str_iequal(charset, charset_types::usascii) || + utility::details::str_iequal(charset, charset_types::ascii)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()) + .get(); // There is no risk of blocking. return utility::conversions::utf8_to_utf16(std::move(body)); } @@ -753,7 +765,8 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()) + .get(); // There is no risk of blocking. return latin1_to_utf16(std::move(body)); } @@ -762,7 +775,8 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return convert_utf16_to_utf16(std::move(body)); } @@ -771,7 +785,8 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return convert_utf16be_to_utf16le(std::move(body), false); } @@ -783,7 +798,7 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type utility::string_t details::http_msg_base::extract_string(bool ignore_content_type) { - const auto &charset = parse_and_check_content_type(ignore_content_type, is_content_type_textual); + const auto& charset = parse_and_check_content_type(ignore_content_type, is_content_type_textual); if (charset.empty()) { return utility::string_t(); @@ -791,58 +806,64 @@ utility::string_t details::http_msg_base::extract_string(bool ignore_content_typ auto buf_r = instream().streambuf(); // Perform the correct character set conversion if one is necessary. - if (utility::details::str_iequal(charset, charset_types::usascii) - || utility::details::str_iequal(charset, charset_types::ascii)) + if (utility::details::str_iequal(charset, charset_types::usascii) || + utility::details::str_iequal(charset, charset_types::ascii)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()) + .get(); // There is no risk of blocking. return to_string_t(std::move(body)); } // Latin1 - if(utility::details::str_iequal(charset, charset_types::latin1)) + if (utility::details::str_iequal(charset, charset_types::latin1)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()) + .get(); // There is no risk of blocking. // Could optimize for linux in the future if a latin1_to_utf8 function was written. return to_string_t(latin1_to_utf16(std::move(body))); } // utf-8. - else if(utility::details::str_iequal(charset, charset_types::utf8)) + else if (utility::details::str_iequal(charset, charset_types::utf8)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()) + .get(); // There is no risk of blocking. return to_string_t(std::move(body)); } // utf-16. - else if(utility::details::str_iequal(charset, charset_types::utf16)) + else if (utility::details::str_iequal(charset, charset_types::utf16)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return convert_utf16_to_string_t(std::move(body)); } // utf-16le - else if(utility::details::str_iequal(charset, charset_types::utf16le)) + else if (utility::details::str_iequal(charset, charset_types::utf16le)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return convert_utf16le_to_string_t(std::move(body), false); } // utf-16be - else if(utility::details::str_iequal(charset, charset_types::utf16be)) + else if (utility::details::str_iequal(charset, charset_types::utf16be)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return convert_utf16be_to_string_t(std::move(body), false); } @@ -854,7 +875,7 @@ utility::string_t details::http_msg_base::extract_string(bool ignore_content_typ json::value details::http_msg_base::_extract_json(bool ignore_content_type) { - const auto &charset = parse_and_check_content_type(ignore_content_type, is_content_type_json); + const auto& charset = parse_and_check_content_type(ignore_content_type, is_content_type_json); if (charset.empty()) { return json::value(); @@ -862,50 +883,55 @@ json::value details::http_msg_base::_extract_json(bool ignore_content_type) auto buf_r = instream().streambuf(); // Latin1 - if(utility::details::str_iequal(charset, charset_types::latin1)) + if (utility::details::str_iequal(charset, charset_types::latin1)) { std::string body; body.resize(buf_r.in_avail()); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()) + .get(); // There is no risk of blocking. // On Linux could optimize in the future if a latin1_to_utf8 function is written. return json::value::parse(to_string_t(latin1_to_utf16(std::move(body)))); } // utf-8, usascii and ascii - else if(utility::details::str_iequal(charset, charset_types::utf8) - || utility::details::str_iequal(charset, charset_types::usascii) - || utility::details::str_iequal(charset, charset_types::ascii)) + else if (utility::details::str_iequal(charset, charset_types::utf8) || + utility::details::str_iequal(charset, charset_types::usascii) || + utility::details::str_iequal(charset, charset_types::ascii)) { std::string body; body.resize(buf_r.in_avail()); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size()) + .get(); // There is no risk of blocking. return json::value::parse(to_string_t(std::move(body))); } // utf-16. - else if(utility::details::str_iequal(charset, charset_types::utf16)) + else if (utility::details::str_iequal(charset, charset_types::utf16)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return json::value::parse(convert_utf16_to_string_t(std::move(body))); } // utf-16le - else if(utility::details::str_iequal(charset, charset_types::utf16le)) + else if (utility::details::str_iequal(charset, charset_types::utf16le)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return json::value::parse(convert_utf16le_to_string_t(std::move(body), false)); } // utf-16be - else if(utility::details::str_iequal(charset, charset_types::utf16be)) + else if (utility::details::str_iequal(charset, charset_types::utf16be)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); - buf_r.getn(const_cast(reinterpret_cast(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), + body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking. return json::value::parse(convert_utf16be_to_string_t(std::move(body), false)); } @@ -926,13 +952,15 @@ std::vector details::http_msg_base::_extract_vector() auto buf_r = instream().streambuf(); const size_t size = buf_r.in_avail(); body.resize(size); - buf_r.getn(const_cast(reinterpret_cast(body.data())), size).get(); // There is no risk of blocking. + buf_r.getn(const_cast(reinterpret_cast(body.data())), size) + .get(); // There is no risk of blocking. return body; } // Helper function to convert message body without extracting. -static utility::string_t convert_body_to_string_t(const utility::string_t &content_type, concurrency::streams::istream instream) +static utility::string_t convert_body_to_string_t(const utility::string_t& content_type, + concurrency::streams::istream instream) { if (!instream) { @@ -940,7 +968,7 @@ static utility::string_t convert_body_to_string_t(const utility::string_t &conte return utility::string_t(); } - concurrency::streams::streambuf streambuf = instream.streambuf(); + concurrency::streams::streambuf streambuf = instream.streambuf(); _ASSERTE((bool)streambuf); _ASSERTE(streambuf.is_open()); @@ -950,53 +978,56 @@ static utility::string_t convert_body_to_string_t(const utility::string_t &conte parse_content_type_and_charset(content_type, content, charset); // Content-Type must have textual type. - if(!is_content_type_textual(content) || streambuf.in_avail() == 0) + if (!is_content_type_textual(content) || streambuf.in_avail() == 0) { return utility::string_t(); } // Latin1 - if(utility::details::str_iequal(charset, charset_types::latin1)) + if (utility::details::str_iequal(charset, charset_types::latin1)) { std::string body; body.resize(streambuf.in_avail()); - if(streambuf.scopy((unsigned char *)&body[0], body.size()) == 0) return string_t(); + if (streambuf.scopy((unsigned char*)&body[0], body.size()) == 0) return string_t(); return to_string_t(latin1_to_utf16(std::move(body))); } // utf-8. - else if(utility::details::str_iequal(charset, charset_types::utf8)) + else if (utility::details::str_iequal(charset, charset_types::utf8)) { std::string body; body.resize(streambuf.in_avail()); - if(streambuf.scopy((unsigned char *)&body[0], body.size()) == 0) return string_t(); + if (streambuf.scopy((unsigned char*)&body[0], body.size()) == 0) return string_t(); return to_string_t(std::move(body)); } // utf-16. - else if(utility::details::str_iequal(charset, charset_types::utf16)) + else if (utility::details::str_iequal(charset, charset_types::utf16)) { utf16string body; body.resize(streambuf.in_avail() / sizeof(utf16string::value_type)); - if(streambuf.scopy((unsigned char *)&body[0], body.size() * sizeof(utf16string::value_type)) == 0) return string_t(); + if (streambuf.scopy((unsigned char*)&body[0], body.size() * sizeof(utf16string::value_type)) == 0) + return string_t(); return convert_utf16_to_string_t(std::move(body)); } // utf-16le - else if(utility::details::str_iequal(charset, charset_types::utf16le)) + else if (utility::details::str_iequal(charset, charset_types::utf16le)) { utf16string body; body.resize(streambuf.in_avail() / sizeof(utf16string::value_type)); - if(streambuf.scopy((unsigned char *)&body[0], body.size() * sizeof(utf16string::value_type)) == 0) return string_t(); + if (streambuf.scopy((unsigned char*)&body[0], body.size() * sizeof(utf16string::value_type)) == 0) + return string_t(); return convert_utf16le_to_string_t(std::move(body), false); } // utf-16be - else if(utility::details::str_iequal(charset, charset_types::utf16be)) + else if (utility::details::str_iequal(charset, charset_types::utf16be)) { utf16string body; body.resize(streambuf.in_avail() / sizeof(utf16string::value_type)); - if(streambuf.scopy((unsigned char *)&body[0], body.size() * sizeof(utf16string::value_type)) == 0) return string_t(); + if (streambuf.scopy((unsigned char*)&body[0], body.size() * sizeof(utf16string::value_type)) == 0) + return string_t(); return convert_utf16be_to_string_t(std::move(body), false); } @@ -1009,10 +1040,11 @@ static utility::string_t convert_body_to_string_t(const utility::string_t &conte // // Helper function to generate a wstring from given http_headers and message body. // -static utility::string_t http_headers_body_to_string(const http_headers &headers, concurrency::streams::istream instream) +static utility::string_t http_headers_body_to_string(const http_headers& headers, + concurrency::streams::istream instream) { utility::string_t result; - for (const auto &header : headers) + for (const auto& header : headers) { result += header.first; result += _XPLATSTR(": "); @@ -1023,7 +1055,7 @@ static utility::string_t http_headers_body_to_string(const http_headers &headers result += CRLF; utility::string_t content_type; - if(headers.match(http::header_names::content_type, content_type)) + if (headers.match(http::header_names::content_type, content_type)) { result += convert_body_to_string_t(content_type, instream); } @@ -1036,47 +1068,49 @@ utility::string_t details::http_msg_base::to_string() const return http_headers_body_to_string(m_headers, instream()); } -static void set_content_type_if_not_present(http::http_headers &headers, const utility::string_t &content_type) +static void set_content_type_if_not_present(http::http_headers& headers, const utility::string_t& content_type) { utility::string_t temp; - if(!headers.match(http::header_names::content_type, temp)) + if (!headers.match(http::header_names::content_type, temp)) { headers.add(http::header_names::content_type, content_type); } } -void details::http_msg_base::set_body(const streams::istream &instream, const utf8string &contentType) +void details::http_msg_base::set_body(const streams::istream& instream, const utf8string& contentType) { - set_content_type_if_not_present( - headers(), + set_content_type_if_not_present(headers(), #ifdef _UTF16_STRINGS - utility::conversions::utf8_to_utf16(contentType)); + utility::conversions::utf8_to_utf16(contentType)); #else - contentType); + contentType); #endif set_instream(instream); } -void details::http_msg_base::set_body(const streams::istream &instream, const utf16string &contentType) +void details::http_msg_base::set_body(const streams::istream& instream, const utf16string& contentType) { - set_content_type_if_not_present( - headers(), + set_content_type_if_not_present(headers(), #ifdef _UTF16_STRINGS - contentType); + contentType); #else - utility::conversions::utf16_to_utf8(contentType)); + utility::conversions::utf16_to_utf8(contentType)); #endif set_instream(instream); } -void details::http_msg_base::set_body(const streams::istream &instream, utility::size64_t contentLength, const utf8string &contentType) +void details::http_msg_base::set_body(const streams::istream& instream, + utility::size64_t contentLength, + const utf8string& contentType) { headers().set_content_length(contentLength); set_body(instream, contentType); m_data_available.set(contentLength); } -void details::http_msg_base::set_body(const concurrency::streams::istream &instream, utility::size64_t contentLength, const utf16string &contentType) +void details::http_msg_base::set_body(const concurrency::streams::istream& instream, + utility::size64_t contentLength, + const utf16string& contentType) { headers().set_content_length(contentLength); set_body(instream, contentType); @@ -1084,23 +1118,23 @@ void details::http_msg_base::set_body(const concurrency::streams::istream &instr } details::_http_request::_http_request(http::method mtd) - : m_method(std::move(mtd)), - m_initiated_response(0), - m_server_context(), - m_cancellationToken(pplx::cancellation_token::none()), - m_http_version(http::http_version{0, 0}) + : m_method(std::move(mtd)) + , m_initiated_response(0) + , m_server_context() + , m_cancellationToken(pplx::cancellation_token::none()) + , m_http_version(http::http_version {0, 0}) { - if(m_method.empty()) + if (m_method.empty()) { throw std::invalid_argument("Invalid HTTP method specified. Method can't be an empty string."); } } details::_http_request::_http_request(std::unique_ptr server_context) - : m_initiated_response(0), - m_server_context(std::move(server_context)), - m_cancellationToken(pplx::cancellation_token::none()), - m_http_version(http::http_version{0, 0}) + : m_initiated_response(0) + , m_server_context(std::move(server_context)) + , m_cancellationToken(pplx::cancellation_token::none()) + , m_http_version(http::http_version {0, 0}) { } @@ -1109,30 +1143,30 @@ void http_request::set_decompress_factories() return _m_impl->set_decompress_factories(compression::details::builtin::get_decompress_factories()); } -const http_version http_versions::HTTP_0_9 = { 0, 9 }; -const http_version http_versions::HTTP_1_0 = { 1, 0 }; -const http_version http_versions::HTTP_1_1 = { 1, 1 }; +const http_version http_versions::HTTP_0_9 = {0, 9}; +const http_version http_versions::HTTP_1_0 = {1, 0}; +const http_version http_versions::HTTP_1_1 = {1, 1}; #define _METHODS -#define DAT(a,b) const method methods::a = b; +#define DAT(a, b) const method methods::a = b; #include "cpprest/details/http_constants.dat" #undef _METHODS #undef DAT #define _HEADER_NAMES -#define DAT(a,b) const utility::string_t header_names::a = _XPLATSTR(b); +#define DAT(a, b) const utility::string_t header_names::a = _XPLATSTR(b); #include "cpprest/details/http_constants.dat" #undef _HEADER_NAMES #undef DAT #define _MIME_TYPES -#define DAT(a,b) const utility::string_t mime_types::a = _XPLATSTR(b); +#define DAT(a, b) const utility::string_t mime_types::a = _XPLATSTR(b); #include "cpprest/details/http_constants.dat" #undef _MIME_TYPES #undef DAT #define _CHARSET_TYPES -#define DAT(a,b) const utility::string_t charset_types::a = _XPLATSTR(b); +#define DAT(a, b) const utility::string_t charset_types::a = _XPLATSTR(b); #include "cpprest/details/http_constants.dat" #undef _CHARSET_TYPES #undef DAT @@ -1140,9 +1174,10 @@ const http_version http_versions::HTTP_1_1 = { 1, 1 }; // This is necessary for Linux because of a bug in GCC 4.7 #ifndef _WIN32 #define _PHRASES -#define DAT(a,b,c) const status_code status_codes::a; +#define DAT(a, b, c) const status_code status_codes::a; #include "cpprest/details/http_constants.dat" #undef _PHRASES #undef DAT #endif -}} // namespace web::http +} // namespace http +} // namespace web diff --git a/Release/src/http/common/internal_http_helpers.h b/Release/src/http/common/internal_http_helpers.h index 76b4f4f4da..2270f7b955 100644 --- a/Release/src/http/common/internal_http_helpers.h +++ b/Release/src/http/common/internal_http_helpers.h @@ -1,15 +1,19 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + ****/ #pragma once #include "cpprest/details/basic_types.h" #include -namespace web { namespace http { namespace details { - +namespace web +{ +namespace http +{ +namespace details +{ /// /// Helper function to get the default HTTP reason phrase for a status code. /// @@ -17,33 +21,46 @@ utility::string_t get_default_reason_phrase(status_code code); // simple helper functions to trim whitespace. template -void trim_whitespace(std::basic_string &str) +void trim_whitespace(std::basic_string& str) { size_t index; // trim left whitespace - for (index = 0; index < str.size() && isspace(str[index]); ++index); + for (index = 0; index < str.size() && isspace(str[index]); ++index) + ; str.erase(0, index); // trim right whitespace - for (index = str.size(); index > 0 && isspace(str[index - 1]); --index); + for (index = str.size(); index > 0 && isspace(str[index - 1]); --index) + ; str.erase(index); } bool validate_method(const utility::string_t& method); -}}} - -namespace web { namespace http { namespace compression { +} // namespace details +} // namespace http +} // namespace web +namespace web +{ +namespace http +{ +namespace compression +{ class decompress_factory; -namespace details { namespace builtin { - +namespace details +{ +namespace builtin +{ /// /// Helper function to get the set of built-in decompress factories /// const std::vector> get_decompress_factories(); -}} +} // namespace builtin +} // namespace details -}}} +} // namespace compression +} // namespace http +} // namespace web diff --git a/Release/src/http/common/x509_cert_utilities.h b/Release/src/http/common/x509_cert_utilities.h index 9884b05993..854e30534d 100644 --- a/Release/src/http/common/x509_cert_utilities.h +++ b/Release/src/http/common/x509_cert_utilities.h @@ -2,13 +2,13 @@ * Copyright (C) Microsoft. All rights reserved. * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * - * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * Contains utility functions for helping to verify server certificates in OS X/iOS and Android. * * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk * - * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #pragma once @@ -55,10 +55,10 @@ struct winhttp_cert_chain_context } } }; -} -} -} -} // namespaces +} // namespace details +} // namespace client +} // namespace http +} // namespace web #endif // _WIN32 #if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || \ @@ -102,9 +102,9 @@ namespace details /// Host name from the URI. /// True if verification passed and server can be trusted, false otherwise. bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context& verifyCtx, const std::string& hostName); -} -} -} -} +} // namespace details +} // namespace client +} // namespace http +} // namespace web #endif // CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE diff --git a/Release/src/http/listener/http_listener.cpp b/Release/src/http/listener/http_listener.cpp index 423adfe00b..6a2edf6d92 100644 --- a/Release/src/http/listener/http_listener.cpp +++ b/Release/src/http/listener/http_listener.cpp @@ -1,58 +1,60 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: HTTP listener (server-side) APIs -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: HTTP listener (server-side) APIs + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) +#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || \ + defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) using namespace web::http::experimental; -namespace web { namespace http +namespace web +{ +namespace http +{ +namespace experimental { -namespace experimental { namespace listener { - // Helper function to check URI components. -static void check_listener_uri(const http::uri &address) +static void check_listener_uri(const http::uri& address) { // Some things like proper URI schema are verified by the URI class. // We only need to check certain things specific to HTTP. - //HTTP Server API includes SSL support - if(address.scheme() != U("http") && address.scheme() != U("https")) + // HTTP Server API includes SSL support + if (address.scheme() != U("http") && address.scheme() != U("https")) { throw std::invalid_argument("URI scheme must be 'http' or 'https'"); } - if(address.host().empty()) + if (address.host().empty()) { throw std::invalid_argument("URI must contain a hostname."); } - if(!address.query().empty()) + if (!address.query().empty()) { throw std::invalid_argument("URI can't contain a query."); } - if(!address.fragment().empty()) + if (!address.fragment().empty()) { throw std::invalid_argument("URI can't contain a fragment."); } } -details::http_listener_impl::http_listener_impl(http::uri address) - : m_uri(std::move(address)), m_closed(true) +details::http_listener_impl::http_listener_impl(http::uri address) : m_uri(std::move(address)), m_closed(true) { check_listener_uri(m_uri); } @@ -69,24 +71,23 @@ pplx::task details::http_listener_impl::open() // Not thread safe if (!m_closed) return pplx::task_from_result(); - if ( m_uri.is_empty() ) - throw std::invalid_argument("No URI defined for listener."); + if (m_uri.is_empty()) throw std::invalid_argument("No URI defined for listener."); m_closed = false; - return web::http::experimental::details::http_server_api::register_listener(this).then([this](pplx::task openOp) - { - try - { - // If failed to open need to mark as closed. - openOp.wait(); - } - catch(...) - { - m_closed = true; - throw; - } - return openOp; - }); + return web::http::experimental::details::http_server_api::register_listener(this).then( + [this](pplx::task openOp) { + try + { + // If failed to open need to mark as closed. + openOp.wait(); + } + catch (...) + { + m_closed = true; + throw; + } + return openOp; + }); } pplx::task details::http_listener_impl::close() @@ -104,20 +105,20 @@ pplx::task details::http_listener_impl::close() void details::http_listener_impl::handle_request(http_request msg) { // Specific method handler takes priority over general. - const method &mtd = msg.method(); - if(m_supported_methods.count(mtd)) + const method& mtd = msg.method(); + if (m_supported_methods.count(mtd)) { m_supported_methods[mtd](msg); } - else if(mtd == methods::OPTIONS) + else if (mtd == methods::OPTIONS) { handle_options(msg); } - else if(mtd == methods::TRCE) + else if (mtd == methods::TRCE) { handle_trace(msg); } - else if(m_all_requests != nullptr) + else if (m_all_requests != nullptr) { m_all_requests(msg); } @@ -137,7 +138,7 @@ utility::string_t details::http_listener_impl::get_supported_methods() const bool first = true; for (auto iter = m_supported_methods.begin(); iter != m_supported_methods.end(); ++iter) { - if(!first) + if (!first) { allowed += U(", "); } @@ -163,6 +164,9 @@ void details::http_listener_impl::handle_options(http_request message) message.reply(response); } -}}}} +} // namespace listener +} // namespace experimental +} // namespace http +} // namespace web -#endif \ No newline at end of file +#endif diff --git a/Release/src/http/listener/http_listener_msg.cpp b/Release/src/http/listener/http_listener_msg.cpp index dfdb4e95f2..3cc4cc4ed9 100644 --- a/Release/src/http/listener/http_listener_msg.cpp +++ b/Release/src/http/listener/http_listener_msg.cpp @@ -1,22 +1,23 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Request and reply message definitions (server side). -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Request and reply message definitions (server side). + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" #include "../common/internal_http_helpers.h" using namespace web; using namespace utility; -namespace web { namespace http +namespace web +{ +namespace http { - // Actual initiates sending the response. pplx::task details::_http_request::_reply_impl(http_response response) { @@ -37,9 +38,14 @@ pplx::task details::_http_request::_reply_impl(http_response response) // Add a task-based continuation so no exceptions thrown from the task go 'unobserved'. response._set_server_context(std::move(m_server_context)); response_completed = server_api->respond(response); - response_completed.then([](pplx::task t) - { - try { t.wait(); } catch(...) {} + response_completed.then([](pplx::task t) { + try + { + t.wait(); + } + catch (...) + { + } }); } else @@ -66,20 +72,18 @@ pplx::task details::_http_request::_reply_if_not_already(status_code statu return pplx::task_from_result(); } -pplx::task details::_http_request::reply(const http_response &response) +pplx::task details::_http_request::reply(const http_response& response) { const long expected = 0; const long desired = 1; - switch (pplx::details::atomic_compare_exchange(m_initiated_response, desired, expected)) { - case 0: - return _reply_impl(response); // success - case 1: - throw http_exception(U("Error: trying to send multiple responses to an HTTP request")); - case 2: - return pplx::task_from_result(); // already handled - default: - abort(); + switch (pplx::details::atomic_compare_exchange(m_initiated_response, desired, expected)) + { + case 0: return _reply_impl(response); // success + case 1: throw http_exception(U("Error: trying to send multiple responses to an HTTP request")); + case 2: return pplx::task_from_result(); // already handled + default: abort(); } } -}} // namespace web::http +} // namespace http +} // namespace web diff --git a/Release/src/http/listener/http_server_api.cpp b/Release/src/http/listener/http_server_api.cpp index 9a8289b7fa..8c50353783 100644 --- a/Release/src/http/listener/http_server_api.cpp +++ b/Release/src/http/listener/http_server_api.cpp @@ -1,39 +1,39 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: exposes the entry points to the http server transport apis. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: exposes the entry points to the http server transport apis. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) +#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || \ + defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) #include "http_server_impl.h" using namespace web; using namespace utility; using namespace web::http::experimental::listener; -namespace web { namespace http +namespace web +{ +namespace http +{ +namespace experimental { -namespace experimental { namespace details { - pplx::extensibility::critical_section_t http_server_api::s_lock; std::unique_ptr http_server_api::s_server_api((http_server*)nullptr); pplx::details::atomic_long http_server_api::s_registrations(0L); -bool http_server_api::has_listener() -{ - return s_registrations > 0L; -} +bool http_server_api::has_listener() { return s_registrations > 0L; } void http_server_api::register_server_api(std::unique_ptr server_api) { @@ -64,14 +64,14 @@ void http_server_api::unsafe_register_server_api(std::unique_ptr se s_server_api.swap(server_api); } -pplx::task http_server_api::register_listener(_In_ web::http::experimental::listener::details::http_listener_impl *listener) +pplx::task http_server_api::register_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* listener) { - return pplx::create_task([listener]() - { + return pplx::create_task([listener]() { pplx::extensibility::scoped_critical_section_t lock(s_lock); // the server API was not initialized, register a default - if(s_server_api == nullptr) + if (s_server_api == nullptr) { #if defined(_WIN32) && !defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) auto server_api = make_http_httpsys_server(); @@ -94,13 +94,14 @@ pplx::task http_server_api::register_listener(_In_ web::http::experimental // register listener s_server_api->register_listener(listener).wait(); - } catch(...) + } + catch (...) { except = std::current_exception(); } // Registration failed, need to decrement registration count. - if(except != nullptr) + if (except != nullptr) { if (pplx::details::atomic_decrement(s_registrations) == 0L) { @@ -108,7 +109,8 @@ pplx::task http_server_api::register_listener(_In_ web::http::experimental { server_api()->stop().wait(); http_server_api::unsafe_register_server_api(nullptr); - } catch(...) + } + catch (...) { // ignore this exception since we want to report the original one } @@ -118,10 +120,10 @@ pplx::task http_server_api::register_listener(_In_ web::http::experimental }); } -pplx::task http_server_api::unregister_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener) +pplx::task http_server_api::unregister_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener) { - return pplx::create_task([pListener]() - { + return pplx::create_task([pListener]() { pplx::extensibility::scoped_critical_section_t lock(s_lock); // unregister listener @@ -129,7 +131,8 @@ pplx::task http_server_api::unregister_listener(_In_ web::http::experiment try { server_api()->unregister_listener(pListener).wait(); - } catch(...) + } + catch (...) { except = std::current_exception(); } @@ -142,28 +145,29 @@ pplx::task http_server_api::unregister_listener(_In_ web::http::experiment server_api()->stop().wait(); http_server_api::unsafe_register_server_api(nullptr); } - } catch(...) + } + catch (...) { // save the original exception from unregister listener - if(except == nullptr) + if (except == nullptr) { except = std::current_exception(); } } // rethrow exception if one occurred - if(except != nullptr) + if (except != nullptr) { std::rethrow_exception(except); } }); } -http_server *http_server_api::server_api() -{ - return s_server_api.get(); -} +http_server* http_server_api::server_api() { return s_server_api.get(); } -}}}} +} // namespace details +} // namespace experimental +} // namespace http +} // namespace web #endif diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 0d162f41df..e35838a077 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -2,7 +2,7 @@ * Copyright (C) Microsoft. All rights reserved. * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * HTTP Library: HTTP listener (server-side) APIs @@ -10,15 +10,15 @@ * * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk * -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ #include "stdafx.h" -#include -#include #include #include #include +#include +#include #if defined(__clang__) #pragma clang diagnostic push @@ -31,10 +31,10 @@ #pragma clang diagnostic pop #endif -#include "cpprest/asyncrt_utils.h" -#include "pplx/threadpool.h" #include "../common/internal_http_helpers.h" +#include "cpprest/asyncrt_utils.h" #include "http_server_impl.h" +#include "pplx/threadpool.h" #ifdef __ANDROID__ using utility::conversions::details::to_string; @@ -52,158 +52,151 @@ namespace listener = web::http::experimental::listener; namespace chunked_encoding = web::http::details::chunked_encoding; using web::uri; +using web::http::header_names; +using web::http::http_exception; using web::http::http_request; using web::http::http_response; using web::http::methods; using web::http::status_codes; -using web::http::header_names; -using web::http::http_exception; -using web::http::experimental::listener::details::http_listener_impl; using web::http::experimental::listener::http_listener_config; +using web::http::experimental::listener::details::http_listener_impl; using utility::details::make_unique; namespace { - class hostport_listener; - class http_linux_server; - class asio_server_connection; -} +class hostport_listener; +class http_linux_server; +class asio_server_connection; +} // namespace namespace { - struct iequal_to +struct iequal_to +{ + bool operator()(const std::string& left, const std::string& right) const { - bool operator()(const std::string& left, const std::string& right) const - { - return boost::ilexicographical_compare(left, right); - } - }; + return boost::ilexicographical_compare(left, right); + } +}; - class http_linux_server : public web::http::experimental::details::http_server - { - private: - friend class asio_server_connection; +class http_linux_server : public web::http::experimental::details::http_server +{ +private: + friend class asio_server_connection; - pplx::extensibility::reader_writer_lock_t m_listeners_lock; - std::map, iequal_to> m_listeners; - std::unordered_map> m_registered_listeners; - bool m_started; + pplx::extensibility::reader_writer_lock_t m_listeners_lock; + std::map, iequal_to> m_listeners; + std::unordered_map> + m_registered_listeners; + bool m_started; - public: - http_linux_server() - : m_listeners_lock() - , m_listeners() - , m_started(false) - {} +public: + http_linux_server() : m_listeners_lock(), m_listeners(), m_started(false) {} - ~http_linux_server() - { - stop(); - } + ~http_linux_server() { stop(); } - virtual pplx::task start(); - virtual pplx::task stop(); + virtual pplx::task start(); + virtual pplx::task stop(); - virtual pplx::task register_listener(http_listener_impl* listener); - virtual pplx::task unregister_listener(http_listener_impl* listener); + virtual pplx::task register_listener(http_listener_impl* listener); + virtual pplx::task unregister_listener(http_listener_impl* listener); - pplx::task respond(http_response response); - }; + pplx::task respond(http_response response); +}; - struct linux_request_context : web::http::details::_http_server_context - { - linux_request_context() {} +struct linux_request_context : web::http::details::_http_server_context +{ + linux_request_context() {} - pplx::task_completion_event m_response_completed; + pplx::task_completion_event m_response_completed; - private: - linux_request_context(const linux_request_context&) = delete; - linux_request_context& operator=(const linux_request_context&) = delete; - }; +private: + linux_request_context(const linux_request_context&) = delete; + linux_request_context& operator=(const linux_request_context&) = delete; +}; - class hostport_listener - { - private: - int m_backlog; - std::unique_ptr m_acceptor; - std::map m_listeners; - pplx::extensibility::reader_writer_lock_t m_listeners_lock; - - std::mutex m_connections_lock; - pplx::extensibility::event_t m_all_connections_complete; - std::set m_connections; - - http_linux_server* m_p_server; - - std::string m_host; - std::string m_port; - - bool m_is_https; - const std::function& m_ssl_context_callback; - - public: - hostport_listener(http_linux_server* server, const std::string& hostport, bool is_https, const http_listener_config& config) - : m_backlog(config.backlog()) - , m_acceptor() - , m_listeners() - , m_listeners_lock() - , m_connections_lock() - , m_connections() - , m_p_server(server) - , m_is_https(is_https) - , m_ssl_context_callback(config.get_ssl_context_callback()) - { - m_all_connections_complete.set(); +class hostport_listener +{ +private: + int m_backlog; + std::unique_ptr m_acceptor; + std::map m_listeners; + pplx::extensibility::reader_writer_lock_t m_listeners_lock; - std::istringstream hostport_in(hostport); - hostport_in.imbue(std::locale::classic()); + std::mutex m_connections_lock; + pplx::extensibility::event_t m_all_connections_complete; + std::set m_connections; - std::getline(hostport_in, m_host, ':'); - std::getline(hostport_in, m_port); - } + http_linux_server* m_p_server; - ~hostport_listener() - { - stop(); - } + std::string m_host; + std::string m_port; - void start(); - void stop(); + bool m_is_https; + const std::function& m_ssl_context_callback; - void add_listener(const std::string& path, http_listener_impl* listener); - void remove_listener(const std::string& path, http_listener_impl* listener); +public: + hostport_listener(http_linux_server* server, + const std::string& hostport, + bool is_https, + const http_listener_config& config) + : m_backlog(config.backlog()) + , m_acceptor() + , m_listeners() + , m_listeners_lock() + , m_connections_lock() + , m_connections() + , m_p_server(server) + , m_is_https(is_https) + , m_ssl_context_callback(config.get_ssl_context_callback()) + { + m_all_connections_complete.set(); + + std::istringstream hostport_in(hostport); + hostport_in.imbue(std::locale::classic()); + + std::getline(hostport_in, m_host, ':'); + std::getline(hostport_in, m_port); + } - void internal_erase_connection(asio_server_connection*); + ~hostport_listener() { stop(); } - http_listener_impl* find_listener(uri const& u) + void start(); + void stop(); + + void add_listener(const std::string& path, http_listener_impl* listener); + void remove_listener(const std::string& path, http_listener_impl* listener); + + void internal_erase_connection(asio_server_connection*); + + http_listener_impl* find_listener(uri const& u) + { + auto path_segments = uri::split_path(uri::decode(u.path())); + for (auto i = static_cast(path_segments.size()); i >= 0; --i) { - auto path_segments = uri::split_path(uri::decode(u.path())); - for (auto i = static_cast(path_segments.size()); i >= 0; --i) + std::string path = ""; + for (size_t j = 0; j < static_cast(i); ++j) { - std::string path = ""; - for (size_t j = 0; j < static_cast(i); ++j) - { - path += "/" + utility::conversions::to_utf8string(path_segments[j]); - } - path += "/"; + path += "/" + utility::conversions::to_utf8string(path_segments[j]); + } + path += "/"; - pplx::extensibility::scoped_read_lock_t lock(m_listeners_lock); - auto it = m_listeners.find(path); - if (it != m_listeners.end()) - { - return it->second; - } + pplx::extensibility::scoped_read_lock_t lock(m_listeners_lock); + auto it = m_listeners.find(path); + if (it != m_listeners.end()) + { + return it->second; } - return nullptr; } + return nullptr; + } - private: - void on_accept(std::unique_ptr socket, const boost::system::error_code& ec); +private: + void on_accept(std::unique_ptr socket, const boost::system::error_code& ec); +}; - }; - -} +} // namespace namespace { @@ -219,14 +212,14 @@ struct crlfcrlf_nonascii_searcher_t { enum class State { - none = 0, // ".\r\n\r\n$" - cr = 1, // "\r.\n\r\n$" - // " .\r\n\r\n$" - crlf = 2, // "\r\n.\r\n$" - // " .\r\n\r\n$" - crlfcr = 3 // "\r\n\r.\n$" - // " \r.\n\r\n$" - // " .\r\n\r\n$" + none = 0, // ".\r\n\r\n$" + cr = 1, // "\r.\n\r\n$" + // " .\r\n\r\n$" + crlf = 2, // "\r\n.\r\n$" + // " .\r\n\r\n$" + crlfcr = 3 // "\r\n\r.\n$" + // " \r.\n\r\n$" + // " .\r\n\r\n$" }; // This function implements the searcher which "consumes" a certain amount of the input @@ -292,23 +285,28 @@ struct crlfcrlf_nonascii_searcher_t state = State::none; } ++cur; - if (state == State::none) - excluded = cur; + if (state == State::none) excluded = cur; } return std::make_pair(excluded, false); } } crlfcrlf_nonascii_searcher; // These structures serve as proof witnesses -struct will_erase_from_parent_t {}; -struct will_deref_and_erase_t {}; -struct will_deref_t {}; +struct will_erase_from_parent_t +{ +}; +struct will_deref_and_erase_t +{ +}; +struct will_deref_t +{ +}; class asio_server_connection { private: - - typedef void (asio_server_connection::*ResponseFuncPtr) (const http_response &response, const boost::system::error_code& ec); + typedef void (asio_server_connection::*ResponseFuncPtr)(const http_response& response, + const boost::system::error_code& ec); std::unique_ptr m_socket; boost::asio::streambuf m_request_buf; @@ -318,12 +316,14 @@ class asio_server_connection mutable std::mutex m_request_mtx; http_request m_request_tmp; - void set_request(http_request req) { + void set_request(http_request req) + { std::lock_guard lck(m_request_mtx); m_request_tmp = std::move(req); } - http_request get_request() const { + http_request get_request() const + { std::lock_guard lck(m_request_mtx); return m_request_tmp; } @@ -339,7 +339,9 @@ class asio_server_connection std::unique_ptr m_ssl_context; std::unique_ptr m_ssl_stream; - asio_server_connection(std::unique_ptr socket, http_linux_server* server, hostport_listener* parent) + asio_server_connection(std::unique_ptr socket, + http_linux_server* server, + hostport_listener* parent) : m_socket(std::move(socket)) , m_request_buf() , m_response_buf() @@ -359,7 +361,9 @@ class asio_server_connection public: using refcount_ptr = std::unique_ptr; - static refcount_ptr create(std::unique_ptr socket, http_linux_server* server, hostport_listener* parent) + static refcount_ptr create(std::unique_ptr socket, + http_linux_server* server, + hostport_listener* parent) { return refcount_ptr(new asio_server_connection(std::move(socket), server, parent)); } @@ -370,7 +374,8 @@ class asio_server_connection return refcount_ptr(this); } - will_erase_from_parent_t start_connection(bool is_https, const std::function& ssl_context_callback) + will_erase_from_parent_t start_connection( + bool is_https, const std::function& ssl_context_callback) { auto unique_reference = this->get_reference(); @@ -383,18 +388,17 @@ class asio_server_connection } m_ssl_stream = make_unique(*m_socket, *m_ssl_context); - m_ssl_stream->async_handshake(boost::asio::ssl::stream_base::server, [this](const boost::system::error_code&) - { - (will_deref_and_erase_t)this->start_request_response(); - }); + m_ssl_stream->async_handshake( + boost::asio::ssl::stream_base::server, + [this](const boost::system::error_code&) { (will_deref_and_erase_t) this->start_request_response(); }); unique_reference.release(); - return will_erase_from_parent_t{}; + return will_erase_from_parent_t {}; } else { - (will_deref_and_erase_t)start_request_response(); + (will_deref_and_erase_t) start_request_response(); unique_reference.release(); - return will_erase_from_parent_t{}; + return will_erase_from_parent_t {}; } } @@ -416,8 +420,7 @@ class asio_server_connection will_erase_from_parent_t do_response() { auto unique_reference = this->get_reference(); - get_request().get_response().then([=](pplx::task r_task) - { + get_request().get_response().then([=](pplx::task r_task) { http_response response; try { @@ -431,19 +434,17 @@ class asio_server_connection serialize_headers(response); // before sending response, the full incoming message need to be processed. - return get_request().content_ready().then([=](pplx::task) - { - (will_deref_and_erase_t)this->async_write(&asio_server_connection::handle_headers_written, response); + return get_request().content_ready().then([=](pplx::task) { + (will_deref_and_erase_t) this->async_write(&asio_server_connection::handle_headers_written, response); }); }); unique_reference.release(); - return will_erase_from_parent_t{}; + return will_erase_from_parent_t {}; } will_erase_from_parent_t do_bad_response() { auto unique_reference = this->get_reference(); - get_request().get_response().then([=](pplx::task r_task) - { + get_request().get_response().then([=](pplx::task r_task) { http_response response; try { @@ -457,45 +458,50 @@ class asio_server_connection // before sending response, the full incoming message need to be processed. serialize_headers(response); - (will_deref_and_erase_t)async_write(&asio_server_connection::handle_headers_written, response); + (will_deref_and_erase_t) async_write(&asio_server_connection::handle_headers_written, response); }); unique_reference.release(); - return will_erase_from_parent_t{}; + return will_erase_from_parent_t {}; } will_deref_t async_handle_chunked_header(); - template - void async_read_until_buffersize(size_t size, const ReadHandler &handler); + template + void async_read_until_buffersize(size_t size, const ReadHandler& handler); void serialize_headers(http_response response); - will_deref_and_erase_t cancel_sending_response_with_error(const http_response &response, const std::exception_ptr &); - will_deref_and_erase_t handle_headers_written(const http_response &response, const boost::system::error_code& ec); - will_deref_and_erase_t handle_write_large_response(const http_response &response, const boost::system::error_code& ec); - will_deref_and_erase_t handle_write_chunked_response(const http_response &response, const boost::system::error_code& ec); - will_deref_and_erase_t handle_response_written(const http_response &response, const boost::system::error_code& ec); + will_deref_and_erase_t cancel_sending_response_with_error(const http_response& response, const std::exception_ptr&); + will_deref_and_erase_t handle_headers_written(const http_response& response, const boost::system::error_code& ec); + will_deref_and_erase_t handle_write_large_response(const http_response& response, + const boost::system::error_code& ec); + will_deref_and_erase_t handle_write_chunked_response(const http_response& response, + const boost::system::error_code& ec); + will_deref_and_erase_t handle_response_written(const http_response& response, const boost::system::error_code& ec); will_deref_and_erase_t finish_request_response(); using WriteFunc = decltype(&asio_server_connection::handle_headers_written); - will_deref_and_erase_t async_write(WriteFunc response_func_ptr, const http_response &response); + will_deref_and_erase_t async_write(WriteFunc response_func_ptr, const http_response& response); inline will_deref_t deref() { if (--m_refs == 0) delete this; - return will_deref_t{}; + return will_deref_t {}; } }; -} +} // namespace namespace boost { namespace asio { -template <> struct is_match_condition : public boost::true_type {}; -}} +template<> +struct is_match_condition : public boost::true_type +{ +}; +} // namespace asio +} // namespace boost namespace { - const size_t ChunkSize = 4 * 1024; void hostport_listener::internal_erase_connection(asio_server_connection* conn) @@ -514,9 +520,7 @@ void hostport_listener::start() auto& service = crossplat::threadpool::shared_instance().service(); tcp::resolver resolver(service); // #446: boost resolver does not recognize "+" as a host wildchar - tcp::resolver::query query = ( "+" == m_host)? - tcp::resolver::query(m_port): - tcp::resolver::query(m_host, m_port); + tcp::resolver::query query = ("+" == m_host) ? tcp::resolver::query(m_port) : tcp::resolver::query(m_host, m_port); tcp::endpoint endpoint = *resolver.resolve(query); @@ -528,8 +532,7 @@ void hostport_listener::start() auto socket = new ip::tcp::socket(service); std::unique_ptr usocket(socket); - m_acceptor->async_accept(*socket, [this, socket](const boost::system::error_code& ec) - { + m_acceptor->async_accept(*socket, [this, socket](const boost::system::error_code& ec) { std::unique_ptr usocket(socket); this->on_accept(std::move(usocket), ec); }); @@ -558,19 +561,21 @@ will_deref_and_erase_t asio_server_connection::start_request_response() if (m_ssl_stream) { - boost::asio::async_read_until(*m_ssl_stream, m_request_buf, CRLFCRLF, [this](const boost::system::error_code& ec, std::size_t) - { - (will_deref_and_erase_t)this->handle_http_line(ec); - }); + boost::asio::async_read_until( + *m_ssl_stream, m_request_buf, CRLFCRLF, [this](const boost::system::error_code& ec, std::size_t) { + (will_deref_and_erase_t) this->handle_http_line(ec); + }); } else { - boost::asio::async_read_until(*m_socket, m_request_buf, crlfcrlf_nonascii_searcher, [this](const boost::system::error_code& ec, std::size_t) - { - (will_deref_and_erase_t)this->handle_http_line(ec); - }); + boost::asio::async_read_until(*m_socket, + m_request_buf, + crlfcrlf_nonascii_searcher, + [this](const boost::system::error_code& ec, std::size_t) { + (will_deref_and_erase_t) this->handle_http_line(ec); + }); } - return will_deref_and_erase_t{}; + return will_deref_and_erase_t {}; } void hostport_listener::on_accept(std::unique_ptr socket, const boost::system::error_code& ec) @@ -591,13 +596,12 @@ void hostport_listener::on_accept(std::unique_ptr socket, const m_connections.insert(conn.get()); try { - (will_erase_from_parent_t)conn->start_connection(m_is_https, m_ssl_context_callback); + (will_erase_from_parent_t) conn->start_connection(m_is_https, m_ssl_context_callback); // at this point an asynchronous task has been launched which will call // m_connections.erase(conn.get()) eventually // the following cannot throw - if (m_connections.size() == 1) - m_all_connections_complete.reset(); + if (m_connections.size() == 1) m_all_connections_complete.reset(); } catch (boost::system::system_error&) { @@ -613,8 +617,7 @@ void hostport_listener::on_accept(std::unique_ptr socket, const // spin off another async accept auto newSocket = new ip::tcp::socket(crossplat::threadpool::shared_instance().service()); std::unique_ptr usocket(newSocket); - m_acceptor->async_accept(*newSocket, [this, newSocket](const boost::system::error_code& ec) - { + m_acceptor->async_accept(*newSocket, [this, newSocket](const boost::system::error_code& ec) { std::unique_ptr usocket(newSocket); this->on_accept(std::move(usocket), ec); }); @@ -629,11 +632,11 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys if (ec) { // client closed connection - if ( - ec == boost::asio::error::eof || // peer has performed an orderly shutdown - ec == boost::asio::error::operation_aborted || // this can be removed. ECONNABORTED happens only for accept() - ec == boost::asio::error::connection_reset || // connection reset by peer - ec == boost::asio::error::timed_out // connection timed out + if (ec == boost::asio::error::eof || // peer has performed an orderly shutdown + ec == + boost::asio::error::operation_aborted || // this can be removed. ECONNABORTED happens only for accept() + ec == boost::asio::error::connection_reset || // connection reset by peer + ec == boost::asio::error::timed_out // connection timed out ) { return finish_request_response(); @@ -642,9 +645,9 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys { thisRequest._reply_if_not_already(status_codes::BadRequest); m_close = true; - (will_erase_from_parent_t)do_bad_response(); - (will_deref_t)deref(); - return will_deref_and_erase_t{}; + (will_erase_from_parent_t) do_bad_response(); + (will_deref_t) deref(); + return will_deref_and_erase_t {}; } } else @@ -665,23 +668,31 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys } #endif - if (boost::iequals(http_verb, methods::GET)) http_verb = methods::GET; - else if (boost::iequals(http_verb, methods::POST)) http_verb = methods::POST; - else if (boost::iequals(http_verb, methods::PUT)) http_verb = methods::PUT; - else if (boost::iequals(http_verb, methods::DEL)) http_verb = methods::DEL; - else if (boost::iequals(http_verb, methods::HEAD)) http_verb = methods::HEAD; - else if (boost::iequals(http_verb, methods::TRCE)) http_verb = methods::TRCE; - else if (boost::iequals(http_verb, methods::CONNECT)) http_verb = methods::CONNECT; - else if (boost::iequals(http_verb, methods::OPTIONS)) http_verb = methods::OPTIONS; + if (boost::iequals(http_verb, methods::GET)) + http_verb = methods::GET; + else if (boost::iequals(http_verb, methods::POST)) + http_verb = methods::POST; + else if (boost::iequals(http_verb, methods::PUT)) + http_verb = methods::PUT; + else if (boost::iequals(http_verb, methods::DEL)) + http_verb = methods::DEL; + else if (boost::iequals(http_verb, methods::HEAD)) + http_verb = methods::HEAD; + else if (boost::iequals(http_verb, methods::TRCE)) + http_verb = methods::TRCE; + else if (boost::iequals(http_verb, methods::CONNECT)) + http_verb = methods::CONNECT; + else if (boost::iequals(http_verb, methods::OPTIONS)) + http_verb = methods::OPTIONS; // Check to see if there is not allowed character on the input if (!web::http::details::validate_method(http_verb)) { thisRequest.reply(status_codes::BadRequest); m_close = true; - (will_erase_from_parent_t)do_bad_response(); - (will_deref_t)deref(); - return will_deref_and_erase_t{}; + (will_erase_from_parent_t) do_bad_response(); + (will_deref_t) deref(); + return will_deref_and_erase_t {}; } thisRequest.set_method(http_verb); @@ -691,13 +702,13 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys const size_t VersionPortionSize = sizeof(" HTTP/1.1\r") - 1; // Make sure path and version is long enough to contain the HTTP version - if(http_path_and_version.size() < VersionPortionSize + 2) + if (http_path_and_version.size() < VersionPortionSize + 2) { thisRequest.reply(status_codes::BadRequest); m_close = true; - (will_erase_from_parent_t)do_bad_response(); - (will_deref_t)deref(); - return will_deref_and_erase_t{}; + (will_erase_from_parent_t) do_bad_response(); + (will_deref_t) deref(); + return will_deref_and_erase_t {}; } // Get the path - remove the version portion and prefix space @@ -710,13 +721,14 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys { thisRequest.reply(status_codes::BadRequest, e.what()); m_close = true; - (will_erase_from_parent_t)do_bad_response(); - (will_deref_t)deref(); - return will_deref_and_erase_t{}; + (will_erase_from_parent_t) do_bad_response(); + (will_deref_t) deref(); + return will_deref_and_erase_t {}; } // Get the version - std::string http_version = http_path_and_version.substr(http_path_and_version.size() - VersionPortionSize + 1, VersionPortionSize - 2); + std::string http_version = + http_path_and_version.substr(http_path_and_version.size() - VersionPortionSize + 1, VersionPortionSize - 2); auto requestImpl = thisRequest._get_impl().get(); web::http::http_version parsed_version = web::http::http_version::from_string(http_version); @@ -733,8 +745,7 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys auto endpoint = m_socket->remote_endpoint(socket_ec); if (!socket_ec) { - requestImpl->_set_remote_address(utility::conversions::to_string_t( - endpoint.address().to_string())); + requestImpl->_set_remote_address(utility::conversions::to_string_t(endpoint.address().to_string())); } return handle_headers(); @@ -774,9 +785,9 @@ will_deref_and_erase_t asio_server_connection::handle_headers() { currentRequest.reply(status_codes::BadRequest); m_close = true; - (will_erase_from_parent_t)do_bad_response(); - (will_deref_t)deref(); - return will_deref_and_erase_t{}; + (will_erase_from_parent_t) do_bad_response(); + (will_deref_t) deref(); + return will_deref_and_erase_t {}; } } @@ -797,7 +808,7 @@ will_deref_and_erase_t asio_server_connection::handle_headers() if (m_chunked) { ++m_refs; - (will_deref_t)async_handle_chunked_header(); + (will_deref_t) async_handle_chunked_header(); return dispatch_request_to_listener(); } @@ -814,10 +825,9 @@ will_deref_and_erase_t asio_server_connection::handle_headers() { m_read = 0; ++m_refs; - async_read_until_buffersize(std::min(ChunkSize, m_read_size), [this](const boost::system::error_code& ec, size_t) - { - (will_deref_t)this->handle_body(ec); - }); + async_read_until_buffersize( + std::min(ChunkSize, m_read_size), + [this](const boost::system::error_code& ec, size_t) { (will_deref_t) this->handle_body(ec); }); } return dispatch_request_to_listener(); @@ -846,11 +856,10 @@ will_deref_t asio_server_connection::handle_chunked_header(const boost::system:: } else { - async_read_until_buffersize(len + 2, [this, len](const boost::system::error_code& ec, size_t) - { - (will_deref_t)this->handle_chunked_body(ec, len); + async_read_until_buffersize(len + 2, [this, len](const boost::system::error_code& ec, size_t) { + (will_deref_t) this->handle_chunked_body(ec, len); }); - return will_deref_t{}; + return will_deref_t {}; } } } @@ -866,22 +875,22 @@ will_deref_t asio_server_connection::handle_chunked_body(const boost::system::er else { auto writebuf = requestImpl->outstream().streambuf(); - writebuf.putn_nocopy(buffer_cast(m_request_buf.data()), toWrite).then([=](pplx::task writeChunkTask) -> will_deref_t - { - try - { - writeChunkTask.get(); - } - catch (...) - { - requestImpl->_complete(0, std::current_exception()); - return deref(); - } + writebuf.putn_nocopy(buffer_cast(m_request_buf.data()), toWrite) + .then([=](pplx::task writeChunkTask) -> will_deref_t { + try + { + writeChunkTask.get(); + } + catch (...) + { + requestImpl->_complete(0, std::current_exception()); + return deref(); + } - m_request_buf.consume(2 + toWrite); - return async_handle_chunked_header(); - }); - return will_deref_t{}; + m_request_buf.consume(2 + toWrite); + return async_handle_chunked_header(); + }); + return will_deref_t {}; } } @@ -894,81 +903,81 @@ will_deref_t asio_server_connection::handle_body(const boost::system::error_code requestImpl->_complete(0, std::make_exception_ptr(http_exception(ec.value()))); return deref(); } - else if (m_read < m_read_size) // there is more to read + else if (m_read < m_read_size) // there is more to read { auto writebuf = requestImpl->outstream().streambuf(); - writebuf.putn_nocopy(boost::asio::buffer_cast(m_request_buf.data()), std::min(m_request_buf.size(), m_read_size - m_read)).then([this](pplx::task writtenSizeTask) -> will_deref_t - { - size_t writtenSize = 0; - try - { - writtenSize = writtenSizeTask.get(); - } - catch (...) - { - get_request()._get_impl()->_complete(0, std::current_exception()); - return deref(); - } - m_read += writtenSize; - m_request_buf.consume(writtenSize); + writebuf + .putn_nocopy(boost::asio::buffer_cast(m_request_buf.data()), + std::min(m_request_buf.size(), m_read_size - m_read)) + .then([this](pplx::task writtenSizeTask) -> will_deref_t { + size_t writtenSize = 0; + try + { + writtenSize = writtenSizeTask.get(); + } + catch (...) + { + get_request()._get_impl()->_complete(0, std::current_exception()); + return deref(); + } + m_read += writtenSize; + m_request_buf.consume(writtenSize); - async_read_until_buffersize(std::min(ChunkSize, m_read_size - m_read), [this](const boost::system::error_code& ec, size_t) - { - (will_deref_t) this->handle_body(ec); + async_read_until_buffersize( + std::min(ChunkSize, m_read_size - m_read), + [this](const boost::system::error_code& ec, size_t) { (will_deref_t) this->handle_body(ec); }); + return will_deref_t {}; }); - return will_deref_t{}; - }); - return will_deref_t{}; + return will_deref_t {}; } - else // have read request body + else // have read request body { requestImpl->_complete(m_read); return deref(); } } -will_deref_and_erase_t asio_server_connection::async_write(WriteFunc response_func_ptr, const http_response &response) +will_deref_and_erase_t asio_server_connection::async_write(WriteFunc response_func_ptr, const http_response& response) { if (m_ssl_stream) { - boost::asio::async_write(*m_ssl_stream, m_response_buf, [=] (const boost::system::error_code& ec, std::size_t) - { + boost::asio::async_write(*m_ssl_stream, m_response_buf, [=](const boost::system::error_code& ec, std::size_t) { (this->*response_func_ptr)(response, ec); }); } else { - boost::asio::async_write(*m_socket, m_response_buf, [=] (const boost::system::error_code& ec, std::size_t) - { + boost::asio::async_write(*m_socket, m_response_buf, [=](const boost::system::error_code& ec, std::size_t) { (this->*response_func_ptr)(response, ec); }); } - return will_deref_and_erase_t{}; + return will_deref_and_erase_t {}; } will_deref_t asio_server_connection::async_handle_chunked_header() { if (m_ssl_stream) { - boost::asio::async_read_until(*m_ssl_stream, m_request_buf, CRLF, [this](const boost::system::error_code& ec, size_t) - { - (will_deref_t)this->handle_chunked_header(ec); - }); + boost::asio::async_read_until( + *m_ssl_stream, m_request_buf, CRLF, [this](const boost::system::error_code& ec, size_t) { + (will_deref_t) this->handle_chunked_header(ec); + }); } else { - boost::asio::async_read_until(*m_socket, m_request_buf, CRLF, [this](const boost::system::error_code& ec, size_t) - { - (will_deref_t)this->handle_chunked_header(ec); - }); + boost::asio::async_read_until( + *m_socket, m_request_buf, CRLF, [this](const boost::system::error_code& ec, size_t) { + (will_deref_t) this->handle_chunked_header(ec); + }); } - return will_deref_t{}; + return will_deref_t {}; } -template -void asio_server_connection::async_read_until_buffersize(size_t size, const ReadHandler &handler) +template +void asio_server_connection::async_read_until_buffersize(size_t size, const ReadHandler& handler) { - // The condition is such that after completing the async_read below, m_request_buf will contain at least `size` bytes. + // The condition is such that after completing the async_read below, m_request_buf will contain at least `size` + // bytes. auto condition = transfer_at_least(0); auto bufsize = m_request_buf.size(); @@ -987,8 +996,6 @@ void asio_server_connection::async_read_until_buffersize(size_t size, const Read } } - - will_deref_and_erase_t asio_server_connection::dispatch_request_to_listener() { // locate the listener: @@ -1001,34 +1008,34 @@ will_deref_and_erase_t asio_server_connection::dispatch_request_to_listener() catch (const std::exception&) // may be web::uri_exception, or std::range_error indicating invalid Unicode { currentRequest.reply(status_codes::BadRequest); - (will_erase_from_parent_t)do_response(); - (will_deref_t)deref(); - return will_deref_and_erase_t{}; + (will_erase_from_parent_t) do_response(); + (will_deref_t) deref(); + return will_deref_and_erase_t {}; } if (pListener == nullptr) { currentRequest.reply(status_codes::NotFound); - (will_erase_from_parent_t)do_response(); - (will_deref_t)deref(); - return will_deref_and_erase_t{}; + (will_erase_from_parent_t) do_response(); + (will_deref_t) deref(); + return will_deref_and_erase_t {}; } currentRequest._set_listener_path(pListener->uri().path()); - (will_erase_from_parent_t)do_response(); + (will_erase_from_parent_t) do_response(); // Look up the lock for the http_listener. - pplx::extensibility::reader_writer_lock_t *pListenerLock; + pplx::extensibility::reader_writer_lock_t* pListenerLock; { pplx::extensibility::reader_writer_lock_t::scoped_lock_read lock(m_p_server->m_listeners_lock); // It is possible the listener could have unregistered. - if(m_p_server->m_registered_listeners.find(pListener) == m_p_server->m_registered_listeners.end()) + if (m_p_server->m_registered_listeners.find(pListener) == m_p_server->m_registered_listeners.end()) { currentRequest.reply(status_codes::NotFound); - (will_deref_t)deref(); - return will_deref_and_erase_t{}; + (will_deref_t) deref(); + return will_deref_and_erase_t {}; } pListenerLock = m_p_server->m_registered_listeners[pListener].get(); @@ -1042,14 +1049,14 @@ will_deref_and_erase_t asio_server_connection::dispatch_request_to_listener() pListener->handle_request(currentRequest); pListenerLock->unlock(); } - catch(...) + catch (...) { pListenerLock->unlock(); currentRequest._reply_if_not_already(status_codes::InternalError); } - (will_deref_t)deref(); - return will_deref_and_erase_t{}; + (will_deref_t) deref(); + return will_deref_and_erase_t {}; } void asio_server_connection::serialize_headers(http_response response) @@ -1058,9 +1065,8 @@ void asio_server_connection::serialize_headers(http_response response) std::ostream os(&m_response_buf); os.imbue(std::locale::classic()); - os << "HTTP/1.1 " << response.status_code() << " " - << utility::conversions::to_utf8string(response.reason_phrase()) - << CRLF; + os << "HTTP/1.1 " << response.status_code() << " " << utility::conversions::to_utf8string(response.reason_phrase()) + << CRLF; m_chunked = false; m_write = m_write_size = 0; @@ -1068,7 +1074,7 @@ void asio_server_connection::serialize_headers(http_response response) std::string transferencoding; if (response.headers().match(header_names::transfer_encoding, transferencoding) && transferencoding == "chunked") { - m_chunked = true; + m_chunked = true; } if (!response.headers().match(header_names::content_length, m_write_size) && response.body()) { @@ -1077,10 +1083,10 @@ void asio_server_connection::serialize_headers(http_response response) } if (!response.body()) { - response.headers().add(header_names::content_length,0); + response.headers().add(header_names::content_length, 0); } - for(const auto & header : response.headers()) + for (const auto& header : response.headers()) { // check if the responder has requested we close the connection if (boost::iequals(header.first, U("connection"))) @@ -1090,21 +1096,24 @@ void asio_server_connection::serialize_headers(http_response response) m_close = true; } } - os << utility::conversions::to_utf8string(header.first) << ": " << utility::conversions::to_utf8string(header.second) << CRLF; + os << utility::conversions::to_utf8string(header.first) << ": " + << utility::conversions::to_utf8string(header.second) << CRLF; } os << CRLF; } -will_deref_and_erase_t asio_server_connection::cancel_sending_response_with_error(const http_response &response, const std::exception_ptr &eptr) +will_deref_and_erase_t asio_server_connection::cancel_sending_response_with_error(const http_response& response, + const std::exception_ptr& eptr) { - auto * context = static_cast(response._get_server_context()); + auto* context = static_cast(response._get_server_context()); context->m_response_completed.set_exception(eptr); // always terminate the connection since error happens return finish_request_response(); } -will_deref_and_erase_t asio_server_connection::handle_write_chunked_response(const http_response &response, const boost::system::error_code& ec) +will_deref_and_erase_t asio_server_connection::handle_write_chunked_response(const http_response& response, + const boost::system::error_code& ec) { if (ec) { @@ -1114,65 +1123,69 @@ will_deref_and_erase_t asio_server_connection::handle_write_chunked_response(con auto readbuf = response._get_impl()->instream().streambuf(); if (readbuf.is_eof()) { - return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception("Response stream close early!"))); + return cancel_sending_response_with_error( + response, std::make_exception_ptr(http_exception("Response stream close early!"))); } auto membuf = m_response_buf.prepare(ChunkSize + chunked_encoding::additional_encoding_space); - readbuf.getn(buffer_cast(membuf) + chunked_encoding::data_offset, ChunkSize).then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t - { - size_t actualSize = 0; - try - { - actualSize = actualSizeTask.get(); - } - catch (...) - { - return cancel_sending_response_with_error(response, std::current_exception()); - } - size_t offset = chunked_encoding::add_chunked_delimiters(buffer_cast(membuf), ChunkSize + chunked_encoding::additional_encoding_space, actualSize); - m_response_buf.commit(actualSize + chunked_encoding::additional_encoding_space); - m_response_buf.consume(offset); - if (actualSize == 0) - return async_write(&asio_server_connection::handle_response_written, response); - else - return async_write(&asio_server_connection::handle_write_chunked_response, response); - }); - return will_deref_and_erase_t{}; + readbuf.getn(buffer_cast(membuf) + chunked_encoding::data_offset, ChunkSize) + .then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t { + size_t actualSize = 0; + try + { + actualSize = actualSizeTask.get(); + } + catch (...) + { + return cancel_sending_response_with_error(response, std::current_exception()); + } + size_t offset = chunked_encoding::add_chunked_delimiters( + buffer_cast(membuf), ChunkSize + chunked_encoding::additional_encoding_space, actualSize); + m_response_buf.commit(actualSize + chunked_encoding::additional_encoding_space); + m_response_buf.consume(offset); + if (actualSize == 0) + return async_write(&asio_server_connection::handle_response_written, response); + else + return async_write(&asio_server_connection::handle_write_chunked_response, response); + }); + return will_deref_and_erase_t {}; } -will_deref_and_erase_t asio_server_connection::handle_write_large_response( - const http_response &response, - const boost::system::error_code& ec) +will_deref_and_erase_t asio_server_connection::handle_write_large_response(const http_response& response, + const boost::system::error_code& ec) { - if (ec || m_write == m_write_size) - return handle_response_written(response, ec); + if (ec || m_write == m_write_size) return handle_response_written(response, ec); auto readbuf = response._get_impl()->instream().streambuf(); if (readbuf.is_eof()) - return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception("Response stream close early!"))); + return cancel_sending_response_with_error( + response, std::make_exception_ptr(http_exception("Response stream close early!"))); size_t readBytes = std::min(ChunkSize, m_write_size - m_write); - readbuf.getn(buffer_cast(m_response_buf.prepare(readBytes)), readBytes).then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t - { - size_t actualSize = 0; - try - { - actualSize = actualSizeTask.get(); - } catch (...) - { - return cancel_sending_response_with_error(response, std::current_exception()); - } - m_write += actualSize; - m_response_buf.commit(actualSize); - return async_write(&asio_server_connection::handle_write_large_response, response); - }); - return will_deref_and_erase_t{}; + readbuf.getn(buffer_cast(m_response_buf.prepare(readBytes)), readBytes) + .then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t { + size_t actualSize = 0; + try + { + actualSize = actualSizeTask.get(); + } + catch (...) + { + return cancel_sending_response_with_error(response, std::current_exception()); + } + m_write += actualSize; + m_response_buf.commit(actualSize); + return async_write(&asio_server_connection::handle_write_large_response, response); + }); + return will_deref_and_erase_t {}; } -will_deref_and_erase_t asio_server_connection::handle_headers_written(const http_response &response, const boost::system::error_code& ec) +will_deref_and_erase_t asio_server_connection::handle_headers_written(const http_response& response, + const boost::system::error_code& ec) { if (ec) { - return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception(ec.value(), "error writing headers"))); + return cancel_sending_response_with_error( + response, std::make_exception_ptr(http_exception(ec.value(), "error writing headers"))); } else { @@ -1183,14 +1196,14 @@ will_deref_and_erase_t asio_server_connection::handle_headers_written(const http } } -will_deref_and_erase_t asio_server_connection::handle_response_written( - const http_response &response, - const boost::system::error_code& ec) +will_deref_and_erase_t asio_server_connection::handle_response_written(const http_response& response, + const boost::system::error_code& ec) { - auto * context = static_cast(response._get_server_context()); + auto* context = static_cast(response._get_server_context()); if (ec) { - return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception(ec.value(), "error writing response"))); + return cancel_sending_response_with_error( + response, std::make_exception_ptr(http_exception(ec.value(), "error writing response"))); } else { @@ -1212,10 +1225,10 @@ will_deref_and_erase_t asio_server_connection::finish_request_response() m_p_parent->internal_erase_connection(this); close(); - (will_deref_t)deref(); + (will_deref_t) deref(); // internal_erase_connection has been called above. - return will_deref_and_erase_t{}; + return will_deref_and_erase_t {}; } void hostport_listener::stop() @@ -1224,7 +1237,7 @@ void hostport_listener::stop() { std::lock_guard lock(m_connections_lock); m_acceptor.reset(); - for(auto connection : m_connections) + for (auto connection : m_connections) { connection->close(); } @@ -1238,8 +1251,9 @@ void hostport_listener::add_listener(const std::string& path, http_listener_impl pplx::extensibility::scoped_rw_lock_t lock(m_listeners_lock); if (m_is_https != (listener->uri().scheme() == U("https"))) - throw std::invalid_argument("Error: http_listener can not simultaneously listen both http and https paths of one host"); - else if (!m_listeners.insert(std::map::value_type(path, listener)).second) + throw std::invalid_argument( + "Error: http_listener can not simultaneously listen both http and https paths of one host"); + else if (!m_listeners.insert(std::map::value_type(path, listener)).second) throw std::invalid_argument("Error: http_listener is already registered for this path"); } @@ -1247,8 +1261,7 @@ void hostport_listener::remove_listener(const std::string& path, http_listener_i { pplx::extensibility::scoped_rw_lock_t lock(m_listeners_lock); - if (m_listeners.erase(path) != 1) - throw std::invalid_argument("Error: no http_listener found for this path"); + if (m_listeners.erase(path) != 1) throw std::invalid_argument("Error: no http_listener found for this path"); } pplx::task http_linux_server::start() @@ -1283,7 +1296,7 @@ pplx::task http_linux_server::stop() m_started = false; - for(auto & listener : m_listeners) + for (auto& listener : m_listeners) { listener.second->stop(); } @@ -1291,7 +1304,7 @@ pplx::task http_linux_server::stop() return pplx::task_from_result(); } -std::pair canonical_parts(const uri& uri) +std::pair canonical_parts(const uri& uri) { std::string endpoint; endpoint += utility::conversions::to_utf8string(uri::decode(uri.host())); @@ -1300,7 +1313,7 @@ std::pair canonical_parts(const uri& uri) auto path = utility::conversions::to_utf8string(uri::decode(uri.path())); - if (path.size() > 1 && path[path.size()-1] != '/') + if (path.size() > 1 && path[path.size() - 1] != '/') { path += "/"; // ensure the end slash is present } @@ -1329,8 +1342,12 @@ pplx::task http_linux_server::register_listener(http_listener_impl* listen auto found_hostport_listener = m_listeners.find(hostport); if (found_hostport_listener == m_listeners.end()) { - found_hostport_listener = m_listeners.insert( - std::make_pair(hostport, make_unique(this, hostport, is_https, listener->configuration()))).first; + found_hostport_listener = + m_listeners + .insert(std::make_pair( + hostport, + make_unique(this, hostport, is_https, listener->configuration()))) + .first; if (m_started) { @@ -1392,11 +1409,11 @@ pplx::task http_linux_server::unregister_listener(http_listener_impl* list pplx::task http_linux_server::respond(http_response response) { - linux_request_context * p_context = static_cast(response._get_server_context()); + linux_request_context* p_context = static_cast(response._get_server_context()); return pplx::create_task(p_context->m_response_completed); } -} +} // namespace namespace web { @@ -1406,10 +1423,9 @@ namespace experimental { namespace details { +std::unique_ptr make_http_asio_server() { return make_unique(); } -std::unique_ptr make_http_asio_server() -{ - return make_unique(); -} - -}}}} +} // namespace details +} // namespace experimental +} // namespace http +} // namespace web diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index e882870cbf..9c5827a825 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -1,19 +1,20 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: HTTP listener (server-side) APIs -* -* This file contains implementation built on Windows HTTP Server APIs. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: HTTP listener (server-side) APIs + * + * This file contains implementation built on Windows HTTP Server APIs. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/rawptrstream.h" #if _WIN32_WINNT >= _WIN32_WINNT_VISTA @@ -41,137 +42,98 @@ namespace experimental { namespace details { - /// /// String values for all HTTP Server API known headers. /// NOTE: the order here is important it is from the _HTTP_HEADER_ID enum. /// -static utility::string_t HttpServerAPIKnownHeaders[] = -{ - U("Cache-Control"), - U("Connection"), - U("Data"), - U("Keep-Alive"), - U("Pragma"), - U("Trailer"), - U("Transfer-Encoding"), - U("Upgrade"), - U("Via"), - U("Warning"), - U("Allow"), - U("Content-Length"), - U("Content-Type"), - U("Content-Encoding"), - U("Content-Language"), - U("Content-Location"), - U("Content-Md5"), - U("Content-Range"), - U("Expires"), - U("Last-Modified"), - U("Accept"), - U("Accept-Charset"), - U("Accept-Encoding"), - U("Accept-Language"), - U("Authorization"), - U("Cookie"), - U("Expect"), - U("From"), - U("Host"), - U("If-Match"), - U("If-Modified-Since"), - U("If-None-Match"), - U("If-Range"), - U("If-Unmodified-Since"), - U("Max-Forwards"), - U("Proxy-Authorization"), - U("Referer"), - U("Range"), - U("TE"), - U("Translate"), - U("User-Agent"), - U("Request-Maximum"), - U("Accept-Ranges"), - U("Age"), - U("Etag"), - U("Location"), - U("Proxy-Authenticate"), - U("Retry-After"), - U("Server"), - U("Set-Cookie"), - U("Vary"), - U("Www-Authenticate"), - U("Response-Maximum") -}; - -static void char_to_wstring(utf16string &dest, const char * src) +static utility::string_t HttpServerAPIKnownHeaders[] = {U("Cache-Control"), + U("Connection"), + U("Data"), + U("Keep-Alive"), + U("Pragma"), + U("Trailer"), + U("Transfer-Encoding"), + U("Upgrade"), + U("Via"), + U("Warning"), + U("Allow"), + U("Content-Length"), + U("Content-Type"), + U("Content-Encoding"), + U("Content-Language"), + U("Content-Location"), + U("Content-Md5"), + U("Content-Range"), + U("Expires"), + U("Last-Modified"), + U("Accept"), + U("Accept-Charset"), + U("Accept-Encoding"), + U("Accept-Language"), + U("Authorization"), + U("Cookie"), + U("Expect"), + U("From"), + U("Host"), + U("If-Match"), + U("If-Modified-Since"), + U("If-None-Match"), + U("If-Range"), + U("If-Unmodified-Since"), + U("Max-Forwards"), + U("Proxy-Authorization"), + U("Referer"), + U("Range"), + U("TE"), + U("Translate"), + U("User-Agent"), + U("Request-Maximum"), + U("Accept-Ranges"), + U("Age"), + U("Etag"), + U("Location"), + U("Proxy-Authenticate"), + U("Retry-After"), + U("Server"), + U("Set-Cookie"), + U("Vary"), + U("Www-Authenticate"), + U("Response-Maximum")}; + +static void char_to_wstring(utf16string& dest, const char* src) { dest = utility::conversions::to_utf16string(std::string(src)); } -http::method parse_request_method(const HTTP_REQUEST *p_request) +http::method parse_request_method(const HTTP_REQUEST* p_request) { http::method method; - switch(p_request->Verb) + switch (p_request->Verb) { - case HttpVerbGET: - method = methods::GET; - break; - case HttpVerbPOST: - method = methods::POST; - break; - case HttpVerbPUT: - method = methods::PUT; - break; - case HttpVerbDELETE: - method = methods::DEL; - break; - case HttpVerbHEAD: - method = methods::HEAD; - break; - case HttpVerbOPTIONS: - method = methods::OPTIONS; - break; - case HttpVerbTRACE: - method = methods::TRCE; - break; - case HttpVerbCONNECT: - method = methods::CONNECT; - break; - case HttpVerbUnknown: - char_to_wstring(method, p_request->pUnknownVerb); - break; - case HttpVerbMOVE: - method = _XPLATSTR("MOVE"); - break; - case HttpVerbCOPY: - method = _XPLATSTR("COPY"); - break; - case HttpVerbPROPFIND: - method = _XPLATSTR("PROPFIND"); - break; - case HttpVerbPROPPATCH: - method = _XPLATSTR("PROPPATCH"); - break; - case HttpVerbMKCOL: - method = _XPLATSTR("MKCOL"); - break; - case HttpVerbLOCK: - method = _XPLATSTR("LOCK"); - break; - case HttpVerbUNLOCK: - method = _XPLATSTR("UNLOCK"); - break; - case HttpVerbSEARCH: - method = _XPLATSTR("SEARCH"); - break; - default: - break; + case HttpVerbGET: method = methods::GET; break; + case HttpVerbPOST: method = methods::POST; break; + case HttpVerbPUT: method = methods::PUT; break; + case HttpVerbDELETE: method = methods::DEL; break; + case HttpVerbHEAD: method = methods::HEAD; break; + case HttpVerbOPTIONS: method = methods::OPTIONS; break; + case HttpVerbTRACE: method = methods::TRCE; break; + case HttpVerbCONNECT: method = methods::CONNECT; break; + case HttpVerbUnknown: char_to_wstring(method, p_request->pUnknownVerb); break; + case HttpVerbMOVE: method = _XPLATSTR("MOVE"); break; + case HttpVerbCOPY: method = _XPLATSTR("COPY"); break; + case HttpVerbPROPFIND: method = _XPLATSTR("PROPFIND"); break; + case HttpVerbPROPPATCH: method = _XPLATSTR("PROPPATCH"); break; + case HttpVerbMKCOL: method = _XPLATSTR("MKCOL"); break; + case HttpVerbLOCK: method = _XPLATSTR("LOCK"); break; + case HttpVerbUNLOCK: method = _XPLATSTR("UNLOCK"); break; + case HttpVerbSEARCH: method = _XPLATSTR("SEARCH"); break; + default: break; } return method; } -void parse_http_headers(const HTTP_REQUEST_HEADERS &headers, http::http_headers & msgHeaders) +void parse_http_headers(const HTTP_REQUEST_HEADERS& headers, http::http_headers& msgHeaders) { // // This is weird for the 'KnownHeaders' but there is no way I can find with the HTTP Server API @@ -180,26 +142,28 @@ void parse_http_headers(const HTTP_REQUEST_HEADERS &headers, http::http_headers // // TFS 354587 As a perf optimization we could parse the headers from Windows on demand in the // http_header class itself. - for(USHORT i = 0; i < headers.UnknownHeaderCount; ++i) + for (USHORT i = 0; i < headers.UnknownHeaderCount; ++i) { utf16string unknown_header_name; char_to_wstring(unknown_header_name, headers.pUnknownHeaders[i].pName); // header value can be empty - if(headers.pUnknownHeaders[i].RawValueLength > 0) + if (headers.pUnknownHeaders[i].RawValueLength > 0) { - msgHeaders.add(unknown_header_name, utility::conversions::to_utf16string(headers.pUnknownHeaders[i].pRawValue)); + msgHeaders.add(unknown_header_name, + utility::conversions::to_utf16string(headers.pUnknownHeaders[i].pRawValue)); } else { msgHeaders[unknown_header_name] = U(""); } } - for(int i = 0; i < HttpHeaderMaximum; ++i) + for (int i = 0; i < HttpHeaderMaximum; ++i) { - if(headers.KnownHeaders[i].RawValueLength > 0) + if (headers.KnownHeaders[i].RawValueLength > 0) { - msgHeaders.add(HttpServerAPIKnownHeaders[i], utility::conversions::to_utf16string(headers.KnownHeaders[i].pRawValue)); + msgHeaders.add(HttpServerAPIKnownHeaders[i], + utility::conversions::to_utf16string(headers.KnownHeaders[i].pRawValue)); } } } @@ -210,19 +174,17 @@ http_windows_server::http_windows_server() HttpInitialize(httpApiVersion, HTTP_INITIALIZE_SERVER, NULL); } -http_windows_server::~http_windows_server() -{ - HttpTerminate(HTTP_INITIALIZE_SERVER, NULL); -} +http_windows_server::~http_windows_server() { HttpTerminate(HTTP_INITIALIZE_SERVER, NULL); } -pplx::task http_windows_server::register_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener) +pplx::task http_windows_server::register_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener) { unsigned long errorCode; // Create a url group for this listener. HTTP_URL_GROUP_ID urlGroupId; errorCode = HttpCreateUrlGroup(m_serverSessionId, &urlGroupId, 0); - if(errorCode != NO_ERROR) + if (errorCode != NO_ERROR) { return pplx::task_from_exception(http_exception(errorCode)); } @@ -242,7 +204,7 @@ pplx::task http_windows_server::register_listener(_In_ web::http::experime // Windows HTTP Server API will not accept a uri with an empty path, it must have a '/'. // Windows HTTP Server API will only accept decoded uri strings. utility::string_t host_uri = http::uri::decode(u.to_string()); - if(host_uri.back() != U('/') && u.query().empty() && u.fragment().empty()) + if (host_uri.back() != U('/') && u.query().empty() && u.fragment().empty()) { host_uri.push_back(U('/')); } @@ -250,23 +212,26 @@ pplx::task http_windows_server::register_listener(_In_ web::http::experime // inside here we check for a few specific error types that know about // there may be more possibilities for windows to return a different error errorCode = HttpAddUrlToUrlGroup(urlGroupId, host_uri.c_str(), (HTTP_URL_CONTEXT)pListener, 0); - if(errorCode) + if (errorCode) { HttpCloseUrlGroup(urlGroupId); - if(errorCode == ERROR_ALREADY_EXISTS || errorCode == ERROR_SHARING_VIOLATION) + if (errorCode == ERROR_ALREADY_EXISTS || errorCode == ERROR_SHARING_VIOLATION) { - return pplx::task_from_exception(http_exception(errorCode, - _XPLATSTR("Address '") + pListener->uri().to_string() + _XPLATSTR("' is already in use"))); + return pplx::task_from_exception(http_exception( + errorCode, _XPLATSTR("Address '") + pListener->uri().to_string() + _XPLATSTR("' is already in use"))); } else if (errorCode == ERROR_ACCESS_DENIED) { - return pplx::task_from_exception(http_exception(errorCode, - _XPLATSTR("Access denied: attempting to add Address '") + pListener->uri().to_string() + _XPLATSTR("'. ") - _XPLATSTR("Run as administrator to listen on an hostname other than localhost, or to listen on port 80."))); + return pplx::task_from_exception( + http_exception(errorCode, + _XPLATSTR("Access denied: attempting to add Address '") + pListener->uri().to_string() + + _XPLATSTR("'. ") _XPLATSTR("Run as administrator to listen on an hostname other " + "than localhost, or to listen on port 80."))); } else { - return pplx::task_from_exception(http_exception(errorCode, _XPLATSTR("Error adding url to url group"))); + return pplx::task_from_exception( + http_exception(errorCode, _XPLATSTR("Error adding url to url group"))); } } @@ -279,12 +244,9 @@ pplx::task http_windows_server::register_listener(_In_ web::http::experime timeouts.IdleConnection = secs; timeouts.HeaderWait = secs; timeouts.Flags.Present = 1; - errorCode = HttpSetUrlGroupProperty( - urlGroupId, - HttpServerTimeoutsProperty, - &timeouts, - sizeof(HTTP_TIMEOUT_LIMIT_INFO)); - if(errorCode) + errorCode = + HttpSetUrlGroupProperty(urlGroupId, HttpServerTimeoutsProperty, &timeouts, sizeof(HTTP_TIMEOUT_LIMIT_INFO)); + if (errorCode) { HttpCloseUrlGroup(urlGroupId); return pplx::task_from_exception(http_exception(errorCode)); @@ -293,24 +255,21 @@ pplx::task http_windows_server::register_listener(_In_ web::http::experime // Add listener registration. { pplx::extensibility::scoped_rw_lock_t lock(_M_listenersLock); - if(_M_registeredListeners.find(pListener) != _M_registeredListeners.end()) + if (_M_registeredListeners.find(pListener) != _M_registeredListeners.end()) { HttpCloseUrlGroup(urlGroupId); throw std::invalid_argument("Error: http_listener is already registered"); } - _M_registeredListeners[pListener] = std::unique_ptr(new listener_registration(urlGroupId)); + _M_registeredListeners[pListener] = + std::unique_ptr(new listener_registration(urlGroupId)); } // Associate Url group with request queue. HTTP_BINDING_INFO bindingInfo; bindingInfo.RequestQueueHandle = m_hRequestQueue; bindingInfo.Flags.Present = 1; - errorCode = HttpSetUrlGroupProperty( - urlGroupId, - HttpServerBindingProperty, - &bindingInfo, - sizeof(HTTP_BINDING_INFO)); - if(errorCode) + errorCode = HttpSetUrlGroupProperty(urlGroupId, HttpServerBindingProperty, &bindingInfo, sizeof(HTTP_BINDING_INFO)); + if (errorCode) { HttpCloseUrlGroup(urlGroupId); return pplx::task_from_exception(http_exception(errorCode)); @@ -319,10 +278,10 @@ pplx::task http_windows_server::register_listener(_In_ web::http::experime return pplx::task_from_result(); } -pplx::task http_windows_server::unregister_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener) +pplx::task http_windows_server::unregister_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener) { - return pplx::create_task([=]() - { + return pplx::create_task([=]() { // First remove listener registration. std::unique_ptr registration; { @@ -359,21 +318,21 @@ pplx::task http_windows_server::start() // Open server session. HTTPAPI_VERSION httpApiVersion = HTTPAPI_VERSION_2; ULONG errorCode = HttpCreateServerSession(httpApiVersion, &m_serverSessionId, 0); - if(errorCode) + if (errorCode) { return pplx::task_from_exception(http_exception(errorCode)); } // Create request queue. errorCode = HttpCreateRequestQueue(httpApiVersion, NULL, NULL, NULL, &m_hRequestQueue); - if(errorCode) + if (errorCode) { return pplx::task_from_exception(http_exception(errorCode)); } // Create and start ThreadPool I/O so we can process asynchronous I/O. m_threadpool_io = CreateThreadpoolIo(m_hRequestQueue, &http_overlapped::io_completion_callback, NULL, NULL); - if(m_threadpool_io == nullptr) + if (m_threadpool_io == nullptr) { return pplx::task_from_exception(http_exception(errorCode)); } @@ -387,7 +346,7 @@ pplx::task http_windows_server::start() pplx::task http_windows_server::stop() { // Shutdown request queue. - if(m_hRequestQueue != nullptr) + if (m_hRequestQueue != nullptr) { HttpShutdownRequestQueue(m_hRequestQueue); m_receivingTask.wait(); @@ -399,11 +358,11 @@ pplx::task http_windows_server::stop() } // Release resources. - if(m_serverSessionId != 0) + if (m_serverSessionId != 0) { HttpCloseServerSession(m_serverSessionId); } - if(m_threadpool_io != nullptr) + if (m_threadpool_io != nullptr) { CloseThreadpoolIo(m_threadpool_io); m_threadpool_io = nullptr; @@ -429,13 +388,7 @@ void http_windows_server::receive_requests() for (;;) { unsigned long error_code = HttpReceiveHttpRequest( - m_hRequestQueue, - HTTP_NULL_ID, - 0, - &p_request, - sizeof(HTTP_REQUEST), - &bytes_received, - 0); + m_hRequestQueue, HTTP_NULL_ID, 0, &p_request, sizeof(HTTP_REQUEST), &bytes_received, 0); if (error_code != NO_ERROR && error_code != ERROR_MORE_DATA) { @@ -455,17 +408,15 @@ void http_windows_server::receive_requests() pplx::task http_windows_server::respond(http::http_response response) { - windows_request_context * p_context = static_cast(response._get_server_context()); + windows_request_context* p_context = static_cast(response._get_server_context()); return pplx::create_task(p_context->m_response_completed); } windows_request_context::windows_request_context() - : m_sending_in_chunks(false), - m_transfer_encoding(false), - m_remaining_to_write(0) + : m_sending_in_chunks(false), m_transfer_encoding(false), m_remaining_to_write(0) { - auto *pServer = static_cast(http_server_api::server_api()); - if(++pServer->m_numOutstandingRequests == 1) + auto* pServer = static_cast(http_server_api::server_api()); + if (++pServer->m_numOutstandingRequests == 1) { pServer->m_zeroOutstandingRequests.reset(); } @@ -480,44 +431,47 @@ windows_request_context::~windows_request_context() std::lock_guard lock(m_responseCompletedLock); // Add a task-based continuation so no exceptions thrown from the task go 'unobserved'. - pplx::create_task(m_response_completed).then([](pplx::task t) - { - try { t.wait(); } catch(...) {} + pplx::create_task(m_response_completed).then([](pplx::task t) { + try + { + t.wait(); + } + catch (...) + { + } }); - auto *pServer = static_cast(http_server_api::server_api()); - if(--pServer->m_numOutstandingRequests == 0) + auto* pServer = static_cast(http_server_api::server_api()); + if (--pServer->m_numOutstandingRequests == 0) { pServer->m_zeroOutstandingRequests.set(); } } -void windows_request_context::async_process_request(HTTP_REQUEST_ID request_id, http_request msg, const unsigned long headers_size) +void windows_request_context::async_process_request(HTTP_REQUEST_ID request_id, + http_request msg, + const unsigned long headers_size) { - auto *pServer = static_cast(http_server_api::server_api()); + auto* pServer = static_cast(http_server_api::server_api()); m_request_id = request_id; // Save the http_request as the member of windows_request_context for the callback use. m_msg = msg; - m_request_buffer = std::unique_ptr(new unsigned char[msl::safeint3::SafeInt(headers_size)]); - m_request = (HTTP_REQUEST *) m_request_buffer.get(); + m_request_buffer = + std::unique_ptr(new unsigned char[msl::safeint3::SafeInt(headers_size)]); + m_request = (HTTP_REQUEST*)m_request_buffer.get(); // The read_headers_io_completion callback function. - m_overlapped.set_http_io_completion([this](DWORD error, DWORD nBytes){ read_headers_io_completion(error, nBytes); }); + m_overlapped.set_http_io_completion( + [this](DWORD error, DWORD nBytes) { read_headers_io_completion(error, nBytes); }); StartThreadpoolIo(pServer->m_threadpool_io); - const unsigned long error_code = HttpReceiveHttpRequest( - pServer->m_hRequestQueue, - m_request_id, - 0, - m_request, - headers_size, - NULL, - &m_overlapped); + const unsigned long error_code = + HttpReceiveHttpRequest(pServer->m_hRequestQueue, m_request_id, 0, m_request, headers_size, NULL, &m_overlapped); - if(error_code != NO_ERROR && error_code != ERROR_IO_PENDING) + if (error_code != NO_ERROR && error_code != ERROR_IO_PENDING) { CancelThreadpoolIo(pServer->m_threadpool_io); m_msg.reply(status_codes::InternalError); @@ -530,7 +484,7 @@ void windows_request_context::async_process_request(HTTP_REQUEST_ID request_id, /// void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD) { - if(error_code != NO_ERROR) + if (error_code != NO_ERROR) { m_msg.reply(status_codes::InternalError); init_response_callbacks(ShouldWaitForBody::DontWait); @@ -546,7 +500,7 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD // some encoded and some not. m_msg.set_request_uri(utf8_to_utf16(m_request->pRawUrl)); } - catch(const uri_exception &e) + catch (const uri_exception& e) { // If an exception occurred, finish processing the request below but // respond with BadRequest instead of dispatching to the user's @@ -563,9 +517,10 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD { try { - m_decompressor = http::compression::details::get_decompressor_from_header(header, http::compression::details::header_types::transfer_encoding); + m_decompressor = http::compression::details::get_decompressor_from_header( + header, http::compression::details::header_types::transfer_encoding); } - catch (http_exception &e) + catch (http_exception& e) { if (e.error_code().value() != status_codes::NotImplemented) { @@ -581,9 +536,10 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD { try { - m_decompressor = http::compression::details::get_decompressor_from_header(header, http::compression::details::header_types::content_encoding); + m_decompressor = http::compression::details::get_decompressor_from_header( + header, http::compression::details::header_types::content_encoding); } - catch (http_exception &e) + catch (http_exception& e) { if (e.error_code().value() != status_codes::UnsupportedMediaType) { @@ -599,15 +555,18 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD { // Note that init_response_headers throws away m_msg, so we need to set our compressor here. If // the header contains all unsupported algorithms, it's not an error -- we just won't compress - m_compressor = http::compression::details::get_compressor_from_header(header, http::compression::details::header_types::te); + m_compressor = http::compression::details::get_compressor_from_header( + header, http::compression::details::header_types::te); } else if (m_msg.headers().match(header_names::accept_encoding, header)) { - // This would require pre-compression of the input stream, since we MUST send Content-Length, so we'll (legally) ignore it - //m_compressor = http::compression::details::get_compressor_from_header(header, http::compression::details::header_types:accept_encoding); + // This would require pre-compression of the input stream, since we MUST send Content-Length, so we'll + // (legally) ignore it + // m_compressor = http::compression::details::get_compressor_from_header(header, + // http::compression::details::header_types:accept_encoding); } } - catch (http_exception &e) + catch (http_exception& e) { if (badRequestMsg.empty()) { @@ -616,19 +575,20 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD } } - m_msg._get_impl()->_set_http_version({ (uint8_t)m_request->Version.MajorVersion, (uint8_t)m_request->Version.MinorVersion }); + m_msg._get_impl()->_set_http_version( + {(uint8_t)m_request->Version.MajorVersion, (uint8_t)m_request->Version.MinorVersion}); // Retrieve the remote IP address std::vector remoteAddressBuffer(50); if (m_request->Address.pRemoteAddress->sa_family == AF_INET6) { - auto inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin6_addr; + auto inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin6_addr; InetNtopW(AF_INET6, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); } else if (m_request->Address.pRemoteAddress->sa_family == AF_INET) { - auto inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin_addr; + auto inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin_addr; InetNtopW(AF_INET, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); } else @@ -643,9 +603,10 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD read_request_body_chunk(); // Dispatch request to the http_listener. - if(badRequestMsg.empty()) + if (badRequestMsg.empty()) { - dispatch_request_to_listener((web::http::experimental::listener::details::http_listener_impl *)m_request->UrlContext); + dispatch_request_to_listener( + (web::http::experimental::listener::details::http_listener_impl*)m_request->UrlContext); } else { @@ -659,11 +620,11 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD void windows_request_context::read_request_body_chunk() { - auto *pServer = static_cast(http_server_api::server_api()); + auto* pServer = static_cast(http_server_api::server_api()); PVOID body; // The read_body_io_completion callback function - m_overlapped.set_http_io_completion([this](DWORD error, DWORD nBytes){ read_body_io_completion(error, nBytes);}); + m_overlapped.set_http_io_completion([this](DWORD error, DWORD nBytes) { read_body_io_completion(error, nBytes); }); auto request_body_buf = m_msg._get_impl()->outstream().streambuf(); if (!m_decompressor) @@ -684,16 +645,15 @@ void windows_request_context::read_request_body_chunk() _ASSERTE(body != nullptr); StartThreadpoolIo(pServer->m_threadpool_io); - const ULONG error_code = HttpReceiveRequestEntityBody( - pServer->m_hRequestQueue, - m_request_id, - HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, - (PVOID)body, - CHUNK_SIZE, - NULL, - &m_overlapped); - - if(error_code != ERROR_IO_PENDING && error_code != NO_ERROR) + const ULONG error_code = HttpReceiveRequestEntityBody(pServer->m_hRequestQueue, + m_request_id, + HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, + (PVOID)body, + CHUNK_SIZE, + NULL, + &m_overlapped); + + if (error_code != ERROR_IO_PENDING && error_code != NO_ERROR) { // There was no more data to read. CancelThreadpoolIo(pServer->m_threadpool_io); @@ -701,7 +661,7 @@ void windows_request_context::read_request_body_chunk() { request_body_buf.commit(0); } - if(error_code == ERROR_HANDLE_EOF) + if (error_code == ERROR_HANDLE_EOF) { m_msg._get_impl()->_complete(request_body_buf.in_avail()); } @@ -737,7 +697,13 @@ void windows_request_context::read_body_io_completion(DWORD error_code, DWORD by try { bool done_unused; - got = m_decompressor->decompress(m_compress_buffer.data()+total_used, bytes_read-total_used, body, CHUNK_SIZE, http::compression::operation_hint::has_more, used, done_unused); + got = m_decompressor->decompress(m_compress_buffer.data() + total_used, + bytes_read - total_used, + body, + CHUNK_SIZE, + http::compression::operation_hint::has_more, + used, + done_unused); } catch (...) { @@ -769,7 +735,8 @@ void windows_request_context::read_body_io_completion(DWORD error_code, DWORD by } } -void windows_request_context::dispatch_request_to_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener) +void windows_request_context::dispatch_request_to_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener) { m_msg._set_listener_path(pListener->uri().path()); @@ -779,13 +746,13 @@ void windows_request_context::dispatch_request_to_listener(_In_ web::http::exper init_response_callbacks(ShouldWaitForBody::Wait); // Look up the lock for the http_listener. - auto *pServer = static_cast(http_server_api::server_api()); - pplx::extensibility::reader_writer_lock_t *pListenerLock; + auto* pServer = static_cast(http_server_api::server_api()); + pplx::extensibility::reader_writer_lock_t* pListenerLock; { pplx::extensibility::scoped_read_lock_t lock(pServer->_M_listenersLock); // It is possible the listener could have unregistered. - if(pServer->_M_registeredListeners.find(pListener) == pServer->_M_registeredListeners.end()) + if (pServer->_M_registeredListeners.find(pListener) == pServer->_M_registeredListeners.end()) { request.reply(status_codes::NotFound); return; @@ -802,7 +769,7 @@ void windows_request_context::dispatch_request_to_listener(_In_ web::http::exper pListener->handle_request(request); pListenerLock->unlock(); } - catch(...) + catch (...) { pListenerLock->unlock(); request._reply_if_not_already(status_codes::InternalError); @@ -817,8 +784,7 @@ void windows_request_context::init_response_callbacks(ShouldWaitForBody shouldWa auto content_ready_task = m_msg.content_ready(); auto get_response_task = m_msg.get_response(); - content_ready_task.then([this, proxy_content_ready](pplx::task requestBody) - { + content_ready_task.then([this, proxy_content_ready](pplx::task requestBody) { // If an exception occurred while processing the body then there is no reason // to even try sending the response, just re-surface the same exception. try @@ -841,22 +807,26 @@ void windows_request_context::init_response_callbacks(ShouldWaitForBody shouldWa proxy_content_ready.set(); }); - get_response_task.then([this, proxy_content_ready](pplx::task responseTask) - { + get_response_task.then([this, proxy_content_ready](pplx::task responseTask) { // Don't let an exception from sending the response bring down the server. try { m_response = responseTask.get(); } - catch (const pplx::task_canceled &) + catch (const pplx::task_canceled&) { // This means the user didn't respond to the request, allowing the // http_request instance to be destroyed. There is nothing to do then // so don't send a response. // Avoid unobserved exception handler - pplx::create_task(proxy_content_ready).then([](pplx::task t) - { - try { t.wait(); } catch (...) {} + pplx::create_task(proxy_content_ready).then([](pplx::task t) { + try + { + t.wait(); + } + catch (...) + { + } }); return; } @@ -868,8 +838,7 @@ void windows_request_context::init_response_callbacks(ShouldWaitForBody shouldWa m_response = http::http_response(status_codes::InternalError); } - pplx::create_task(m_response_completed).then([this](pplx::task t) - { + pplx::create_task(m_response_completed).then([this](pplx::task t) { // After response is sent, break circular reference between http_response and the request context. // Otherwise http_listener::close() can hang. m_response._get_impl()->_set_server_context(nullptr); @@ -877,17 +846,18 @@ void windows_request_context::init_response_callbacks(ShouldWaitForBody shouldWa // Wait until the content download finished before replying because m_overlapped is reused, // and we don't want to delete 'this' if the body is still downloading - pplx::create_task(proxy_content_ready).then([this](pplx::task t) - { - try - { - t.wait(); - async_process_response(); - } - catch (...) - { - } - }).wait(); + pplx::create_task(proxy_content_ready) + .then([this](pplx::task t) { + try + { + t.wait(); + async_process_response(); + } + catch (...) + { + } + }) + .wait(); }); if (shouldWait == ShouldWaitForBody::DontWait) @@ -899,7 +869,7 @@ void windows_request_context::init_response_callbacks(ShouldWaitForBody shouldWa void windows_request_context::async_process_response() { - auto *pServer = static_cast(http_server_api::server_api()); + auto* pServer = static_cast(http_server_api::server_api()); HTTP_RESPONSE win_api_response; ZeroMemory(&win_api_response, sizeof(win_api_response)); @@ -932,7 +902,8 @@ void windows_request_context::async_process_response() auto factories = m_response._get_impl()->decompress_factories(); try { - m_decompressor = http::compression::details::get_decompressor_from_header(m_decompress_header, m_decompress_header_type, factories); + m_decompressor = http::compression::details::get_decompressor_from_header( + m_decompress_header, m_decompress_header_type, factories); m_decompress_header.clear(); if (!m_decompressor) { @@ -944,7 +915,7 @@ void windows_request_context::async_process_response() throw http_exception(code); } } - catch (http_exception &e) + catch (http_exception& e) { // No matching decompressor was supplied via callback CancelThreadpoolIo(pServer->m_threadpool_io); @@ -955,43 +926,46 @@ void windows_request_context::async_process_response() content_length = m_response._get_impl()->_get_content_length(); } - m_headers = std::unique_ptr(new HTTP_UNKNOWN_HEADER[msl::safeint3::SafeInt(m_response.headers().size())]); + m_headers = std::unique_ptr( + new HTTP_UNKNOWN_HEADER[msl::safeint3::SafeInt(m_response.headers().size())]); m_headers_buffer.resize(msl::safeint3::SafeInt(m_response.headers().size()) * 2); win_api_response.Headers.UnknownHeaderCount = (USHORT)m_response.headers().size(); win_api_response.Headers.pUnknownHeaders = m_headers.get(); int headerIndex = 0; - for(auto iter = m_response.headers().begin(); iter != m_response.headers().end(); ++iter, ++headerIndex) + for (auto iter = m_response.headers().begin(); iter != m_response.headers().end(); ++iter, ++headerIndex) { m_headers_buffer[headerIndex * 2] = utf16_to_utf8(iter->first); m_headers_buffer[headerIndex * 2 + 1] = utf16_to_utf8(iter->second); - win_api_response.Headers.pUnknownHeaders[headerIndex].NameLength = (USHORT)m_headers_buffer[headerIndex * 2].size(); + win_api_response.Headers.pUnknownHeaders[headerIndex].NameLength = + (USHORT)m_headers_buffer[headerIndex * 2].size(); win_api_response.Headers.pUnknownHeaders[headerIndex].pName = m_headers_buffer[headerIndex * 2].c_str(); - win_api_response.Headers.pUnknownHeaders[headerIndex].RawValueLength = (USHORT)m_headers_buffer[headerIndex * 2 + 1].size(); + win_api_response.Headers.pUnknownHeaders[headerIndex].RawValueLength = + (USHORT)m_headers_buffer[headerIndex * 2 + 1].size(); win_api_response.Headers.pUnknownHeaders[headerIndex].pRawValue = m_headers_buffer[headerIndex * 2 + 1].c_str(); } // Send response callback function - m_overlapped.set_http_io_completion([this](DWORD error, DWORD nBytes){ send_response_io_completion(error, nBytes);}); + m_overlapped.set_http_io_completion( + [this](DWORD error, DWORD nBytes) { send_response_io_completion(error, nBytes); }); // Figure out how to send the entity body of the message. if (content_length == 0) { // There's no data. This is easy! StartThreadpoolIo(pServer->m_threadpool_io); - const unsigned long error_code = HttpSendHttpResponse( - pServer->m_hRequestQueue, - m_request_id, - NULL, - &win_api_response, - NULL, - NULL, - NULL, - NULL, - &m_overlapped, - NULL); - - if(error_code != NO_ERROR && error_code != ERROR_IO_PENDING) + const unsigned long error_code = HttpSendHttpResponse(pServer->m_hRequestQueue, + m_request_id, + NULL, + &win_api_response, + NULL, + NULL, + NULL, + NULL, + &m_overlapped, + NULL); + + if (error_code != NO_ERROR && error_code != ERROR_IO_PENDING) { CancelThreadpoolIo(pServer->m_threadpool_io); cancel_request(std::make_exception_ptr(http_exception(error_code))); @@ -1012,19 +986,18 @@ void windows_request_context::async_process_response() } StartThreadpoolIo(pServer->m_threadpool_io); - const unsigned long error_code = HttpSendHttpResponse( - pServer->m_hRequestQueue, - m_request_id, - HTTP_SEND_RESPONSE_FLAG_MORE_DATA, - &win_api_response, - NULL, - NULL, - NULL, - NULL, - &m_overlapped, - NULL); - - if(error_code != NO_ERROR && error_code != ERROR_IO_PENDING) + const unsigned long error_code = HttpSendHttpResponse(pServer->m_hRequestQueue, + m_request_id, + HTTP_SEND_RESPONSE_FLAG_MORE_DATA, + &win_api_response, + NULL, + NULL, + NULL, + NULL, + &m_overlapped, + NULL); + + if (error_code != NO_ERROR && error_code != ERROR_IO_PENDING) { CancelThreadpoolIo(pServer->m_threadpool_io); cancel_request(std::make_exception_ptr(http_exception(error_code))); @@ -1036,7 +1009,7 @@ void windows_request_context::async_process_response() /// void windows_request_context::send_response_io_completion(DWORD error_code, DWORD) { - if(error_code != NO_ERROR) + if (error_code != NO_ERROR) { cancel_request(std::make_exception_ptr(http_exception(error_code))); } @@ -1049,7 +1022,7 @@ void windows_request_context::send_response_io_completion(DWORD error_code, DWOR // Transmit the response body to the network void windows_request_context::transmit_body() { - if ( !m_sending_in_chunks && !m_transfer_encoding ) + if (!m_sending_in_chunks && !m_transfer_encoding) { // We are done sending data. std::lock_guard lock(m_responseCompletedLock); @@ -1061,31 +1034,35 @@ void windows_request_context::transmit_body() size_t next_chunk_size = safeCount.Min(CHUNK_SIZE); // In both cases here we could perform optimizations to try and use acquire on the streams to avoid an extra copy. - if ( m_sending_in_chunks ) + if (m_sending_in_chunks) { m_body_data.resize(CHUNK_SIZE); streams::rawptr_buffer buf(&m_body_data[0], next_chunk_size); - m_response.body().read(buf, next_chunk_size).then([this](pplx::task op) - { + m_response.body().read(buf, next_chunk_size).then([this](pplx::task op) { size_t bytes_read = 0; // If an exception occurs surface the error to user on the server side // and cancel the request so the client sees the error. - try { bytes_read = op.get(); } catch (...) + try + { + bytes_read = op.get(); + } + catch (...) { cancel_request(std::current_exception()); return; } - if ( bytes_read == 0 ) + if (bytes_read == 0) { - cancel_request(std::make_exception_ptr(http_exception(_XPLATSTR("Error unexpectedly encountered the end of the response stream early")))); + cancel_request(std::make_exception_ptr( + http_exception(_XPLATSTR("Error unexpectedly encountered the end of the response stream early")))); return; } // Check whether this is the last one to send... - m_remaining_to_write = m_remaining_to_write-bytes_read; + m_remaining_to_write = m_remaining_to_write - bytes_read; m_sending_in_chunks = (m_remaining_to_write > 0); send_entity_body(&m_body_data[0], bytes_read); @@ -1097,7 +1074,7 @@ void windows_request_context::transmit_body() if (m_compressor) { // ...and compressing. For simplicity, we allocate a buffer that's "too large to fail" while compressing. - const size_t body_data_length = 2*CHUNK_SIZE + http::details::chunked_encoding::additional_encoding_space; + const size_t body_data_length = 2 * CHUNK_SIZE + http::details::chunked_encoding::additional_encoding_space; m_body_data.resize(body_data_length); // We'll read into a temporary buffer before compressing @@ -1108,8 +1085,7 @@ void windows_request_context::transmit_body() streams::rawptr_buffer buf(m_compress_buffer.data(), next_chunk_size); - m_response.body().read(buf, next_chunk_size).then([this, body_data_length](pplx::task op) - { + m_response.body().read(buf, next_chunk_size).then([this, body_data_length](pplx::task op) { size_t bytes_read = 0; // If an exception occurs surface the error to user on the server side @@ -1131,39 +1107,48 @@ void windows_request_context::transmit_body() { hint = http::compression::operation_hint::is_last; } - m_compressor->compress(m_compress_buffer.data(), bytes_read, &m_body_data[http::details::chunked_encoding::data_offset], body_data_length, hint) - .then([this, bytes_read, body_data_length](pplx::task op) - { - http::compression::operation_result r; - - try - { - r = op.get(); - } - catch (...) - { - cancel_request(std::current_exception()); - return; - } - - if (r.input_bytes_processed != bytes_read || - r.output_bytes_produced == body_data_length - http::details::chunked_encoding::additional_encoding_space || - r.done != !bytes_read) - { - // We chose our parameters so that compression should - // never overflow body_data_length; fail if it does - cancel_request(std::make_exception_ptr(std::exception("Compressed data exceeds internal buffer size."))); - return; - } - - // Check whether this is the last one to send; note that this is a - // few lines of near-duplicate code with the non-compression path - _ASSERTE(bytes_read <= m_remaining_to_write); - m_remaining_to_write -= bytes_read; - m_transfer_encoding = (r.output_bytes_produced > 0); - size_t offset = http::details::chunked_encoding::add_chunked_delimiters(&m_body_data[0], body_data_length, r.output_bytes_produced); - send_entity_body(&m_body_data[offset], r.output_bytes_produced + http::details::chunked_encoding::additional_encoding_space - offset); - }); + m_compressor + ->compress(m_compress_buffer.data(), + bytes_read, + &m_body_data[http::details::chunked_encoding::data_offset], + body_data_length, + hint) + .then([this, bytes_read, body_data_length](pplx::task op) { + http::compression::operation_result r; + + try + { + r = op.get(); + } + catch (...) + { + cancel_request(std::current_exception()); + return; + } + + if (r.input_bytes_processed != bytes_read || + r.output_bytes_produced == + body_data_length - http::details::chunked_encoding::additional_encoding_space || + r.done != !bytes_read) + { + // We chose our parameters so that compression should + // never overflow body_data_length; fail if it does + cancel_request(std::make_exception_ptr( + std::exception("Compressed data exceeds internal buffer size."))); + return; + } + + // Check whether this is the last one to send; note that this is a + // few lines of near-duplicate code with the non-compression path + _ASSERTE(bytes_read <= m_remaining_to_write); + m_remaining_to_write -= bytes_read; + m_transfer_encoding = (r.output_bytes_produced > 0); + size_t offset = http::details::chunked_encoding::add_chunked_delimiters( + &m_body_data[0], body_data_length, r.output_bytes_produced); + send_entity_body(&m_body_data[offset], + r.output_bytes_produced + + http::details::chunked_encoding::additional_encoding_space - offset); + }); }); } else @@ -1171,10 +1156,10 @@ void windows_request_context::transmit_body() const size_t body_data_length = CHUNK_SIZE + http::details::chunked_encoding::additional_encoding_space; m_body_data.resize(body_data_length); - streams::rawptr_buffer buf(&m_body_data[http::details::chunked_encoding::data_offset], body_data_length); + streams::rawptr_buffer buf(&m_body_data[http::details::chunked_encoding::data_offset], + body_data_length); - m_response.body().read(buf, next_chunk_size).then([this, body_data_length](pplx::task op) - { + m_response.body().read(buf, next_chunk_size).then([this, body_data_length](pplx::task op) { size_t bytes_read = 0; // If an exception occurs surface the error to user on the server side @@ -1191,7 +1176,8 @@ void windows_request_context::transmit_body() // Check whether this is the last one to send... m_transfer_encoding = (bytes_read > 0); - size_t offset = http::details::chunked_encoding::add_chunked_delimiters(&m_body_data[0], body_data_length, bytes_read); + size_t offset = http::details::chunked_encoding::add_chunked_delimiters( + &m_body_data[0], body_data_length, bytes_read); auto data_length = bytes_read + (http::details::chunked_encoding::additional_encoding_space - offset); send_entity_body(&m_body_data[offset], data_length); @@ -1201,7 +1187,7 @@ void windows_request_context::transmit_body() } // Send the body through HTTP.sys -void windows_request_context::send_entity_body(_In_reads_(data_length) unsigned char * data, _In_ size_t data_length) +void windows_request_context::send_entity_body(_In_reads_(data_length) unsigned char* data, _In_ size_t data_length) { HTTP_DATA_CHUNK dataChunk; memset(&dataChunk, 0, sizeof(dataChunk)); @@ -1211,28 +1197,28 @@ void windows_request_context::send_entity_body(_In_reads_(data_length) unsigned const bool this_is_the_last_chunk = !m_transfer_encoding && !m_sending_in_chunks; // Send response. - auto *pServer = static_cast(http_server_api::server_api()); + auto* pServer = static_cast(http_server_api::server_api()); // Send response body callback function - m_overlapped.set_http_io_completion([this](DWORD error, DWORD nBytes){ send_response_body_io_completion(error, nBytes); }); + m_overlapped.set_http_io_completion( + [this](DWORD error, DWORD nBytes) { send_response_body_io_completion(error, nBytes); }); StartThreadpoolIo(pServer->m_threadpool_io); - auto error_code = HttpSendResponseEntityBody( - pServer->m_hRequestQueue, - m_request_id, - this_is_the_last_chunk ? NULL : HTTP_SEND_RESPONSE_FLAG_MORE_DATA, - 1, - &dataChunk, - NULL, - NULL, - NULL, - &m_overlapped, - NULL); - - if(error_code != NO_ERROR && error_code != ERROR_IO_PENDING) + auto error_code = HttpSendResponseEntityBody(pServer->m_hRequestQueue, + m_request_id, + this_is_the_last_chunk ? NULL : HTTP_SEND_RESPONSE_FLAG_MORE_DATA, + 1, + &dataChunk, + NULL, + NULL, + NULL, + &m_overlapped, + NULL); + + if (error_code != NO_ERROR && error_code != ERROR_IO_PENDING) { CancelThreadpoolIo(pServer->m_threadpool_io); - cancel_request( std::make_exception_ptr(http_exception(error_code))); + cancel_request(std::make_exception_ptr(http_exception(error_code))); } } @@ -1241,7 +1227,7 @@ void windows_request_context::send_entity_body(_In_reads_(data_length) unsigned /// void windows_request_context::send_response_body_io_completion(DWORD error_code, DWORD) { - if(error_code != NO_ERROR) + if (error_code != NO_ERROR) { cancel_request(std::make_exception_ptr(http_exception(error_code))); return; @@ -1260,21 +1246,19 @@ void windows_request_context::cancel_request_io_completion(DWORD, DWORD) void windows_request_context::cancel_request(std::exception_ptr except_ptr) { - auto *pServer = static_cast(http_server_api::server_api()); + auto* pServer = static_cast(http_server_api::server_api()); m_except_ptr = except_ptr; // Cancel request callback function. - m_overlapped.set_http_io_completion([this](DWORD error, DWORD nBytes){cancel_request_io_completion(error, nBytes);}); + m_overlapped.set_http_io_completion( + [this](DWORD error, DWORD nBytes) { cancel_request_io_completion(error, nBytes); }); StartThreadpoolIo(pServer->m_threadpool_io); - auto error_code = HttpCancelHttpRequest( - pServer->m_hRequestQueue, - m_request_id, - &m_overlapped); + auto error_code = HttpCancelHttpRequest(pServer->m_hRequestQueue, m_request_id, &m_overlapped); - if(error_code != NO_ERROR && error_code != ERROR_IO_PENDING) + if (error_code != NO_ERROR && error_code != ERROR_IO_PENDING) { CancelThreadpoolIo(pServer->m_threadpool_io); std::lock_guard lock(m_responseCompletedLock); @@ -1282,11 +1266,11 @@ void windows_request_context::cancel_request(std::exception_ptr except_ptr) } } -std::unique_ptr make_http_httpsys_server() -{ - return std::make_unique(); -} +std::unique_ptr make_http_httpsys_server() { return std::make_unique(); } -}}}} +} // namespace details +} // namespace experimental +} // namespace http +} // namespace web #endif diff --git a/Release/src/http/listener/http_server_httpsys.h b/Release/src/http/listener/http_server_httpsys.h index 5a8cbd137b..d998619bbe 100644 --- a/Release/src/http/listener/http_server_httpsys.h +++ b/Release/src/http/listener/http_server_httpsys.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: implementation of HTTP server API built on Windows HTTP Server APIs. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: implementation of HTTP server API built on Windows HTTP Server APIs. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -21,11 +21,10 @@ #include #pragma warning(pop) +#include "cpprest/details/http_server.h" #include #include -#include "cpprest/details/http_server.h" - namespace web { namespace http @@ -34,7 +33,6 @@ namespace experimental { namespace details { - class http_windows_server; struct windows_request_context; @@ -53,20 +51,19 @@ class http_overlapped : public OVERLAPPED /// /// Callback for all I/O completions. /// - static void CALLBACK io_completion_callback( - PTP_CALLBACK_INSTANCE instance, - PVOID context, - PVOID pOverlapped, - ULONG result, - ULONG_PTR numberOfBytesTransferred, - PTP_IO io) + static void CALLBACK io_completion_callback(PTP_CALLBACK_INSTANCE instance, + PVOID context, + PVOID pOverlapped, + ULONG result, + ULONG_PTR numberOfBytesTransferred, + PTP_IO io) { CASABLANCA_UNREFERENCED_PARAMETER(io); CASABLANCA_UNREFERENCED_PARAMETER(context); CASABLANCA_UNREFERENCED_PARAMETER(instance); - http_overlapped *p_http_overlapped = (http_overlapped *)pOverlapped; - p_http_overlapped->m_http_io_completion(result, (DWORD) numberOfBytesTransferred); + http_overlapped* p_http_overlapped = (http_overlapped*)pOverlapped; + p_http_overlapped->m_http_io_completion(result, (DWORD)numberOfBytesTransferred); } private: @@ -85,14 +82,15 @@ struct windows_request_context : http::details::_http_server_context void async_process_request(HTTP_REQUEST_ID request_id, http::http_request msg, const unsigned long headers_size); // Dispatch request to the provided http_listener. - void dispatch_request_to_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener); + void dispatch_request_to_listener(_In_ web::http::experimental::listener::details::http_listener_impl* pListener); enum class ShouldWaitForBody { Wait, DontWait }; - // Initialise the response task callbacks. If the body has been requested, we should wait for it to avoid race conditions. + // Initialise the response task callbacks. If the body has been requested, we should wait for it to avoid race + // conditions. void init_response_callbacks(ShouldWaitForBody shouldWait); // Read in a portion of the request body. @@ -131,10 +129,10 @@ struct windows_request_context : http::details::_http_server_context size_t m_remaining_to_write; - HTTP_REQUEST *m_request; + HTTP_REQUEST* m_request; std::unique_ptr m_request_buffer; - std::unique_ptr m_headers; + std::unique_ptr m_headers; std::vector m_headers_buffer; http_overlapped m_overlapped; @@ -151,11 +149,11 @@ struct windows_request_context : http::details::_http_server_context http::compression::details::header_types m_decompress_header_type; private: - windows_request_context(const windows_request_context &); - windows_request_context& operator=(const windows_request_context &); + windows_request_context(const windows_request_context&); + windows_request_context& operator=(const windows_request_context&); // Sends entity body chunk. - void send_entity_body(_In_reads_(data_length) unsigned char * data, _In_ size_t data_length); + void send_entity_body(_In_reads_(data_length) unsigned char* data, _In_ size_t data_length); // Cancels this request. void cancel_request(std::exception_ptr except_ptr); @@ -169,7 +167,6 @@ struct windows_request_context : http::details::_http_server_context class http_windows_server : public http_server { public: - /// /// Constructs a http_windows_server. /// @@ -188,12 +185,14 @@ class http_windows_server : public http_server /// /// Registers an http listener. /// - virtual pplx::task register_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener); + virtual pplx::task register_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener); /// /// Unregisters an http listener. /// - virtual pplx::task unregister_listener(_In_ web::http::experimental::listener::details::http_listener_impl *pListener); + virtual pplx::task unregister_listener( + _In_ web::http::experimental::listener::details::http_listener_impl* pListener); /// /// Stop processing and listening for incoming requests. @@ -214,9 +213,7 @@ class http_windows_server : public http_server class listener_registration { public: - listener_registration(HTTP_URL_GROUP_ID urlGroupId) - : m_urlGroupId(urlGroupId) - {} + listener_registration(HTTP_URL_GROUP_ID urlGroupId) : m_urlGroupId(urlGroupId) {} // URL group id for this listener. Each listener needs it own URL group // because configuration like timeouts, authentication, etc... @@ -228,7 +225,9 @@ class http_windows_server : public http_server // Registered listeners pplx::extensibility::reader_writer_lock_t _M_listenersLock; - std::unordered_map> _M_registeredListeners; + std::unordered_map> + _M_registeredListeners; // HTTP Server API server session id. HTTP_SERVER_SESSION_ID m_serverSessionId; @@ -241,13 +240,14 @@ class http_windows_server : public http_server HANDLE m_hRequestQueue; // Threadpool I/O structure for overlapped I/O. - TP_IO * m_threadpool_io; + TP_IO* m_threadpool_io; // Task which actually handles receiving requests from HTTP Server API request queue. pplx::task m_receivingTask; void receive_requests(); }; -} // namespace details; +} // namespace details } // namespace experimental -}} // namespace web::http +} // namespace http +} // namespace web diff --git a/Release/src/http/listener/http_server_impl.h b/Release/src/http/listener/http_server_impl.h index 6a4380b708..7caa5a6666 100644 --- a/Release/src/http/listener/http_server_impl.h +++ b/Release/src/http/listener/http_server_impl.h @@ -1,7 +1,7 @@ #pragma once -#include #include "cpprest/details/http_server.h" +#include namespace web { @@ -11,8 +11,10 @@ namespace experimental { namespace details { - std::unique_ptr make_http_httpsys_server(); std::unique_ptr make_http_asio_server(); -}}}} +} // namespace details +} // namespace experimental +} // namespace http +} // namespace web diff --git a/Release/src/http/oauth/oauth1.cpp b/Release/src/http/oauth/oauth1.cpp index 22029593b8..506d9f1faa 100644 --- a/Release/src/http/oauth/oauth1.cpp +++ b/Release/src/http/oauth/oauth1.cpp @@ -1,17 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Oauth 1.0 -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Oauth 1.0 + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/asyncrt_utils.h" #if !defined(CPPREST_TARGET_XP) @@ -22,30 +23,31 @@ using web::http::client::http_client_config; using web::http::oauth1::details::oauth1_state; using web::http::oauth1::details::oauth1_strings; -namespace web { namespace http { namespace oauth1 +namespace web +{ +namespace http +{ +namespace oauth1 { - namespace details { - #define _OAUTH1_STRINGS #define DAT(a_, b_) const oauth1_string oauth1_strings::a_(_XPLATSTR(b_)); #include "cpprest/details/http_constants.dat" #undef _OAUTH1_STRINGS #undef DAT -} // namespace web::http::oauth1::details +} // namespace details namespace experimental { - // // Start of platform-dependent _hmac_sha1() block... // #if defined(_WIN32) && !defined(__cplusplus_winrt) // Windows desktop -#include #include +#include // Code analysis complains even though there is no bug. #pragma warning(push) @@ -60,27 +62,27 @@ std::vector oauth1_config::_hmac_sha1(const utility::string_t& ke DWORD hash_len = 0; ULONG result_len = 0; - const auto &key_c = conversions::utf16_to_utf8(key); - const auto &data_c = conversions::utf16_to_utf8(data); + const auto& key_c = conversions::utf16_to_utf8(key); + const auto& data_c = conversions::utf16_to_utf8(data); status = BCryptOpenAlgorithmProvider(&alg_handle, BCRYPT_SHA1_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG); if (!NT_SUCCESS(status)) { goto cleanup; } - status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH, (PBYTE) &hash_len, sizeof(hash_len), &result_len, 0); + status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH, (PBYTE)&hash_len, sizeof(hash_len), &result_len, 0); if (!NT_SUCCESS(status)) { goto cleanup; } hash.resize(hash_len); - status = BCryptCreateHash(alg_handle, &hash_handle, nullptr, 0, (PBYTE) key_c.c_str(), (ULONG) key_c.length(), 0); + status = BCryptCreateHash(alg_handle, &hash_handle, nullptr, 0, (PBYTE)key_c.c_str(), (ULONG)key_c.length(), 0); if (!NT_SUCCESS(status)) { goto cleanup; } - status = BCryptHashData(hash_handle, (PBYTE) data_c.c_str(), (ULONG) data_c.length(), 0); + status = BCryptHashData(hash_handle, (PBYTE)data_c.c_str(), (ULONG)data_c.length(), 0); if (!NT_SUCCESS(status)) { goto cleanup; @@ -113,17 +115,17 @@ using namespace Windows::Storage::Streams; std::vector oauth1_config::_hmac_sha1(const utility::string_t& key, const utility::string_t& data) { - Platform::String^ data_str = ref new Platform::String(data.c_str()); - Platform::String^ key_str = ref new Platform::String(key.c_str()); + Platform::String ^ data_str = ref new Platform::String(data.c_str()); + Platform::String ^ key_str = ref new Platform::String(key.c_str()); - MacAlgorithmProvider^ HMACSha1Provider = MacAlgorithmProvider::OpenAlgorithm(MacAlgorithmNames::HmacSha1); - IBuffer^ content_buffer = CryptographicBuffer::ConvertStringToBinary(data_str, BinaryStringEncoding::Utf8); - IBuffer^ key_buffer = CryptographicBuffer::ConvertStringToBinary(key_str, BinaryStringEncoding::Utf8); + MacAlgorithmProvider ^ HMACSha1Provider = MacAlgorithmProvider::OpenAlgorithm(MacAlgorithmNames::HmacSha1); + IBuffer ^ content_buffer = CryptographicBuffer::ConvertStringToBinary(data_str, BinaryStringEncoding::Utf8); + IBuffer ^ key_buffer = CryptographicBuffer::ConvertStringToBinary(key_str, BinaryStringEncoding::Utf8); auto signature_key = HMACSha1Provider->CreateKey(key_buffer); auto signed_buffer = CryptographicEngine::Sign(signature_key, content_buffer); - Platform::Array^ arr; + Platform::Array ^ arr; CryptographicBuffer::CopyToByteArray(signed_buffer, &arr); return std::vector(arr->Data, arr->Data + arr->Length); } @@ -137,9 +139,13 @@ std::vector oauth1_config::_hmac_sha1(const utility::string_t& ke unsigned char digest[HMAC_MAX_MD_CBLOCK]; unsigned int digest_len = 0; - HMAC(EVP_sha1(), key.c_str(), static_cast(key.length()), - (const unsigned char*) data.c_str(), data.length(), - digest, &digest_len); + HMAC(EVP_sha1(), + key.c_str(), + static_cast(key.length()), + (const unsigned char*)data.c_str(), + data.length(), + digest, + &digest_len); return std::vector(digest, digest + digest_len); } @@ -216,7 +222,7 @@ utility::string_t oauth1_config::_build_normalized_parameters(web::http::uri u, return uri::encode_data_string(result); } -static bool is_application_x_www_form_urlencoded (http_request &request) +static bool is_application_x_www_form_urlencoded(http_request& request) { const auto content_type(request.headers()[header_names::content_type]); return 0 == content_type.find(web::http::details::mime_types::application_x_www_form_urlencoded); @@ -229,11 +235,11 @@ utility::string_t oauth1_config::_build_signature_base_string(http_request reque result += _XPLATSTR('&'); result += _build_base_string_uri(u); - // http://oauth.net/core/1.0a/#signing_process - // 9.1.1. Normalize Request Parameters - // The request parameters are collected, sorted and concatenated into a normalized string: - // - Parameters in the OAuth HTTP Authorization header excluding the realm parameter. - // - Parameters in the HTTP POST request body (with a content-type of application/x-www-form-urlencoded). + // http://oauth.net/core/1.0a/#signing_process + // 9.1.1. Normalize Request Parameters + // The request parameters are collected, sorted and concatenated into a normalized string: + // - Parameters in the OAuth HTTP Authorization header excluding the realm parameter. + // - Parameters in the HTTP POST request body (with a content-type of application/x-www-form-urlencoded). // - HTTP GET parameters added to the URLs in the query part (as defined by [RFC3986] section 3). result += _XPLATSTR('&'); if (is_application_x_www_form_urlencoded(request)) @@ -282,50 +288,47 @@ pplx::task oauth1_config::_request_token(oauth1_state state, bool is_temp_ http_client client(endpoint, config); return client.request(req) - .then([](http_response resp) - { - return resp.extract_string(); - }) - .then([this, is_temp_token_request](utility::string_t body) -> void - { - auto query(uri::split_query(body)); + .then([](http_response resp) { return resp.extract_string(); }) + .then([this, is_temp_token_request](utility::string_t body) -> void { + auto query(uri::split_query(body)); - if (is_temp_token_request) - { - auto callback_confirmed_param = query.find(oauth1_strings::callback_confirmed); - if (callback_confirmed_param == query.end()) + if (is_temp_token_request) { - throw oauth1_exception(U("parameter 'oauth_callback_confirmed' is missing from response: ") + body - + U(". the service may be using obsoleted and insecure OAuth Core 1.0 protocol.")); + auto callback_confirmed_param = query.find(oauth1_strings::callback_confirmed); + if (callback_confirmed_param == query.end()) + { + throw oauth1_exception( + U("parameter 'oauth_callback_confirmed' is missing from response: ") + body + + U(". the service may be using obsoleted and insecure OAuth Core 1.0 protocol.")); + } } - } - auto token_param = query.find(oauth1_strings::token); - if (token_param == query.end()) - { - throw oauth1_exception(U("parameter 'oauth_token' missing from response: ") + body); - } + auto token_param = query.find(oauth1_strings::token); + if (token_param == query.end()) + { + throw oauth1_exception(U("parameter 'oauth_token' missing from response: ") + body); + } - auto token_secret_param = query.find(oauth1_strings::token_secret); - if (token_secret_param == query.end()) - { - throw oauth1_exception(U("parameter 'oauth_token_secret' missing from response: ") + body); - } + auto token_secret_param = query.find(oauth1_strings::token_secret); + if (token_secret_param == query.end()) + { + throw oauth1_exception(U("parameter 'oauth_token_secret' missing from response: ") + body); + } - // Here the token can be either temporary or access token. - // The authorization is complete if it is access token. - m_is_authorization_completed = !is_temp_token_request; - m_token = oauth1_token(web::uri::decode(token_param->second), web::uri::decode(token_secret_param->second)); + // Here the token can be either temporary or access token. + // The authorization is complete if it is access token. + m_is_authorization_completed = !is_temp_token_request; + m_token = oauth1_token(web::uri::decode(token_param->second), web::uri::decode(token_secret_param->second)); - for (const auto& qa : query) - { - if (qa.first == oauth1_strings::token || qa.first == oauth1_strings::token_secret) continue ; - m_token.set_additional_parameter(web::uri::decode(qa.first), web::uri::decode(qa.second)); - } - }); + for (const auto& qa : query) + { + if (qa.first == oauth1_strings::token || qa.first == oauth1_strings::token_secret) continue; + m_token.set_additional_parameter(web::uri::decode(qa.first), web::uri::decode(qa.second)); + } + }); } -void oauth1_config::_authenticate_request(http_request &request, oauth1_state state) +void oauth1_config::_authenticate_request(http_request& request, oauth1_state state) { utility::string_t authHeader(_XPLATSTR("OAuth ")); if (!realm().empty()) @@ -340,7 +343,7 @@ void oauth1_config::_authenticate_request(http_request &request, oauth1_state st authHeader += _XPLATSTR("=\"1.0\", "); authHeader += oauth1_strings::consumer_key; authHeader += _XPLATSTR("=\""); - authHeader += web::uri::encode_data_string (consumer_key()); + authHeader += web::uri::encode_data_string(consumer_key()); if (!m_token.access_token().empty()) { @@ -382,10 +385,10 @@ void oauth1_config::_authenticate_request(http_request &request, oauth1_state st pplx::task oauth1_config::build_authorization_uri() { - pplx::task temp_token_req = _request_token(_generate_auth_state(oauth1_strings::callback, callback_uri()), true); + pplx::task temp_token_req = + _request_token(_generate_auth_state(oauth1_strings::callback, callback_uri()), true); - return temp_token_req.then([this] - { + return temp_token_req.then([this] { uri_builder ub(auth_endpoint()); ub.append_query(oauth1_strings::token, m_token.access_token()); return ub.to_string(); @@ -399,20 +402,21 @@ pplx::task oauth1_config::token_from_redirected_uri(const web::http::uri& auto token_param = query.find(oauth1_strings::token); if (token_param == query.end()) { - return pplx::task_from_exception(oauth1_exception(U("parameter 'oauth_token' missing from redirected URI."))); + return pplx::task_from_exception( + oauth1_exception(U("parameter 'oauth_token' missing from redirected URI."))); } if (m_token.access_token() != token_param->second) { return pplx::task_from_exception(oauth1_exception( - _XPLATSTR("redirected URI parameter 'oauth_token'='") + token_param->second - + _XPLATSTR("' does not match temporary token='") + m_token.access_token() + _XPLATSTR("'.") - )); + _XPLATSTR("redirected URI parameter 'oauth_token'='") + token_param->second + + _XPLATSTR("' does not match temporary token='") + m_token.access_token() + _XPLATSTR("'."))); } auto verifier_param = query.find(oauth1_strings::verifier); if (verifier_param == query.end()) { - return pplx::task_from_exception(oauth1_exception(U("parameter 'oauth_verifier' missing from redirected URI."))); + return pplx::task_from_exception( + oauth1_exception(U("parameter 'oauth_verifier' missing from redirected URI."))); } return token_from_verifier(verifier_param->second); @@ -441,11 +445,14 @@ const oauth1_token& oauth1_config::token() const } #define _OAUTH1_METHODS -#define DAT(a,b) const oauth1_method oauth1_methods::a = b; +#define DAT(a, b) const oauth1_method oauth1_methods::a = b; #include "cpprest/details/http_constants.dat" #undef _OAUTH1_METHODS #undef DAT -}}}} +} // namespace experimental +} // namespace oauth1 +} // namespace http +} // namespace web #endif diff --git a/Release/src/http/oauth/oauth2.cpp b/Release/src/http/oauth/oauth2.cpp index f37f876dbc..3e54a6e07c 100644 --- a/Release/src/http/oauth/oauth2.cpp +++ b/Release/src/http/oauth/oauth2.cpp @@ -1,46 +1,47 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Oauth 2.0 -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Oauth 2.0 + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" #include +using utility::conversions::to_utf8string; using web::http::client::http_client; using web::http::client::http_client_config; -using web::http::oauth2::details::oauth2_strings; using web::http::details::mime_types; -using utility::conversions::to_utf8string; +using web::http::oauth2::details::oauth2_strings; // Expose base64 conversion for arbitrary buffer. -extern utility::string_t _to_base64(const unsigned char *ptr, size_t size); +extern utility::string_t _to_base64(const unsigned char* ptr, size_t size); -namespace web { namespace http { namespace oauth2 +namespace web +{ +namespace http +{ +namespace oauth2 { - namespace details { - #define _OAUTH2_STRINGS #define DAT(a_, b_) const oauth2_string oauth2_strings::a_(_XPLATSTR(b_)); #include "cpprest/details/http_constants.dat" #undef _OAUTH2_STRINGS #undef DAT -} // namespace web::http::oauth2::details +} // namespace details namespace experimental { - utility::string_t oauth2_config::build_authorization_uri(bool generate_state) { const utility::string_t response_type((implicit_grant()) ? oauth2_strings::token : oauth2_strings::code); @@ -92,7 +93,8 @@ pplx::task oauth2_config::token_from_redirected_uri(const web::http::uri& auto token_param = query.find(oauth2_strings::access_token); if (token_param == query.end()) { - return pplx::task_from_exception(oauth2_exception(U("either 'code' or 'access_token' parameter must be in the redirected URI."))); + return pplx::task_from_exception( + oauth2_exception(U("either 'code' or 'access_token' parameter must be in the redirected URI."))); } set_token(token_param->second); @@ -105,7 +107,7 @@ pplx::task oauth2_config::_request_token(uri_builder& request_body_ub) request.set_method(methods::POST); request.set_request_uri(utility::string_t()); - if(!user_agent().empty()) + if (!user_agent().empty()) { request.headers().add(web::http::header_names::user_agent, user_agent()); } @@ -118,10 +120,11 @@ pplx::task oauth2_config::_request_token(uri_builder& request_body_ub) if (http_basic_auth()) { // Build HTTP Basic authorization header. - const std::string creds_utf8(to_utf8string( - uri::encode_data_string(client_key()) + U(":") + uri::encode_data_string(client_secret()))); - request.headers().add(header_names::authorization, U("Basic ") - + _to_base64(reinterpret_cast(creds_utf8.data()), creds_utf8.size())); + const std::string creds_utf8( + to_utf8string(uri::encode_data_string(client_key()) + U(":") + uri::encode_data_string(client_secret()))); + request.headers().add( + header_names::authorization, + U("Basic ") + _to_base64(reinterpret_cast(creds_utf8.data()), creds_utf8.size())); } else { @@ -131,21 +134,15 @@ pplx::task oauth2_config::_request_token(uri_builder& request_body_ub) } request.set_body(request_body_ub.query(), mime_types::application_x_www_form_urlencoded); - // configure proxy - http_client_config config; - config.set_proxy(m_proxy); + // configure proxy + http_client_config config; + config.set_proxy(m_proxy); http_client token_client(token_endpoint(), config); return token_client.request(request) - .then([](http_response resp) - { - return resp.extract_json(); - }) - .then([this](json::value json_resp) -> void - { - set_token(_parse_token_from_json(json_resp)); - }); + .then([](http_response resp) { return resp.extract_json(); }) + .then([this](json::value json_resp) -> void { set_token(_parse_token_from_json(json_resp)); }); } oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json) @@ -174,7 +171,8 @@ oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json } if (!utility::details::str_iequal(result.token_type(), oauth2_strings::bearer)) { - throw oauth2_exception(U("only 'token_type=bearer' access tokens are currently supported: ") + token_json.serialize()); + throw oauth2_exception(U("only 'token_type=bearer' access tokens are currently supported: ") + + token_json.serialize()); } if (token_json.has_string_field(oauth2_strings::refresh_token)) @@ -188,10 +186,10 @@ oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json if (token_json.has_field(oauth2_strings::expires_in)) { - const auto &json_expires_in_val = token_json.at(oauth2_strings::expires_in); + const auto& json_expires_in_val = token_json.at(oauth2_strings::expires_in); if (json_expires_in_val.is_number()) - result.set_expires_in(json_expires_in_val.as_number().to_int64()); + result.set_expires_in(json_expires_in_val.as_number().to_int64()); else { // Handle the case of a number as a JSON "string". @@ -224,4 +222,7 @@ oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json return result; } -}}}} // namespace web::http::oauth2::experimental +} // namespace experimental +} // namespace oauth2 +} // namespace http +} // namespace web diff --git a/Release/src/json/json.cpp b/Release/src/json/json.cpp index e5a6089aea..7b61a179cc 100644 --- a/Release/src/json/json.cpp +++ b/Release/src/json/json.cpp @@ -1,125 +1,134 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: JSON parser and writer -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: JSON parser and writer + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; bool json::details::g_keep_json_object_unsorted = false; -void json::keep_object_element_order(bool keep_order) -{ - json::details::g_keep_json_object_unsorted = keep_order; -} +void json::keep_object_element_order(bool keep_order) { json::details::g_keep_json_object_unsorted = keep_order; } -utility::ostream_t& web::json::operator << (utility::ostream_t &os, const web::json::value &val) +utility::ostream_t& web::json::operator<<(utility::ostream_t& os, const web::json::value& val) { val.serialize(os); return os; } -utility::istream_t& web::json::operator >> (utility::istream_t &is, json::value &val) +utility::istream_t& web::json::operator>>(utility::istream_t& is, json::value& val) { val = json::value::parse(is); return is; } -web::json::value::value() : - m_value(utility::details::make_unique()) +web::json::value::value() + : m_value(utility::details::make_unique()) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(value::Null) + , m_kind(value::Null) #endif - { } +{ +} -web::json::value::value(int32_t value) : - m_value(utility::details::make_unique(value)) +web::json::value::value(int32_t value) + : m_value(utility::details::make_unique(value)) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(value::Number) + , m_kind(value::Number) #endif - { } +{ +} -web::json::value::value(uint32_t value) : - m_value(utility::details::make_unique(value)) +web::json::value::value(uint32_t value) + : m_value(utility::details::make_unique(value)) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(value::Number) + , m_kind(value::Number) #endif - { } +{ +} -web::json::value::value(int64_t value) : - m_value(utility::details::make_unique(value)) +web::json::value::value(int64_t value) + : m_value(utility::details::make_unique(value)) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(value::Number) + , m_kind(value::Number) #endif - { } +{ +} -web::json::value::value(uint64_t value) : - m_value(utility::details::make_unique(value)) +web::json::value::value(uint64_t value) + : m_value(utility::details::make_unique(value)) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(value::Number) + , m_kind(value::Number) #endif - { } +{ +} -web::json::value::value(double value) : - m_value(utility::details::make_unique(value)) +web::json::value::value(double value) + : m_value(utility::details::make_unique(value)) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(value::Number) + , m_kind(value::Number) #endif - { } +{ +} -web::json::value::value(bool value) : - m_value(utility::details::make_unique(value)) +web::json::value::value(bool value) + : m_value(utility::details::make_unique(value)) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(value::Boolean) + , m_kind(value::Boolean) #endif - { } +{ +} -web::json::value::value(utility::string_t value) : - m_value(utility::details::make_unique(std::move(value))) +web::json::value::value(utility::string_t value) + : m_value(utility::details::make_unique(std::move(value))) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(value::String) + , m_kind(value::String) #endif - { } +{ +} -web::json::value::value(utility::string_t value, bool has_escape_chars) : -m_value(utility::details::make_unique(std::move(value), has_escape_chars)) +web::json::value::value(utility::string_t value, bool has_escape_chars) + : m_value(utility::details::make_unique(std::move(value), has_escape_chars)) #ifdef ENABLE_JSON_VALUE_VISUALIZER -, m_kind(value::String) + , m_kind(value::String) #endif -{ } +{ +} -web::json::value::value(const utility::char_t* value) : - m_value(utility::details::make_unique(value)) +web::json::value::value(const utility::char_t* value) + : m_value(utility::details::make_unique(value)) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(value::String) + , m_kind(value::String) #endif - { } +{ +} -web::json::value::value(const utility::char_t* value, bool has_escape_chars) : -m_value(utility::details::make_unique(utility::string_t(value), has_escape_chars)) +web::json::value::value(const utility::char_t* value, bool has_escape_chars) + : m_value(utility::details::make_unique(utility::string_t(value), has_escape_chars)) #ifdef ENABLE_JSON_VALUE_VISUALIZER -, m_kind(value::String) + , m_kind(value::String) #endif -{ } +{ +} -web::json::value::value(const value &other) : - m_value(other.m_value->_copy_value()) +web::json::value::value(const value& other) + : m_value(other.m_value->_copy_value()) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(other.m_kind) + , m_kind(other.m_kind) #endif - { } +{ +} -web::json::value &web::json::value::operator=(const value &other) +web::json::value& web::json::value::operator=(const value& other) { - if(this != &other) + if (this != &other) { m_value = std::unique_ptr(other.m_value->_copy_value()); #ifdef ENABLE_JSON_VALUE_VISUALIZER @@ -129,16 +138,17 @@ web::json::value &web::json::value::operator=(const value &other) return *this; } -web::json::value::value(value &&other) CPPREST_NOEXCEPT : - m_value(std::move(other.m_value)) +web::json::value::value(value&& other) CPPREST_NOEXCEPT : m_value(std::move(other.m_value)) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,m_kind(other.m_kind) + , + m_kind(other.m_kind) #endif -{} +{ +} -web::json::value &web::json::value::operator=(web::json::value &&other) CPPREST_NOEXCEPT +web::json::value& web::json::value::operator=(web::json::value&& other) CPPREST_NOEXCEPT { - if(this != &other) + if (this != &other) { m_value.swap(other.m_value); #ifdef ENABLE_JSON_VALUE_VISUALIZER @@ -148,70 +158,54 @@ web::json::value &web::json::value::operator=(web::json::value &&other) CPPREST_ return *this; } -web::json::value web::json::value::null() -{ - return web::json::value(); -} +web::json::value web::json::value::null() { return web::json::value(); } -web::json::value web::json::value::number(double value) -{ - return web::json::value(value); -} +web::json::value web::json::value::number(double value) { return web::json::value(value); } -web::json::value web::json::value::number(int32_t value) -{ - return web::json::value(value); -} +web::json::value web::json::value::number(int32_t value) { return web::json::value(value); } -web::json::value web::json::value::number(uint32_t value) -{ - return web::json::value(value); -} +web::json::value web::json::value::number(uint32_t value) { return web::json::value(value); } -web::json::value web::json::value::number(int64_t value) -{ - return web::json::value(value); -} +web::json::value web::json::value::number(int64_t value) { return web::json::value(value); } -web::json::value web::json::value::number(uint64_t value) -{ - return web::json::value(value); -} +web::json::value web::json::value::number(uint64_t value) { return web::json::value(value); } -web::json::value web::json::value::boolean(bool value) -{ - return web::json::value(value); -} +web::json::value web::json::value::boolean(bool value) { return web::json::value(value); } web::json::value web::json::value::string(utility::string_t value) { std::unique_ptr ptr = utility::details::make_unique(std::move(value)); return web::json::value(std::move(ptr) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,value::String + , + value::String #endif - ); + ); } web::json::value web::json::value::string(utility::string_t value, bool has_escape_chars) { - std::unique_ptr ptr = utility::details::make_unique(std::move(value), has_escape_chars); + std::unique_ptr ptr = + utility::details::make_unique(std::move(value), has_escape_chars); return web::json::value(std::move(ptr) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,value::String + , + value::String #endif - ); + ); } #ifdef _WIN32 -web::json::value web::json::value::string(const std::string &value) +web::json::value web::json::value::string(const std::string& value) { - std::unique_ptr ptr = utility::details::make_unique(utility::conversions::to_utf16string(value)); + std::unique_ptr ptr = + utility::details::make_unique(utility::conversions::to_utf16string(value)); return web::json::value(std::move(ptr) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,value::String + , + value::String #endif - ); + ); } #endif @@ -220,19 +214,22 @@ web::json::value web::json::value::object(bool keep_order) std::unique_ptr ptr = utility::details::make_unique(keep_order); return web::json::value(std::move(ptr) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,value::Object + , + value::Object #endif - ); + ); } web::json::value web::json::value::object(std::vector> fields, bool keep_order) { - std::unique_ptr ptr = utility::details::make_unique(std::move(fields), keep_order); + std::unique_ptr ptr = + utility::details::make_unique(std::move(fields), keep_order); return web::json::value(std::move(ptr) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,value::Object + , + value::Object #endif - ); + ); } web::json::value web::json::value::array() @@ -240,9 +237,10 @@ web::json::value web::json::value::array() std::unique_ptr ptr = utility::details::make_unique(); return web::json::value(std::move(ptr) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,value::Array + , + value::Array #endif - ); + ); } web::json::value web::json::value::array(size_t size) @@ -250,9 +248,10 @@ web::json::value web::json::value::array(size_t size) std::unique_ptr ptr = utility::details::make_unique(size); return web::json::value(std::move(ptr) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,value::Array + , + value::Array #endif - ); + ); } web::json::value web::json::value::array(std::vector elements) @@ -260,60 +259,37 @@ web::json::value web::json::value::array(std::vector elements) std::unique_ptr ptr = utility::details::make_unique(std::move(elements)); return web::json::value(std::move(ptr) #ifdef ENABLE_JSON_VALUE_VISUALIZER - ,value::Array + , + value::Array #endif - ); + ); } -const web::json::number& web::json::value::as_number() const -{ - return m_value->as_number(); -} +const web::json::number& web::json::value::as_number() const { return m_value->as_number(); } -double web::json::value::as_double() const -{ - return m_value->as_double(); -} +double web::json::value::as_double() const { return m_value->as_double(); } -int web::json::value::as_integer() const -{ - return m_value->as_integer(); -} +int web::json::value::as_integer() const { return m_value->as_integer(); } -bool web::json::value::as_bool() const -{ - return m_value->as_bool(); -} +bool web::json::value::as_bool() const { return m_value->as_bool(); } -json::array& web::json::value::as_array() -{ - return m_value->as_array(); -} +json::array& web::json::value::as_array() { return m_value->as_array(); } -const json::array& web::json::value::as_array() const -{ - return m_value->as_array(); -} +const json::array& web::json::value::as_array() const { return m_value->as_array(); } -json::object& web::json::value::as_object() -{ - return m_value->as_object(); -} +json::object& web::json::value::as_object() { return m_value->as_object(); } -const json::object& web::json::value::as_object() const -{ - return m_value->as_object(); -} +const json::object& web::json::value::as_object() const { return m_value->as_object(); } bool web::json::number::is_int32() const { switch (m_type) { - case signed_type : return m_intval >= std::numeric_limits::min() && m_intval <= std::numeric_limits::max(); - case unsigned_type : return m_uintval <= std::numeric_limits::max(); - case double_type : - default : - return false; + case signed_type: + return m_intval >= std::numeric_limits::min() && m_intval <= std::numeric_limits::max(); + case unsigned_type: return m_uintval <= std::numeric_limits::max(); + case double_type: + default: return false; } } @@ -321,11 +297,10 @@ bool web::json::number::is_uint32() const { switch (m_type) { - case signed_type : return m_intval >= 0 && m_intval <= std::numeric_limits::max(); - case unsigned_type : return m_uintval <= std::numeric_limits::max(); - case double_type : - default : - return false; + case signed_type: return m_intval >= 0 && m_intval <= std::numeric_limits::max(); + case unsigned_type: return m_uintval <= std::numeric_limits::max(); + case double_type: + default: return false; } } @@ -333,21 +308,28 @@ bool web::json::number::is_int64() const { switch (m_type) { - case signed_type : return true; - case unsigned_type : return m_uintval <= static_cast(std::numeric_limits::max()); - case double_type : - default : - return false; + case signed_type: return true; + case unsigned_type: return m_uintval <= static_cast(std::numeric_limits::max()); + case double_type: + default: return false; } } -bool web::json::details::_String::has_escape_chars(const _String &str) -{ - return std::any_of(std::begin(str.m_string), std::end(str.m_string), [](utility::string_t::value_type const x) - { - if (x <= 31) { return true; } - if (x == '"') { return true; } - if (x == '\\') { return true; } +bool web::json::details::_String::has_escape_chars(const _String& str) +{ + return std::any_of(std::begin(str.m_string), std::end(str.m_string), [](utility::string_t::value_type const x) { + if (x <= 31) + { + return true; + } + if (x == '"') + { + return true; + } + if (x == '\\') + { + return true; + } return false; }); } @@ -356,7 +338,7 @@ web::json::value::value_type json::value::type() const { return m_value->type(); bool json::value::is_integer() const { - if(!is_number()) + if (!is_number()) { return false; } @@ -365,56 +347,53 @@ bool json::value::is_integer() const bool json::value::is_double() const { - if(!is_number()) + if (!is_number()) { return false; } return m_value->is_double(); } -json::value& web::json::details::_Object::index(const utility::string_t &key) -{ - return m_object[key]; -} +json::value& web::json::details::_Object::index(const utility::string_t& key) { return m_object[key]; } -bool web::json::details::_Object::has_field(const utility::string_t &key) const +bool web::json::details::_Object::has_field(const utility::string_t& key) const { return m_object.find(key) != m_object.end(); } -bool web::json::value::has_number_field(const utility::string_t &key) const +bool web::json::value::has_number_field(const utility::string_t& key) const { - return has_field(key) && at(key).is_number(); + return has_field(key) && at(key).is_number(); } -bool web::json::value::has_integer_field(const utility::string_t &key) const +bool web::json::value::has_integer_field(const utility::string_t& key) const { - return has_field(key) && at(key).is_integer(); + return has_field(key) && at(key).is_integer(); } -bool web::json::value::has_double_field(const utility::string_t &key) const +bool web::json::value::has_double_field(const utility::string_t& key) const { - return has_field(key) && at(key).is_double(); + return has_field(key) && at(key).is_double(); } -bool web::json::value::has_boolean_field(const utility::string_t &key) const +bool web::json::value::has_boolean_field(const utility::string_t& key) const { - return has_field(key) && at(key).is_boolean(); + return has_field(key) && at(key).is_boolean(); } -bool web::json::value::has_string_field(const utility::string_t &key) const +bool web::json::value::has_string_field(const utility::string_t& key) const { - return has_field(key) && at(key).is_string(); + return has_field(key) && at(key).is_string(); } -bool web::json::value::has_array_field(const utility::string_t &key) const +bool web::json::value::has_array_field(const utility::string_t& key) const { - return has_field(key) && at(key).is_array(); + return has_field(key) && at(key).is_array(); } -bool web::json::value::has_object_field(const utility::string_t &key) const +bool web::json::value::has_object_field(const utility::string_t& key) const { - return has_field(key) && at(key).is_object(); + return has_field(key) && at(key).is_object(); } utility::string_t json::value::to_string() const @@ -425,65 +404,43 @@ utility::string_t json::value::to_string() const return m_value->to_string(); } -bool json::value::operator==(const json::value &other) const +bool json::value::operator==(const json::value& other) const { - if (this->m_value.get() == other.m_value.get()) - return true; - if (this->type() != other.type()) - return false; + if (this->m_value.get() == other.m_value.get()) return true; + if (this->type() != other.type()) return false; - switch(this->type()) + switch (this->type()) { - case Null: - return true; - case Number: - return this->as_number() == other.as_number(); - case Boolean: - return this->as_bool() == other.as_bool(); - case String: - return this->as_string() == other.as_string(); - case Object: - return static_cast(this->m_value.get())->is_equal(static_cast(other.m_value.get())); - case Array: - return static_cast(this->m_value.get())->is_equal(static_cast(other.m_value.get())); + case Null: return true; + case Number: return this->as_number() == other.as_number(); + case Boolean: return this->as_bool() == other.as_bool(); + case String: return this->as_string() == other.as_string(); + case Object: + return static_cast(this->m_value.get()) + ->is_equal(static_cast(other.m_value.get())); + case Array: + return static_cast(this->m_value.get()) + ->is_equal(static_cast(other.m_value.get())); } __assume(0); } -void web::json::value::erase(size_t index) -{ - return this->as_array().erase(index); -} +void web::json::value::erase(size_t index) { return this->as_array().erase(index); } -void web::json::value::erase(const utility::string_t &key) -{ - return this->as_object().erase(key); -} +void web::json::value::erase(const utility::string_t& key) { return this->as_object().erase(key); } // at() overloads -web::json::value& web::json::value::at(size_t index) -{ - return this->as_array().at(index); -} +web::json::value& web::json::value::at(size_t index) { return this->as_array().at(index); } -const web::json::value& web::json::value::at(size_t index) const -{ - return this->as_array().at(index); -} +const web::json::value& web::json::value::at(size_t index) const { return this->as_array().at(index); } -web::json::value& web::json::value::at(const utility::string_t& key) -{ - return this->as_object().at(key); -} +web::json::value& web::json::value::at(const utility::string_t& key) { return this->as_object().at(key); } -const web::json::value& web::json::value::at(const utility::string_t& key) const -{ - return this->as_object().at(key); -} +const web::json::value& web::json::value::at(const utility::string_t& key) const { return this->as_object().at(key); } -web::json::value& web::json::value::operator [] (const utility::string_t &key) +web::json::value& web::json::value::operator[](const utility::string_t& key) { - if ( this->is_null() ) + if (this->is_null()) { m_value.reset(new web::json::details::_Object(details::g_keep_json_object_unsorted)); #ifdef ENABLE_JSON_VALUE_VISUALIZER @@ -495,7 +452,7 @@ web::json::value& web::json::value::operator [] (const utility::string_t &key) web::json::value& web::json::value::operator[](size_t index) { - if ( this->is_null() ) + if (this->is_null()) { m_value.reset(new web::json::details::_Array()); #ifdef ENABLE_JSON_VALUE_VISUALIZER diff --git a/Release/src/json/json_parsing.cpp b/Release/src/json/json_parsing.cpp index ffa631aac1..6de65381f1 100644 --- a/Release/src/json/json_parsing.cpp +++ b/Release/src/json/json_parsing.cpp @@ -1,17 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: JSON parser -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: JSON parser + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include #if defined(_MSC_VER) @@ -22,32 +23,30 @@ using namespace web::json; using namespace utility; using namespace utility::conversions; -std::array _hexval = {{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }}; +std::array _hexval = { + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}; -namespace web { +namespace web +{ namespace json { namespace details { - // // JSON Parsing // -template +template #if defined(_WIN32) - __declspec(noreturn) +__declspec(noreturn) #else __attribute__((noreturn)) #endif -void CreateException(const Token &tk, const utility::string_t &message) + void CreateException(const Token& tk, const utility::string_t& message) { std::string str("* Line "); str += std::to_string(tk.start.m_line); @@ -58,21 +57,17 @@ void CreateException(const Token &tk, const utility::string_t &message) throw web::json::json_exception(std::move(str)); } -template -void SetErrorCode(Token &tk, json_error jsonErrorCode) +template +void SetErrorCode(Token& tk, json_error jsonErrorCode) { tk.m_error = std::error_code(jsonErrorCode, json_error_category()); } -template +template class JSON_Parser { public: - JSON_Parser() - : m_currentLine(1), - m_currentColumn(1), - m_currentParsingDepth(0) - { } + JSON_Parser() : m_currentLine(1), m_currentColumn(1), m_currentParsingDepth(0) {} struct Location { @@ -107,8 +102,7 @@ class JSON_Parser typename JSON_Parser::Location start; - union - { + union { double double_val; int64_t int64_val; uint64_t uint64_val; @@ -121,9 +115,9 @@ class JSON_Parser std::error_code m_error; }; - void GetNextToken(Token &); + void GetNextToken(Token&); - web::json::value ParseValue(typename JSON_Parser::Token &first) + web::json::value ParseValue(typename JSON_Parser::Token& first) { #ifndef _WIN32 utility::details::scoped_c_thread_locale locale; @@ -143,26 +137,25 @@ class JSON_Parser virtual int_type NextCharacter() = 0; virtual int_type PeekCharacter() = 0; - virtual bool CompleteComment(Token &token); - virtual bool CompleteStringLiteral(Token &token); - bool handle_unescape_char(Token &token); + virtual bool CompleteComment(Token& token); + virtual bool CompleteStringLiteral(Token& token); + bool handle_unescape_char(Token& token); private: - - bool CompleteNumberLiteral(CharType first, Token &token); + bool CompleteNumberLiteral(CharType first, Token& token); bool ParseInt64(CharType first, uint64_t& value); - bool CompleteKeywordTrue(Token &token); - bool CompleteKeywordFalse(Token &token); - bool CompleteKeywordNull(Token &token); - std::unique_ptr _ParseValue(typename JSON_Parser::Token &first); - std::unique_ptr _ParseObject(typename JSON_Parser::Token &tkn); - std::unique_ptr _ParseArray(typename JSON_Parser::Token &tkn); + bool CompleteKeywordTrue(Token& token); + bool CompleteKeywordFalse(Token& token); + bool CompleteKeywordNull(Token& token); + std::unique_ptr _ParseValue(typename JSON_Parser::Token& first); + std::unique_ptr _ParseObject(typename JSON_Parser::Token& tkn); + std::unique_ptr _ParseArray(typename JSON_Parser::Token& tkn); JSON_Parser& operator=(const JSON_Parser&); int_type EatWhitespace(); - void CreateToken(typename JSON_Parser::Token& tk, typename Token::Kind kind, Location &start) + void CreateToken(typename JSON_Parser::Token& tk, typename Token::Kind kind, Location& start) { tk.kind = kind; tk.start = start; @@ -178,7 +171,6 @@ class JSON_Parser } protected: - size_t m_currentLine; size_t m_currentColumn; size_t m_currentParsingDepth; @@ -194,23 +186,19 @@ class JSON_Parser }; // Replace with template alias once VS 2012 support is removed. -template +template typename std::char_traits::int_type eof() { return std::char_traits::eof(); } -template +template class JSON_StreamParser : public JSON_Parser - { +{ public: - JSON_StreamParser(std::basic_istream &stream) - : m_streambuf(stream.rdbuf()) - { - } + JSON_StreamParser(std::basic_istream& stream) : m_streambuf(stream.rdbuf()) {} protected: - virtual typename JSON_Parser::int_type NextCharacter(); virtual typename JSON_Parser::int_type PeekCharacter(); @@ -218,34 +206,31 @@ class JSON_StreamParser : public JSON_Parser typename std::basic_streambuf>* m_streambuf; }; -template +template class JSON_StringParser : public JSON_Parser { public: - JSON_StringParser(const std::basic_string& string) - : m_position(&string[0]) + JSON_StringParser(const std::basic_string& string) : m_position(&string[0]) { m_startpos = m_position; - m_endpos = m_position+string.size(); + m_endpos = m_position + string.size(); } protected: - virtual typename JSON_Parser::int_type NextCharacter(); virtual typename JSON_Parser::int_type PeekCharacter(); - virtual bool CompleteComment(typename JSON_Parser::Token &token); - virtual bool CompleteStringLiteral(typename JSON_Parser::Token &token); + virtual bool CompleteComment(typename JSON_Parser::Token& token); + virtual bool CompleteStringLiteral(typename JSON_Parser::Token& token); private: - bool finish_parsing_string_with_unescape_char(typename JSON_Parser::Token &token); + bool finish_parsing_string_with_unescape_char(typename JSON_Parser::Token& token); const CharType* m_position; const CharType* m_startpos; const CharType* m_endpos; }; - -template +template typename JSON_Parser::int_type JSON_StreamParser::NextCharacter() { auto ch = m_streambuf->sbumpc(); @@ -263,22 +248,21 @@ typename JSON_Parser::int_type JSON_StreamParser::NextCharac return ch; } -template +template typename JSON_Parser::int_type JSON_StreamParser::PeekCharacter() { return m_streambuf->sgetc(); } -template +template typename JSON_Parser::int_type JSON_StringParser::NextCharacter() { - if (m_position == m_endpos) - return eof(); + if (m_position == m_endpos) return eof(); CharType ch = *m_position; m_position += 1; - if ( ch == '\n' ) + if (ch == '\n') { this->m_currentLine += 1; this->m_currentColumn = 0; @@ -291,10 +275,10 @@ typename JSON_Parser::int_type JSON_StringParser::NextCharac return ch; } -template +template typename JSON_Parser::int_type JSON_StringParser::PeekCharacter() { - if ( m_position == m_endpos ) return eof(); + if (m_position == m_endpos) return eof(); return *m_position; } @@ -302,64 +286,54 @@ typename JSON_Parser::int_type JSON_StringParser::PeekCharac // // Consume whitespace characters and return the first non-space character or EOF // -template +template typename JSON_Parser::int_type JSON_Parser::EatWhitespace() { - auto ch = NextCharacter(); + auto ch = NextCharacter(); - while ( ch != eof() && iswspace(static_cast(ch))) - { - ch = NextCharacter(); - } + while (ch != eof() && iswspace(static_cast(ch))) + { + ch = NextCharacter(); + } - return ch; + return ch; } -template -bool JSON_Parser::CompleteKeywordTrue(Token &token) +template +bool JSON_Parser::CompleteKeywordTrue(Token& token) { - if (NextCharacter() != 'r') - return false; - if (NextCharacter() != 'u') - return false; - if (NextCharacter() != 'e') - return false; + if (NextCharacter() != 'r') return false; + if (NextCharacter() != 'u') return false; + if (NextCharacter() != 'e') return false; token.kind = Token::TKN_BooleanLiteral; token.boolean_val = true; return true; } -template -bool JSON_Parser::CompleteKeywordFalse(Token &token) +template +bool JSON_Parser::CompleteKeywordFalse(Token& token) { - if (NextCharacter() != 'a') - return false; - if (NextCharacter() != 'l') - return false; - if (NextCharacter() != 's') - return false; - if (NextCharacter() != 'e') - return false; + if (NextCharacter() != 'a') return false; + if (NextCharacter() != 'l') return false; + if (NextCharacter() != 's') return false; + if (NextCharacter() != 'e') return false; token.kind = Token::TKN_BooleanLiteral; token.boolean_val = false; return true; } -template -bool JSON_Parser::CompleteKeywordNull(Token &token) +template +bool JSON_Parser::CompleteKeywordNull(Token& token) { - if (NextCharacter() != 'u') - return false; - if (NextCharacter() != 'l') - return false; - if (NextCharacter() != 'l') - return false; + if (NextCharacter() != 'u') return false; + if (NextCharacter() != 'l') return false; + if (NextCharacter() != 'l') return false; token.kind = Token::TKN_NullLiteral; return true; } // Returns false only on overflow -template +template inline bool JSON_Parser::ParseInt64(CharType first, uint64_t& value) { value = first - '0'; @@ -367,8 +341,7 @@ inline bool JSON_Parser::ParseInt64(CharType first, uint64_t& value) while (ch >= '0' && ch <= '9') { unsigned int next_digit = (unsigned int)(ch - '0'); - if (value > (ULLONG_MAX / 10) || (value == ULLONG_MAX/10 && next_digit > ULLONG_MAX%10)) - return false; + if (value > (ULLONG_MAX / 10) || (value == ULLONG_MAX / 10 && next_digit > ULLONG_MAX % 10)) return false; NextCharacter(); @@ -383,45 +356,39 @@ inline bool JSON_Parser::ParseInt64(CharType first, uint64_t& value) namespace { #if defined(_WIN32) - static int print_llu(char* ptr, size_t n, uint64_t val64) - { - return _snprintf_s_l(ptr, n, _TRUNCATE, "%I64u", utility::details::scoped_c_thread_locale::c_locale(), val64); - } +static int print_llu(char* ptr, size_t n, uint64_t val64) +{ + return _snprintf_s_l(ptr, n, _TRUNCATE, "%I64u", utility::details::scoped_c_thread_locale::c_locale(), val64); +} - static int print_llu(wchar_t* ptr, size_t n, uint64_t val64) - { - return _snwprintf_s_l(ptr, n, _TRUNCATE, L"%I64u", utility::details::scoped_c_thread_locale::c_locale(), val64); - } - static double anystod(const char* str) - { - return _strtod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale()); - } - static double anystod(const wchar_t* str) - { - return _wcstod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale()); - } +static int print_llu(wchar_t* ptr, size_t n, uint64_t val64) +{ + return _snwprintf_s_l(ptr, n, _TRUNCATE, L"%I64u", utility::details::scoped_c_thread_locale::c_locale(), val64); +} +static double anystod(const char* str) +{ + return _strtod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale()); +} +static double anystod(const wchar_t* str) +{ + return _wcstod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale()); +} #else - static int __attribute__((__unused__)) print_llu(char* ptr, size_t n, unsigned long long val64) - { - return snprintf(ptr, n, "%llu", val64); - } - static int __attribute__((__unused__)) print_llu(char* ptr, size_t n, unsigned long val64) - { - return snprintf(ptr, n, "%lu", val64); - } - static double __attribute__((__unused__)) anystod(const char* str) - { - return strtod(str, nullptr); - } - static double __attribute__((__unused__)) anystod(const wchar_t* str) - { - return wcstod(str, nullptr); - } -#endif +static int __attribute__((__unused__)) print_llu(char* ptr, size_t n, unsigned long long val64) +{ + return snprintf(ptr, n, "%llu", val64); +} +static int __attribute__((__unused__)) print_llu(char* ptr, size_t n, unsigned long val64) +{ + return snprintf(ptr, n, "%lu", val64); } +static double __attribute__((__unused__)) anystod(const char* str) { return strtod(str, nullptr); } +static double __attribute__((__unused__)) anystod(const wchar_t* str) { return wcstod(str, nullptr); } +#endif +} // namespace -template -bool JSON_Parser::CompleteNumberLiteral(CharType first, Token &token) +template +bool JSON_Parser::CompleteNumberLiteral(CharType first, Token& token) { bool minus_sign; @@ -437,25 +404,23 @@ bool JSON_Parser::CompleteNumberLiteral(CharType first, Token &token) minus_sign = false; } - if (first < '0' || first > '9') - return false; + if (first < '0' || first > '9') return false; auto ch = PeekCharacter(); - //Check for two (or more) zeros at the beginning - if (first == '0' && ch == '0') - return false; + // Check for two (or more) zeros at the beginning + if (first == '0' && ch == '0') return false; // Parse the number assuming its integer uint64_t val64; bool complete = ParseInt64(first, val64); ch = PeekCharacter(); - if (complete && ch!='.' && ch!='E' && ch!='e') + if (complete && ch != '.' && ch != 'E' && ch != 'e') { if (minus_sign) { - if (val64 > static_cast(1) << 63 ) + if (val64 > static_cast(1) << 63) { // It is negative and cannot be represented in int64, so we resort to double token.double_val = 0 - static_cast(val64); @@ -501,8 +466,7 @@ bool JSON_Parser::CompleteNumberLiteral(CharType first, Token &token) // Decimal dot? else if (ch == '.') { - if (decimal) - return false; + if (decimal) return false; decimal = true; buf.push_back(static_cast(ch)); @@ -511,8 +475,7 @@ bool JSON_Parser::CompleteNumberLiteral(CharType first, Token &token) ch = PeekCharacter(); // Check that the following char is a digit - if (ch < '0' || ch > '9') - return false; + if (ch < '0' || ch > '9') return false; buf.push_back(static_cast(ch)); NextCharacter(); @@ -547,7 +510,8 @@ bool JSON_Parser::CompleteNumberLiteral(CharType first, Token &token) NextCharacter(); ch = PeekCharacter(); } - else return false; + else + return false; // The rest of the exponent while (ch >= '0' && ch <= '9') @@ -578,23 +542,22 @@ bool JSON_Parser::CompleteNumberLiteral(CharType first, Token &token) return true; } -template -bool JSON_Parser::CompleteComment(Token &token) +template +bool JSON_Parser::CompleteComment(Token& token) { // We already found a '/' character as the first of a token -- what kind of comment is it? auto ch = NextCharacter(); - if ( ch == eof() || (ch != '/' && ch != '*') ) - return false; + if (ch == eof() || (ch != '/' && ch != '*')) return false; - if ( ch == '/' ) + if (ch == '/') { // Line comment -- look for a newline or EOF to terminate. ch = NextCharacter(); - while ( ch != eof() && ch != '\n') + while (ch != eof() && ch != '\n') { ch = NextCharacter(); } @@ -605,19 +568,17 @@ bool JSON_Parser::CompleteComment(Token &token) ch = NextCharacter(); - while ( true ) + while (true) { - if ( ch == eof()) - return false; + if (ch == eof()) return false; - if ( ch == '*' ) + if (ch == '*') { auto ch1 = PeekCharacter(); - if ( ch1 == eof()) - return false; + if (ch1 == eof()) return false; - if ( ch1 == '/' ) + if (ch1 == '/') { // Consume the character NextCharacter(); @@ -636,8 +597,8 @@ bool JSON_Parser::CompleteComment(Token &token) return true; } -template -bool JSON_StringParser::CompleteComment(typename JSON_Parser::Token &token) +template +bool JSON_StringParser::CompleteComment(typename JSON_Parser::Token& token) { // This function is specialized for the string parser, since we can be slightly more // efficient in copying data from the input to the token: do a memcpy() rather than @@ -645,16 +606,15 @@ bool JSON_StringParser::CompleteComment(typename JSON_Parser auto ch = JSON_StringParser::NextCharacter(); - if ( ch == eof() || (ch != '/' && ch != '*') ) - return false; + if (ch == eof() || (ch != '/' && ch != '*')) return false; - if ( ch == '/' ) + if (ch == '/') { // Line comment -- look for a newline or EOF to terminate. ch = JSON_StringParser::NextCharacter(); - while ( ch != eof() && ch != '\n') + while (ch != eof() && ch != '\n') { ch = JSON_StringParser::NextCharacter(); } @@ -665,25 +625,22 @@ bool JSON_StringParser::CompleteComment(typename JSON_Parser ch = JSON_StringParser::NextCharacter(); - while ( true ) + while (true) { - if ( ch == eof()) - return false; + if (ch == eof()) return false; - if ( ch == '*' ) + if (ch == '*') { ch = JSON_StringParser::PeekCharacter(); - if ( ch == eof()) - return false; + if (ch == eof()) return false; - if ( ch == '/' ) + if (ch == '/') { // Consume the character JSON_StringParser::NextCharacter(); break; } - } ch = JSON_StringParser::NextCharacter(); @@ -695,50 +652,34 @@ bool JSON_StringParser::CompleteComment(typename JSON_Parser return true; } -void convert_append_unicode_code_unit(JSON_Parser::Token &token, utf16char value) +void convert_append_unicode_code_unit(JSON_Parser::Token& token, utf16char value) { token.string_val.push_back(value); } -void convert_append_unicode_code_unit(JSON_Parser::Token &token, utf16char value) +void convert_append_unicode_code_unit(JSON_Parser::Token& token, utf16char value) { - utf16string utf16(reinterpret_cast(&value), 1); + utf16string utf16(reinterpret_cast(&value), 1); token.string_val.append(::utility::conversions::utf16_to_utf8(utf16)); } -template -inline bool JSON_Parser::handle_unescape_char(Token &token) +template +inline bool JSON_Parser::handle_unescape_char(Token& token) { token.has_unescape_symbol = true; - // This function converts unescaped character pairs (e.g. "\t") into their ASCII or Unicode representations (e.g. tab sign) - // Also it handles \u + 4 hexadecimal digits + // This function converts unescaped character pairs (e.g. "\t") into their ASCII or Unicode representations (e.g. + // tab sign) Also it handles \u + 4 hexadecimal digits auto ch = NextCharacter(); switch (ch) { - case '\"': - token.string_val.push_back('\"'); - return true; - case '\\': - token.string_val.push_back('\\'); - return true; - case '/': - token.string_val.push_back('/'); - return true; - case 'b': - token.string_val.push_back('\b'); - return true; - case 'f': - token.string_val.push_back('\f'); - return true; - case 'r': - token.string_val.push_back('\r'); - return true; - case 'n': - token.string_val.push_back('\n'); - return true; - case 't': - token.string_val.push_back('\t'); - return true; + case '\"': token.string_val.push_back('\"'); return true; + case '\\': token.string_val.push_back('\\'); return true; + case '/': token.string_val.push_back('/'); return true; + case 'b': token.string_val.push_back('\b'); return true; + case 'f': token.string_val.push_back('\f'); return true; + case 'r': token.string_val.push_back('\r'); return true; + case 'n': token.string_val.push_back('\n'); return true; + case 't': token.string_val.push_back('\t'); return true; case 'u': { // A four-hexdigit Unicode character. @@ -748,15 +689,13 @@ inline bool JSON_Parser::handle_unescape_char(Token &token) { ch = NextCharacter(); int ch_int = static_cast(ch); - if (ch_int < 0 || ch_int > 127) - return false; + if (ch_int < 0 || ch_int > 127) return false; #ifdef _WIN32 const int isxdigitResult = _isxdigit_l(ch_int, utility::details::scoped_c_thread_locale::c_locale()); #else const int isxdigitResult = isxdigit(ch_int); #endif - if (!isxdigitResult) - return false; + if (!isxdigitResult) return false; int val = _hexval[static_cast(ch_int)]; _ASSERTE(val != -1); @@ -766,23 +705,22 @@ inline bool JSON_Parser::handle_unescape_char(Token &token) } // Construct the character based on the decoded number - convert_append_unicode_code_unit(token, static_cast(decoded)); + convert_append_unicode_code_unit(token, static_cast(decoded)); return true; } - default: - return false; + default: return false; } } -template -bool JSON_Parser::CompleteStringLiteral(Token &token) +template +bool JSON_Parser::CompleteStringLiteral(Token& token) { token.has_unescape_symbol = false; auto ch = NextCharacter(); - while ( ch != '"' ) + while (ch != '"') { - if ( ch == '\\' ) + if (ch == '\\') { handle_unescape_char(token); } @@ -792,15 +730,14 @@ bool JSON_Parser::CompleteStringLiteral(Token &token) } else { - if (ch == eof()) - return false; + if (ch == eof()) return false; token.string_val.push_back(static_cast(ch)); } ch = NextCharacter(); } - if ( ch == '"' ) + if (ch == '"') { token.kind = Token::TKN_StringLiteral; } @@ -812,8 +749,8 @@ bool JSON_Parser::CompleteStringLiteral(Token &token) return true; } -template -bool JSON_StringParser::CompleteStringLiteral(typename JSON_Parser::Token &token) +template +bool JSON_StringParser::CompleteStringLiteral(typename JSON_Parser::Token& token) { // This function is specialized for the string parser, since we can be slightly more // efficient in copying data from the input to the token: do a memcpy() rather than @@ -826,15 +763,14 @@ bool JSON_StringParser::CompleteStringLiteral(typename JSON_Parser()) - return false; + if (ch == eof()) return false; if (ch == '\\') { const size_t numChars = m_position - start - 1; const size_t prevSize = token.string_val.size(); token.string_val.resize(prevSize + numChars); - memcpy(const_cast(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); + memcpy(const_cast(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); if (!JSON_StringParser::handle_unescape_char(token)) { @@ -855,14 +791,14 @@ bool JSON_StringParser::CompleteStringLiteral(typename JSON_Parser(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); + memcpy(const_cast(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); token.kind = JSON_Parser::Token::TKN_StringLiteral; return true; } -template +template void JSON_Parser::GetNextToken(typename JSON_Parser::Token& result) { try_again: @@ -874,10 +810,10 @@ void JSON_Parser::GetNextToken(typename JSON_Parser::Token& switch (ch) { - case '{': - case '[': + case '{': + case '[': { - if(++m_currentParsingDepth > JSON_Parser::maxParsingDepth) + if (++m_currentParsingDepth > JSON_Parser::maxParsingDepth) { SetErrorCode(result, json_error::nesting); break; @@ -887,84 +823,80 @@ void JSON_Parser::GetNextToken(typename JSON_Parser::Token& CreateToken(result, tk, result.start); break; } - case '}': - case ']': + case '}': + case ']': { - if((signed int)(--m_currentParsingDepth) < 0) + if ((signed int)(--m_currentParsingDepth) < 0) { SetErrorCode(result, json_error::mismatched_brances); break; } - typename JSON_Parser::Token::Kind tk = ch == '}' ? Token::TKN_CloseBrace : Token::TKN_CloseBracket; + typename JSON_Parser::Token::Kind tk = + ch == '}' ? Token::TKN_CloseBrace : Token::TKN_CloseBracket; CreateToken(result, tk, result.start); break; } - case ',': - CreateToken(result, Token::TKN_Comma, result.start); - break; + case ',': CreateToken(result, Token::TKN_Comma, result.start); break; - case ':': - CreateToken(result, Token::TKN_Colon, result.start); - break; + case ':': CreateToken(result, Token::TKN_Colon, result.start); break; - case 't': - if (!CompleteKeywordTrue(result)) - { - SetErrorCode(result, json_error::malformed_literal); - } - break; - case 'f': - if (!CompleteKeywordFalse(result)) - { - SetErrorCode(result, json_error::malformed_literal); - } - break; - case 'n': - if (!CompleteKeywordNull(result)) - { - SetErrorCode(result, json_error::malformed_literal); - } - break; - case '/': - if (!CompleteComment(result)) - { - SetErrorCode(result, json_error::malformed_comment); + case 't': + if (!CompleteKeywordTrue(result)) + { + SetErrorCode(result, json_error::malformed_literal); + } break; - } - // For now, we're ignoring comments. - goto try_again; - case '"': - if (!CompleteStringLiteral(result)) - { - SetErrorCode(result, json_error::malformed_string_literal); - } - break; - - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (!CompleteNumberLiteral(static_cast(ch), result)) - { - SetErrorCode(result, json_error::malformed_numeric_literal); - } - break; - default: - SetErrorCode(result, json_error::malformed_token); - break; + case 'f': + if (!CompleteKeywordFalse(result)) + { + SetErrorCode(result, json_error::malformed_literal); + } + break; + case 'n': + if (!CompleteKeywordNull(result)) + { + SetErrorCode(result, json_error::malformed_literal); + } + break; + case '/': + if (!CompleteComment(result)) + { + SetErrorCode(result, json_error::malformed_comment); + break; + } + // For now, we're ignoring comments. + goto try_again; + case '"': + if (!CompleteStringLiteral(result)) + { + SetErrorCode(result, json_error::malformed_string_literal); + } + break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (!CompleteNumberLiteral(static_cast(ch), result)) + { + SetErrorCode(result, json_error::malformed_numeric_literal); + } + break; + default: SetErrorCode(result, json_error::malformed_token); break; } } -template -std::unique_ptr JSON_Parser::_ParseObject(typename JSON_Parser::Token &tkn) +template +std::unique_ptr JSON_Parser::_ParseObject( + typename JSON_Parser::Token& tkn) { auto obj = utility::details::make_unique(g_keep_json_object_unsorted); auto& elems = obj->m_object.m_elements; @@ -980,11 +912,8 @@ std::unique_ptr JSON_Parser::_ParseObject( std::basic_string fieldName; switch (tkn.kind) { - case JSON_Parser::Token::TKN_StringLiteral: - fieldName = std::move(tkn.string_val); - break; - default: - goto error; + case JSON_Parser::Token::TKN_StringLiteral: fieldName = std::move(tkn.string_val); break; + default: goto error; } GetNextToken(tkn); @@ -996,11 +925,12 @@ std::unique_ptr JSON_Parser::_ParseObject( GetNextToken(tkn); if (tkn.m_error) goto error; - // State 3: Looking for an expression. + // State 3: Looking for an expression. #ifdef ENABLE_JSON_VALUE_VISUALIZER auto fieldValue = _ParseValue(tkn); auto type = fieldValue->type(); - elems.emplace_back(utility::conversions::to_string_t(std::move(fieldName)), json::value(std::move(fieldValue), type)); + elems.emplace_back(utility::conversions::to_string_t(std::move(fieldName)), + json::value(std::move(fieldValue), type)); #else elems.emplace_back(utility::conversions::to_string_t(std::move(fieldName)), json::value(_ParseValue(tkn))); #endif @@ -1009,14 +939,12 @@ std::unique_ptr JSON_Parser::_ParseObject( // State 4: Looking for a comma or a closing brace switch (tkn.kind) { - case JSON_Parser::Token::TKN_Comma: - GetNextToken(tkn); - if (tkn.m_error) goto error; - break; - case JSON_Parser::Token::TKN_CloseBrace: - goto done; - default: - goto error; + case JSON_Parser::Token::TKN_Comma: + GetNextToken(tkn); + if (tkn.m_error) goto error; + break; + case JSON_Parser::Token::TKN_CloseBrace: goto done; + default: goto error; } } } @@ -1025,7 +953,8 @@ std::unique_ptr JSON_Parser::_ParseObject( GetNextToken(tkn); if (tkn.m_error) return utility::details::make_unique(); - if (!g_keep_json_object_unsorted) { + if (!g_keep_json_object_unsorted) + { ::std::sort(elems.begin(), elems.end(), json::object::compare_pairs); } @@ -1039,8 +968,9 @@ std::unique_ptr JSON_Parser::_ParseObject( return utility::details::make_unique(); } -template -std::unique_ptr JSON_Parser::_ParseArray(typename JSON_Parser::Token &tkn) +template +std::unique_ptr JSON_Parser::_ParseArray( + typename JSON_Parser::Token& tkn) { GetNextToken(tkn); if (tkn.m_error) return utility::details::make_unique(); @@ -1058,17 +988,17 @@ std::unique_ptr JSON_Parser::_ParseArray(t // State 4: Looking for a comma or a closing bracket switch (tkn.kind) { - case JSON_Parser::Token::TKN_Comma: - GetNextToken(tkn); - if (tkn.m_error) return utility::details::make_unique(); - break; - case JSON_Parser::Token::TKN_CloseBracket: - GetNextToken(tkn); - if (tkn.m_error) return utility::details::make_unique(); - return std::move(result); - default: - SetErrorCode(tkn, json_error::malformed_array_literal); - return utility::details::make_unique(); + case JSON_Parser::Token::TKN_Comma: + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + break; + case JSON_Parser::Token::TKN_CloseBracket: + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(result); + default: + SetErrorCode(tkn, json_error::malformed_array_literal); + return utility::details::make_unique(); } } } @@ -1079,69 +1009,69 @@ std::unique_ptr JSON_Parser::_ParseArray(t return std::unique_ptr(result.release()); } -template -std::unique_ptr JSON_Parser::_ParseValue(typename JSON_Parser::Token &tkn) +template +std::unique_ptr JSON_Parser::_ParseValue( + typename JSON_Parser::Token& tkn) { switch (tkn.kind) { - case JSON_Parser::Token::TKN_OpenBrace: - { - return _ParseObject(tkn); - } - case JSON_Parser::Token::TKN_OpenBracket: - { - return _ParseArray(tkn); - } + case JSON_Parser::Token::TKN_OpenBrace: { return _ParseObject(tkn); + } + case JSON_Parser::Token::TKN_OpenBracket: { return _ParseArray(tkn); + } case JSON_Parser::Token::TKN_StringLiteral: - { - auto value = utility::details::make_unique(std::move(tkn.string_val), tkn.has_unescape_symbol); - GetNextToken(tkn); - if (tkn.m_error) return utility::details::make_unique(); - return std::move(value); - } + { + auto value = utility::details::make_unique(std::move(tkn.string_val), + tkn.has_unescape_symbol); + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(value); + } case JSON_Parser::Token::TKN_IntegerLiteral: - { - std::unique_ptr value; - if (tkn.signed_number) - value = utility::details::make_unique(tkn.int64_val); - else - value = utility::details::make_unique(tkn.uint64_val); - - GetNextToken(tkn); - if (tkn.m_error) return utility::details::make_unique(); - return std::move(value); - } + { + std::unique_ptr value; + if (tkn.signed_number) + value = utility::details::make_unique(tkn.int64_val); + else + value = utility::details::make_unique(tkn.uint64_val); + + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(value); + } case JSON_Parser::Token::TKN_NumberLiteral: - { - auto value = utility::details::make_unique(tkn.double_val); - GetNextToken(tkn); - if (tkn.m_error) return utility::details::make_unique(); - return std::move(value); - } + { + auto value = utility::details::make_unique(tkn.double_val); + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(value); + } case JSON_Parser::Token::TKN_BooleanLiteral: - { - auto value = utility::details::make_unique(tkn.boolean_val); - GetNextToken(tkn); - if (tkn.m_error) return utility::details::make_unique(); - return std::move(value); - } + { + auto value = utility::details::make_unique(tkn.boolean_val); + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(value); + } case JSON_Parser::Token::TKN_NullLiteral: - { - GetNextToken(tkn); - // Returning a null value whether or not an error occurred. - return utility::details::make_unique(); - } + { + GetNextToken(tkn); + // Returning a null value whether or not an error occurred. + return utility::details::make_unique(); + } default: - { - SetErrorCode(tkn, json_error::malformed_token); - return utility::details::make_unique(); - } + { + SetErrorCode(tkn, json_error::malformed_token); + return utility::details::make_unique(); + } } } -}}} +} // namespace details +} // namespace json +} // namespace web -static web::json::value _parse_stream(utility::istream_t &stream) +static web::json::value _parse_stream(utility::istream_t& stream) { web::json::details::JSON_StreamParser parser(stream); web::json::details::JSON_Parser::Token tkn; @@ -1159,12 +1089,13 @@ static web::json::value _parse_stream(utility::istream_t &stream) } else if (tkn.kind != web::json::details::JSON_Parser::Token::TKN_EOF) { - web::json::details::CreateException(tkn, _XPLATSTR("Left-over characters in stream after parsing a JSON value")); + web::json::details::CreateException(tkn, + _XPLATSTR("Left-over characters in stream after parsing a JSON value")); } return value; } -static web::json::value _parse_stream(utility::istream_t &stream, std::error_code& error) +static web::json::value _parse_stream(utility::istream_t& stream, std::error_code& error) { web::json::details::JSON_StreamParser parser(stream); web::json::details::JSON_Parser::Token tkn; @@ -1187,7 +1118,7 @@ static web::json::value _parse_stream(utility::istream_t &stream, std::error_cod } #ifdef _WIN32 -static web::json::value _parse_narrow_stream(std::istream &stream) +static web::json::value _parse_narrow_stream(std::istream& stream) { web::json::details::JSON_StreamParser parser(stream); web::json::details::JSON_StreamParser::Token tkn; @@ -1205,12 +1136,13 @@ static web::json::value _parse_narrow_stream(std::istream &stream) } else if (tkn.kind != web::json::details::JSON_Parser::Token::TKN_EOF) { - web::json::details::CreateException(tkn, _XPLATSTR("Left-over characters in stream after parsing a JSON value")); + web::json::details::CreateException(tkn, + _XPLATSTR("Left-over characters in stream after parsing a JSON value")); } return value; } -static web::json::value _parse_narrow_stream(std::istream &stream, std::error_code& error) +static web::json::value _parse_narrow_stream(std::istream& stream, std::error_code& error) { web::json::details::JSON_StreamParser parser(stream); web::json::details::JSON_StreamParser::Token tkn; @@ -1252,7 +1184,8 @@ web::json::value web::json::value::parse(const utility::string_t& str) } else if (tkn.kind != web::json::details::JSON_Parser::Token::TKN_EOF) { - web::json::details::CreateException(tkn, _XPLATSTR("Left-over characters in stream after parsing a JSON value")); + web::json::details::CreateException(tkn, + _XPLATSTR("Left-over characters in stream after parsing a JSON value")); } return value; } @@ -1280,21 +1213,15 @@ web::json::value web::json::value::parse(const utility::string_t& str, std::erro return returnObject; } -web::json::value web::json::value::parse(utility::istream_t &stream) -{ - return _parse_stream(stream); -} +web::json::value web::json::value::parse(utility::istream_t& stream) { return _parse_stream(stream); } -web::json::value web::json::value::parse(utility::istream_t &stream, std::error_code& error) +web::json::value web::json::value::parse(utility::istream_t& stream, std::error_code& error) { return _parse_stream(stream, error); } #ifdef _WIN32 -web::json::value web::json::value::parse(std::istream& stream) -{ - return _parse_narrow_stream(stream); -} +web::json::value web::json::value::parse(std::istream& stream) { return _parse_narrow_stream(stream); } web::json::value web::json::value::parse(std::istream& stream, std::error_code& error) { diff --git a/Release/src/json/json_serialization.cpp b/Release/src/json/json_serialization.cpp index e5ddbf0776..3aa0c50ceb 100644 --- a/Release/src/json/json_serialization.cpp +++ b/Release/src/json/json_serialization.cpp @@ -1,17 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: JSON parser and writer -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: JSON parser and writer + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include #ifndef _WIN32 @@ -36,13 +37,10 @@ void web::json::value::serialize(std::ostream& stream) const m_value->serialize_impl(str); stream << str; } -void web::json::value::format(std::basic_string &string) const -{ - m_value->format(string); -} +void web::json::value::format(std::basic_string& string) const { m_value->format(string); } #endif -void web::json::value::serialize(utility::ostream_t &stream) const +void web::json::value::serialize(utility::ostream_t& stream) const { #ifndef _WIN32 utility::details::scoped_c_thread_locale locale; @@ -54,15 +52,13 @@ void web::json::value::serialize(utility::ostream_t &stream) const stream << str; } -void web::json::value::format(std::basic_string& string) const -{ - m_value->format(string); -} +void web::json::value::format(std::basic_string& string) const { m_value->format(string); } template -void web::json::details::append_escape_string(std::basic_string& str, const std::basic_string& escaped) +void web::json::details::append_escape_string(std::basic_string& str, + const std::basic_string& escaped) { - for (const auto &ch : escaped) + for (const auto& ch : escaped) { switch (ch) { @@ -99,7 +95,8 @@ void web::json::details::append_escape_string(std::basic_string& str, // If a control character then must unicode escaped. if (ch >= 0 && ch <= 0x1F) { - static const std::array intToHex = { { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' } }; + static const std::array intToHex = { + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}}; str += '\\'; str += 'u'; str += '0'; @@ -135,7 +132,7 @@ void web::json::details::_String::format(std::basic_string& str) const { str.push_back('"'); - if(m_has_escape_char) + if (m_has_escape_char) { append_escape_string(str, utility::conversions::to_utf8string(m_string)); } @@ -149,7 +146,7 @@ void web::json::details::_String::format(std::basic_string& str) const void web::json::details::_Number::format(std::basic_string& stream) const { - if(m_number.m_type != number::type::double_type) + if (m_number.m_type != number::type::double_type) { // #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator. const size_t tempSize = std::numeric_limits::digits10 + 3; @@ -174,19 +171,20 @@ void web::json::details::_Number::format(std::basic_string& stream) const } else { - // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null terminator + // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null + // terminator const size_t tempSize = std::numeric_limits::digits10 + 10; char tempBuffer[tempSize]; #ifdef _WIN32 - const auto numChars = _sprintf_s_l( - tempBuffer, - tempSize, - "%.*g", - utility::details::scoped_c_thread_locale::c_locale(), - std::numeric_limits::digits10 + 2, - m_number.m_value); + const auto numChars = _sprintf_s_l(tempBuffer, + tempSize, + "%.*g", + utility::details::scoped_c_thread_locale::c_locale(), + std::numeric_limits::digits10 + 2, + m_number.m_value); #else - const auto numChars = snprintf(tempBuffer, tempSize, "%.*g", std::numeric_limits::digits10 + 2, m_number.m_value); + const auto numChars = + snprintf(tempBuffer, tempSize, "%.*g", std::numeric_limits::digits10 + 2, m_number.m_value); #endif stream.append(tempBuffer, numChars); } @@ -198,7 +196,7 @@ void web::json::details::_String::format(std::basic_string& str) const { str.push_back(L'"'); - if(m_has_escape_char) + if (m_has_escape_char) { append_escape_string(str, m_string); } @@ -212,7 +210,7 @@ void web::json::details::_String::format(std::basic_string& str) const void web::json::details::_Number::format(std::basic_string& stream) const { - if(m_number.m_type != number::type::double_type) + if (m_number.m_type != number::type::double_type) { // #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator. const size_t tempSize = std::numeric_limits::digits10 + 3; @@ -227,31 +225,25 @@ void web::json::details::_Number::format(std::basic_string& stream) con } else { - // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null terminator + // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null + // terminator const size_t tempSize = std::numeric_limits::digits10 + 10; wchar_t tempBuffer[tempSize]; - const int numChars = _swprintf_s_l( - tempBuffer, - tempSize, - L"%.*g", - utility::details::scoped_c_thread_locale::c_locale(), - std::numeric_limits::digits10 + 2, - m_number.m_value); + const int numChars = _swprintf_s_l(tempBuffer, + tempSize, + L"%.*g", + utility::details::scoped_c_thread_locale::c_locale(), + std::numeric_limits::digits10 + 2, + m_number.m_value); stream.append(tempBuffer, numChars); } } #endif -const utility::string_t & web::json::details::_String::as_string() const -{ - return m_string; -} +const utility::string_t& web::json::details::_String::as_string() const { return m_string; } -const utility::string_t & web::json::value::as_string() const -{ - return m_value->as_string(); -} +const utility::string_t& web::json::value::as_string() const { return m_value->as_string(); } utility::string_t json::value::serialize() const { diff --git a/Release/src/pch/stdafx.cpp b/Release/src/pch/stdafx.cpp index 189c9a00a0..e4c61a1283 100644 --- a/Release/src/pch/stdafx.cpp +++ b/Release/src/pch/stdafx.cpp @@ -1,15 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ // stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" - - diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 811786cacf..7cb9504b2e 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Pre-compiled headers -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Pre-compiled headers + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -24,34 +24,35 @@ #ifdef CPPREST_TARGET_XP #include #ifndef _WIN32_WINNT -#define _WIN32_WINNT _WIN32_WINNT_WS03 //Windows XP with SP2 +#define _WIN32_WINNT _WIN32_WINNT_WS03 // Windows XP with SP2 #endif #endif #include // use the debug version of the CRT if _DEBUG is defined #ifdef _DEBUG - #define _CRTDBG_MAP_ALLOC - #include - #include +#define _CRTDBG_MAP_ALLOC +#include +#include #endif -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#include +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include +#include + // Windows Header Files: #if !defined(__cplusplus_winrt) #include #endif // #if !defined(__cplusplus_winrt) -#else // LINUX or APPLE +#else // LINUX or APPLE #define __STDC_LIMIT_MACROS -#include -#include -#include +#include "pthread.h" #include +#include #include -#include "pthread.h" +#include +#include #if (defined(ANDROID) || defined(__ANDROID__)) && !defined(_LIBCPP_VERSION) // Boost doesn't recognize libstdcpp on top of clang correctly #include "boost/config.hpp" @@ -59,34 +60,32 @@ #undef BOOST_NO_CXX11_SMART_PTR #undef BOOST_NO_CXX11_NULLPTR #endif -#include "boost/thread/mutex.hpp" -#include "boost/thread/condition_variable.hpp" -#include "boost/date_time/posix_time/posix_time_types.hpp" #include "boost/bind/bind.hpp" -#include -#include +#include "boost/date_time/posix_time/posix_time_types.hpp" +#include "boost/thread/condition_variable.hpp" +#include "boost/thread/mutex.hpp" #include +#include #include +#include #endif // _WIN32 // Macro indicating the C++ Rest SDK product itself is being built. // This is to help track how many developers are directly building from source themselves. #define _CASA_BUILD_FROM_SRC +#include "cpprest/details/basic_types.h" +#include "cpprest/details/cpprest_compat.h" +#include "cpprest/version.h" +#include "pplx/pplxtasks.h" #include -#include +#include #include #include +#include +#include #include -#include #include -#include - -#include "cpprest/details/cpprest_compat.h" -#include "cpprest/details/basic_types.h" - -#include "pplx/pplxtasks.h" -#include "cpprest/version.h" // json #include "cpprest/json.h" @@ -99,10 +98,10 @@ #include "cpprest/details/web_utilities.h" // http +#include "cpprest/details/http_helpers.h" +#include "cpprest/http_client.h" #include "cpprest/http_headers.h" #include "cpprest/http_msg.h" -#include "cpprest/http_client.h" -#include "cpprest/details/http_helpers.h" // oauth #if !defined(_WIN32) || _WIN32_WINNT >= _WIN32_WINNT_VISTA @@ -113,8 +112,8 @@ #if !defined(__cplusplus_winrt) #if _WIN32_WINNT >= _WIN32_WINNT_VISTA #include "cpprest/details/http_server.h" -#include "cpprest/http_listener.h" #include "cpprest/details/http_server_api.h" +#include "cpprest/http_listener.h" #endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA #endif diff --git a/Release/src/pplx/pplx.cpp b/Release/src/pplx/pplx.cpp index 99d00e9ea5..5f9626edd8 100644 --- a/Release/src/pplx/pplx.cpp +++ b/Release/src/pplx/pplx.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Parallel Patterns Library implementation (common code across platforms) -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Parallel Patterns Library implementation (common code across platforms) + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -19,93 +19,82 @@ // Disable false alarm code analyze warning #if defined(_MSC_VER) -#pragma warning (disable : 26165 26110) +#pragma warning(disable : 26165 26110) #endif namespace pplx { - - namespace details { - /// - /// Spin lock to allow for locks to be used in global scope - /// - class _Spin_lock - { - public: - - _Spin_lock() - : _M_lock(0) - { - } +/// +/// Spin lock to allow for locks to be used in global scope +/// +class _Spin_lock +{ +public: + _Spin_lock() : _M_lock(0) {} - void lock() + void lock() + { + if (details::atomic_compare_exchange(_M_lock, 1l, 0l) != 0l) { - if ( details::atomic_compare_exchange(_M_lock, 1l, 0l) != 0l ) + do { - do - { - pplx::details::platform::YieldExecution(); + pplx::details::platform::YieldExecution(); - } while ( details::atomic_compare_exchange(_M_lock, 1l, 0l) != 0l ); - } + } while (details::atomic_compare_exchange(_M_lock, 1l, 0l) != 0l); } + } - void unlock() - { - // fence for release semantics - details::atomic_exchange(_M_lock, 0l); - } + void unlock() + { + // fence for release semantics + details::atomic_exchange(_M_lock, 0l); + } - private: - atomic_long _M_lock; - }; +private: + atomic_long _M_lock; +}; - typedef ::pplx::scoped_lock<_Spin_lock> _Scoped_spin_lock; +typedef ::pplx::scoped_lock<_Spin_lock> _Scoped_spin_lock; } // namespace details static struct _pplx_g_sched_t { typedef std::shared_ptr sched_ptr; - _pplx_g_sched_t() - { - m_state = post_ctor; - } + _pplx_g_sched_t() { m_state = post_ctor; } - ~_pplx_g_sched_t() - { - m_state = post_dtor; - } + ~_pplx_g_sched_t() { m_state = post_dtor; } sched_ptr get_scheduler() { switch (m_state) { - case post_ctor: - // This is the 99.9% case. + case post_ctor: + // This is the 99.9% case. - if (!m_scheduler) - { - ::pplx::details::_Scoped_spin_lock lock(m_spinlock); if (!m_scheduler) { - m_scheduler = std::make_shared< ::pplx::default_scheduler_t>(); + ::pplx::details::_Scoped_spin_lock lock(m_spinlock); + if (!m_scheduler) + { + m_scheduler = std::make_shared<::pplx::default_scheduler_t>(); + } } - } - return m_scheduler; - default: - // This case means the global m_scheduler is not available. - // We spin off an individual scheduler instead. - return std::make_shared< ::pplx::default_scheduler_t>(); + return m_scheduler; + default: + // This case means the global m_scheduler is not available. + // We spin off an individual scheduler instead. + return std::make_shared<::pplx::default_scheduler_t>(); } } void set_scheduler(sched_ptr scheduler) { - if (m_state == pre_ctor || m_state == post_dtor) { + if (m_state == pre_ctor || m_state == post_dtor) + { throw invalid_operation("Scheduler cannot be initialized now"); } diff --git a/Release/src/pplx/pplxapple.cpp b/Release/src/pplx/pplxapple.cpp index 44c25f6b39..6eff5e7575 100644 --- a/Release/src/pplx/pplxapple.cpp +++ b/Release/src/pplx/pplxapple.cpp @@ -1,52 +1,50 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* - * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * Apple-specific pplx implementations * - * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ -#include -#include -#include -#include -#include #include "stdafx.h" + #include "pplx/pplx.h" +#include +#include +#include +#include +#include // DEVNOTE: // The use of mutexes is suboptimal for synchronization of task execution. -// Given that scheduler implementations should use GCD queues, there are potentially better mechanisms available to coordinate tasks (such as dispatch groups). +// Given that scheduler implementations should use GCD queues, there are potentially better mechanisms available to +// coordinate tasks (such as dispatch groups). namespace pplx { +namespace details +{ +namespace platform +{ +_PPLXIMP long GetCurrentThreadId() +{ + pthread_t threadId = pthread_self(); + return (long)threadId; +} -namespace details { - - namespace platform - { - _PPLXIMP long GetCurrentThreadId() - { - pthread_t threadId = pthread_self(); - return (long)threadId; - } - - void YieldExecution() - { - sleep(0); - } +void YieldExecution() { sleep(0); } - } // namespace platform +} // namespace platform - void apple_scheduler::schedule( TaskProc_t proc, void* param) - { - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_async_f(queue, param, proc); - } +void apple_scheduler::schedule(TaskProc_t proc, void* param) +{ + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async_f(queue, param, proc); +} } // namespace details -} // pplx +} // namespace pplx diff --git a/Release/src/pplx/pplxlinux.cpp b/Release/src/pplx/pplxlinux.cpp index 50365794a3..630a9e477f 100644 --- a/Release/src/pplx/pplxlinux.cpp +++ b/Release/src/pplx/pplxlinux.cpp @@ -1,17 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Parallel Patterns Library - Linux version -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Parallel Patterns Library - Linux version + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "pplx/pplx.h" #include "pplx/threadpool.h" #include "sys/syscall.h" @@ -23,26 +24,19 @@ namespace pplx { +namespace details +{ +namespace platform +{ +_PPLXIMP long GetCurrentThreadId() { return reinterpret_cast(reinterpret_cast(pthread_self())); } -namespace details { - - namespace platform - { - _PPLXIMP long GetCurrentThreadId() - { - return reinterpret_cast(reinterpret_cast(pthread_self())); - } - - _PPLXIMP void YieldExecution() - { - std::this_thread::yield(); - } - } - - _PPLXIMP void linux_scheduler::schedule(TaskProc_t proc, void* param) - { - crossplat::threadpool::shared_instance().service().post(boost::bind(proc, param)); - } +_PPLXIMP void YieldExecution() { std::this_thread::yield(); } +} // namespace platform + +_PPLXIMP void linux_scheduler::schedule(TaskProc_t proc, void* param) +{ + crossplat::threadpool::shared_instance().service().post(boost::bind(proc, param)); +} } // namespace details diff --git a/Release/src/pplx/pplxwin.cpp b/Release/src/pplx/pplxwin.cpp index c414397c16..05a548de34 100644 --- a/Release/src/pplx/pplxwin.cpp +++ b/Release/src/pplx/pplxwin.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Windows specific implementation of PPL constructs -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Windows specific implementation of PPL constructs + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -18,256 +18,222 @@ #include "pplx/pplxwin.h" // Disable false alarm code analysis warning -#pragma warning (disable : 26165 26110) +#pragma warning(disable : 26165 26110) namespace pplx { namespace details { - namespace platform - { - _PPLXIMP long __cdecl GetCurrentThreadId() - { - return (long)(::GetCurrentThreadId()); - } - - _PPLXIMP void __cdecl YieldExecution() - { - YieldProcessor(); - } - - _PPLXIMP size_t __cdecl CaptureCallstack(void **stackData, size_t skipFrames, size_t captureFrames) - { - (stackData); - (skipFrames); - (captureFrames); - - size_t capturedFrames = 0; - // RtlCaptureSTackBackTrace is not available in MSDK, so we only call it under Desktop or _DEBUG MSDK. - // For MSDK unsupported version, we will return zero frame number. +namespace platform +{ +_PPLXIMP long __cdecl GetCurrentThreadId() { return (long)(::GetCurrentThreadId()); } + +_PPLXIMP void __cdecl YieldExecution() { YieldProcessor(); } + +_PPLXIMP size_t __cdecl CaptureCallstack(void** stackData, size_t skipFrames, size_t captureFrames) +{ + (stackData); + (skipFrames); + (captureFrames); + + size_t capturedFrames = 0; + // RtlCaptureSTackBackTrace is not available in MSDK, so we only call it under Desktop or _DEBUG MSDK. + // For MSDK unsupported version, we will return zero frame number. #if !defined(__cplusplus_winrt) - capturedFrames = RtlCaptureStackBackTrace(static_cast(skipFrames + 1), static_cast(captureFrames), stackData, nullptr); + capturedFrames = RtlCaptureStackBackTrace( + static_cast(skipFrames + 1), static_cast(captureFrames), stackData, nullptr); #endif - return capturedFrames; - } + return capturedFrames; +} #if defined(__cplusplus_winrt) - volatile long s_asyncId = 0; +volatile long s_asyncId = 0; - _PPLXIMP unsigned int __cdecl GetNextAsyncId() - { - return static_cast(_InterlockedIncrement(&s_asyncId)); - } +_PPLXIMP unsigned int __cdecl GetNextAsyncId() { return static_cast(_InterlockedIncrement(&s_asyncId)); } #endif // defined(__cplusplus_winrt) - void InitializeCriticalSection(LPCRITICAL_SECTION _cs) - { +void InitializeCriticalSection(LPCRITICAL_SECTION _cs) +{ #ifndef __cplusplus_winrt - // InitializeCriticalSection can cause STATUS_NO_MEMORY see C28125 - __try { - ::InitializeCriticalSection(_cs); - } - __except(GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - throw ::std::bad_alloc(); - } + // InitializeCriticalSection can cause STATUS_NO_MEMORY see C28125 + __try + { + ::InitializeCriticalSection(_cs); + } + __except (GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + throw ::std::bad_alloc(); + } #else - InitializeCriticalSectionEx(_cs, 0, 0); + InitializeCriticalSectionEx(_cs, 0, 0); #endif // !__cplusplus_winrt - } +} - } +} // namespace platform - // - // Event implementation - // - _PPLXIMP event_impl::event_impl() - { - static_assert(sizeof(HANDLE) <= sizeof(_M_impl), "HANDLE version mismatch"); +// +// Event implementation +// +_PPLXIMP event_impl::event_impl() +{ + static_assert(sizeof(HANDLE) <= sizeof(_M_impl), "HANDLE version mismatch"); #ifndef __cplusplus_winrt - _M_impl = CreateEvent(NULL, true, false, NULL); + _M_impl = CreateEvent(NULL, true, false, NULL); #else - _M_impl = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); + _M_impl = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); #endif // !__cplusplus_winrt - if( _M_impl != NULL ) - { - ResetEvent(static_cast(_M_impl)); - } - } - - _PPLXIMP event_impl::~event_impl() + if (_M_impl != NULL) { - CloseHandle(static_cast(_M_impl)); + ResetEvent(static_cast(_M_impl)); } +} - _PPLXIMP void event_impl::set() - { - SetEvent(static_cast(_M_impl)); - } +_PPLXIMP event_impl::~event_impl() { CloseHandle(static_cast(_M_impl)); } - _PPLXIMP void event_impl::reset() - { - ResetEvent(static_cast(_M_impl)); - } +_PPLXIMP void event_impl::set() { SetEvent(static_cast(_M_impl)); } - _PPLXIMP unsigned int event_impl::wait(unsigned int timeout) - { - DWORD waitTime = (timeout == event_impl::timeout_infinite) ? INFINITE : (DWORD)timeout; - DWORD status = WaitForSingleObjectEx(static_cast(_M_impl), waitTime, 0); - _ASSERTE((status == WAIT_OBJECT_0) || (waitTime != INFINITE)); +_PPLXIMP void event_impl::reset() { ResetEvent(static_cast(_M_impl)); } - return (status == WAIT_OBJECT_0) ? 0 : event_impl::timeout_infinite; - } +_PPLXIMP unsigned int event_impl::wait(unsigned int timeout) +{ + DWORD waitTime = (timeout == event_impl::timeout_infinite) ? INFINITE : (DWORD)timeout; + DWORD status = WaitForSingleObjectEx(static_cast(_M_impl), waitTime, 0); + _ASSERTE((status == WAIT_OBJECT_0) || (waitTime != INFINITE)); - // - // critical_section implementation - // - // TFS# 612702 -- this implementation is unnecessarily recursive. See bug for details. - _PPLXIMP critical_section_impl::critical_section_impl() - { - static_assert(sizeof(CRITICAL_SECTION) <= sizeof(_M_impl), "CRITICAL_SECTION version mismatch"); + return (status == WAIT_OBJECT_0) ? 0 : event_impl::timeout_infinite; +} - platform::InitializeCriticalSection(reinterpret_cast(&_M_impl)); - } +// +// critical_section implementation +// +// TFS# 612702 -- this implementation is unnecessarily recursive. See bug for details. +_PPLXIMP critical_section_impl::critical_section_impl() +{ + static_assert(sizeof(CRITICAL_SECTION) <= sizeof(_M_impl), "CRITICAL_SECTION version mismatch"); - _PPLXIMP critical_section_impl::~critical_section_impl() - { - DeleteCriticalSection(reinterpret_cast(&_M_impl)); - } + platform::InitializeCriticalSection(reinterpret_cast(&_M_impl)); +} - _PPLXIMP void critical_section_impl::lock() - { - EnterCriticalSection(reinterpret_cast(&_M_impl)); - } +_PPLXIMP critical_section_impl::~critical_section_impl() +{ + DeleteCriticalSection(reinterpret_cast(&_M_impl)); +} - _PPLXIMP void critical_section_impl::unlock() - { - LeaveCriticalSection(reinterpret_cast(&_M_impl)); - } +_PPLXIMP void critical_section_impl::lock() { EnterCriticalSection(reinterpret_cast(&_M_impl)); } + +_PPLXIMP void critical_section_impl::unlock() { LeaveCriticalSection(reinterpret_cast(&_M_impl)); } #if _WIN32_WINNT >= _WIN32_WINNT_VISTA - // - // reader_writer_lock implementation - // - _PPLXIMP reader_writer_lock_impl::reader_writer_lock_impl() - : m_locked_exclusive(false) - { - static_assert(sizeof(SRWLOCK) <= sizeof(_M_impl), "SRWLOCK version mismatch"); - InitializeSRWLock(reinterpret_cast(&_M_impl)); - } +// +// reader_writer_lock implementation +// +_PPLXIMP reader_writer_lock_impl::reader_writer_lock_impl() : m_locked_exclusive(false) +{ + static_assert(sizeof(SRWLOCK) <= sizeof(_M_impl), "SRWLOCK version mismatch"); + InitializeSRWLock(reinterpret_cast(&_M_impl)); +} - _PPLXIMP void reader_writer_lock_impl::lock() - { - AcquireSRWLockExclusive(reinterpret_cast(&_M_impl)); - m_locked_exclusive = true; - } +_PPLXIMP void reader_writer_lock_impl::lock() +{ + AcquireSRWLockExclusive(reinterpret_cast(&_M_impl)); + m_locked_exclusive = true; +} + +_PPLXIMP void reader_writer_lock_impl::lock_read() { AcquireSRWLockShared(reinterpret_cast(&_M_impl)); } - _PPLXIMP void reader_writer_lock_impl::lock_read() +_PPLXIMP void reader_writer_lock_impl::unlock() +{ + if (m_locked_exclusive) { - AcquireSRWLockShared(reinterpret_cast(&_M_impl)); + m_locked_exclusive = false; + ReleaseSRWLockExclusive(reinterpret_cast(&_M_impl)); } - - _PPLXIMP void reader_writer_lock_impl::unlock() + else { - if(m_locked_exclusive) - { - m_locked_exclusive = false; - ReleaseSRWLockExclusive(reinterpret_cast(&_M_impl)); - } - else - { - ReleaseSRWLockShared(reinterpret_cast(&_M_impl)); - } + ReleaseSRWLockShared(reinterpret_cast(&_M_impl)); } +} #endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA - // - // scheduler implementation - // +// +// scheduler implementation +// #if defined(__cplusplus_winrt) - _PPLXIMP void windows_scheduler::schedule( TaskProc_t proc, _In_ void* param) - { - auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([proc, param](Windows::Foundation::IAsyncAction ^ ) - { - proc(param); - }); +_PPLXIMP void windows_scheduler::schedule(TaskProc_t proc, _In_ void* param) +{ + auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler( + [proc, param](Windows::Foundation::IAsyncAction ^) { proc(param); }); - Windows::System::Threading::ThreadPool::RunAsync(workItemHandler); - } + Windows::System::Threading::ThreadPool::RunAsync(workItemHandler); +} #else #if _WIN32_WINNT < _WIN32_WINNT_VISTA - struct _Scheduler_Param - { - TaskProc_t m_proc; - void * m_param; +struct _Scheduler_Param +{ + TaskProc_t m_proc; + void* m_param; - _Scheduler_Param(TaskProc_t proc, _In_ void * param) - : m_proc(proc), m_param(param) - { - } + _Scheduler_Param(TaskProc_t proc, _In_ void* param) : m_proc(proc), m_param(param) {} - static DWORD CALLBACK DefaultWorkCallback(LPVOID lpParameter) - { - auto schedulerParam = (_Scheduler_Param *)(lpParameter); + static DWORD CALLBACK DefaultWorkCallback(LPVOID lpParameter) + { + auto schedulerParam = (_Scheduler_Param*)(lpParameter); - schedulerParam->m_proc(schedulerParam->m_param); + schedulerParam->m_proc(schedulerParam->m_param); - delete schedulerParam; + delete schedulerParam; - return 1; - } - }; + return 1; + } +}; + +_PPLXIMP void windows_scheduler::schedule(TaskProc_t proc, _In_ void* param) +{ + auto schedulerParam = new _Scheduler_Param(proc, param); + auto work = QueueUserWorkItem(_Scheduler_Param::DefaultWorkCallback, schedulerParam, WT_EXECUTELONGFUNCTION); - _PPLXIMP void windows_scheduler::schedule( TaskProc_t proc, _In_ void* param) + if (!work) { - auto schedulerParam = new _Scheduler_Param(proc, param); - auto work = QueueUserWorkItem(_Scheduler_Param::DefaultWorkCallback, schedulerParam, WT_EXECUTELONGFUNCTION); - - if (!work) - { - delete schedulerParam; - throw utility::details::create_system_error(GetLastError()); - } + delete schedulerParam; + throw utility::details::create_system_error(GetLastError()); } +} #else - struct _Scheduler_Param - { - TaskProc_t m_proc; - void * m_param; - - _Scheduler_Param(TaskProc_t proc, _In_ void * param) - : m_proc(proc), m_param(param) - { - } +struct _Scheduler_Param +{ + TaskProc_t m_proc; + void* m_param; - static void CALLBACK DefaultWorkCallback(PTP_CALLBACK_INSTANCE, PVOID pContext, PTP_WORK) - { - auto schedulerParam = (_Scheduler_Param *)(pContext); + _Scheduler_Param(TaskProc_t proc, _In_ void* param) : m_proc(proc), m_param(param) {} - schedulerParam->m_proc(schedulerParam->m_param); + static void CALLBACK DefaultWorkCallback(PTP_CALLBACK_INSTANCE, PVOID pContext, PTP_WORK) + { + auto schedulerParam = (_Scheduler_Param*)(pContext); - delete schedulerParam; - } - }; + schedulerParam->m_proc(schedulerParam->m_param); - _PPLXIMP void windows_scheduler::schedule( TaskProc_t proc, _In_ void* param) - { - auto schedulerParam = new _Scheduler_Param(proc, param); - auto work = CreateThreadpoolWork(_Scheduler_Param::DefaultWorkCallback, schedulerParam, NULL); + delete schedulerParam; + } +}; - if (work == nullptr) - { - delete schedulerParam; - throw utility::details::create_system_error(GetLastError()); - } +_PPLXIMP void windows_scheduler::schedule(TaskProc_t proc, _In_ void* param) +{ + auto schedulerParam = new _Scheduler_Param(proc, param); + auto work = CreateThreadpoolWork(_Scheduler_Param::DefaultWorkCallback, schedulerParam, NULL); - SubmitThreadpoolWork(work); - CloseThreadpoolWork(work); + if (work == nullptr) + { + delete schedulerParam; + throw utility::details::create_system_error(GetLastError()); } + + SubmitThreadpoolWork(work); + CloseThreadpoolWork(work); +} #endif // _WIN32_WINNT < _WIN32_WINNT_VISTA #endif @@ -278,7 +244,6 @@ namespace details #else namespace Concurrency { - void __cdecl set_cpprestsdk_ambient_scheduler(const std::shared_ptr& _Scheduler) { pplx::set_ambient_scheduler(_Scheduler); @@ -289,5 +254,5 @@ const std::shared_ptr& __cdecl get_cpprestsdk_ambient_sched return pplx::get_ambient_scheduler(); } -} // namespace pplx -#endif \ No newline at end of file +} // namespace Concurrency +#endif diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index 58920c0253..624d69c12a 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -6,7 +6,6 @@ #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32) #include "pplx/threadpool.h" - #include #include #include @@ -165,9 +164,9 @@ std::pair initialize_shared_threadpool(size_t bool initialized_this_time = false; static std::once_flag of; - #if defined(__ANDROID__) - abort_if_no_jvm(); - #endif // __ANDROID__ +#if defined(__ANDROID__) + abort_if_no_jvm(); +#endif // __ANDROID__ std::call_once(of, [num_threads, &initialized_this_time] { uninit_threadpool.construct(num_threads); @@ -176,7 +175,7 @@ std::pair initialize_shared_threadpool(size_t return {initialized_this_time, &uninit_threadpool.storage}; } -} +} // namespace namespace crossplat { @@ -190,7 +189,7 @@ void threadpool::initialize_with_threads(size_t num_threads) throw std::runtime_error("the cpprestsdk threadpool has already been initialized"); } } -} +} // namespace crossplat #if defined(__ANDROID__) void cpprest_init(JavaVM* vm) { JVM = vm; } diff --git a/Release/src/streams/fileio_posix.cpp b/Release/src/streams/fileio_posix.cpp index a3690f1070..013d910d44 100644 --- a/Release/src/streams/fileio_posix.cpp +++ b/Release/src/streams/fileio_posix.cpp @@ -1,35 +1,40 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Asynchronous I/O: stream buffer implementation details -* -* We're going to some lengths to avoid exporting C++ class member functions and implementation details across -* module boundaries, and the factoring requires that we keep the implementation details away from the main header -* files. The supporting functions, which are in this file, use C-like signatures to avoid as many issues as -* possible. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Asynchronous I/O: stream buffer implementation details + * + * We're going to some lengths to avoid exporting C++ class member functions and implementation details across + * module boundaries, and the factoring requires that we keep the implementation details away from the main header + * files. The supporting functions, which are in this file, use C-like signatures to avoid as many issues as + * possible. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/details/fileio.h" using namespace boost::asio; using namespace Concurrency::streams::details; -namespace Concurrency { namespace streams { namespace details { - +namespace Concurrency +{ +namespace streams +{ +namespace details +{ /*** -* ==++== -* -* Implementation details of the file stream buffer -* -* =-=-=- -****/ + * ==++== + * + * Implementation details of the file stream buffer + * + * =-=-=- + ****/ /// /// The public parts of the file information record contain only what is implementation- @@ -38,30 +43,29 @@ namespace Concurrency { namespace streams { namespace details { /// struct _file_info_impl : _file_info { - _file_info_impl(int handle, std::ios_base::openmode mode, bool buffer_reads) : - _file_info(mode, 512), - m_handle(handle), - m_buffer_reads(buffer_reads), - m_outstanding_writes(0) + _file_info_impl(int handle, std::ios_base::openmode mode, bool buffer_reads) + : _file_info(mode, 512), m_handle(handle), m_buffer_reads(buffer_reads), m_outstanding_writes(0) { } /// /// The file handle of the file /// - int m_handle; + int m_handle; bool m_buffer_reads; /// /// A list of callback waiting to be signaled that there are no outstanding writes. /// - std::vector<_filestream_callback *> m_sync_waiters; + std::vector<_filestream_callback*> m_sync_waiters; std::atomic m_outstanding_writes; }; -}}} +} // namespace details +} // namespace streams +} // namespace Concurrency /// /// Perform post-CreateFile processing. @@ -70,7 +74,7 @@ struct _file_info_impl : _file_info /// The callback interface pointer /// The C++ file open mode /// The error code if there was an error in file creation. -bool _finish_create(int fh, _filestream_callback *callback, std::ios_base::openmode mode, int /* prot */) +bool _finish_create(int fh, _filestream_callback* callback, std::ios_base::openmode mode, int /* prot */) { if (fh != -1) { @@ -119,7 +123,7 @@ int get_open_flags(std::ios_base::openmode mode) } else if (mode & std::ios_base::out) { - result = O_WRONLY|O_CREAT; + result = O_WRONLY | O_CREAT; } if (mode & std::ios_base::app) @@ -129,7 +133,7 @@ int get_open_flags(std::ios_base::openmode mode) if (mode & std::ios_base::trunc) { - result |= O_TRUNC|O_CREAT; + result |= O_TRUNC | O_CREAT; } return result; @@ -146,16 +150,15 @@ int get_open_flags(std::ios_base::openmode mode) /// /// True does not signal that the file will eventually be successfully opened, just that the process was started. /// -bool _open_fsb_str(_filestream_callback *callback, const char *filename, std::ios_base::openmode mode, int prot) +bool _open_fsb_str(_filestream_callback* callback, const char* filename, std::ios_base::openmode mode, int prot) { - if ( callback == nullptr || filename == nullptr) return false; + if (callback == nullptr || filename == nullptr) return false; std::string name(filename); - pplx::create_task([=]() -> void - { + pplx::create_task([=]() -> void { int cmode = get_open_flags(mode); - if(cmode==O_RDWR) + if (cmode == O_RDWR) { cmode |= O_CREAT; } @@ -177,56 +180,55 @@ bool _open_fsb_str(_filestream_callback *callback, const char *filename, std::io /// /// True does not signal that the file will eventually be successfully closed, just that the process was started. /// -bool _close_fsb_nolock(_file_info **info, Concurrency::streams::details::_filestream_callback *callback) +bool _close_fsb_nolock(_file_info** info, Concurrency::streams::details::_filestream_callback* callback) { - if ( callback == nullptr ) return false; - if ( info == nullptr || *info == nullptr ) return false; + if (callback == nullptr) return false; + if (info == nullptr || *info == nullptr) return false; - _file_info_impl *fInfo = static_cast<_file_info_impl *>(*info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(*info); - if ( fInfo->m_handle == -1 ) return false; + if (fInfo->m_handle == -1) return false; // Since closing a file may involve waiting for outstanding writes which can take some time // if the file is on a network share, the close action is done in a separate task, as // CloseHandle doesn't have I/O completion events. - pplx::create_task([=] () -> void + pplx::create_task([=]() -> void { + bool result = false; + { - bool result = false; + pplx::extensibility::scoped_recursive_lock_t lock(fInfo->m_lock); + if (fInfo->m_handle != -1) { - pplx::extensibility::scoped_recursive_lock_t lock(fInfo->m_lock); - - if ( fInfo->m_handle != -1 ) - { - result = close(fInfo->m_handle) != -1; - } - - if ( fInfo->m_buffer != nullptr ) - { - delete[] fInfo->m_buffer; - } + result = close(fInfo->m_handle) != -1; } - delete fInfo; - if (result) - { - callback->on_closed(); - } - else + if (fInfo->m_buffer != nullptr) { - callback->on_error(std::make_exception_ptr(utility::details::create_system_error(errno))); + delete[] fInfo->m_buffer; } - }); + } + + delete fInfo; + if (result) + { + callback->on_closed(); + } + else + { + callback->on_error(std::make_exception_ptr(utility::details::create_system_error(errno))); + } + }); *info = nullptr; return true; } -bool _close_fsb(_file_info **info, Concurrency::streams::details::_filestream_callback *callback) +bool _close_fsb(_file_info** info, Concurrency::streams::details::_filestream_callback* callback) { - if ( callback == nullptr ) return false; - if ( info == nullptr || *info == nullptr ) return false; + if (callback == nullptr) return false; + if (info == nullptr || *info == nullptr) return false; pplx::extensibility::scoped_recursive_lock_t lock((*info)->m_lock); @@ -240,17 +242,21 @@ bool _close_fsb(_file_info **info, Concurrency::streams::details::_filestream_ca /// A pointer to the callback interface to invoke when the write request is completed. /// A pointer to the data to write /// The size (in bytes) of the data -/// 0 if the write request is still outstanding, -1 if the request failed, otherwise the size of the data written -size_t _write_file_async(Concurrency::streams::details::_file_info_impl *fInfo, Concurrency::streams::details::_filestream_callback *callback, const void *ptr, size_t count, size_t position) +/// 0 if the write request is still outstanding, -1 if the request failed, otherwise the size of the data +/// written +size_t _write_file_async(Concurrency::streams::details::_file_info_impl* fInfo, + Concurrency::streams::details::_filestream_callback* callback, + const void* ptr, + size_t count, + size_t position) { ++fInfo->m_outstanding_writes; - - pplx::create_task([=]() -> void - { + + pplx::create_task([=]() -> void { off_t abs_position; bool must_restore_pos; off_t orig_pos; - if( position == static_cast(-1) ) + if (position == static_cast(-1)) { orig_pos = lseek(fInfo->m_handle, 0, SEEK_CUR); abs_position = lseek(fInfo->m_handle, 0, SEEK_END); @@ -269,7 +275,7 @@ size_t _write_file_async(Concurrency::streams::details::_file_info_impl *fInfo, callback->on_error(std::make_exception_ptr(utility::details::create_system_error(errno))); } - if(must_restore_pos) + if (must_restore_pos) { lseek(fInfo->m_handle, orig_pos, SEEK_SET); } @@ -280,7 +286,7 @@ size_t _write_file_async(Concurrency::streams::details::_file_info_impl *fInfo, pplx::extensibility::scoped_recursive_lock_t lock(fInfo->m_lock); // Decrement the counter of outstanding write events. - if ( --fInfo->m_outstanding_writes == 0 ) + if (--fInfo->m_outstanding_writes == 0) { // If this was the last one, signal all objects waiting for it to complete. @@ -304,11 +310,15 @@ size_t _write_file_async(Concurrency::streams::details::_file_info_impl *fInfo, /// A pointer to a buffer where the data should be placed /// The size (in bytes) of the buffer /// The offset in the file to read from -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -size_t _read_file_async(Concurrency::streams::details::_file_info_impl *fInfo, Concurrency::streams::details::_filestream_callback *callback, void *ptr, size_t count, size_t offset) +/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read +/// into the buffer +size_t _read_file_async(Concurrency::streams::details::_file_info_impl* fInfo, + Concurrency::streams::details::_filestream_callback* callback, + void* ptr, + size_t count, + size_t offset) { - pplx::create_task([=]() -> void - { + pplx::create_task([=]() -> void { auto bytes_read = pread(fInfo->m_handle, ptr, count, offset); if (bytes_read < 0) { @@ -327,51 +337,55 @@ template class _filestream_callback_fill_buffer : public _filestream_callback { public: - _filestream_callback_fill_buffer(_file_info *info, _filestream_callback *callback, const Func &func) : m_info(info), m_func(func), m_callback(callback) { } + _filestream_callback_fill_buffer(_file_info* info, _filestream_callback* callback, const Func& func) + : m_info(info), m_func(func), m_callback(callback) + { + } virtual void on_completed(size_t result) override { m_func(result); delete this; } - virtual void on_error(const std::exception_ptr &e) override + virtual void on_error(const std::exception_ptr& e) override { auto exptr = std::make_exception_ptr(e); m_callback->on_error(exptr); delete this; } + private: - _file_info *m_info; - Func m_func; - _filestream_callback *m_callback; + _file_info* m_info; + Func m_func; + _filestream_callback* m_callback; }; template -_filestream_callback_fill_buffer *create_callback(_file_info *info, _filestream_callback *callback, const Func &func) +_filestream_callback_fill_buffer* create_callback(_file_info* info, + _filestream_callback* callback, + const Func& func) { return new _filestream_callback_fill_buffer(info, callback, func); } static const size_t PageSize = 512; -size_t _fill_buffer_fsb(_file_info_impl *fInfo, _filestream_callback *callback, size_t count, size_t charSize) +size_t _fill_buffer_fsb(_file_info_impl* fInfo, _filestream_callback* callback, size_t count, size_t charSize) { size_t byteCount = count * charSize; - if ( fInfo->m_buffer == nullptr ) + if (fInfo->m_buffer == nullptr) { fInfo->m_bufsize = std::max(PageSize, byteCount); fInfo->m_buffer = new char[static_cast(fInfo->m_bufsize)]; fInfo->m_bufoff = fInfo->m_rdpos; - auto cb = create_callback(fInfo, callback, - [=] (size_t result) - { - pplx::extensibility::scoped_recursive_lock_t lock(fInfo->m_lock); - fInfo->m_buffill = result / charSize; - callback->on_completed(result); - }); + auto cb = create_callback(fInfo, callback, [=](size_t result) { + pplx::extensibility::scoped_recursive_lock_t lock(fInfo->m_lock); + fInfo->m_buffill = result / charSize; + callback->on_completed(result); + }); - return _read_file_async(fInfo, cb, (uint8_t *)fInfo->m_buffer, fInfo->m_bufsize, fInfo->m_rdpos * charSize); + return _read_file_async(fInfo, cb, (uint8_t*)fInfo->m_buffer, fInfo->m_bufsize, fInfo->m_rdpos * charSize); } // First, we need to understand how far into the buffer we have already read @@ -380,18 +394,17 @@ size_t _fill_buffer_fsb(_file_info_impl *fInfo, _filestream_callback *callback, size_t bufpos = fInfo->m_rdpos - fInfo->m_bufoff; size_t bufrem = fInfo->m_buffill - bufpos; - if ( bufrem < count ) + if (bufrem < count) { fInfo->m_bufsize = std::max(PageSize, byteCount); // Then, we allocate a new buffer. - char *newbuf = new char[static_cast(fInfo->m_bufsize)]; + char* newbuf = new char[static_cast(fInfo->m_bufsize)]; // Then, we copy the unread part to the new buffer and delete the old buffer - if ( bufrem > 0 ) - memcpy(newbuf, fInfo->m_buffer + bufpos * charSize, bufrem * charSize); + if (bufrem > 0) memcpy(newbuf, fInfo->m_buffer + bufpos * charSize, bufrem * charSize); delete[] fInfo->m_buffer; fInfo->m_buffer = newbuf; @@ -399,21 +412,22 @@ size_t _fill_buffer_fsb(_file_info_impl *fInfo, _filestream_callback *callback, // Then, we read the remainder of the count into the new buffer fInfo->m_bufoff = fInfo->m_rdpos; - auto cb = create_callback(fInfo, callback, - [=] (size_t result) - { - pplx::extensibility::scoped_recursive_lock_t lock(fInfo->m_lock); - fInfo->m_buffill = result / charSize; - callback->on_completed(result + bufrem * charSize); - }); + auto cb = create_callback(fInfo, callback, [=](size_t result) { + pplx::extensibility::scoped_recursive_lock_t lock(fInfo->m_lock); + fInfo->m_buffill = result / charSize; + callback->on_completed(result + bufrem * charSize); + }); - return _read_file_async(fInfo, cb, (uint8_t*)fInfo->m_buffer + bufrem * charSize, fInfo->m_bufsize - bufrem * charSize, (fInfo->m_rdpos+bufrem)*charSize); + return _read_file_async(fInfo, + cb, + (uint8_t*)fInfo->m_buffer + bufrem * charSize, + fInfo->m_bufsize - bufrem * charSize, + (fInfo->m_rdpos + bufrem) * charSize); } else return byteCount; } - /// /// Read data from a file stream into a buffer /// @@ -421,34 +435,37 @@ size_t _fill_buffer_fsb(_file_info_impl *fInfo, _filestream_callback *callback, /// A pointer to the callback interface to invoke when the write request is completed. /// A pointer to a buffer where the data should be placed /// The size (in bytes) of the buffer -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -size_t _getn_fsb(Concurrency::streams::details::_file_info *info, Concurrency::streams::details::_filestream_callback *callback, void *ptr, size_t count, size_t charSize) +/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read +/// into the buffer +size_t _getn_fsb(Concurrency::streams::details::_file_info* info, + Concurrency::streams::details::_filestream_callback* callback, + void* ptr, + size_t count, + size_t charSize) { - if ( callback == nullptr || info == nullptr ) return static_cast(-1); + if (callback == nullptr || info == nullptr) return static_cast(-1); - _file_info_impl *fInfo = (_file_info_impl *)info; + _file_info_impl* fInfo = (_file_info_impl*)info; pplx::extensibility::scoped_recursive_lock_t lock(info->m_lock); - if ( fInfo->m_handle == -1 ) return static_cast(-1); + if (fInfo->m_handle == -1) return static_cast(-1); size_t byteCount = count * charSize; - if ( fInfo->m_buffer_reads ) + if (fInfo->m_buffer_reads) { - auto cb = create_callback(fInfo, callback, - [=] (size_t read) - { - auto copy = std::min(read, byteCount); - auto bufoff = fInfo->m_rdpos - fInfo->m_bufoff; - memcpy(ptr, fInfo->m_buffer + bufoff * charSize, copy); - fInfo->m_atend = copy < byteCount; - callback->on_completed(copy); - }); + auto cb = create_callback(fInfo, callback, [=](size_t read) { + auto copy = std::min(read, byteCount); + auto bufoff = fInfo->m_rdpos - fInfo->m_bufoff; + memcpy(ptr, fInfo->m_buffer + bufoff * charSize, copy); + fInfo->m_atend = copy < byteCount; + callback->on_completed(copy); + }); size_t read = _fill_buffer_fsb(fInfo, cb, count, charSize); - if ( static_cast(read) > 0 ) + if (static_cast(read) > 0) { auto copy = std::min(read, byteCount); auto bufoff = fInfo->m_rdpos - fInfo->m_bufoff; @@ -472,16 +489,21 @@ size_t _getn_fsb(Concurrency::streams::details::_file_info *info, Concurrency::s /// A pointer to the callback interface to invoke when the write request is completed. /// A pointer to a buffer where the data should be placed /// The size (in bytes) of the buffer -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -size_t _putn_fsb(Concurrency::streams::details::_file_info *info, Concurrency::streams::details::_filestream_callback *callback, const void *ptr, size_t count, size_t charSize) +/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read +/// into the buffer +size_t _putn_fsb(Concurrency::streams::details::_file_info* info, + Concurrency::streams::details::_filestream_callback* callback, + const void* ptr, + size_t count, + size_t charSize) { if (callback == nullptr || info == nullptr) return static_cast(-1); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lock(fInfo->m_lock); - if ( fInfo->m_handle == -1 ) return static_cast(-1); + if (fInfo->m_handle == -1) return static_cast(-1); size_t byteSize = count * charSize; @@ -502,18 +524,19 @@ size_t _putn_fsb(Concurrency::streams::details::_file_info *info, Concurrency::s /// The file info record of the file /// A pointer to the callback interface to invoke when the write request is completed. /// True if the request was initiated -bool _sync_fsb(Concurrency::streams::details::_file_info *info, Concurrency::streams::details::_filestream_callback *callback) +bool _sync_fsb(Concurrency::streams::details::_file_info* info, + Concurrency::streams::details::_filestream_callback* callback) { - if ( callback == nullptr ) return false; - if ( info == nullptr ) return false; + if (callback == nullptr) return false; + if (info == nullptr) return false; - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lock(fInfo->m_lock); - if ( fInfo->m_handle == -1 ) return false; + if (fInfo->m_handle == -1) return false; - if ( fInfo->m_outstanding_writes > 0 ) + if (fInfo->m_outstanding_writes > 0) fInfo->m_sync_waiters.push_back(callback); else callback->on_completed(0); @@ -527,17 +550,17 @@ bool _sync_fsb(Concurrency::streams::details::_file_info *info, Concurrency::str /// The file info record of the file /// The new position (offset from the start) in the file stream /// New file position or -1 if error -size_t _seekrdtoend_fsb(Concurrency::streams::details::_file_info *info, int64_t offset, size_t char_size) +size_t _seekrdtoend_fsb(Concurrency::streams::details::_file_info* info, int64_t offset, size_t char_size) { - if ( info == nullptr ) return static_cast(-1); + if (info == nullptr) return static_cast(-1); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lock(info->m_lock); - if ( fInfo->m_handle == -1 ) return static_cast(-1); + if (fInfo->m_handle == -1) return static_cast(-1); - if ( fInfo->m_buffer != nullptr ) + if (fInfo->m_buffer != nullptr) { delete[] fInfo->m_buffer; fInfo->m_buffer = nullptr; @@ -546,23 +569,23 @@ size_t _seekrdtoend_fsb(Concurrency::streams::details::_file_info *info, int64_t auto newpos = lseek(fInfo->m_handle, static_cast(offset * char_size), SEEK_END); - if ( newpos == -1 ) return static_cast(-1); + if (newpos == -1) return static_cast(-1); - fInfo->m_rdpos = static_cast (newpos) / char_size; + fInfo->m_rdpos = static_cast(newpos) / char_size; return fInfo->m_rdpos; } -utility::size64_t _get_size(_In_ concurrency::streams::details::_file_info *info, size_t char_size) +utility::size64_t _get_size(_In_ concurrency::streams::details::_file_info* info, size_t char_size) { - if ( info == nullptr ) return static_cast(-1); + if (info == nullptr) return static_cast(-1); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lock(info->m_lock); - if ( fInfo->m_handle == -1 ) return static_cast(-1); + if (fInfo->m_handle == -1) return static_cast(-1); - if ( fInfo->m_buffer != nullptr ) + if (fInfo->m_buffer != nullptr) { delete[] fInfo->m_buffer; fInfo->m_buffer = nullptr; @@ -571,11 +594,11 @@ utility::size64_t _get_size(_In_ concurrency::streams::details::_file_info *info auto oldpos = lseek(fInfo->m_handle, 0, SEEK_CUR); - if ( oldpos == -1 ) return utility::size64_t(-1); + if (oldpos == -1) return utility::size64_t(-1); auto newpos = lseek(fInfo->m_handle, 0, SEEK_END); - if ( newpos == -1 ) return utility::size64_t(-1); + if (newpos == -1) return utility::size64_t(-1); lseek(fInfo->m_handle, oldpos, SEEK_SET); @@ -588,17 +611,17 @@ utility::size64_t _get_size(_In_ concurrency::streams::details::_file_info *info /// The file info record of the file /// The new position (offset from the start) in the file stream /// New file position or -1 if error -size_t _seekrdpos_fsb(Concurrency::streams::details::_file_info *info, size_t pos, size_t) +size_t _seekrdpos_fsb(Concurrency::streams::details::_file_info* info, size_t pos, size_t) { - if ( info == nullptr ) return static_cast(-1); + if (info == nullptr) return static_cast(-1); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lock(info->m_lock); - if ( fInfo->m_handle == -1 ) return static_cast(-1); + if (fInfo->m_handle == -1) return static_cast(-1); - if ( pos < fInfo->m_bufoff || pos > (fInfo->m_bufoff+fInfo->m_buffill) ) + if (pos < fInfo->m_bufoff || pos > (fInfo->m_bufoff + fInfo->m_buffill)) { delete[] fInfo->m_buffer; fInfo->m_buffer = nullptr; @@ -615,15 +638,15 @@ size_t _seekrdpos_fsb(Concurrency::streams::details::_file_info *info, size_t po /// The file info record of the file /// The new position (offset from the start) in the file stream /// New file position or -1 if error -size_t _seekwrpos_fsb(Concurrency::streams::details::_file_info *info, size_t pos, size_t) +size_t _seekwrpos_fsb(Concurrency::streams::details::_file_info* info, size_t pos, size_t) { - if ( info == nullptr ) return static_cast(-1); + if (info == nullptr) return static_cast(-1); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lock(info->m_lock); - if ( fInfo->m_handle == -1 ) return static_cast(-1); + if (fInfo->m_handle == -1) return static_cast(-1); fInfo->m_wrpos = pos; return fInfo->m_wrpos; diff --git a/Release/src/streams/fileio_win32.cpp b/Release/src/streams/fileio_win32.cpp index cebe72a171..3972a707cc 100644 --- a/Release/src/streams/fileio_win32.cpp +++ b/Release/src/streams/fileio_win32.cpp @@ -1,21 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Asynchronous I/O: stream buffer implementation details -* -* We're going to some lengths to avoid exporting C++ class member functions and implementation details across -* module boundaries, and the factoring requires that we keep the implementation details away from the main header -* files. The supporting functions, which are in this file, use C-like signatures to avoid as many issues as -* possible. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Asynchronous I/O: stream buffer implementation details + * + * We're going to some lengths to avoid exporting C++ class member functions and implementation details across + * module boundaries, and the factoring requires that we keep the implementation details away from the main header + * files. The supporting functions, which are in this file, use C-like signatures to avoid as many issues as + * possible. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/details/fileio.h" using namespace web; @@ -23,16 +24,19 @@ using namespace utility; using namespace concurrency; using namespace utility::conversions; -namespace Concurrency { namespace streams { namespace details { - +namespace Concurrency +{ +namespace streams +{ +namespace details +{ /*** -* ==++== -* -* Implementation details of the file stream buffer -* -* =-=-=- -****/ - + * ==++== + * + * Implementation details of the file stream buffer + * + * =-=-=- + ****/ /// /// The public parts of the file information record contain only what is implementation- @@ -41,25 +45,25 @@ namespace Concurrency { namespace streams { namespace details { /// struct _file_info_impl : _file_info { - _file_info_impl(HANDLE handle, _In_ void *io_ctxt, std::ios_base::openmode mode, size_t buffer_size) : - _file_info(mode, buffer_size), - m_io_context(io_ctxt), - m_handle(handle) + _file_info_impl(HANDLE handle, _In_ void* io_ctxt, std::ios_base::openmode mode, size_t buffer_size) + : _file_info(mode, buffer_size), m_io_context(io_ctxt), m_handle(handle) { } /// /// The Win32 file handle of the file /// - HANDLE m_handle; + HANDLE m_handle; /// /// A Win32 I/O context, used by the thread pool to scheduler work. /// - void *m_io_context; + void* m_io_context; }; -}}} +} // namespace details +} // namespace streams +} // namespace Concurrency using namespace streams::details; @@ -72,44 +76,40 @@ using namespace streams::details; /// struct EXTENDED_OVERLAPPED : OVERLAPPED { - EXTENDED_OVERLAPPED(LPOVERLAPPED_COMPLETION_ROUTINE func, streams::details::_filestream_callback *cb) : callback(cb), func(func) + EXTENDED_OVERLAPPED(LPOVERLAPPED_COMPLETION_ROUTINE func, streams::details::_filestream_callback* cb) + : callback(cb), func(func) { ZeroMemory(this, sizeof(OVERLAPPED)); } - streams::details::_filestream_callback *callback; + streams::details::_filestream_callback* callback; LPOVERLAPPED_COMPLETION_ROUTINE func; }; #if _WIN32_WINNT < _WIN32_WINNT_VISTA -void CALLBACK IoCompletionCallback( - DWORD dwErrorCode, - DWORD dwNumberOfBytesTransfered, - LPOVERLAPPED pOverlapped) +void CALLBACK IoCompletionCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED pOverlapped) { - EXTENDED_OVERLAPPED *pExtOverlapped = static_cast(pOverlapped); + EXTENDED_OVERLAPPED* pExtOverlapped = static_cast(pOverlapped); ////If dwErrorCode is 0xc0000011, it means STATUS_END_OF_FILE. ////Map this error code to system error code:ERROR_HANDLE_EOF - if (dwErrorCode == 0xc0000011) - dwErrorCode = ERROR_HANDLE_EOF; + if (dwErrorCode == 0xc0000011) dwErrorCode = ERROR_HANDLE_EOF; pExtOverlapped->func(dwErrorCode, dwNumberOfBytesTransfered, pOverlapped); delete pOverlapped; } #else -void CALLBACK IoCompletionCallback( - PTP_CALLBACK_INSTANCE instance, - PVOID ctxt, - PVOID pOverlapped, - ULONG result, - ULONG_PTR numberOfBytesTransferred, - PTP_IO io) +void CALLBACK IoCompletionCallback(PTP_CALLBACK_INSTANCE instance, + PVOID ctxt, + PVOID pOverlapped, + ULONG result, + ULONG_PTR numberOfBytesTransferred, + PTP_IO io) { CASABLANCA_UNREFERENCED_PARAMETER(io); CASABLANCA_UNREFERENCED_PARAMETER(ctxt); CASABLANCA_UNREFERENCED_PARAMETER(instance); - EXTENDED_OVERLAPPED *pExtOverlapped = static_cast(pOverlapped); + EXTENDED_OVERLAPPED* pExtOverlapped = static_cast(pOverlapped); pExtOverlapped->func(result, static_cast(numberOfBytesTransferred), static_cast(pOverlapped)); delete pOverlapped; } @@ -123,20 +123,21 @@ void CALLBACK IoCompletionCallback( /// A pointer to a DWORD that will hold the desired access flags /// A pointer to a DWORD that will hold the creation disposition /// A pointer to a DWORD that will hold the share mode -void _get_create_flags(std::ios_base::openmode mode, int prot, DWORD &dwDesiredAccess, DWORD &dwCreationDisposition, DWORD &dwShareMode) +void _get_create_flags( + std::ios_base::openmode mode, int prot, DWORD& dwDesiredAccess, DWORD& dwCreationDisposition, DWORD& dwShareMode) { dwDesiredAccess = 0x0; - if ( mode & std::ios_base::in ) dwDesiredAccess |= GENERIC_READ; - if ( mode & std::ios_base::out ) dwDesiredAccess |= GENERIC_WRITE; + if (mode & std::ios_base::in) dwDesiredAccess |= GENERIC_READ; + if (mode & std::ios_base::out) dwDesiredAccess |= GENERIC_WRITE; - if ( mode & std::ios_base::in ) + if (mode & std::ios_base::in) { - if ( mode & std::ios_base::out ) + if (mode & std::ios_base::out) dwCreationDisposition = OPEN_ALWAYS; else dwCreationDisposition = OPEN_EXISTING; } - else if ( mode & std::ios_base::trunc ) + else if (mode & std::ios_base::trunc) { dwCreationDisposition = CREATE_ALWAYS; } @@ -149,15 +150,9 @@ void _get_create_flags(std::ios_base::openmode mode, int prot, DWORD &dwDesiredA dwShareMode = 0x3; switch (prot) { - case _SH_DENYRW: - dwShareMode = 0x0; - break; - case _SH_DENYWR: - dwShareMode = 0x1; - break; - case _SH_DENYRD: - dwShareMode = 0x2; - break; + case _SH_DENYRW: dwShareMode = 0x0; break; + case _SH_DENYWR: dwShareMode = 0x1; break; + case _SH_DENYRD: dwShareMode = 0x2; break; } } @@ -167,7 +162,7 @@ void _get_create_flags(std::ios_base::openmode mode, int prot, DWORD &dwDesiredA /// The Win32 file handle /// The callback interface pointer /// The C++ file open mode -void _finish_create(HANDLE fh, _In_ _filestream_callback *callback, std::ios_base::openmode mode, int prot) +void _finish_create(HANDLE fh, _In_ _filestream_callback* callback, std::ios_base::openmode mode, int prot) { if (fh == INVALID_HANDLE_VALUE) { @@ -175,7 +170,7 @@ void _finish_create(HANDLE fh, _In_ _filestream_callback *callback, std::ios_bas return; } - void *io_ctxt = nullptr; + void* io_ctxt = nullptr; #if _WIN32_WINNT < _WIN32_WINNT_VISTA if (!BindIoCompletionCallback(fh, IoCompletionCallback, 0)) { @@ -225,19 +220,22 @@ void _finish_create(HANDLE fh, _In_ _filestream_callback *callback, std::ios_bas /// /// True does not signal that the file will eventually be successfully opened, just that the process was started. /// -bool __cdecl _open_fsb_str(_In_ _filestream_callback *callback, const utility::char_t *filename, std::ios_base::openmode mode, int prot) +bool __cdecl _open_fsb_str(_In_ _filestream_callback* callback, + const utility::char_t* filename, + std::ios_base::openmode mode, + int prot) { _ASSERTE(callback != nullptr); _ASSERTE(filename != nullptr); std::wstring name(filename); - pplx::create_task([=]() - { + pplx::create_task([=]() { DWORD dwDesiredAccess, dwCreationDisposition, dwShareMode; _get_create_flags(mode, prot, dwDesiredAccess, dwCreationDisposition, dwShareMode); - HANDLE fh = ::CreateFileW(name.c_str(), dwDesiredAccess, dwShareMode, nullptr, dwCreationDisposition, FILE_FLAG_OVERLAPPED, 0); + HANDLE fh = ::CreateFileW( + name.c_str(), dwDesiredAccess, dwShareMode, nullptr, dwCreationDisposition, FILE_FLAG_OVERLAPPED, 0); _finish_create(fh, callback, mode, prot); }); @@ -254,21 +252,20 @@ bool __cdecl _open_fsb_str(_In_ _filestream_callback *callback, const utility::c /// /// True does not signal that the file will eventually be successfully closed, just that the process was started. /// -bool __cdecl _close_fsb_nolock(_In_ _file_info **info, _In_ streams::details::_filestream_callback *callback) +bool __cdecl _close_fsb_nolock(_In_ _file_info** info, _In_ streams::details::_filestream_callback* callback) { _ASSERTE(callback != nullptr); _ASSERTE(info != nullptr); _ASSERTE(*info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(*info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(*info); - if ( fInfo->m_handle == INVALID_HANDLE_VALUE ) return false; + if (fInfo->m_handle == INVALID_HANDLE_VALUE) return false; // Since closing a file may involve waiting for outstanding writes which can take some time // if the file is on a network share, the close action is done in a separate task, as // CloseHandle doesn't have I/O completion events. - pplx::create_task([=]() - { + pplx::create_task([=]() { bool result = false; { @@ -299,7 +296,7 @@ bool __cdecl _close_fsb_nolock(_In_ _file_info **info, _In_ streams::details::_f return true; } -bool __cdecl _close_fsb(_In_ _file_info **info, _In_ streams::details::_filestream_callback *callback) +bool __cdecl _close_fsb(_In_ _file_info** info, _In_ streams::details::_filestream_callback* callback) { _ASSERTE(callback != nullptr); _ASSERTE(info != nullptr); @@ -317,7 +314,7 @@ bool __cdecl _close_fsb(_In_ _file_info **info, _In_ streams::details::_filestre template VOID CALLBACK _WriteFileCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) { - EXTENDED_OVERLAPPED* pOverlapped = static_cast(lpOverlapped); + EXTENDED_OVERLAPPED* pOverlapped = static_cast(lpOverlapped); if (dwErrorCode != ERROR_SUCCESS && dwErrorCode != ERROR_HANDLE_EOF) { @@ -338,7 +335,7 @@ VOID CALLBACK _WriteFileCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfByt template VOID CALLBACK _ReadFileCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) { - EXTENDED_OVERLAPPED* pOverlapped = static_cast(lpOverlapped); + EXTENDED_OVERLAPPED* pOverlapped = static_cast(lpOverlapped); if (dwErrorCode != ERROR_SUCCESS && dwErrorCode != ERROR_HANDLE_EOF) { @@ -357,10 +354,16 @@ VOID CALLBACK _ReadFileCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfByte /// A pointer to the callback interface to invoke when the write request is completed. /// A pointer to the data to write /// The size (in bytes) of the data -/// 0 if the write request is still outstanding, -1 if the request failed, otherwise the size of the data written -size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ streams::details::_filestream_callback *callback, const void *ptr, size_t count, size_t position) +/// 0 if the write request is still outstanding, -1 if the request failed, otherwise the size of the data +/// written +size_t _write_file_async(_In_ streams::details::_file_info_impl* fInfo, + _In_ streams::details::_filestream_callback* callback, + const void* ptr, + size_t count, + size_t position) { - auto pOverlapped = std::unique_ptr(new EXTENDED_OVERLAPPED(_WriteFileCompletionRoutine, callback)); + auto pOverlapped = std::unique_ptr( + new EXTENDED_OVERLAPPED(_WriteFileCompletionRoutine, callback)); if (position == static_cast(-1)) { @@ -396,13 +399,14 @@ size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ str size_t result = static_cast(-1); - if ( wrResult == TRUE ) + if (wrResult == TRUE) { // If WriteFile returned true, it must be because the operation completed immediately. // However, we didn't pass in an address for the number of bytes written, so // we have to retrieve it using 'GetOverlappedResult,' which may, in turn, fail. DWORD written = 0; - result = GetOverlappedResult(fInfo->m_handle, pOverlapped.get(), &written, FALSE) ? static_cast(written) : static_cast(-1); + result = GetOverlappedResult(fInfo->m_handle, pOverlapped.get(), &written, FALSE) ? static_cast(written) + : static_cast(-1); } if (result == static_cast(-1)) @@ -415,11 +419,12 @@ size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ str // 1. If WriteFile returned true, it must be because the operation completed immediately. // The xp threadpool immediately creates a workerthread to run "_WriteFileCompletionRoutine". - // If this function return value > 0, the condition "if (written == sizeof(_CharType))" in the filestreams.h "_getcImpl()" function will be satisfied. - // The main thread will delete the input "callback", while the threadpool workerthread is accessing this "callback"; there will be a race condition and AV error. - // We directly return 0 and leave all the completion callbacks working on the workerthread. - // We do not need to call GetOverlappedResult, the workerthread will call the "on_error()" if the WriteFaile failed. - // "req" is deleted in "_WriteFileCompletionRoutine, "pOverlapped" is deleted in io_scheduler::FileIOCompletionRoutine. + // If this function return value > 0, the condition "if (written == sizeof(_CharType))" in the filestreams.h + // "_getcImpl()" function will be satisfied. The main thread will delete the input "callback", while the threadpool + // workerthread is accessing this "callback"; there will be a race condition and AV error. We directly return 0 and + // leave all the completion callbacks working on the workerthread. We do not need to call GetOverlappedResult, the + // workerthread will call the "on_error()" if the WriteFaile failed. "req" is deleted in + // "_WriteFileCompletionRoutine, "pOverlapped" is deleted in io_scheduler::FileIOCompletionRoutine. if (wrResult == TRUE) { pOverlapped.release(); @@ -427,7 +432,8 @@ size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ str } // 2. If WriteFile returned false and GetLastError is ERROR_IO_PENDING, return 0, - // The xp threadpool will create a workerthread to run "_WriteFileCompletionRoutine" after the operation completed. + // The xp threadpool will create a workerthread to run "_WriteFileCompletionRoutine" after the operation + // completed. if (wrResult == FALSE && error == ERROR_IO_PENDING) { // Overlapped is deleted in the threadpool callback. @@ -451,10 +457,16 @@ size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ str /// A pointer to a buffer where the data should be placed /// The size (in bytes) of the buffer /// The offset in the file to read from -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -size_t _read_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ streams::details::_filestream_callback *callback, _Out_writes_ (count) void *ptr, _In_ size_t count, size_t offset) +/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read +/// into the buffer +size_t _read_file_async(_In_ streams::details::_file_info_impl* fInfo, + _In_ streams::details::_filestream_callback* callback, + _Out_writes_(count) void* ptr, + _In_ size_t count, + size_t offset) { - auto pOverlapped = std::unique_ptr(new EXTENDED_OVERLAPPED(_ReadFileCompletionRoutine, callback)); + auto pOverlapped = std::unique_ptr( + new EXTENDED_OVERLAPPED(_ReadFileCompletionRoutine, callback)); pOverlapped->Offset = static_cast(offset); #ifdef _WIN64 pOverlapped->OffsetHigh = static_cast(offset >> 32); @@ -490,7 +502,8 @@ size_t _read_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ stre // However, we didn't pass in an address for the number of bytes written, so // we have to retrieve it using 'GetOverlappedResult,' which may, in turn, fail. DWORD read = 0; - result = GetOverlappedResult(fInfo->m_handle, pOverlapped.get(), &read, FALSE) ? static_cast(read) : static_cast(-1); + result = GetOverlappedResult(fInfo->m_handle, pOverlapped.get(), &read, FALSE) ? static_cast(read) + : static_cast(-1); } if (wrResult == FALSE && error == ERROR_HANDLE_EOF) @@ -509,11 +522,12 @@ size_t _read_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ stre // 1. If ReadFile returned true, it must be because the operation completed immediately. // The xp threadpool immediately creates a workerthread to run "_WriteFileCompletionRoutine". - // If this function return value > 0, the condition "if ( ch == sizeof(_CharType) )" in the filestreams.h "_getcImpl()" function will be satisfied. - // The main thread will delete the input "callback", while the threadpool workerthread is accessing this "callback"; there will be a race condition and AV error. - // We can directly return 0 and leave all the completion callbacks working on the workerthread. - // We do not need to call GetOverlappedResult, the workerthread will call the "on_error()" if the ReadFile failed. - // "req" is deleted in "_ReadFileCompletionRoutine, "pOverlapped" is deleted in io_scheduler::FileIOCompletionRoutine. + // If this function return value > 0, the condition "if ( ch == sizeof(_CharType) )" in the filestreams.h + // "_getcImpl()" function will be satisfied. The main thread will delete the input "callback", while the threadpool + // workerthread is accessing this "callback"; there will be a race condition and AV error. We can directly return 0 + // and leave all the completion callbacks working on the workerthread. We do not need to call GetOverlappedResult, + // the workerthread will call the "on_error()" if the ReadFile failed. "req" is deleted in + // "_ReadFileCompletionRoutine, "pOverlapped" is deleted in io_scheduler::FileIOCompletionRoutine. if (wrResult == TRUE) { pOverlapped.release(); @@ -521,7 +535,8 @@ size_t _read_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ stre } // 2. If ReadFile returned false and GetLastError is ERROR_IO_PENDING, return 0. - // The xp threadpool will create a workerthread to run "_WriteFileCompletionRoutine" after the operation completed. + // The xp threadpool will create a workerthread to run "_WriteFileCompletionRoutine" after the operation + // completed. if (wrResult == FALSE && error == ERROR_IO_PENDING) { // Overlapped is deleted in the threadpool callback. @@ -549,7 +564,7 @@ template class _filestream_callback_fill_buffer : public _filestream_callback { public: - _filestream_callback_fill_buffer(_In_ _file_info *info, const Func &func) : m_func(func), m_info(info) { } + _filestream_callback_fill_buffer(_In_ _file_info* info, const Func& func) : m_func(func), m_info(info) {} virtual void on_completed(size_t result) { @@ -558,58 +573,62 @@ class _filestream_callback_fill_buffer : public _filestream_callback } private: - _file_info *m_info; - Func m_func; + _file_info* m_info; + Func m_func; }; template -_filestream_callback_fill_buffer *create_callback(_In_ _file_info *info, const Func &func) +_filestream_callback_fill_buffer* create_callback(_In_ _file_info* info, const Func& func) { return new _filestream_callback_fill_buffer(info, func); } -size_t _fill_buffer_fsb(_In_ _file_info_impl *fInfo, _In_ _filestream_callback *callback, size_t count, size_t char_size) +size_t _fill_buffer_fsb(_In_ _file_info_impl* fInfo, + _In_ _filestream_callback* callback, + size_t count, + size_t char_size) { msl::safeint3::SafeInt safeCount = count; - if ( fInfo->m_buffer == nullptr || safeCount > fInfo->m_bufsize ) + if (fInfo->m_buffer == nullptr || safeCount > fInfo->m_bufsize) { - if ( fInfo->m_buffer != nullptr ) - delete fInfo->m_buffer; + if (fInfo->m_buffer != nullptr) delete fInfo->m_buffer; fInfo->m_bufsize = safeCount.Max(fInfo->m_buffer_size); - fInfo->m_buffer = new char[fInfo->m_bufsize*char_size]; + fInfo->m_buffer = new char[fInfo->m_bufsize * char_size]; fInfo->m_bufoff = fInfo->m_rdpos; - auto cb = create_callback(fInfo, - [=] (size_t result) - { - pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); - fInfo->m_buffill = result/char_size; - callback->on_completed(result); - }); + auto cb = create_callback(fInfo, [=](size_t result) { + pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); + fInfo->m_buffill = result / char_size; + callback->on_completed(result); + }); - auto read = _read_file_async(fInfo, cb, reinterpret_cast(fInfo->m_buffer), fInfo->m_bufsize*char_size, fInfo->m_rdpos*char_size); + auto read = _read_file_async(fInfo, + cb, + reinterpret_cast(fInfo->m_buffer), + fInfo->m_bufsize * char_size, + fInfo->m_rdpos * char_size); switch (read) { - case 0: - // pending - return read; - - case (-1): - // error - delete cb; - return read; - - default: - // operation is complete. The pattern of returning synchronously - // has the expectation that we duplicate the callback code here... - // Do the expedient thing for now. - cb->on_completed(read); - - // return pending - return 0; + case 0: + // pending + return read; + + case (-1): + // error + delete cb; + return read; + + default: + // operation is complete. The pattern of returning synchronously + // has the expectation that we duplicate the callback code here... + // Do the expedient thing for now. + cb->on_completed(read); + + // return pending + return 0; }; } @@ -625,55 +644,56 @@ size_t _fill_buffer_fsb(_In_ _file_info_impl *fInfo, _In_ _filestream_callback * // 3. The read position is beyond the end of the buffer. Do as in #1. // 4. We have everything we need. - if ( (fInfo->m_rdpos < fInfo->m_bufoff) || (fInfo->m_rdpos >= (fInfo->m_bufoff+fInfo->m_buffill)) ) + if ((fInfo->m_rdpos < fInfo->m_bufoff) || (fInfo->m_rdpos >= (fInfo->m_bufoff + fInfo->m_buffill))) { // Reuse the existing buffer. fInfo->m_bufoff = fInfo->m_rdpos; - auto cb = create_callback(fInfo, - [=] (size_t result) - { - pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); - fInfo->m_buffill = result/char_size; - callback->on_completed(bufrem*char_size+result); - }); + auto cb = create_callback(fInfo, [=](size_t result) { + pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); + fInfo->m_buffill = result / char_size; + callback->on_completed(bufrem * char_size + result); + }); - auto read = _read_file_async(fInfo, cb, reinterpret_cast(fInfo->m_buffer), fInfo->m_bufsize*char_size, fInfo->m_rdpos*char_size); + auto read = _read_file_async(fInfo, + cb, + reinterpret_cast(fInfo->m_buffer), + fInfo->m_bufsize * char_size, + fInfo->m_rdpos * char_size); switch (read) { - case 0: - // pending - return read; - - case (-1): - // error - delete cb; - return read; - - default: - // operation is complete. The pattern of returning synchronously - // has the expectation that we duplicate the callback code here... - // Do the expedient thing for now. - cb->on_completed(read); - - // return pending - return 0; + case 0: + // pending + return read; + + case (-1): + // error + delete cb; + return read; + + default: + // operation is complete. The pattern of returning synchronously + // has the expectation that we duplicate the callback code here... + // Do the expedient thing for now. + cb->on_completed(read); + + // return pending + return 0; }; } - else if ( bufrem < count ) + else if (bufrem < count) { fInfo->m_bufsize = safeCount.Max(fInfo->m_buffer_size); // Then, we allocate a new buffer. - char *newbuf = new char[fInfo->m_bufsize*char_size]; + char* newbuf = new char[fInfo->m_bufsize * char_size]; // Then, we copy the unread part to the new buffer and delete the old buffer - if ( bufrem > 0 ) - memcpy(newbuf, fInfo->m_buffer+bufpos*char_size, bufrem*char_size); + if (bufrem > 0) memcpy(newbuf, fInfo->m_buffer + bufpos * char_size, bufrem * char_size); delete fInfo->m_buffer; fInfo->m_buffer = newbuf; @@ -681,45 +701,46 @@ size_t _fill_buffer_fsb(_In_ _file_info_impl *fInfo, _In_ _filestream_callback * // Then, we read the remainder of the count into the new buffer fInfo->m_bufoff = fInfo->m_rdpos; - auto cb = create_callback(fInfo, - [=] (size_t result) - { - pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); - fInfo->m_buffill = result/char_size; - callback->on_completed(bufrem*char_size+result); - }); + auto cb = create_callback(fInfo, [=](size_t result) { + pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); + fInfo->m_buffill = result / char_size; + callback->on_completed(bufrem * char_size + result); + }); - auto read = _read_file_async(fInfo, cb, reinterpret_cast(fInfo->m_buffer) + bufrem*char_size, (fInfo->m_bufsize - bufrem)*char_size, (fInfo->m_rdpos + bufrem)*char_size); + auto read = _read_file_async(fInfo, + cb, + reinterpret_cast(fInfo->m_buffer) + bufrem * char_size, + (fInfo->m_bufsize - bufrem) * char_size, + (fInfo->m_rdpos + bufrem) * char_size); switch (read) { - case 0: - // pending - return read; - - case (-1): - // error - delete cb; - return read; - - default: - // operation is complete. The pattern of returning synchronously - // has the expectation that we duplicate the callback code here... - // Do the expedient thing for now. - cb->on_completed(read); - - // return pending - return 0; + case 0: + // pending + return read; + + case (-1): + // error + delete cb; + return read; + + default: + // operation is complete. The pattern of returning synchronously + // has the expectation that we duplicate the callback code here... + // Do the expedient thing for now. + cb->on_completed(read); + + // return pending + return 0; }; } else { // If we are here, it means that we didn't need to read, we already have enough data in the buffer - return count*char_size; + return count * char_size; } } - /// /// Read data from a file stream into a buffer /// @@ -727,43 +748,46 @@ size_t _fill_buffer_fsb(_In_ _file_info_impl *fInfo, _In_ _filestream_callback * /// A pointer to the callback interface to invoke when the write request is completed. /// A pointer to a buffer where the data should be placed /// The size (in characters) of the buffer -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -size_t __cdecl _getn_fsb(_In_ streams::details::_file_info *info, _In_ streams::details::_filestream_callback *callback, _Out_writes_ (count) void *ptr, _In_ size_t count, size_t char_size) +/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read +/// into the buffer +size_t __cdecl _getn_fsb(_In_ streams::details::_file_info* info, + _In_ streams::details::_filestream_callback* callback, + _Out_writes_(count) void* ptr, + _In_ size_t count, + size_t char_size) { _ASSERTE(callback != nullptr); _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(info->m_lock); - if ( fInfo->m_handle == INVALID_HANDLE_VALUE ) + if (fInfo->m_handle == INVALID_HANDLE_VALUE) { callback->on_error(std::make_exception_ptr(utility::details::create_system_error(ERROR_INVALID_HANDLE))); return (size_t)-1; } - if ( fInfo->m_buffer_size > 0 ) + if (fInfo->m_buffer_size > 0) { - auto cb = create_callback(fInfo, - [=] (size_t read) - { - auto sz = count*char_size; - auto copy = (read < sz) ? read : sz; - auto bufoff = fInfo->m_rdpos - fInfo->m_bufoff; - memcpy(ptr, fInfo->m_buffer+bufoff*char_size, copy); - fInfo->m_atend = copy < sz; - callback->on_completed(copy); - }); + auto cb = create_callback(fInfo, [=](size_t read) { + auto sz = count * char_size; + auto copy = (read < sz) ? read : sz; + auto bufoff = fInfo->m_rdpos - fInfo->m_bufoff; + memcpy(ptr, fInfo->m_buffer + bufoff * char_size, copy); + fInfo->m_atend = copy < sz; + callback->on_completed(copy); + }); size_t read = _fill_buffer_fsb(fInfo, cb, count, char_size); - if ( read > 0 ) + if (read > 0) { - auto sz = count*char_size; + auto sz = count * char_size; auto copy = (read < sz) ? read : sz; auto bufoff = fInfo->m_rdpos - fInfo->m_bufoff; - memcpy(ptr, fInfo->m_buffer+bufoff*char_size, copy); + memcpy(ptr, fInfo->m_buffer + bufoff * char_size, copy); fInfo->m_atend = copy < sz; return copy; } @@ -772,7 +796,7 @@ size_t __cdecl _getn_fsb(_In_ streams::details::_file_info *info, _In_ streams:: } else { - return _read_file_async(fInfo, callback, ptr, count*char_size, fInfo->m_rdpos*char_size); + return _read_file_async(fInfo, callback, ptr, count * char_size, fInfo->m_rdpos * char_size); } } @@ -783,16 +807,21 @@ size_t __cdecl _getn_fsb(_In_ streams::details::_file_info *info, _In_ streams:: /// A pointer to the callback interface to invoke when the write request is completed. /// A pointer to a buffer where the data should be placed /// The size (in characters) of the buffer -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -size_t __cdecl _putn_fsb(_In_ streams::details::_file_info *info, _In_ streams::details::_filestream_callback *callback, const void *ptr, size_t count, size_t char_size) +/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read +/// into the buffer +size_t __cdecl _putn_fsb(_In_ streams::details::_file_info* info, + _In_ streams::details::_filestream_callback* callback, + const void* ptr, + size_t count, + size_t char_size) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); - if ( fInfo->m_handle == INVALID_HANDLE_VALUE ) + if (fInfo->m_handle == INVALID_HANDLE_VALUE) { callback->on_error(std::make_exception_ptr(utility::details::create_system_error(ERROR_INVALID_HANDLE))); return static_cast(-1); @@ -805,7 +834,7 @@ size_t __cdecl _putn_fsb(_In_ streams::details::_file_info *info, _In_ streams:: fInfo->m_wrpos += count; lastPos *= char_size; } - return _write_file_async(fInfo, callback, ptr, count*char_size, lastPos); + return _write_file_async(fInfo, callback, ptr, count * char_size, lastPos); } /// @@ -814,7 +843,7 @@ size_t __cdecl _putn_fsb(_In_ streams::details::_file_info *info, _In_ streams:: /// The file info record of the file /// A pointer to the callback interface to invoke when the write request is completed. /// true if the request was initiated -bool __cdecl _sync_fsb(_In_ streams::details::_file_info *, _In_ streams::details::_filestream_callback *callback) +bool __cdecl _sync_fsb(_In_ streams::details::_file_info*, _In_ streams::details::_filestream_callback* callback) { _ASSERTE(callback != nullptr); @@ -830,17 +859,17 @@ bool __cdecl _sync_fsb(_In_ streams::details::_file_info *, _In_ streams::detail /// The file info record of the file /// The new position (offset from the start) in the file stream /// New file position or -1 if error -size_t __cdecl _seekrdpos_fsb(_In_ streams::details::_file_info *info, size_t pos, size_t) +size_t __cdecl _seekrdpos_fsb(_In_ streams::details::_file_info* info, size_t pos, size_t) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(info->m_lock); if (fInfo->m_handle == INVALID_HANDLE_VALUE) return static_cast(-1); - if ( pos < fInfo->m_bufoff || pos > (fInfo->m_bufoff+fInfo->m_buffill) ) + if (pos < fInfo->m_bufoff || pos > (fInfo->m_bufoff + fInfo->m_buffill)) { delete fInfo->m_buffer; fInfo->m_buffer = nullptr; @@ -858,17 +887,17 @@ size_t __cdecl _seekrdpos_fsb(_In_ streams::details::_file_info *info, size_t po /// The new position (offset from the end of the stream) in the file stream /// The size of the character type used for this stream /// New file position or -1 if error -size_t __cdecl _seekrdtoend_fsb(_In_ streams::details::_file_info *info, int64_t offset, size_t char_size) +size_t __cdecl _seekrdtoend_fsb(_In_ streams::details::_file_info* info, int64_t offset, size_t char_size) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(info->m_lock); if (fInfo->m_handle == INVALID_HANDLE_VALUE) return static_cast(-1); - if ( fInfo->m_buffer != nullptr ) + if (fInfo->m_buffer != nullptr) { // Clear the internal buffer. delete fInfo->m_buffer; @@ -876,7 +905,7 @@ size_t __cdecl _seekrdtoend_fsb(_In_ streams::details::_file_info *info, int64_t fInfo->m_bufoff = fInfo->m_buffill = fInfo->m_bufsize = 0; } - auto newpos = SetFilePointer(fInfo->m_handle, (LONG)(offset*char_size), nullptr, FILE_END); + auto newpos = SetFilePointer(fInfo->m_handle, (LONG)(offset * char_size), nullptr, FILE_END); if (newpos == INVALID_SET_FILE_POINTER) return static_cast(-1); @@ -885,20 +914,20 @@ size_t __cdecl _seekrdtoend_fsb(_In_ streams::details::_file_info *info, int64_t return fInfo->m_rdpos; } -utility::size64_t __cdecl _get_size(_In_ concurrency::streams::details::_file_info *info, size_t char_size) +utility::size64_t __cdecl _get_size(_In_ concurrency::streams::details::_file_info* info, size_t char_size) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(info->m_lock); - if ( fInfo->m_handle == INVALID_HANDLE_VALUE ) return (utility::size64_t)-1; + if (fInfo->m_handle == INVALID_HANDLE_VALUE) return (utility::size64_t)-1; LARGE_INTEGER size; - if ( GetFileSizeEx(fInfo->m_handle, &size) == TRUE ) - return utility::size64_t(size.QuadPart/char_size); + if (GetFileSizeEx(fInfo->m_handle, &size) == TRUE) + return utility::size64_t(size.QuadPart / char_size); else return 0; } @@ -909,11 +938,11 @@ utility::size64_t __cdecl _get_size(_In_ concurrency::streams::details::_file_in /// The file info record of the file /// The new position (offset from the start) in the file stream /// New file position or -1 if error -size_t __cdecl _seekwrpos_fsb(_In_ streams::details::_file_info *info, size_t pos, size_t) +size_t __cdecl _seekwrpos_fsb(_In_ streams::details::_file_info* info, size_t pos, size_t) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(info->m_lock); diff --git a/Release/src/streams/fileio_winrt.cpp b/Release/src/streams/fileio_winrt.cpp index 65723af3b3..ef6a588ae8 100644 --- a/Release/src/streams/fileio_winrt.cpp +++ b/Release/src/streams/fileio_winrt.cpp @@ -1,21 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Asynchronous I/O: stream buffer implementation details -* -* We're going to some lengths to avoid exporting C++ class member functions and implementation details across -* module boundaries, and the factoring requires that we keep the implementation details away from the main header -* files. The supporting functions, which are in this file, use C-like signatures to avoid as many issues as -* possible. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Asynchronous I/O: stream buffer implementation details + * + * We're going to some lengths to avoid exporting C++ class member functions and implementation details across + * module boundaries, and the factoring requires that we keep the implementation details away from the main header + * files. The supporting functions, which are in this file, use C-like signatures to avoid as many issues as + * possible. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/details/fileio.h" #include "cpprest/interopstream.h" #include "robuffer.h" @@ -26,8 +27,12 @@ using namespace ::Windows::Storage::Streams; using namespace ::Windows::Networking; using namespace ::Windows::Networking::Sockets; -namespace Concurrency { namespace streams { namespace details { - +namespace Concurrency +{ +namespace streams +{ +namespace details +{ /// /// The public parts of the file information record contain only what is implementation- /// independent. The actual allocated record is larger and has details that the implementation @@ -35,28 +40,26 @@ namespace Concurrency { namespace streams { namespace details { /// struct _file_info_impl : _file_info { - _file_info_impl(Streams::IRandomAccessStream^ stream, std::ios_base::openmode mode) : - m_stream(stream), - m_writer(nullptr), - _file_info(mode, 0) + _file_info_impl(Streams::IRandomAccessStream ^ stream, std::ios_base::openmode mode) + : m_stream(stream), m_writer(nullptr), _file_info(mode, 0) { m_pendingWrites = pplx::task_from_result(); } - _file_info_impl(Streams::IRandomAccessStream^ stream, std::ios_base::openmode mode, size_t buffer_size) : - m_stream(stream), - m_writer(nullptr), - _file_info(mode, buffer_size) + _file_info_impl(Streams::IRandomAccessStream ^ stream, std::ios_base::openmode mode, size_t buffer_size) + : m_stream(stream), m_writer(nullptr), _file_info(mode, buffer_size) { m_pendingWrites = pplx::task_from_result(); } - Streams::IRandomAccessStream^ m_stream; - Streams::IDataWriter^ m_writer; + Streams::IRandomAccessStream ^ m_stream; + Streams::IDataWriter ^ m_writer; pplx::task m_pendingWrites; }; -}}} +} // namespace details +} // namespace streams +} // namespace Concurrency using namespace Concurrency::streams::details; @@ -71,15 +74,16 @@ using namespace Concurrency::streams::details; /// A pointer to a DWORD that will hold the desired access flags /// A pointer to a DWORD that will hold the creation disposition /// A pointer to a DWORD that will hold the share mode -void _get_create_flags(std::ios_base::openmode mode, int prot, FileAccessMode &acc_mode, CreationCollisionOption &options) +void _get_create_flags(std::ios_base::openmode mode, + int prot, + FileAccessMode& acc_mode, + CreationCollisionOption& options) { options = CreationCollisionOption::OpenIfExists; acc_mode = FileAccessMode::ReadWrite; - if ( (mode & std::ios_base::in) && !(mode & std::ios_base::out) ) - acc_mode = FileAccessMode::Read; - if ( mode & std::ios_base::trunc ) - options = CreationCollisionOption::ReplaceExisting; + if ((mode & std::ios_base::in) && !(mode & std::ios_base::out)) acc_mode = FileAccessMode::Read; + if (mode & std::ios_base::trunc) options = CreationCollisionOption::ReplaceExisting; } /// @@ -89,14 +93,17 @@ void _get_create_flags(std::ios_base::openmode mode, int prot, FileAccessMode &a /// The callback interface pointer /// The C++ file open mode /// The error code if there was an error in file creation. -void _finish_create(Streams::IRandomAccessStream^ stream, _In_ _filestream_callback *callback, std::ios_base::openmode mode, int prot) +void _finish_create(Streams::IRandomAccessStream ^ stream, + _In_ _filestream_callback* callback, + std::ios_base::openmode mode, + int prot) { - _file_info_impl *info = nullptr; + _file_info_impl* info = nullptr; info = new _file_info_impl(stream, mode, 512); // Seek to end if it's in appending write mode - if ((mode & std::ios_base::out) && (mode & std::ios_base::app || mode & std::ios_base::ate )) + if ((mode & std::ios_base::out) && (mode & std::ios_base::app || mode & std::ios_base::ate)) { _seekwrpos_fsb(info, static_cast(stream->Size), 1); } @@ -115,7 +122,10 @@ void _finish_create(Streams::IRandomAccessStream^ stream, _In_ _filestream_callb /// True does not signal that the file will eventually be successfully opened, just that the process was started. /// This is only available for WinRT. /// -bool __cdecl _open_fsb_stf_str(_In_ Concurrency::streams::details::_filestream_callback *callback, ::Windows::Storage::StorageFile^ file, std::ios_base::openmode mode, int prot) +bool __cdecl _open_fsb_stf_str(_In_ Concurrency::streams::details::_filestream_callback* callback, + ::Windows::Storage::StorageFile ^ file, + std::ios_base::openmode mode, + int prot) { _ASSERTE(callback != nullptr); _ASSERTE(file != nullptr); @@ -125,58 +135,57 @@ bool __cdecl _open_fsb_stf_str(_In_ Concurrency::streams::details::_filestream_c _get_create_flags(mode, prot, acc_mode, options); - pplx::create_task(file->OpenAsync(acc_mode)).then( - [=](pplx::task sop) + pplx::create_task(file->OpenAsync(acc_mode)).then([=](pplx::task sop) { + try { - try - { - _finish_create(sop.get(), callback, mode, prot); - } - catch(Platform::Exception^ exc) - { - callback->on_error(std::make_exception_ptr(utility::details::create_system_error(exc->HResult))); - } - }); + _finish_create(sop.get(), callback, mode, prot); + } + catch (Platform::Exception ^ exc) + { + callback->on_error(std::make_exception_ptr(utility::details::create_system_error(exc->HResult))); + } + }); return true; } -bool __cdecl _sync_fsb_winrt(_In_ Concurrency::streams::details::_file_info *info, _In_opt_ Concurrency::streams::details::_filestream_callback *callback) +bool __cdecl _sync_fsb_winrt(_In_ Concurrency::streams::details::_file_info* info, + _In_opt_ Concurrency::streams::details::_filestream_callback* callback) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); - if ( fInfo->m_stream == nullptr || fInfo->m_writer == nullptr || !fInfo->m_stream->CanWrite) - return false; + if (fInfo->m_stream == nullptr || fInfo->m_writer == nullptr || !fInfo->m_stream->CanWrite) return false; // take a snapshot of current writer, since writer can be replaced during flush auto writer = fInfo->m_writer; // Flush operation will not begin until all previous writes (StoreAsync) finished, thus it could avoid race. - fInfo->m_pendingWrites = fInfo->m_pendingWrites.then([=] { - return writer->StoreAsync(); - }).then([=](unsigned int) { - fInfo->m_buffill = 0; - return writer->FlushAsync(); - }).then([=] (pplx::task result) { - // Rethrow exception if no callback attached. - if (callback == nullptr) - result.wait(); - else - { - try - { - result.wait(); - callback->on_completed(0); - } - catch (Platform::Exception^ exc) - { - callback->on_error(std::make_exception_ptr(utility::details::create_system_error(exc->HResult))); - } - } - }); + fInfo->m_pendingWrites = fInfo->m_pendingWrites.then([=] { return writer->StoreAsync(); }) + .then([=](unsigned int) { + fInfo->m_buffill = 0; + return writer->FlushAsync(); + }) + .then([=](pplx::task result) { + // Rethrow exception if no callback attached. + if (callback == nullptr) + result.wait(); + else + { + try + { + result.wait(); + callback->on_completed(0); + } + catch (Platform::Exception ^ exc) + { + callback->on_error(std::make_exception_ptr( + utility::details::create_system_error(exc->HResult))); + } + } + }); return true; } @@ -189,13 +198,14 @@ bool __cdecl _sync_fsb_winrt(_In_ Concurrency::streams::details::_file_info *inf /// /// True does not signal that the file will eventually be successfully closed, just that the process was started. /// -bool __cdecl _close_fsb_nolock(_In_ _file_info **info, _In_ Concurrency::streams::details::_filestream_callback *callback) +bool __cdecl _close_fsb_nolock(_In_ _file_info** info, + _In_ Concurrency::streams::details::_filestream_callback* callback) { _ASSERTE(callback != nullptr); _ASSERTE(info != nullptr); _ASSERTE(*info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(*info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(*info); *info = nullptr; @@ -204,14 +214,16 @@ bool __cdecl _close_fsb_nolock(_In_ _file_info **info, _In_ Concurrency::streams if (fInfo->m_stream->CanWrite) { _sync_fsb_winrt(fInfo, nullptr); - fInfo->m_pendingWrites.then([=] (pplx::task t) { - try { + fInfo->m_pendingWrites.then([=](pplx::task t) { + try + { // The lock fInfo->m_lock must not be held at this point delete fInfo; t.wait(); callback->on_closed(); } - catch (Platform::Exception^ exc) { + catch (Platform::Exception ^ exc) + { callback->on_error(std::make_exception_ptr(utility::details::create_system_error(exc->HResult))); } }); @@ -225,12 +237,11 @@ bool __cdecl _close_fsb_nolock(_In_ _file_info **info, _In_ Concurrency::streams return true; } -bool __cdecl _close_fsb(_In_ _file_info **info, _In_ Concurrency::streams::details::_filestream_callback *callback) +bool __cdecl _close_fsb(_In_ _file_info** info, _In_ Concurrency::streams::details::_filestream_callback* callback) { return _close_fsb_nolock(info, callback); } - /// /// Initiate an asynchronous (overlapped) read from the file stream. /// @@ -239,12 +250,17 @@ bool __cdecl _close_fsb(_In_ _file_info **info, _In_ Concurrency::streams::detai /// A pointer to a buffer where the data should be placed /// The size (in bytes) of the buffer /// The offset in the file to read from -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -size_t __cdecl _read_file_async(_In_ Concurrency::streams::details::_file_info_impl *fInfo, _In_ Concurrency::streams::details::_filestream_callback *callback, _Out_writes_ (count) void *ptr, _In_ size_t count, size_t offset) +/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read +/// into the buffer +size_t __cdecl _read_file_async(_In_ Concurrency::streams::details::_file_info_impl* fInfo, + _In_ Concurrency::streams::details::_filestream_callback* callback, + _Out_writes_(count) void* ptr, + _In_ size_t count, + size_t offset) { - if ( fInfo->m_stream == nullptr ) + if (fInfo->m_stream == nullptr) { - if ( callback != nullptr ) + if (callback != nullptr) { // I don't know of a better error code, so this will have to do. callback->on_error(std::make_exception_ptr(utility::details::create_system_error(ERROR_INVALID_ADDRESS))); @@ -254,21 +270,19 @@ size_t __cdecl _read_file_async(_In_ Concurrency::streams::details::_file_info_i auto reader = ref new Streams::DataReader(fInfo->m_stream->GetInputStreamAt(offset)); - pplx::create_task(reader->LoadAsync(static_cast(count))).then( - [=](pplx::task result) - { + pplx::create_task(reader->LoadAsync(static_cast(count))).then([=](pplx::task result) { try { auto read = result.get(); if (read > 0) { - reader->ReadBytes(Platform::ArrayReference(static_cast(ptr), read)); + reader->ReadBytes(Platform::ArrayReference(static_cast(ptr), read)); } callback->on_completed(read); } - catch (Platform::Exception^ exc) + catch (Platform::Exception ^ exc) { callback->on_error(std::make_exception_ptr(utility::details::create_system_error(exc->HResult))); } @@ -277,12 +291,11 @@ size_t __cdecl _read_file_async(_In_ Concurrency::streams::details::_file_info_i return 0; } - template class _filestream_callback_fill_buffer : public _filestream_callback { public: - _filestream_callback_fill_buffer(_In_ _file_info *info, const Func &func) : m_func(func), m_info(info) { } + _filestream_callback_fill_buffer(_In_ _file_info* info, const Func& func) : m_func(func), m_info(info) {} virtual void on_completed(size_t result) { @@ -291,61 +304,61 @@ class _filestream_callback_fill_buffer : public _filestream_callback } private: - _file_info *m_info; - Func m_func; + _file_info* m_info; + Func m_func; }; template -_filestream_callback_fill_buffer *create_callback(_In_ _file_info *info, const Func &func) +_filestream_callback_fill_buffer* create_callback(_In_ _file_info* info, const Func& func) { return new _filestream_callback_fill_buffer(info, func); } -size_t _fill_buffer_fsb(_In_ _file_info_impl *fInfo, _In_ _filestream_callback *callback, size_t count, size_t char_size) +size_t _fill_buffer_fsb(_In_ _file_info_impl* fInfo, + _In_ _filestream_callback* callback, + size_t count, + size_t char_size) { msl::safeint3::SafeInt safeCount = count; - if ( fInfo->m_buffer == nullptr || safeCount > fInfo->m_bufsize ) + if (fInfo->m_buffer == nullptr || safeCount > fInfo->m_bufsize) { - if ( fInfo->m_buffer != nullptr ) - delete fInfo->m_buffer; + if (fInfo->m_buffer != nullptr) delete fInfo->m_buffer; fInfo->m_bufsize = safeCount.Max(fInfo->m_buffer_size); - fInfo->m_buffer = new char[fInfo->m_bufsize*char_size]; + fInfo->m_buffer = new char[fInfo->m_bufsize * char_size]; fInfo->m_bufoff = fInfo->m_rdpos; - auto cb = create_callback(fInfo, - [=] (size_t result) + auto cb = create_callback(fInfo, [=](size_t result) { { - { - pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); - fInfo->m_buffill = result / char_size; - } - callback->on_completed(result); - - }); + pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); + fInfo->m_buffill = result / char_size; + } + callback->on_completed(result); + }); - auto read = _read_file_async(fInfo, cb, (uint8_t *)fInfo->m_buffer, fInfo->m_bufsize*char_size, fInfo->m_rdpos*char_size); + auto read = _read_file_async( + fInfo, cb, (uint8_t*)fInfo->m_buffer, fInfo->m_bufsize * char_size, fInfo->m_rdpos * char_size); switch (read) { - case 0: - // pending - return read; - - case (-1): - // error - delete cb; - return read; - - default: - // operation is complete. The pattern of returning synchronously - // has the expectation that we duplicate the callback code here... - // Do the expedient thing for now. - cb->on_completed(read); - - // return pending - return 0; + case 0: + // pending + return read; + + case (-1): + // error + delete cb; + return read; + + default: + // operation is complete. The pattern of returning synchronously + // has the expectation that we duplicate the callback code here... + // Do the expedient thing for now. + cb->on_completed(read); + + // return pending + return 0; }; } @@ -361,57 +374,55 @@ size_t _fill_buffer_fsb(_In_ _file_info_impl *fInfo, _In_ _filestream_callback * // 3. The read position is beyond the end of the buffer. Do as in #1. // 4. We have everything we need. - if ( (fInfo->m_rdpos < fInfo->m_bufoff) || (fInfo->m_rdpos >= (fInfo->m_bufoff+fInfo->m_buffill)) ) + if ((fInfo->m_rdpos < fInfo->m_bufoff) || (fInfo->m_rdpos >= (fInfo->m_bufoff + fInfo->m_buffill))) { // Reuse the existing buffer. fInfo->m_bufoff = fInfo->m_rdpos; - auto cb = create_callback(fInfo, - [=] (size_t result) + auto cb = create_callback(fInfo, [=](size_t result) { { - { - pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); - fInfo->m_buffill = result / char_size; - } - callback->on_completed(bufrem*char_size+result); - }); + pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); + fInfo->m_buffill = result / char_size; + } + callback->on_completed(bufrem * char_size + result); + }); - auto read = _read_file_async(fInfo, cb, (uint8_t*)fInfo->m_buffer, fInfo->m_bufsize*char_size, fInfo->m_rdpos*char_size); + auto read = _read_file_async( + fInfo, cb, (uint8_t*)fInfo->m_buffer, fInfo->m_bufsize * char_size, fInfo->m_rdpos * char_size); switch (read) { - case 0: - // pending - return read; - - case (-1): - // error - delete cb; - return read; - - default: - // operation is complete. The pattern of returning synchronously - // has the expectation that we duplicate the callback code here... - // Do the expedient thing for now. - cb->on_completed(read); - - // return pending - return 0; + case 0: + // pending + return read; + + case (-1): + // error + delete cb; + return read; + + default: + // operation is complete. The pattern of returning synchronously + // has the expectation that we duplicate the callback code here... + // Do the expedient thing for now. + cb->on_completed(read); + + // return pending + return 0; }; } - else if ( bufrem < count ) + else if (bufrem < count) { fInfo->m_bufsize = safeCount.Max(fInfo->m_buffer_size); // Then, we allocate a new buffer. - char *newbuf = new char[fInfo->m_bufsize*char_size]; + char* newbuf = new char[fInfo->m_bufsize * char_size]; // Then, we copy the unread part to the new buffer and delete the old buffer - if ( bufrem > 0 ) - memcpy(newbuf, fInfo->m_buffer+bufpos*char_size, bufrem*char_size); + if (bufrem > 0) memcpy(newbuf, fInfo->m_buffer + bufpos * char_size, bufrem * char_size); delete fInfo->m_buffer; fInfo->m_buffer = newbuf; @@ -419,43 +430,45 @@ size_t _fill_buffer_fsb(_In_ _file_info_impl *fInfo, _In_ _filestream_callback * // Then, we read the remainder of the count into the new buffer fInfo->m_bufoff = fInfo->m_rdpos; - auto cb = create_callback(fInfo, - [=] (size_t result) + auto cb = create_callback(fInfo, [=](size_t result) { { - { - pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); - fInfo->m_buffill = result / char_size; - } - callback->on_completed(bufrem*char_size+result); - }); + pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); + fInfo->m_buffill = result / char_size; + } + callback->on_completed(bufrem * char_size + result); + }); - auto read = _read_file_async(fInfo, cb, (uint8_t*)fInfo->m_buffer+bufrem*char_size, (fInfo->m_bufsize-bufrem)*char_size, (fInfo->m_rdpos+bufrem)*char_size); + auto read = _read_file_async(fInfo, + cb, + (uint8_t*)fInfo->m_buffer + bufrem * char_size, + (fInfo->m_bufsize - bufrem) * char_size, + (fInfo->m_rdpos + bufrem) * char_size); switch (read) { - case 0: - // pending - return read; - - case (-1): - // error - delete cb; - return read; - - default: - // operation is complete. The pattern of returning synchronously - // has the expectation that we duplicate the callback code here... - // Do the expedient thing for now. - cb->on_completed(read); - - // return pending - return 0; + case 0: + // pending + return read; + + case (-1): + // error + delete cb; + return read; + + default: + // operation is complete. The pattern of returning synchronously + // has the expectation that we duplicate the callback code here... + // Do the expedient thing for now. + cb->on_completed(read); + + // return pending + return 0; }; } else { // If we are here, it means that we didn't need to read, we already have enough data in the buffer - return count*char_size; + return count * char_size; } } @@ -466,38 +479,41 @@ size_t _fill_buffer_fsb(_In_ _file_info_impl *fInfo, _In_ _filestream_callback * /// A pointer to the callback interface to invoke when the write request is completed. /// A pointer to a buffer where the data should be placed /// The size (in characters) of the buffer -/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -size_t __cdecl _getn_fsb(_In_ Concurrency::streams::details::_file_info *info, _In_ Concurrency::streams::details::_filestream_callback *callback, _Out_writes_ (count) void *ptr, _In_ size_t count, size_t char_size) +/// 0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read +/// into the buffer +size_t __cdecl _getn_fsb(_In_ Concurrency::streams::details::_file_info* info, + _In_ Concurrency::streams::details::_filestream_callback* callback, + _Out_writes_(count) void* ptr, + _In_ size_t count, + size_t char_size) { _ASSERTE(callback != nullptr); _ASSERTE(info != nullptr); _ASSERTE(count > 0); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(info->m_lock); - if ( fInfo->m_buffer_size > 0 ) + if (fInfo->m_buffer_size > 0) { - auto cb = create_callback(fInfo, - [=] (size_t read) - { - auto sz = count*char_size; - auto copy = (read < sz) ? read : sz; - auto bufoff = fInfo->m_rdpos - fInfo->m_bufoff; - memcpy(ptr, fInfo->m_buffer+bufoff*char_size, copy); - fInfo->m_atend = copy < sz; - callback->on_completed(copy); - }); + auto cb = create_callback(fInfo, [=](size_t read) { + auto sz = count * char_size; + auto copy = (read < sz) ? read : sz; + auto bufoff = fInfo->m_rdpos - fInfo->m_bufoff; + memcpy(ptr, fInfo->m_buffer + bufoff * char_size, copy); + fInfo->m_atend = copy < sz; + callback->on_completed(copy); + }); size_t read = _fill_buffer_fsb(fInfo, cb, count, char_size); - if ( read > 0 ) + if (read > 0) { - auto sz = count*char_size; + auto sz = count * char_size; auto copy = (read < sz) ? read : sz; auto bufoff = fInfo->m_rdpos - fInfo->m_bufoff; - memcpy(ptr, fInfo->m_buffer+bufoff*char_size, copy); + memcpy(ptr, fInfo->m_buffer + bufoff * char_size, copy); fInfo->m_atend = copy < sz; return copy; } @@ -506,11 +522,10 @@ size_t __cdecl _getn_fsb(_In_ Concurrency::streams::details::_file_info *info, _ } else { - return _read_file_async(fInfo, callback, ptr, count*char_size, fInfo->m_rdpos*char_size); + return _read_file_async(fInfo, callback, ptr, count * char_size, fInfo->m_rdpos * char_size); } } - /// /// Write data from a buffer into the file stream. /// @@ -518,28 +533,30 @@ size_t __cdecl _getn_fsb(_In_ Concurrency::streams::details::_file_info *info, _ /// A pointer to the callback interface to invoke when the write request is completed. /// A pointer to a buffer where the data should be placed /// The size (in characters) of the buffer -/// 0 if the write request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer -size_t __cdecl _putn_fsb(_In_ Concurrency::streams::details::_file_info *info, _In_ Concurrency::streams::details::_filestream_callback *callback, const void *ptr, size_t count, size_t char_size) +/// 0 if the write request is still outstanding, -1 if the request failed, otherwise the size of the data read +/// into the buffer +size_t __cdecl _putn_fsb(_In_ Concurrency::streams::details::_file_info* info, + _In_ Concurrency::streams::details::_filestream_callback* callback, + const void* ptr, + size_t count, + size_t char_size) { _ASSERTE(callback != nullptr); _ASSERTE(info != nullptr); _ASSERTE(count > 0); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(fInfo->m_lock); - if ( fInfo->m_stream == nullptr ) - return static_cast(-1); + if (fInfo->m_stream == nullptr) return static_cast(-1); // To preserve the async write order, we have to move the write head before read. - if (fInfo->m_wrpos != static_cast(-1)) - fInfo->m_wrpos += count; + if (fInfo->m_wrpos != static_cast(-1)) fInfo->m_wrpos += count; msl::safeint3::SafeInt safeWriteSize = count; safeWriteSize *= char_size; - // In most of the time, we preserve the writer so that it would have better performance. // However, after user call seek, we will dispose old writer. By doing so, users could // write to new writer in new position while the old writer is still flushing data into stream. @@ -553,25 +570,26 @@ size_t __cdecl _putn_fsb(_In_ Concurrency::streams::details::_file_info *info, _ fInfo->m_buffill += count; // ArrayReference here is for avoiding data copy. - fInfo->m_writer->WriteBytes(Platform::ArrayReference(const_cast(static_cast(ptr)), safeWriteSize)); + fInfo->m_writer->WriteBytes(Platform::ArrayReference( + const_cast(static_cast(ptr)), safeWriteSize)); // Flush data from m_writer buffer into stream , if the buffer is full if (fInfo->m_buffill >= fInfo->m_buffer_size) { fInfo->m_buffill = 0; - fInfo->m_pendingWrites = fInfo->m_pendingWrites.then([=] { - return fInfo->m_writer->StoreAsync(); - }).then([=] (pplx::task result) { - try - { - result.wait(); - callback->on_completed(safeWriteSize); - } - catch (Platform::Exception^ exc) - { - callback->on_error(std::make_exception_ptr(utility::details::create_system_error(exc->HResult))); - } - }); + fInfo->m_pendingWrites = fInfo->m_pendingWrites.then([=] { return fInfo->m_writer->StoreAsync(); }) + .then([=](pplx::task result) { + try + { + result.wait(); + callback->on_completed(safeWriteSize); + } + catch (Platform::Exception ^ exc) + { + callback->on_error(std::make_exception_ptr( + utility::details::create_system_error(exc->HResult))); + } + }); return 0; } else @@ -584,7 +602,8 @@ size_t __cdecl _putn_fsb(_In_ Concurrency::streams::details::_file_info *info, _ /// The file info record of the file /// A pointer to the callback interface to invoke when the write request is completed. /// True if the request was initiated -bool __cdecl _sync_fsb(_In_ Concurrency::streams::details::_file_info *info, _In_ Concurrency::streams::details::_filestream_callback *callback) +bool __cdecl _sync_fsb(_In_ Concurrency::streams::details::_file_info* info, + _In_ Concurrency::streams::details::_filestream_callback* callback) { return _sync_fsb_winrt(info, callback); } @@ -595,17 +614,18 @@ bool __cdecl _sync_fsb(_In_ Concurrency::streams::details::_file_info *info, _In /// The file info record of the file /// The new position (offset from the start) in the file stream /// New file position or -1 if error -size_t __cdecl _seekrdpos_fsb(_In_ Concurrency::streams::details::_file_info *info, size_t pos, size_t char_size) +size_t __cdecl _seekrdpos_fsb(_In_ Concurrency::streams::details::_file_info* info, size_t pos, size_t char_size) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(info->m_lock); - if ( fInfo->m_stream == nullptr) return static_cast(-1);; + if (fInfo->m_stream == nullptr) return static_cast(-1); + ; - if ( pos < fInfo->m_bufoff || pos > (fInfo->m_bufoff+fInfo->m_buffill) ) + if (pos < fInfo->m_bufoff || pos > (fInfo->m_bufoff + fInfo->m_buffill)) { delete fInfo->m_buffer; fInfo->m_buffer = nullptr; @@ -624,25 +644,27 @@ size_t __cdecl _seekrdpos_fsb(_In_ Concurrency::streams::details::_file_info *in /// The new position (offset from the end of the stream) in the file stream /// The size of the character type used for this stream /// New file position or -1 if error -_ASYNCRTIMP size_t __cdecl _seekrdtoend_fsb(_In_ Concurrency::streams::details::_file_info *info, int64_t offset, size_t char_size) +_ASYNCRTIMP size_t __cdecl _seekrdtoend_fsb(_In_ Concurrency::streams::details::_file_info* info, + int64_t offset, + size_t char_size) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); return _seekrdpos_fsb(info, static_cast(fInfo->m_stream->Size / char_size + offset), char_size); } -utility::size64_t __cdecl _get_size(_In_ concurrency::streams::details::_file_info *info, size_t char_size) +utility::size64_t __cdecl _get_size(_In_ concurrency::streams::details::_file_info* info, size_t char_size) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(info->m_lock); - if ( fInfo->m_stream == nullptr) return 0; + if (fInfo->m_stream == nullptr) return 0; - return utility::size64_t(fInfo->m_stream->Size/char_size); + return utility::size64_t(fInfo->m_stream->Size / char_size); } /// @@ -651,22 +673,21 @@ utility::size64_t __cdecl _get_size(_In_ concurrency::streams::details::_file_in /// The file info record of the file /// The new position (offset from the start) in the file stream /// New file position or -1 if error -size_t __cdecl _seekwrpos_fsb(_In_ Concurrency::streams::details::_file_info *info, size_t pos, size_t char_size) +size_t __cdecl _seekwrpos_fsb(_In_ Concurrency::streams::details::_file_info* info, size_t pos, size_t char_size) { _ASSERTE(info != nullptr); - _file_info_impl *fInfo = static_cast<_file_info_impl *>(info); + _file_info_impl* fInfo = static_cast<_file_info_impl*>(info); pplx::extensibility::scoped_recursive_lock_t lck(info->m_lock); - if ( fInfo->m_stream == nullptr) return static_cast(-1); + if (fInfo->m_stream == nullptr) return static_cast(-1); fInfo->m_wrpos = pos; // m_buffill keeps number of chars written into the m_writer buffer. // We need to flush it into stream before seek the write head of the stream - if (fInfo->m_buffill > 0) - _sync_fsb_winrt(fInfo, nullptr); + if (fInfo->m_buffill > 0) _sync_fsb_winrt(fInfo, nullptr); // Moving write head should follow the flush operation. is_done test is for perf optimization. if (fInfo->m_pendingWrites.is_done()) @@ -686,7 +707,11 @@ size_t __cdecl _seekwrpos_fsb(_In_ Concurrency::streams::details::_file_info *in return fInfo->m_wrpos; } -namespace Concurrency { namespace streams { namespace details +namespace Concurrency +{ +namespace streams +{ +namespace details { /// /// This class acts as a bridge between WinRT input streams and Casablanca asynchronous streams. @@ -694,18 +719,26 @@ namespace Concurrency { namespace streams { namespace details ref class IRandomAccessStream_bridge sealed : public Windows::Storage::Streams::IRandomAccessStream { public: - virtual property bool CanRead { bool get() { return m_buffer.can_read(); } } + virtual property bool CanRead + { + bool get() { return m_buffer.can_read(); } + } - virtual property bool CanWrite { bool get() { return m_buffer.can_write(); } } + virtual property bool CanWrite + { + bool get() { return m_buffer.can_write(); } + } - virtual property uint64_t Position { uint64_t get() { return m_position; } } + virtual property uint64_t Position + { + uint64_t get() { return m_position; } + } virtual property uint64_t Size { uint64_t get() { - if (!m_buffer.has_size()) - return m_remembered_size; + if (!m_buffer.has_size()) return m_remembered_size; return m_buffer.size(); } @@ -718,70 +751,66 @@ ref class IRandomAccessStream_bridge sealed : public Windows::Storage::Streams:: } } - virtual Windows::Storage::Streams::IRandomAccessStream^ CloneStream() - { - return ref new IRandomAccessStream_bridge(m_buffer); - } + virtual Windows::Storage::Streams::IRandomAccessStream ^ + CloneStream() { return ref new IRandomAccessStream_bridge(m_buffer); } - virtual Windows::Storage::Streams::IInputStream^ GetInputStreamAt(uint64_t position) - { - if ( !m_buffer.can_read() ) return nullptr; + virtual Windows::Storage::Streams::IInputStream + ^ + GetInputStreamAt(uint64_t position) { + if (!m_buffer.can_read()) return nullptr; - concurrency::streams::streambuf::pos_type pos = position; + concurrency::streams::streambuf::pos_type pos = position; - if ( m_buffer.can_seek() || pos == m_buffer.getpos(std::ios_base::in) ) - { - return ref new IRandomAccessStream_bridge(m_buffer,position); + if (m_buffer.can_seek() || pos == m_buffer.getpos(std::ios_base::in)) + { + return ref new IRandomAccessStream_bridge(m_buffer, position); + } + return nullptr; } - return nullptr; - } - virtual Windows::Storage::Streams::IOutputStream^ GetOutputStreamAt(uint64_t position) - { - if ( !m_buffer.can_write() ) return nullptr; + virtual Windows::Storage::Streams::IOutputStream + ^ GetOutputStreamAt(uint64_t position) { + if (!m_buffer.can_write()) return nullptr; - concurrency::streams::streambuf::pos_type pos = position; + concurrency::streams::streambuf::pos_type pos = position; - if ( m_buffer.can_seek() || pos == m_buffer.getpos(std::ios_base::out) ) - { - return ref new IRandomAccessStream_bridge(m_buffer,position); - } - return nullptr; - }; + if (m_buffer.can_seek() || pos == m_buffer.getpos(std::ios_base::out)) + { + return ref new IRandomAccessStream_bridge(m_buffer, position); + } + return nullptr; + }; virtual void Seek(uint64_t position) { - if (!m_buffer.can_seek()) - throw ref new Platform::InvalidArgumentException(L"underlying buffer cannot seek"); + if (!m_buffer.can_seek()) throw ref new Platform::InvalidArgumentException(L"underlying buffer cannot seek"); m_position = position; - m_buffer.seekpos(concurrency::streams::streambuf::pos_type(m_position),std::ios_base::in); - m_buffer.seekpos(concurrency::streams::streambuf::pos_type(m_position),std::ios_base::out); + m_buffer.seekpos(concurrency::streams::streambuf::pos_type(m_position), std::ios_base::in); + m_buffer.seekpos(concurrency::streams::streambuf::pos_type(m_position), std::ios_base::out); } - virtual Windows::Foundation::IAsyncOperationWithProgress^ WriteAsync(Windows::Storage::Streams::IBuffer^ buffer); - virtual Windows::Foundation::IAsyncOperationWithProgress<::Windows::Storage::Streams::IBuffer^, unsigned int>^ ReadAsync(::Windows::Storage::Streams::IBuffer^ buffer, unsigned int count, Windows::Storage::Streams::InputStreamOptions options); - virtual Windows::Foundation::IAsyncOperation^ FlushAsync(); + virtual Windows::Foundation::IAsyncOperationWithProgress ^ + WriteAsync(Windows::Storage::Streams::IBuffer ^ buffer); + virtual Windows::Foundation::IAsyncOperationWithProgress<::Windows::Storage::Streams::IBuffer ^, unsigned int> ^ + ReadAsync(::Windows::Storage::Streams::IBuffer ^ buffer, + unsigned int count, + Windows::Storage::Streams::InputStreamOptions options); + virtual Windows::Foundation::IAsyncOperation ^ FlushAsync(); - virtual ~IRandomAccessStream_bridge() - { - } + virtual ~IRandomAccessStream_bridge() {} -internal: + internal : - IRandomAccessStream_bridge(const concurrency::streams::streambuf &buffer) : - m_buffer(buffer), - m_remembered_size(0), - m_position(0) + IRandomAccessStream_bridge(const concurrency::streams::streambuf& buffer) + : m_buffer(buffer), m_remembered_size(0), m_position(0) { } - IRandomAccessStream_bridge(const concurrency::streams::streambuf &buffer, - concurrency::streams::streambuf::pos_type position) : - m_buffer(buffer), - m_remembered_size(0), - m_position(position) + IRandomAccessStream_bridge(const concurrency::streams::streambuf& buffer, + concurrency::streams::streambuf::pos_type position) + : m_buffer(buffer), m_remembered_size(0), m_position(position) { } @@ -793,15 +822,9 @@ ref class IRandomAccessStream_bridge sealed : public Windows::Storage::Streams:: struct _alloc_protector { - _alloc_protector(concurrency::streams::streambuf& buffer) : - m_buffer(buffer), m_size(0) - { - } + _alloc_protector(concurrency::streams::streambuf& buffer) : m_buffer(buffer), m_size(0) {} - ~_alloc_protector() - { - m_buffer.commit(m_size); - } + ~_alloc_protector() { m_buffer.commit(m_size); } size_t m_size; @@ -813,17 +836,14 @@ struct _alloc_protector struct _acquire_protector { - _acquire_protector(concurrency::streams::streambuf& buffer, uint8_t* ptr) : - m_buffer(buffer), m_ptr(ptr), m_size(0) + _acquire_protector(concurrency::streams::streambuf& buffer, uint8_t* ptr) + : m_buffer(buffer), m_ptr(ptr), m_size(0) { } - ~_acquire_protector() - { - m_buffer.release(m_ptr, m_size); - } + ~_acquire_protector() { m_buffer.release(m_ptr, m_size); } - size_t m_size; + size_t m_size; private: _acquire_protector& operator=(const _acquire_protector&); @@ -837,13 +857,19 @@ struct _acquire_protector struct _IUnknown_protector { _IUnknown_protector(IUnknown* unk_ptr) : m_unknown(unk_ptr) {} - ~_IUnknown_protector() { if (m_unknown != nullptr) m_unknown->Release(); } + ~_IUnknown_protector() + { + if (m_unknown != nullptr) m_unknown->Release(); + } + private: IUnknown* m_unknown; }; -Windows::Foundation::IAsyncOperationWithProgress<::Windows::Storage::Streams::IBuffer^, unsigned int>^ -IRandomAccessStream_bridge::ReadAsync(::Windows::Storage::Streams::IBuffer^ buffer, unsigned int count, Windows::Storage::Streams::InputStreamOptions options) +Windows::Foundation::IAsyncOperationWithProgress<::Windows::Storage::Streams::IBuffer ^, unsigned int> ^ + IRandomAccessStream_bridge::ReadAsync(::Windows::Storage::Streams::IBuffer ^ buffer, + unsigned int count, + Windows::Storage::Streams::InputStreamOptions options) { if (!m_buffer.can_read()) { @@ -853,115 +879,90 @@ IRandomAccessStream_bridge::ReadAsync(::Windows::Storage::Streams::IBuffer^ buff if (buffer->Capacity < count) return pplx::create_async([buffer](pplx::progress_reporter reporter) { return buffer; }); - m_buffer.seekpos(concurrency::streams::streambuf::pos_type(m_position),std::ios_base::in); + m_buffer.seekpos(concurrency::streams::streambuf::pos_type(m_position), std::ios_base::in); concurrency::streams::streambuf streambuf = m_buffer; - return pplx::create_async( - [streambuf,buffer,options,count](pplx::progress_reporter reporter) - { - auto sbuf = streambuf; - auto local_buf = ref new ::Platform::Array(count); + return pplx::create_async([streambuf, buffer, options, count](pplx::progress_reporter reporter) { + auto sbuf = streambuf; + auto local_buf = ref new ::Platform::Array(count); - uint8_t* ptr = nullptr; - size_t acquired_size = 0; + uint8_t* ptr = nullptr; + size_t acquired_size = 0; - if ( sbuf.acquire(ptr, acquired_size) && acquired_size >= count ) - { - _acquire_protector prot(sbuf, ptr); + if (sbuf.acquire(ptr, acquired_size) && acquired_size >= count) + { + _acquire_protector prot(sbuf, ptr); - IUnknown* pUnk = reinterpret_cast(buffer); - ::Windows::Storage::Streams::IBufferByteAccess* pBufferByteAccess = nullptr; - HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess)); - __abi_ThrowIfFailed(hr); + IUnknown* pUnk = reinterpret_cast(buffer); + ::Windows::Storage::Streams::IBufferByteAccess* pBufferByteAccess = nullptr; + HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess)); + __abi_ThrowIfFailed(hr); - _IUnknown_protector unkprot(pBufferByteAccess); + _IUnknown_protector unkprot(pBufferByteAccess); - byte* buffer_data = nullptr; - hr = pBufferByteAccess->Buffer(&buffer_data); - __abi_ThrowIfFailed(hr); + byte* buffer_data = nullptr; + hr = pBufferByteAccess->Buffer(&buffer_data); + __abi_ThrowIfFailed(hr); - memcpy(buffer_data,ptr,count); + memcpy(buffer_data, ptr, count); - prot.m_size = count; - buffer->Length = count; + prot.m_size = count; + buffer->Length = count; - return pplx::task_from_result(buffer); - } - else + return pplx::task_from_result(buffer); + } + else + { + if (acquired_size > 0) { - if ( acquired_size > 0 ) - { - sbuf.release(ptr, 0); - } + sbuf.release(ptr, 0); + } - IUnknown* pUnk = reinterpret_cast(buffer); - ::Windows::Storage::Streams::IBufferByteAccess* pBufferByteAccess = nullptr; - HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess)); - __abi_ThrowIfFailed(hr); + IUnknown* pUnk = reinterpret_cast(buffer); + ::Windows::Storage::Streams::IBufferByteAccess* pBufferByteAccess = nullptr; + HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess)); + __abi_ThrowIfFailed(hr); - _IUnknown_protector unkprot(pBufferByteAccess); + _IUnknown_protector unkprot(pBufferByteAccess); - byte* buffer_data = nullptr; - hr = pBufferByteAccess->Buffer(&buffer_data); - __abi_ThrowIfFailed(hr); + byte* buffer_data = nullptr; + hr = pBufferByteAccess->Buffer(&buffer_data); + __abi_ThrowIfFailed(hr); - pBufferByteAccess->AddRef(); + pBufferByteAccess->AddRef(); - return sbuf.getn(buffer_data,count).then( - [buffer,pBufferByteAccess,count](pplx::task written) - { - _IUnknown_protector unkprot(pBufferByteAccess); - buffer->Length = (unsigned int)written.get(); - return pplx::task_from_result(buffer); - }); - } - }); + return sbuf.getn(buffer_data, count).then([buffer, pBufferByteAccess, count](pplx::task written) { + _IUnknown_protector unkprot(pBufferByteAccess); + buffer->Length = (unsigned int)written.get(); + return pplx::task_from_result(buffer); + }); + } + }); } -Windows::Foundation::IAsyncOperationWithProgress^ -IRandomAccessStream_bridge::WriteAsync(Windows::Storage::Streams::IBuffer^ buffer) +Windows::Foundation::IAsyncOperationWithProgress ^ + IRandomAccessStream_bridge::WriteAsync(Windows::Storage::Streams::IBuffer ^ buffer) { if (!m_buffer.can_write()) { return pplx::create_async([](pplx::progress_reporter reporter) { return 0U; }); } - m_buffer.seekpos(concurrency::streams::streambuf::pos_type(m_position),std::ios_base::out); + m_buffer.seekpos(concurrency::streams::streambuf::pos_type(m_position), std::ios_base::out); concurrency::streams::streambuf streambuf = m_buffer; - return pplx::create_async( - [buffer,streambuf](pplx::progress_reporter reporter) - { - auto size = buffer->Length; - auto sbuf = streambuf; - uint8_t* ptr = sbuf.alloc(size); + return pplx::create_async([buffer, streambuf](pplx::progress_reporter reporter) { + auto size = buffer->Length; + auto sbuf = streambuf; + uint8_t* ptr = sbuf.alloc(size); - if ( ptr != nullptr) + if (ptr != nullptr) + { { - { - _alloc_protector prot(sbuf); - - IUnknown* pUnk = reinterpret_cast(buffer); - ::Windows::Storage::Streams::IBufferByteAccess* pBufferByteAccess = nullptr; - HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess)); - __abi_ThrowIfFailed(hr); + _alloc_protector prot(sbuf); - _IUnknown_protector unkprot(pBufferByteAccess); - - byte* buffer_data = nullptr; - hr = pBufferByteAccess->Buffer(&buffer_data); - __abi_ThrowIfFailed(hr); - - memcpy(ptr,buffer_data,size); - - prot.m_size = size; - } - return pplx::task_from_result((unsigned int)size); - } - else - { IUnknown* pUnk = reinterpret_cast(buffer); ::Windows::Storage::Streams::IBufferByteAccess* pBufferByteAccess = nullptr; HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess)); @@ -973,47 +974,67 @@ IRandomAccessStream_bridge::WriteAsync(Windows::Storage::Streams::IBuffer^ buffe hr = pBufferByteAccess->Buffer(&buffer_data); __abi_ThrowIfFailed(hr); - pBufferByteAccess->AddRef(); + memcpy(ptr, buffer_data, size); - return sbuf.putn_nocopy(buffer_data, size).then( - [pBufferByteAccess](pplx::task size) - { - pBufferByteAccess->Release(); - return (unsigned int)size.get(); - }); + prot.m_size = size; } - }); + return pplx::task_from_result((unsigned int)size); + } + else + { + IUnknown* pUnk = reinterpret_cast(buffer); + ::Windows::Storage::Streams::IBufferByteAccess* pBufferByteAccess = nullptr; + HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess)); + __abi_ThrowIfFailed(hr); + + _IUnknown_protector unkprot(pBufferByteAccess); + + byte* buffer_data = nullptr; + hr = pBufferByteAccess->Buffer(&buffer_data); + __abi_ThrowIfFailed(hr); + + pBufferByteAccess->AddRef(); + + return sbuf.putn_nocopy(buffer_data, size).then([pBufferByteAccess](pplx::task size) { + pBufferByteAccess->Release(); + return (unsigned int)size.get(); + }); + } + }); } -Windows::Foundation::IAsyncOperation^ -IRandomAccessStream_bridge::FlushAsync() +Windows::Foundation::IAsyncOperation ^ IRandomAccessStream_bridge::FlushAsync() { concurrency::streams::streambuf streambuf = m_buffer; - return pplx::create_async([streambuf]() + return pplx::create_async([streambuf]() { + if (!streambuf.can_write()) { - if (!streambuf.can_write()) - { - return pplx::task_from_result(false); - } + return pplx::task_from_result(false); + } - auto sbuf = streambuf; - return sbuf.sync().then([] { return pplx::task_from_result(true); }); - }); + auto sbuf = streambuf; + return sbuf.sync().then([] { return pplx::task_from_result(true); }); + }); } -}}} // namespaces +} // namespace details +} // namespace streams +} // namespace Concurrency -Windows::Storage::Streams::IInputStream^ Concurrency::streams::winrt_stream::create_input_stream(const concurrency::streams::streambuf &buffer) +Windows::Storage::Streams::IInputStream ^ + Concurrency::streams::winrt_stream::create_input_stream(const concurrency::streams::streambuf& buffer) { - return ref new ::Concurrency::streams::details::IRandomAccessStream_bridge(buffer,0); + return ref new ::Concurrency::streams::details::IRandomAccessStream_bridge(buffer, 0); } -Windows::Storage::Streams::IOutputStream^ Concurrency::streams::winrt_stream::create_output_stream(const concurrency::streams::streambuf &buffer) +Windows::Storage::Streams::IOutputStream ^ + Concurrency::streams::winrt_stream::create_output_stream(const concurrency::streams::streambuf& buffer) { - return ref new Concurrency::streams::details::IRandomAccessStream_bridge(buffer,0); + return ref new Concurrency::streams::details::IRandomAccessStream_bridge(buffer, 0); } -Windows::Storage::Streams::IRandomAccessStream^ Concurrency::streams::winrt_stream::create_random_access_stream(const concurrency::streams::streambuf &buffer) +Windows::Storage::Streams::IRandomAccessStream ^ Concurrency::streams::winrt_stream::create_random_access_stream( + const concurrency::streams::streambuf& buffer) { return ref new Concurrency::streams::details::IRandomAccessStream_bridge(buffer); } diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index 6dfa02cb63..92781f67a8 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Protocol independent support for URIs. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Protocol independent support for URIs. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -17,45 +17,47 @@ using namespace utility::conversions; -namespace web { namespace details +namespace web +{ +namespace details { namespace { - /// - /// Unreserved characters are those that are allowed in a URI but do not have a reserved purpose. They include: - /// - A-Z - /// - a-z - /// - 0-9 - /// - '-' (hyphen) - /// - '.' (period) - /// - '_' (underscore) - /// - '~' (tilde) - /// - inline bool is_unreserved(int c) - { - return ::utility::details::is_alnum((char)c) || c == '-' || c == '.' || c == '_' || c == '~'; - } +/// +/// Unreserved characters are those that are allowed in a URI but do not have a reserved purpose. They include: +/// - A-Z +/// - a-z +/// - 0-9 +/// - '-' (hyphen) +/// - '.' (period) +/// - '_' (underscore) +/// - '~' (tilde) +/// +inline bool is_unreserved(int c) +{ + return ::utility::details::is_alnum((char)c) || c == '-' || c == '.' || c == '_' || c == '~'; +} - /// - /// General delimiters serve as the delimiters between different uri components. - /// General delimiters include: - /// - All of these :/?#[]@ - /// - inline bool is_gen_delim(int c) - { - return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'; - } +/// +/// General delimiters serve as the delimiters between different uri components. +/// General delimiters include: +/// - All of these :/?#[]@ +/// +inline bool is_gen_delim(int c) +{ + return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'; +} - /// - /// Subdelimiters are those characters that may have a defined meaning within component - /// of a uri for a particular scheme. They do not serve as delimiters in any case between - /// uri segments. sub_delimiters include: - /// - All of these !$&'()*+,;= - /// - inline bool is_sub_delim(int c) +/// +/// Subdelimiters are those characters that may have a defined meaning within component +/// of a uri for a particular scheme. They do not serve as delimiters in any case between +/// uri segments. sub_delimiters include: +/// - All of these !$&'()*+,;= +/// +inline bool is_sub_delim(int c) +{ + switch (c) { - switch (c) - { case '!': case '$': case '&': @@ -66,421 +68,408 @@ namespace case '+': case ',': case ';': - case '=': - return true; - default: - return false; - } + case '=': return true; + default: return false; } +} - /// - /// Reserved characters includes the general delimiters and sub delimiters. Some characters - /// are neither reserved nor unreserved, and must be percent-encoded. - /// - inline bool is_reserved(int c) - { - return is_gen_delim(c) || is_sub_delim(c); - } +/// +/// Reserved characters includes the general delimiters and sub delimiters. Some characters +/// are neither reserved nor unreserved, and must be percent-encoded. +/// +inline bool is_reserved(int c) { return is_gen_delim(c) || is_sub_delim(c); } - /// - /// Legal characters in the scheme portion include: - /// - Any alphanumeric character - /// - '+' (plus) - /// - '-' (hyphen) - /// - '.' (period) - /// - /// Note that the scheme must BEGIN with an alpha character. - /// - inline bool is_scheme_character(int c) - { - return ::utility::details::is_alnum((char)c) || c == '+' || c == '-' || c == '.'; - } +/// +/// Legal characters in the scheme portion include: +/// - Any alphanumeric character +/// - '+' (plus) +/// - '-' (hyphen) +/// - '.' (period) +/// +/// Note that the scheme must BEGIN with an alpha character. +/// +inline bool is_scheme_character(int c) +{ + return ::utility::details::is_alnum((char)c) || c == '+' || c == '-' || c == '.'; +} - /// - /// Legal characters in the user information portion include: - /// - Any unreserved character - /// - The percent character ('%'), and thus any percent-endcoded octet - /// - The sub-delimiters - /// - ':' (colon) - /// - inline bool is_user_info_character(int c) - { - return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':'; - } +/// +/// Legal characters in the user information portion include: +/// - Any unreserved character +/// - The percent character ('%'), and thus any percent-endcoded octet +/// - The sub-delimiters +/// - ':' (colon) +/// +inline bool is_user_info_character(int c) { return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':'; } - /// - /// Legal characters in the authority portion include: - /// - Any unreserved character - /// - The percent character ('%'), and thus any percent-endcoded octet - /// - The sub-delimiters - /// - ':' (colon) - /// - IPv6 requires '[]' allowed for it to be valid URI and passed to underlying platform for IPv6 support - /// - inline bool is_authority_character(int c) - { - return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '@' || c == ':' || c == '[' || c == ']'; - } +/// +/// Legal characters in the authority portion include: +/// - Any unreserved character +/// - The percent character ('%'), and thus any percent-endcoded octet +/// - The sub-delimiters +/// - ':' (colon) +/// - IPv6 requires '[]' allowed for it to be valid URI and passed to underlying platform for IPv6 support +/// +inline bool is_authority_character(int c) +{ + return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '@' || c == ':' || c == '[' || c == ']'; +} - /// - /// Legal characters in the path portion include: - /// - Any unreserved character - /// - The percent character ('%'), and thus any percent-endcoded octet - /// - The sub-delimiters - /// - ':' (colon) - /// - '@' (at sign) - /// - inline bool is_path_character(int c) - { - return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '/' || c == ':' || c == '@'; - } +/// +/// Legal characters in the path portion include: +/// - Any unreserved character +/// - The percent character ('%'), and thus any percent-endcoded octet +/// - The sub-delimiters +/// - ':' (colon) +/// - '@' (at sign) +/// +inline bool is_path_character(int c) +{ + return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '/' || c == ':' || c == '@'; +} + +/// +/// Legal characters in the query portion include: +/// - Any path character +/// - '?' (question mark) +/// +inline bool is_query_character(int c) { return is_path_character(c) || c == '?'; } + +/// +/// Legal characters in the fragment portion include: +/// - Any path character +/// - '?' (question mark) +/// +inline bool is_fragment_character(int c) +{ + // this is intentional, they have the same set of legal characters + return is_query_character(c); +} + +struct inner_parse_out +{ + const utility::char_t* scheme_begin = nullptr; + const utility::char_t* scheme_end = nullptr; + const utility::char_t* uinfo_begin = nullptr; + const utility::char_t* uinfo_end = nullptr; + const utility::char_t* host_begin = nullptr; + const utility::char_t* host_end = nullptr; + int port = 0; + const utility::char_t* path_begin = nullptr; + const utility::char_t* path_end = nullptr; + const utility::char_t* query_begin = nullptr; + const utility::char_t* query_end = nullptr; + const utility::char_t* fragment_begin = nullptr; + const utility::char_t* fragment_end = nullptr; /// - /// Legal characters in the query portion include: - /// - Any path character - /// - '?' (question mark) + /// Parses the uri, setting the given pointers to locations inside the given buffer. + /// 'encoded' is expected to point to an encoded zero-terminated string containing a uri /// - inline bool is_query_character(int c) + bool parse_from(const utility::char_t* encoded) { - return is_path_character(c) || c == '?'; - } + const utility::char_t* p = encoded; - /// - /// Legal characters in the fragment portion include: - /// - Any path character - /// - '?' (question mark) - /// - inline bool is_fragment_character(int c) - { - // this is intentional, they have the same set of legal characters - return is_query_character(c); - } - - struct inner_parse_out - { - const utility::char_t *scheme_begin = nullptr; - const utility::char_t *scheme_end = nullptr; - const utility::char_t *uinfo_begin = nullptr; - const utility::char_t *uinfo_end = nullptr; - const utility::char_t *host_begin = nullptr; - const utility::char_t *host_end = nullptr; - int port = 0; - const utility::char_t *path_begin = nullptr; - const utility::char_t *path_end = nullptr; - const utility::char_t *query_begin = nullptr; - const utility::char_t *query_end = nullptr; - const utility::char_t *fragment_begin = nullptr; - const utility::char_t *fragment_end = nullptr; - - /// - /// Parses the uri, setting the given pointers to locations inside the given buffer. - /// 'encoded' is expected to point to an encoded zero-terminated string containing a uri - /// - bool parse_from(const utility::char_t *encoded) - { - const utility::char_t *p = encoded; - - // IMPORTANT -- A uri may either be an absolute uri, or an relative-reference - // Absolute: 'http://host.com' - // Relative-Reference: '//:host.com', '/path1/path2?query', './path1:path2' - // A Relative-Reference can be disambiguated by parsing for a ':' before the first slash - - bool is_relative_reference = true; - const utility::char_t *p2 = p; - for (; *p2 != _XPLATSTR('/') && *p2 != _XPLATSTR('\0'); p2++) + // IMPORTANT -- A uri may either be an absolute uri, or an relative-reference + // Absolute: 'http://host.com' + // Relative-Reference: '//:host.com', '/path1/path2?query', './path1:path2' + // A Relative-Reference can be disambiguated by parsing for a ':' before the first slash + + bool is_relative_reference = true; + const utility::char_t* p2 = p; + for (; *p2 != _XPLATSTR('/') && *p2 != _XPLATSTR('\0'); p2++) + { + if (*p2 == _XPLATSTR(':')) { - if (*p2 == _XPLATSTR(':')) - { - // found a colon, the first portion is a scheme - is_relative_reference = false; - break; - } + // found a colon, the first portion is a scheme + is_relative_reference = false; + break; } + } - if (!is_relative_reference) + if (!is_relative_reference) + { + // the first character of a scheme must be a letter + if (!isalpha(*p)) { - // the first character of a scheme must be a letter - if (!isalpha(*p)) + return false; + } + + // start parsing the scheme, it's always delimited by a colon (must be present) + scheme_begin = p++; + for (; *p != ':'; p++) + { + if (!is_scheme_character(*p)) { return false; } + } + scheme_end = p; - // start parsing the scheme, it's always delimited by a colon (must be present) - scheme_begin = p++; - for (; *p != ':'; p++) + // skip over the colon + p++; + } + + // if we see two slashes next, then we're going to parse the authority portion + // later on we'll break up the authority into the port and host + const utility::char_t* authority_begin = nullptr; + const utility::char_t* authority_end = nullptr; + if (*p == _XPLATSTR('/') && p[1] == _XPLATSTR('/')) + { + // skip over the slashes + p += 2; + authority_begin = p; + + // the authority is delimited by a slash (resource), question-mark (query) or octothorpe (fragment) + // or by EOS. The authority could be empty ('file:///C:\file_name.txt') + for (; *p != _XPLATSTR('/') && *p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) + { + // We're NOT currently supporting IPvFuture or username/password in authority + // IPv6 as the host (i.e. http://[:::::::]) is allowed as valid URI and passed to subsystem for support. + if (!is_authority_character(*p)) { - if (!is_scheme_character(*p)) - { - return false; - } + return false; } - scheme_end = p; - - // skip over the colon - p++; } + authority_end = p; - // if we see two slashes next, then we're going to parse the authority portion - // later on we'll break up the authority into the port and host - const utility::char_t *authority_begin = nullptr; - const utility::char_t *authority_end = nullptr; - if (*p == _XPLATSTR('/') && p[1] == _XPLATSTR('/')) + // now lets see if we have a port specified -- by working back from the end + if (authority_begin != authority_end) { - // skip over the slashes - p += 2; - authority_begin = p; - - // the authority is delimited by a slash (resource), question-mark (query) or octothorpe (fragment) - // or by EOS. The authority could be empty ('file:///C:\file_name.txt') - for (; *p != _XPLATSTR('/') && *p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) + // the port is made up of all digits + const utility::char_t* port_begin = authority_end - 1; + for (; isdigit(*port_begin) && port_begin != authority_begin; port_begin--) { - // We're NOT currently supporting IPvFuture or username/password in authority - // IPv6 as the host (i.e. http://[:::::::]) is allowed as valid URI and passed to subsystem for support. - if (!is_authority_character(*p)) - { - return false; - } } - authority_end = p; - // now lets see if we have a port specified -- by working back from the end - if (authority_begin != authority_end) + if (*port_begin == _XPLATSTR(':')) { - // the port is made up of all digits - const utility::char_t *port_begin = authority_end - 1; - for (; isdigit(*port_begin) && port_begin != authority_begin; port_begin--) - { - } - - if (*port_begin == _XPLATSTR(':')) - { - // has a port - host_begin = authority_begin; - host_end = port_begin; - - //skip the colon - port_begin++; - - port = utility::conversions::details::scan_string(utility::string_t(port_begin, authority_end)); - } - else - { - // no port - host_begin = authority_begin; - host_end = authority_end; - } - - // look for a user_info component - const utility::char_t *u_end = host_begin; - for (; is_user_info_character(*u_end) && u_end != host_end; u_end++) - { - } - - if (*u_end == _XPLATSTR('@')) - { - host_begin = u_end + 1; - uinfo_begin = authority_begin; - uinfo_end = u_end; - } - } - } + // has a port + host_begin = authority_begin; + host_end = port_begin; - // if we see a path character or a slash, then the - // if we see a slash, or any other legal path character, parse the path next - if (*p == _XPLATSTR('/') || is_path_character(*p)) - { - path_begin = p; + // skip the colon + port_begin++; - // the path is delimited by a question-mark (query) or octothorpe (fragment) or by EOS - for (; *p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) + port = + utility::conversions::details::scan_string(utility::string_t(port_begin, authority_end)); + } + else { - if (!is_path_character(*p)) - { - return false; - } + // no port + host_begin = authority_begin; + host_end = authority_end; } - path_end = p; - } - - // if we see a ?, then the query is next - if (*p == _XPLATSTR('?')) - { - // skip over the question mark - p++; - query_begin = p; - // the query is delimited by a '#' (fragment) or EOS - for (; *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) + // look for a user_info component + const utility::char_t* u_end = host_begin; + for (; is_user_info_character(*u_end) && u_end != host_end; u_end++) { - if (!is_query_character(*p)) - { - return false; - } } - query_end = p; - } - - // if we see a #, then the fragment is next - if (*p == _XPLATSTR('#')) - { - // skip over the hash mark - p++; - fragment_begin = p; - // the fragment is delimited by EOS - for (; *p != _XPLATSTR('\0'); p++) + if (*u_end == _XPLATSTR('@')) { - if (!is_fragment_character(*p)) - { - return false; - } + host_begin = u_end + 1; + uinfo_begin = authority_begin; + uinfo_end = u_end; } - fragment_end = p; } - - return true; } - void write_to(uri_components& components) + // if we see a path character or a slash, then the + // if we see a slash, or any other legal path character, parse the path next + if (*p == _XPLATSTR('/') || is_path_character(*p)) { - if (scheme_begin) - { - components.m_scheme.assign(scheme_begin, scheme_end); - utility::details::inplace_tolower(components.m_scheme); - } - else - { - components.m_scheme.clear(); - } + path_begin = p; - if (uinfo_begin) + // the path is delimited by a question-mark (query) or octothorpe (fragment) or by EOS + for (; *p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) { - components.m_user_info.assign(uinfo_begin, uinfo_end); - } - - if (host_begin) - { - components.m_host.assign(host_begin, host_end); - utility::details::inplace_tolower(components.m_host); - } - else - { - components.m_host.clear(); + if (!is_path_character(*p)) + { + return false; + } } + path_end = p; + } - components.m_port = port; + // if we see a ?, then the query is next + if (*p == _XPLATSTR('?')) + { + // skip over the question mark + p++; + query_begin = p; - if (path_begin) - { - components.m_path.assign(path_begin, path_end); - } - else + // the query is delimited by a '#' (fragment) or EOS + for (; *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) { - // default path to begin with a slash for easy comparison - components.m_path = _XPLATSTR("/"); + if (!is_query_character(*p)) + { + return false; + } } + query_end = p; + } - if (query_begin) - { - components.m_query.assign(query_begin, query_end); - } - else - { - components.m_query.clear(); - } + // if we see a #, then the fragment is next + if (*p == _XPLATSTR('#')) + { + // skip over the hash mark + p++; + fragment_begin = p; - if (fragment_begin) + // the fragment is delimited by EOS + for (; *p != _XPLATSTR('\0'); p++) { - components.m_fragment.assign(fragment_begin, fragment_end); - } - else - { - components.m_fragment.clear(); + if (!is_fragment_character(*p)) + { + return false; + } } + fragment_end = p; } - }; - // Encodes all characters not in given set determined by given function. - template - utility::string_t encode_impl(const utf8string &raw, F should_encode) + return true; + } + + void write_to(uri_components& components) { - const utility::char_t * const hex = _XPLATSTR("0123456789ABCDEF"); - utility::string_t encoded; - for (auto iter = raw.begin(); iter != raw.end(); ++iter) + if (scheme_begin) { - // for utf8 encoded string, char ASCII can be greater than 127. - int ch = static_cast(*iter); - // ch should be same under both utf8 and utf16. - if (should_encode(ch)) - { - encoded.push_back(_XPLATSTR('%')); - encoded.push_back(hex[(ch >> 4) & 0xF]); - encoded.push_back(hex[ch & 0xF]); - } - else - { - // ASCII don't need to be encoded, which should be same on both utf8 and utf16. - encoded.push_back((utility::char_t)ch); - } + components.m_scheme.assign(scheme_begin, scheme_end); + utility::details::inplace_tolower(components.m_scheme); + } + else + { + components.m_scheme.clear(); } - return encoded; - } - // 5.2.3. Merge Paths https://tools.ietf.org/html/rfc3986#section-5.2.3 - utility::string_t mergePaths(const utility::string_t &base, const utility::string_t &relative) - { - const auto lastSlash = base.rfind(_XPLATSTR('/')); - if (lastSlash == utility::string_t::npos) + if (uinfo_begin) + { + components.m_user_info.assign(uinfo_begin, uinfo_end); + } + + if (host_begin) { - return base + _XPLATSTR('/') + relative; + components.m_host.assign(host_begin, host_end); + utility::details::inplace_tolower(components.m_host); } - else if (lastSlash == base.size() - 1) + else { - return base + relative; + components.m_host.clear(); } - // path contains and does not end with '/', we remove segment after last '/' - return base.substr(0, lastSlash + 1) + relative; - } - // 5.2.4. Remove Dot Segments https://tools.ietf.org/html/rfc3986#section-5.2.4 - void removeDotSegments(uri_builder &builder) - { - const ::utility::string_t dotSegment = _XPLATSTR("."); - const ::utility::string_t dotDotSegment = _XPLATSTR(".."); + components.m_port = port; + + if (path_begin) + { + components.m_path.assign(path_begin, path_end); + } + else + { + // default path to begin with a slash for easy comparison + components.m_path = _XPLATSTR("/"); + } - if (builder.path().find(_XPLATSTR('.')) == utility::string_t::npos) - return; + if (query_begin) + { + components.m_query.assign(query_begin, query_end); + } + else + { + components.m_query.clear(); + } - const auto segments = uri::split_path(builder.path()); - std::vector> result; - for (auto& segment : segments) + if (fragment_begin) { - if (segment == dotSegment) - continue; - else if (segment != dotDotSegment) - result.push_back(segment); - else if (!result.empty()) - result.pop_back(); + components.m_fragment.assign(fragment_begin, fragment_end); } - if (result.empty()) + else { - builder.set_path(utility::string_t()); - return; + components.m_fragment.clear(); } - utility::string_t path = result.front().get(); - for (size_t i = 1; i != result.size(); ++i) + } +}; + +// Encodes all characters not in given set determined by given function. +template +utility::string_t encode_impl(const utf8string& raw, F should_encode) +{ + const utility::char_t* const hex = _XPLATSTR("0123456789ABCDEF"); + utility::string_t encoded; + for (auto iter = raw.begin(); iter != raw.end(); ++iter) + { + // for utf8 encoded string, char ASCII can be greater than 127. + int ch = static_cast(*iter); + // ch should be same under both utf8 and utf16. + if (should_encode(ch)) { - path += _XPLATSTR('/'); - path += result[i].get(); + encoded.push_back(_XPLATSTR('%')); + encoded.push_back(hex[(ch >> 4) & 0xF]); + encoded.push_back(hex[ch & 0xF]); } - if (segments.back() == dotDotSegment - || segments.back() == dotSegment - || builder.path().back() == _XPLATSTR('/')) + else { - path += _XPLATSTR('/'); + // ASCII don't need to be encoded, which should be same on both utf8 and utf16. + encoded.push_back((utility::char_t)ch); } + } + return encoded; +} - builder.set_path(std::move(path)); +// 5.2.3. Merge Paths https://tools.ietf.org/html/rfc3986#section-5.2.3 +utility::string_t mergePaths(const utility::string_t& base, const utility::string_t& relative) +{ + const auto lastSlash = base.rfind(_XPLATSTR('/')); + if (lastSlash == utility::string_t::npos) + { + return base + _XPLATSTR('/') + relative; } + else if (lastSlash == base.size() - 1) + { + return base + relative; + } + // path contains and does not end with '/', we remove segment after last '/' + return base.substr(0, lastSlash + 1) + relative; +} + +// 5.2.4. Remove Dot Segments https://tools.ietf.org/html/rfc3986#section-5.2.4 +void removeDotSegments(uri_builder& builder) +{ + const ::utility::string_t dotSegment = _XPLATSTR("."); + const ::utility::string_t dotDotSegment = _XPLATSTR(".."); + + if (builder.path().find(_XPLATSTR('.')) == utility::string_t::npos) return; + + const auto segments = uri::split_path(builder.path()); + std::vector> result; + for (auto& segment : segments) + { + if (segment == dotSegment) + continue; + else if (segment != dotDotSegment) + result.push_back(segment); + else if (!result.empty()) + result.pop_back(); + } + if (result.empty()) + { + builder.set_path(utility::string_t()); + return; + } + utility::string_t path = result.front().get(); + for (size_t i = 1; i != result.size(); ++i) + { + path += _XPLATSTR('/'); + path += result[i].get(); + } + if (segments.back() == dotDotSegment || segments.back() == dotSegment || builder.path().back() == _XPLATSTR('/')) + { + path += _XPLATSTR('/'); + } + + builder.set_path(std::move(path)); +} } // namespace utility::string_t uri_components::join() @@ -516,14 +505,14 @@ utility::string_t uri_components::join() if (!m_user_info.empty()) { - ret.append(m_user_info).append({ _XPLATSTR('@') }); + ret.append(m_user_info).append({_XPLATSTR('@')}); } ret.append(m_host); if (m_port > 0) { - ret.append({ _XPLATSTR(':') }).append(utility::conversions::details::to_string_t(m_port)); + ret.append({_XPLATSTR(':')}).append(utility::conversions::details::to_string_t(m_port)); } } @@ -554,7 +543,7 @@ utility::string_t uri_components::join() } } // namespace details -uri::uri(const details::uri_components &components) : m_components(components) +uri::uri(const details::uri_components& components) : m_components(components) { m_uri = m_components.join(); @@ -564,9 +553,9 @@ uri::uri(const details::uri_components &components) : m_components(components) } } -uri::uri(const utility::string_t &uri_string) : uri(uri_string.c_str()) {} +uri::uri(const utility::string_t& uri_string) : uri(uri_string.c_str()) {} -uri::uri(const utility::char_t *uri_string) +uri::uri(const utility::char_t* uri_string) { details::inner_parse_out out; @@ -579,22 +568,19 @@ uri::uri(const utility::char_t *uri_string) m_uri = m_components.join(); } -utility::string_t uri::encode_query_impl(const utf8string & raw) +utility::string_t uri::encode_query_impl(const utf8string& raw) { - return details::encode_impl(raw, [](int ch) -> bool - { + return details::encode_impl(raw, [](int ch) -> bool { switch (ch) { - // Encode '&', ';', and '=' since they are used - // as delimiters in query component. - case '&': - case ';': - case '=': - case '%': - case '+': - return true; - default: - return !details::is_query_character(ch); + // Encode '&', ';', and '=' since they are used + // as delimiters in query component. + case '&': + case ';': + case '=': + case '%': + case '+': return true; + default: return !details::is_query_character(ch); } }); } @@ -603,61 +589,44 @@ utility::string_t uri::encode_query_impl(const utf8string & raw) /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their /// hexadecimal representation. /// -utility::string_t uri::encode_data_string(const utility::string_t &data) +utility::string_t uri::encode_data_string(const utility::string_t& data) { auto&& raw = utility::conversions::to_utf8string(data); - return details::encode_impl(raw, [](int ch) -> bool - { - return !details::is_unreserved(ch); - }); + return details::encode_impl(raw, [](int ch) -> bool { return !details::is_unreserved(ch); }); } -utility::string_t uri::encode_uri(const utility::string_t &raw, uri::components::component component) +utility::string_t uri::encode_uri(const utility::string_t& raw, uri::components::component component) { auto&& raw_utf8 = utility::conversions::to_utf8string(raw); // Note: we also encode the '+' character because some non-standard implementations // encode the space character as a '+' instead of %20. To better interoperate we encode // '+' to avoid any confusion and be mistaken as a space. - switch(component) - { - case components::user_info: - return details::encode_impl(raw_utf8, [](int ch) -> bool - { - return !details::is_user_info_character(ch) - || ch == '%' || ch == '+'; - }); - case components::host: - return details::encode_impl(raw_utf8, [](int ch) -> bool - { - // No encoding of ASCII characters in host name (RFC 3986 3.2.2) - return ch > 127; - }); - case components::path: - return details::encode_impl(raw_utf8, [](int ch) -> bool - { - return !details::is_path_character(ch) - || ch == '%' || ch == '+'; - }); - case components::query: - return details::encode_impl(raw_utf8, [](int ch) -> bool - { - return !details::is_query_character(ch) - || ch == '%' || ch == '+'; - }); - case components::fragment: - return details::encode_impl(raw_utf8, [](int ch) -> bool - { - return !details::is_fragment_character(ch) - || ch == '%' || ch == '+'; - }); - case components::full_uri: - default: - return details::encode_impl(raw_utf8, [](int ch) -> bool - { - return !details::is_unreserved(ch) && !details::is_reserved(ch); - }); + switch (component) + { + case components::user_info: + return details::encode_impl(raw_utf8, [](int ch) -> bool { + return !details::is_user_info_character(ch) || ch == '%' || ch == '+'; + }); + case components::host: + return details::encode_impl(raw_utf8, [](int ch) -> bool { + // No encoding of ASCII characters in host name (RFC 3986 3.2.2) + return ch > 127; + }); + case components::path: + return details::encode_impl( + raw_utf8, [](int ch) -> bool { return !details::is_path_character(ch) || ch == '%' || ch == '+'; }); + case components::query: + return details::encode_impl( + raw_utf8, [](int ch) -> bool { return !details::is_query_character(ch) || ch == '%' || ch == '+'; }); + case components::fragment: + return details::encode_impl( + raw_utf8, [](int ch) -> bool { return !details::is_fragment_character(ch) || ch == '%' || ch == '+'; }); + case components::full_uri: + default: + return details::encode_impl( + raw_utf8, [](int ch) -> bool { return !details::is_unreserved(ch) && !details::is_reserved(ch); }); }; } @@ -668,15 +637,15 @@ utility::string_t uri::encode_uri(const utility::string_t &raw, uri::components: static int hex_char_digit_to_decimal_char(int hex) { int decimal; - if(hex >= '0' && hex <= '9') + if (hex >= '0' && hex <= '9') { decimal = hex - '0'; } - else if(hex >= 'A' && hex <= 'F') + else if (hex >= 'A' && hex <= 'F') { decimal = 10 + (hex - 'A'); } - else if(hex >= 'a' && hex <= 'f') + else if (hex >= 'a' && hex <= 'f') { decimal = 10 + (hex - 'a'); } @@ -721,12 +690,9 @@ static std::string decode_template(const String& encoded) return raw; } -utility::string_t uri::decode(const utility::string_t &encoded) -{ - return to_string_t(decode_template(encoded)); -} +utility::string_t uri::decode(const utility::string_t& encoded) { return to_string_t(decode_template(encoded)); } -std::vector uri::split_path(const utility::string_t &path) +std::vector uri::split_path(const utility::string_t& path) { std::vector results; utility::istringstream_t iss(path); @@ -744,17 +710,16 @@ std::vector uri::split_path(const utility::string_t &path) return results; } -std::map uri::split_query(const utility::string_t &query) +std::map uri::split_query(const utility::string_t& query) { std::map results; // Split into key value pairs separated by '&'. size_t prev_amp_index = 0; - while(prev_amp_index != utility::string_t::npos) + while (prev_amp_index != utility::string_t::npos) { size_t amp_index = query.find_first_of(_XPLATSTR('&'), prev_amp_index); - if (amp_index == utility::string_t::npos) - amp_index = query.find_first_of(_XPLATSTR(';'), prev_amp_index); + if (amp_index == utility::string_t::npos) amp_index = query.find_first_of(_XPLATSTR(';'), prev_amp_index); utility::string_t key_value_pair = query.substr( prev_amp_index, @@ -762,7 +727,7 @@ std::map uri::split_query(const utility::s prev_amp_index = amp_index == utility::string_t::npos ? utility::string_t::npos : amp_index + 1; size_t equals_index = key_value_pair.find_first_of(_XPLATSTR('=')); - if(equals_index == utility::string_t::npos) + if (equals_index == utility::string_t::npos) { continue; } @@ -775,14 +740,14 @@ std::map uri::split_query(const utility::s { utility::string_t key(key_value_pair.begin(), key_value_pair.begin() + equals_index); utility::string_t value(key_value_pair.begin() + equals_index + 1, key_value_pair.end()); - results[key] = value; + results[key] = value; } } return results; } -bool uri::validate(const utility::string_t &uri_string) +bool uri::validate(const utility::string_t& uri_string) { details::inner_parse_out out; return out.parse_from(uri_string.c_str()); @@ -790,7 +755,12 @@ bool uri::validate(const utility::string_t &uri_string) uri uri::authority() const { - return uri_builder().set_scheme(this->scheme()).set_host(this->host()).set_port(this->port()).set_user_info(this->user_info()).to_uri(); + return uri_builder() + .set_scheme(this->scheme()) + .set_host(this->host()) + .set_port(this->port()) + .set_user_info(this->user_info()) + .to_uri(); } uri uri::resource() const @@ -798,7 +768,7 @@ uri uri::resource() const return uri_builder().set_path(this->path()).set_query(this->query()).set_fragment(this->fragment()).to_uri(); } -bool uri::operator == (const uri &other) const +bool uri::operator==(const uri& other) const { // Each individual URI component must be decoded before performing comparison. // TFS # 375865 @@ -816,7 +786,7 @@ bool uri::operator == (const uri &other) const // scheme is canonicalized to lowercase return false; } - else if(uri::decode(this->user_info()) != uri::decode(other.user_info())) + else if (uri::decode(this->user_info()) != uri::decode(other.user_info())) { return false; } @@ -845,17 +815,17 @@ bool uri::operator == (const uri &other) const return true; } -//resolving URI according to RFC3986, Section 5 https://tools.ietf.org/html/rfc3986#section-5 -utility::string_t uri::resolve_uri(const utility::string_t &relativeUri) const +// resolving URI according to RFC3986, Section 5 https://tools.ietf.org/html/rfc3986#section-5 +utility::string_t uri::resolve_uri(const utility::string_t& relativeUri) const { if (relativeUri.empty()) { return to_string(); } - if (relativeUri[0] == _XPLATSTR('/')) // starts with '/' + if (relativeUri[0] == _XPLATSTR('/')) // starts with '/' { - if (relativeUri.size() >= 2 && relativeUri[1] == _XPLATSTR('/')) // starts with '//' + if (relativeUri.size() >= 2 && relativeUri[1] == _XPLATSTR('/')) // starts with '//' { return this->scheme() + _XPLATSTR(':') + relativeUri; } @@ -868,17 +838,16 @@ utility::string_t uri::resolve_uri(const utility::string_t &relativeUri) const } const auto url = uri(relativeUri); - if (!url.scheme().empty()) - return relativeUri; + if (!url.scheme().empty()) return relativeUri; if (!url.authority().is_empty()) - { + { return uri_builder(url).set_scheme(this->scheme()).to_string(); - } + } // relative url auto builder = uri_builder(*this); - if (url.path() == _XPLATSTR("/") || url.path().empty()) // web::uri considers empty path as '/' + if (url.path() == _XPLATSTR("/") || url.path().empty()) // web::uri considers empty path as '/' { if (!url.query().empty()) { diff --git a/Release/src/uri/uri_builder.cpp b/Release/src/uri/uri_builder.cpp index 0135610466..e1bb0a1552 100644 --- a/Release/src/uri/uri_builder.cpp +++ b/Release/src/uri/uri_builder.cpp @@ -2,13 +2,13 @@ * Copyright (C) Microsoft. All rights reserved. * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * - * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * Builder for constructing URIs. * * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk * - * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index 0bafacd514..4269774781 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -1,21 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Utilities -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Utilities + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include + #include -#include +#include #include +#include #ifndef _WIN32 #if defined(__clang__) @@ -35,77 +36,71 @@ using namespace utility::conversions; namespace { - struct to_lower_ch_impl +struct to_lower_ch_impl +{ + char operator()(char c) const CPPREST_NOEXCEPT { - char operator()(char c) const CPPREST_NOEXCEPT - { - if (c >= 'A' && c <= 'Z') - return static_cast(c - 'A' + 'a'); - return c; - } + if (c >= 'A' && c <= 'Z') return static_cast(c - 'A' + 'a'); + return c; + } - wchar_t operator()(wchar_t c) const CPPREST_NOEXCEPT - { - if (c >= L'A' && c <= L'Z') - return static_cast(c - L'A' + L'a'); - return c; - } - }; + wchar_t operator()(wchar_t c) const CPPREST_NOEXCEPT + { + if (c >= L'A' && c <= L'Z') return static_cast(c - L'A' + L'a'); + return c; + } +}; - CPPREST_CONSTEXPR to_lower_ch_impl to_lower_ch{}; +CPPREST_CONSTEXPR to_lower_ch_impl to_lower_ch {}; - struct eq_lower_ch_impl +struct eq_lower_ch_impl +{ + template + inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT { - template - inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT - { - return to_lower_ch(left) == to_lower_ch(right); - } - }; + return to_lower_ch(left) == to_lower_ch(right); + } +}; - CPPREST_CONSTEXPR eq_lower_ch_impl eq_lower_ch{}; +CPPREST_CONSTEXPR eq_lower_ch_impl eq_lower_ch {}; - struct lt_lower_ch_impl +struct lt_lower_ch_impl +{ + template + inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT { - template - inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT - { - return to_lower_ch(left) < to_lower_ch(right); - } - }; - - CPPREST_CONSTEXPR lt_lower_ch_impl lt_lower_ch{}; + return to_lower_ch(left) < to_lower_ch(right); } +}; + +CPPREST_CONSTEXPR lt_lower_ch_impl lt_lower_ch {}; +} // namespace namespace utility { - namespace details { - -_ASYNCRTIMP bool __cdecl str_iequal(const std::string &left, const std::string &right) CPPREST_NOEXCEPT +_ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& right) CPPREST_NOEXCEPT { - return left.size() == right.size() - && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); + return left.size() == right.size() && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); } -_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT +_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT { - return left.size() == right.size() - && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); + return left.size() == right.size() && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); } -_ASYNCRTIMP bool __cdecl str_iless(const std::string &left, const std::string &right) CPPREST_NOEXCEPT +_ASYNCRTIMP bool __cdecl str_iless(const std::string& left, const std::string& right) CPPREST_NOEXCEPT { return std::lexicographical_compare(left.cbegin(), left.cend(), right.cbegin(), right.cend(), lt_lower_ch); } -_ASYNCRTIMP bool __cdecl str_iless(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT +_ASYNCRTIMP bool __cdecl str_iless(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT { return std::lexicographical_compare(left.cbegin(), left.cend(), right.cbegin(), right.cend(), lt_lower_ch); } -_ASYNCRTIMP void __cdecl inplace_tolower(std::string &target) CPPREST_NOEXCEPT +_ASYNCRTIMP void __cdecl inplace_tolower(std::string& target) CPPREST_NOEXCEPT { for (auto& ch : target) { @@ -113,7 +108,7 @@ _ASYNCRTIMP void __cdecl inplace_tolower(std::string &target) CPPREST_NOEXCEPT } } -_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring &target) CPPREST_NOEXCEPT +_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring& target) CPPREST_NOEXCEPT { for (auto& ch : target) { @@ -123,20 +118,19 @@ _ASYNCRTIMP void __cdecl inplace_tolower(std::wstring &target) CPPREST_NOEXCEPT #if !defined(ANDROID) && !defined(__ANDROID__) std::once_flag g_c_localeFlag; -std::unique_ptr g_c_locale(nullptr, [](scoped_c_thread_locale::xplat_locale *){}); +std::unique_ptr g_c_locale( + nullptr, [](scoped_c_thread_locale::xplat_locale*) {}); scoped_c_thread_locale::xplat_locale scoped_c_thread_locale::c_locale() { - std::call_once(g_c_localeFlag, [&]() - { - scoped_c_thread_locale::xplat_locale *clocale = new scoped_c_thread_locale::xplat_locale(); + std::call_once(g_c_localeFlag, [&]() { + scoped_c_thread_locale::xplat_locale* clocale = new scoped_c_thread_locale::xplat_locale(); #ifdef _WIN32 *clocale = _create_locale(LC_ALL, "C"); if (clocale == nullptr || *clocale == nullptr) { throw std::runtime_error("Unable to create 'C' locale."); } - auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale) - { + auto deleter = [](scoped_c_thread_locale::xplat_locale* clocale) { _free_locale(*clocale); delete clocale; }; @@ -152,17 +146,18 @@ scoped_c_thread_locale::xplat_locale scoped_c_thread_locale::c_locale() delete clocale; }; #endif - g_c_locale = std::unique_ptr(clocale, deleter); + g_c_locale = + std::unique_ptr( + clocale, deleter); }); return *g_c_locale; } #endif #ifdef _WIN32 -scoped_c_thread_locale::scoped_c_thread_locale() - : m_prevLocale(), m_prevThreadSetting(-1) +scoped_c_thread_locale::scoped_c_thread_locale() : m_prevLocale(), m_prevThreadSetting(-1) { - char *prevLocale = setlocale(LC_ALL, nullptr); + char* prevLocale = setlocale(LC_ALL, nullptr); if (prevLocale == nullptr) { throw std::runtime_error("Unable to retrieve current locale."); @@ -178,8 +173,8 @@ scoped_c_thread_locale::scoped_c_thread_locale() } if (setlocale(LC_ALL, "C") == nullptr) { - _configthreadlocale(m_prevThreadSetting); - throw std::runtime_error("Unable to set locale"); + _configthreadlocale(m_prevThreadSetting); + throw std::runtime_error("Unable to set locale"); } } } @@ -196,10 +191,9 @@ scoped_c_thread_locale::~scoped_c_thread_locale() scoped_c_thread_locale::scoped_c_thread_locale() {} scoped_c_thread_locale::~scoped_c_thread_locale() {} #else -scoped_c_thread_locale::scoped_c_thread_locale() - : m_prevLocale(nullptr) +scoped_c_thread_locale::scoped_c_thread_locale() : m_prevLocale(nullptr) { - char *prevLocale = setlocale(LC_ALL, nullptr); + char* prevLocale = setlocale(LC_ALL, nullptr); if (prevLocale == nullptr) { throw std::runtime_error("Unable to retrieve current locale."); @@ -223,12 +217,11 @@ scoped_c_thread_locale::~scoped_c_thread_locale() } } #endif -} +} // namespace details namespace details { - -const std::error_category & __cdecl platform_category() +const std::error_category& __cdecl platform_category() { #ifdef _WIN32 return windows_category(); @@ -243,7 +236,7 @@ const std::error_category & __cdecl platform_category() #if _MSC_VER < 1900 static details::windows_category_impl instance; #endif -const std::error_category & __cdecl windows_category() +const std::error_category& __cdecl windows_category() { #if _MSC_VER >= 1900 static details::windows_category_impl instance; @@ -267,15 +260,7 @@ std::string windows_category_impl::message(int errorCode) const CPPREST_NOEXCEPT std::wstring buffer(buffer_size, 0); - const auto result = ::FormatMessageW( - dwFlags, - lpSource, - errorCode, - 0, - &buffer[0], - buffer_size, - NULL); - + const auto result = ::FormatMessageW(dwFlags, lpSource, errorCode, 0, &buffer[0], buffer_size, NULL); if (result == 0) { @@ -293,30 +278,23 @@ std::error_condition windows_category_impl::default_error_condition(int errorCod // First see if the STL implementation can handle the mapping for common cases. const std::error_condition errCondition = std::system_category().default_error_condition(errorCode); const std::string errConditionMsg = errCondition.message(); - if(!utility::details::str_iequal(errConditionMsg, "unknown error")) + if (!utility::details::str_iequal(errConditionMsg, "unknown error")) { return errCondition; } - switch(errorCode) + switch (errorCode) { #ifndef __cplusplus_winrt - case ERROR_WINHTTP_TIMEOUT: - return std::errc::timed_out; - case ERROR_WINHTTP_CANNOT_CONNECT: - return std::errc::host_unreachable; - case ERROR_WINHTTP_CONNECTION_ERROR: - return std::errc::connection_aborted; + case ERROR_WINHTTP_TIMEOUT: return std::errc::timed_out; + case ERROR_WINHTTP_CANNOT_CONNECT: return std::errc::host_unreachable; + case ERROR_WINHTTP_CONNECTION_ERROR: return std::errc::connection_aborted; #endif - case INET_E_RESOURCE_NOT_FOUND: - case INET_E_CANNOT_CONNECT: - return std::errc::host_unreachable; - case INET_E_CONNECTION_TIMEOUT: - return std::errc::timed_out; - case INET_E_DOWNLOAD_FAILURE: - return std::errc::connection_aborted; - default: - break; + case INET_E_RESOURCE_NOT_FOUND: + case INET_E_CANNOT_CONNECT: return std::errc::host_unreachable; + case INET_E_CONNECTION_TIMEOUT: return std::errc::timed_out; + case INET_E_DOWNLOAD_FAILURE: return std::errc::connection_aborted; + default: break; } return std::error_condition(errorCode, *this); @@ -324,7 +302,7 @@ std::error_condition windows_category_impl::default_error_condition(int errorCod #else -const std::error_category & __cdecl linux_category() +const std::error_category& __cdecl linux_category() { // On Linux we are using boost error codes which have the exact same // mapping and are equivalent with std::generic_category error codes. @@ -333,7 +311,7 @@ const std::error_category & __cdecl linux_category() #endif -} +} // namespace details #define LOW_3BITS 0x7 #define LOW_4BITS 0xF @@ -355,16 +333,15 @@ const std::error_category & __cdecl linux_category() // or unsigned. using UtilCharInternal_t = signed char; - inline size_t count_utf8_to_utf16(const std::string& s) { const size_t sSize = s.size(); auto const sData = reinterpret_cast(s.data()); - size_t result{ sSize }; + size_t result {sSize}; for (size_t index = 0; index < sSize;) { - if( sData[index] > 0 ) + if (sData[index] > 0) { // use fast inner loop to skip single byte code points (which are // expected to be the most frequent) @@ -375,7 +352,7 @@ inline size_t count_utf8_to_utf16(const std::string& s) } // start special handling for multi-byte code points - const UtilCharInternal_t c{ sData[index++] }; + const UtilCharInternal_t c {sData[index++]}; if ((c & BIT7) == 0) { @@ -388,7 +365,7 @@ inline size_t count_utf8_to_utf16(const std::string& s) throw std::range_error("UTF-8 string is missing bytes in character"); } - const UtilCharInternal_t c2{ sData[index++] }; + const UtilCharInternal_t c2 {sData[index++]}; if ((c2 & 0xC0) != BIT8) { throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); @@ -404,8 +381,8 @@ inline size_t count_utf8_to_utf16(const std::string& s) throw std::range_error("UTF-8 string is missing bytes in character"); } - const UtilCharInternal_t c2{ sData[index++] }; - const UtilCharInternal_t c3{ sData[index++] }; + const UtilCharInternal_t c2 {sData[index++]}; + const UtilCharInternal_t c3 {sData[index++]}; if (((c2 | c3) & 0xC0) != BIT8) { throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); @@ -420,15 +397,16 @@ inline size_t count_utf8_to_utf16(const std::string& s) throw std::range_error("UTF-8 string is missing bytes in character"); } - const UtilCharInternal_t c2{ sData[index++] }; - const UtilCharInternal_t c3{ sData[index++] }; - const UtilCharInternal_t c4{ sData[index++] }; + const UtilCharInternal_t c2 {sData[index++]}; + const UtilCharInternal_t c3 {sData[index++]}; + const UtilCharInternal_t c4 {sData[index++]}; if (((c2 | c3 | c4) & 0xC0) != BIT8) { throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); } - const uint32_t codePoint = ((c & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); + const uint32_t codePoint = + ((c & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); result -= (3 - (codePoint >= SURROGATE_PAIR_START)); } else @@ -440,7 +418,7 @@ inline size_t count_utf8_to_utf16(const std::string& s) return result; } -utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) +utf16string __cdecl conversions::utf8_to_utf16(const std::string& s) { // Save repeated heap allocations, use the length of resulting sequence. const size_t srcSize = s.size(); @@ -454,12 +432,13 @@ utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) UtilCharInternal_t src = srcData[index]; switch (src & 0xF0) { - case 0xF0: // 4 byte character, 0x10000 to 0x10FFFF + case 0xF0: // 4 byte character, 0x10000 to 0x10FFFF { - const UtilCharInternal_t c2{ srcData[++index] }; - const UtilCharInternal_t c3{ srcData[++index] }; - const UtilCharInternal_t c4{ srcData[++index] }; - uint32_t codePoint = ((src & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); + const UtilCharInternal_t c2 {srcData[++index]}; + const UtilCharInternal_t c3 {srcData[++index]}; + const UtilCharInternal_t c4 {srcData[++index]}; + uint32_t codePoint = + ((src & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); if (codePoint >= SURROGATE_PAIR_START) { // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs. @@ -468,49 +447,51 @@ utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) // - low surrogate is 0xDC00 added to the low ten bits codePoint -= SURROGATE_PAIR_START; destData[destIndex++] = static_cast((codePoint >> 10) | H_SURROGATE_START); - destData[destIndex++] = static_cast((codePoint & 0x3FF) | L_SURROGATE_START); + destData[destIndex++] = + static_cast((codePoint & 0x3FF) | L_SURROGATE_START); } else { - // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point value. - // U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present but will encode - // them if encountered. + // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point + // value. U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present + // but will encode them if encountered. destData[destIndex++] = static_cast(codePoint); } } break; - case 0xE0: // 3 byte character, 0x800 to 0xFFFF + case 0xE0: // 3 byte character, 0x800 to 0xFFFF { - const UtilCharInternal_t c2{ srcData[++index] }; - const UtilCharInternal_t c3{ srcData[++index] }; - destData[destIndex++] = static_cast(((src & LOW_4BITS) << 12) | ((c2 & LOW_6BITS) << 6) | (c3 & LOW_6BITS)); + const UtilCharInternal_t c2 {srcData[++index]}; + const UtilCharInternal_t c3 {srcData[++index]}; + destData[destIndex++] = static_cast( + ((src & LOW_4BITS) << 12) | ((c2 & LOW_6BITS) << 6) | (c3 & LOW_6BITS)); } break; - case 0xD0: // 2 byte character, 0x80 to 0x7FF - case 0xC0: + case 0xD0: // 2 byte character, 0x80 to 0x7FF + case 0xC0: { - const UtilCharInternal_t c2{ srcData[++index] }; - destData[destIndex++] = static_cast(((src & LOW_5BITS) << 6) | (c2 & LOW_6BITS)); + const UtilCharInternal_t c2 {srcData[++index]}; + destData[destIndex++] = + static_cast(((src & LOW_5BITS) << 6) | (c2 & LOW_6BITS)); } break; - default: // single byte character, 0x0 to 0x7F - // try to use a fast inner loop for following single byte characters, - // since they are quite probable - do - { - destData[destIndex++] = static_cast(srcData[index++]); - } while (index < srcSize && srcData[index] > 0); - // adjust index since it will be incremented by the for loop - --index; + default: // single byte character, 0x0 to 0x7F + // try to use a fast inner loop for following single byte characters, + // since they are quite probable + do + { + destData[destIndex++] = static_cast(srcData[index++]); + } while (index < srcSize && srcData[index] > 0); + // adjust index since it will be incremented by the for loop + --index; } } return dest; } - -inline size_t count_utf16_to_utf8(const utf16string &w) +inline size_t count_utf16_to_utf8(const utf16string& w) { - const utf16string::value_type * const srcData = &w[0]; + const utf16string::value_type* const srcData = &w[0]; const size_t srcSize = w.size(); size_t destSize(srcSize); for (size_t index = 0; index < srcSize; ++index) @@ -549,7 +530,7 @@ inline size_t count_utf16_to_utf8(const utf16string &w) return destSize; } -std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) +std::string __cdecl conversions::utf16_to_utf8(const utf16string& w) { const size_t srcSize = w.size(); const utf16string::value_type* const srcData = &w[0]; @@ -568,8 +549,8 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) } else // 2 bytes needed (11 bits used) { - destData[destIndex++] = static_cast(char((src >> 6) | 0xC0)); // leading 5 bits - destData[destIndex++] = static_cast(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits + destData[destIndex++] = static_cast(char((src >> 6) | 0xC0)); // leading 5 bits + destData[destIndex++] = static_cast(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits } } // Check for high surrogate. @@ -589,10 +570,10 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) codePoint += SURROGATE_PAIR_START; // 4 bytes needed (21 bits used) - destData[destIndex++] = static_cast((codePoint >> 18) | 0xF0); // leading 3 bits - destData[destIndex++] = static_cast(((codePoint >> 12) & LOW_6BITS) | BIT8); // next 6 bits - destData[destIndex++] = static_cast(((codePoint >> 6) & LOW_6BITS) | BIT8); // next 6 bits - destData[destIndex++] = static_cast((codePoint & LOW_6BITS) | BIT8); // trailing 6 bits + destData[destIndex++] = static_cast((codePoint >> 18) | 0xF0); // leading 3 bits + destData[destIndex++] = static_cast(((codePoint >> 12) & LOW_6BITS) | BIT8); // next 6 bits + destData[destIndex++] = static_cast(((codePoint >> 6) & LOW_6BITS) | BIT8); // next 6 bits + destData[destIndex++] = static_cast((codePoint & LOW_6BITS) | BIT8); // trailing 6 bits } else // 3 bytes needed (16 bits used) { @@ -605,13 +586,13 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) return dest; } -utf16string __cdecl conversions::usascii_to_utf16(const std::string &s) +utf16string __cdecl conversions::usascii_to_utf16(const std::string& s) { // Ascii is a subset of UTF-8 so just convert to UTF-16 return utf8_to_utf16(s); } -utf16string __cdecl conversions::latin1_to_utf16(const std::string &s) +utf16string __cdecl conversions::latin1_to_utf16(const std::string& s) { // Latin1 is the first 256 code points in Unicode. // In UTF-16 encoding each of these is represented as exactly the numeric code point. @@ -626,49 +607,34 @@ utf16string __cdecl conversions::latin1_to_utf16(const std::string &s) return dest; } -utf8string __cdecl conversions::latin1_to_utf8(const std::string &s) -{ - return utf16_to_utf8(latin1_to_utf16(s)); -} +utf8string __cdecl conversions::latin1_to_utf8(const std::string& s) { return utf16_to_utf8(latin1_to_utf16(s)); } #ifndef _UTF16_STRINGS -utility::string_t __cdecl conversions::to_string_t(utf16string &&s) -{ - return utf16_to_utf8(std::move(s)); -} +utility::string_t __cdecl conversions::to_string_t(utf16string&& s) { return utf16_to_utf8(std::move(s)); } #endif #ifdef _UTF16_STRINGS -utility::string_t __cdecl conversions::to_string_t(std::string &&s) -{ - return utf8_to_utf16(std::move(s)); -} +utility::string_t __cdecl conversions::to_string_t(std::string&& s) { return utf8_to_utf16(std::move(s)); } #endif #ifndef _UTF16_STRINGS -utility::string_t __cdecl conversions::to_string_t(const utf16string &s) -{ - return utf16_to_utf8(s); -} +utility::string_t __cdecl conversions::to_string_t(const utf16string& s) { return utf16_to_utf8(s); } #endif #ifdef _UTF16_STRINGS -utility::string_t __cdecl conversions::to_string_t(const std::string &s) -{ - return utf8_to_utf16(s); -} +utility::string_t __cdecl conversions::to_string_t(const std::string& s) { return utf8_to_utf16(s); } #endif -std::string __cdecl conversions::to_utf8string(const utf16string &value) { return utf16_to_utf8(value); } +std::string __cdecl conversions::to_utf8string(const utf16string& value) { return utf16_to_utf8(value); } -utf16string __cdecl conversions::to_utf16string(const std::string &value) { return utf8_to_utf16(value); } +utf16string __cdecl conversions::to_utf16string(const std::string& value) { return utf8_to_utf16(value); } #ifndef WIN32 -datetime datetime::timeval_to_datetime(const timeval &time) +datetime datetime::timeval_to_datetime(const timeval& time) { const uint64_t epoch_offset = 11644473600LL; // diff between windows and unix epochs (seconds) uint64_t result = epoch_offset + time.tv_sec; - result *= _secondTicks; // convert to 10e-7 + result *= _secondTicks; // convert to 10e-7 result += time.tv_usec * 10; // convert and add microseconds, 10e-6 to 10e-7 return datetime(result); } @@ -687,7 +653,7 @@ datetime __cdecl datetime::utc_now() largeInt.HighPart = fileTime.dwHighDateTime; return datetime(largeInt.QuadPart); -#else //LINUX +#else // LINUX struct timeval time; gettimeofday(&time, nullptr); return timeval_to_datetime(time); @@ -707,7 +673,7 @@ utility::string_t datetime::to_string(date_format format) const ft.dwLowDateTime = largeInt.LowPart; SYSTEMTIME systemTime; - if (!FileTimeToSystemTime((const FILETIME *)&ft, &systemTime)) + if (!FileTimeToSystemTime((const FILETIME*)&ft, &systemTime)) { throw utility::details::create_system_error(GetLastError()); } @@ -718,9 +684,16 @@ utility::string_t datetime::to_string(date_format format) const { wchar_t dateStr[18] = {0}; #if _WIN32_WINNT < _WIN32_WINNT_VISTA - status = GetDateFormatW(LOCALE_INVARIANT, 0, &systemTime, L"ddd',' dd MMM yyyy", dateStr, sizeof(dateStr) / sizeof(wchar_t)); + status = GetDateFormatW( + LOCALE_INVARIANT, 0, &systemTime, L"ddd',' dd MMM yyyy", dateStr, sizeof(dateStr) / sizeof(wchar_t)); #else - status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L"ddd',' dd MMM yyyy", dateStr, sizeof(dateStr) / sizeof(wchar_t), NULL); + status = GetDateFormatEx(LOCALE_NAME_INVARIANT, + 0, + &systemTime, + L"ddd',' dd MMM yyyy", + dateStr, + sizeof(dateStr) / sizeof(wchar_t), + NULL); #endif // _WIN32_WINNT < _WIN32_WINNT_VISTA if (status == 0) { @@ -734,9 +707,19 @@ utility::string_t datetime::to_string(date_format format) const { wchar_t timeStr[10] = {0}; #if _WIN32_WINNT < _WIN32_WINNT_VISTA - status = GetTimeFormatW(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, sizeof(timeStr) / sizeof(wchar_t)); + status = GetTimeFormatW(LOCALE_INVARIANT, + TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, + &systemTime, + L"HH':'mm':'ss", + timeStr, + sizeof(timeStr) / sizeof(wchar_t)); #else - status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, sizeof(timeStr) / sizeof(wchar_t)); + status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, + TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, + &systemTime, + L"HH':'mm':'ss", + timeStr, + sizeof(timeStr) / sizeof(wchar_t)); #endif // _WIN32_WINNT < _WIN32_WINNT_VISTA if (status == 0) { @@ -746,7 +729,6 @@ utility::string_t datetime::to_string(date_format format) const result += timeStr; result += L" GMT"; } - } else if (format == ISO_8601) { @@ -770,27 +752,37 @@ utility::string_t datetime::to_string(date_format format) const { wchar_t timeStr[buffSize] = {0}; #if _WIN32_WINNT < _WIN32_WINNT_VISTA - status = GetTimeFormatW(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, buffSize); + status = GetTimeFormatW(LOCALE_INVARIANT, + TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, + &systemTime, + L"HH':'mm':'ss", + timeStr, + buffSize); #else - status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, buffSize); + status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, + TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, + &systemTime, + L"HH':'mm':'ss", + timeStr, + buffSize); #endif // _WIN32_WINNT < _WIN32_WINNT_VISTA if (status == 0) { - throw utility::details::create_system_error(GetLastError()); + throw utility::details::create_system_error(GetLastError()); } result += timeStr; } - uint64_t frac_sec = largeInt.QuadPart % _secondTicks; if (frac_sec > 0) { // Append fractional second, which is a 7-digit value with no trailing zeros // This way, '1200' becomes '00012' - wchar_t buf[9] = { 0 }; + wchar_t buf[9] = {0}; size_t appended = swprintf_s(buf, 9, L".%07ld", static_cast(frac_sec)); - while (buf[appended - 1] == L'0') --appended; // trim trailing zeros + while (buf[appended - 1] == L'0') + --appended; // trim trailing zeros result.append(buf, appended); } @@ -798,38 +790,38 @@ utility::string_t datetime::to_string(date_format format) const } return result; -#else //LINUX +#else // LINUX uint64_t input = m_interval; uint64_t frac_sec = input % _secondTicks; - input /= _secondTicks; // convert to seconds - time_t time = (time_t)input - (time_t)11644473600LL;// diff between windows and unix epochs (seconds) + input /= _secondTicks; // convert to seconds + time_t time = (time_t)input - (time_t)11644473600LL; // diff between windows and unix epochs (seconds) struct tm datetime; gmtime_r(&time, &datetime); const int max_dt_length = 64; - char output[max_dt_length+1] = {0}; + char output[max_dt_length + 1] = {0}; if (format != RFC_1123 && frac_sec > 0) { // Append fractional second, which is a 7-digit value with no trailing zeros // This way, '1200' becomes '00012' const int max_frac_length = 8; - char buf[max_frac_length+1] = { 0 }; + char buf[max_frac_length + 1] = {0}; snprintf(buf, sizeof(buf), ".%07ld", (long int)frac_sec); // trim trailing zeros - for (int i = max_frac_length-1; buf[i] == '0'; i--) buf[i] = '\0'; + for (int i = max_frac_length - 1; buf[i] == '0'; i--) + buf[i] = '\0'; // format the datetime into a separate buffer - char datetime_str[max_dt_length-max_frac_length-1+1] = {0}; + char datetime_str[max_dt_length - max_frac_length - 1 + 1] = {0}; strftime(datetime_str, sizeof(datetime_str), "%Y-%m-%dT%H:%M:%S", &datetime); // now print this buffer into the output buffer snprintf(output, sizeof(output), "%s%sZ", datetime_str, buf); } else { - strftime(output, sizeof(output), - format == RFC_1123 ? "%a, %d %b %Y %H:%M:%S GMT" : "%Y-%m-%dT%H:%M:%SZ", - &datetime); + strftime( + output, sizeof(output), format == RFC_1123 ? "%a, %d %b %Y %H:%M:%S GMT" : "%Y-%m-%dT%H:%M:%SZ", &datetime); } return std::string(output); @@ -837,7 +829,7 @@ utility::string_t datetime::to_string(date_format format) const } #ifdef _WIN32 -bool __cdecl datetime::system_type_to_datetime(void* pvsysTime, uint64_t seconds, datetime * pdt) +bool __cdecl datetime::system_type_to_datetime(void* pvsysTime, uint64_t seconds, datetime* pdt) { SYSTEMTIME* psysTime = (SYSTEMTIME*)pvsysTime; FILETIME fileTime; @@ -876,7 +868,9 @@ uint64_t timeticks_from_second(StringIterator begin, StringIterator end) return ufrac_second; } -void extract_fractional_second(const utility::string_t& dateString, utility::string_t& resultString, uint64_t& ufrac_second) +void extract_fractional_second(const utility::string_t& dateString, + utility::string_t& resultString, + uint64_t& ufrac_second) { resultString = dateString; // First, the string must be strictly longer than 2 characters, and the trailing character must be 'Z' @@ -914,25 +908,31 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date std::wstring month(3, L'\0'); std::wstring unused(3, L'\0'); - const wchar_t * formatString = L"%3c, %2d %3c %4d %2d:%2d:%2d %3c"; - auto n = swscanf_s(dateString.c_str(), formatString, - unused.data(), unused.size(), - &sysTime.wDay, - month.data(), month.size(), - &sysTime.wYear, - &sysTime.wHour, - &sysTime.wMinute, - &sysTime.wSecond, - unused.data(), unused.size()); + const wchar_t* formatString = L"%3c, %2d %3c %4d %2d:%2d:%2d %3c"; + auto n = swscanf_s(dateString.c_str(), + formatString, + unused.data(), + unused.size(), + &sysTime.wDay, + month.data(), + month.size(), + &sysTime.wYear, + &sysTime.wHour, + &sysTime.wMinute, + &sysTime.wSecond, + unused.data(), + unused.size()); if (n == 8) { - std::wstring monthnames[12] = {L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec"}; - auto loc = std::find_if(monthnames, monthnames+12, [&month](const std::wstring& m) { return m == month;}); + std::wstring monthnames[12] = { + L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec"}; + auto loc = + std::find_if(monthnames, monthnames + 12, [&month](const std::wstring& m) { return m == month; }); - if (loc != monthnames+12) + if (loc != monthnames + 12) { - sysTime.wMonth = (short) ((loc - monthnames) + 1); + sysTime.wMonth = (short)((loc - monthnames) + 1); if (system_type_to_datetime(&sysTime, ufrac_second, &result)) { return result; @@ -949,15 +949,16 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date utility::string_t input; extract_fractional_second(dateString, input, ufrac_second); { - SYSTEMTIME sysTime = { 0 }; - const wchar_t * formatString = L"%4d-%2d-%2dT%2d:%2d:%2dZ"; - auto n = swscanf_s(input.c_str(), formatString, - &sysTime.wYear, - &sysTime.wMonth, - &sysTime.wDay, - &sysTime.wHour, - &sysTime.wMinute, - &sysTime.wSecond); + SYSTEMTIME sysTime = {0}; + const wchar_t* formatString = L"%4d-%2d-%2dT%2d:%2d:%2dZ"; + auto n = swscanf_s(input.c_str(), + formatString, + &sysTime.wYear, + &sysTime.wMonth, + &sysTime.wDay, + &sysTime.wHour, + &sysTime.wMinute, + &sysTime.wSecond); if (n == 3 || n == 6) { @@ -971,12 +972,8 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date SYSTEMTIME sysTime = {0}; DWORD date = 0; - const wchar_t * formatString = L"%8dT%2d:%2d:%2dZ"; - auto n = swscanf_s(input.c_str(), formatString, - &date, - &sysTime.wHour, - &sysTime.wMinute, - &sysTime.wSecond); + const wchar_t* formatString = L"%8dT%2d:%2d:%2dZ"; + auto n = swscanf_s(input.c_str(), formatString, &date, &sysTime.wHour, &sysTime.wMinute, &sysTime.wSecond); if (n == 1 || n == 4) { @@ -994,15 +991,12 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date } { SYSTEMTIME sysTime = {0}; - GetSystemTime(&sysTime); // Fill date portion with today's information + GetSystemTime(&sysTime); // Fill date portion with today's information sysTime.wSecond = 0; sysTime.wMilliseconds = 0; - const wchar_t * formatString = L"%2d:%2d:%2dZ"; - auto n = swscanf_s(input.c_str(), formatString, - &sysTime.wHour, - &sysTime.wMinute, - &sysTime.wSecond); + const wchar_t* formatString = L"%2d:%2d:%2dZ"; + auto n = swscanf_s(input.c_str(), formatString, &sysTime.wHour, &sysTime.wMinute, &sysTime.wSecond); if (n == 3) { @@ -1117,7 +1111,7 @@ utility::string_t __cdecl timespan::seconds_to_xml_duration(utility::seconds dur auto numSecs = durationSecs.count(); // Find the number of minutes - auto numMins = numSecs / 60; + auto numMins = numSecs / 60; if (numMins > 0) { numSecs = numSecs % 60; @@ -1179,7 +1173,7 @@ utility::string_t __cdecl timespan::seconds_to_xml_duration(utility::seconds dur return result; } -utility::seconds __cdecl timespan::xml_duration_to_seconds(const utility::string_t ×panString) +utility::seconds __cdecl timespan::xml_duration_to_seconds(const utility::string_t& timespanString) { // The format is: // PnDTnHnMnS @@ -1208,13 +1202,16 @@ utility::seconds __cdecl timespan::xml_duration_to_seconds(const utility::string if (c == '.') { // decimal point is not handled - do { c = is.get(); } while(is_digit((utility::char_t)c)); + do + { + c = is.get(); + } while (is_digit((utility::char_t)c)); } } if (c == L'D') numSecs += val * 24 * 3600; // days - if (c == L'H') numSecs += val * 3600; // Hours - if (c == L'M') numSecs += val * 60; // Minutes + if (c == L'H') numSecs += val * 3600; // Hours + if (c == L'M') numSecs += val * 60; // Minutes if (c == L'S' || c == eof) { numSecs += val; // seconds @@ -1225,16 +1222,16 @@ utility::seconds __cdecl timespan::xml_duration_to_seconds(const utility::string return utility::seconds(numSecs); } -const utility::string_t nonce_generator::c_allowed_chars(_XPLATSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")); +const utility::string_t nonce_generator::c_allowed_chars( + _XPLATSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")); utility::string_t nonce_generator::generate() { std::uniform_int_distribution<> distr(0, static_cast(c_allowed_chars.length() - 1)); utility::string_t result; result.reserve(length()); - std::generate_n(std::back_inserter(result), length(), [&]() { return c_allowed_chars[distr(m_random)]; } ); + std::generate_n(std::back_inserter(result), length(), [&]() { return c_allowed_chars[distr(m_random)]; }); return result; } - -} +} // namespace utility diff --git a/Release/src/utilities/base64.cpp b/Release/src/utilities/base64.cpp index 8e29289deb..1cb235c3b5 100644 --- a/Release/src/utilities/base64.cpp +++ b/Release/src/utilities/base64.cpp @@ -1,25 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; using namespace utility; std::vector _from_base64(const utility::string_t& str); -utility::string_t _to_base64(const unsigned char *ptr, size_t size); +utility::string_t _to_base64(const unsigned char* ptr, size_t size); -std::vector __cdecl conversions::from_base64(const utility::string_t& str) -{ - return _from_base64(str); -} +std::vector __cdecl conversions::from_base64(const utility::string_t& str) { return _from_base64(str); } utility::string_t __cdecl conversions::to_base64(const std::vector& input) { @@ -38,30 +35,28 @@ utility::string_t __cdecl conversions::to_base64(uint64_t input) } static const char* _base64_enctbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -const std::array _base64_dectbl = - {{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 254, 255, 255, - 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 }}; +const std::array _base64_dectbl = { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, + 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 254, 255, 255, 255, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255}}; struct _triple_byte { unsigned char _1_1 : 2; - unsigned char _0 : 6; + unsigned char _0 : 6; unsigned char _2_1 : 4; unsigned char _1_2 : 4; - unsigned char _3 : 6; + unsigned char _3 : 6; unsigned char _2_2 : 2; }; struct _double_byte { unsigned char _1_1 : 2; - unsigned char _0 : 6; + unsigned char _0 : 6; unsigned char _2_1 : 4; unsigned char _1_2 : 4; }; @@ -69,7 +64,7 @@ struct _double_byte struct _single_byte { unsigned char _1_1 : 2; - unsigned char _0 : 6; + unsigned char _0 : 6; }; // @@ -88,8 +83,7 @@ std::vector _from_base64(const utility::string_t& input) { std::vector result; - if ( input.empty() ) - return result; + if (input.empty()) return result; size_t padding = 0; @@ -97,30 +91,30 @@ std::vector _from_base64(const utility::string_t& input) { auto size = input.size(); - if ( (size % 4) != 0 ) + if ((size % 4) != 0) { throw std::runtime_error("length of base64 string is not an even multiple of 4"); } - for (auto iter = input.begin(); iter != input.end(); ++iter,--size) + for (auto iter = input.begin(); iter != input.end(); ++iter, --size) { const size_t ch_sz = static_cast(*iter); - if ( ch_sz >= _base64_dectbl.size() || _base64_dectbl[ch_sz] == 255 ) + if (ch_sz >= _base64_dectbl.size() || _base64_dectbl[ch_sz] == 255) { throw std::runtime_error("invalid character found in base64 string"); } - if ( _base64_dectbl[ch_sz] == 254 ) + if (_base64_dectbl[ch_sz] == 254) { padding++; // padding only at the end - if ( size > 2 ) + if (size > 2) { throw std::runtime_error("invalid padding character found in base64 string"); } - if ( size == 2 ) + if (size == 2) { - const size_t ch2_sz = static_cast(*(iter+1)); - if ( ch2_sz >= _base64_dectbl.size() || _base64_dectbl[ch2_sz] != 254 ) + const size_t ch2_sz = static_cast(*(iter + 1)); + if (ch2_sz >= _base64_dectbl.size() || _base64_dectbl[ch2_sz] != 254) { throw std::runtime_error("invalid padding character found in base64 string"); } @@ -129,17 +123,16 @@ std::vector _from_base64(const utility::string_t& input) } } - auto size = input.size(); const char_t* ptr = &input[0]; - auto outsz = (size / 4)*3; + auto outsz = (size / 4) * 3; outsz -= padding; result.resize(outsz); size_t idx = 0; - for (; size > 4; ++idx ) + for (; size > 4; ++idx) { unsigned char target[3]; memset(target, 0, sizeof(target)); @@ -150,7 +143,7 @@ std::vector _from_base64(const utility::string_t& input) unsigned char val2 = _base64_dectbl[ptr[2]]; unsigned char val3 = _base64_dectbl[ptr[3]]; - record->_0 = val0; + record->_0 = val0; record->_1_1 = val1 >> 4; result[idx] = target[0]; @@ -159,7 +152,7 @@ std::vector _from_base64(const utility::string_t& input) result[++idx] = target[1]; record->_2_2 = val2 & 0x3; - record->_3 = val3 & 0x3F; + record->_3 = val3 & 0x3F; result[++idx] = target[2]; ptr += 4; @@ -179,12 +172,12 @@ std::vector _from_base64(const utility::string_t& input) unsigned char val2 = _base64_dectbl[ptr[2]]; unsigned char val3 = _base64_dectbl[ptr[3]]; - record->_0 = val0; + record->_0 = val0; record->_1_1 = val1 >> 4; result[idx] = target[0]; record->_1_2 = val1 & 0xF; - if ( val2 != 254 ) + if (val2 != 254) { record->_2_1 = val2 >> 2; result[++idx] = target[1]; @@ -192,38 +185,38 @@ std::vector _from_base64(const utility::string_t& input) else { // There shouldn't be any information (ones) in the unused bits, - if ( record->_1_2 != 0 ) + if (record->_1_2 != 0) { throw std::runtime_error("Invalid end of base64 string"); } - return result; + return result; } record->_2_2 = val2 & 0x3; - if ( val3 != 254 ) + if (val3 != 254) { - record->_3 = val3 & 0x3F; + record->_3 = val3 & 0x3F; result[++idx] = target[2]; } else { // There shouldn't be any information (ones) in the unused bits. - if ( record->_2_2 != 0 ) + if (record->_2_2 != 0) { throw std::runtime_error("Invalid end of base64 string"); } - return result; + return result; } } return result; } -utility::string_t _to_base64(const unsigned char *ptr, size_t size) +utility::string_t _to_base64(const unsigned char* ptr, size_t size) { utility::string_t result; - for (; size >= 3; ) + for (; size >= 3;) { const _triple_byte* record = reinterpret_cast(ptr); unsigned char idx0 = record->_0; @@ -237,7 +230,7 @@ utility::string_t _to_base64(const unsigned char *ptr, size_t size) size -= 3; ptr += 3; } - switch(size) + switch (size) { case 1: { diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index 7ac9d306a2..9316f41f4f 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -1,17 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Credential and proxy utilities. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Credential and proxy utilities. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include #if defined(_WIN32) && !defined(__cplusplus_winrt) @@ -30,35 +31,35 @@ namespace details #if defined(__cplusplus_winrt) // Helper function to zero out memory of an IBuffer. -void winrt_secure_zero_buffer(Windows::Storage::Streams::IBuffer ^buffer) +void winrt_secure_zero_buffer(Windows::Storage::Streams::IBuffer ^ buffer) { - Microsoft::WRL::ComPtr bufferInspectable(reinterpret_cast(buffer)); + Microsoft::WRL::ComPtr bufferInspectable(reinterpret_cast(buffer)); Microsoft::WRL::ComPtr bufferByteAccess; bufferInspectable.As(&bufferByteAccess); // This shouldn't happen but if can't get access to the raw bytes for some reason // then we can't zero out. - byte * rawBytes; + byte* rawBytes; if (bufferByteAccess->Buffer(&rawBytes) == S_OK) { SecureZeroMemory(rawBytes, buffer->Length); } } -winrt_encryption::winrt_encryption(const std::wstring &data) +winrt_encryption::winrt_encryption(const std::wstring& data) { - auto provider = ref new Windows::Security::Cryptography::DataProtection::DataProtectionProvider(ref new Platform::String(L"Local=user")); + auto provider = ref new Windows::Security::Cryptography::DataProtection::DataProtectionProvider( + ref new Platform::String(L"Local=user")); // Create buffer containing plain text password. Platform::ArrayReference arrayref( - reinterpret_cast(const_cast(data.c_str())), + reinterpret_cast(const_cast(data.c_str())), static_cast(data.size()) * sizeof(std::wstring::value_type)); - Windows::Storage::Streams::IBuffer ^plaintext = Windows::Security::Cryptography::CryptographicBuffer::CreateFromByteArray(arrayref); + Windows::Storage::Streams::IBuffer ^ plaintext = + Windows::Security::Cryptography::CryptographicBuffer::CreateFromByteArray(arrayref); m_buffer = pplx::create_task(provider->ProtectAsync(plaintext)); - m_buffer.then([plaintext](pplx::task) - { - winrt_secure_zero_buffer(plaintext); - }); + m_buffer.then( + [plaintext](pplx::task) { winrt_secure_zero_buffer(plaintext); }); } plaintext_string winrt_encryption::decrypt() const @@ -70,28 +71,26 @@ plaintext_string winrt_encryption::decrypt() const auto plaintext = pplx::create_task(provider->UnprotectAsync(encrypted)).get(); // Get access to raw bytes in plain text buffer. - Microsoft::WRL::ComPtr bufferInspectable(reinterpret_cast(plaintext)); + Microsoft::WRL::ComPtr bufferInspectable(reinterpret_cast(plaintext)); Microsoft::WRL::ComPtr bufferByteAccess; bufferInspectable.As(&bufferByteAccess); - byte * rawPlaintext; - const auto &result = bufferByteAccess->Buffer(&rawPlaintext); + byte* rawPlaintext; + const auto& result = bufferByteAccess->Buffer(&rawPlaintext); if (result != S_OK) { throw ::utility::details::create_system_error(result); } // Construct string and zero out memory from plain text buffer. - auto data = plaintext_string(new std::wstring( - reinterpret_cast(rawPlaintext), - plaintext->Length / 2)); + auto data = plaintext_string( + new std::wstring(reinterpret_cast(rawPlaintext), plaintext->Length / 2)); SecureZeroMemory(rawPlaintext, plaintext->Length); return std::move(data); } #else -win32_encryption::win32_encryption(const std::wstring &data) : - m_numCharacters(data.size()) +win32_encryption::win32_encryption(const std::wstring& data) : m_numCharacters(data.size()) { // Early return because CryptProtectMemory crashes with empty string if (m_numCharacters == 0) @@ -120,22 +119,17 @@ win32_encryption::win32_encryption(const std::wstring &data) : } } -win32_encryption::~win32_encryption() -{ - SecureZeroMemory(m_buffer.data(), m_buffer.size()); -} +win32_encryption::~win32_encryption() { SecureZeroMemory(m_buffer.data(), m_buffer.size()); } plaintext_string win32_encryption::decrypt() const { // Copy the buffer and decrypt to avoid having to re-encrypt. - auto result = plaintext_string(new std::wstring( - reinterpret_cast(m_buffer.data()), m_buffer.size() / sizeof(wchar_t))); + auto result = plaintext_string(new std::wstring(reinterpret_cast(m_buffer.data()), + m_buffer.size() / sizeof(wchar_t))); auto& data = *result; - if (!m_buffer.empty()) { - if (!CryptUnprotectMemory( - &data[0], - static_cast(m_buffer.size()), - CRYPTPROTECTMEMORY_SAME_PROCESS)) + if (!m_buffer.empty()) + { + if (!CryptUnprotectMemory(&data[0], static_cast(m_buffer.size()), CRYPTPROTECTMEMORY_SAME_PROCESS)) { throw ::utility::details::create_system_error(GetLastError()); } @@ -150,7 +144,7 @@ plaintext_string win32_encryption::decrypt() const #endif #endif -void zero_memory_deleter::operator()(::utility::string_t *data) const +void zero_memory_deleter::operator()(::utility::string_t* data) const { CASABLANCA_UNREFERENCED_PARAMETER(data); #if defined(_WIN32) @@ -158,6 +152,6 @@ void zero_memory_deleter::operator()(::utility::string_t *data) const delete data; #endif } -} +} // namespace details -} +} // namespace web diff --git a/Release/src/websockets/client/ws_client.cpp b/Release/src/websockets/client/ws_client.cpp index 1d829eb746..f768e968fb 100644 --- a/Release/src/websockets/client/ws_client.cpp +++ b/Release/src/websockets/client/ws_client.cpp @@ -1,14 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Portions common to both WinRT and Websocket++ implementations. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Portions common to both WinRT and Websocket++ implementations. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ + #include "stdafx.h" + #include "cpprest/ws_client.h" #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) @@ -21,7 +23,6 @@ namespace client { namespace details { - websocket_client_task_impl::~websocket_client_task_impl() CPPREST_NOEXCEPT { close_pending_tasks_with_error(websocket_exception("Websocket client is being destroyed")); @@ -29,9 +30,9 @@ websocket_client_task_impl::~websocket_client_task_impl() CPPREST_NOEXCEPT void websocket_client_task_impl::set_handler() { - m_callback_client->set_message_handler([=](const websocket_incoming_message &msg) - { - pplx::task_completion_event tce; // This will be set if there are any tasks waiting to receive a message + m_callback_client->set_message_handler([=](const websocket_incoming_message& msg) { + pplx::task_completion_event + tce; // This will be set if there are any tasks waiting to receive a message { std::lock_guard lock(m_receive_queue_lock); if (m_receive_task_queue.empty()) // Push message to the queue as no one is waiting to receive @@ -49,14 +50,14 @@ void websocket_client_task_impl::set_handler() tce.set(msg); }); - m_callback_client->set_close_handler([=](websocket_close_status status, const utility::string_t& reason, const std::error_code& error_code) - { - CASABLANCA_UNREFERENCED_PARAMETER(status); - close_pending_tasks_with_error(websocket_exception(error_code, reason)); - }); + m_callback_client->set_close_handler( + [=](websocket_close_status status, const utility::string_t& reason, const std::error_code& error_code) { + CASABLANCA_UNREFERENCED_PARAMETER(status); + close_pending_tasks_with_error(websocket_exception(error_code, reason)); + }); } -void websocket_client_task_impl::close_pending_tasks_with_error(const websocket_exception &exc) +void websocket_client_task_impl::close_pending_tasks_with_error(const websocket_exception& exc) { std::lock_guard lock(m_receive_queue_lock); m_client_closed = true; @@ -73,10 +74,12 @@ pplx::task websocket_client_task_impl::receive() std::lock_guard lock(m_receive_queue_lock); if (m_client_closed == true) { - return pplx::task_from_exception(std::make_exception_ptr(websocket_exception("Websocket connection has closed."))); + return pplx::task_from_exception( + std::make_exception_ptr(websocket_exception("Websocket connection has closed."))); } - if (m_receive_msg_queue.empty()) // Push task completion event to the tce queue, so that it gets signaled when we have a message. + if (m_receive_msg_queue + .empty()) // Push task completion event to the tce queue, so that it gets signaled when we have a message. { pplx::task_completion_event tce; m_receive_task_queue.push(tce); @@ -90,6 +93,9 @@ pplx::task websocket_client_task_impl::receive() } } -}}}} +} // namespace details +} // namespace client +} // namespace websockets +} // namespace web #endif diff --git a/Release/src/websockets/client/ws_client_impl.h b/Release/src/websockets/client/ws_client_impl.h index 2cd824d24a..5c66c8bd37 100644 --- a/Release/src/websockets/client/ws_client_impl.h +++ b/Release/src/websockets/client/ws_client_impl.h @@ -1,9 +1,9 @@ #pragma once -#include -#include #include "cpprest/ws_client.h" #include "cpprest/ws_msg.h" +#include +#include namespace web { @@ -13,7 +13,6 @@ namespace client { namespace details { - struct outgoing_msg_queue { enum class state @@ -54,5 +53,7 @@ struct outgoing_msg_queue std::queue m_queue; }; - -}}}} \ No newline at end of file +} // namespace details +} // namespace client +} // namespace websockets +} // namespace web \ No newline at end of file diff --git a/Release/src/websockets/client/ws_client_winrt.cpp b/Release/src/websockets/client/ws_client_winrt.cpp index 38b4f7989d..291ba8ce8a 100644 --- a/Release/src/websockets/client/ws_client_winrt.cpp +++ b/Release/src/websockets/client/ws_client_winrt.cpp @@ -1,16 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Websocket library: Client-side APIs. -* -* This file contains the implementation for the Windows Runtime based on Windows::Networking::Sockets::MessageWebSocket. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Websocket library: Client-side APIs. + * + * This file contains the implementation for the Windows Runtime based on + *Windows::Networking::Sockets::MessageWebSocket. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) @@ -32,9 +34,8 @@ namespace client { namespace details { - // Helper function to build an error string from a Platform::Exception and a location. -static std::string build_error_msg(Platform::Exception ^exc, const std::string &location) +static std::string build_error_msg(Platform::Exception ^ exc, const std::string& location) { std::string msg(location); msg.append(": "); @@ -53,15 +54,17 @@ ref class ReceiveContext sealed friend class winrt_callback_client; friend class winrt_task_client; - void OnReceive(MessageWebSocket^ sender, MessageWebSocketMessageReceivedEventArgs^ args); - void OnClosed(IWebSocket^ sender, WebSocketClosedEventArgs^ args); + void OnReceive(MessageWebSocket ^ sender, MessageWebSocketMessageReceivedEventArgs ^ args); + void OnClosed(IWebSocket ^ sender, WebSocketClosedEventArgs ^ args); private: // Public members cannot have native types ReceiveContext( std::function receive_handler, - std::function close_handler) - : m_receive_handler(std::move(receive_handler)), m_close_handler(std::move(close_handler)) {} + std::function close_handler) + : m_receive_handler(std::move(receive_handler)), m_close_handler(std::move(close_handler)) + { + } // Handler to be executed when a message has been received by the client std::function m_receive_handler; @@ -70,25 +73,26 @@ ref class ReceiveContext sealed std::function m_close_handler; }; -class winrt_callback_client : public websocket_client_callback_impl, public std::enable_shared_from_this +class winrt_callback_client : public websocket_client_callback_impl, + public std::enable_shared_from_this { public: - winrt_callback_client(websocket_client_config config) : - websocket_client_callback_impl(std::move(config)), - m_connected(false) + winrt_callback_client(websocket_client_config config) + : websocket_client_callback_impl(std::move(config)), m_connected(false) { m_msg_websocket = ref new MessageWebSocket(); // Sets the HTTP request headers to the HTTP request message used in the WebSocket protocol handshake const utility::string_t protocolHeader(_XPLATSTR("Sec-WebSocket-Protocol")); - const auto & headers = m_config.headers(); - for (const auto & header : headers) + const auto& headers = m_config.headers(); + for (const auto& header : headers) { // Unfortunately the MessageWebSocket API throws a COMException if you try to set the // 'Sec-WebSocket-Protocol' header here. It requires you to go through their API instead. if (!utility::details::str_iequal(header.first, protocolHeader)) { - m_msg_websocket->SetRequestHeader(Platform::StringReference(header.first.c_str()), Platform::StringReference(header.second.c_str())); + m_msg_websocket->SetRequestHeader(Platform::StringReference(header.first.c_str()), + Platform::StringReference(header.second.c_str())); } } @@ -96,7 +100,7 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: if (headers.has(protocolHeader)) { const std::vector protocols = m_config.subprotocols(); - for (const auto & value : protocols) + for (const auto& value : protocols) { m_msg_websocket->Control->SupportedProtocols->Append(Platform::StringReference(value.c_str())); } @@ -105,31 +109,31 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: if (m_config.credentials().is_set()) { auto password = m_config.credentials()._internal_decrypt(); - m_msg_websocket->Control->ServerCredential = ref new Windows::Security::Credentials::PasswordCredential("WebSocketClientCredentialResource", + m_msg_websocket->Control->ServerCredential = ref new Windows::Security::Credentials::PasswordCredential( + "WebSocketClientCredentialResource", Platform::StringReference(m_config.credentials().username().c_str()), Platform::StringReference(password->c_str())); } - m_context = ref new ReceiveContext([=](const websocket_incoming_message &msg) - { - if (m_external_message_handler) - { - m_external_message_handler(msg); - } - }, - [=](websocket_close_status status, const utility::string_t& reason, const std::error_code& error_code) - { - if (m_external_close_handler) - { - m_external_close_handler(status, reason, error_code); - } + m_context = ref new ReceiveContext( + [=](const websocket_incoming_message& msg) { + if (m_external_message_handler) + { + m_external_message_handler(msg); + } + }, + [=](websocket_close_status status, const utility::string_t& reason, const std::error_code& error_code) { + if (m_external_close_handler) + { + m_external_close_handler(status, reason, error_code); + } - // Locally copy the task completion event since there is a PPL bug - // that the set method accesses internal state in the event and the websocket - // client could be destroyed. - auto local_close_tce = m_close_tce; - local_close_tce.set(); - }); + // Locally copy the task completion event since there is a PPL bug + // that the set method accesses internal state in the event and the websocket + // client could be destroyed. + auto local_close_tce = m_close_tce; + local_close_tce.set(); + }); } ~winrt_callback_client() @@ -148,78 +152,81 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: pplx::task connect() { _ASSERTE(!m_connected); - const auto &proxy = m_config.proxy(); - if(!proxy.is_default()) + const auto& proxy = m_config.proxy(); + if (!proxy.is_default()) { return pplx::task_from_exception(websocket_exception("Only a default proxy server is supported.")); } - const auto &proxy_cred = proxy.credentials(); - if(proxy_cred.is_set()) + const auto& proxy_cred = proxy.credentials(); + if (proxy_cred.is_set()) { auto password = proxy_cred._internal_decrypt(); - m_msg_websocket->Control->ProxyCredential = ref new Windows::Security::Credentials::PasswordCredential("WebSocketClientProxyCredentialResource", + m_msg_websocket->Control->ProxyCredential = ref new Windows::Security::Credentials::PasswordCredential( + "WebSocketClientProxyCredentialResource", Platform::StringReference(proxy_cred.username().c_str()), Platform::StringReference(password->c_str())); } const auto uri = ref new Windows::Foundation::Uri(Platform::StringReference(m_uri.to_string().c_str())); - m_msg_websocket->MessageReceived += ref new TypedEventHandler(m_context, &ReceiveContext::OnReceive); - m_msg_websocket->Closed += ref new TypedEventHandler(m_context, &ReceiveContext::OnClosed); + m_msg_websocket->MessageReceived += + ref new TypedEventHandler( + m_context, &ReceiveContext::OnReceive); + m_msg_websocket->Closed += + ref new TypedEventHandler(m_context, &ReceiveContext::OnClosed); std::weak_ptr thisWeakPtr = shared_from_this(); - return pplx::create_task(m_msg_websocket->ConnectAsync(uri)).then([thisWeakPtr](pplx::task result) -> pplx::task - { - // result.get() should happen before anything else, to make sure there is no unobserved exception - // in the task chain. - try - { - result.get(); - } - catch (Platform::Exception ^e) - { - throw websocket_exception(e->HResult, build_error_msg(e, "ConnectAsync")); - } - - if (auto pThis = thisWeakPtr.lock()) - { + return pplx::create_task(m_msg_websocket->ConnectAsync(uri)) + .then([thisWeakPtr](pplx::task result) -> pplx::task { + // result.get() should happen before anything else, to make sure there is no unobserved exception + // in the task chain. try { - pThis->m_messageWriter = ref new DataWriter(pThis->m_msg_websocket->OutputStream); + result.get(); } - catch (Platform::Exception^ e) + catch (Platform::Exception ^ e) { throw websocket_exception(e->HResult, build_error_msg(e, "ConnectAsync")); } - pThis->m_connected = true; - } - else - { - return pplx::task_from_exception(websocket_exception("Websocket client is being destroyed")); - } - return pplx::task_from_result(); - }); + if (auto pThis = thisWeakPtr.lock()) + { + try + { + pThis->m_messageWriter = ref new DataWriter(pThis->m_msg_websocket->OutputStream); + } + catch (Platform::Exception ^ e) + { + throw websocket_exception(e->HResult, build_error_msg(e, "ConnectAsync")); + } + pThis->m_connected = true; + } + else + { + return pplx::task_from_exception(websocket_exception("Websocket client is being destroyed")); + } + + return pplx::task_from_result(); + }); } - pplx::task send(websocket_outgoing_message &msg) + pplx::task send(websocket_outgoing_message& msg) { if (m_messageWriter == nullptr) { return pplx::task_from_exception(websocket_exception("Client not connected.")); } - switch(msg.m_msg_type) + switch (msg.m_msg_type) { - case websocket_message_type::binary_message : - m_msg_websocket->Control->MessageType = SocketMessageType::Binary; - break; - case websocket_message_type::text_message: - m_msg_websocket->Control->MessageType = SocketMessageType::Utf8; - break; - default: - return pplx::task_from_exception(websocket_exception("Message Type not supported.")); + case websocket_message_type::binary_message: + m_msg_websocket->Control->MessageType = SocketMessageType::Binary; + break; + case websocket_message_type::text_message: + m_msg_websocket->Control->MessageType = SocketMessageType::Utf8; + break; + default: return pplx::task_from_exception(websocket_exception("Message Type not supported.")); } const auto length = msg.m_length; @@ -229,7 +236,8 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: } if (length >= UINT_MAX && length != SIZE_MAX) { - return pplx::task_from_exception(websocket_exception("Message size too large. Ensure message length is less than UINT_MAX.")); + return pplx::task_from_exception( + websocket_exception("Message size too large. Ensure message length is less than UINT_MAX.")); } auto msg_pending = m_out_queue.push(msg); @@ -244,10 +252,10 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: return pplx::create_task(msg.body_sent()); } - void send_msg(websocket_outgoing_message &msg) + void send_msg(websocket_outgoing_message& msg) { auto this_client = this->shared_from_this(); - auto &is_buf = msg.m_body; + auto& is_buf = msg.m_body; auto length = msg.m_length; if (length == SIZE_MAX) @@ -259,7 +267,8 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: auto buf_sz = is_buf.size(); if (buf_sz >= SIZE_MAX) { - msg.signal_body_sent(std::make_exception_ptr(websocket_exception("Cannot send messages larger than SIZE_MAX."))); + msg.signal_body_sent( + std::make_exception_ptr(websocket_exception("Cannot send messages larger than SIZE_MAX."))); return; } length = static_cast(buf_sz); @@ -270,8 +279,7 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: // The stream needs to be buffered. auto is_buf_istream = is_buf.create_istream(); msg.m_body = concurrency::streams::container_buffer>(); - is_buf_istream.read_to_end(msg.m_body).then([this_client, msg](pplx::task t) mutable - { + is_buf_istream.read_to_end(msg.m_body).then([this_client, msg](pplx::task t) mutable { try { msg.m_length = t.get(); @@ -288,15 +296,17 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: } // First try to acquire the data (Get a pointer to the next already allocated contiguous block of data) - // If acquire succeeds, send the data over the socket connection, there is no copy of data from stream to temporary buffer. - // If acquire fails, copy the data to a temporary buffer managed by sp_allocated and send it over the socket connection. + // If acquire succeeds, send the data over the socket connection, there is no copy of data from stream to + // temporary buffer. If acquire fails, copy the data to a temporary buffer managed by sp_allocated and send it + // over the socket connection. std::shared_ptr sp_allocated; size_t acquired_size = 0; - uint8_t *ptr; + uint8_t* ptr; auto read_task = pplx::task_from_result(); bool acquired = is_buf.acquire(ptr, acquired_size); - if (!acquired || acquired_size < length) // Stream does not support acquire or failed to acquire specified number of bytes + if (!acquired || + acquired_size < length) // Stream does not support acquire or failed to acquire specified number of bytes { // If acquire did not return the required number of bytes, do not rely on its return value. if (acquired_size < length) @@ -306,10 +316,9 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: } // Allocate buffer to hold the data to be read from the stream. - sp_allocated.reset(new uint8_t[length], [=](uint8_t *p ) { delete[] p; }); + sp_allocated.reset(new uint8_t[length], [=](uint8_t* p) { delete[] p; }); - read_task = is_buf.getn(sp_allocated.get(), length).then([length](size_t bytes_read) - { + read_task = is_buf.getn(sp_allocated.get(), length).then([length](size_t bytes_read) { if (bytes_read != length) { throw websocket_exception("Failed to read required length of data from the stream."); @@ -319,66 +328,69 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: else { // Acquire succeeded, assign the acquired pointer to sp_allocated. Use an empty custom destructor - // so that the data is not released when sp_allocated goes out of scope. The streambuf will manage its memory. - sp_allocated.reset(ptr, [](uint8_t *) {}); + // so that the data is not released when sp_allocated goes out of scope. The streambuf will manage its + // memory. + sp_allocated.reset(ptr, [](uint8_t*) {}); } - read_task.then([this_client, acquired, sp_allocated, length]() - { - this_client->m_messageWriter->WriteBytes(Platform::ArrayReference(sp_allocated.get(), static_cast(length))); - - // Send the data as one complete message, in WinRT we do not have an option to send fragments. - return pplx::task(this_client->m_messageWriter->StoreAsync()); - }).then([this_client, msg, is_buf, acquired, sp_allocated, length](pplx::task previousTask) mutable - { - std::exception_ptr eptr; - unsigned int bytes_written = 0; - try - { - // Catch exceptions from previous tasks, if any and convert it to websocket exception. - bytes_written = previousTask.get(); - if (bytes_written != length) + read_task + .then([this_client, acquired, sp_allocated, length]() { + this_client->m_messageWriter->WriteBytes( + Platform::ArrayReference(sp_allocated.get(), static_cast(length))); + + // Send the data as one complete message, in WinRT we do not have an option to send fragments. + return pplx::task(this_client->m_messageWriter->StoreAsync()); + }) + .then([this_client, msg, is_buf, acquired, sp_allocated, length]( + pplx::task previousTask) mutable { + std::exception_ptr eptr; + unsigned int bytes_written = 0; + try { - eptr = std::make_exception_ptr(websocket_exception("Failed to send all the bytes.")); + // Catch exceptions from previous tasks, if any and convert it to websocket exception. + bytes_written = previousTask.get(); + if (bytes_written != length) + { + eptr = std::make_exception_ptr(websocket_exception("Failed to send all the bytes.")); + } + } + catch (Platform::Exception ^ e) + { + // Convert to websocket_exception. + eptr = std::make_exception_ptr(websocket_exception(e->HResult, build_error_msg(e, "send_msg"))); + } + catch (const websocket_exception& e) + { + // Catch to avoid slicing and losing the type if falling through to catch (...). + eptr = std::make_exception_ptr(e); + } + catch (...) + { + eptr = std::make_exception_ptr(std::current_exception()); } - } - catch (Platform::Exception^ e) - { - // Convert to websocket_exception. - eptr = std::make_exception_ptr(websocket_exception(e->HResult, build_error_msg(e, "send_msg"))); - } - catch (const websocket_exception &e) - { - // Catch to avoid slicing and losing the type if falling through to catch (...). - eptr = std::make_exception_ptr(e); - } - catch (...) - { - eptr = std::make_exception_ptr(std::current_exception()); - } - if (acquired) - { - is_buf.release(sp_allocated.get(), bytes_written); - } + if (acquired) + { + is_buf.release(sp_allocated.get(), bytes_written); + } - // Set the send_task_completion_event after calling release. - if (eptr) - { - msg.signal_body_sent(eptr); - } - else - { - msg.signal_body_sent(); - } + // Set the send_task_completion_event after calling release. + if (eptr) + { + msg.signal_body_sent(eptr); + } + else + { + msg.signal_body_sent(); + } - websocket_outgoing_message next_msg; - bool msg_pending = this_client->m_out_queue.pop_and_peek(next_msg); - if (msg_pending) - { - this_client->send_msg(next_msg); - } - }); + websocket_outgoing_message next_msg; + bool msg_pending = this_client->m_out_queue.pop_and_peek(next_msg); + if (msg_pending) + { + this_client->send_msg(next_msg); + } + }); } void set_message_handler(const std::function& handler) @@ -392,7 +404,7 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: return close(websocket_close_status::normal, _XPLATSTR("Normal")); } - pplx::task close(websocket_close_status status, const utility::string_t &strreason=_XPLATSTR("")) + pplx::task close(websocket_close_status status, const utility::string_t& strreason = _XPLATSTR("")) { // Send a close frame to the server m_msg_websocket->Close(static_cast(status), Platform::StringReference(strreason.c_str())); @@ -400,16 +412,16 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: return pplx::create_task(m_close_tce); } - void set_close_handler(const std::function& handler) + void set_close_handler( + const std::function& handler) { m_external_close_handler = handler; } private: - // WinRT MessageWebSocket object - Windows::Networking::Sockets::MessageWebSocket^ m_msg_websocket; - Windows::Storage::Streams::DataWriter^ m_messageWriter; + Windows::Networking::Sockets::MessageWebSocket ^ m_msg_websocket; + Windows::Storage::Streams::DataWriter ^ m_messageWriter; // Context object that implements the WinRT handlers: receive handler and close handler ReceiveContext ^ m_context; @@ -420,65 +432,68 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: // External callback for handling received and close event std::function m_external_message_handler; - std::function m_external_close_handler; + std::function + m_external_close_handler; // Queue to track pending sends outgoing_msg_queue m_out_queue; }; -void ReceiveContext::OnReceive(MessageWebSocket^ sender, MessageWebSocketMessageReceivedEventArgs^ args) +void ReceiveContext::OnReceive(MessageWebSocket ^ sender, MessageWebSocketMessageReceivedEventArgs ^ args) { websocket_incoming_message incoming_msg; - switch(args->MessageType) + switch (args->MessageType) { - case SocketMessageType::Binary: - incoming_msg.m_msg_type = websocket_message_type::binary_message; - break; - case SocketMessageType::Utf8: - incoming_msg.m_msg_type = websocket_message_type::text_message; - break; + case SocketMessageType::Binary: incoming_msg.m_msg_type = websocket_message_type::binary_message; break; + case SocketMessageType::Utf8: incoming_msg.m_msg_type = websocket_message_type::text_message; break; } try { - DataReader^ reader = args->GetDataReader(); + DataReader ^ reader = args->GetDataReader(); const auto len = reader->UnconsumedBufferLength; if (len > 0) { std::string payload; payload.resize(len); - reader->ReadBytes(Platform::ArrayReference(reinterpret_cast(&payload[0]), len)); + reader->ReadBytes(Platform::ArrayReference(reinterpret_cast(&payload[0]), len)); incoming_msg.m_body = concurrency::streams::container_buffer(std::move(payload)); } m_receive_handler(incoming_msg); } - catch (Platform::Exception ^e) + catch (Platform::Exception ^ e) { - m_close_handler(websocket_close_status::abnormal_close, _XPLATSTR("Abnormal close"), utility::details::create_error_code(e->HResult)); + m_close_handler(websocket_close_status::abnormal_close, + _XPLATSTR("Abnormal close"), + utility::details::create_error_code(e->HResult)); } } -void ReceiveContext::OnClosed(IWebSocket^ sender, WebSocketClosedEventArgs^ args) +void ReceiveContext::OnClosed(IWebSocket ^ sender, WebSocketClosedEventArgs ^ args) { - m_close_handler(static_cast(args->Code), args->Reason->Data(), utility::details::create_error_code(0)); + m_close_handler( + static_cast(args->Code), args->Reason->Data(), utility::details::create_error_code(0)); } -websocket_client_task_impl::websocket_client_task_impl(websocket_client_config config) : - m_callback_client(std::make_shared(std::move(config))), - m_client_closed(false) +websocket_client_task_impl::websocket_client_task_impl(websocket_client_config config) + : m_callback_client(std::make_shared(std::move(config))), m_client_closed(false) { set_handler(); } -} +} // namespace details -websocket_callback_client::websocket_callback_client() : - m_client(std::make_shared(websocket_client_config())) -{} +websocket_callback_client::websocket_callback_client() + : m_client(std::make_shared(websocket_client_config())) +{ +} -websocket_callback_client::websocket_callback_client(websocket_client_config config) : - m_client(std::make_shared(std::move(config))) -{} +websocket_callback_client::websocket_callback_client(websocket_client_config config) + : m_client(std::make_shared(std::move(config))) +{ +} -}}} +} // namespace client +} // namespace websockets +} // namespace web #endif diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index 0715249f16..3b6e9c8ddf 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -1,66 +1,65 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Websocket library: Client-side APIs. -* -* This file contains a cross platform implementation based on WebSocket++. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Websocket library: Client-side APIs. + * + * This file contains a cross platform implementation based on WebSocket++. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) #include "../../http/common/x509_cert_utilities.h" #include "pplx/threadpool.h" - #include "ws_client_impl.h" // Force websocketpp to use C++ std::error_code instead of Boost. #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ #if defined(_MSC_VER) - #pragma warning( push ) - #pragma warning( disable : 4100 4127 4512 4996 4701 4267 ) - #define _WEBSOCKETPP_CPP11_STL_ - #define _WEBSOCKETPP_CONSTEXPR_TOKEN_ - #if _MSC_VER < 1900 - #define _WEBSOCKETPP_NOEXCEPT_TOKEN_ - #endif +#pragma warning(push) +#pragma warning(disable : 4100 4127 4512 4996 4701 4267) +#define _WEBSOCKETPP_CPP11_STL_ +#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ +#if _MSC_VER < 1900 +#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ +#endif #elif defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wconversion" - #pragma clang diagnostic ignored "-Winfinite-recursion" - #pragma clang diagnostic ignored "-Wtautological-constant-compare" - #pragma clang diagnostic ignored "-Wtautological-unsigned-enum-zero-compare" - #pragma clang diagnostic ignored "-Wcast-qual" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Winfinite-recursion" +#pragma clang diagnostic ignored "-Wtautological-constant-compare" +#pragma clang diagnostic ignored "-Wtautological-unsigned-enum-zero-compare" +#pragma clang diagnostic ignored "-Wcast-qual" #elif defined(__GNUC__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wconversion" - #pragma GCC diagnostic ignored "-Wunused-parameter" - #pragma GCC diagnostic ignored "-Wignored-qualifiers" - #pragma GCC diagnostic ignored "-Wcast-qual" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#pragma GCC diagnostic ignored "-Wcast-qual" #endif +#include #include #include -#include #if defined(_WIN32) -#pragma warning( pop ) +#pragma warning(pop) #elif defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) #pragma GCC diagnostic pop #endif - #if defined(_MSC_VER) -#pragma warning( disable : 4503 ) +#pragma warning(disable : 4503) #endif // This is a hack to avoid memory leak reports from the debug MSVC CRT for all @@ -85,9 +84,9 @@ static struct ASIO_SSL_memory_leak_suppress #endif /* _WIN32 && !NDEBUG */ +using websocketpp::lib::bind; using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; -using websocketpp::lib::bind; namespace web { @@ -97,9 +96,8 @@ namespace client { namespace details { - // Utility function to build up error string based on error code and location. -static std::string build_error_msg(const std::error_code &ec, const std::string &location) +static std::string build_error_msg(const std::error_code& ec, const std::string& location) { std::string result = location; result += ": "; @@ -111,10 +109,12 @@ static std::string build_error_msg(const std::error_code &ec, const std::string static utility::string_t g_subProtocolHeader(_XPLATSTR("Sec-WebSocket-Protocol")); -class wspp_callback_client : public websocket_client_callback_impl, public std::enable_shared_from_this +class wspp_callback_client : public websocket_client_callback_impl, + public std::enable_shared_from_this { private: - enum State { + enum State + { CREATED, CONNECTING, CONNECTED, @@ -122,14 +122,16 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: CLOSED, DESTROYED }; + public: - wspp_callback_client(websocket_client_config config) : - websocket_client_callback_impl(std::move(config)), - m_state(CREATED) + wspp_callback_client(websocket_client_config config) + : websocket_client_callback_impl(std::move(config)) + , m_state(CREATED) #ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE , m_openssl_failed(false) #endif - {} + { + } ~wspp_callback_client() CPPREST_NOEXCEPT { @@ -138,32 +140,36 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: { std::lock_guard lock(m_wspp_client_lock); localState = m_state; - } // Unlock the mutex so connect/close can use it. + } // Unlock the mutex so connect/close can use it. // Now, what states could we be in? - switch (localState) { - case DESTROYED: - // This should be impossible - std::abort(); - case CREATED: - break; - case CLOSED: - case CONNECTING: - case CONNECTED: - case CLOSING: - try - { - // This will do nothing in the already-connected case - pplx::task(m_connect_tce).get(); - } - catch (...) {} - try - { - // This will do nothing in the already-closing case - close().wait(); - } - catch (...) {} - break; + switch (localState) + { + case DESTROYED: + // This should be impossible + std::abort(); + case CREATED: break; + case CLOSED: + case CONNECTING: + case CONNECTED: + case CLOSING: + try + { + // This will do nothing in the already-connected case + pplx::task(m_connect_tce).get(); + } + catch (...) + { + } + try + { + // This will do nothing in the already-closing case + close().wait(); + } + catch (...) + { + } + break; } // At this point, there should be no more references to me. @@ -177,10 +183,10 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: m_client = std::unique_ptr(new websocketpp_tls_client()); // Options specific to TLS client. - auto &client = m_client->client(); - client.set_tls_init_handler([this](websocketpp::connection_hdl) - { - auto sslContext = websocketpp::lib::shared_ptr(new boost::asio::ssl::context(boost::asio::ssl::context::sslv23)); + auto& client = m_client->client(); + client.set_tls_init_handler([this](websocketpp::connection_hdl) { + auto sslContext = websocketpp::lib::shared_ptr( + new boost::asio::ssl::context(boost::asio::ssl::context::sslv23)); sslContext->set_default_verify_paths(); sslContext->set_options(boost::asio::ssl::context::default_workarounds); if (m_config.validate_certificates()) @@ -195,20 +201,20 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: #ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE m_openssl_failed = false; #endif - sslContext->set_verify_callback([this](bool preverified, boost::asio::ssl::verify_context &verifyCtx) - { + sslContext->set_verify_callback([this](bool preverified, boost::asio::ssl::verify_context& verifyCtx) { #ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE // Attempt to use platform certificate validation when it is available: // If OpenSSL fails we will doing verification at the end using the whole certificate chain, // so wait until the 'leaf' cert. For now return true so OpenSSL continues down the certificate // chain. - if(!preverified) + if (!preverified) { m_openssl_failed = true; } - if(m_openssl_failed) + if (m_openssl_failed) { - return http::client::details::verify_cert_chain_platform_specific(verifyCtx, utility::conversions::to_utf8string(m_uri.host())); + return http::client::details::verify_cert_chain_platform_specific( + verifyCtx, utility::conversions::to_utf8string(m_uri.host())); } #endif boost::asio::ssl::rfc2818_verification rfc2818(utility::conversions::to_utf8string(m_uri.host())); @@ -229,8 +235,8 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: }); // Options specific to underlying socket. - client.set_socket_init_handler([this](websocketpp::connection_hdl, boost::asio::ssl::stream &ssl_stream) - { + client.set_socket_init_handler([this](websocketpp::connection_hdl, + boost::asio::ssl::stream& ssl_stream) { // Support for SNI. if (m_config.is_sni_enabled()) { @@ -239,12 +245,13 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: { // OpenSSL runs the string parameter through a macro casting away const with a C style cast. // Do a C++ cast ourselves to avoid warnings. - SSL_set_tlsext_host_name(ssl_stream.native_handle(), const_cast(m_config.server_name().c_str())); + SSL_set_tlsext_host_name(ssl_stream.native_handle(), + const_cast(m_config.server_name().c_str())); } else { - const auto &server_name = utility::conversions::to_utf8string(m_uri.host()); - SSL_set_tlsext_host_name(ssl_stream.native_handle(), const_cast(server_name.c_str())); + const auto& server_name = utility::conversions::to_utf8string(m_uri.host()); + SSL_set_tlsext_host_name(ssl_stream.native_handle(), const_cast(server_name.c_str())); } } }); @@ -258,10 +265,10 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: } } - template + template pplx::task connect_impl() { - auto &client = m_client->client(); + auto& client = m_client->client(); client.clear_access_channels(websocketpp::log::alevel::all); client.clear_error_channels(websocketpp::log::alevel::all); @@ -269,50 +276,48 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: client.start_perpetual(); _ASSERTE(m_state == CREATED); - client.set_open_handler([this](websocketpp::connection_hdl) - { + client.set_open_handler([this](websocketpp::connection_hdl) { _ASSERTE(m_state == CONNECTING); m_state = CONNECTED; m_connect_tce.set(); }); - client.set_fail_handler([this](websocketpp::connection_hdl con_hdl) - { + client.set_fail_handler([this](websocketpp::connection_hdl con_hdl) { _ASSERTE(m_state == CONNECTING); shutdown_wspp_impl(con_hdl, true); }); - client.set_message_handler([this](websocketpp::connection_hdl, const websocketpp::config::asio_client::message_type::ptr &msg) - { - if (m_external_message_handler) - { - _ASSERTE(m_state >= CONNECTED && m_state < CLOSED); - websocket_incoming_message incoming_msg; - - switch (msg->get_opcode()) + client.set_message_handler( + [this](websocketpp::connection_hdl, const websocketpp::config::asio_client::message_type::ptr& msg) { + if (m_external_message_handler) { - case websocketpp::frame::opcode::binary: - incoming_msg.m_msg_type = websocket_message_type::binary_message; - break; - case websocketpp::frame::opcode::text: - incoming_msg.m_msg_type = websocket_message_type::text_message; - break; - default: - // Unknown message type. Since both websocketpp and our code use the RFC codes, we'll just pass it on to the user. - incoming_msg.m_msg_type = static_cast(msg->get_opcode()); - break; - } + _ASSERTE(m_state >= CONNECTED && m_state < CLOSED); + websocket_incoming_message incoming_msg; - // 'move' the payload into a container buffer to avoid any copies. - auto &payload = msg->get_raw_payload(); - incoming_msg.m_body = concurrency::streams::container_buffer(std::move(payload)); + switch (msg->get_opcode()) + { + case websocketpp::frame::opcode::binary: + incoming_msg.m_msg_type = websocket_message_type::binary_message; + break; + case websocketpp::frame::opcode::text: + incoming_msg.m_msg_type = websocket_message_type::text_message; + break; + default: + // Unknown message type. Since both websocketpp and our code use the RFC codes, we'll just + // pass it on to the user. + incoming_msg.m_msg_type = static_cast(msg->get_opcode()); + break; + } - m_external_message_handler(incoming_msg); - } - }); + // 'move' the payload into a container buffer to avoid any copies. + auto& payload = msg->get_raw_payload(); + incoming_msg.m_body = concurrency::streams::container_buffer(std::move(payload)); - client.set_close_handler([this](websocketpp::connection_hdl con_hdl) - { + m_external_message_handler(incoming_msg); + } + }); + + client.set_close_handler([this](websocketpp::connection_hdl con_hdl) { _ASSERTE(m_state != CLOSED); shutdown_wspp_impl(con_hdl, false); }); @@ -337,11 +342,12 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: } // Add any request headers specified by the user. - for (const auto & header : headers) + for (const auto& header : headers) { if (!utility::details::str_iequal(header.first, g_subProtocolHeader)) { - con->append_header(utility::conversions::to_utf8string(header.first), utility::conversions::to_utf8string(header.second)); + con->append_header(utility::conversions::to_utf8string(header.first), + utility::conversions::to_utf8string(header.second)); } } @@ -349,18 +355,19 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: if (headers.has(g_subProtocolHeader)) { const std::vector protocols = m_config.subprotocols(); - for (const auto & value : protocols) + for (const auto& value : protocols) { con->add_subprotocol(utility::conversions::to_utf8string(value), ec); if (ec.value()) { - return pplx::task_from_exception(websocket_exception(ec, build_error_msg(ec, "add_subprotocol"))); + return pplx::task_from_exception( + websocket_exception(ec, build_error_msg(ec, "add_subprotocol"))); } } } // Setup proxy options. - const auto &proxy = m_config.proxy(); + const auto& proxy = m_config.proxy(); if (proxy.is_specified()) { con->set_proxy(utility::conversions::to_utf8string(proxy.address().to_string()), ec); @@ -369,24 +376,23 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: return pplx::task_from_exception(websocket_exception(ec, build_error_msg(ec, "set_proxy"))); } - const auto &cred = proxy.credentials(); + const auto& cred = proxy.credentials(); if (cred.is_set()) { - con->set_proxy_basic_auth( - utility::conversions::to_utf8string(cred.username()), - utility::conversions::to_utf8string(*cred._internal_decrypt()), - ec); + con->set_proxy_basic_auth(utility::conversions::to_utf8string(cred.username()), + utility::conversions::to_utf8string(*cred._internal_decrypt()), + ec); if (ec) { - return pplx::task_from_exception(websocket_exception(ec, build_error_msg(ec, "set_proxy_basic_auth"))); + return pplx::task_from_exception( + websocket_exception(ec, build_error_msg(ec, "set_proxy_basic_auth"))); } } } m_state = CONNECTING; client.connect(con); - m_thread = std::thread([&client]() - { + m_thread = std::thread([&client]() { #if defined(__ANDROID__) crossplat::get_jvm_env(); #endif @@ -402,12 +408,11 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: // See http://www.openssl.org/support/faq.html#PROG13 ERR_remove_thread_state(nullptr); #endif - }); return pplx::create_task(m_connect_tce); } - pplx::task send(websocket_outgoing_message &msg) + pplx::task send(websocket_outgoing_message& msg) { if (!m_connect_tce._IsTriggered()) { @@ -416,12 +421,10 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: switch (msg.m_msg_type) { - case websocket_message_type::text_message: - case websocket_message_type::binary_message: - case websocket_message_type::pong: - break; - default: - return pplx::task_from_exception(websocket_exception("Message Type not supported.")); + case websocket_message_type::text_message: + case websocket_message_type::binary_message: + case websocket_message_type::pong: break; + default: return pplx::task_from_exception(websocket_exception("Message Type not supported.")); } const auto length = msg.m_length; @@ -431,7 +434,8 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: } if (length >= UINT_MAX && length != SIZE_MAX) { - return pplx::task_from_exception(websocket_exception("Message size too large. Ensure message length is less than UINT_MAX.")); + return pplx::task_from_exception( + websocket_exception("Message size too large. Ensure message length is less than UINT_MAX.")); } auto msg_pending = m_out_queue.push(msg); @@ -446,7 +450,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: return pplx::create_task(msg.body_sent()); } - void send_msg(websocket_outgoing_message &msg) + void send_msg(websocket_outgoing_message& msg) { auto this_client = this->shared_from_this(); auto& is_buf = msg.m_body; @@ -461,7 +465,8 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: auto buf_sz = is_buf.size(); if (buf_sz >= SIZE_MAX) { - msg.signal_body_sent(std::make_exception_ptr(websocket_exception("Cannot send messages larger than SIZE_MAX."))); + msg.signal_body_sent( + std::make_exception_ptr(websocket_exception("Cannot send messages larger than SIZE_MAX."))); return; } length = static_cast(buf_sz); @@ -472,8 +477,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: // The stream needs to be buffered. auto is_buf_istream = is_buf.create_istream(); msg.m_body = concurrency::streams::container_buffer>(); - is_buf_istream.read_to_end(msg.m_body).then([this_client, msg](pplx::task t) mutable - { + is_buf_istream.read_to_end(msg.m_body).then([this_client, msg](pplx::task t) mutable { try { msg.m_length = t.get(); @@ -490,15 +494,17 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: } // First try to acquire the data (Get a pointer to the next already allocated contiguous block of data) - // If acquire succeeds, send the data over the socket connection, there is no copy of data from stream to temporary buffer. - // If acquire fails, copy the data to a temporary buffer managed by sp_allocated and send it over the socket connection. + // If acquire succeeds, send the data over the socket connection, there is no copy of data from stream to + // temporary buffer. If acquire fails, copy the data to a temporary buffer managed by sp_allocated and send it + // over the socket connection. std::shared_ptr sp_allocated; size_t acquired_size = 0; uint8_t* ptr; auto read_task = pplx::task_from_result(); bool acquired = is_buf.acquire(ptr, acquired_size); - if (!acquired || acquired_size < length) // Stream does not support acquire or failed to acquire specified number of bytes + if (!acquired || + acquired_size < length) // Stream does not support acquire or failed to acquire specified number of bytes { // If acquire did not return the required number of bytes, do not rely on its return value. if (acquired_size < length) @@ -508,10 +514,9 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: } // Allocate buffer to hold the data to be read from the stream. - sp_allocated.reset(new uint8_t[length], [=](uint8_t *p) { delete [] p; }); + sp_allocated.reset(new uint8_t[length], [=](uint8_t* p) { delete[] p; }); - read_task = is_buf.getn(sp_allocated.get(), length).then([length](size_t bytes_read) - { + read_task = is_buf.getn(sp_allocated.get(), length).then([length](size_t bytes_read) { if (bytes_read != length) { throw websocket_exception("Failed to read required length of data from the stream."); @@ -521,69 +526,73 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: else { // Acquire succeeded, assign the acquired pointer to sp_allocated. Use an empty custom destructor - // so that the data is not released when sp_allocated goes out of scope. The streambuf will manage its memory. - sp_allocated.reset(ptr, [](uint8_t *) {}); + // so that the data is not released when sp_allocated goes out of scope. The streambuf will manage its + // memory. + sp_allocated.reset(ptr, [](uint8_t*) {}); } - read_task.then([this_client, msg, sp_allocated, length]() - { - std::lock_guard lock(this_client->m_wspp_client_lock); - if (this_client->m_state > CONNECTED) - { - // The client has already been closed. - throw websocket_exception("Websocket connection is closed."); - } + read_task + .then([this_client, msg, sp_allocated, length]() { + std::lock_guard lock(this_client->m_wspp_client_lock); + if (this_client->m_state > CONNECTED) + { + // The client has already been closed. + throw websocket_exception("Websocket connection is closed."); + } - websocketpp::lib::error_code ec; - if (this_client->m_client->is_tls_client()) - { - this_client->send_msg_impl(this_client, msg, sp_allocated, length, ec); - } - else - { - this_client->send_msg_impl(this_client, msg, sp_allocated, length, ec); - } - return ec; - }).then([this_client, msg, is_buf, acquired, sp_allocated, length](pplx::task previousTask) mutable - { - std::exception_ptr eptr; - try - { - // Catch exceptions from previous tasks, if any and convert it to websocket exception. - const auto &ec = previousTask.get(); - if (ec.value() != 0) + websocketpp::lib::error_code ec; + if (this_client->m_client->is_tls_client()) { - eptr = std::make_exception_ptr(websocket_exception(ec, build_error_msg(ec, "sending message"))); + this_client->send_msg_impl( + this_client, msg, sp_allocated, length, ec); + } + else + { + this_client->send_msg_impl( + this_client, msg, sp_allocated, length, ec); + } + return ec; + }) + .then([this_client, msg, is_buf, acquired, sp_allocated, length]( + pplx::task previousTask) mutable { + std::exception_ptr eptr; + try + { + // Catch exceptions from previous tasks, if any and convert it to websocket exception. + const auto& ec = previousTask.get(); + if (ec.value() != 0) + { + eptr = std::make_exception_ptr(websocket_exception(ec, build_error_msg(ec, "sending message"))); + } + } + catch (...) + { + eptr = std::current_exception(); } - } - catch (...) - { - eptr = std::current_exception(); - } - if (acquired) - { - is_buf.release(sp_allocated.get(), length); - } + if (acquired) + { + is_buf.release(sp_allocated.get(), length); + } - // Set the send_task_completion_event after calling release. - if (eptr) - { - msg.signal_body_sent(eptr); - } - else - { - msg.signal_body_sent(); - } + // Set the send_task_completion_event after calling release. + if (eptr) + { + msg.signal_body_sent(eptr); + } + else + { + msg.signal_body_sent(); + } - websocket_outgoing_message next_msg; - bool msg_pending = this_client->m_out_queue.pop_and_peek(next_msg); + websocket_outgoing_message next_msg; + bool msg_pending = this_client->m_out_queue.pop_and_peek(next_msg); - if (msg_pending) - { - this_client->send_msg(next_msg); - } - }); + if (msg_pending) + { + this_client->send_msg(next_msg); + } + }); } pplx::task close() @@ -613,9 +622,8 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: } private: - - template - void shutdown_wspp_impl(const websocketpp::connection_hdl &con_hdl, bool connecting) + template + void shutdown_wspp_impl(const websocketpp::connection_hdl& con_hdl, bool connecting) { // Only need to hold the lock when setting the state to closed. { @@ -623,16 +631,15 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: m_state = CLOSED; } - auto &client = m_client->client(); - const auto &connection = client.get_con_from_hdl(con_hdl); - const auto &closeCode = connection->get_local_close_code(); - const auto &reason = connection->get_local_close_reason(); - const auto &ec = connection->get_ec(); + auto& client = m_client->client(); + const auto& connection = client.get_con_from_hdl(con_hdl); + const auto& closeCode = connection->get_local_close_code(); + const auto& reason = connection->get_local_close_reason(); + const auto& ec = connection->get_ec(); client.stop_perpetual(); // Can't join thread directly since it is the current thread. - pplx::create_task([this, connecting, ec, closeCode, reason] - { + pplx::create_task([this, connecting, ec, closeCode, reason] { if (m_thread.joinable()) { m_thread.join(); @@ -648,7 +655,8 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: } if (m_external_close_handler) { - m_external_close_handler(static_cast(closeCode), utility::conversions::to_string_t(reason), ec); + m_external_close_handler( + static_cast(closeCode), utility::conversions::to_string_t(reason), ec); } // Making a local copy of the TCE prevents it from being destroyed along with "this" auto tceref = m_close_tce; @@ -656,50 +664,37 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: }); } - template - static void send_msg_impl( - const std::shared_ptr &this_client, - const websocket_outgoing_message &msg, - const std::shared_ptr &sp_allocated, - size_t length, - websocketpp::lib::error_code &ec) + template + static void send_msg_impl(const std::shared_ptr& this_client, + const websocket_outgoing_message& msg, + const std::shared_ptr& sp_allocated, + size_t length, + websocketpp::lib::error_code& ec) { - auto &client = this_client->m_client->client(); + auto& client = this_client->m_client->client(); switch (msg.m_msg_type) { - case websocket_message_type::text_message: - client.send( - this_client->m_con, - sp_allocated.get(), - length, - websocketpp::frame::opcode::text, - ec); - break; - case websocket_message_type::binary_message: - client.send( - this_client->m_con, - sp_allocated.get(), - length, - websocketpp::frame::opcode::binary, - ec); - break; - case websocket_message_type::pong: - client.pong( - this_client->m_con, - "", - ec); - break; - default: - // This case should have already been filtered above. - std::abort(); + case websocket_message_type::text_message: + client.send(this_client->m_con, sp_allocated.get(), length, websocketpp::frame::opcode::text, ec); + break; + case websocket_message_type::binary_message: + client.send(this_client->m_con, sp_allocated.get(), length, websocketpp::frame::opcode::binary, ec); + break; + case websocket_message_type::pong: client.pong(this_client->m_con, "", ec); break; + default: + // This case should have already been filtered above. + std::abort(); } } - template - void close_impl(websocket_close_status status, const utility::string_t& reason, websocketpp::lib::error_code &ec) + template + void close_impl(websocket_close_status status, const utility::string_t& reason, websocketpp::lib::error_code& ec) { - auto &client = m_client->client(); - client.close(m_con, static_cast(status), utility::conversions::to_utf8string(reason), ec); + auto& client = m_client->client(); + client.close(m_con, + static_cast(status), + utility::conversions::to_utf8string(reason), + ec); } void set_message_handler(const std::function& handler) @@ -707,7 +702,8 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: m_external_message_handler = handler; } - void set_close_handler(const std::function& handler) + void set_close_handler( + const std::function& handler) { m_external_close_handler = handler; } @@ -719,45 +715,33 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: struct websocketpp_client_base { virtual ~websocketpp_client_base() CPPREST_NOEXCEPT {} - template - websocketpp::client & client() + template + websocketpp::client& client() { - if(is_tls_client()) + if (is_tls_client()) { - return reinterpret_cast &>(tls_client()); + return reinterpret_cast&>(tls_client()); } else { - return reinterpret_cast &>(non_tls_client()); + return reinterpret_cast&>(non_tls_client()); } } - virtual websocketpp::client & non_tls_client() - { - throw std::bad_cast(); - } - virtual websocketpp::client & tls_client() - { - throw std::bad_cast(); - } + virtual websocketpp::client& non_tls_client() { throw std::bad_cast(); } + virtual websocketpp::client& tls_client() { throw std::bad_cast(); } virtual bool is_tls_client() const = 0; }; struct websocketpp_client : websocketpp_client_base { ~websocketpp_client() CPPREST_NOEXCEPT {} - websocketpp::client & non_tls_client() override - { - return m_client; - } + websocketpp::client& non_tls_client() override { return m_client; } bool is_tls_client() const override { return false; } websocketpp::client m_client; }; struct websocketpp_tls_client : websocketpp_client_base { ~websocketpp_tls_client() CPPREST_NOEXCEPT {} - websocketpp::client & tls_client() override - { - return m_client; - } + websocketpp::client& tls_client() override { return m_client; } bool is_tls_client() const override { return true; } websocketpp::client m_client; }; @@ -777,7 +761,8 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: // External callback for handling received and close event std::function m_external_message_handler; - std::function m_external_close_handler; + std::function + m_external_close_handler; // Used to track if any of the OpenSSL server certificate verifications // failed. This can safely be tracked at the client level since connections @@ -785,25 +770,27 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: #ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE bool m_openssl_failed; #endif - }; -websocket_client_task_impl::websocket_client_task_impl(websocket_client_config config) : - m_client_closed(false), - m_callback_client(std::make_shared(std::move(config))) +websocket_client_task_impl::websocket_client_task_impl(websocket_client_config config) + : m_client_closed(false), m_callback_client(std::make_shared(std::move(config))) { set_handler(); } -} +} // namespace details -websocket_callback_client::websocket_callback_client() : - m_client(std::make_shared(websocket_client_config())) -{} +websocket_callback_client::websocket_callback_client() + : m_client(std::make_shared(websocket_client_config())) +{ +} -websocket_callback_client::websocket_callback_client(websocket_client_config config) : - m_client(std::make_shared(std::move(config))) -{} +websocket_callback_client::websocket_callback_client(websocket_client_config config) + : m_client(std::make_shared(std::move(config))) +{ +} -}}} +} // namespace client +} // namespace websockets +} // namespace web #endif diff --git a/Release/src/websockets/client/ws_msg.cpp b/Release/src/websockets/client/ws_msg.cpp index c9a5bea8ae..730e625a3b 100644 --- a/Release/src/websockets/client/ws_msg.cpp +++ b/Release/src/websockets/client/ws_msg.cpp @@ -1,22 +1,24 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Websocket library: Client-side APIs. -* -* This file contains the websocket message implementation -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Websocket library: Client-side APIs. + * + * This file contains the websocket message implementation + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include -#include "cpprest/ws_client.h" + #include "cpprest/ws_msg.h" + #include "../../http/common/internal_http_helpers.h" +#include "cpprest/ws_client.h" +#include #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) @@ -29,15 +31,14 @@ namespace websockets { namespace client { - static ::utility::string_t g_subProtocolHeader = _XPLATSTR("Sec-WebSocket-Protocol"); -void websocket_client_config::set_user_agent(const utf8string &user_agent) +void websocket_client_config::set_user_agent(const utf8string& user_agent) { headers().add(web::http::header_names::user_agent, utility::conversions::to_string_t(user_agent)); } -void websocket_client_config::add_subprotocol(const ::utility::string_t &name) +void websocket_client_config::add_subprotocol(const ::utility::string_t& name) { m_headers.add(g_subProtocolHeader, name); } @@ -71,6 +72,8 @@ pplx::task websocket_incoming_message::extract_string() const return pplx::task_from_result(std::move(m_body.collection())); } -}}} +} // namespace client +} // namespace websockets +} // namespace web #endif diff --git a/Release/tests/common/TestRunner/test_module_loader.cpp b/Release/tests/common/TestRunner/test_module_loader.cpp index 65968e7a0d..b6cb3c0d18 100644 --- a/Release/tests/common/TestRunner/test_module_loader.cpp +++ b/Release/tests/common/TestRunner/test_module_loader.cpp @@ -1,9 +1,9 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -*/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + */ #ifdef WIN32 #include #else @@ -27,13 +27,14 @@ class test_module auto ptr = dlsym(m_handle, "GetTestList"); if (ptr == nullptr) { - std::cerr << "couldn't find GetTestList" << + std::cerr << "couldn't find GetTestList" + << #ifdef __APPLE__ " " << dlerror() << #endif std::endl; } - return (GetTestsFunc)ptr; + return (GetTestsFunc)ptr; #endif } @@ -43,10 +44,8 @@ class test_module { #if defined(_WIN32) // Make sure ends in .dll - if (*(m_dllName.end() - 1) != 'l' - || *(m_dllName.end() - 2) != 'l' - || *(m_dllName.end() - 3) != 'd' - || *(m_dllName.end() - 4) != '.') + if (*(m_dllName.end() - 1) != 'l' || *(m_dllName.end() - 2) != 'l' || *(m_dllName.end() - 3) != 'd' || + *(m_dllName.end() - 4) != '.') { return (unsigned long)-1; } @@ -110,37 +109,35 @@ class test_module void* m_handle; #endif - test_module(const test_module &) = delete; - test_module & operator=(const test_module &) = delete; + test_module(const test_module&) = delete; + test_module& operator=(const test_module&) = delete; }; -test_module_loader::test_module_loader() -{ -} +test_module_loader::test_module_loader() {} test_module_loader::~test_module_loader() { - for(auto iter = m_modules.begin(); iter != m_modules.end(); ++iter) + for (auto iter = m_modules.begin(); iter != m_modules.end(); ++iter) { iter->second->unload(); delete iter->second; } } -unsigned long test_module_loader::load(const std::string &dllName) +unsigned long test_module_loader::load(const std::string& dllName) { // Check if the module is already loaded. - if(m_modules.find(dllName) != m_modules.end()) + if (m_modules.find(dllName) != m_modules.end()) { return 0; } - test_module *pModule; + test_module* pModule; pModule = new test_module(dllName); // Load dll. const unsigned long error_code = pModule->load(); - if(error_code != 0) + if (error_code != 0) { delete pModule; return error_code; @@ -154,13 +151,13 @@ unsigned long test_module_loader::load(const std::string &dllName) UnitTest::TestList g_list; -UnitTest::TestList& test_module_loader::get_test_list(const std::string &dllName) +UnitTest::TestList& test_module_loader::get_test_list(const std::string& dllName) { GetTestsFunc getTestsFunc = m_modules[dllName]->get_test_list(); // If there is no GetTestList function then it must be a dll without any tests. // Simply return an empty TestList. - if(getTestsFunc == nullptr) + if (getTestsFunc == nullptr) { return g_list; } diff --git a/Release/tests/common/TestRunner/test_module_loader.h b/Release/tests/common/TestRunner/test_module_loader.h index 01d90ba4c7..ce52328f47 100644 --- a/Release/tests/common/TestRunner/test_module_loader.h +++ b/Release/tests/common/TestRunner/test_module_loader.h @@ -1,18 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -***/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + ***/ #ifndef INCLUDED_TEST_MODULE_LOADER #define INCLUDED_TEST_MODULE_LOADER -#include #include "unittestpp.h" +#include // Exported function from all test dlls. -typedef UnitTest::TestList & (__cdecl *GetTestsFunc)(); +typedef UnitTest::TestList&(__cdecl* GetTestsFunc)(); // Interface to implement on each platform to be be able to load/unload and call global functions. class test_module; @@ -25,16 +25,16 @@ class test_module_loader ~test_module_loader(); // Does't complain if module with same name is already loaded. - unsigned long load(const std::string &dllName); + unsigned long load(const std::string& dllName); // Module must have already been loaded. - UnitTest::TestList& get_test_list(const std::string &dllName); + UnitTest::TestList& get_test_list(const std::string& dllName); private: - test_module_loader(const test_module_loader &) = delete; - test_module_loader & operator=(const test_module_loader &) = delete; + test_module_loader(const test_module_loader&) = delete; + test_module_loader& operator=(const test_module_loader&) = delete; - std::map m_modules; + std::map m_modules; }; #endif diff --git a/Release/tests/common/TestRunner/test_runner.cpp b/Release/tests/common/TestRunner/test_runner.cpp index 7ec573dbbd..4d1a8d39f9 100644 --- a/Release/tests/common/TestRunner/test_runner.cpp +++ b/Release/tests/common/TestRunner/test_runner.cpp @@ -1,21 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ // TestRunner.cpp : Defines the entry point for the console application. // -#include -#include #include #include +#include #include +#include #ifdef _WIN32 -#include #include + +#include #else #include #ifdef __APPLE__ @@ -25,15 +26,16 @@ #endif #endif +#include "../UnitTestpp/src/GlobalSettings.h" #include "../UnitTestpp/src/TestReporterStdout.h" #include "../UnitTestpp/src/TimeHelpers.h" -#include "../UnitTestpp/src/GlobalSettings.h" - #include "test_module_loader.h" static void print_help() { - std::cout << "Usage: testrunner.exe [/list] [/listproperties] [/noignore] [/breakonerror] [/detectleaks]" < [/list] [/listproperties] [/noignore] [/breakonerror] [/detectleaks]" + << std::endl; std::cout << " [/name:] [/select:@key=value] [/loop:]" << std::endl; std::cout << std::endl; std::cout << " /list List all the names of the test_binaries and their" << std::endl; @@ -56,13 +58,13 @@ static void print_help() std::cout << std::endl; std::cout << "Can also specify general global settings with the following:" << std::endl; - std::cout << " /global_key:global_value OR /global_key" << std::endl << std::endl; + std::cout << " /global_key:global_value OR /global_key" << std::endl << std::endl; } -static std::string to_lower(const std::string &str) +static std::string to_lower(const std::string& str) { std::string lower; - for(auto iter = str.begin(); iter != str.end(); ++iter) + for (auto iter = str.begin(); iter != str.end(); ++iter) { lower.push_back((char)tolower(*iter)); } @@ -85,20 +87,20 @@ static std::vector get_files_in_directory() } else { - std::cout << "Could not determine execution directory" << std::endl; - exit(-1); + std::cout << "Could not determine execution directory" << std::endl; + exit(-1); } exe_directory.append("*"); WIN32_FIND_DATAA findFileData; HANDLE hFind = FindFirstFileA(exe_directory.c_str(), &findFileData); - if(hFind != INVALID_HANDLE_VALUE && !(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + if (hFind != INVALID_HANDLE_VALUE && !(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { files.push_back(findFileData.cFileName); } - while(FindNextFileA(hFind, &findFileData) != 0) + while (FindNextFileA(hFind, &findFileData) != 0) { - if(!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { files.push_back(findFileData.cFileName); } @@ -108,12 +110,12 @@ static std::vector get_files_in_directory() #elif defined(__APPLE__) auto exe_directory = getcwd(nullptr, 0); - DIR *dir = opendir(exe_directory); + DIR* dir = opendir(exe_directory); free(exe_directory); if (dir != nullptr) { - struct dirent *ent = readdir(dir); + struct dirent* ent = readdir(dir); while (ent != nullptr) { if (ent->d_type == DT_REG) @@ -121,7 +123,7 @@ static std::vector get_files_in_directory() files.push_back(ent->d_name); } ent = readdir(dir); - } + } closedir(dir); } #else @@ -140,12 +142,12 @@ static std::vector get_files_in_directory() return files; } -static std::string replace_wildcard_for_regex(const std::string &str) +static std::string replace_wildcard_for_regex(const std::string& str) { std::string result; - for(auto iter = str.begin(); iter != str.end(); ++iter) + for (auto iter = str.begin(); iter != str.end(); ++iter) { - if(*iter == '*') + if (*iter == '*') { result.push_back('.'); } @@ -154,13 +156,13 @@ static std::string replace_wildcard_for_regex(const std::string &str) return result; } -static std::vector get_matching_binaries(const std::string &dllName) +static std::vector get_matching_binaries(const std::string& dllName) { std::vector matchingFiles; // If starts with .\ remove it. std::string expandedDllName(dllName); - if(expandedDllName.size() > 2 && expandedDllName[0] == '.' && expandedDllName[1] == '\\') + if (expandedDllName.size() > 2 && expandedDllName[0] == '.' && expandedDllName[1] == '\\') { expandedDllName = expandedDllName.substr(2); } @@ -168,7 +170,7 @@ static std::vector get_matching_binaries(const std::string &dllName // Escape any '.' size_t oldLocation = 0; size_t location = expandedDllName.find(".", oldLocation); - while(location != std::string::npos) + while (location != std::string::npos) { expandedDllName.insert(expandedDllName.find(".", oldLocation), "\\"); oldLocation = location + 2; @@ -183,9 +185,9 @@ static std::vector get_matching_binaries(const std::string &dllName // Filter out any files that don't match. std::regex dllRegex(expandedDllName, std::regex_constants::icase); - for(auto iter = allFiles.begin(); iter != allFiles.end(); ++iter) + for (auto iter = allFiles.begin(); iter != allFiles.end(); ++iter) { - if(std::regex_match(*iter, dllRegex)) + if (std::regex_match(*iter, dllRegex)) { matchingFiles.push_back(*iter); } @@ -198,29 +200,28 @@ static std::multimap g_properties; static std::vector g_test_binaries; static int g_individual_test_timeout = 60000 * 3; -static int parse_command_line(int argc, char **argv) +static int parse_command_line(int argc, char** argv) { - - for(int i = 1; i < argc; ++i) + for (int i = 1; i < argc; ++i) { std::string arg(argv[i]); arg = to_lower(arg); - if(arg.compare("/?") == 0) + if (arg.compare("/?") == 0) { print_help(); return -1; } - else if(arg.find("/") == 0) + else if (arg.find("/") == 0) { - if(arg.find("/select:@") == 0) + if (arg.find("/select:@") == 0) { std::string prop_asgn = std::string(argv[i]).substr(std::string("/select:@").size()); auto eqsgn = prop_asgn.find('='); if (eqsgn < prop_asgn.size()) { - auto key = prop_asgn.substr(0,eqsgn); - auto value = prop_asgn.substr(eqsgn+1); + auto key = prop_asgn.substr(0, eqsgn); + auto value = prop_asgn.substr(eqsgn + 1); g_properties.insert(std::make_pair(key, value)); } else @@ -228,7 +229,7 @@ static int parse_command_line(int argc, char **argv) g_properties.insert(std::make_pair(prop_asgn, "*")); } } - else if(arg.find(":") != std::string::npos) + else if (arg.find(":") != std::string::npos) { const size_t index = arg.find(":"); const std::string key = std::string(argv[i]).substr(1, index - 1); @@ -240,7 +241,7 @@ static int parse_command_line(int argc, char **argv) UnitTest::GlobalSettings::Add(arg.substr(1), ""); } } - else if(arg.find("/debug") == 0) + else if (arg.find("/debug") == 0) { printf("Attach debugger now...\n"); int temp; @@ -259,7 +260,7 @@ static bool matched_properties(const UnitTest::TestProperties& test_props) { // TestRunner can only execute either desktop or winrt tests, but not both. // This starts with visual studio versions after VS 2012. -#if defined (_MSC_VER) && (_MSC_VER >= 1800) +#if defined(_MSC_VER) && (_MSC_VER >= 1800) #ifdef WINRT_TEST_RUNNER UnitTest::GlobalSettings::Add("winrt", ""); #elif defined DESKTOP_TEST_RUNNER @@ -269,7 +270,7 @@ static bool matched_properties(const UnitTest::TestProperties& test_props) // The 'Require' property on a test case is special. // It requires a certain global setting to be fulfilled to execute. - if(test_props.Has("Requires")) + if (test_props.Has("Requires")) { const std::string requires = test_props.Get("Requires"); std::vector requirements; @@ -277,31 +278,30 @@ static bool matched_properties(const UnitTest::TestProperties& test_props) // Can be multiple requirements, a semi colon seperated list std::string::size_type pos = requires.find_first_of(';'); std::string::size_type last_pos = 0; - while(pos != std::string::npos) + while (pos != std::string::npos) { requirements.push_back(requires.substr(last_pos, pos - last_pos)); last_pos = pos + 1; pos = requires.find_first_of(';', last_pos); } requirements.push_back(requires.substr(last_pos)); - for(auto iter = requirements.begin(); iter != requirements.end(); ++iter) + for (auto iter = requirements.begin(); iter != requirements.end(); ++iter) { - if(!UnitTest::GlobalSettings::Has(to_lower(*iter))) + if (!UnitTest::GlobalSettings::Has(to_lower(*iter))) { return false; } } } - if (g_properties.size() == 0) - return true; + if (g_properties.size() == 0) return true; // All the properties specified at the cmd line act as a 'filter'. for (auto iter = g_properties.begin(); iter != g_properties.end(); ++iter) { auto name = iter->first; auto value = iter->second; - if (test_props.Has(name) && (value == "*" || test_props[name] == value) ) + if (test_props.Has(name) && (value == "*" || test_props[name] == value)) { return true; } @@ -310,24 +310,25 @@ static bool matched_properties(const UnitTest::TestProperties& test_props) } // Functions to list all the test cases and their properties. -static void handle_list_option(bool listProperties, const UnitTest::TestList &tests, const std::regex &nameRegex) +static void handle_list_option(bool listProperties, const UnitTest::TestList& tests, const std::regex& nameRegex) { - UnitTest::Test *pTest = tests.GetFirst(); - while(pTest != nullptr) + UnitTest::Test* pTest = tests.GetFirst(); + while (pTest != nullptr) { std::string fullTestName = pTest->m_details.suiteName; fullTestName.append(":"); fullTestName.append(pTest->m_details.testName); - if(matched_properties(pTest->m_properties) && std::regex_match(fullTestName, nameRegex)) + if (matched_properties(pTest->m_properties) && std::regex_match(fullTestName, nameRegex)) { std::cout << " " << fullTestName << std::endl; - if(listProperties) + if (listProperties) { - std::for_each(pTest->m_properties.begin(), pTest->m_properties.end(), [&](const std::pair key_value) - { - std::cout << " " << key_value.first << ": " << key_value.second << std::endl; - }); + std::for_each(pTest->m_properties.begin(), + pTest->m_properties.end(), + [&](const std::pair key_value) { + std::cout << " " << key_value.first << ": " << key_value.second << std::endl; + }); } } pTest = pTest->m_nextTest; @@ -364,17 +365,17 @@ static void ChangeConsoleTextColorToGrey() #endif } -bool IsTestIgnored(UnitTest::Test *pTest) +bool IsTestIgnored(UnitTest::Test* pTest) { - if(pTest->m_properties.Has("Ignore")) return true; + if (pTest->m_properties.Has("Ignore")) return true; #ifdef _WIN32 - if(pTest->m_properties.Has("Ignore:Windows")) return true; + if (pTest->m_properties.Has("Ignore:Windows")) return true; #elif defined(__APPLE__) - if(pTest->m_properties.Has("Ignore:Apple")) return true; + if (pTest->m_properties.Has("Ignore:Apple")) return true; #elif (defined(ANDROID) || defined(__ANDROID__)) - if(pTest->m_properties.Has("Ignore:Android")) return true; + if (pTest->m_properties.Has("Ignore:Android")) return true; #else - if(pTest->m_properties.Has("Ignore:Linux")) return true; + if (pTest->m_properties.Has("Ignore:Linux")) return true; #endif return false; } @@ -409,7 +410,7 @@ testlist_t load_all_tests(test_module_loader& module_loader) testlist_t testlists; // Retrieve the static tests and clear for dll loading. - testlists.insert({ "", UnitTest::GetTestList() }); + testlists.insert({"", UnitTest::GetTestList()}); UnitTest::GetTestList().Clear(); // Cycle through all the test binaries and load them @@ -425,14 +426,13 @@ testlist_t load_all_tests(test_module_loader& module_loader) for (auto& binary : matchingBinaries) { unsigned long error_code = module_loader.load(binary); - if(error_code != 0) + if (error_code != 0) { // Only omit an error if a wildcard wasn't used. - if(binary_names.find('*') == std::string::npos) + if (binary_names.find('*') == std::string::npos) { ChangeConsoleTextColorToRed(); - std::cout << "Error loading " << binary << ": " - << error_code << std::endl; + std::cout << "Error loading " << binary << ": " << error_code << std::endl; ChangeConsoleTextColorToGrey(); std::exit(error_code); @@ -445,7 +445,7 @@ testlist_t load_all_tests(test_module_loader& module_loader) std::cout << "Loaded " << binary << "..." << std::endl; // Store the loaded binary into the test list map - testlists.insert({ binary, UnitTest::GetTestList() }); + testlists.insert({binary, UnitTest::GetTestList()}); UnitTest::GetTestList().Clear(); } } @@ -456,7 +456,7 @@ testlist_t load_all_tests(test_module_loader& module_loader) void run_all_tests(UnitTest::TestRunner& testRunner, testlist_t& testlists) { int numTimesToRun = 1; - if(UnitTest::GlobalSettings::Has("loop")) + if (UnitTest::GlobalSettings::Has("loop")) { std::istringstream strstream(UnitTest::GlobalSettings::Get("loop")); strstream >> numTimesToRun; @@ -464,7 +464,7 @@ void run_all_tests(UnitTest::TestRunner& testRunner, testlist_t& testlists) const bool include_ignored_tests = UnitTest::GlobalSettings::Has("noignore"); - for(int i = 0; i < numTimesToRun; ++i) + for (int i = 0; i < numTimesToRun; ++i) { for (auto& test_p : testlists) { @@ -473,26 +473,24 @@ void run_all_tests(UnitTest::TestRunner& testRunner, testlist_t& testlists) std::regex nameRegex(".*"); - if(UnitTest::GlobalSettings::Has("name")) + if (UnitTest::GlobalSettings::Has("name")) { nameRegex = replace_wildcard_for_regex(UnitTest::GlobalSettings::Get("name")); } - testRunner.RunTestsIf( - tests, - [&](UnitTest::Test *pTest) -> bool - { - // Combine suite and test name - std::string fullTestName = pTest->m_details.suiteName; - fullTestName.append(":"); - fullTestName.append(pTest->m_details.testName); - - if(IsTestIgnored(pTest) && !include_ignored_tests) - return false; - else - return matched_properties(pTest->m_properties) && - std::regex_match(fullTestName, nameRegex); - }, - g_individual_test_timeout); + testRunner.RunTestsIf(tests, + [&](UnitTest::Test* pTest) -> bool { + // Combine suite and test name + std::string fullTestName = pTest->m_details.suiteName; + fullTestName.append(":"); + fullTestName.append(pTest->m_details.testName); + + if (IsTestIgnored(pTest) && !include_ignored_tests) + return false; + else + return matched_properties(pTest->m_properties) && + std::regex_match(fullTestName, nameRegex); + }, + g_individual_test_timeout); } } } @@ -518,35 +516,33 @@ int main(int argc, char* argv[]) // Obviously in that case WinRT test cases can't run, but non WinRT ones should be // fine. So dynamically try to call RoInitialize/RoUninitialize. HMODULE hComBase = LoadLibrary(L"combase.dll"); - if(hComBase != nullptr) + if (hComBase != nullptr) { - typedef HRESULT (WINAPI *RoInit)(int); + typedef HRESULT(WINAPI * RoInit)(int); RoInit roInitFunc = (RoInit)GetProcAddress(hComBase, "RoInitialize"); - if(roInitFunc != nullptr) + if (roInitFunc != nullptr) { roInitFunc(1); // RO_INIT_MULTITHREADED } } - struct console_restorer { + struct console_restorer + { CONSOLE_SCREEN_BUFFER_INFO m_originalConsoleInfo; - console_restorer() - { - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &m_originalConsoleInfo); - } + console_restorer() { GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &m_originalConsoleInfo); } ~console_restorer() { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), m_originalConsoleInfo.wAttributes); } - }local; + } local; #endif - if(parse_command_line(argc, argv) != 0) + if (parse_command_line(argc, argv) != 0) { return -1; } - if(g_test_binaries.empty()) + if (g_test_binaries.empty()) { std::cout << "Warning: no test binaries were specified" << std::endl; } @@ -556,18 +552,18 @@ int main(int argc, char* argv[]) UnitTest::TestReporterStdout testReporter; bool breakOnError = false; - if(UnitTest::GlobalSettings::Has("breakonerror")) + if (UnitTest::GlobalSettings::Has("breakonerror")) { breakOnError = true; } // Determine if list or listProperties. bool listOption = false, listPropertiesOption = false; - if(UnitTest::GlobalSettings::Has("list")) + if (UnitTest::GlobalSettings::Has("list")) { listOption = true; } - if(UnitTest::GlobalSettings::Has("listproperties")) + if (UnitTest::GlobalSettings::Has("listproperties")) { listOption = true; listPropertiesOption = true; @@ -593,7 +589,6 @@ int main(int argc, char* argv[]) return 0; } - // Run test cases UnitTest::TestRunner testRunner(testReporter, breakOnError); @@ -601,21 +596,20 @@ int main(int argc, char* argv[]) totalTestCount += testRunner.GetTestResults()->GetTotalTestCount(); failedTestCount += testRunner.GetTestResults()->GetFailedTestCount(); - if( totalTestCount == 0 ) + if (totalTestCount == 0) { std::cout << "No tests were run. Check the command line syntax (try 'TestRunner.exe /help')" << std::endl; } else { - if(testRunner.GetTestResults()->GetFailedTestCount() > 0) + if (testRunner.GetTestResults()->GetFailedTestCount() > 0) { ChangeConsoleTextColorToRed(); - const std::vector & failed = testRunner.GetTestResults()->GetFailedTests(); - std::for_each(failed.begin(), failed.end(), [](const std::string &failedTest) - { - std::cout << "**** " << failedTest << " FAILED ****" << std::endl << std::endl; - std::fflush(stdout); - }); + const std::vector& failed = testRunner.GetTestResults()->GetFailedTests(); + std::for_each(failed.begin(), failed.end(), [](const std::string& failedTest) { + std::cout << "**** " << failedTest << " FAILED ****" << std::endl << std::endl; + std::fflush(stdout); + }); ChangeConsoleTextColorToGrey(); } else @@ -624,7 +618,7 @@ int main(int argc, char* argv[]) std::cout << "All test cases PASSED" << std::endl << std::endl; ChangeConsoleTextColorToGrey(); } - const std::vector &newFailedTests = testRunner.GetTestResults()->GetFailedTests(); + const std::vector& newFailedTests = testRunner.GetTestResults()->GetFailedTests(); failedTests.insert(failedTests.end(), newFailedTests.begin(), newFailedTests.end()); const double elapsedTime = timer.GetTimeInMs(); @@ -634,11 +628,11 @@ int main(int argc, char* argv[]) #if defined(__cplusplus_winrt) #elif defined(_WIN32) - if(hComBase != nullptr) + if (hComBase != nullptr) { - typedef void (WINAPI *RoUnInit)(); + typedef void(WINAPI * RoUnInit)(); RoUnInit roUnInitFunc = (RoUnInit)GetProcAddress(hComBase, "RoUninitialize"); - if(roUnInitFunc != nullptr) + if (roUnInitFunc != nullptr) { roUnInitFunc(); } diff --git a/Release/tests/common/UnitTestpp/COPYING b/Release/tests/common/UnitTestpp/COPYING index 9f963085a3..a86c179b27 100644 --- a/Release/tests/common/UnitTestpp/COPYING +++ b/Release/tests/common/UnitTestpp/COPYING @@ -1,20 +1,19 @@ -Copyright (c) 2006 Noel Llopis and Charles Nicholson +Copyright(c) 2006 Noel Llopis and Charles Nicholson -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: + Permission is hereby granted, + free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), + to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and / or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions : -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in all copies + or + substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + THE SOFTWARE IS PROVIDED "AS IS", + WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Release/tests/common/UnitTestpp/config.h b/Release/tests/common/UnitTestpp/config.h index 7d0fd563a7..1fb3ad6668 100644 --- a/Release/tests/common/UnitTestpp/config.h +++ b/Release/tests/common/UnitTestpp/config.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_CONFIG_H #define UNITTEST_CONFIG_H @@ -35,30 +35,29 @@ // Standard defines documented here: http://predef.sourceforge.net #if defined(_MSC_VER) - #pragma warning(disable:4702) // unreachable code - #pragma warning(disable:4722) // destructor never returns, potential memory leak +#pragma warning(disable : 4702) // unreachable code +#pragma warning(disable : 4722) // destructor never returns, potential memory leak - #if (_MSC_VER == 1200) // VC6 - #pragma warning(disable:4786) - #pragma warning(disable:4290) - #endif +#if (_MSC_VER == 1200) // VC6 +#pragma warning(disable : 4786) +#pragma warning(disable : 4290) +#endif - #ifdef _USRDLL - #define UNITTEST_WIN32_DLL - #endif - #define UNITTEST_WIN32 +#ifdef _USRDLL +#define UNITTEST_WIN32_DLL +#endif +#define UNITTEST_WIN32 #endif -#if defined(unix) || defined(__unix__) || defined(__unix) || defined(linux) || \ - defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) - #define UNITTEST_POSIX +#if defined(unix) || defined(__unix__) || defined(__unix) || defined(linux) || defined(__APPLE__) || \ + defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) +#define UNITTEST_POSIX #endif #if defined(__MINGW32__) - #define UNITTEST_MINGW +#define UNITTEST_MINGW #endif - // MemoryOutStream is a custom reimplementation of parts of std::ostringstream. // Uncomment this line to have MemoryOutStream implemented in terms of std::ostringstream. // This is useful if you are using the CHECK macros on objects that have something like this defined: @@ -66,17 +65,15 @@ #define UNITTEST_MEMORYOUTSTREAM_IS_STD_OSTRINGSTREAM - // DeferredTestReporter uses the STL to collect test results for subsequent export by reporters like // XmlTestReporter. If you don't want to use this functionality, uncomment this line and no STL // headers or code will be compiled into UnitTest++ //#define UNITTEST_NO_DEFERRED_REPORTER - // By default, asserts that you report via UnitTest::ReportAssert() abort the current test and // continue to the next one by throwing an exception, which unwinds the stack naturally, destroying -// all auto variables on its way back down. If you don't want to (or can't) use exceptions for your +// all auto variables on its way back down. If you don't want to (or can't) use exceptions for your // platform/compiler, uncomment this line. All exception code will be removed from UnitTest++, // assert recovery will be done via setjmp/longjmp, and NO correct stack unwinding will happen! diff --git a/Release/tests/common/UnitTestpp/src/AssertException.cpp b/Release/tests/common/UnitTestpp/src/AssertException.cpp index 17e49c5bd1..6b8372e056 100644 --- a/Release/tests/common/UnitTestpp/src/AssertException.cpp +++ b/Release/tests/common/UnitTestpp/src/AssertException.cpp @@ -1,48 +1,44 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" #ifndef UNITTEST_NO_EXCEPTIONS -namespace UnitTest { - -AssertException::AssertException() +namespace UnitTest { -} +AssertException::AssertException() {} -AssertException::~AssertException() throw() -{ -} +AssertException::~AssertException() throw() {} -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/AssertException.h b/Release/tests/common/UnitTestpp/src/AssertException.h index 517875130e..59d4b83c25 100644 --- a/Release/tests/common/UnitTestpp/src/AssertException.h +++ b/Release/tests/common/UnitTestpp/src/AssertException.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_ASSERTEXCEPTION_H #define UNITTEST_ASSERTEXCEPTION_H @@ -38,8 +38,8 @@ #include "HelperMacros.h" #include -namespace UnitTest { - +namespace UnitTest +{ class AssertException : public std::exception { public: @@ -47,7 +47,7 @@ class AssertException : public std::exception UNITTEST_LINKAGE virtual ~AssertException() throw(); }; -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/CheckMacros.h b/Release/tests/common/UnitTestpp/src/CheckMacros.h index 8831d7a1af..43a9cccaf8 100644 --- a/Release/tests/common/UnitTestpp/src/CheckMacros.h +++ b/Release/tests/common/UnitTestpp/src/CheckMacros.h @@ -1,98 +1,97 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ - -#ifndef UNITTEST_CHECKMACROS_H + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ + +#ifndef UNITTEST_CHECKMACROS_H #define UNITTEST_CHECKMACROS_H -#include - -#include "HelperMacros.h" -#include "ExceptionMacros.h" -#include "Checks.h" #include "AssertException.h" -#include "MemoryOutStream.h" -#include "TestDetails.h" +#include "Checks.h" #include "CurrentTest.h" +#include "ExceptionMacros.h" +#include "HelperMacros.h" +#include "MemoryOutStream.h" #include "ReportAssertImpl.h" +#include "TestDetails.h" +#include #ifdef CHECK - #error UnitTest++ redefines CHECK +#error UnitTest++ redefines CHECK #endif #ifdef CHECK_EQUAL - #error UnitTest++ redefines CHECK_EQUAL +#error UnitTest++ redefines CHECK_EQUAL #endif #ifdef CHECK_CLOSE - #error UnitTest++ redefines CHECK_CLOSE +#error UnitTest++ redefines CHECK_CLOSE #endif #ifdef CHECK_ARRAY_EQUAL - #error UnitTest++ redefines CHECK_ARRAY_EQUAL +#error UnitTest++ redefines CHECK_ARRAY_EQUAL #endif #ifdef CHECK_ARRAY_CLOSE - #error UnitTest++ redefines CHECK_ARRAY_CLOSE +#error UnitTest++ redefines CHECK_ARRAY_CLOSE #endif #ifdef CHECK_ARRAY2D_CLOSE - #error UnitTest++ redefines CHECK_ARRAY2D_CLOSE +#error UnitTest++ redefines CHECK_ARRAY2D_CLOSE #endif #ifdef VERIFY_IS_TRUE - #error UnitTest++ redefines VERIFY_IS_TRUE +#error UnitTest++ redefines VERIFY_IS_TRUE #endif #ifdef VERIFY_IS_FALSE - #error UnitTest++ redefines VERIFY_IS_FALSE +#error UnitTest++ redefines VERIFY_IS_FALSE #endif #ifdef VERIFY_ARE_EQUAL - #error UnitTest++ redefines VERIFY_ARE_EQUAL +#error UnitTest++ redefines VERIFY_ARE_EQUAL #endif #ifdef VERIFY_ARE_NOT_EQUAL - #error UnitTest++ redefines VERIFY_ARE_NOT_EQUAL +#error UnitTest++ redefines VERIFY_ARE_NOT_EQUAL #endif #ifdef VERIFY_THROWS - #error UnitTest++ redefines VERIFY_THROWS +#error UnitTest++ redefines VERIFY_THROWS #endif #ifdef VERIFY_IS_NOT_NULL - #error UnitTest++ redefines VERIFY_IS_NOT_NULL +#error UnitTest++ redefines VERIFY_IS_NOT_NULL #endif #ifdef VERIFY_IS_NULL - #error UnitTest++ redefines VERIFY_IS_NULL +#error UnitTest++ redefines VERIFY_IS_NULL #endif #ifdef WIN32 @@ -112,129 +111,201 @@ #define VERIFY_IS_NOT_NULL(expression) CHECK_NOT_NULL(expression) #define VERIFY_IS_NULL(expression) CHECK_NULL(expression) -#define CHECK(value) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - if (!UnitTest::Check(value)) \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), #value); \ +#define CHECK(value) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + if (!UnitTest::Check(value)) \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), #value); \ UNITTEST_MULTILINE_MACRO_END #ifdef WIN32 -#define CHECK_EQUAL(expected, actual, ...) \ - do { \ - UnitTest::CheckEqual(*UnitTest::CurrentTest::Results(), #expected, #actual, expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), __VA_ARGS__); \ +#define CHECK_EQUAL(expected, actual, ...) \ + do \ + { \ + UnitTest::CheckEqual(*UnitTest::CurrentTest::Results(), \ + #expected, \ + #actual, \ + expected, \ + actual, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + __VA_ARGS__); \ UNITTEST_MULTILINE_MACRO_END -#define CHECK_NOT_EQUAL(expected, actual, ...) \ - do { \ - UnitTest::CheckNotEqual(*UnitTest::CurrentTest::Results(), #expected, #actual, expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), __VA_ARGS__); \ +#define CHECK_NOT_EQUAL(expected, actual, ...) \ + do \ + { \ + UnitTest::CheckNotEqual(*UnitTest::CurrentTest::Results(), \ + #expected, \ + #actual, \ + expected, \ + actual, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + __VA_ARGS__); \ UNITTEST_MULTILINE_MACRO_END #else -#define CHECK_EQUAL(expected, actual, ...) \ - do { \ - try \ - { \ - UnitTest::CheckEqual(*UnitTest::CurrentTest::Results(), #expected, #actual, expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), ##__VA_ARGS__); \ - } \ - catch (const std::exception& ex) \ - { \ - std::cerr << ex.what() << std::endl; \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ - "Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ") - details: "); \ - } \ - UT_CATCH_ALL \ - ({ \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ - "Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ")"); \ - }) \ +#define CHECK_EQUAL(expected, actual, ...) \ + do \ + { \ + try \ + { \ + UnitTest::CheckEqual(*UnitTest::CurrentTest::Results(), \ + #expected, \ + #actual, \ + expected, \ + actual, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + ##__VA_ARGS__); \ + } \ + catch (const std::exception& ex) \ + { \ + std::cerr << ex.what() << std::endl; \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ") - details: "); \ + } \ + UT_CATCH_ALL({ \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ")"); \ + }) \ UNITTEST_MULTILINE_MACRO_END -#define CHECK_NOT_EQUAL(expected, actual, ...) \ - do { \ - try \ - { \ - UnitTest::CheckNotEqual(*UnitTest::CurrentTest::Results(), #expected, #actual, expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), ##__VA_ARGS__); \ - } \ - UT_CATCH_ALL \ - ({ \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ - "Unhandled exception in CHECK_NOT_EQUAL(" #expected ", " #actual ")"); \ - }) \ +#define CHECK_NOT_EQUAL(expected, actual, ...) \ + do \ + { \ + try \ + { \ + UnitTest::CheckNotEqual(*UnitTest::CurrentTest::Results(), \ + #expected, \ + #actual, \ + expected, \ + actual, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + ##__VA_ARGS__); \ + } \ + UT_CATCH_ALL({ \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Unhandled exception in CHECK_NOT_EQUAL(" #expected ", " #actual ")"); \ + }) \ UNITTEST_MULTILINE_MACRO_END #endif -#define CHECK_NULL(expression) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - UnitTest::CheckNull(*UnitTest::CurrentTest::Results(), #expression, expression, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ +#define CHECK_NULL(expression) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + UnitTest::CheckNull(*UnitTest::CurrentTest::Results(), \ + #expression, \ + expression, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ UNITTEST_MULTILINE_MACRO_END -#define CHECK_NOT_NULL(expression) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - UnitTest::CheckNotNull(*UnitTest::CurrentTest::Results(), #expression, expression, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ +#define CHECK_NOT_NULL(expression) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + UnitTest::CheckNotNull(*UnitTest::CurrentTest::Results(), \ + #expression, \ + expression, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ UNITTEST_MULTILINE_MACRO_END -#define CHECK_CLOSE(expected, actual, tolerance) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - UnitTest::CheckClose(*UnitTest::CurrentTest::Results(), expected, actual, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ +#define CHECK_CLOSE(expected, actual, tolerance) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + UnitTest::CheckClose(*UnitTest::CurrentTest::Results(), \ + expected, \ + actual, \ + tolerance, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ UNITTEST_MULTILINE_MACRO_END -#define CHECK_ARRAY_EQUAL(expected, actual, count) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - UnitTest::CheckArrayEqual(*UnitTest::CurrentTest::Results(), expected, actual, count, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ +#define CHECK_ARRAY_EQUAL(expected, actual, count) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + UnitTest::CheckArrayEqual(*UnitTest::CurrentTest::Results(), \ + expected, \ + actual, \ + count, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ UNITTEST_MULTILINE_MACRO_END -#define CHECK_ARRAY_CLOSE(expected, actual, count, tolerance) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - UnitTest::CheckArrayClose(*UnitTest::CurrentTest::Results(), expected, actual, count, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ +#define CHECK_ARRAY_CLOSE(expected, actual, count, tolerance) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + UnitTest::CheckArrayClose(*UnitTest::CurrentTest::Results(), \ + expected, \ + actual, \ + count, \ + tolerance, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ UNITTEST_MULTILINE_MACRO_END -#define CHECK_ARRAY2D_CLOSE(expected, actual, rows, columns, tolerance) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - UnitTest::CheckArray2DClose(*UnitTest::CurrentTest::Results(), expected, actual, rows, columns, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ +#define CHECK_ARRAY2D_CLOSE(expected, actual, rows, columns, tolerance) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + UnitTest::CheckArray2DClose(*UnitTest::CurrentTest::Results(), \ + expected, \ + actual, \ + rows, \ + columns, \ + tolerance, \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ UNITTEST_MULTILINE_MACRO_END - // CHECK_THROW and CHECK_ASSERT only exist when UNITTEST_NO_EXCEPTIONS isn't defined (see config.h) #ifndef UNITTEST_NO_EXCEPTIONS -#define CHECK_THROW(expression, ExpectedExceptionType) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - bool caught_ = false; \ - try { \ - try { \ - expression; \ - } catch(const std::exception & _exc) { \ - std::string _msg(_exc.what()); \ - VERIFY_IS_TRUE(_msg.size() > 0); \ - throw; \ - } \ - } \ - catch (ExpectedExceptionType const&) { caught_ = true; } \ - catch (...) {} \ - if (!caught_) \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), "Expected exception: \"" #ExpectedExceptionType "\" not thrown"); \ +#define CHECK_THROW(expression, ExpectedExceptionType) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + bool caught_ = false; \ + try \ + { \ + try \ + { \ + expression; \ + } \ + catch (const std::exception& _exc) \ + { \ + std::string _msg(_exc.what()); \ + VERIFY_IS_TRUE(_msg.size() > 0); \ + throw; \ + } \ + } \ + catch (ExpectedExceptionType const&) \ + { \ + caught_ = true; \ + } \ + catch (...) \ + { \ + } \ + if (!caught_) \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Expected exception: \"" #ExpectedExceptionType "\" not thrown"); \ UNITTEST_MULTILINE_MACRO_END -#define CHECK_NO_THROW(expression) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - try { \ - expression; \ - } catch(const std::exception & _exc) { \ - std::string _msg("(" #expression ") threw exception: "); \ - _msg.append(_exc.what()); \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ - } catch (...) { \ - std::string _msg("(" #expression ") threw exception: <...>"); \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ - } \ +#define CHECK_NO_THROW(expression) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + try \ + { \ + expression; \ + } \ + catch (const std::exception& _exc) \ + { \ + std::string _msg("(" #expression ") threw exception: "); \ + _msg.append(_exc.what()); \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ + } \ + catch (...) \ + { \ + std::string _msg("(" #expression ") threw exception: <...>"); \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ + } \ UNITTEST_MULTILINE_MACRO_END -#define CHECK_ASSERT(expression) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - UnitTest::Detail::ExpectAssert(true); \ - CHECK_THROW(expression, UnitTest::AssertException); \ - UnitTest::Detail::ExpectAssert(false); \ +#define CHECK_ASSERT(expression) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + UnitTest::Detail::ExpectAssert(true); \ + CHECK_THROW(expression, UnitTest::AssertException); \ + UnitTest::Detail::ExpectAssert(false); \ UNITTEST_MULTILINE_MACRO_END #endif #endif diff --git a/Release/tests/common/UnitTestpp/src/Checks.h b/Release/tests/common/UnitTestpp/src/Checks.h index a791246833..4425fed100 100644 --- a/Release/tests/common/UnitTestpp/src/Checks.h +++ b/Release/tests/common/UnitTestpp/src/Checks.h @@ -1,140 +1,161 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_CHECKS_H #define UNITTEST_CHECKS_H -#include - -#include "config.h" - -#include "TestResults.h" #include "MemoryOutStream.h" -#include +#include "TestResults.h" +#include "config.h" #include +#include +#include #ifndef _WIN32 #include #endif -namespace UnitTest { - +namespace UnitTest +{ namespace details { - inline std::string utf16_to_utf8(const std::basic_string &w) - { +inline std::string utf16_to_utf8(const std::basic_string& w) +{ #ifdef _WIN32 - std::string result; - size_t size; - wcstombs_s(&size, nullptr, 0, (const wchar_t *)w.c_str(), w.size()); - result.resize(size); - // integr0808: added cast - wcstombs_s(&size, &result[0], size, (const wchar_t *)w.c_str(), w.size()); - return result; + std::string result; + size_t size; + wcstombs_s(&size, nullptr, 0, (const wchar_t*)w.c_str(), w.size()); + result.resize(size); + // integr0808: added cast + wcstombs_s(&size, &result[0], size, (const wchar_t*)w.c_str(), w.size()); + return result; #else - return boost::locale::conv::utf_to_utf(w, boost::locale::conv::stop); + return boost::locale::conv::utf_to_utf(w, boost::locale::conv::stop); #endif - } +} - typedef char yes; - typedef char (&no)[2]; +typedef char yes; +typedef char (&no)[2]; - struct anyx - { - template anyx(const T &); - }; - no operator << (const anyx &, const anyx &); +struct anyx +{ + template + anyx(const T&); +}; +no operator<<(const anyx&, const anyx&); - template yes check(T const&); - no check(no); +template +yes check(T const&); +no check(no); - template - struct support_stream_write { - static StreamType & stream; - static T1 & x; - static T2 & y; - static const bool value = (sizeof(check(stream << x)) == sizeof(yes)) && (sizeof(check(stream << y)) == sizeof(yes)); - }; +template +struct support_stream_write +{ + static StreamType& stream; + static T1& x; + static T2& y; + static const bool value = + (sizeof(check(stream << x)) == sizeof(yes)) && (sizeof(check(stream << y)) == sizeof(yes)); +}; + +template +inline std::string BuildFailureStringWithStream(const char* expectedStr, + const char* actualStr, + const T1& expected, + const T2& actual) +{ + UnitTest::MemoryOutStream stream; + stream << " where " << expectedStr << "=" << expected << " and " << actualStr << "=" << actual; + return stream.GetText(); +} - template - inline std::string BuildFailureStringWithStream(const char *expectedStr, const char *actualStr, const T1 &expected, const T2 &actual) +template +struct BuildFailureStringImpl +{ + std::string BuildString(const char*, const char*, const T1&, const T2&) { - UnitTest::MemoryOutStream stream; - stream << " where " << expectedStr << "=" << expected << " and " << actualStr << "=" << actual; - return stream.GetText(); + // Don't do anything since operator<< isn't supported. + return ""; } +}; - template - struct BuildFailureStringImpl - { - std::string BuildString(const char *, const char *, const T1 &, const T2 &) - { - // Don't do anything since operator<< isn't supported. - return ""; - } - }; - - template - struct BuildFailureStringImpl - { - std::string BuildString(const char *expectedStr, const char *actualStr, const T1 &expected, const T2 &actual) - { - return BuildFailureStringWithStream(expectedStr, actualStr, expected, actual); - } - }; - - template - inline std::string BuildFailureString(const char *expectedStr, const char *actualStr, const T1 &expected, const T2 &actual) - { - return BuildFailureStringImpl::value>().BuildString(expectedStr, actualStr, expected, actual); - } - inline std::string BuildFailureString(const char *expectedStr, const char *actualStr, const std::basic_string &expected, const std::basic_string &actual) - { - return BuildFailureStringWithStream(expectedStr, actualStr, utf16_to_utf8(expected), utf16_to_utf8(actual)); - } - inline std::string BuildFailureString(const char *expectedStr, const char *actualStr, const utf16char *expected, const utf16char *actual) - { - return BuildFailureStringWithStream(expectedStr, actualStr, utf16_to_utf8(expected), utf16_to_utf8(actual)); - } - inline std::string BuildFailureString(const char *expectedStr, const char *actualStr, const std::basic_string &expected, const utf16char *actual) - { - return BuildFailureStringWithStream(expectedStr, actualStr, utf16_to_utf8(expected), utf16_to_utf8(actual)); - } - inline std::string BuildFailureString(const char *expectedStr, const char *actualStr, const utf16char *expected, const std::basic_string &actual) +template +struct BuildFailureStringImpl +{ + std::string BuildString(const char* expectedStr, const char* actualStr, const T1& expected, const T2& actual) { - return BuildFailureStringWithStream(expectedStr, actualStr, utf16_to_utf8(expected), utf16_to_utf8(actual)); + return BuildFailureStringWithStream(expectedStr, actualStr, expected, actual); } +}; + +template +inline std::string BuildFailureString(const char* expectedStr, + const char* actualStr, + const T1& expected, + const T2& actual) +{ + return BuildFailureStringImpl::value>().BuildString( + expectedStr, actualStr, expected, actual); +} +inline std::string BuildFailureString(const char* expectedStr, + const char* actualStr, + const std::basic_string& expected, + const std::basic_string& actual) +{ + return BuildFailureStringWithStream(expectedStr, actualStr, utf16_to_utf8(expected), utf16_to_utf8(actual)); +} +inline std::string BuildFailureString(const char* expectedStr, + const char* actualStr, + const utf16char* expected, + const utf16char* actual) +{ + return BuildFailureStringWithStream(expectedStr, actualStr, utf16_to_utf8(expected), utf16_to_utf8(actual)); +} +inline std::string BuildFailureString(const char* expectedStr, + const char* actualStr, + const std::basic_string& expected, + const utf16char* actual) +{ + return BuildFailureStringWithStream(expectedStr, actualStr, utf16_to_utf8(expected), utf16_to_utf8(actual)); +} +inline std::string BuildFailureString(const char* expectedStr, + const char* actualStr, + const utf16char* expected, + const std::basic_string& actual) +{ + return BuildFailureStringWithStream(expectedStr, actualStr, utf16_to_utf8(expected), utf16_to_utf8(actual)); +} } // namespace details -template< typename Value > +template bool Check(Value const value) { return !!value; // doing double negative to avoid silly VS warnings @@ -144,8 +165,8 @@ bool Check(Value const value) #pragma warning(push) #pragma warning(disable : 4389) #endif -template -bool CheckEqualImpl(const Expected &expected, const Actual &actual) +template +bool CheckEqualImpl(const Expected& expected, const Actual& actual) { return !(expected == actual); } @@ -153,24 +174,30 @@ bool CheckEqualImpl(const Expected &expected, const Actual &actual) #pragma warning(pop) #endif -inline bool CheckEqualImpl(const char *expected, const char *actual) { return !(std::strcmp(expected, actual) == 0); } -inline bool CheckEqualImpl(char *expected, const char *actual) { return !(std::strcmp(expected, actual) == 0); } -inline bool CheckEqualImpl(const char *expected, char *actual) { return !(std::strcmp(expected, actual) == 0); } -inline bool CheckEqualImpl(char *expected, char *actual) { return !(std::strcmp(expected, actual) == 0); } -inline bool CheckEqualImpl(const wchar_t *expected, const wchar_t *actual) { return !(wcscmp(expected, actual) == 0); } -inline bool CheckEqualImpl(wchar_t *expected, const wchar_t *actual) { return !(wcscmp(expected, actual) == 0); } -inline bool CheckEqualImpl(const wchar_t *expected, wchar_t *actual) { return !(wcscmp(expected, actual) == 0); } -inline bool CheckEqualImpl(wchar_t *expected, wchar_t *actual) { return !(wcscmp(expected, actual) == 0); } - -template< typename Expected, typename Actual > -void CheckEqual(TestResults& results, const char *expectedStr, const char *actualStr, const Expected & expected, const Actual & actual, TestDetails const& details, const char *msg = nullptr) +inline bool CheckEqualImpl(const char* expected, const char* actual) { return !(std::strcmp(expected, actual) == 0); } +inline bool CheckEqualImpl(char* expected, const char* actual) { return !(std::strcmp(expected, actual) == 0); } +inline bool CheckEqualImpl(const char* expected, char* actual) { return !(std::strcmp(expected, actual) == 0); } +inline bool CheckEqualImpl(char* expected, char* actual) { return !(std::strcmp(expected, actual) == 0); } +inline bool CheckEqualImpl(const wchar_t* expected, const wchar_t* actual) { return !(wcscmp(expected, actual) == 0); } +inline bool CheckEqualImpl(wchar_t* expected, const wchar_t* actual) { return !(wcscmp(expected, actual) == 0); } +inline bool CheckEqualImpl(const wchar_t* expected, wchar_t* actual) { return !(wcscmp(expected, actual) == 0); } +inline bool CheckEqualImpl(wchar_t* expected, wchar_t* actual) { return !(wcscmp(expected, actual) == 0); } + +template +void CheckEqual(TestResults& results, + const char* expectedStr, + const char* actualStr, + const Expected& expected, + const Actual& actual, + TestDetails const& details, + const char* msg = nullptr) { if (CheckEqualImpl(expected, actual)) { UnitTest::MemoryOutStream stream; stream << "CHECK_EQUAL(" << expectedStr << ", " << actualStr << ")"; stream << details::BuildFailureString(expectedStr, actualStr, expected, actual) << std::endl; - if(msg != nullptr) + if (msg != nullptr) { stream << msg; } @@ -178,15 +205,21 @@ void CheckEqual(TestResults& results, const char *expectedStr, const char *actua } } -template -void CheckNotEqual(TestResults& results, const char *expectedStr, const char *actualStr, Expected const& expected, Actual const& actual, TestDetails const& details, const char *msg = nullptr) +template +void CheckNotEqual(TestResults& results, + const char* expectedStr, + const char* actualStr, + Expected const& expected, + Actual const& actual, + TestDetails const& details, + const char* msg = nullptr) { - if(!CheckEqualImpl(expected, actual)) + if (!CheckEqualImpl(expected, actual)) { UnitTest::MemoryOutStream stream; stream << "CHECK_NOT_EQUAL(" << expectedStr << ", " << actualStr << ")"; stream << details::BuildFailureString(expectedStr, actualStr, expected, actual) << std::endl; - if(msg != nullptr) + if (msg != nullptr) { stream << msg; } @@ -194,10 +227,10 @@ void CheckNotEqual(TestResults& results, const char *expectedStr, const char *ac } } -template -void CheckNull(TestResults& results, const char *actualStr, Actual const& actual, TestDetails const& details) +template +void CheckNull(TestResults& results, const char* actualStr, Actual const& actual, TestDetails const& details) { - if(actual) + if (actual) { UnitTest::MemoryOutStream stream; stream << "CHECK_NULL(" << actualStr << ")"; @@ -205,10 +238,10 @@ void CheckNull(TestResults& results, const char *actualStr, Actual const& actual } } -template -void CheckNotNull(TestResults& results, const char *actualStr, Actual const& actual, TestDetails const& details) +template +void CheckNotNull(TestResults& results, const char* actualStr, Actual const& actual, TestDetails const& details) { - if(!actual) + if (!actual) { UnitTest::MemoryOutStream stream; stream << "CHECK_NOT_NULL(" << actualStr << ")"; @@ -216,18 +249,21 @@ void CheckNotNull(TestResults& results, const char *actualStr, Actual const& act } } -template< typename Expected, typename Actual, typename Tolerance > +template bool AreClose(Expected const& expected, Actual const& actual, Tolerance const& tolerance) { return (actual >= (expected - tolerance)) && (actual <= (expected + tolerance)); } -template< typename Expected, typename Actual, typename Tolerance > -void CheckClose(TestResults& results, Expected const& expected, Actual const& actual, Tolerance const& tolerance, +template +void CheckClose(TestResults& results, + Expected const& expected, + Actual const& actual, + Tolerance const& tolerance, TestDetails const& details) { if (!AreClose(expected, actual, tolerance)) - { + { UnitTest::MemoryOutStream stream; stream << "Expected " << expected << " +/- " << tolerance << " but was " << actual; @@ -235,9 +271,9 @@ void CheckClose(TestResults& results, Expected const& expected, Actual const& ac } } -template< typename Expected, typename Actual > -void CheckArrayEqual(TestResults& results, Expected const& expected, Actual const& actual, - int const count, TestDetails const& details) +template +void CheckArrayEqual( + TestResults& results, Expected const& expected, Actual const& actual, int const count, TestDetails const& details) { bool equal = true; for (int i = 0; i < count; ++i) @@ -263,7 +299,7 @@ void CheckArrayEqual(TestResults& results, Expected const& expected, Actual cons } } -template< typename Expected, typename Actual, typename Tolerance > +template bool ArrayAreClose(Expected const& expected, Actual const& actual, int const count, Tolerance const& tolerance) { bool equal = true; @@ -272,9 +308,13 @@ bool ArrayAreClose(Expected const& expected, Actual const& actual, int const cou return equal; } -template< typename Expected, typename Actual, typename Tolerance > -void CheckArrayClose(TestResults& results, Expected const& expected, Actual const& actual, - int const count, Tolerance const& tolerance, TestDetails const& details) +template +void CheckArrayClose(TestResults& results, + Expected const& expected, + Actual const& actual, + int const count, + Tolerance const& tolerance, + TestDetails const& details) { bool equal = ArrayAreClose(expected, actual, count, tolerance); @@ -295,9 +335,14 @@ void CheckArrayClose(TestResults& results, Expected const& expected, Actual cons } } -template< typename Expected, typename Actual, typename Tolerance > -void CheckArray2DClose(TestResults& results, Expected const& expected, Actual const& actual, - int const rows, int const columns, Tolerance const& tolerance, TestDetails const& details) +template +void CheckArray2DClose(TestResults& results, + Expected const& expected, + Actual const& actual, + int const rows, + int const columns, + Tolerance const& tolerance, + TestDetails const& details) { bool equal = true; for (int i = 0; i < rows; ++i) @@ -307,7 +352,7 @@ void CheckArray2DClose(TestResults& results, Expected const& expected, Actual co { UnitTest::MemoryOutStream stream; - stream << "Expected [ "; + stream << "Expected [ "; for (int expectedRow = 0; expectedRow < rows; ++expectedRow) { @@ -333,6 +378,6 @@ void CheckArray2DClose(TestResults& results, Expected const& expected, Actual co } } -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/CompositeTestReporter.cpp b/Release/tests/common/UnitTestpp/src/CompositeTestReporter.cpp index 07efb3fe32..c5ed9993d2 100644 --- a/Release/tests/common/UnitTestpp/src/CompositeTestReporter.cpp +++ b/Release/tests/common/UnitTestpp/src/CompositeTestReporter.cpp @@ -1,66 +1,59 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" #include "CompositeTestReporter.h" -namespace UnitTest { - -CompositeTestReporter::CompositeTestReporter() - : m_reporterCount(0) +namespace UnitTest { -} +CompositeTestReporter::CompositeTestReporter() : m_reporterCount(0) {} -int CompositeTestReporter::GetReporterCount() const -{ - return m_reporterCount; -} +int CompositeTestReporter::GetReporterCount() const { return m_reporterCount; } bool CompositeTestReporter::AddReporter(TestReporter* reporter) { - if (m_reporterCount == kMaxReporters) - return false; + if (m_reporterCount == kMaxReporters) return false; // Safe to ignore we check the size to make sure no buffer overruns before. #if defined(_MSC_VER) -#pragma warning (push) -#pragma warning (disable : 6386) +#pragma warning(push) +#pragma warning(disable : 6386) #endif m_reporters[m_reporterCount++] = reporter; #if defined(_MSC_VER) -#pragma warning (pop) +#pragma warning(pop) #endif - return true; + return true; } bool CompositeTestReporter::RemoveReporter(TestReporter* reporter) @@ -70,8 +63,8 @@ bool CompositeTestReporter::RemoveReporter(TestReporter* reporter) if (m_reporters[index] == reporter) { m_reporters[index] = m_reporters[m_reporterCount - 1]; - --m_reporterCount; - return true; + --m_reporterCount; + return true; } } @@ -81,28 +74,28 @@ bool CompositeTestReporter::RemoveReporter(TestReporter* reporter) void CompositeTestReporter::ReportFailure(TestDetails const& details, char const* failure) { for (int index = 0; index < m_reporterCount; ++index) - m_reporters[index]->ReportFailure(details, failure); + m_reporters[index]->ReportFailure(details, failure); } void CompositeTestReporter::ReportTestStart(TestDetails const& test) { - for (int index = 0; index < m_reporterCount; ++index) - m_reporters[index]->ReportTestStart(test); + for (int index = 0; index < m_reporterCount; ++index) + m_reporters[index]->ReportTestStart(test); } void CompositeTestReporter::ReportTestFinish(TestDetails const& test, bool passed, float secondsElapsed) { - for (int index = 0; index < m_reporterCount; ++index) - m_reporters[index]->ReportTestFinish(test, passed, secondsElapsed); + for (int index = 0; index < m_reporterCount; ++index) + m_reporters[index]->ReportTestFinish(test, passed, secondsElapsed); } void CompositeTestReporter::ReportSummary(int totalTestCount, - int failedTestCount, - int failureCount, - float secondsElapsed) + int failedTestCount, + int failureCount, + float secondsElapsed) { - for (int index = 0; index < m_reporterCount; ++index) - m_reporters[index]->ReportSummary(totalTestCount, failedTestCount, failureCount, secondsElapsed); + for (int index = 0; index < m_reporterCount; ++index) + m_reporters[index]->ReportSummary(totalTestCount, failedTestCount, failureCount, secondsElapsed); } -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/CompositeTestReporter.h b/Release/tests/common/UnitTestpp/src/CompositeTestReporter.h index abc51d163e..08dc2e5413 100644 --- a/Release/tests/common/UnitTestpp/src/CompositeTestReporter.h +++ b/Release/tests/common/UnitTestpp/src/CompositeTestReporter.h @@ -1,65 +1,71 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_COMPOSITETESTREPORTER_H #define UNITTEST_COMPOSITETESTREPORTER_H #include "TestReporter.h" -namespace UnitTest { - +namespace UnitTest +{ class CompositeTestReporter : public TestReporter { public: UNITTEST_LINKAGE CompositeTestReporter(); - UNITTEST_LINKAGE int GetReporterCount() const; + UNITTEST_LINKAGE int GetReporterCount() const; UNITTEST_LINKAGE bool AddReporter(TestReporter* reporter); UNITTEST_LINKAGE bool RemoveReporter(TestReporter* reporter); UNITTEST_LINKAGE virtual void ReportTestStart(TestDetails const& test); UNITTEST_LINKAGE virtual void ReportFailure(TestDetails const& test, char const* failure); UNITTEST_LINKAGE virtual void ReportTestFinish(TestDetails const& test, bool passed, float secondsElapsed); - UNITTEST_LINKAGE virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); + UNITTEST_LINKAGE virtual void ReportSummary(int totalTestCount, + int failedTestCount, + int failureCount, + float secondsElapsed); private: - enum { kMaxReporters = 16 }; - TestReporter* m_reporters[kMaxReporters]; - int m_reporterCount; + enum + { + kMaxReporters = 16 + }; + TestReporter* m_reporters[kMaxReporters]; + int m_reporterCount; - // revoked - CompositeTestReporter(const CompositeTestReporter&); - CompositeTestReporter& operator =(const CompositeTestReporter&); + // revoked + CompositeTestReporter(const CompositeTestReporter&); + CompositeTestReporter& operator=(const CompositeTestReporter&); }; -} +} // namespace UnitTest -#endif +#endif diff --git a/Release/tests/common/UnitTestpp/src/CurrentTest.cpp b/Release/tests/common/UnitTestpp/src/CurrentTest.cpp index 35aa1a9cba..f7e9f2fb46 100644 --- a/Release/tests/common/UnitTestpp/src/CurrentTest.cpp +++ b/Release/tests/common/UnitTestpp/src/CurrentTest.cpp @@ -1,60 +1,55 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" -#include -namespace { - std::atomic testResults; - std::atomic testDetails; // non-const pointer to avoid VS2013 STL bug -} +#include -namespace UnitTest { +namespace +{ +std::atomic testResults; +std::atomic testDetails; // non-const pointer to avoid VS2013 STL bug +} // namespace -UNITTEST_LINKAGE TestResults* CurrentTest::Results() +namespace UnitTest { - return testResults; -} +UNITTEST_LINKAGE TestResults* CurrentTest::Results() { return testResults; } -UNITTEST_LINKAGE void CurrentTest::SetResults(TestResults * r) { - testResults.store(r); -} +UNITTEST_LINKAGE void CurrentTest::SetResults(TestResults* r) { testResults.store(r); } -UNITTEST_LINKAGE const TestDetails* CurrentTest::Details() -{ - return testDetails; -} +UNITTEST_LINKAGE const TestDetails* CurrentTest::Details() { return testDetails; } -UNITTEST_LINKAGE void CurrentTest::SetDetails(const UnitTest::TestDetails * d) { - testDetails.store(const_cast(d)); +UNITTEST_LINKAGE void CurrentTest::SetDetails(const UnitTest::TestDetails* d) +{ + testDetails.store(const_cast(d)); } -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/CurrentTest.h b/Release/tests/common/UnitTestpp/src/CurrentTest.h index 4dbe6eff94..bc92c954c0 100644 --- a/Release/tests/common/UnitTestpp/src/CurrentTest.h +++ b/Release/tests/common/UnitTestpp/src/CurrentTest.h @@ -1,52 +1,52 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_CURRENTTESTRESULTS_H #define UNITTEST_CURRENTTESTRESULTS_H #include "HelperMacros.h" -namespace UnitTest { - +namespace UnitTest +{ class TestResults; class TestDetails; namespace CurrentTest { - UNITTEST_LINKAGE TestResults* __cdecl Results(); - UNITTEST_LINKAGE void __cdecl SetResults(TestResults*); - UNITTEST_LINKAGE const TestDetails* __cdecl Details(); - UNITTEST_LINKAGE void __cdecl SetDetails(const TestDetails *); -} +UNITTEST_LINKAGE TestResults* __cdecl Results(); +UNITTEST_LINKAGE void __cdecl SetResults(TestResults*); +UNITTEST_LINKAGE const TestDetails* __cdecl Details(); +UNITTEST_LINKAGE void __cdecl SetDetails(const TestDetails*); +} // namespace CurrentTest -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/DeferredTestReporter.cpp b/Release/tests/common/UnitTestpp/src/DeferredTestReporter.cpp index 34dd2b2497..5a958c4ae3 100644 --- a/Release/tests/common/UnitTestpp/src/DeferredTestReporter.cpp +++ b/Release/tests/common/UnitTestpp/src/DeferredTestReporter.cpp @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" @@ -54,9 +54,6 @@ void DeferredTestReporter::ReportTestFinish(TestDetails const&, bool, float seco r.timeElapsed = secondsElapsed; } -DeferredTestReporter::DeferredTestResultList& DeferredTestReporter::GetResults() -{ - return m_results; -} +DeferredTestReporter::DeferredTestResultList& DeferredTestReporter::GetResults() { return m_results; } #endif diff --git a/Release/tests/common/UnitTestpp/src/DeferredTestReporter.h b/Release/tests/common/UnitTestpp/src/DeferredTestReporter.h index 4f40d9d67e..b64fb72d58 100644 --- a/Release/tests/common/UnitTestpp/src/DeferredTestReporter.h +++ b/Release/tests/common/UnitTestpp/src/DeferredTestReporter.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_DEFERREDTESTREPORTER_H #define UNITTEST_DEFERREDTESTREPORTER_H @@ -36,14 +36,12 @@ #ifndef UNITTEST_NO_DEFERRED_REPORTER -#include "TestReporter.h" #include "DeferredTestResult.h" - +#include "TestReporter.h" #include namespace UnitTest { - class DeferredTestReporter : public TestReporter { public: @@ -51,14 +49,14 @@ class DeferredTestReporter : public TestReporter UNITTEST_LINKAGE virtual void ReportFailure(TestDetails const& details, char const* failure); UNITTEST_LINKAGE virtual void ReportTestFinish(TestDetails const& details, bool passed, float secondsElapsed); - typedef std::vector< DeferredTestResult > DeferredTestResultList; + typedef std::vector DeferredTestResultList; UNITTEST_LINKAGE DeferredTestResultList& GetResults(); private: DeferredTestResultList m_results; }; -} +} // namespace UnitTest #endif #endif diff --git a/Release/tests/common/UnitTestpp/src/DeferredTestResult.cpp b/Release/tests/common/UnitTestpp/src/DeferredTestResult.cpp index 31d2b8a57b..5800eeb6f1 100644 --- a/Release/tests/common/UnitTestpp/src/DeferredTestResult.cpp +++ b/Release/tests/common/UnitTestpp/src/DeferredTestResult.cpp @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" @@ -37,50 +37,34 @@ namespace UnitTest { +DeferredTestFailure::DeferredTestFailure() : lineNumber(-1) { failureStr[0] = '\0'; } -DeferredTestFailure::DeferredTestFailure() - : lineNumber(-1) -{ - failureStr[0] = '\0'; -} - -DeferredTestFailure::DeferredTestFailure(int lineNumber_, const char* failureStr_) - : lineNumber(lineNumber_) +DeferredTestFailure::DeferredTestFailure(int lineNumber_, const char* failureStr_) : lineNumber(lineNumber_) { // Ignoring warning about possible overrun because we aren't going to entirely // change how unittestpp deals with strings. #if defined(_MSC_VER) -#pragma warning (push) -#pragma warning (disable : 6204) +#pragma warning(push) +#pragma warning(disable : 6204) #endif - std::strcpy(failureStr, failureStr_); + std::strcpy(failureStr, failureStr_); #if defined(_MSC_VER) -#pragma warning (pop) +#pragma warning(pop) #endif } DeferredTestResult::DeferredTestResult() - : suiteName("") - , testName("") - , failureFile("") - , timeElapsed(0.0f) - , failed(false) + : suiteName(""), testName(""), failureFile(""), timeElapsed(0.0f), failed(false) { } DeferredTestResult::DeferredTestResult(char const* suite, char const* test) - : suiteName(suite) - , testName(test) - , failureFile("") - , timeElapsed(0.0f) - , failed(false) + : suiteName(suite), testName(test), failureFile(""), timeElapsed(0.0f), failed(false) { } -DeferredTestResult::~DeferredTestResult() -{ -} +DeferredTestResult::~DeferredTestResult() {} -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/DeferredTestResult.h b/Release/tests/common/UnitTestpp/src/DeferredTestResult.h index 8276e2d493..711b6549ed 100644 --- a/Release/tests/common/UnitTestpp/src/DeferredTestResult.h +++ b/Release/tests/common/UnitTestpp/src/DeferredTestResult.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_DEFERREDTESTRESULT_H #define UNITTEST_DEFERREDTESTRESULT_H @@ -41,41 +41,39 @@ namespace UnitTest { - class DeferredTestFailure { public: - UNITTEST_LINKAGE DeferredTestFailure(); - UNITTEST_LINKAGE DeferredTestFailure(int lineNumber_, const char* failureStr_); + UNITTEST_LINKAGE DeferredTestFailure(); + UNITTEST_LINKAGE DeferredTestFailure(int lineNumber_, const char* failureStr_); - int lineNumber; - char failureStr[1024]; + int lineNumber; + char failureStr[1024]; }; -} +} // namespace UnitTest namespace UnitTest { - class DeferredTestResult { public: - UNITTEST_LINKAGE DeferredTestResult(); + UNITTEST_LINKAGE DeferredTestResult(); UNITTEST_LINKAGE DeferredTestResult(char const* suite, char const* test); UNITTEST_LINKAGE ~DeferredTestResult(); - + std::string suiteName; std::string testName; std::string failureFile; - - typedef std::vector< DeferredTestFailure > FailureVec; + + typedef std::vector FailureVec; FailureVec failures; - + float timeElapsed; - bool failed; + bool failed; }; -} +} // namespace UnitTest #endif #endif diff --git a/Release/tests/common/UnitTestpp/src/ExceptionMacros.h b/Release/tests/common/UnitTestpp/src/ExceptionMacros.h index 1d92b329a9..8c57e43d4b 100644 --- a/Release/tests/common/UnitTestpp/src/ExceptionMacros.h +++ b/Release/tests/common/UnitTestpp/src/ExceptionMacros.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_EXCEPTIONMACROS_H #define UNITTEST_EXCEPTIONMACROS_H @@ -35,15 +35,17 @@ #include "../config.h" #ifndef UNITTEST_NO_EXCEPTIONS - #define UT_TRY(x) try x - #define UT_THROW(x) throw x - #define UT_CATCH(ExceptionType, ExceptionName, CatchBody) catch(ExceptionType& ExceptionName) CatchBody - #define UT_CATCH_ALL(CatchBody) catch(...) CatchBody +#define UT_TRY(x) \ + try \ + x +#define UT_THROW(x) throw x +#define UT_CATCH(ExceptionType, ExceptionName, CatchBody) catch (ExceptionType & ExceptionName) CatchBody +#define UT_CATCH_ALL(CatchBody) catch (...) CatchBody #else - #define UT_TRY(x) x - #define UT_THROW(x) - #define UT_CATCH(ExceptionType, ExceptionName, CatchBody) - #define UT_CATCH_ALL(CatchBody) +#define UT_TRY(x) x +#define UT_THROW(x) +#define UT_CATCH(ExceptionType, ExceptionName, CatchBody) +#define UT_CATCH_ALL(CatchBody) #endif #endif diff --git a/Release/tests/common/UnitTestpp/src/ExecuteTest.h b/Release/tests/common/UnitTestpp/src/ExecuteTest.h index ef87c48dc3..274d55005b 100644 --- a/Release/tests/common/UnitTestpp/src/ExecuteTest.h +++ b/Release/tests/common/UnitTestpp/src/ExecuteTest.h @@ -1,94 +1,89 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_EXECUTE_TEST_H #define UNITTEST_EXECUTE_TEST_H #include "../config.h" -#include "ExceptionMacros.h" -#include "TestDetails.h" -#include "MemoryOutStream.h" #include "AssertException.h" #include "CurrentTest.h" +#include "ExceptionMacros.h" +#include "MemoryOutStream.h" +#include "TestDetails.h" #include "TestResults.h" #ifdef UNITTEST_NO_EXCEPTIONS - #include "ReportAssertImpl.h" +#include "ReportAssertImpl.h" #endif #ifdef UNITTEST_POSIX - #include "Posix/SignalTranslator.h" +#include "Posix/SignalTranslator.h" #endif #include -namespace UnitTest { - -template< typename T > +namespace UnitTest +{ +template void ExecuteTest(T& testObject, TestDetails const& details, bool isMockTest) { - if (isMockTest == false) + if (isMockTest == false) { CurrentTest::SetDetails(&details); } #ifdef UNITTEST_NO_EXCEPTIONS - if (UNITTEST_SET_ASSERT_JUMP_TARGET() == 0) - { + if (UNITTEST_SET_ASSERT_JUMP_TARGET() == 0) + { #endif #ifndef UNITTEST_POSIX - UT_TRY({ testObject.RunImpl(); }) + UT_TRY({ testObject.RunImpl(); }) #else - UT_TRY - ({ - UNITTEST_THROW_SIGNALS_POSIX_ONLY - testObject.RunImpl(); - }) + UT_TRY({ + UNITTEST_THROW_SIGNALS_POSIX_ONLY + testObject.RunImpl(); + }) #endif - UT_CATCH(AssertException, e, { (void)e; }) - UT_CATCH(std::exception, e, - { - MemoryOutStream stream; - stream << "Unhandled exception: " << e.what(); - CurrentTest::Results()->OnTestFailure(details, stream.GetText()); - }) - UT_CATCH_ALL - ({ - CurrentTest::Results()->OnTestFailure(details, "Unhandled exception: test crashed"); - }) + UT_CATCH(AssertException, e, { (void)e; }) + UT_CATCH(std::exception, e, { + MemoryOutStream stream; + stream << "Unhandled exception: " << e.what(); + CurrentTest::Results()->OnTestFailure(details, stream.GetText()); + }) + UT_CATCH_ALL({ CurrentTest::Results()->OnTestFailure(details, "Unhandled exception: test crashed"); }) #ifdef UNITTEST_NO_EXCEPTIONS - } + } #endif } -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/GlobalSettings.cpp b/Release/tests/common/UnitTestpp/src/GlobalSettings.cpp index 9d97ef7413..2a9f625d42 100644 --- a/Release/tests/common/UnitTestpp/src/GlobalSettings.cpp +++ b/Release/tests/common/UnitTestpp/src/GlobalSettings.cpp @@ -1,69 +1,64 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" -#include -#include #include "GlobalSettings.h" -namespace UnitTest { +#include +#include -static std::string to_lower(const std::string &str) +namespace UnitTest { - std::string retVal; - retVal.resize(str.size()); - std::transform(str.begin(), str.end(), retVal.begin(), ::tolower); - return retVal; +static std::string to_lower(const std::string& str) +{ + std::string retVal; + retVal.resize(str.size()); + std::transform(str.begin(), str.end(), retVal.begin(), ::tolower); + return retVal; } std::map g_settings; -void GlobalSettings::Add(const std::string &key, const std::string &value) -{ - g_settings[to_lower(key)] = value; -} +void GlobalSettings::Add(const std::string& key, const std::string& value) { g_settings[to_lower(key)] = value; } -bool GlobalSettings::Has(const std::string &key) -{ - return g_settings.find(to_lower(key)) != g_settings.end(); -} +bool GlobalSettings::Has(const std::string& key) { return g_settings.find(to_lower(key)) != g_settings.end(); } -const std::string & GlobalSettings::Get(const std::string &key) +const std::string& GlobalSettings::Get(const std::string& key) { - if(!Has(key)) + if (!Has(key)) { throw std::invalid_argument("Error: property is not found"); } return g_settings.find(to_lower(key))->second; } -} \ No newline at end of file +} // namespace UnitTest \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/src/GlobalSettings.h b/Release/tests/common/UnitTestpp/src/GlobalSettings.h index 6eaf0ff1b5..e1de21846d 100644 --- a/Release/tests/common/UnitTestpp/src/GlobalSettings.h +++ b/Release/tests/common/UnitTestpp/src/GlobalSettings.h @@ -1,59 +1,59 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_GLOBAL_PROPERTIES_H #define UNITTEST_GLOBAL_PROPERTIES_H +#include "HelperMacros.h" #include -namespace UnitTest { - - // Simple key value pairs for global properties. - // Any test case which specifies a 'Requires' TestProperty will only execute if - // the required property is satisfied as a key in the GlobalSettings. - class GlobalSettings - { - public: - - UNITTEST_LINKAGE static void __cdecl Add(const std::string &key, const std::string &value); - - UNITTEST_LINKAGE static bool __cdecl Has(const std::string &key); - - UNITTEST_LINKAGE static const std::string & __cdecl Get(const std::string &key); - - private: - GlobalSettings(); - GlobalSettings(const GlobalSettings &); - GlobalSettings &operator=(const GlobalSettings &); - }; -} +namespace UnitTest +{ +// Simple key value pairs for global properties. +// Any test case which specifies a 'Requires' TestProperty will only execute if +// the required property is satisfied as a key in the GlobalSettings. +class GlobalSettings +{ +public: + UNITTEST_LINKAGE static void __cdecl Add(const std::string& key, const std::string& value); + + UNITTEST_LINKAGE static bool __cdecl Has(const std::string& key); + + UNITTEST_LINKAGE static const std::string& __cdecl Get(const std::string& key); + +private: + GlobalSettings(); + GlobalSettings(const GlobalSettings&); + GlobalSettings& operator=(const GlobalSettings&); +}; +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/HelperMacros.h b/Release/tests/common/UnitTestpp/src/HelperMacros.h index 512a71ef94..6cc8559cef 100644 --- a/Release/tests/common/UnitTestpp/src/HelperMacros.h +++ b/Release/tests/common/UnitTestpp/src/HelperMacros.h @@ -1,83 +1,85 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_HELPERMACROS_H #define UNITTEST_HELPERMACROS_H #include "../config.h" -#define UNITTEST_MULTILINE_MACRO_BEGIN do { - +#define UNITTEST_MULTILINE_MACRO_BEGIN \ + do \ + { #ifdef UNITTEST_WIN32 - #define UNITTEST_MULTILINE_MACRO_END \ - } __pragma(warning(push)) __pragma(warning(disable:4127)) while (0) __pragma(warning(pop)) +#define UNITTEST_MULTILINE_MACRO_END \ + } \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) while (0) __pragma(warning(pop)) #else - #define UNITTEST_MULTILINE_MACRO_END } while(0) +#define UNITTEST_MULTILINE_MACRO_END \ + } \ + while (0) #endif - #ifdef UNITTEST_WIN32_DLL - #define UNITTEST_IMPORT __declspec(dllimport) - #define UNITTEST_EXPORT __declspec(dllexport) +#define UNITTEST_IMPORT __declspec(dllimport) +#define UNITTEST_EXPORT __declspec(dllexport) - #ifdef UNITTEST_DLL_EXPORT - #define UNITTEST_LINKAGE UNITTEST_EXPORT - #define UNITTEST_IMPEXP_TEMPLATE - #else - #define UNITTEST_LINKAGE UNITTEST_IMPORT - #define UNITTEST_IMPEXP_TEMPLATE extern - #endif +#ifdef UNITTEST_DLL_EXPORT +#define UNITTEST_LINKAGE UNITTEST_EXPORT +#define UNITTEST_IMPEXP_TEMPLATE +#else +#define UNITTEST_LINKAGE UNITTEST_IMPORT +#define UNITTEST_IMPEXP_TEMPLATE extern +#endif - #define UNITTEST_STDVECTOR_LINKAGE(T) \ - __pragma(warning(push)) \ - __pragma(warning(disable:4231)) \ - UNITTEST_IMPEXP_TEMPLATE template class UNITTEST_LINKAGE std::allocator< T >; \ - UNITTEST_IMPEXP_TEMPLATE template class UNITTEST_LINKAGE std::vector< T >; \ - __pragma(warning(pop)) +#define UNITTEST_STDVECTOR_LINKAGE(T) \ + __pragma(warning(push)) __pragma(warning(disable : 4231)) \ + UNITTEST_IMPEXP_TEMPLATE template class UNITTEST_LINKAGE std::allocator; \ + UNITTEST_IMPEXP_TEMPLATE template class UNITTEST_LINKAGE std::vector; \ + __pragma(warning(pop)) #else - #define UNITTEST_IMPORT - #define UNITTEST_EXPORT - #define UNITTEST_LINKAGE - #define UNITTEST_IMPEXP_TEMPLATE - #define UNITTEST_STDVECTOR_LINKAGE(T) +#define UNITTEST_IMPORT +#define UNITTEST_EXPORT +#define UNITTEST_LINKAGE +#define UNITTEST_IMPEXP_TEMPLATE +#define UNITTEST_STDVECTOR_LINKAGE(T) #endif #ifdef UNITTEST_WIN32 - #define UNITTEST_JMPBUF jmp_buf - #define UNITTEST_SETJMP setjmp - #define UNITTEST_LONGJMP longjmp +#define UNITTEST_JMPBUF jmp_buf +#define UNITTEST_SETJMP setjmp +#define UNITTEST_LONGJMP longjmp #elif defined UNITTEST_POSIX - #define UNITTEST_JMPBUF std::jmp_buf - #define UNITTEST_SETJMP setjmp - #define UNITTEST_LONGJMP std::longjmp +#define UNITTEST_JMPBUF std::jmp_buf +#define UNITTEST_SETJMP setjmp +#define UNITTEST_LONGJMP std::longjmp #endif #endif diff --git a/Release/tests/common/UnitTestpp/src/MemoryOutStream.cpp b/Release/tests/common/UnitTestpp/src/MemoryOutStream.cpp index 3bb529ec92..c16845efb8 100644 --- a/Release/tests/common/UnitTestpp/src/MemoryOutStream.cpp +++ b/Release/tests/common/UnitTestpp/src/MemoryOutStream.cpp @@ -1,108 +1,89 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" #ifdef UNITTEST_MEMORYOUTSTREAM_IS_STD_OSTRINGSTREAM -namespace UnitTest { - +namespace UnitTest +{ MemoryOutStream::MemoryOutStream() {} MemoryOutStream::~MemoryOutStream() {} char const* MemoryOutStream::GetText() const { - m_text = this->str(); - return m_text.c_str(); + m_text = this->str(); + return m_text.c_str(); } void MemoryOutStream::Clear() { - this->str(std::string()); - m_text = this->str(); + this->str(std::string()); + m_text = this->str(); } -} +} // namespace UnitTest #else -namespace UnitTest { - -namespace { - +namespace UnitTest +{ +namespace +{ template void FormatToStream(MemoryOutStream& stream, char const* format, ValueType const& value) { - using namespace std; + using namespace std; char txt[32]; sprintf(txt, format, value); stream << txt; } -int RoundUpToMultipleOfPow2Number (int n, int pow2Number) -{ - return (n + (pow2Number - 1)) & ~(pow2Number - 1); -} +int RoundUpToMultipleOfPow2Number(int n, int pow2Number) { return (n + (pow2Number - 1)) & ~(pow2Number - 1); } -} +} // namespace +MemoryOutStream::MemoryOutStream(int const size) : m_capacity(0), m_buffer(0) { GrowBuffer(size); } -MemoryOutStream::MemoryOutStream(int const size) - : m_capacity (0) - , m_buffer (0) +MemoryOutStream::~MemoryOutStream() { delete[] m_buffer; } -{ - GrowBuffer(size); -} +void MemoryOutStream::Clear() { m_buffer[0] = '\0'; } -MemoryOutStream::~MemoryOutStream() -{ - delete [] m_buffer; -} +char const* MemoryOutStream::GetText() const { return m_buffer; } -void MemoryOutStream::Clear() +MemoryOutStream& MemoryOutStream::operator<<(char const* txt) { - m_buffer[0] = '\0'; -} - -char const* MemoryOutStream::GetText() const -{ - return m_buffer; -} - -MemoryOutStream& MemoryOutStream::operator <<(char const* txt) -{ - using namespace std; + using namespace std; int const bytesLeft = m_capacity - (int)strlen(m_buffer); int const bytesRequired = (int)strlen(txt) + 1; @@ -117,81 +98,77 @@ MemoryOutStream& MemoryOutStream::operator <<(char const* txt) return *this; } -MemoryOutStream& MemoryOutStream::operator <<(int const n) +MemoryOutStream& MemoryOutStream::operator<<(int const n) { FormatToStream(*this, "%i", n); return *this; } -MemoryOutStream& MemoryOutStream::operator <<(long const n) +MemoryOutStream& MemoryOutStream::operator<<(long const n) { FormatToStream(*this, "%li", n); return *this; } -MemoryOutStream& MemoryOutStream::operator <<(unsigned long const n) +MemoryOutStream& MemoryOutStream::operator<<(unsigned long const n) { FormatToStream(*this, "%lu", n); return *this; } -MemoryOutStream& MemoryOutStream::operator <<(long long const n) +MemoryOutStream& MemoryOutStream::operator<<(long long const n) { #ifdef UNITTEST_WIN32 - FormatToStream(*this, "%I64d", n); + FormatToStream(*this, "%I64d", n); #else - FormatToStream(*this, "%lld", n); + FormatToStream(*this, "%lld", n); #endif - return *this; + return *this; } -MemoryOutStream& MemoryOutStream::operator <<(unsigned long long const n) +MemoryOutStream& MemoryOutStream::operator<<(unsigned long long const n) { #ifdef UNITTEST_WIN32 - FormatToStream(*this, "%I64u", n); + FormatToStream(*this, "%I64u", n); #else - FormatToStream(*this, "%llu", n); + FormatToStream(*this, "%llu", n); #endif - return *this; + return *this; } -MemoryOutStream& MemoryOutStream::operator <<(float const f) +MemoryOutStream& MemoryOutStream::operator<<(float const f) { FormatToStream(*this, "%ff", f); - return *this; + return *this; } -MemoryOutStream& MemoryOutStream::operator <<(void const* p) +MemoryOutStream& MemoryOutStream::operator<<(void const* p) { FormatToStream(*this, "%p", p); - return *this; + return *this; } -MemoryOutStream& MemoryOutStream::operator <<(unsigned int const s) +MemoryOutStream& MemoryOutStream::operator<<(unsigned int const s) { FormatToStream(*this, "%u", s); - return *this; -} - -MemoryOutStream& MemoryOutStream::operator <<(double const d) -{ - FormatToStream(*this, "%f", d); - return *this; + return *this; } -int MemoryOutStream::GetCapacity() const +MemoryOutStream& MemoryOutStream::operator<<(double const d) { - return m_capacity; + FormatToStream(*this, "%f", d); + return *this; } +int MemoryOutStream::GetCapacity() const { return m_capacity; } void MemoryOutStream::GrowBuffer(int const desiredCapacity) { int const newCapacity = RoundUpToMultipleOfPow2Number(desiredCapacity, GROW_CHUNK_SIZE); - using namespace std; + using namespace std; char* buffer = new char[newCapacity]; if (m_buffer) @@ -199,12 +176,11 @@ void MemoryOutStream::GrowBuffer(int const desiredCapacity) else strcpy(buffer, ""); - delete [] m_buffer; + delete[] m_buffer; m_buffer = buffer; m_capacity = newCapacity; } -} - +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/MemoryOutStream.h b/Release/tests/common/UnitTestpp/src/MemoryOutStream.h index 640b4867e9..fa11035488 100644 --- a/Release/tests/common/UnitTestpp/src/MemoryOutStream.h +++ b/Release/tests/common/UnitTestpp/src/MemoryOutStream.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_MEMORYOUTSTREAM_H #define UNITTEST_MEMORYOUTSTREAM_H @@ -41,23 +41,22 @@ namespace UnitTest { - class MemoryOutStream : public std::ostringstream { public: UNITTEST_LINKAGE MemoryOutStream(); UNITTEST_LINKAGE ~MemoryOutStream(); - UNITTEST_LINKAGE void Clear(); - UNITTEST_LINKAGE char const* GetText() const; + UNITTEST_LINKAGE void Clear(); + UNITTEST_LINKAGE char const* GetText() const; private: MemoryOutStream(MemoryOutStream const&); - void operator =(MemoryOutStream const&); + void operator=(MemoryOutStream const&); mutable std::string m_text; }; -} +} // namespace UnitTest #else @@ -65,39 +64,41 @@ class MemoryOutStream : public std::ostringstream namespace UnitTest { - class UNITTEST_LINKAGE MemoryOutStream { public: explicit MemoryOutStream(int const size = 256); ~MemoryOutStream(); - void Clear(); + void Clear(); char const* GetText() const; - MemoryOutStream& operator <<(char const* txt); - MemoryOutStream& operator <<(int n); - MemoryOutStream& operator <<(long n); - MemoryOutStream& operator <<(long long n); - MemoryOutStream& operator <<(unsigned long n); - MemoryOutStream& operator <<(unsigned long long n); - MemoryOutStream& operator <<(float f); - MemoryOutStream& operator <<(double d); - MemoryOutStream& operator <<(void const* p); - MemoryOutStream& operator <<(unsigned int s); - - enum { GROW_CHUNK_SIZE = 32 }; + MemoryOutStream& operator<<(char const* txt); + MemoryOutStream& operator<<(int n); + MemoryOutStream& operator<<(long n); + MemoryOutStream& operator<<(long long n); + MemoryOutStream& operator<<(unsigned long n); + MemoryOutStream& operator<<(unsigned long long n); + MemoryOutStream& operator<<(float f); + MemoryOutStream& operator<<(double d); + MemoryOutStream& operator<<(void const* p); + MemoryOutStream& operator<<(unsigned int s); + + enum + { + GROW_CHUNK_SIZE = 32 + }; int GetCapacity() const; private: - void operator= (MemoryOutStream const&); + void operator=(MemoryOutStream const&); void GrowBuffer(int capacity); int m_capacity; char* m_buffer; }; -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/Posix/SignalTranslator.cpp b/Release/tests/common/UnitTestpp/src/Posix/SignalTranslator.cpp index dce9e25efe..0456216922 100644 --- a/Release/tests/common/UnitTestpp/src/Posix/SignalTranslator.cpp +++ b/Release/tests/common/UnitTestpp/src/Posix/SignalTranslator.cpp @@ -1,49 +1,45 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "SignalTranslator.h" -namespace UnitTest { - +namespace UnitTest +{ sigjmp_buf* SignalTranslator::s_jumpTarget = 0; -namespace { - -void SignalHandler(int sig) +namespace { - siglongjmp(*SignalTranslator::s_jumpTarget, sig ); -} - -} +void SignalHandler(int sig) { siglongjmp(*SignalTranslator::s_jumpTarget, sig); } +} // namespace SignalTranslator::SignalTranslator() { @@ -53,25 +49,24 @@ SignalTranslator::SignalTranslator() struct sigaction action; action.sa_flags = 0; action.sa_handler = SignalHandler; - sigemptyset( &action.sa_mask ); + sigemptyset(&action.sa_mask); - sigaction( SIGSEGV, &action, &m_old_SIGSEGV_action ); - sigaction( SIGFPE , &action, &m_old_SIGFPE_action ); - sigaction( SIGTRAP, &action, &m_old_SIGTRAP_action ); - sigaction( SIGBUS , &action, &m_old_SIGBUS_action ); - sigaction( SIGILL , &action, &m_old_SIGBUS_action ); + sigaction(SIGSEGV, &action, &m_old_SIGSEGV_action); + sigaction(SIGFPE, &action, &m_old_SIGFPE_action); + sigaction(SIGTRAP, &action, &m_old_SIGTRAP_action); + sigaction(SIGBUS, &action, &m_old_SIGBUS_action); + sigaction(SIGILL, &action, &m_old_SIGBUS_action); } SignalTranslator::~SignalTranslator() { - sigaction( SIGILL , &m_old_SIGBUS_action , 0 ); - sigaction( SIGBUS , &m_old_SIGBUS_action , 0 ); - sigaction( SIGTRAP, &m_old_SIGTRAP_action, 0 ); - sigaction( SIGFPE , &m_old_SIGFPE_action , 0 ); - sigaction( SIGSEGV, &m_old_SIGSEGV_action, 0 ); + sigaction(SIGILL, &m_old_SIGBUS_action, 0); + sigaction(SIGBUS, &m_old_SIGBUS_action, 0); + sigaction(SIGTRAP, &m_old_SIGTRAP_action, 0); + sigaction(SIGFPE, &m_old_SIGFPE_action, 0); + sigaction(SIGSEGV, &m_old_SIGSEGV_action, 0); s_jumpTarget = m_oldJumpTarget; } - -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/Posix/SignalTranslator.h b/Release/tests/common/UnitTestpp/src/Posix/SignalTranslator.h index b70327075e..bde4e3a168 100644 --- a/Release/tests/common/UnitTestpp/src/Posix/SignalTranslator.h +++ b/Release/tests/common/UnitTestpp/src/Posix/SignalTranslator.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_SIGNALTRANSLATOR_H #define UNITTEST_SIGNALTRANSLATOR_H @@ -35,8 +35,8 @@ #include #include -namespace UnitTest { - +namespace UnitTest +{ class SignalTranslator { public: @@ -56,17 +56,17 @@ class SignalTranslator struct sigaction m_old_SIGALRM_action; }; -#if !defined (__GNUC__) - #define UNITTEST_EXTENSION +#if !defined(__GNUC__) +#define UNITTEST_EXTENSION #else - #define UNITTEST_EXTENSION __extension__ +#define UNITTEST_EXTENSION __extension__ #endif -#define UNITTEST_THROW_SIGNALS_POSIX_ONLY \ - UnitTest::SignalTranslator sig; \ - if (UNITTEST_EXTENSION sigsetjmp(*UnitTest::SignalTranslator::s_jumpTarget, 1) != 0) \ - throw ("Unhandled system exception"); +#define UNITTEST_THROW_SIGNALS_POSIX_ONLY \ + UnitTest::SignalTranslator sig; \ + if (UNITTEST_EXTENSION sigsetjmp(*UnitTest::SignalTranslator::s_jumpTarget, 1) != 0) \ + throw("Unhandled system exception"); -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/Posix/TimeHelpers.cpp b/Release/tests/common/UnitTestpp/src/Posix/TimeHelpers.cpp index d2fea38921..e27127780b 100644 --- a/Release/tests/common/UnitTestpp/src/Posix/TimeHelpers.cpp +++ b/Release/tests/common/UnitTestpp/src/Posix/TimeHelpers.cpp @@ -1,64 +1,59 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "TimeHelpers.h" -#include -namespace UnitTest { +#include +namespace UnitTest +{ Timer::Timer() { m_startTime.tv_sec = 0; m_startTime.tv_usec = 0; } -void Timer::Start() -{ - gettimeofday(&m_startTime, 0); -} +void Timer::Start() { gettimeofday(&m_startTime, 0); } double Timer::GetTimeInMs() const { struct timeval currentTime; gettimeofday(¤tTime, 0); - double const dsecs = currentTime.tv_sec - m_startTime.tv_sec; + double const dsecs = currentTime.tv_sec - m_startTime.tv_sec; double const dus = currentTime.tv_usec - m_startTime.tv_usec; - return (dsecs * 1000.0) + (dus / 1000.0); + return (dsecs * 1000.0) + (dus / 1000.0); } -void TimeHelpers::SleepMs(int ms) -{ - usleep(ms * 1000); -} +void TimeHelpers::SleepMs(int ms) { usleep(ms * 1000); } -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/Posix/TimeHelpers.h b/Release/tests/common/UnitTestpp/src/Posix/TimeHelpers.h index 83c76ec4c3..75d368ef3f 100644 --- a/Release/tests/common/UnitTestpp/src/Posix/TimeHelpers.h +++ b/Release/tests/common/UnitTestpp/src/Posix/TimeHelpers.h @@ -1,59 +1,57 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TIMEHELPERS_H #define UNITTEST_TIMEHELPERS_H #include -namespace UnitTest { - +namespace UnitTest +{ class Timer { public: Timer(); void Start(); - double GetTimeInMs() const; + double GetTimeInMs() const; private: - struct timeval m_startTime; + struct timeval m_startTime; }; - namespace TimeHelpers { - void SleepMs(int ms); +void SleepMs(int ms); } - -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/ReportAssert.cpp b/Release/tests/common/UnitTestpp/src/ReportAssert.cpp index b0810fed84..4dba03d8d0 100644 --- a/Release/tests/common/UnitTestpp/src/ReportAssert.cpp +++ b/Release/tests/common/UnitTestpp/src/ReportAssert.cpp @@ -1,99 +1,94 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" #include "ReportAssert.h" + #include "ReportAssertImpl.h" #ifdef UNITTEST_NO_EXCEPTIONS - #include "ReportAssertImpl.h" +#include "ReportAssertImpl.h" #endif -namespace UnitTest { - +namespace UnitTest +{ namespace { - bool& AssertExpectedFlag() - { - static bool s_assertExpected = false; - return s_assertExpected; - } +bool& AssertExpectedFlag() +{ + static bool s_assertExpected = false; + return s_assertExpected; } +} // namespace UNITTEST_LINKAGE void ReportAssert(char const* description, char const* filename, int lineNumber) { - Detail::ReportAssertEx(CurrentTest::Results(), CurrentTest::Details(), - description, filename, lineNumber); + Detail::ReportAssertEx(CurrentTest::Results(), CurrentTest::Details(), description, filename, lineNumber); } -namespace Detail { - +namespace Detail +{ #ifdef UNITTEST_NO_EXCEPTIONS UNITTEST_JMPBUF* GetAssertJmpBuf() { - static UNITTEST_JMPBUF s_jmpBuf; - return &s_jmpBuf; + static UNITTEST_JMPBUF s_jmpBuf; + return &s_jmpBuf; } #endif UNITTEST_LINKAGE void ReportAssertEx(TestResults* testResults, - const TestDetails* testDetails, - char const* description, - char const* filename, - int lineNumber) + const TestDetails* testDetails, + char const* description, + char const* filename, + int lineNumber) { - if (AssertExpectedFlag() == false) - { - TestDetails assertDetails(testDetails->testName, testDetails->suiteName, filename, lineNumber); - testResults->OnTestFailure(assertDetails, description); - } + if (AssertExpectedFlag() == false) + { + TestDetails assertDetails(testDetails->testName, testDetails->suiteName, filename, lineNumber); + testResults->OnTestFailure(assertDetails, description); + } - ExpectAssert(false); + ExpectAssert(false); #ifndef UNITTEST_NO_EXCEPTIONS - throw AssertException(); + throw AssertException(); #else - UNITTEST_JUMP_TO_ASSERT_JUMP_TARGET(); + UNITTEST_JUMP_TO_ASSERT_JUMP_TARGET(); #endif } -UNITTEST_LINKAGE void ExpectAssert(bool expected) -{ - AssertExpectedFlag() = expected; -} +UNITTEST_LINKAGE void ExpectAssert(bool expected) { AssertExpectedFlag() = expected; } -UNITTEST_LINKAGE bool AssertExpected() -{ - return AssertExpectedFlag(); -} +UNITTEST_LINKAGE bool AssertExpected() { return AssertExpectedFlag(); } -}} +} // namespace Detail +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/ReportAssert.h b/Release/tests/common/UnitTestpp/src/ReportAssert.h index 24c60987f4..858d8a7162 100644 --- a/Release/tests/common/UnitTestpp/src/ReportAssert.h +++ b/Release/tests/common/UnitTestpp/src/ReportAssert.h @@ -1,41 +1,41 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_ASSERT_H #define UNITTEST_ASSERT_H #include "HelperMacros.h" -namespace UnitTest { - +namespace UnitTest +{ UNITTEST_LINKAGE void ReportAssert(char const* description, char const* filename, int lineNumber); } diff --git a/Release/tests/common/UnitTestpp/src/ReportAssertImpl.h b/Release/tests/common/UnitTestpp/src/ReportAssertImpl.h index 4e08845443..d6c1b3fe69 100644 --- a/Release/tests/common/UnitTestpp/src/ReportAssertImpl.h +++ b/Release/tests/common/UnitTestpp/src/ReportAssertImpl.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_REPORTASSERTIMPL_H #define UNITTEST_REPORTASSERTIMPL_H @@ -36,42 +36,41 @@ #include "HelperMacros.h" #ifdef UNITTEST_NO_EXCEPTIONS - #include +#include #endif -namespace UnitTest { - +namespace UnitTest +{ class TestResults; class TestDetails; -namespace Detail { - +namespace Detail +{ UNITTEST_LINKAGE void ExpectAssert(bool expected); -UNITTEST_LINKAGE void ReportAssertEx(TestResults* testResults, - const TestDetails* testDetails, - char const* description, - char const* filename, - int lineNumber); +UNITTEST_LINKAGE void ReportAssertEx(TestResults* testResults, + const TestDetails* testDetails, + char const* description, + char const* filename, + int lineNumber); UNITTEST_LINKAGE bool AssertExpected(); #ifdef UNITTEST_NO_EXCEPTIONS - UNITTEST_LINKAGE UNITTEST_JMPBUF* GetAssertJmpBuf(); +UNITTEST_LINKAGE UNITTEST_JMPBUF* GetAssertJmpBuf(); - #ifdef UNITTEST_WIN32 - #define UNITTEST_SET_ASSERT_JUMP_TARGET() \ - __pragma(warning(push)) __pragma(warning(disable:4611)) \ - UNITTEST_SETJMP(*UnitTest::Detail::GetAssertJmpBuf()) \ - __pragma(warning(pop)) - #else - #define UNITTEST_SET_ASSERT_JUMP_TARGET() UNITTEST_SETJMP(*UnitTest::Detail::GetAssertJmpBuf()) - #endif +#ifdef UNITTEST_WIN32 +#define UNITTEST_SET_ASSERT_JUMP_TARGET() \ + __pragma(warning(push)) __pragma(warning(disable : 4611)) UNITTEST_SETJMP(*UnitTest::Detail::GetAssertJmpBuf()) \ + __pragma(warning(pop)) +#else +#define UNITTEST_SET_ASSERT_JUMP_TARGET() UNITTEST_SETJMP(*UnitTest::Detail::GetAssertJmpBuf()) +#endif - #define UNITTEST_JUMP_TO_ASSERT_JUMP_TARGET() UNITTEST_LONGJMP(*UnitTest::Detail::GetAssertJmpBuf(), 1) +#define UNITTEST_JUMP_TO_ASSERT_JUMP_TARGET() UNITTEST_LONGJMP(*UnitTest::Detail::GetAssertJmpBuf(), 1) #endif -} -} +} // namespace Detail +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/Test.cpp b/Release/tests/common/UnitTestpp/src/Test.cpp index eff9e0490b..70805b6cfa 100644 --- a/Release/tests/common/UnitTestpp/src/Test.cpp +++ b/Release/tests/common/UnitTestpp/src/Test.cpp @@ -1,62 +1,53 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" #include "ExecuteTest.h" #ifdef UNITTEST_POSIX - #include "Posix/SignalTranslator.h" +#include "Posix/SignalTranslator.h" #endif -namespace UnitTest { - +namespace UnitTest +{ Test::Test(char const* testName, char const* suiteName, char const* filename, int lineNumber) - : m_details(testName, suiteName, filename, lineNumber) - , m_nextTest(0) - , m_isMockTest(false) + : m_details(testName, suiteName, filename, lineNumber), m_nextTest(0), m_isMockTest(false) { } -Test::~Test() -{ -} +Test::~Test() {} -void Test::Run() -{ - ExecuteTest(*this, m_details, m_isMockTest); -} +void Test::Run() { ExecuteTest(*this, m_details, m_isMockTest); } -void Test::RunImpl() const -{ -} +void Test::RunImpl() const {} -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/Test.h b/Release/tests/common/UnitTestpp/src/Test.h index 0bd0a280fc..9c73551bee 100644 --- a/Release/tests/common/UnitTestpp/src/Test.h +++ b/Release/tests/common/UnitTestpp/src/Test.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TEST_H #define UNITTEST_TEST_H @@ -35,14 +35,17 @@ #include "TestDetails.h" #include "TestProperties.h" -namespace UnitTest { - +namespace UnitTest +{ class TestResults; class Test { public: - UNITTEST_LINKAGE explicit Test(char const* testName, char const* suiteName = "DefaultSuite", char const* filename = "", int lineNumber = 0); + UNITTEST_LINKAGE explicit Test(char const* testName, + char const* suiteName = "DefaultSuite", + char const* filename = "", + int lineNumber = 0); UNITTEST_LINKAGE virtual ~Test(); UNITTEST_LINKAGE void Run(); @@ -50,16 +53,15 @@ class Test TestDetails const m_details; Test* m_nextTest; - mutable bool m_isMockTest; + mutable bool m_isMockTest; UNITTEST_LINKAGE virtual void RunImpl() const; private: - Test(Test const&); - Test& operator =(Test const&); + Test(Test const&); + Test& operator=(Test const&); }; - -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/TestDetails.cpp b/Release/tests/common/UnitTestpp/src/TestDetails.cpp index 0d47305bc9..a060df7e72 100644 --- a/Release/tests/common/UnitTestpp/src/TestDetails.cpp +++ b/Release/tests/common/UnitTestpp/src/TestDetails.cpp @@ -1,53 +1,46 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" -namespace UnitTest { - +namespace UnitTest +{ TestDetails::TestDetails(char const* testName_, char const* suiteName_, char const* filename_, int lineNumber_) - : suiteName(suiteName_) - , testName(testName_) - , filename(filename_) - , lineNumber(lineNumber_) + : suiteName(suiteName_), testName(testName_), filename(filename_), lineNumber(lineNumber_) { } TestDetails::TestDetails(const TestDetails& details, int lineNumber_) - : suiteName(details.suiteName) - , testName(details.testName) - , filename(details.filename) - , lineNumber(lineNumber_) + : suiteName(details.suiteName), testName(details.testName), filename(details.filename), lineNumber(lineNumber_) { } - -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/TestDetails.h b/Release/tests/common/UnitTestpp/src/TestDetails.h index 1036e5b816..ef88638f13 100644 --- a/Release/tests/common/UnitTestpp/src/TestDetails.h +++ b/Release/tests/common/UnitTestpp/src/TestDetails.h @@ -1,41 +1,41 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TESTDETAILS_H #define UNITTEST_TESTDETAILS_H #include "HelperMacros.h" -namespace UnitTest { - +namespace UnitTest +{ class TestDetails { public: @@ -52,6 +52,6 @@ class TestDetails TestDetails& operator=(TestDetails const&); }; -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/TestList.cpp b/Release/tests/common/UnitTestpp/src/TestList.cpp index 0227066871..ab3eaaab19 100644 --- a/Release/tests/common/UnitTestpp/src/TestList.cpp +++ b/Release/tests/common/UnitTestpp/src/TestList.cpp @@ -1,41 +1,41 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" #include #include -namespace UnitTest { - +namespace UnitTest +{ TestList::TestList() : m_head(nullptr), m_tail(nullptr) {} void TestList::Clear() @@ -59,28 +59,22 @@ void TestList::Add(Test* test) } } -Test* TestList::GetFirst() const -{ - return m_head; -} +Test* TestList::GetFirst() const { return m_head; } -bool TestList::IsEmpty() const -{ - return m_head == nullptr; -} +bool TestList::IsEmpty() const { return m_head == nullptr; } ListAdder::ListAdder(TestList& list, Test* test, ...) { - char * arg; + char* arg; va_list argList; va_start(argList, test); - for(arg = va_arg(argList, char*); arg != nullptr; arg = va_arg(argList, char*)) + for (arg = va_arg(argList, char*); arg != nullptr; arg = va_arg(argList, char*)) { - char * key = arg; + char* key = arg; arg = va_arg(argList, char*); - if(arg != nullptr) + if (arg != nullptr) { - char *value = arg; + char* value = arg; test->m_properties.Add(key, value); } } @@ -104,8 +98,7 @@ ListAdder::ListAdder(TestList& list, Test* test, ...) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #endif -extern "C" -UNITTEST_LINKAGE TestList& GetTestList() +extern "C" UNITTEST_LINKAGE TestList& GetTestList() #if defined(__clang__) #pragma clang diagnostic pop #endif @@ -114,4 +107,4 @@ UNITTEST_LINKAGE TestList& GetTestList() return GLOBAL_TESTLIST; } -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/TestList.h b/Release/tests/common/UnitTestpp/src/TestList.h index 7cf55949fd..686e4469a2 100644 --- a/Release/tests/common/UnitTestpp/src/TestList.h +++ b/Release/tests/common/UnitTestpp/src/TestList.h @@ -1,41 +1,41 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TESTLIST_H #define UNITTEST_TESTLIST_H #include "HelperMacros.h" -namespace UnitTest { - +namespace UnitTest +{ class Test; class TestList @@ -55,14 +55,12 @@ class TestList Test* m_tail; }; - class UNITTEST_LINKAGE ListAdder { public: ListAdder(TestList& list, Test* test, ...); }; -} - +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/TestMacros.h b/Release/tests/common/UnitTestpp/src/TestMacros.h index 5e52cdb855..a73b3f1e07 100644 --- a/Release/tests/common/UnitTestpp/src/TestMacros.h +++ b/Release/tests/common/UnitTestpp/src/TestMacros.h @@ -1,62 +1,62 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TESTMACROS_H #define UNITTEST_TESTMACROS_H #include "../config.h" -#include "TestSuite.h" -#include "TestList.h" +#include "AssertException.h" #include "ExceptionMacros.h" #include "ExecuteTest.h" -#include "AssertException.h" -#include "TestDetails.h" #include "MemoryOutStream.h" +#include "TestDetails.h" +#include "TestList.h" +#include "TestSuite.h" #ifndef UNITTEST_POSIX - #define UNITTEST_THROW_SIGNALS_POSIX_ONLY +#define UNITTEST_THROW_SIGNALS_POSIX_ONLY #else - #include "Posix/SignalTranslator.h" +#include "Posix/SignalTranslator.h" #endif #ifdef TEST - #error UnitTest++ redefines TEST +#error UnitTest++ redefines TEST #endif #ifdef TEST_EX - #error UnitTest++ redefines TEST_EX +#error UnitTest++ redefines TEST_EX #endif #ifdef TEST_FIXTURE_EX - #error UnitTest++ redefines TEST_FIXTURE_EX +#error UnitTest++ redefines TEST_FIXTURE_EX #endif #ifndef CREATED_GET_TEST_LIST @@ -76,54 +76,54 @@ namespace UnitTest #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #endif - extern "C" - _DLL_EXPORT TestList& __cdecl GetTestList(); +extern "C" _DLL_EXPORT TestList& __cdecl GetTestList(); #if defined(__clang__) #pragma clang diagnostic pop #endif -} +} // namespace UnitTest #endif -#define SUITE(Name) \ - namespace Suite##Name { \ - namespace UnitTestSuite { \ - inline char const* GetSuiteName () { \ - return #Name ; \ - } \ - } \ - } \ - namespace Suite##Name +#define SUITE(Name) \ + namespace Suite##Name \ + { \ + namespace UnitTestSuite \ + { \ + inline char const* GetSuiteName() { return #Name; } \ + } \ + } \ + namespace Suite##Name #ifdef _WIN32 -#define TEST_EX(Name, List, ...) \ - class Test##Name : public UnitTest::Test \ - { \ - public: \ - Test##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ - private: \ - virtual void RunImpl() const; \ - } test##Name##Instance; \ - \ - UnitTest::ListAdder adder##Name (List, &test##Name##Instance, __VA_ARGS__, NULL); \ - \ +#define TEST_EX(Name, List, ...) \ + class Test##Name : public UnitTest::Test \ + { \ + public: \ + Test##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ + \ + private: \ + virtual void RunImpl() const; \ + } test##Name##Instance; \ + \ + UnitTest::ListAdder adder##Name(List, &test##Name##Instance, __VA_ARGS__, NULL); \ + \ void Test##Name::RunImpl() const #else -#define TEST_EX(Name, List, ...) \ - class Test##Name : public UnitTest::Test \ - { \ - public: \ - Test##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ - private: \ - virtual void RunImpl() const; \ - } test##Name##Instance; \ - \ - UnitTest::ListAdder adder##Name (List, &test##Name##Instance, ##__VA_ARGS__, nullptr); \ - \ +#define TEST_EX(Name, List, ...) \ + class Test##Name : public UnitTest::Test \ + { \ + public: \ + Test##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ + \ + private: \ + virtual void RunImpl() const; \ + } test##Name##Instance; \ + \ + UnitTest::ListAdder adder##Name(List, &test##Name##Instance, ##__VA_ARGS__, nullptr); \ + \ void Test##Name::RunImpl() const #endif - #ifdef _WIN32 #define TEST(Name, ...) TEST_EX(Name, UnitTest::GetTestList(), __VA_ARGS__) #else @@ -131,118 +131,114 @@ namespace UnitTest #endif #ifdef _WIN32 -#define TEST_FIXTURE_EX(Fixture, Name, List, ...) \ - class Fixture##Name##Helper : public Fixture \ - { \ - public: \ - explicit Fixture##Name##Helper(UnitTest::TestDetails const& details) : m_details(details) {} \ - void RunImpl(); \ - UnitTest::TestDetails const& m_details; \ - private: \ - Fixture##Name##Helper(Fixture##Name##Helper const&); \ - Fixture##Name##Helper& operator =(Fixture##Name##Helper const&); \ - }; \ - \ - class Test##Fixture##Name : public UnitTest::Test \ - { \ - public: \ - Test##Fixture##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ - private: \ - virtual void RunImpl() const; \ - } test##Fixture##Name##Instance; \ - \ - UnitTest::ListAdder adder##Fixture##Name (List, &test##Fixture##Name##Instance, __VA_ARGS__, NULL); \ - \ - void Test##Fixture##Name::RunImpl() const \ - { \ - volatile bool ctorOk = false; \ - UT_TRY \ - ({ \ - Fixture##Name##Helper fixtureHelper(m_details); \ - ctorOk = true; \ - UnitTest::ExecuteTest(fixtureHelper, m_details, false); \ - }) \ - UT_CATCH (UnitTest::AssertException, e, \ - { \ - (void)e; \ - }) \ - UT_CATCH (std::exception, e, \ - { \ - UnitTest::MemoryOutStream stream; \ - stream << "Unhandled exception: " << e.what(); \ - UnitTest::CurrentTest::Results()->OnTestFailure(m_details, stream.GetText()); \ - }) \ - UT_CATCH_ALL \ - ({ \ - if (ctorOk) \ - { \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ - "Unhandled exception while destroying fixture " #Fixture); \ - } \ - else \ - { \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ - "Unhandled exception while constructing fixture " #Fixture); \ - } \ - }) \ - } \ +#define TEST_FIXTURE_EX(Fixture, Name, List, ...) \ + class Fixture##Name##Helper : public Fixture \ + { \ + public: \ + explicit Fixture##Name##Helper(UnitTest::TestDetails const& details) : m_details(details) {} \ + void RunImpl(); \ + UnitTest::TestDetails const& m_details; \ + \ + private: \ + Fixture##Name##Helper(Fixture##Name##Helper const&); \ + Fixture##Name##Helper& operator=(Fixture##Name##Helper const&); \ + }; \ + \ + class Test##Fixture##Name : public UnitTest::Test \ + { \ + public: \ + Test##Fixture##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ + \ + private: \ + virtual void RunImpl() const; \ + } test##Fixture##Name##Instance; \ + \ + UnitTest::ListAdder adder##Fixture##Name(List, &test##Fixture##Name##Instance, __VA_ARGS__, NULL); \ + \ + void Test##Fixture##Name::RunImpl() const \ + { \ + volatile bool ctorOk = false; \ + UT_TRY({ \ + Fixture##Name##Helper fixtureHelper(m_details); \ + ctorOk = true; \ + UnitTest::ExecuteTest(fixtureHelper, m_details, false); \ + }) \ + UT_CATCH(UnitTest::AssertException, e, { (void)e; }) \ + UT_CATCH(std::exception, e, { \ + UnitTest::MemoryOutStream stream; \ + stream << "Unhandled exception: " << e.what(); \ + UnitTest::CurrentTest::Results()->OnTestFailure(m_details, stream.GetText()); \ + }) \ + UT_CATCH_ALL({ \ + if (ctorOk) \ + { \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception while destroying fixture " #Fixture); \ + } \ + else \ + { \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception while constructing fixture " #Fixture); \ + } \ + }) \ + } \ void Fixture##Name##Helper::RunImpl() #else -#define TEST_FIXTURE_EX(Fixture, Name, List, ...) \ - class Fixture##Name##Helper : public Fixture \ - { \ - public: \ - explicit Fixture##Name##Helper(UnitTest::TestDetails const& details) : m_details(details) {} \ - void RunImpl(); \ - UnitTest::TestDetails const& m_details; \ - private: \ - Fixture##Name##Helper(Fixture##Name##Helper const&); \ - Fixture##Name##Helper& operator =(Fixture##Name##Helper const&); \ - }; \ - \ - class Test##Fixture##Name : public UnitTest::Test \ - { \ - public: \ - Test##Fixture##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ - private: \ - virtual void RunImpl() const; \ - } test##Fixture##Name##Instance; \ - \ - UnitTest::ListAdder adder##Fixture##Name (List, &test##Fixture##Name##Instance, ##__VA_ARGS__, NULL); \ - \ - void Test##Fixture##Name::RunImpl() const \ - { \ - volatile bool ctorOk = false; \ - UT_TRY \ - ({ \ - Fixture##Name##Helper fixtureHelper(m_details); \ - ctorOk = true; \ - UnitTest::ExecuteTest(fixtureHelper, m_details, false); \ - }) \ - UT_CATCH (UnitTest::AssertException, e, \ - { \ - (void)e; \ - }) \ - UT_CATCH (std::exception, e, \ - { \ - UnitTest::MemoryOutStream stream; \ - stream << "Unhandled exception: " << e.what(); \ - UnitTest::CurrentTest::Results()->OnTestFailure(m_details, stream.GetText()); \ - }) \ - UT_CATCH_ALL \ - ({ \ - if (ctorOk) \ - { \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ - "Unhandled exception while destroying fixture " #Fixture); \ - } \ - else \ - { \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ - "Unhandled exception while constructing fixture " #Fixture); \ - } \ - }) \ - } \ +#define TEST_FIXTURE_EX(Fixture, Name, List, ...) \ + class Fixture##Name##Helper : public Fixture \ + { \ + public: \ + explicit Fixture##Name##Helper(UnitTest::TestDetails const& details) : m_details(details) {} \ + void RunImpl(); \ + UnitTest::TestDetails const& m_details; \ + \ + private: \ + Fixture##Name##Helper(Fixture##Name##Helper const&); \ + Fixture##Name##Helper& operator=(Fixture##Name##Helper const&); \ + }; \ + \ + class Test##Fixture##Name : public UnitTest::Test \ + { \ + public: \ + Test##Fixture##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ + \ + private: \ + virtual void RunImpl() const; \ + } test##Fixture##Name##Instance; \ + \ + UnitTest::ListAdder adder##Fixture##Name(List, &test##Fixture##Name##Instance, ##__VA_ARGS__, NULL); \ + \ + void Test##Fixture##Name::RunImpl() const \ + { \ + volatile bool ctorOk = false; \ + UT_TRY({ \ + Fixture##Name##Helper fixtureHelper(m_details); \ + ctorOk = true; \ + UnitTest::ExecuteTest(fixtureHelper, m_details, false); \ + }) \ + UT_CATCH(UnitTest::AssertException, e, { (void)e; }) \ + UT_CATCH(std::exception, e, { \ + UnitTest::MemoryOutStream stream; \ + stream << "Unhandled exception: " << e.what(); \ + UnitTest::CurrentTest::Results()->OnTestFailure(m_details, stream.GetText()); \ + }) \ + UT_CATCH_ALL({ \ + if (ctorOk) \ + { \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception while destroying fixture " #Fixture); \ + } \ + else \ + { \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception while constructing fixture " #Fixture); \ + } \ + }) \ + } \ void Fixture##Name##Helper::RunImpl() #endif @@ -252,5 +248,4 @@ namespace UnitTest #define TEST_FIXTURE(Fixture, Name, ...) TEST_FIXTURE_EX(Fixture, Name, UnitTest::GetTestList(), ##__VA_ARGS__) #endif - #endif diff --git a/Release/tests/common/UnitTestpp/src/TestProperties.h b/Release/tests/common/UnitTestpp/src/TestProperties.h index 9f731d176e..da15a1a026 100644 --- a/Release/tests/common/UnitTestpp/src/TestProperties.h +++ b/Release/tests/common/UnitTestpp/src/TestProperties.h @@ -1,97 +1,84 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TEST_PROPERTIES_H #define UNITTEST_TEST_PROPERTIES_H -#include #include #include +#include namespace UnitTest { - // Simple key value pairs. - class TestProperties - { - public: - - TestProperties() {} +// Simple key value pairs. +class TestProperties +{ +public: + TestProperties() {} - void Add(const std::string &key, const std::string &value) + void Add(const std::string& key, const std::string& value) + { + if (!Has(key)) { - if( !Has( key ) ) - { - m_properties[key] = value; - } - else - { - m_properties[key] += ";"; - m_properties[key] += value; - } - } - - bool Has(const std::string &key) const - { - return m_properties.find(key) != m_properties.end(); + m_properties[key] = value; } - - const std::string &Get(const std::string &key) const + else { - if(!Has(key)) - { - throw std::invalid_argument("Error: property is not found"); - } - return m_properties.find(key)->second; + m_properties[key] += ";"; + m_properties[key] += value; } + } - const std::string &operator[](const std::string &key) const - { - return Get(key); - } + bool Has(const std::string& key) const { return m_properties.find(key) != m_properties.end(); } - std::map::const_iterator begin() const + const std::string& Get(const std::string& key) const + { + if (!Has(key)) { - return m_properties.begin(); + throw std::invalid_argument("Error: property is not found"); } + return m_properties.find(key)->second; + } - std::map::const_iterator end() const - { - return m_properties.end(); - } + const std::string& operator[](const std::string& key) const { return Get(key); } + + std::map::const_iterator begin() const { return m_properties.begin(); } + + std::map::const_iterator end() const { return m_properties.end(); } - private: - std::map m_properties; - TestProperties(const TestProperties &); - TestProperties &operator=(const TestProperties &); - }; +private: + std::map m_properties; + TestProperties(const TestProperties&); + TestProperties& operator=(const TestProperties&); +}; } // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/TestReporter.cpp b/Release/tests/common/UnitTestpp/src/TestReporter.cpp index b2e42982ee..13fffbc002 100644 --- a/Release/tests/common/UnitTestpp/src/TestReporter.cpp +++ b/Release/tests/common/UnitTestpp/src/TestReporter.cpp @@ -1,44 +1,40 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" -namespace UnitTest { - -TestReporter::TestReporter() +namespace UnitTest { -} +TestReporter::TestReporter() {} -TestReporter::~TestReporter() -{ -} +TestReporter::~TestReporter() {} -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/TestReporter.h b/Release/tests/common/UnitTestpp/src/TestReporter.h index f3637643bb..bb455a6f4b 100644 --- a/Release/tests/common/UnitTestpp/src/TestReporter.h +++ b/Release/tests/common/UnitTestpp/src/TestReporter.h @@ -1,41 +1,41 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TESTREPORTER_H #define UNITTEST_TESTREPORTER_H #include "HelperMacros.h" -namespace UnitTest { - +namespace UnitTest +{ class TestDetails; class TestReporter @@ -47,8 +47,11 @@ class TestReporter UNITTEST_LINKAGE virtual void ReportTestStart(TestDetails const& test) = 0; UNITTEST_LINKAGE virtual void ReportFailure(TestDetails const& test, char const* failure) = 0; UNITTEST_LINKAGE virtual void ReportTestFinish(TestDetails const& test, bool passed, float secondsElapsed) = 0; - UNITTEST_LINKAGE virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) = 0; + UNITTEST_LINKAGE virtual void ReportSummary(int totalTestCount, + int failedTestCount, + int failureCount, + float secondsElapsed) = 0; }; -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/TestReporterStdout.cpp b/Release/tests/common/UnitTestpp/src/TestReporterStdout.cpp index a6e9b25b08..04f210c1c2 100644 --- a/Release/tests/common/UnitTestpp/src/TestReporterStdout.cpp +++ b/Release/tests/common/UnitTestpp/src/TestReporterStdout.cpp @@ -1,45 +1,48 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" -#include + #include +#include // cstdio doesn't pull in namespace std on VC6, so we do it here. #if defined(UNITTEST_WIN32) && (_MSC_VER == 1200) - namespace std {} +namespace std +{ +} #endif -namespace UnitTest { - +namespace UnitTest +{ // Function to work around outputing to the console when under WinRT. static void PrintfWrapper(const char* format, ...) { @@ -112,34 +115,31 @@ void TestReporterStdout::ReportFailure(TestDetails const& details, char const* f void TestReporterStdout::ReportTestStart(TestDetails const& test) { - const char * format = "Starting test case %s:%s...\n"; + const char* format = "Starting test case %s:%s...\n"; PrintfWrapper(format, test.suiteName, test.testName); std::fflush(stdout); } void TestReporterStdout::ReportTestFinish(TestDetails const& test, bool passed, float) { - if(passed) + if (passed) { - const char * format = "Test case %s:%s "; + const char* format = "Test case %s:%s "; PrintfWrapper(format, test.suiteName, test.testName); ChangeConsoleTextColorToGreen(); - PrintfWrapper("PASSED\n"); + PrintfWrapper("PASSED\n"); ChangeConsoleTextColorToGrey(); } else { ChangeConsoleTextColorToRed(); - const char * format = "Test case %s:%s FAILED\n"; - PrintfWrapper(format, test.suiteName, test.testName); + const char* format = "Test case %s:%s FAILED\n"; + PrintfWrapper(format, test.suiteName, test.testName); ChangeConsoleTextColorToGrey(); } std::fflush(stdout); } -void TestReporterStdout::ReportSummary(int const, int const, - int const, float) -{ -} +void TestReporterStdout::ReportSummary(int const, int const, int const, float) {} -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/TestReporterStdout.h b/Release/tests/common/UnitTestpp/src/TestReporterStdout.h index 253306b8be..2e48e74a38 100644 --- a/Release/tests/common/UnitTestpp/src/TestReporterStdout.h +++ b/Release/tests/common/UnitTestpp/src/TestReporterStdout.h @@ -1,50 +1,53 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TESTREPORTERSTDOUT_H #define UNITTEST_TESTREPORTERSTDOUT_H #include "TestReporter.h" -namespace UnitTest { - +namespace UnitTest +{ class TestReporterStdout : public TestReporter { private: UNITTEST_LINKAGE virtual void ReportTestStart(TestDetails const& test); UNITTEST_LINKAGE virtual void ReportFailure(TestDetails const& test, char const* failure); UNITTEST_LINKAGE virtual void ReportTestFinish(TestDetails const& test, bool passed, float secondsElapsed); - UNITTEST_LINKAGE virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); + UNITTEST_LINKAGE virtual void ReportSummary(int totalTestCount, + int failedTestCount, + int failureCount, + float secondsElapsed); }; -} +} // namespace UnitTest -#endif +#endif diff --git a/Release/tests/common/UnitTestpp/src/TestResults.cpp b/Release/tests/common/UnitTestpp/src/TestResults.cpp index 37f03181ca..b65611c217 100644 --- a/Release/tests/common/UnitTestpp/src/TestResults.cpp +++ b/Release/tests/common/UnitTestpp/src/TestResults.cpp @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" @@ -35,8 +35,8 @@ #include "signal.h" #endif -namespace UnitTest { - +namespace UnitTest +{ TestResults::TestResults(TestReporter* testReporter, bool breakOnError) : m_testReporter(testReporter) , m_totalTestCount(0) @@ -51,8 +51,7 @@ void TestResults::OnTestStart(TestDetails const& test) { ++m_totalTestCount; m_currentTestFailed = false; - if (m_testReporter) - m_testReporter->ReportTestStart(test); + if (m_testReporter) m_testReporter->ReportTestStart(test); } #ifdef WIN32 @@ -77,7 +76,7 @@ void TestResults::OnTestFailure(TestDetails const& test, char const* failure) if (m_testReporter) { m_testReporter->ReportFailure(test, failure); - if(m_breakOnError) + if (m_breakOnError) { DEBUG_BREAK(); } @@ -86,28 +85,15 @@ void TestResults::OnTestFailure(TestDetails const& test, char const* failure) void TestResults::OnTestFinish(TestDetails const& test, float secondsElapsed) { - if (m_testReporter) - m_testReporter->ReportTestFinish(test, !m_currentTestFailed, secondsElapsed); + if (m_testReporter) m_testReporter->ReportTestFinish(test, !m_currentTestFailed, secondsElapsed); } -int TestResults::GetTotalTestCount() const -{ - return m_totalTestCount; -} +int TestResults::GetTotalTestCount() const { return m_totalTestCount; } -int TestResults::GetFailedTestCount() const -{ - return m_failedTestCount; -} +int TestResults::GetFailedTestCount() const { return m_failedTestCount; } -int TestResults::GetFailureCount() const -{ - return m_failureCount; -} +int TestResults::GetFailureCount() const { return m_failureCount; } -const std::vector & TestResults::GetFailedTests() const -{ - return m_failedTests; -} +const std::vector& TestResults::GetFailedTests() const { return m_failedTests; } -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/TestResults.h b/Release/tests/common/UnitTestpp/src/TestResults.h index 01a6dd96af..6a88b1c4e2 100644 --- a/Release/tests/common/UnitTestpp/src/TestResults.h +++ b/Release/tests/common/UnitTestpp/src/TestResults.h @@ -1,43 +1,43 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TESTRESULTS_H #define UNITTEST_TESTRESULTS_H #include "HelperMacros.h" -#include #include +#include -namespace UnitTest { - +namespace UnitTest +{ class TestReporter; class TestDetails; @@ -54,7 +54,7 @@ class TestResults UNITTEST_LINKAGE int GetFailedTestCount() const; UNITTEST_LINKAGE int GetFailureCount() const; - UNITTEST_LINKAGE const std::vector & GetFailedTests() const; + UNITTEST_LINKAGE const std::vector& GetFailedTests() const; private: TestReporter* m_testReporter; @@ -68,9 +68,9 @@ class TestResults std::vector m_failedTests; TestResults(TestResults const&); - TestResults& operator =(TestResults const&); + TestResults& operator=(TestResults const&); }; -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/TestRunner.cpp b/Release/tests/common/UnitTestpp/src/TestRunner.cpp index 3f523cf9a8..807a0e3b10 100644 --- a/Release/tests/common/UnitTestpp/src/TestRunner.cpp +++ b/Release/tests/common/UnitTestpp/src/TestRunner.cpp @@ -1,39 +1,40 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" -#include "TestMacros.h" #include "TestRunner.h" +#include "TestMacros.h" + #if _MSC_VER == 1600 #include #include @@ -42,24 +43,23 @@ #endif #if (defined(ANDROID) || defined(__ANDROID__)) -#include #include +#include #endif #include #if (defined(ANDROID) || defined(__ANDROID__)) -namespace crossplat { +namespace crossplat +{ extern std::atomic JVM; } #endif -namespace UnitTest { - +namespace UnitTest +{ TestRunner::TestRunner(TestReporter& reporter, bool breakOnError) - : m_reporter(&reporter) - , m_result(new TestResults(&reporter, breakOnError)) - , m_timer(new Timer) + : m_reporter(&reporter), m_result(new TestResults(&reporter, breakOnError)), m_timer(new Timer) { m_timer->Start(); } @@ -70,18 +70,13 @@ TestRunner::~TestRunner() delete m_timer; } -TestResults* TestRunner::GetTestResults() -{ - return m_result; -} +TestResults* TestRunner::GetTestResults() { return m_result; } int TestRunner::Finish() const { float const secondsElapsed = static_cast(m_timer->GetTimeInMs() / 1000.0); - m_reporter->ReportSummary(m_result->GetTotalTestCount(), - m_result->GetFailedTestCount(), - m_result->GetFailureCount(), - secondsElapsed); + m_reporter->ReportSummary( + m_result->GetTotalTestCount(), m_result->GetFailedTestCount(), m_result->GetFailureCount(), secondsElapsed); return m_result->GetFailureCount(); } @@ -99,6 +94,7 @@ class TestRunnerAgent : public Concurrency::agent { public: TestRunnerAgent(std::tr1::function func) : m_func(func) {} + protected: void run() { @@ -107,6 +103,7 @@ class TestRunnerAgent : public Concurrency::agent Concurrency::Context::Oversubscribe(false); done(); } + private: std::tr1::function m_func; }; @@ -120,12 +117,12 @@ int TestRunner::GetTestTimeout(Test* const curTest, int const defaultTestTimeInM { std::stringstream timeoutstream; int timeout = defaultTestTimeInMs; - if(UnitTest::GlobalSettings::Has("testtimeout")) + if (UnitTest::GlobalSettings::Has("testtimeout")) { timeoutstream << UnitTest::GlobalSettings::Get("testtimeout"); timeoutstream >> timeout; } - else if(curTest->m_properties.Has("Timeout")) + else if (curTest->m_properties.Has("Timeout")) { timeoutstream << curTest->m_properties.Get("Timeout"); timeoutstream >> timeout; @@ -133,11 +130,9 @@ int TestRunner::GetTestTimeout(Test* const curTest, int const defaultTestTimeInM return timeout; } - void TestRunner::RunTest(TestResults* const result, Test* const curTest, int const defaultTestTimeInMs) const { - if (curTest->m_isMockTest == false) - CurrentTest::SetResults(result); + if (curTest->m_isMockTest == false) CurrentTest::SetResults(result); int maxTestTimeInMs = GetTestTimeout(curTest, defaultTestTimeInMs); @@ -146,27 +141,23 @@ void TestRunner::RunTest(TestResults* const result, Test* const curTest, int con result->OnTestStart(curTest->m_details); - if(maxTestTimeInMs > 0) + if (maxTestTimeInMs > 0) { bool timedOut = false; #if _MSC_VER == 1600 - TestRunnerAgent testRunnerAgent([&]() - { - curTest->Run(); - }); + TestRunnerAgent testRunnerAgent([&]() { curTest->Run(); }); testRunnerAgent.start(); try { Concurrency::agent::wait(&testRunnerAgent, maxTestTimeInMs); } - catch(const Concurrency::operation_timed_out &) + catch (const Concurrency::operation_timed_out&) { timedOut = true; } #else // Timed wait requires async execution. - auto testRunnerFuture = std::async(std::launch::async, [&]() - { + auto testRunnerFuture = std::async(std::launch::async, [&]() { #if (defined(ANDROID) || defined(__ANDROID__)) JNIEnv* env = nullptr; auto result = crossplat::JVM.load()->AttachCurrentThread(&env, nullptr); @@ -174,20 +165,19 @@ void TestRunner::RunTest(TestResults* const result, Test* const curTest, int con { throw std::runtime_error("Could not attach to JVM"); } - BOOST_SCOPE_EXIT(void) - { - crossplat::JVM.load()->DetachCurrentThread(); - } BOOST_SCOPE_EXIT_END + BOOST_SCOPE_EXIT(void) { crossplat::JVM.load()->DetachCurrentThread(); } + BOOST_SCOPE_EXIT_END #endif curTest->Run(); }); - std::chrono::system_clock::time_point totalTime = std::chrono::system_clock::now() + std::chrono::milliseconds(maxTestTimeInMs); - if(testRunnerFuture.wait_until(totalTime) == std::future_status::timeout) + std::chrono::system_clock::time_point totalTime = + std::chrono::system_clock::now() + std::chrono::milliseconds(maxTestTimeInMs); + if (testRunnerFuture.wait_until(totalTime) == std::future_status::timeout) { timedOut = true; } #endif - if(timedOut) + if (timedOut) { MemoryOutStream stream; stream << "Test case timed out and is hung. Aborting all remaining test cases. "; @@ -203,7 +193,7 @@ void TestRunner::RunTest(TestResults* const result, Test* const curTest, int con } double const testTimeInMs = testTimer.GetTimeInMs(); - result->OnTestFinish(curTest->m_details, static_cast< float >(testTimeInMs / 1000.0)); + result->OnTestFinish(curTest->m_details, static_cast(testTimeInMs / 1000.0)); } -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/TestRunner.h b/Release/tests/common/UnitTestpp/src/TestRunner.h index f275f6bd06..160b36ab97 100644 --- a/Release/tests/common/UnitTestpp/src/TestRunner.h +++ b/Release/tests/common/UnitTestpp/src/TestRunner.h @@ -1,108 +1,107 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TESTRUNNER_H #define UNITTEST_TESTRUNNER_H -#include "Test.h" -#include "TestList.h" #include "CurrentTest.h" #include "GlobalSettings.h" +#include "Test.h" +#include "TestList.h" -namespace UnitTest { - +namespace UnitTest +{ class TestReporter; class TestResults; class Timer; struct True { - bool operator()(const Test* const) const - { - return true; - } + bool operator()(const Test* const) const { return true; } }; class TestRunner { public: - UNITTEST_LINKAGE explicit TestRunner(TestReporter& reporter, bool breakOnError = false); - UNITTEST_LINKAGE ~TestRunner(); + UNITTEST_LINKAGE explicit TestRunner(TestReporter& reporter, bool breakOnError = false); + UNITTEST_LINKAGE ~TestRunner(); - template - int RunTestsIf(TestList const& list, const Predicate& predicate, int defaultTestTimeInMs) const - { + template + int RunTestsIf(TestList const& list, const Predicate& predicate, int defaultTestTimeInMs) const + { return RunTestsIf(list, nullptr, predicate, defaultTestTimeInMs); } - template - int RunTestsIf(TestList const& list, char const* suiteName, - const Predicate& predicate, int defaultTestTimeInMs) const - { - Test* curTest = list.GetFirst(); + template + int RunTestsIf(TestList const& list, + char const* suiteName, + const Predicate& predicate, + int defaultTestTimeInMs) const + { + Test* curTest = list.GetFirst(); - while (curTest != 0) - { - if (IsTestInSuite(curTest, suiteName) && predicate(curTest)) - RunTest(m_result, curTest, defaultTestTimeInMs); + while (curTest != 0) + { + if (IsTestInSuite(curTest, suiteName) && predicate(curTest)) + RunTest(m_result, curTest, defaultTestTimeInMs); - curTest = curTest->m_nextTest; - } + curTest = curTest->m_nextTest; + } - return Finish(); - } + return Finish(); + } int RunTests(TestList const& list, char const* suiteName, int defaultTestTimeInMs) const { return RunTestsIf(list, suiteName, True(), defaultTestTimeInMs); } - int RunTests(TestList const& list, int defaultTestTimeInMs) const + int RunTests(TestList const& list, int defaultTestTimeInMs) const { return RunTestsIf(list, nullptr, True(), defaultTestTimeInMs); } - UNITTEST_LINKAGE TestResults* GetTestResults(); + UNITTEST_LINKAGE TestResults* GetTestResults(); private: - TestReporter* m_reporter; - TestResults* m_result; - Timer* m_timer; + TestReporter* m_reporter; + TestResults* m_result; + Timer* m_timer; int GetTestTimeout(Test* const curTest, int const defaultTestTimeInMs) const; - UNITTEST_LINKAGE int Finish() const; - UNITTEST_LINKAGE bool IsTestInSuite(const Test* const curTest, char const* suiteName) const; - UNITTEST_LINKAGE void RunTest(TestResults* const result, Test* const curTest, int const defaultTestTimeInMs) const; + UNITTEST_LINKAGE int Finish() const; + UNITTEST_LINKAGE bool IsTestInSuite(const Test* const curTest, char const* suiteName) const; + UNITTEST_LINKAGE void RunTest(TestResults* const result, Test* const curTest, int const defaultTestTimeInMs) const; }; -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/TestSuite.h b/Release/tests/common/UnitTestpp/src/TestSuite.h index 55aea6e777..877b8fe8c4 100644 --- a/Release/tests/common/UnitTestpp/src/TestSuite.h +++ b/Release/tests/common/UnitTestpp/src/TestSuite.h @@ -1,43 +1,40 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TESTSUITE_H #define UNITTEST_TESTSUITE_H -namespace UnitTestSuite +namespace UnitTestSuite { - inline char const* GetSuiteName () - { - return "DefaultSuite"; - } -} +inline char const* GetSuiteName() { return "DefaultSuite"; } +} // namespace UnitTestSuite #endif diff --git a/Release/tests/common/UnitTestpp/src/TimeHelpers.h b/Release/tests/common/UnitTestpp/src/TimeHelpers.h index ee93a816ce..a9d964af0c 100644 --- a/Release/tests/common/UnitTestpp/src/TimeHelpers.h +++ b/Release/tests/common/UnitTestpp/src/TimeHelpers.h @@ -1,38 +1,38 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "../config.h" #if defined UNITTEST_POSIX - #include "Posix/TimeHelpers.h" +#include "Posix/TimeHelpers.h" #else - #include "Win32/TimeHelpers.h" +#include "Win32/TimeHelpers.h" #endif diff --git a/Release/tests/common/UnitTestpp/src/Win32/TimeHelpers.cpp b/Release/tests/common/UnitTestpp/src/Win32/TimeHelpers.cpp index 4996cb09a7..e20bb66c1b 100644 --- a/Release/tests/common/UnitTestpp/src/Win32/TimeHelpers.cpp +++ b/Release/tests/common/UnitTestpp/src/Win32/TimeHelpers.cpp @@ -1,77 +1,69 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" -namespace UnitTest { - -Timer::Timer() - : m_threadHandle(::GetCurrentThread()) - , m_startTime(0) +namespace UnitTest +{ +Timer::Timer() : m_threadHandle(::GetCurrentThread()), m_startTime(0) { #if defined(UNITTEST_WIN32) && (_MSC_VER == 1200) // VC6 doesn't have DWORD_PTR - typedef unsigned long DWORD_PTR; + typedef unsigned long DWORD_PTR; #endif - DWORD_PTR systemMask; - ::GetProcessAffinityMask(GetCurrentProcess(), &m_processAffinityMask, &systemMask); - ::SetThreadAffinityMask(m_threadHandle, 1); - ::QueryPerformanceFrequency(reinterpret_cast< LARGE_INTEGER* >(&m_frequency)); - ::SetThreadAffinityMask(m_threadHandle, m_processAffinityMask); + DWORD_PTR systemMask; + ::GetProcessAffinityMask(GetCurrentProcess(), &m_processAffinityMask, &systemMask); + ::SetThreadAffinityMask(m_threadHandle, 1); + ::QueryPerformanceFrequency(reinterpret_cast(&m_frequency)); + ::SetThreadAffinityMask(m_threadHandle, m_processAffinityMask); } -void Timer::Start() -{ - m_startTime = GetTime(); -} +void Timer::Start() { m_startTime = GetTime(); } double Timer::GetTimeInMs() const { - __int64 const elapsedTime = GetTime() - m_startTime; - double const seconds = double(elapsedTime) / double(m_frequency); - return seconds * 1000.0; + __int64 const elapsedTime = GetTime() - m_startTime; + double const seconds = double(elapsedTime) / double(m_frequency); + return seconds * 1000.0; } __int64 Timer::GetTime() const { - LARGE_INTEGER curTime; - ::SetThreadAffinityMask(m_threadHandle, 1); - ::QueryPerformanceCounter(&curTime); - ::SetThreadAffinityMask(m_threadHandle, m_processAffinityMask); - return curTime.QuadPart; + LARGE_INTEGER curTime; + ::SetThreadAffinityMask(m_threadHandle, 1); + ::QueryPerformanceCounter(&curTime); + ::SetThreadAffinityMask(m_threadHandle, m_processAffinityMask); + return curTime.QuadPart; } -void TimeHelpers::SleepMs(int ms) -{ - ::Sleep(ms); -} +void TimeHelpers::SleepMs(int ms) { ::Sleep(ms); } -} +} // namespace UnitTest diff --git a/Release/tests/common/UnitTestpp/src/Win32/TimeHelpers.h b/Release/tests/common/UnitTestpp/src/Win32/TimeHelpers.h index c1b5b09394..7c8edb6da6 100644 --- a/Release/tests/common/UnitTestpp/src/Win32/TimeHelpers.h +++ b/Release/tests/common/UnitTestpp/src/Win32/TimeHelpers.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_TIMEHELPERS_H #define UNITTEST_TIMEHELPERS_H @@ -36,19 +36,19 @@ #include "../HelperMacros.h" #ifdef UNITTEST_MINGW - #ifndef __int64 - #define __int64 long long - #endif +#ifndef __int64 +#define __int64 long long +#endif #endif -namespace UnitTest { - +namespace UnitTest +{ class Timer { public: UNITTEST_LINKAGE Timer(); - UNITTEST_LINKAGE void Start(); - UNITTEST_LINKAGE double GetTimeInMs() const; + UNITTEST_LINKAGE void Start(); + UNITTEST_LINKAGE double GetTimeInMs() const; private: __int64 GetTime() const; @@ -61,16 +61,15 @@ class Timer unsigned long m_processAffinityMask; #endif - __int64 m_startTime; - __int64 m_frequency; + __int64 m_startTime; + __int64 m_frequency; }; - namespace TimeHelpers { - UNITTEST_LINKAGE void SleepMs(int ms); +UNITTEST_LINKAGE void SleepMs(int ms); } -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/XmlTestReporter.cpp b/Release/tests/common/UnitTestpp/src/XmlTestReporter.cpp index 63374bac23..19c796fa0a 100644 --- a/Release/tests/common/UnitTestpp/src/XmlTestReporter.cpp +++ b/Release/tests/common/UnitTestpp/src/XmlTestReporter.cpp @@ -1,49 +1,48 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" #ifndef UNITTEST_NO_DEFERRED_REPORTER #include "XmlTestReporter.h" - #include #include -using std::string; -using std::ostringstream; using std::ostream; +using std::ostringstream; +using std::string; -namespace { - +namespace +{ void ReplaceChar(string& str, char c, string const& replacement) { for (size_t pos = str.find(c); pos != string::npos; pos = str.find(c, pos + 1)) @@ -59,7 +58,7 @@ string XmlEscape(string const& value) ReplaceChar(escaped, '>', ">"); ReplaceChar(escaped, '\'', "'"); ReplaceChar(escaped, '\"', """); - + return escaped; } @@ -70,17 +69,13 @@ string BuildFailureMessage(string const& file, int line, string const& message) return failureMessage.str(); } -} - -namespace UnitTest { +} // namespace -XmlTestReporter::XmlTestReporter(ostream& ostream) - : m_ostream(ostream) +namespace UnitTest { -} +XmlTestReporter::XmlTestReporter(ostream& ostream) : m_ostream(ostream) {} -void XmlTestReporter::ReportSummary(int totalTestCount, int failedTestCount, - int failureCount, float secondsElapsed) +void XmlTestReporter::ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) { AddXmlElement(m_ostream, NULL); @@ -91,8 +86,7 @@ void XmlTestReporter::ReportSummary(int totalTestCount, int failedTestCount, { BeginTest(m_ostream, *i); - if (i->failed) - AddFailure(m_ostream, *i); + if (i->failed) AddFailure(m_ostream, *i); EndTest(m_ostream, *i); } @@ -104,34 +98,30 @@ void XmlTestReporter::AddXmlElement(ostream& os, char const* encoding) { os << ""; } -void XmlTestReporter::BeginResults(std::ostream& os, int totalTestCount, int failedTestCount, - int failureCount, float secondsElapsed) +void XmlTestReporter::BeginResults( + std::ostream& os, int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) { - os << ""; } -void XmlTestReporter::EndResults(std::ostream& os) -{ - os << ""; -} +void XmlTestReporter::EndResults(std::ostream& os) { os << ""; } void XmlTestReporter::BeginTest(std::ostream& os, DeferredTestResult const& result) { os << ""; // close element - for (DeferredTestResult::FailureVec::const_iterator it = result.failures.begin(); - it != result.failures.end(); - ++it) + for (DeferredTestResult::FailureVec::const_iterator it = result.failures.begin(); it != result.failures.end(); ++it) { - string const escapedMessage = XmlEscape(std::string(it->failureStr)); + string const escapedMessage = XmlEscape(std::string(it->failureStr)); string const message = BuildFailureMessage(result.failureFile, it->lineNumber, escapedMessage); - os << ""; + os << ""; } } -} +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/XmlTestReporter.h b/Release/tests/common/UnitTestpp/src/XmlTestReporter.h index 54a5c2ad34..6b728744a2 100644 --- a/Release/tests/common/UnitTestpp/src/XmlTestReporter.h +++ b/Release/tests/common/UnitTestpp/src/XmlTestReporter.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_XMLTESTREPORTER_H #define UNITTEST_XMLTESTREPORTER_H @@ -36,25 +36,27 @@ #ifndef UNITTEST_NO_DEFERRED_REPORTER #include "DeferredTestReporter.h" - #include namespace UnitTest { - class XmlTestReporter : public DeferredTestReporter { public: explicit UNITTEST_LINKAGE XmlTestReporter(std::ostream& ostream); - virtual UNITTEST_LINKAGE void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); + virtual UNITTEST_LINKAGE void ReportSummary(int totalTestCount, + int failedTestCount, + int failureCount, + float secondsElapsed); private: XmlTestReporter(XmlTestReporter const&); XmlTestReporter& operator=(XmlTestReporter const&); void AddXmlElement(std::ostream& os, char const* encoding); - void BeginResults(std::ostream& os, int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); + void BeginResults( + std::ostream& os, int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); void EndResults(std::ostream& os); void BeginTest(std::ostream& os, DeferredTestResult const& result); void AddFailure(std::ostream& os, DeferredTestResult const& result); @@ -63,7 +65,7 @@ class XmlTestReporter : public DeferredTestReporter std::ostream& m_ostream; }; -} +} // namespace UnitTest #endif #endif diff --git a/Release/tests/common/UnitTestpp/src/stdafx.cpp b/Release/tests/common/UnitTestpp/src/stdafx.cpp index dc9c392b64..82fd96b55e 100644 --- a/Release/tests/common/UnitTestpp/src/stdafx.cpp +++ b/Release/tests/common/UnitTestpp/src/stdafx.cpp @@ -1,35 +1,35 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ -// stdafx.cpp : +// stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/src/stdafx.h b/Release/tests/common/UnitTestpp/src/stdafx.h index 7835c99ed5..14b38623cb 100644 --- a/Release/tests/common/UnitTestpp/src/stdafx.h +++ b/Release/tests/common/UnitTestpp/src/stdafx.h @@ -1,53 +1,51 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #pragma once #include "../config.h" - #include "AssertException.h" #include "CurrentTest.h" #include "DeferredTestReporter.h" -#include "TestDetails.h" #include "MemoryOutStream.h" -#include "TestResults.h" #include "Test.h" +#include "TestDetails.h" #include "TestList.h" #include "TestReporter.h" #include "TestReporterStdout.h" +#include "TestResults.h" #include "TimeHelpers.h" - #include -#include #include +#include #ifdef WIN32 #define WIN32_LEAN_AND_MEAN diff --git a/Release/tests/common/UnitTestpp/src/tests/RecordingReporter.h b/Release/tests/common/UnitTestpp/src/tests/RecordingReporter.h index 2f29a93e10..c54ab29855 100644 --- a/Release/tests/common/UnitTestpp/src/tests/RecordingReporter.h +++ b/Release/tests/common/UnitTestpp/src/tests/RecordingReporter.h @@ -1,46 +1,48 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_RECORDINGREPORTER_H #define UNITTEST_RECORDINGREPORTER_H +#include "../TestDetails.h" #include "../TestReporter.h" #include -#include "../TestDetails.h" - struct RecordingReporter : public UnitTest::TestReporter { private: - enum { kMaxStringLength = 256 }; + enum + { + kMaxStringLength = 256 + }; public: RecordingReporter() @@ -66,7 +68,7 @@ struct RecordingReporter : public UnitTest::TestReporter virtual void ReportTestStart(UnitTest::TestDetails const& test) { - using namespace std; + using namespace std; ++testRunCount; strcpy(lastStartedSuite, test.suiteName); @@ -75,9 +77,9 @@ struct RecordingReporter : public UnitTest::TestReporter virtual void ReportFailure(UnitTest::TestDetails const& test, char const* failure) { - using namespace std; + using namespace std; - ++testFailedCount; + ++testFailedCount; strcpy(lastFailedFile, test.filename); lastFailedLine = test.lineNumber; strcpy(lastFailedSuite, test.suiteName); @@ -87,15 +89,15 @@ struct RecordingReporter : public UnitTest::TestReporter virtual void ReportTestFinish(UnitTest::TestDetails const& test, bool, float testDuration) { - using namespace std; + using namespace std; - ++testFinishedCount; + ++testFinishedCount; strcpy(lastFinishedSuite, test.suiteName); strcpy(lastFinishedTest, test.testName); lastFinishedTestTime = testDuration; } - virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) + virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) { summaryTotalTestCount = totalTestCount; summaryFailedTestCount = failedTestCount; @@ -125,5 +127,4 @@ struct RecordingReporter : public UnitTest::TestReporter float summarySecondsElapsed; }; - #endif diff --git a/Release/tests/common/UnitTestpp/src/tests/ScopedCurrentTest.h b/Release/tests/common/UnitTestpp/src/tests/ScopedCurrentTest.h index 81307847a4..399c27c536 100644 --- a/Release/tests/common/UnitTestpp/src/tests/ScopedCurrentTest.h +++ b/Release/tests/common/UnitTestpp/src/tests/ScopedCurrentTest.h @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTEST_SCOPEDCURRENTTEST_H #define UNITTEST_SCOPEDCURRENTTEST_H @@ -38,31 +38,28 @@ class ScopedCurrentTest { public: - ScopedCurrentTest() - : m_oldTestResults(UnitTest::CurrentTest::Results()) - , m_oldTestDetails(UnitTest::CurrentTest::Details()) - { - } + ScopedCurrentTest() + : m_oldTestResults(UnitTest::CurrentTest::Results()), m_oldTestDetails(UnitTest::CurrentTest::Details()) + { + } - explicit ScopedCurrentTest(UnitTest::TestResults& newResults, const UnitTest::TestDetails* newDetails = NULL) - : m_oldTestResults(UnitTest::CurrentTest::Results()) - , m_oldTestDetails(UnitTest::CurrentTest::Details()) - { - UnitTest::CurrentTest::Results() = &newResults; + explicit ScopedCurrentTest(UnitTest::TestResults& newResults, const UnitTest::TestDetails* newDetails = NULL) + : m_oldTestResults(UnitTest::CurrentTest::Results()), m_oldTestDetails(UnitTest::CurrentTest::Details()) + { + UnitTest::CurrentTest::Results() = &newResults; - if (newDetails != NULL) - UnitTest::CurrentTest::Details() = newDetails; - } + if (newDetails != NULL) UnitTest::CurrentTest::Details() = newDetails; + } - ~ScopedCurrentTest() - { - UnitTest::CurrentTest::Results() = m_oldTestResults; - UnitTest::CurrentTest::Details() = m_oldTestDetails; - } + ~ScopedCurrentTest() + { + UnitTest::CurrentTest::Results() = m_oldTestResults; + UnitTest::CurrentTest::Details() = m_oldTestDetails; + } private: - UnitTest::TestResults* m_oldTestResults; - const UnitTest::TestDetails* m_oldTestDetails; + UnitTest::TestResults* m_oldTestResults; + const UnitTest::TestDetails* m_oldTestDetails; }; #endif diff --git a/Release/tests/common/UnitTestpp/src/tests/TestAssertHandler.cpp b/Release/tests/common/UnitTestpp/src/tests/TestAssertHandler.cpp index 3f01f8f7dd..855e4a6e94 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestAssertHandler.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestAssertHandler.cpp @@ -1,51 +1,50 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" #include "../AssertException.h" - #include using namespace UnitTest; -namespace { - +namespace +{ TEST(CanSetAssertExpected) { - Detail::ExpectAssert(true); - CHECK(Detail::AssertExpected()); + Detail::ExpectAssert(true); + CHECK(Detail::AssertExpected()); - Detail::ExpectAssert(false); - CHECK(!Detail::AssertExpected()); + Detail::ExpectAssert(false); + CHECK(!Detail::AssertExpected()); } #ifndef UNITTEST_NO_EXCEPTIONS @@ -56,11 +55,11 @@ TEST(ReportAssertThrowsAssertException) try { - TestResults testResults; - TestDetails testDetails("", "", "", 0); + TestResults testResults; + TestDetails testDetails("", "", "", 0); Detail::ReportAssertEx(&testResults, &testDetails, "", "", 0); } - catch(AssertException const&) + catch (AssertException const&) { caught = true; } @@ -70,21 +69,21 @@ TEST(ReportAssertThrowsAssertException) TEST(ReportAssertClearsExpectAssertFlag) { - RecordingReporter reporter; - TestResults testResults(&reporter); - TestDetails testDetails("", "", "", 0); - - try - { - Detail::ExpectAssert(true); - Detail::ReportAssertEx(&testResults, &testDetails, "", "", 0); - } - catch(AssertException const&) - { - } - - CHECK(Detail::AssertExpected() == false); - CHECK_EQUAL(0, reporter.testFailedCount); + RecordingReporter reporter; + TestResults testResults(&reporter); + TestDetails testDetails("", "", "", 0); + + try + { + Detail::ExpectAssert(true); + Detail::ReportAssertEx(&testResults, &testDetails, "", "", 0); + } + catch (AssertException const&) + { + } + + CHECK(Detail::AssertExpected() == false); + CHECK_EQUAL(0, reporter.testFailedCount); } TEST(ReportAssertWritesFailureToResultsAndDetailsWhenAssertIsNotExpected) @@ -93,71 +92,68 @@ TEST(ReportAssertWritesFailureToResultsAndDetailsWhenAssertIsNotExpected) const char* description = "description"; const char* filename = "filename"; - RecordingReporter reporter; - TestResults testResults(&reporter); - TestDetails testDetails("", "", "", 0); + RecordingReporter reporter; + TestResults testResults(&reporter); + TestDetails testDetails("", "", "", 0); try { Detail::ReportAssertEx(&testResults, &testDetails, description, filename, lineNumber); } - catch(AssertException const&) + catch (AssertException const&) { } - CHECK_EQUAL(description, reporter.lastFailedMessage); - CHECK_EQUAL(filename, reporter.lastFailedFile); - CHECK_EQUAL(lineNumber, reporter.lastFailedLine); + CHECK_EQUAL(description, reporter.lastFailedMessage); + CHECK_EQUAL(filename, reporter.lastFailedFile); + CHECK_EQUAL(lineNumber, reporter.lastFailedLine); } TEST(ReportAssertReportsNoErrorsWhenAssertIsExpected) { - Detail::ExpectAssert(true); + Detail::ExpectAssert(true); - RecordingReporter reporter; - TestResults testResults(&reporter); - TestDetails testDetails("", "", "", 0); + RecordingReporter reporter; + TestResults testResults(&reporter); + TestDetails testDetails("", "", "", 0); - try - { - Detail::ReportAssertEx(&testResults, &testDetails, "", "", 0); - } - catch(AssertException const&) - { - } + try + { + Detail::ReportAssertEx(&testResults, &testDetails, "", "", 0); + } + catch (AssertException const&) + { + } - CHECK_EQUAL(0, reporter.testFailedCount); + CHECK_EQUAL(0, reporter.testFailedCount); } TEST(CheckAssertMacroSetsAssertExpectationToFalseAfterRunning) { - Detail::ExpectAssert(true); - CHECK_ASSERT(ReportAssert("", "", 0)); - CHECK(!Detail::AssertExpected()); - Detail::ExpectAssert(false); + Detail::ExpectAssert(true); + CHECK_ASSERT(ReportAssert("", "", 0)); + CHECK(!Detail::AssertExpected()); + Detail::ExpectAssert(false); } #else -TEST(SetAssertJumpTargetReturnsFalseWhenSettingJumpTarget) -{ - CHECK(UNITTEST_SET_ASSERT_JUMP_TARGET() == false); -} +TEST(SetAssertJumpTargetReturnsFalseWhenSettingJumpTarget) { CHECK(UNITTEST_SET_ASSERT_JUMP_TARGET() == false); } TEST(JumpToAssertJumpTarget_JumpsToSetPoint_ReturnsTrue) { - const volatile bool taken = !!UNITTEST_SET_ASSERT_JUMP_TARGET(); + const volatile bool taken = !!UNITTEST_SET_ASSERT_JUMP_TARGET(); - volatile bool set = false; - if (taken == false) - { - UNITTEST_JUMP_TO_ASSERT_JUMP_TARGET(); - set = true; - } + volatile bool set = false; + if (taken == false) + { + UNITTEST_JUMP_TO_ASSERT_JUMP_TARGET(); + set = true; + } - CHECK(set == false); + CHECK(set == false); } #endif -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestCheckMacros.cpp b/Release/tests/common/UnitTestpp/src/tests/TestCheckMacros.cpp index 2bdd2cc2fe..ec774e2c8f 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestCheckMacros.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestCheckMacros.cpp @@ -1,40 +1,40 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" using namespace std; -namespace { - +namespace +{ TEST(CheckSucceedsOnTrue) { bool failure = true; @@ -42,10 +42,10 @@ TEST(CheckSucceedsOnTrue) RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); - CHECK(true); + ScopedCurrentTest scopedResults(testResults); + CHECK(true); - failure = (testResults.GetFailureCount() > 0); + failure = (testResults.GetFailureCount() > 0); } CHECK(!failure); @@ -57,7 +57,7 @@ TEST(CheckFailsOnFalse) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); CHECK(false); failure = (testResults.GetFailureCount() > 0); } @@ -70,7 +70,7 @@ TEST(FailureReportsCorrectTestName) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); CHECK(false); } @@ -82,7 +82,7 @@ TEST(CheckFailureIncludesCheckContents) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); const bool yaddayadda = false; CHECK(yaddayadda); } @@ -96,7 +96,7 @@ TEST(CheckEqualSucceedsOnEqual) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); CHECK_EQUAL(1, 1); failure = (testResults.GetFailureCount() > 0); } @@ -110,7 +110,7 @@ TEST(CheckEqualFailsOnNotEqual) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); CHECK_EQUAL(1, 2); failure = (testResults.GetFailureCount() > 0); } @@ -124,10 +124,11 @@ TEST(CheckEqualFailureContainsCorrectDetails) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - UnitTest::TestDetails const testDetails("testName", "suiteName", "filename", -1); - ScopedCurrentTest scopedResults(testResults, &testDetails); + UnitTest::TestDetails const testDetails("testName", "suiteName", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); - CHECK_EQUAL(1, 123); line = __LINE__; + CHECK_EQUAL(1, 123); + line = __LINE__; } CHECK_EQUAL("testName", reporter.lastFailedTest); @@ -148,7 +149,7 @@ TEST(CheckEqualDoesNotHaveSideEffectsWhenPassing) g_sideEffect = 0; { UnitTest::TestResults testResults; - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); CHECK_EQUAL(1, FunctionWithSideEffects()); } CHECK_EQUAL(1, g_sideEffect); @@ -159,21 +160,20 @@ TEST(CheckEqualDoesNotHaveSideEffectsWhenFailing) g_sideEffect = 0; { UnitTest::TestResults testResults; - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); CHECK_EQUAL(2, FunctionWithSideEffects()); } CHECK_EQUAL(1, g_sideEffect); } - TEST(CheckCloseSucceedsOnEqual) { bool failure = true; { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); - CHECK_CLOSE (1.0f, 1.001f, 0.01f); + ScopedCurrentTest scopedResults(testResults); + CHECK_CLOSE(1.0f, 1.001f, 0.01f); failure = (testResults.GetFailureCount() > 0); } @@ -186,8 +186,8 @@ TEST(CheckCloseFailsOnNotEqual) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); - CHECK_CLOSE (1.0f, 1.1f, 0.01f); + ScopedCurrentTest scopedResults(testResults); + CHECK_CLOSE(1.0f, 1.1f, 0.01f); failure = (testResults.GetFailureCount() > 0); } @@ -200,10 +200,11 @@ TEST(CheckCloseFailureContainsCorrectDetails) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - UnitTest::TestDetails testDetails("test", "suite", "filename", -1); - ScopedCurrentTest scopedResults(testResults, &testDetails); + UnitTest::TestDetails testDetails("test", "suite", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); - CHECK_CLOSE (1.0f, 1.1f, 0.01f); line = __LINE__; + CHECK_CLOSE(1.0f, 1.1f, 0.01f); + line = __LINE__; } CHECK_EQUAL("test", reporter.lastFailedTest); @@ -217,8 +218,8 @@ TEST(CheckCloseDoesNotHaveSideEffectsWhenPassing) g_sideEffect = 0; { UnitTest::TestResults testResults; - ScopedCurrentTest scopedResults(testResults); - CHECK_CLOSE (1, FunctionWithSideEffects(), 0.1f); + ScopedCurrentTest scopedResults(testResults); + CHECK_CLOSE(1, FunctionWithSideEffects(), 0.1f); } CHECK_EQUAL(1, g_sideEffect); } @@ -228,8 +229,8 @@ TEST(CheckCloseDoesNotHaveSideEffectsWhenFailing) g_sideEffect = 0; { UnitTest::TestResults testResults; - ScopedCurrentTest scopedResults(testResults); - CHECK_CLOSE (2, FunctionWithSideEffects(), 0.1f); + ScopedCurrentTest scopedResults(testResults); + CHECK_CLOSE(2, FunctionWithSideEffects(), 0.1f); } CHECK_EQUAL(1, g_sideEffect); } @@ -240,9 +241,9 @@ TEST(CheckArrayCloseSucceedsOnEqual) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); - const float data[4] = { 0, 1, 2, 3 }; - CHECK_ARRAY_CLOSE (data, data, 4, 0.01f); + ScopedCurrentTest scopedResults(testResults); + const float data[4] = {0, 1, 2, 3}; + CHECK_ARRAY_CLOSE(data, data, 4, 0.01f); failure = (testResults.GetFailureCount() > 0); } @@ -255,13 +256,13 @@ TEST(CheckArrayCloseFailsOnNotEqual) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - int const data1[4] = { 0, 1, 2, 3 }; - int const data2[4] = { 0, 1, 3, 3 }; - CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + int const data1[4] = {0, 1, 2, 3}; + int const data2[4] = {0, 1, 3, 3}; + CHECK_ARRAY_CLOSE(data1, data2, 4, 0.01f); - failure = (testResults.GetFailureCount() > 0); + failure = (testResults.GetFailureCount() > 0); } CHECK(failure); @@ -272,11 +273,11 @@ TEST(CheckArrayCloseFailureIncludesCheckExpectedAndActual) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - int const data1[4] = { 0, 1, 2, 3 }; - int const data2[4] = { 0, 1, 3, 3 }; - CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + int const data1[4] = {0, 1, 2, 3}; + int const data2[4] = {0, 1, 3, 3}; + CHECK_ARRAY_CLOSE(data1, data2, 4, 0.01f); } CHECK(strstr(reporter.lastFailedMessage, "xpected [ 0 1 2 3 ]")); @@ -289,12 +290,13 @@ TEST(CheckArrayCloseFailureContainsCorrectDetails) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - UnitTest::TestDetails testDetails("arrayCloseTest", "arrayCloseSuite", "filename", -1); - ScopedCurrentTest scopedResults(testResults, &testDetails); + UnitTest::TestDetails testDetails("arrayCloseTest", "arrayCloseSuite", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); - int const data1[4] = { 0, 1, 2, 3 }; - int const data2[4] = { 0, 1, 3, 3 }; - CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); line = __LINE__; + int const data1[4] = {0, 1, 2, 3}; + int const data2[4] = {0, 1, 3, 3}; + CHECK_ARRAY_CLOSE(data1, data2, 4, 0.01f); + line = __LINE__; } CHECK_EQUAL("arrayCloseTest", reporter.lastFailedTest); @@ -308,11 +310,11 @@ TEST(CheckArrayCloseFailureIncludesTolerance) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - float const data1[4] = { 0, 1, 2, 3 }; - float const data2[4] = { 0, 1, 3, 3 }; - CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + float const data1[4] = {0, 1, 2, 3}; + float const data2[4] = {0, 1, 3, 3}; + CHECK_ARRAY_CLOSE(data1, data2, 4, 0.01f); } CHECK(strstr(reporter.lastFailedMessage, "0.01")); @@ -324,12 +326,12 @@ TEST(CheckArrayEqualSuceedsOnEqual) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - const float data[4] = { 0, 1, 2, 3 }; - CHECK_ARRAY_EQUAL (data, data, 4); + const float data[4] = {0, 1, 2, 3}; + CHECK_ARRAY_EQUAL(data, data, 4); - failure = (testResults.GetFailureCount() > 0); + failure = (testResults.GetFailureCount() > 0); } CHECK(!failure); @@ -341,13 +343,13 @@ TEST(CheckArrayEqualFailsOnNotEqual) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - int const data1[4] = { 0, 1, 2, 3 }; - int const data2[4] = { 0, 1, 3, 3 }; - CHECK_ARRAY_EQUAL (data1, data2, 4); + int const data1[4] = {0, 1, 2, 3}; + int const data2[4] = {0, 1, 3, 3}; + CHECK_ARRAY_EQUAL(data1, data2, 4); - failure = (testResults.GetFailureCount() > 0); + failure = (testResults.GetFailureCount() > 0); } CHECK(failure); @@ -358,11 +360,11 @@ TEST(CheckArrayEqualFailureIncludesCheckExpectedAndActual) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - int const data1[4] = { 0, 1, 2, 3 }; - int const data2[4] = { 0, 1, 3, 3 }; - CHECK_ARRAY_EQUAL (data1, data2, 4); + int const data1[4] = {0, 1, 2, 3}; + int const data2[4] = {0, 1, 3, 3}; + CHECK_ARRAY_EQUAL(data1, data2, 4); } CHECK(strstr(reporter.lastFailedMessage, "xpected [ 0 1 2 3 ]")); @@ -375,11 +377,12 @@ TEST(CheckArrayEqualFailureContainsCorrectInfo) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - int const data1[4] = { 0, 1, 2, 3 }; - int const data2[4] = { 0, 1, 3, 3 }; - CHECK_ARRAY_EQUAL (data1, data2, 4); line = __LINE__; + int const data1[4] = {0, 1, 2, 3}; + int const data2[4] = {0, 1, 3, 3}; + CHECK_ARRAY_EQUAL(data1, data2, 4); + line = __LINE__; } CHECK_EQUAL("CheckArrayEqualFailureContainsCorrectInfo", reporter.lastFailedTest); @@ -390,7 +393,7 @@ TEST(CheckArrayEqualFailureContainsCorrectInfo) float const* FunctionWithSideEffects2() { ++g_sideEffect; - static float const data[] = {1,2,3,4}; + static float const data[] = {1, 2, 3, 4}; return data; } @@ -399,10 +402,10 @@ TEST(CheckArrayCloseDoesNotHaveSideEffectsWhenPassing) g_sideEffect = 0; { UnitTest::TestResults testResults; - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - const float data[] = { 0, 1, 2, 3 }; - CHECK_ARRAY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f); + const float data[] = {0, 1, 2, 3}; + CHECK_ARRAY_CLOSE(data, FunctionWithSideEffects2(), 4, 0.01f); } CHECK_EQUAL(1, g_sideEffect); } @@ -412,13 +415,13 @@ TEST(CheckArrayCloseDoesNotHaveSideEffectsWhenFailing) g_sideEffect = 0; { UnitTest::TestResults testResults; - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - const float data[] = { 0, 1, 3, 3 }; - CHECK_ARRAY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f); + const float data[] = {0, 1, 3, 3}; + CHECK_ARRAY_CLOSE(data, FunctionWithSideEffects2(), 4, 0.01f); } - CHECK_EQUAL(1, g_sideEffect); + CHECK_EQUAL(1, g_sideEffect); } TEST(CheckArray2DCloseSucceedsOnEqual) @@ -427,12 +430,12 @@ TEST(CheckArray2DCloseSucceedsOnEqual) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - const float data[2][2] = { {0, 1}, {2, 3} }; - CHECK_ARRAY2D_CLOSE (data, data, 2, 2, 0.01f); + const float data[2][2] = {{0, 1}, {2, 3}}; + CHECK_ARRAY2D_CLOSE(data, data, 2, 2, 0.01f); - failure = (testResults.GetFailureCount() > 0); + failure = (testResults.GetFailureCount() > 0); } CHECK(!failure); @@ -444,13 +447,13 @@ TEST(CheckArray2DCloseFailsOnNotEqual) { RecordingReporter reporter; UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - int const data1[2][2] = { {0, 1}, {2, 3} }; - int const data2[2][2] = { {0, 1}, {3, 3} }; - CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + int const data1[2][2] = {{0, 1}, {2, 3}}; + int const data2[2][2] = {{0, 1}, {3, 3}}; + CHECK_ARRAY2D_CLOSE(data1, data2, 2, 2, 0.01f); - failure = (testResults.GetFailureCount() > 0); + failure = (testResults.GetFailureCount() > 0); } CHECK(failure); @@ -461,12 +464,12 @@ TEST(CheckArray2DCloseFailureIncludesCheckExpectedAndActual) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - int const data1[2][2] = { {0, 1}, {2, 3} }; - int const data2[2][2] = { {0, 1}, {3, 3} }; + int const data1[2][2] = {{0, 1}, {2, 3}}; + int const data2[2][2] = {{0, 1}, {3, 3}}; - CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + CHECK_ARRAY2D_CLOSE(data1, data2, 2, 2, 0.01f); } CHECK(strstr(reporter.lastFailedMessage, "xpected [ [ 0 1 ] [ 2 3 ] ]")); @@ -479,12 +482,13 @@ TEST(CheckArray2DCloseFailureContainsCorrectDetails) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - UnitTest::TestDetails testDetails("array2DCloseTest", "array2DCloseSuite", "filename", -1); - ScopedCurrentTest scopedResults(testResults, &testDetails); + UnitTest::TestDetails testDetails("array2DCloseTest", "array2DCloseSuite", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); - int const data1[2][2] = { {0, 1}, {2, 3} }; - int const data2[2][2] = { {0, 1}, {3, 3} }; - CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); line = __LINE__; + int const data1[2][2] = {{0, 1}, {2, 3}}; + int const data2[2][2] = {{0, 1}, {3, 3}}; + CHECK_ARRAY2D_CLOSE(data1, data2, 2, 2, 0.01f); + line = __LINE__; } CHECK_EQUAL("array2DCloseTest", reporter.lastFailedTest); @@ -498,11 +502,11 @@ TEST(CheckArray2DCloseFailureIncludesTolerance) RecordingReporter reporter; { UnitTest::TestResults testResults(&reporter); - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - float const data1[2][2] = { {0, 1}, {2, 3} }; - float const data2[2][2] = { {0, 1}, {3, 3} }; - CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + float const data1[2][2] = {{0, 1}, {2, 3}}; + float const data2[2][2] = {{0, 1}, {3, 3}}; + CHECK_ARRAY2D_CLOSE(data1, data2, 2, 2, 0.01f); } CHECK(strstr(reporter.lastFailedMessage, "0.01")); @@ -511,8 +515,8 @@ TEST(CheckArray2DCloseFailureIncludesTolerance) float const* const* FunctionWithSideEffects3() { ++g_sideEffect; - static float const data1[] = {0,1}; - static float const data2[] = {2,3}; + static float const data1[] = {0, 1}; + static float const data2[] = {2, 3}; static const float* const data[] = {data1, data2}; return data; } @@ -522,10 +526,10 @@ TEST(CheckArray2DCloseDoesNotHaveSideEffectsWhenPassing) g_sideEffect = 0; { UnitTest::TestResults testResults; - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - const float data[2][2] = { {0, 1}, {2, 3} }; - CHECK_ARRAY2D_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f); + const float data[2][2] = {{0, 1}, {2, 3}}; + CHECK_ARRAY2D_CLOSE(data, FunctionWithSideEffects3(), 2, 2, 0.01f); } CHECK_EQUAL(1, g_sideEffect); } @@ -535,12 +539,12 @@ TEST(CheckArray2DCloseDoesNotHaveSideEffectsWhenFailing) g_sideEffect = 0; { UnitTest::TestResults testResults; - ScopedCurrentTest scopedResults(testResults); + ScopedCurrentTest scopedResults(testResults); - const float data[2][2] = { {0, 1}, {3, 3} }; - CHECK_ARRAY2D_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f); + const float data[2][2] = {{0, 1}, {3, 3}}; + CHECK_ARRAY2D_CLOSE(data, FunctionWithSideEffects3(), 2, 2, 0.01f); } CHECK_EQUAL(1, g_sideEffect); } -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestChecks.cpp b/Release/tests/common/UnitTestpp/src/tests/TestChecks.cpp index face29e641..077aaec29d 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestChecks.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestChecks.cpp @@ -1,41 +1,40 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" using namespace UnitTest; -namespace { - - +namespace +{ TEST(CheckEqualWithUnsignedLong) { TestResults results; @@ -106,7 +105,7 @@ TEST(CheckEqualFailureIncludesCheckExpectedAndActual) const int something = 2; CheckEqual(results, "1", "something", 1, something, TestDetails("", "", "", 0)); - using namespace std; + using namespace std; CHECK(strstr(reporter.lastFailedMessage, "1=1")); CHECK(strstr(reporter.lastFailedMessage, "something=2")); } @@ -148,20 +147,20 @@ TEST(CheckCloseWithZeroEpsilonWorksForSameNumber) TEST(CheckCloseWithNaNFails) { - const unsigned int bitpattern = 0xFFFFFFFF; - float nan; - std::memcpy(&nan, &bitpattern, sizeof(bitpattern)); + const unsigned int bitpattern = 0xFFFFFFFF; + float nan; + std::memcpy(&nan, &bitpattern, sizeof(bitpattern)); - TestResults results; + TestResults results; CheckClose(results, 3.0f, nan, 0.1f, TestDetails("", "", "", 0)); CHECK_EQUAL(1, results.GetFailureCount()); } TEST(CheckCloseWithNaNAgainstItselfFails) { - const unsigned int bitpattern = 0xFFFFFFFF; - float nan; - std::memcpy(&nan, &bitpattern, sizeof(bitpattern)); + const unsigned int bitpattern = 0xFFFFFFFF; + float nan; + std::memcpy(&nan, &bitpattern, sizeof(bitpattern)); TestResults results; CheckClose(results, nan, nan, 0.1f, TestDetails("", "", "", 0)); @@ -176,7 +175,7 @@ TEST(CheckCloseFailureIncludesCheckExpectedAndActual) const float actual = 1.1f; CheckClose(results, expected, actual, 0.01f, TestDetails("", "", "", 0)); - using namespace std; + using namespace std; CHECK(strstr(reporter.lastFailedMessage, "xpected 0.9")); CHECK(strstr(reporter.lastFailedMessage, "was 1.1")); } @@ -187,7 +186,7 @@ TEST(CheckCloseFailureIncludesTolerance) TestResults results(&reporter); CheckClose(results, 2, 3, 0.01f, TestDetails("", "", "", 0)); - using namespace std; + using namespace std; CHECK(strstr(reporter.lastFailedMessage, "0.01")); } @@ -205,12 +204,11 @@ TEST(CheckCloseFailureIncludesDetails) CHECK_EQUAL(10, reporter.lastFailedLine); } - TEST(CheckArrayEqualTrue) { TestResults results; - int const array[3] = { 1, 2, 3 }; + int const array[3] = {1, 2, 3}; CheckArrayEqual(results, array, array, 3, TestDetails("", "", "", 0)); CHECK_EQUAL(0, results.GetFailureCount()); } @@ -219,8 +217,8 @@ TEST(CheckArrayEqualFalse) { TestResults results; - int const array1[3] = { 1, 2, 3 }; - int const array2[3] = { 1, 2, 2 }; + int const array1[3] = {1, 2, 3}; + int const array2[3] = {1, 2, 2}; CheckArrayEqual(results, array1, array2, 3, TestDetails("", "", "", 0)); CHECK_EQUAL(1, results.GetFailureCount()); } @@ -229,8 +227,8 @@ TEST(CheckArrayCloseTrue) { TestResults results; - float const array1[3] = { 1.0f, 1.5f, 2.0f }; - float const array2[3] = { 1.01f, 1.51f, 2.01f }; + float const array1[3] = {1.0f, 1.5f, 2.0f}; + float const array2[3] = {1.01f, 1.51f, 2.01f}; CheckArrayClose(results, array1, array2, 3, 0.02f, TestDetails("", "", "", 0)); CHECK_EQUAL(0, results.GetFailureCount()); } @@ -239,8 +237,8 @@ TEST(CheckArrayCloseFalse) { TestResults results; - float const array1[3] = { 1.0f, 1.5f, 2.0f }; - float const array2[3] = { 1.01f, 1.51f, 2.01f }; + float const array1[3] = {1.0f, 1.5f, 2.0f}; + float const array2[3] = {1.01f, 1.51f, 2.01f}; CheckArrayClose(results, array1, array2, 3, 0.001f, TestDetails("", "", "", 0)); CHECK_EQUAL(1, results.GetFailureCount()); } @@ -251,8 +249,8 @@ TEST(CheckArrayCloseFailureIncludesDetails) TestResults results(&reporter); TestDetails const details("arrayCloseTest", "arrayCloseSuite", "file", 1337); - float const array1[3] = { 1.0f, 1.5f, 2.0f }; - float const array2[3] = { 1.01f, 1.51f, 2.01f }; + float const array1[3] = {1.0f, 1.5f, 2.0f}; + float const array2[3] = {1.01f, 1.51f, 2.01f}; CheckArrayClose(results, array1, array2, 3, 0.001f, details); CHECK_EQUAL("arrayCloseTest", reporter.lastFailedTest); @@ -261,17 +259,12 @@ TEST(CheckArrayCloseFailureIncludesDetails) CHECK_EQUAL(1337, reporter.lastFailedLine); } - TEST(CheckArray2DCloseTrue) { TestResults results; - float const array1[3][3] = { { 1.0f, 1.5f, 2.0f }, - { 2.0f, 2.5f, 3.0f }, - { 3.0f, 3.5f, 4.0f } }; - float const array2[3][3] = { { 1.01f, 1.51f, 2.01f }, - { 2.01f, 2.51f, 3.01f }, - { 3.01f, 3.51f, 4.01f } }; + float const array1[3][3] = {{1.0f, 1.5f, 2.0f}, {2.0f, 2.5f, 3.0f}, {3.0f, 3.5f, 4.0f}}; + float const array2[3][3] = {{1.01f, 1.51f, 2.01f}, {2.01f, 2.51f, 3.01f}, {3.01f, 3.51f, 4.01f}}; CheckArray2DClose(results, array1, array2, 3, 3, 0.02f, TestDetails("", "", "", 0)); CHECK_EQUAL(0, results.GetFailureCount()); } @@ -280,20 +273,13 @@ TEST(CheckArray2DCloseFalse) { TestResults results; - float const array1[3][3] = { { 1.0f, 1.5f, 2.0f }, - { 2.0f, 2.5f, 3.0f }, - { 3.0f, 3.5f, 4.0f } }; - float const array2[3][3] = { { 1.01f, 1.51f, 2.01f }, - { 2.01f, 2.51f, 3.01f }, - { 3.01f, 3.51f, 4.01f } }; + float const array1[3][3] = {{1.0f, 1.5f, 2.0f}, {2.0f, 2.5f, 3.0f}, {3.0f, 3.5f, 4.0f}}; + float const array2[3][3] = {{1.01f, 1.51f, 2.01f}, {2.01f, 2.51f, 3.01f}, {3.01f, 3.51f, 4.01f}}; CheckArray2DClose(results, array1, array2, 3, 3, 0.001f, TestDetails("", "", "", 0)); CHECK_EQUAL(1, results.GetFailureCount()); } -TEST(CheckCloseWithDoublesSucceeds) -{ - CHECK_CLOSE(0.5, 0.5, 0.0001); -} +TEST(CheckCloseWithDoublesSucceeds) { CHECK_CLOSE(0.5, 0.5, 0.0001); } TEST(CheckArray2DCloseFailureIncludesDetails) { @@ -301,12 +287,8 @@ TEST(CheckArray2DCloseFailureIncludesDetails) TestResults results(&reporter); TestDetails const details("array2DCloseTest", "array2DCloseSuite", "file", 1234); - float const array1[3][3] = { { 1.0f, 1.5f, 2.0f }, - { 2.0f, 2.5f, 3.0f }, - { 3.0f, 3.5f, 4.0f } }; - float const array2[3][3] = { { 1.01f, 1.51f, 2.01f }, - { 2.01f, 2.51f, 3.01f }, - { 3.01f, 3.51f, 4.01f } }; + float const array1[3][3] = {{1.0f, 1.5f, 2.0f}, {2.0f, 2.5f, 3.0f}, {3.0f, 3.5f, 4.0f}}; + float const array2[3][3] = {{1.01f, 1.51f, 2.01f}, {2.01f, 2.51f, 3.01f}, {3.01f, 3.51f, 4.01f}}; CheckArray2DClose(results, array1, array2, 3, 3, 0.001f, details); CHECK_EQUAL("array2DCloseTest", reporter.lastFailedTest); @@ -315,4 +297,4 @@ TEST(CheckArray2DCloseFailureIncludesDetails) CHECK_EQUAL(1234, reporter.lastFailedLine); } -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestCompositeTestReporter.cpp b/Release/tests/common/UnitTestpp/src/tests/TestCompositeTestReporter.cpp index 0a2cf008b8..96810927f9 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestCompositeTestReporter.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestCompositeTestReporter.cpp @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" @@ -35,174 +35,168 @@ using namespace UnitTest; -namespace { - -TEST(ZeroReportersByDefault) +namespace { - CHECK_EQUAL(0, CompositeTestReporter().GetReporterCount()); -} +TEST(ZeroReportersByDefault) { CHECK_EQUAL(0, CompositeTestReporter().GetReporterCount()); } struct MockReporter : TestReporter { - MockReporter() - : testStartCalled(false) - , testStartDetails(NULL) - , failureCalled(false) - , failureDetails(NULL) - , failureStr(NULL) - , testFinishCalled(false) - , testFinishDetails(NULL) - , testFinishSecondsElapsed(-1.0f) - , summaryCalled(false) - , summaryTotalTestCount(-1) - , summaryFailureCount(-1) - , summarySecondsElapsed(-1.0f) - { - } - - virtual void ReportTestStart(TestDetails const& test) - { - testStartCalled = true; - testStartDetails = &test; - } - - virtual void ReportFailure(TestDetails const& test, char const* failure) - { - failureCalled = true; - failureDetails = &test; - failureStr = failure; - } - - virtual void ReportTestFinish(TestDetails const& test, bool, float secondsElapsed) - { - testFinishCalled = true; - testFinishDetails = &test; - testFinishSecondsElapsed = secondsElapsed; - } - - virtual void ReportSummary(int totalTestCount, - int failedTestCount, - int failureCount, - float secondsElapsed) - { - summaryCalled = true; - summaryTotalTestCount = totalTestCount; - summaryFailedTestCount = failedTestCount; - summaryFailureCount = failureCount; - summarySecondsElapsed = secondsElapsed; - } - - bool testStartCalled; - TestDetails const* testStartDetails; - - bool failureCalled; - TestDetails const* failureDetails; - const char* failureStr; - - bool testFinishCalled; - TestDetails const* testFinishDetails; - float testFinishSecondsElapsed; - - bool summaryCalled; - int summaryTotalTestCount; - int summaryFailedTestCount; - int summaryFailureCount; - float summarySecondsElapsed; + MockReporter() + : testStartCalled(false) + , testStartDetails(NULL) + , failureCalled(false) + , failureDetails(NULL) + , failureStr(NULL) + , testFinishCalled(false) + , testFinishDetails(NULL) + , testFinishSecondsElapsed(-1.0f) + , summaryCalled(false) + , summaryTotalTestCount(-1) + , summaryFailureCount(-1) + , summarySecondsElapsed(-1.0f) + { + } + + virtual void ReportTestStart(TestDetails const& test) + { + testStartCalled = true; + testStartDetails = &test; + } + + virtual void ReportFailure(TestDetails const& test, char const* failure) + { + failureCalled = true; + failureDetails = &test; + failureStr = failure; + } + + virtual void ReportTestFinish(TestDetails const& test, bool, float secondsElapsed) + { + testFinishCalled = true; + testFinishDetails = &test; + testFinishSecondsElapsed = secondsElapsed; + } + + virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) + { + summaryCalled = true; + summaryTotalTestCount = totalTestCount; + summaryFailedTestCount = failedTestCount; + summaryFailureCount = failureCount; + summarySecondsElapsed = secondsElapsed; + } + + bool testStartCalled; + TestDetails const* testStartDetails; + + bool failureCalled; + TestDetails const* failureDetails; + const char* failureStr; + + bool testFinishCalled; + TestDetails const* testFinishDetails; + float testFinishSecondsElapsed; + + bool summaryCalled; + int summaryTotalTestCount; + int summaryFailedTestCount; + int summaryFailureCount; + float summarySecondsElapsed; }; TEST(AddReporter) { - MockReporter r; - CompositeTestReporter c; + MockReporter r; + CompositeTestReporter c; - CHECK(c.AddReporter(&r)); - CHECK_EQUAL(1, c.GetReporterCount()); + CHECK(c.AddReporter(&r)); + CHECK_EQUAL(1, c.GetReporterCount()); } TEST(RemoveReporter) { - MockReporter r; - CompositeTestReporter c; + MockReporter r; + CompositeTestReporter c; - c.AddReporter(&r); - CHECK(c.RemoveReporter(&r)); - CHECK_EQUAL(0, c.GetReporterCount()); + c.AddReporter(&r); + CHECK(c.RemoveReporter(&r)); + CHECK_EQUAL(0, c.GetReporterCount()); } struct Fixture { - Fixture() - { - c.AddReporter(&r0); - c.AddReporter(&r1); - } - - MockReporter r0, r1; - CompositeTestReporter c; + Fixture() + { + c.AddReporter(&r0); + c.AddReporter(&r1); + } + + MockReporter r0, r1; + CompositeTestReporter c; }; TEST_FIXTURE(Fixture, ReportTestStartCallsReportTestStartOnAllAggregates) { - TestDetails t("", "", "", 0); - c.ReportTestStart(t); + TestDetails t("", "", "", 0); + c.ReportTestStart(t); - CHECK(r0.testStartCalled); - CHECK_EQUAL(&t, r0.testStartDetails); - CHECK(r1.testStartCalled); - CHECK_EQUAL(&t, r1.testStartDetails); + CHECK(r0.testStartCalled); + CHECK_EQUAL(&t, r0.testStartDetails); + CHECK(r1.testStartCalled); + CHECK_EQUAL(&t, r1.testStartDetails); } TEST_FIXTURE(Fixture, ReportFailureCallsReportFailureOnAllAggregates) { - TestDetails t("", "", "", 0); - const char* failStr = "fail"; - c.ReportFailure(t, failStr); + TestDetails t("", "", "", 0); + const char* failStr = "fail"; + c.ReportFailure(t, failStr); - CHECK(r0.failureCalled); - CHECK_EQUAL(&t, r0.failureDetails); - CHECK_EQUAL(failStr, r0.failureStr); + CHECK(r0.failureCalled); + CHECK_EQUAL(&t, r0.failureDetails); + CHECK_EQUAL(failStr, r0.failureStr); - CHECK(r1.failureCalled); - CHECK_EQUAL(&t, r1.failureDetails); - CHECK_EQUAL(failStr, r1.failureStr); + CHECK(r1.failureCalled); + CHECK_EQUAL(&t, r1.failureDetails); + CHECK_EQUAL(failStr, r1.failureStr); } TEST_FIXTURE(Fixture, ReportTestFinishCallsReportTestFinishOnAllAggregates) { - TestDetails t("", "", "", 0); - const float s = 1.2345f; - c.ReportTestFinish(t, true, s); + TestDetails t("", "", "", 0); + const float s = 1.2345f; + c.ReportTestFinish(t, true, s); - CHECK(r0.testFinishCalled); - CHECK_EQUAL(&t, r0.testFinishDetails); - CHECK_CLOSE(s, r0.testFinishSecondsElapsed, 0.00001f); + CHECK(r0.testFinishCalled); + CHECK_EQUAL(&t, r0.testFinishDetails); + CHECK_CLOSE(s, r0.testFinishSecondsElapsed, 0.00001f); - CHECK(r1.testFinishCalled); - CHECK_EQUAL(&t, r1.testFinishDetails); - CHECK_CLOSE(s, r1.testFinishSecondsElapsed, 0.00001f); + CHECK(r1.testFinishCalled); + CHECK_EQUAL(&t, r1.testFinishDetails); + CHECK_CLOSE(s, r1.testFinishSecondsElapsed, 0.00001f); } TEST_FIXTURE(Fixture, ReportSummaryCallsReportSummaryOnAllAggregates) { - TestDetails t("", "", "", 0); - const int testCount = 3; - const int failedTestCount = 4; - const int failureCount = 5; - const float secondsElapsed = 3.14159f; - - c.ReportSummary(testCount, failedTestCount, failureCount, secondsElapsed); - - CHECK(r0.summaryCalled); - CHECK_EQUAL(testCount, r0.summaryTotalTestCount); - CHECK_EQUAL(failedTestCount, r0.summaryFailedTestCount); - CHECK_EQUAL(failureCount, r0.summaryFailureCount); - CHECK_CLOSE(secondsElapsed, r0.summarySecondsElapsed, 0.00001f); - - CHECK(r1.summaryCalled); - CHECK_EQUAL(testCount, r1.summaryTotalTestCount); - CHECK_EQUAL(failedTestCount, r1.summaryFailedTestCount); - CHECK_EQUAL(failureCount, r1.summaryFailureCount); - CHECK_CLOSE(secondsElapsed, r1.summarySecondsElapsed, 0.00001f); + TestDetails t("", "", "", 0); + const int testCount = 3; + const int failedTestCount = 4; + const int failureCount = 5; + const float secondsElapsed = 3.14159f; + + c.ReportSummary(testCount, failedTestCount, failureCount, secondsElapsed); + + CHECK(r0.summaryCalled); + CHECK_EQUAL(testCount, r0.summaryTotalTestCount); + CHECK_EQUAL(failedTestCount, r0.summaryFailedTestCount); + CHECK_EQUAL(failureCount, r0.summaryFailureCount); + CHECK_CLOSE(secondsElapsed, r0.summarySecondsElapsed, 0.00001f); + + CHECK(r1.summaryCalled); + CHECK_EQUAL(testCount, r1.summaryTotalTestCount); + CHECK_EQUAL(failedTestCount, r1.summaryFailedTestCount); + CHECK_EQUAL(failureCount, r1.summaryFailureCount); + CHECK_CLOSE(secondsElapsed, r1.summarySecondsElapsed, 0.00001f); } -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestCurrentTest.cpp b/Release/tests/common/UnitTestpp/src/tests/TestCurrentTest.cpp index daa6d4a88a..e0f2076a01 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestCurrentTest.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestCurrentTest.cpp @@ -1,67 +1,66 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" -namespace +namespace { - TEST(CanSetandGetDetails) { - bool ok = false; - { - ScopedCurrentTest scopedTest; + bool ok = false; + { + ScopedCurrentTest scopedTest; - const UnitTest::TestDetails* details = reinterpret_cast< const UnitTest::TestDetails* >(12345); - UnitTest::CurrentTest::Details() = details; + const UnitTest::TestDetails* details = reinterpret_cast(12345); + UnitTest::CurrentTest::Details() = details; - ok = (UnitTest::CurrentTest::Details() == details); - } + ok = (UnitTest::CurrentTest::Details() == details); + } - CHECK(ok); + CHECK(ok); } TEST(CanSetAndGetResults) { - bool ok = false; - { - ScopedCurrentTest scopedTest; + bool ok = false; + { + ScopedCurrentTest scopedTest; - UnitTest::TestResults results; - UnitTest::CurrentTest::Results() = &results; + UnitTest::TestResults results; + UnitTest::CurrentTest::Results() = &results; - ok = (UnitTest::CurrentTest::Results() == &results); - } + ok = (UnitTest::CurrentTest::Results() == &results); + } - CHECK(ok); + CHECK(ok); } -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestDeferredTestReporter.cpp b/Release/tests/common/UnitTestpp/src/tests/TestDeferredTestReporter.cpp index ac19b67234..6e8bfe845c 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestDeferredTestReporter.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestDeferredTestReporter.cpp @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" @@ -37,23 +37,19 @@ namespace UnitTest { - -namespace +namespace { - #ifndef UNITTEST_MEMORYOUTSTREAM_IS_STD_OSTRINGSTREAM - MemoryOutStream& operator <<(MemoryOutStream& lhs, const std::string& rhs) - { - lhs << rhs.c_str(); - return lhs; - } +MemoryOutStream& operator<<(MemoryOutStream& lhs, const std::string& rhs) +{ + lhs << rhs.c_str(); + return lhs; +} #endif struct MockDeferredTestReporter : public DeferredTestReporter { - virtual void ReportSummary(int, int, int, float) - { - } + virtual void ReportSummary(int, int, int, float) {} }; struct DeferredTestReporterFixture @@ -134,8 +130,8 @@ TEST_FIXTURE(DeferredTestReporterFixture, DeferredTestReporterTakesCopyOfFailure char failureMessage[128]; char const* goodStr = "Real failure message"; char const* badStr = "Bogus failure message"; - - using namespace std; + + using namespace std; strcpy(failureMessage, goodStr); reporter.ReportFailure(details, failureMessage); @@ -146,6 +142,7 @@ TEST_FIXTURE(DeferredTestReporterFixture, DeferredTestReporterTakesCopyOfFailure CHECK_EQUAL(goodStr, failure.failureStr); } -}} +} // namespace +} // namespace UnitTest #endif diff --git a/Release/tests/common/UnitTestpp/src/tests/TestMemoryOutStream.cpp b/Release/tests/common/UnitTestpp/src/tests/TestMemoryOutStream.cpp index c4345bcbea..79aa88c5b7 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestMemoryOutStream.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestMemoryOutStream.cpp @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" @@ -38,8 +38,8 @@ using namespace UnitTest; using namespace std; -namespace { - +namespace +{ TEST(DefaultIsEmptyString) { MemoryOutStream const stream; @@ -57,7 +57,9 @@ TEST(StreamingTextCopiesCharacters) TEST(StreamingMultipleTimesConcatenatesResult) { MemoryOutStream stream; - stream << "Bork" << "To" << "Fred"; + stream << "Bork" + << "To" + << "Fred"; CHECK_EQUAL("BorkToFred", stream.GetText()); } @@ -91,30 +93,30 @@ TEST(StreamingUnsignedLongWritesCorrectCharacters) TEST(StreamingLongLongWritesCorrectCharacters) { - MemoryOutStream stream; - stream << (long long)(ULONG_MAX) * 2; - CHECK_EQUAL("8589934590", stream.GetText()); + MemoryOutStream stream; + stream << (long long)(ULONG_MAX)*2; + CHECK_EQUAL("8589934590", stream.GetText()); } TEST(StreamingUnsignedLongLongWritesCorrectCharacters) { - MemoryOutStream stream; - stream << (unsigned long long)(ULONG_MAX) * 2; - CHECK_EQUAL("8589934590", stream.GetText()); + MemoryOutStream stream; + stream << (unsigned long long)(ULONG_MAX)*2; + CHECK_EQUAL("8589934590", stream.GetText()); } TEST(StreamingFloatWritesCorrectCharacters) { MemoryOutStream stream; stream << 3.1415f; - CHECK(strstr(stream.GetText(), "3.1415")); + CHECK(strstr(stream.GetText(), "3.1415")); } TEST(StreamingDoubleWritesCorrectCharacters) { - MemoryOutStream stream; - stream << 3.1415; - CHECK(strstr(stream.GetText(), "3.1415")); + MemoryOutStream stream; + stream << 3.1415; + CHECK(strstr(stream.GetText(), "3.1415")); } TEST(StreamingPointerWritesCorrectCharacters) @@ -135,10 +137,10 @@ TEST(StreamingSizeTWritesCorrectCharacters) TEST(ClearEmptiesMemoryOutStreamContents) { - MemoryOutStream stream; - stream << "Hello world"; - stream.Clear(); - CHECK_EQUAL("", stream.GetText()); + MemoryOutStream stream; + stream << "Hello world"; + stream.Clear(); + CHECK_EQUAL("", stream.GetText()); } #ifndef UNITTEST_MEMORYOUTSTREAM_IS_STD_OSTRINGSTREAM @@ -155,7 +157,6 @@ TEST(StreamInitialCapacityIsMultipleOfGrowChunkSize) CHECK_EQUAL((int)MemoryOutStream::GROW_CHUNK_SIZE * 2, stream.GetCapacity()); } - TEST(ExceedingCapacityGrowsBuffer) { MemoryOutStream stream(MemoryOutStream::GROW_CHUNK_SIZE); @@ -182,14 +183,16 @@ TEST(WritingStringLongerThanCapacityFitsInNewBuffer) TEST(WritingIntLongerThanCapacityFitsInNewBuffer) { MemoryOutStream stream(8); - stream << "aaaa" << 123456;; + stream << "aaaa" << 123456; + ; CHECK_EQUAL("aaaa123456", stream.GetText()); } TEST(WritingFloatLongerThanCapacityFitsInNewBuffer) { MemoryOutStream stream(8); - stream << "aaaa" << 123456.0f;; + stream << "aaaa" << 123456.0f; + ; CHECK_EQUAL("aaaa123456.000000f", stream.GetText()); } @@ -202,4 +205,4 @@ TEST(WritingSizeTLongerThanCapacityFitsInNewBuffer) #endif -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestTest.cpp b/Release/tests/common/UnitTestpp/src/tests/TestTest.cpp index c7377b7fa9..82394d2c85 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestTest.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestTest.cpp @@ -1,79 +1,72 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" using namespace UnitTest; -namespace { - +namespace +{ TEST(PassingTestHasNoFailures) { class PassingTest : public Test { public: PassingTest() : Test("passing") {} - virtual void RunImpl() const - { - CHECK(true); - } + virtual void RunImpl() const { CHECK(true); } }; TestResults results; - { - ScopedCurrentTest scopedResults(results); - PassingTest().Run(); - } + { + ScopedCurrentTest scopedResults(results); + PassingTest().Run(); + } CHECK_EQUAL(0, results.GetFailureCount()); } - TEST(FailingTestHasFailures) { class FailingTest : public Test { public: FailingTest() : Test("failing") {} - virtual void RunImpl() const - { - CHECK(false); - } + virtual void RunImpl() const { CHECK(false); } }; TestResults results; - { - ScopedCurrentTest scopedResults(results); - FailingTest().Run(); - } + { + ScopedCurrentTest scopedResults(results); + FailingTest().Run(); + } CHECK_EQUAL(1, results.GetFailureCount()); } @@ -85,19 +78,16 @@ TEST(ThrowingTestsAreReportedAsFailures) { public: CrashingTest() : Test("throwing") {} - virtual void RunImpl() const - { - throw "Blah"; - } + virtual void RunImpl() const { throw "Blah"; } }; - + TestResults results; - { - ScopedCurrentTest scopedResult(results); - CrashingTest().Run(); - } + { + ScopedCurrentTest scopedResult(results); + CrashingTest().Run(); + } - CHECK_EQUAL(1, results.GetFailureCount()); + CHECK_EQUAL(1, results.GetFailureCount()); } /* #ifndef UNITTEST_MINGW @@ -114,12 +104,12 @@ TEST(CrashingTestsAreReportedAsFailures) }; TestResults results; - { - ScopedCurrentTest scopedResult(results); - CrashingTest().Run(); - } + { + ScopedCurrentTest scopedResult(results); + CrashingTest().Run(); + } - CHECK_EQUAL(1, results.GetFailureCount()); + CHECK_EQUAL(1, results.GetFailureCount()); } #endif */ @@ -139,20 +129,17 @@ TEST(TestReflectsSpecifiedSuiteName) CHECK_EQUAL("testSuite", test.m_details.suiteName); } -void Fail() -{ - CHECK(false); -} +void Fail() { CHECK(false); } TEST(OutOfCoreCHECKMacrosCanFailTests) { - TestResults results; - { - ScopedCurrentTest scopedResult(results); - Fail(); - } + TestResults results; + { + ScopedCurrentTest scopedResult(results); + Fail(); + } - CHECK_EQUAL(1, results.GetFailureCount()); + CHECK_EQUAL(1, results.GetFailureCount()); } -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestTestList.cpp b/Release/tests/common/UnitTestpp/src/tests/TestTestList.cpp index ddb69385d1..9987dd0e13 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestTestList.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestTestList.cpp @@ -1,41 +1,40 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" using namespace UnitTest; -namespace { - - +namespace +{ TEST(TestListIsEmptyByDefault) { TestList list; @@ -70,11 +69,11 @@ TEST(ListAdderAddsTestToList) { TestList list; - Test test(""); + Test test(""); ListAdder adder(list, &test, nullptr); CHECK(list.GetFirst() == &test); CHECK(test.m_nextTest == 0); } -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestTestMacros.cpp b/Release/tests/common/UnitTestpp/src/tests/TestTestMacros.cpp index 808d450180..6f7e415873 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestTestMacros.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestTestMacros.cpp @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" @@ -42,14 +42,12 @@ extern "C" UnitTest::TestList& UnitTest::GetTestList() } #endif -namespace { - -TestList list1; -TEST_EX(DummyTest, list1) +namespace { -} +TestList list1; +TEST_EX(DummyTest, list1) {} -TEST (TestsAreAddedToTheListThroughMacro) +TEST(TestsAreAddedToTheListThroughMacro) { CHECK(list1.GetFirst() != 0); CHECK(list1.GetFirst()->m_nextTest == 0); @@ -61,26 +59,23 @@ struct ThrowingThingie { ThrowingThingie() : dummy(false) { - if (!dummy) - throw "Oops"; + if (!dummy) throw "Oops"; } bool dummy; }; TestList list2; -TEST_FIXTURE_EX(ThrowingThingie, DummyTestName, list2) -{ -} +TEST_FIXTURE_EX(ThrowingThingie, DummyTestName, list2) {} -TEST (ExceptionsInFixtureAreReportedAsHappeningInTheFixture) +TEST(ExceptionsInFixtureAreReportedAsHappeningInTheFixture) { RecordingReporter reporter; TestResults result(&reporter); - { - ScopedCurrentTest scopedResults(result); - list2.GetFirst()->Run(); - } + { + ScopedCurrentTest scopedResults(result); + list2.GetFirst()->Run(); + } CHECK(strstr(reporter.lastFailedMessage, "xception")); CHECK(strstr(reporter.lastFailedMessage, "fixture")); @@ -97,119 +92,98 @@ struct DummyFixture // We're really testing the macros so we just want them to compile and link SUITE(TestSuite1) { - TEST(SimilarlyNamedTestsInDifferentSuitesWork) - { - } + TEST(SimilarlyNamedTestsInDifferentSuitesWork) {} - TEST_FIXTURE(DummyFixture, SimilarlyNamedFixtureTestsInDifferentSuitesWork) - { - } + TEST_FIXTURE(DummyFixture, SimilarlyNamedFixtureTestsInDifferentSuitesWork) {} } SUITE(TestSuite2) { - TEST(SimilarlyNamedTestsInDifferentSuitesWork) - { - } + TEST(SimilarlyNamedTestsInDifferentSuitesWork) {} - TEST_FIXTURE(DummyFixture,SimilarlyNamedFixtureTestsInDifferentSuitesWork) - { - } + TEST_FIXTURE(DummyFixture, SimilarlyNamedFixtureTestsInDifferentSuitesWork) {} } TestList macroTestList1; -TEST_EX(MacroTestHelper1, macroTestList1) -{ -} +TEST_EX(MacroTestHelper1, macroTestList1) {} TEST(TestAddedWithTEST_EXMacroGetsDefaultSuite) { CHECK(macroTestList1.GetFirst() != NULL); - CHECK_EQUAL ("MacroTestHelper1", macroTestList1.GetFirst()->m_details.testName); - CHECK_EQUAL ("DefaultSuite", macroTestList1.GetFirst()->m_details.suiteName); + CHECK_EQUAL("MacroTestHelper1", macroTestList1.GetFirst()->m_details.testName); + CHECK_EQUAL("DefaultSuite", macroTestList1.GetFirst()->m_details.suiteName); } TestList macroTestList2; -TEST_FIXTURE_EX(DummyFixture, MacroTestHelper2, macroTestList2) -{ -} +TEST_FIXTURE_EX(DummyFixture, MacroTestHelper2, macroTestList2) {} TEST(TestAddedWithTEST_FIXTURE_EXMacroGetsDefaultSuite) { CHECK(macroTestList2.GetFirst() != NULL); - CHECK_EQUAL ("MacroTestHelper2", macroTestList2.GetFirst()->m_details.testName); - CHECK_EQUAL ("DefaultSuite", macroTestList2.GetFirst()->m_details.suiteName); + CHECK_EQUAL("MacroTestHelper2", macroTestList2.GetFirst()->m_details.testName); + CHECK_EQUAL("DefaultSuite", macroTestList2.GetFirst()->m_details.suiteName); } #ifndef UNITTEST_NO_EXCEPTIONS struct FixtureCtorThrows { - FixtureCtorThrows() { throw "exception"; } + FixtureCtorThrows() { throw "exception"; } }; TestList throwingFixtureTestList1; -TEST_FIXTURE_EX(FixtureCtorThrows, FixtureCtorThrowsTestName, throwingFixtureTestList1) -{ -} +TEST_FIXTURE_EX(FixtureCtorThrows, FixtureCtorThrowsTestName, throwingFixtureTestList1) {} TEST(FixturesWithThrowingCtorsAreFailures) { - CHECK(throwingFixtureTestList1.GetFirst() != NULL); - RecordingReporter reporter; - TestResults result(&reporter); - { - ScopedCurrentTest scopedResult(result); - throwingFixtureTestList1.GetFirst()->Run(); - } - - int const failureCount = result.GetFailedTestCount(); - CHECK_EQUAL(1, failureCount); - CHECK(strstr(reporter.lastFailedMessage, "while constructing fixture")); + CHECK(throwingFixtureTestList1.GetFirst() != NULL); + RecordingReporter reporter; + TestResults result(&reporter); + { + ScopedCurrentTest scopedResult(result); + throwingFixtureTestList1.GetFirst()->Run(); + } + + int const failureCount = result.GetFailedTestCount(); + CHECK_EQUAL(1, failureCount); + CHECK(strstr(reporter.lastFailedMessage, "while constructing fixture")); } const int FailingLine = 123; struct FixtureCtorAsserts { - FixtureCtorAsserts() - { - UnitTest::ReportAssert("assert failure", "file", FailingLine); - } + FixtureCtorAsserts() { UnitTest::ReportAssert("assert failure", "file", FailingLine); } }; TestList ctorAssertFixtureTestList; -TEST_FIXTURE_EX(FixtureCtorAsserts, CorrectlyReportsAssertFailureInCtor, ctorAssertFixtureTestList) -{ -} +TEST_FIXTURE_EX(FixtureCtorAsserts, CorrectlyReportsAssertFailureInCtor, ctorAssertFixtureTestList) {} TEST(CorrectlyReportsFixturesWithCtorsThatAssert) { - RecordingReporter reporter; - TestResults result(&reporter); - { - ScopedCurrentTest scopedResults(result); - ctorAssertFixtureTestList.GetFirst()->Run(); - } - - const int failureCount = result.GetFailedTestCount(); - CHECK_EQUAL(1, failureCount); - CHECK_EQUAL(FailingLine, reporter.lastFailedLine); - CHECK(strstr(reporter.lastFailedMessage, "assert failure")); + RecordingReporter reporter; + TestResults result(&reporter); + { + ScopedCurrentTest scopedResults(result); + ctorAssertFixtureTestList.GetFirst()->Run(); + } + + const int failureCount = result.GetFailedTestCount(); + CHECK_EQUAL(1, failureCount); + CHECK_EQUAL(FailingLine, reporter.lastFailedLine); + CHECK(strstr(reporter.lastFailedMessage, "assert failure")); } #endif -} +} // namespace // We're really testing if it's possible to use the same suite in two files // to compile and link successfuly (TestTestSuite.cpp has suite with the same name) // Note: we are outside of the anonymous namespace SUITE(SameTestSuite) { - TEST(DummyTest1) - { - } + TEST(DummyTest1) {} } #define CUR_TEST_NAME CurrentTestDetailsContainCurrentTestInfo @@ -218,8 +192,8 @@ SUITE(SameTestSuite) TEST(CUR_TEST_NAME) { - const UnitTest::TestDetails* details = CurrentTest::Details(); - CHECK_EQUAL(STRINGIFY(CUR_TEST_NAME), details->testName); + const UnitTest::TestDetails* details = CurrentTest::Details(); + CHECK_EQUAL(STRINGIFY(CUR_TEST_NAME), details->testName); } #undef CUR_TEST_NAME diff --git a/Release/tests/common/UnitTestpp/src/tests/TestTestResults.cpp b/Release/tests/common/UnitTestpp/src/tests/TestTestResults.cpp index b63b87dee6..6609a08bb4 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestTestResults.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestTestResults.cpp @@ -1,47 +1,46 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" using namespace UnitTest; -namespace { - +namespace +{ TestDetails const g_testdetails("testname", "suitename", "filename", 123); - TEST(StartsWithNoTestsRun) { TestResults results; - CHECK_EQUAL (0, results.GetTotalTestCount()); + CHECK_EQUAL(0, results.GetTotalTestCount()); } TEST(RecordsNumbersOfTests) @@ -56,7 +55,7 @@ TEST(RecordsNumbersOfTests) TEST(StartsWithNoTestsFailing) { TestResults results; - CHECK_EQUAL (0, results.GetFailureCount()); + CHECK_EQUAL(0, results.GetFailureCount()); } TEST(RecordsNumberOfFailures) @@ -81,7 +80,7 @@ TEST(RecordsNumberOfFailedTests) results.OnTestFailure(g_testdetails, ""); results.OnTestFinish(g_testdetails, 0); - CHECK_EQUAL (2, results.GetFailedTestCount()); + CHECK_EQUAL(2, results.GetFailedTestCount()); } TEST(NotifiesReporterOfTestStartWithCorrectInfo) @@ -90,9 +89,9 @@ TEST(NotifiesReporterOfTestStartWithCorrectInfo) TestResults results(&reporter); results.OnTestStart(g_testdetails); - CHECK_EQUAL (1, reporter.testRunCount); - CHECK_EQUAL ("suitename", reporter.lastStartedSuite); - CHECK_EQUAL ("testname", reporter.lastStartedTest); + CHECK_EQUAL(1, reporter.testRunCount); + CHECK_EQUAL("suitename", reporter.lastStartedSuite); + CHECK_EQUAL("testname", reporter.lastStartedTest); } TEST(NotifiesReporterOfTestFailureWithCorrectInfo) @@ -101,12 +100,12 @@ TEST(NotifiesReporterOfTestFailureWithCorrectInfo) TestResults results(&reporter); results.OnTestFailure(g_testdetails, "failurestring"); - CHECK_EQUAL (1, reporter.testFailedCount); - CHECK_EQUAL ("filename", reporter.lastFailedFile); - CHECK_EQUAL (123, reporter.lastFailedLine); - CHECK_EQUAL ("suitename", reporter.lastFailedSuite); - CHECK_EQUAL ("testname", reporter.lastFailedTest); - CHECK_EQUAL ("failurestring", reporter.lastFailedMessage); + CHECK_EQUAL(1, reporter.testFailedCount); + CHECK_EQUAL("filename", reporter.lastFailedFile); + CHECK_EQUAL(123, reporter.lastFailedLine); + CHECK_EQUAL("suitename", reporter.lastFailedSuite); + CHECK_EQUAL("testname", reporter.lastFailedTest); + CHECK_EQUAL("failurestring", reporter.lastFailedMessage); } TEST(NotifiesReporterOfCheckFailureWithCorrectInfo) @@ -115,13 +114,13 @@ TEST(NotifiesReporterOfCheckFailureWithCorrectInfo) TestResults results(&reporter); results.OnTestFailure(g_testdetails, "failurestring"); - CHECK_EQUAL (1, reporter.testFailedCount); + CHECK_EQUAL(1, reporter.testFailedCount); - CHECK_EQUAL ("filename", reporter.lastFailedFile); - CHECK_EQUAL (123, reporter.lastFailedLine); - CHECK_EQUAL ("testname", reporter.lastFailedTest); - CHECK_EQUAL ("suitename", reporter.lastFailedSuite); - CHECK_EQUAL ("failurestring", reporter.lastFailedMessage); + CHECK_EQUAL("filename", reporter.lastFailedFile); + CHECK_EQUAL(123, reporter.lastFailedLine); + CHECK_EQUAL("testname", reporter.lastFailedTest); + CHECK_EQUAL("suitename", reporter.lastFailedSuite); + CHECK_EQUAL("failurestring", reporter.lastFailedMessage); } TEST(NotifiesReporterOfTestEnd) @@ -130,11 +129,10 @@ TEST(NotifiesReporterOfTestEnd) TestResults results(&reporter); results.OnTestFinish(g_testdetails, 0.1234f); - CHECK_EQUAL (1, reporter.testFinishedCount); - CHECK_EQUAL ("testname", reporter.lastFinishedTest); - CHECK_EQUAL ("suitename", reporter.lastFinishedSuite); - CHECK_CLOSE (0.1234f, reporter.lastFinishedTestTime, 0.0001f); + CHECK_EQUAL(1, reporter.testFinishedCount); + CHECK_EQUAL("testname", reporter.lastFinishedTest); + CHECK_EQUAL("suitename", reporter.lastFinishedSuite); + CHECK_CLOSE(0.1234f, reporter.lastFinishedTestTime, 0.0001f); } - -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestTestRunner.cpp b/Release/tests/common/UnitTestpp/src/tests/TestTestRunner.cpp index f5199a2bf9..ac9f02f007 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestTestRunner.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestTestRunner.cpp @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" @@ -37,20 +37,15 @@ using namespace UnitTest; namespace { - struct TestRunnerFixture { - TestRunnerFixture() - : runner(reporter) - { - s_testRunnerFixtureTestResults = runner.GetTestResults(); - } + TestRunnerFixture() : runner(reporter) { s_testRunnerFixtureTestResults = runner.GetTestResults(); } - static TestResults* s_testRunnerFixtureTestResults; + static TestResults* s_testRunnerFixtureTestResults; RecordingReporter reporter; TestList list; - TestRunner runner; + TestRunner runner; }; TestResults* TestRunnerFixture::s_testRunnerFixtureTestResults = NULL; @@ -58,24 +53,21 @@ TestResults* TestRunnerFixture::s_testRunnerFixtureTestResults = NULL; struct MockTest : public Test { MockTest(char const* testName, bool const success_, bool const assert_, int const count_ = 1) - : Test(testName) - , success(success_) - , asserted(assert_) - , count(count_) + : Test(testName), success(success_), asserted(assert_), count(count_) { - m_isMockTest = true; + m_isMockTest = true; } virtual void RunImpl() const { - TestResults* testResults = TestRunnerFixture::s_testRunnerFixtureTestResults; + TestResults* testResults = TestRunnerFixture::s_testRunnerFixtureTestResults; - for (int i=0; i < count; ++i) + for (int i = 0; i < count; ++i) { if (asserted) - Detail::ReportAssertEx(testResults, &m_details, "desc", "file", 0); + Detail::ReportAssertEx(testResults, &m_details, "desc", "file", 0); else if (!success) - testResults->OnTestFailure(m_details, "message"); + testResults->OnTestFailure(m_details, "message"); } } @@ -89,7 +81,7 @@ TEST_FIXTURE(TestRunnerFixture, TestStartIsReportedCorrectly) MockTest test("goodtest", true, false); list.Add(&test); - runner.RunTestsIf(list, NULL, True(), 0); + runner.RunTestsIf(list, NULL, True(), 0); CHECK_EQUAL(1, reporter.testRunCount); CHECK_EQUAL("goodtest", reporter.lastStartedTest); } @@ -99,7 +91,7 @@ TEST_FIXTURE(TestRunnerFixture, TestFinishIsReportedCorrectly) MockTest test("goodtest", true, false); list.Add(&test); - runner.RunTestsIf(list, NULL, True(), 0); + runner.RunTestsIf(list, NULL, True(), 0); CHECK_EQUAL(1, reporter.testFinishedCount); CHECK_EQUAL("goodtest", reporter.lastFinishedTest); } @@ -108,10 +100,7 @@ class SlowTest : public Test { public: SlowTest() : Test("slow", "somesuite", "filename", 123) {} - virtual void RunImpl() const - { - TimeHelpers::SleepMs(20); - } + virtual void RunImpl() const { TimeHelpers::SleepMs(20); } }; TEST_FIXTURE(TestRunnerFixture, TestFinishIsCalledWithCorrectTime) @@ -119,13 +108,13 @@ TEST_FIXTURE(TestRunnerFixture, TestFinishIsCalledWithCorrectTime) SlowTest test; list.Add(&test); - runner.RunTestsIf(list, NULL, True(), 0); + runner.RunTestsIf(list, NULL, True(), 0); CHECK(reporter.lastFinishedTestTime >= 0.005f && reporter.lastFinishedTestTime <= 0.050f); } TEST_FIXTURE(TestRunnerFixture, FailureCountIsZeroWhenNoTestsAreRun) { - CHECK_EQUAL(0, runner.RunTestsIf(list, NULL, True(), 0)); + CHECK_EQUAL(0, runner.RunTestsIf(list, NULL, True(), 0)); CHECK_EQUAL(0, reporter.testRunCount); CHECK_EQUAL(0, reporter.testFailedCount); } @@ -139,7 +128,7 @@ TEST_FIXTURE(TestRunnerFixture, CallsReportFailureOncePerFailingTest) MockTest test3("test", false, false); list.Add(&test3); - CHECK_EQUAL(2, runner.RunTestsIf(list, NULL, True(), 0)); + CHECK_EQUAL(2, runner.RunTestsIf(list, NULL, True(), 0)); CHECK_EQUAL(2, reporter.testFailedCount); } @@ -148,16 +137,16 @@ TEST_FIXTURE(TestRunnerFixture, TestsThatAssertAreReportedAsFailing) MockTest test("test", true, true); list.Add(&test); - runner.RunTestsIf(list, NULL, True(), 0); + runner.RunTestsIf(list, NULL, True(), 0); CHECK_EQUAL(1, reporter.testFailedCount); } TEST_FIXTURE(TestRunnerFixture, AssertingTestAbortsAsSoonAsAssertIsHit) { - MockTest test("test", false, true, 3); - list.Add(&test); - runner.RunTestsIf(list, NULL, True(), 0); - CHECK_EQUAL(1, reporter.summaryFailureCount); + MockTest test("test", false, true, 3); + list.Add(&test); + runner.RunTestsIf(list, NULL, True(), 0); + CHECK_EQUAL(1, reporter.summaryFailureCount); } TEST_FIXTURE(TestRunnerFixture, ReporterNotifiedOfTestCount) @@ -169,7 +158,7 @@ TEST_FIXTURE(TestRunnerFixture, ReporterNotifiedOfTestCount) list.Add(&test2); list.Add(&test3); - runner.RunTestsIf(list, NULL, True(), 0); + runner.RunTestsIf(list, NULL, True(), 0); CHECK_EQUAL(3, reporter.summaryTotalTestCount); } @@ -182,7 +171,7 @@ TEST_FIXTURE(TestRunnerFixture, ReporterNotifiedOfFailedTests) list.Add(&test2); list.Add(&test3); - runner.RunTestsIf(list, NULL, True(), 0); + runner.RunTestsIf(list, NULL, True(), 0); CHECK_EQUAL(2, reporter.summaryFailedTestCount); } @@ -195,8 +184,8 @@ TEST_FIXTURE(TestRunnerFixture, ReporterNotifiedOfFailures) list.Add(&test2); list.Add(&test3); - runner.RunTestsIf(list, NULL, True(), 0); - CHECK_EQUAL(5, reporter.summaryFailureCount); + runner.RunTestsIf(list, NULL, True(), 0); + CHECK_EQUAL(5, reporter.summaryFailureCount); } TEST_FIXTURE(TestRunnerFixture, SlowTestPassesForHighTimeThreshold) @@ -204,7 +193,7 @@ TEST_FIXTURE(TestRunnerFixture, SlowTestPassesForHighTimeThreshold) SlowTest test; list.Add(&test); - runner.RunTestsIf(list, NULL, True(), 0); + runner.RunTestsIf(list, NULL, True(), 0); CHECK_EQUAL(0, reporter.testFailedCount); } @@ -214,7 +203,7 @@ struct TestSuiteFixture : test1("TestInDefaultSuite") , test2("TestInOtherSuite", "OtherSuite") , test3("SecondTestInDefaultSuite") - , runner(reporter) + , runner(reporter) { list.Add(&test1); list.Add(&test2); @@ -225,47 +214,44 @@ struct TestSuiteFixture Test test3; RecordingReporter reporter; TestList list; - TestRunner runner; + TestRunner runner; }; TEST_FIXTURE(TestSuiteFixture, TestRunnerRunsAllSuitesIfNullSuiteIsPassed) { - runner.RunTestsIf(list, NULL, True(), 0); + runner.RunTestsIf(list, NULL, True(), 0); CHECK_EQUAL(2, reporter.summaryTotalTestCount); } -TEST_FIXTURE(TestSuiteFixture,TestRunnerRunsOnlySpecifiedSuite) +TEST_FIXTURE(TestSuiteFixture, TestRunnerRunsOnlySpecifiedSuite) { - runner.RunTestsIf(list, "OtherSuite", True(), 0); + runner.RunTestsIf(list, "OtherSuite", True(), 0); CHECK_EQUAL(1, reporter.summaryTotalTestCount); CHECK_EQUAL("TestInOtherSuite", reporter.lastFinishedTest); } struct RunTestIfNameIs { - RunTestIfNameIs(char const* name_) - : name(name_) - { - } - - bool operator()(const Test* const test) const - { - using namespace std; - return (0 == strcmp(test->m_details.testName, name)); - } - - char const* name; + RunTestIfNameIs(char const* name_) : name(name_) {} + + bool operator()(const Test* const test) const + { + using namespace std; + return (0 == strcmp(test->m_details.testName, name)); + } + + char const* name; }; TEST(TestMockPredicateBehavesCorrectly) { - RunTestIfNameIs predicate("pass"); - - Test pass("pass"); - Test fail("fail"); - - CHECK(predicate(&pass)); - CHECK(!predicate(&fail)); + RunTestIfNameIs predicate("pass"); + + Test pass("pass"); + Test fail("fail"); + + CHECK(predicate(&pass)); + CHECK(!predicate(&fail)); } TEST_FIXTURE(TestRunnerFixture, TestRunnerRunsTestsThatPassPredicate) @@ -274,10 +260,10 @@ TEST_FIXTURE(TestRunnerFixture, TestRunnerRunsTestsThatPassPredicate) list.Add(&should_run); Test should_not_run("badtest"); - list.Add(&should_not_run); - - runner.RunTestsIf(list, NULL, RunTestIfNameIs("goodtest"), 0); - CHECK_EQUAL(1, reporter.testRunCount); + list.Add(&should_not_run); + + runner.RunTestsIf(list, NULL, RunTestIfNameIs("goodtest"), 0); + CHECK_EQUAL(1, reporter.testRunCount); CHECK_EQUAL("goodtest", reporter.lastStartedTest); } @@ -287,17 +273,17 @@ TEST_FIXTURE(TestRunnerFixture, TestRunnerOnlyRunsTestsInSpecifiedSuiteAndThatPa Test skippedTest2("goodtest"); Test skippedTest3("badtest", "suite"); Test skippedTest4("badtest"); - + list.Add(&runningTest1); list.Add(&skippedTest2); list.Add(&skippedTest3); - list.Add(&skippedTest4); + list.Add(&skippedTest4); - runner.RunTestsIf(list, "suite", RunTestIfNameIs("goodtest"), 0); + runner.RunTestsIf(list, "suite", RunTestIfNameIs("goodtest"), 0); - CHECK_EQUAL(1, reporter.testRunCount); - CHECK_EQUAL("goodtest", reporter.lastStartedTest); - CHECK_EQUAL("suite", reporter.lastStartedSuite); + CHECK_EQUAL(1, reporter.testRunCount); + CHECK_EQUAL("goodtest", reporter.lastStartedTest); + CHECK_EQUAL("suite", reporter.lastStartedSuite); } -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestTestSuite.cpp b/Release/tests/common/UnitTestpp/src/tests/TestTestSuite.cpp index 3b904a5743..ba97d9de64 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestTestSuite.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestTestSuite.cpp @@ -1,33 +1,33 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" @@ -36,8 +36,5 @@ // Note: we are outside of the anonymous namespace SUITE(SameTestSuite) { - TEST(DummyTest2) - { - } + TEST(DummyTest2) {} } - diff --git a/Release/tests/common/UnitTestpp/src/tests/TestUnitTestPP.cpp b/Release/tests/common/UnitTestpp/src/tests/TestUnitTestPP.cpp index 70c12be791..ac4cf66f16 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestUnitTestPP.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestUnitTestPP.cpp @@ -1,40 +1,40 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" // These are sample tests that show the different features of the framework -namespace { - +namespace +{ TEST(ValidCheckSucceeds) { bool const b = true; @@ -43,7 +43,7 @@ TEST(ValidCheckSucceeds) TEST(CheckWorksWithPointers) { - void* p = (void *)0x100; + void* p = (void*)0x100; CHECK(p); CHECK(p != 0); } @@ -57,7 +57,7 @@ TEST(ValidCheckEqualSucceeds) TEST(CheckEqualWorksWithPointers) { - void* p = (void *)0; + void* p = (void*)0; CHECK_EQUAL((void*)0, p); } @@ -78,14 +78,13 @@ TEST(ArrayCloseSucceeds) TEST(CheckThrowMacroSucceedsOnCorrectException) { - struct TestException {}; + struct TestException + { + }; CHECK_THROW(throw TestException(), TestException); } -TEST(CheckAssertSucceeds) -{ - CHECK_ASSERT(UnitTest::ReportAssert("desc", "file", 0)); -} +TEST(CheckAssertSucceeds) { CHECK_ASSERT(UnitTest::ReportAssert("desc", "file", 0)); } TEST(CheckThrowMacroFailsOnMissingException) { @@ -93,25 +92,20 @@ TEST(CheckThrowMacroFailsOnMissingException) { public: NoThrowTest() : Test("nothrow") {} - void DontThrow() const - { - } - - virtual void RunImpl() const - { - CHECK_THROW(DontThrow(), int); - } + void DontThrow() const {} + + virtual void RunImpl() const { CHECK_THROW(DontThrow(), int); } }; UnitTest::TestResults results; - { - ScopedCurrentTest scopedResults(results); + { + ScopedCurrentTest scopedResults(results); - NoThrowTest test; - test.Run(); - } + NoThrowTest test; + test.Run(); + } - CHECK_EQUAL(1, results.GetFailureCount()); + CHECK_EQUAL(1, results.GetFailureCount()); } TEST(CheckThrowMacroFailsOnWrongException) @@ -120,59 +114,38 @@ TEST(CheckThrowMacroFailsOnWrongException) { public: WrongThrowTest() : Test("wrongthrow") {} - virtual void RunImpl() const - { - CHECK_THROW(throw "oops", int); - } + virtual void RunImpl() const { CHECK_THROW(throw "oops", int); } }; UnitTest::TestResults results; - { - ScopedCurrentTest scopedResults(results); + { + ScopedCurrentTest scopedResults(results); - WrongThrowTest test; - test.Run(); - } + WrongThrowTest test; + test.Run(); + } - CHECK_EQUAL(1, results.GetFailureCount()); + CHECK_EQUAL(1, results.GetFailureCount()); } #endif struct SimpleFixture { - SimpleFixture() - { - ++instanceCount; - } - ~SimpleFixture() - { - --instanceCount; - } + SimpleFixture() { ++instanceCount; } + ~SimpleFixture() { --instanceCount; } static int instanceCount; }; int SimpleFixture::instanceCount = 0; -TEST_FIXTURE(SimpleFixture, DefaultFixtureCtorIsCalled) -{ - CHECK(SimpleFixture::instanceCount > 0); -} +TEST_FIXTURE(SimpleFixture, DefaultFixtureCtorIsCalled) { CHECK(SimpleFixture::instanceCount > 0); } -TEST_FIXTURE(SimpleFixture, OnlyOneFixtureAliveAtATime) -{ - CHECK_EQUAL(1, SimpleFixture::instanceCount); -} +TEST_FIXTURE(SimpleFixture, OnlyOneFixtureAliveAtATime) { CHECK_EQUAL(1, SimpleFixture::instanceCount); } -void CheckBool(const bool b) -{ - CHECK(b); -} +void CheckBool(const bool b) { CHECK(b); } -TEST(CanCallCHECKOutsideOfTestFunction) -{ - CheckBool(true); -} +TEST(CanCallCHECKOutsideOfTestFunction) { CheckBool(true); } -} +} // namespace diff --git a/Release/tests/common/UnitTestpp/src/tests/TestXmlTestReporter.cpp b/Release/tests/common/UnitTestpp/src/tests/TestXmlTestReporter.cpp index 5022c9ba49..de78002f59 100644 --- a/Release/tests/common/UnitTestpp/src/tests/TestXmlTestReporter.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/TestXmlTestReporter.cpp @@ -1,40 +1,39 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #include "stdafx.h" #ifndef UNITTEST_NO_DEFERRED_REPORTER #include "../XmlTestReporter.h" - #include using namespace UnitTest; @@ -42,7 +41,6 @@ using std::ostringstream; namespace { - #ifndef UNITTEST_MEMORYOUTSTREAM_IS_STD_OSTRINGSTREAM // Overload to let MemoryOutStream accept std::string @@ -56,10 +54,7 @@ MemoryOutStream& operator<<(MemoryOutStream& s, const std::string& value) struct XmlTestReporterFixture { - XmlTestReporterFixture() - : reporter(output) - { - } + XmlTestReporterFixture() : reporter(output) {} ostringstream output; XmlTestReporter reporter; @@ -74,14 +69,13 @@ TEST_FIXTURE(XmlTestReporterFixture, MultipleCharactersAreEscaped) reporter.ReportTestFinish(details, false, 0.1f); reporter.ReportSummary(1, 2, 3, 0.1f); - char const* expected = - "" - "" - "" - "" - "" - ""; + char const* expected = "" + "" + "" + "" + "" + ""; CHECK_EQUAL(expected, output.str()); } @@ -103,10 +97,9 @@ TEST_FIXTURE(XmlTestReporterFixture, EmptyReportSummaryFormat) { reporter.ReportSummary(0, 0, 0, 0.1f); - const char *expected = - "" - "" - ""; + const char* expected = "" + "" + ""; CHECK_EQUAL(expected, output.str()); } @@ -118,11 +111,10 @@ TEST_FIXTURE(XmlTestReporterFixture, SingleSuccessfulTestReportSummaryFormat) reporter.ReportTestStart(details); reporter.ReportSummary(1, 0, 0, 0.1f); - const char *expected = - "" - "" - "" - ""; + const char* expected = "" + "" + "" + ""; CHECK_EQUAL(expected, output.str()); } @@ -135,13 +127,12 @@ TEST_FIXTURE(XmlTestReporterFixture, SingleFailedTestReportSummaryFormat) reporter.ReportFailure(details, "A Failure"); reporter.ReportSummary(1, 1, 1, 0.1f); - const char *expected = - "" - "" - "" - "" - "" - ""; + const char* expected = "" + "" + "" + "" + "" + ""; CHECK_EQUAL(expected, output.str()); } @@ -155,13 +146,12 @@ TEST_FIXTURE(XmlTestReporterFixture, FailureMessageIsXMLEscaped) reporter.ReportTestFinish(details, false, 0.1f); reporter.ReportSummary(1, 1, 1, 0.1f); - char const* expected = - "" - "" - "" - "" - "" - ""; + char const* expected = "" + "" + "" + "" + "" + ""; CHECK_EQUAL(expected, output.str()); } @@ -178,14 +168,13 @@ TEST_FIXTURE(XmlTestReporterFixture, OneFailureAndOneSuccess) reporter.ReportTestFinish(succeededDetails, true, 1.0f); reporter.ReportSummary(2, 1, 1, 1.1f); - char const* expected = - "" - "" - "" - "" - "" - "" - ""; + char const* expected = "" + "" + "" + "" + "" + "" + ""; CHECK_EQUAL(expected, output.str()); } @@ -202,18 +191,17 @@ TEST_FIXTURE(XmlTestReporterFixture, MultipleFailures) reporter.ReportSummary(1, 1, 2, 1.1f); - char const* expected = - "" - "" - "" - "" - "" - "" - ""; + char const* expected = "" + "" + "" + "" + "" + "" + ""; CHECK_EQUAL(expected, output.str()); } -} +} // namespace #endif diff --git a/Release/tests/common/UnitTestpp/src/tests/stdafx.cpp b/Release/tests/common/UnitTestpp/src/tests/stdafx.cpp index dc9c392b64..82fd96b55e 100644 --- a/Release/tests/common/UnitTestpp/src/tests/stdafx.cpp +++ b/Release/tests/common/UnitTestpp/src/tests/stdafx.cpp @@ -1,35 +1,35 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ -// stdafx.cpp : +// stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/src/tests/stdafx.h b/Release/tests/common/UnitTestpp/src/tests/stdafx.h index 6fa6382215..cd587ddd7a 100644 --- a/Release/tests/common/UnitTestpp/src/tests/stdafx.h +++ b/Release/tests/common/UnitTestpp/src/tests/stdafx.h @@ -1,48 +1,45 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #pragma once #include "../../config.h" #include "../../unittestpp.h" - -#include "../TestMacros.h" #include "../CurrentTest.h" +#include "../ReportAssert.h" +#include "../ReportAssertImpl.h" +#include "../TestMacros.h" #include "../TestReporter.h" #include "../TestResults.h" -#include "../ReportAssert.h" #include "../TimeHelpers.h" -#include "../ReportAssertImpl.h" - -#include "ScopedCurrentTest.h" #include "RecordingReporter.h" - +#include "ScopedCurrentTest.h" #include \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/unittestpp.h b/Release/tests/common/UnitTestpp/unittestpp.h index 6cd7601d1e..9df892e7d5 100644 --- a/Release/tests/common/UnitTestpp/unittestpp.h +++ b/Release/tests/common/UnitTestpp/unittestpp.h @@ -1,42 +1,42 @@ /*** -* This file is based on or incorporates material from the UnitTest++ r30 open source project. -* Microsoft is not the original author of this code but has modified it and is licensing the code under -* the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, -* whether by implication, estoppel or otherwise. -* -* UnitTest++ r30 -* -* Copyright (c) 2006 Noel Llopis and Charles Nicholson -* Portions Copyright (c) Microsoft Corporation -* -* All Rights Reserved. -* -* MIT License -* -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software -* and associated documentation files (the "Software"), to deal in the Software without restriction, -* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -* subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all copies or -* substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE -* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -***/ + * This file is based on or incorporates material from the UnitTest++ r30 open source project. + * Microsoft is not the original author of this code but has modified it and is licensing the code under + * the MIT License. Microsoft reserves all other rights not expressly granted under the MIT License, + * whether by implication, estoppel or otherwise. + * + * UnitTest++ r30 + * + * Copyright (c) 2006 Noel Llopis and Charles Nicholson + * Portions Copyright (c) Microsoft Corporation + * + * All Rights Reserved. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ***/ #ifndef UNITTESTPP_H #define UNITTESTPP_H #include "config.h" -#include "src/TestMacros.h" #include "src/CheckMacros.h" -#include "src/TestRunner.h" -#include "src/ReportAssert.h" #include "src/GlobalSettings.h" +#include "src/ReportAssert.h" +#include "src/TestMacros.h" +#include "src/TestRunner.h" #endif diff --git a/Release/tests/common/utilities/include/common_utilities_public.h b/Release/tests/common/utilities/include/common_utilities_public.h index f8f8705174..67abfb8fb4 100644 --- a/Release/tests/common/utilities/include/common_utilities_public.h +++ b/Release/tests/common/utilities/include/common_utilities_public.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* common_utilities.h -- Common definitions for public test utility headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * common_utilities.h -- Common definitions for public test utility headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once diff --git a/Release/tests/common/utilities/include/locale_guard.h b/Release/tests/common/utilities/include/locale_guard.h index 04d528b6a4..ea3eeb89cf 100644 --- a/Release/tests/common/utilities/include/locale_guard.h +++ b/Release/tests/common/utilities/include/locale_guard.h @@ -1,33 +1,34 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Defines an RAII container for setting global locale. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Defines an RAII container for setting global locale. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include -namespace tests { namespace common { namespace utilities { - +namespace tests +{ +namespace common +{ +namespace utilities +{ class locale_guard { public: - locale_guard(std::locale const &loc) - { - m_prev = std::locale::global(loc); - } - ~locale_guard() - { - std::locale::global(m_prev); - } + locale_guard(std::locale const& loc) { m_prev = std::locale::global(loc); } + ~locale_guard() { std::locale::global(m_prev); } + private: std::locale m_prev; - locale_guard(locale_guard const &); - locale_guard & operator=(locale_guard const &); + locale_guard(locale_guard const&); + locale_guard& operator=(locale_guard const&); }; -}}} \ No newline at end of file +} // namespace utilities +} // namespace common +} // namespace tests diff --git a/Release/tests/common/utilities/include/os_utilities.h b/Release/tests/common/utilities/include/os_utilities.h index 465524af52..51f103b88b 100644 --- a/Release/tests/common/utilities/include/os_utilities.h +++ b/Release/tests/common/utilities/include/os_utilities.h @@ -1,36 +1,40 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* os_utilities.h - defines an abstraction for common OS functions like Sleep, hiding the underlying platform. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * os_utilities.h - defines an abstraction for common OS functions like Sleep, hiding the underlying platform. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "common_utilities_public.h" #include "cpprest/details/cpprest_compat.h" -namespace tests { namespace common { namespace utilities { - +namespace tests +{ +namespace common +{ +namespace utilities +{ class os_utilities { public: - static TEST_UTILITY_API void __cdecl sleep(unsigned long ms); // Could use std::atomics but VS 2010 doesn't support it yet. - static TEST_UTILITY_API unsigned long __cdecl interlocked_increment(volatile unsigned long *addend); - static TEST_UTILITY_API long __cdecl interlocked_exchange(volatile long *target, long value); + static TEST_UTILITY_API unsigned long __cdecl interlocked_increment(volatile unsigned long* addend); + static TEST_UTILITY_API long __cdecl interlocked_exchange(volatile long* target, long value); private: os_utilities(); - os_utilities(const os_utilities &); - os_utilities & operator=(const os_utilities &); + os_utilities(const os_utilities&); + os_utilities& operator=(const os_utilities&); }; -}}} - +} // namespace utilities +} // namespace common +} // namespace tests diff --git a/Release/tests/common/utilities/os_utilities.cpp b/Release/tests/common/utilities/os_utilities.cpp index 0e318e8069..de2a06d9fb 100644 --- a/Release/tests/common/utilities/os_utilities.cpp +++ b/Release/tests/common/utilities/os_utilities.cpp @@ -1,37 +1,42 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* os_utilities.cpp - defines an abstraction for common OS functions like Sleep, hiding the underlying platform. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * os_utilities.cpp - defines an abstraction for common OS functions like Sleep, hiding the underlying platform. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "os_utilities.h" #ifdef WIN32 #define NOMINMAX -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include + #include #else #include #endif -namespace tests { namespace common { namespace utilities { - +namespace tests +{ +namespace common +{ +namespace utilities +{ void os_utilities::sleep(unsigned long ms) { #ifdef WIN32 Sleep(ms); #else - usleep(ms*1000); + usleep(ms * 1000); #endif } -unsigned long os_utilities::interlocked_increment(volatile unsigned long *addend) +unsigned long os_utilities::interlocked_increment(volatile unsigned long* addend) { #ifdef WIN32 return InterlockedIncrement(addend); @@ -42,7 +47,7 @@ unsigned long os_utilities::interlocked_increment(volatile unsigned long *addend #endif } -long os_utilities::interlocked_exchange(volatile long *target, long value) +long os_utilities::interlocked_exchange(volatile long* target, long value) { #ifdef WIN32 return InterlockedExchange(target, value); @@ -53,4 +58,6 @@ long os_utilities::interlocked_exchange(volatile long *target, long value) #endif } -}}} +} // namespace utilities +} // namespace common +} // namespace tests diff --git a/Release/tests/functional/http/client/authentication_tests.cpp b/Release/tests/functional/http/client/authentication_tests.cpp index c58ca1c90c..c0440fed24 100644 --- a/Release/tests/functional/http/client/authentication_tests.cpp +++ b/Release/tests/functional/http/client/authentication_tests.cpp @@ -1,15 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases for authentication with http_clients. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases for authentication with http_clients. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include #ifdef _WIN32 @@ -17,10 +18,11 @@ #if !defined(__WRL_NO_DEFAULT_LIB__) #define __WRL_NO_DEFAULT_LIB__ #endif -#include #include +#include #else #include + #include #pragma comment(lib, "winhttp") #endif @@ -46,162 +48,143 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(authentication_tests) +namespace tests { - -TEST_FIXTURE(uri_address, auth_no_data, "Ignore:Linux", "89", "Ignore:Apple", "89") +namespace functional +{ +namespace http { - pplx::task t, t2; +namespace client +{ +SUITE(authentication_tests) +{ + TEST_FIXTURE(uri_address, auth_no_data, "Ignore:Linux", "89", "Ignore:Apple", "89") { - test_http_server::scoped_server scoped(m_uri); - http_client_config client_config; - web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password - client_config.set_credentials(cred); - http_client client(m_uri, client_config); - const method mtd = methods::POST; - - http_request msg(mtd); - - t = scoped.server()->next_request().then([&](test_request *p_request) + pplx::task t, t2; { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - - // Auth header - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - - // unauthorized - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - - }); - t2 = scoped.server()->next_request().then([&](test_request *p_request) + test_http_server::scoped_server scoped(m_uri); + http_client_config client_config; + web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password + client_config.set_credentials(cred); + http_client client(m_uri, client_config); + const method mtd = methods::POST; + + http_request msg(mtd); + + t = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + + // Auth header + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + + // unauthorized + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + }); + t2 = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); + p_request->reply(200); + }); + + try + { + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + catch (...) + { + VERIFY_ARE_EQUAL(0, 1); + } + } + try { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); - p_request->reply(200); - }); - + t.get(); + } + catch (...) + { + VERIFY_ARE_EQUAL(0, 1); + } try { - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + t2.get(); } catch (...) { VERIFY_ARE_EQUAL(0, 1); } } - try { t.get(); } - catch (...) { VERIFY_ARE_EQUAL(0, 1); } - try { t2.get(); } - catch (...) { VERIFY_ARE_EQUAL(0, 1); } -} // TFS 648783 #ifndef __cplusplus_winrt -TEST_FIXTURE(uri_address, proxy_auth_known_contentlength, "Ignore:Linux", "88", "Ignore:Apple", "88") -{ - pplx::task t, t2; + TEST_FIXTURE(uri_address, proxy_auth_known_contentlength, "Ignore:Linux", "88", "Ignore:Apple", "88") { - test_http_server::scoped_server scoped(m_uri); - http_client_config client_config; - web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password - client_config.set_credentials(cred); - http_client client(m_uri, client_config); - const method mtd = methods::POST; - utility::string_t contents(U("Hello World")); - - http_request msg(mtd); - msg.set_body(contents); - - t = scoped.server()->next_request().then([&](test_request *p_request) + pplx::task t, t2; { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + test_http_server::scoped_server scoped(m_uri); + http_client_config client_config; + web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password + client_config.set_credentials(cred); + http_client client(m_uri, client_config); + const method mtd = methods::POST; + utility::string_t contents(U("Hello World")); - // Auth header - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + http_request msg(mtd); + msg.set_body(contents); - // unauthorized - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + t = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - }); + // Auth header + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - t2 = scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("text/plain; charset=utf-8"), contents); + // unauthorized + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + }); - p_request->reply(200); - }); + t2 = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::POST, U("/"), U("text/plain; charset=utf-8"), contents); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + p_request->reply(200); + }); + + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + try + { + t.get(); + } + catch (...) + { + VERIFY_ARE_EQUAL(0, 1); + } + try + { + t2.get(); + } + catch (...) + { + VERIFY_ARE_EQUAL(0, 1); + } } - try { t.get(); } - catch (...) { VERIFY_ARE_EQUAL(0, 1); } - try { t2.get(); } - catch (...) { VERIFY_ARE_EQUAL(0, 1); } -} #endif -TEST_FIXTURE(uri_address, proxy_auth_noseek, "Ignore:Linux", "88", "Ignore:Apple", "88") -{ - web::http::uri uri(U("http://localhost:34567/")); - test_http_server::scoped_server scoped(uri); - http_client client(uri); // In this test, the request cannot be resent, so the username and password are not required - const method mtd = methods::POST; - - auto buf = streams::producer_consumer_buffer(); - buf.putc('a').get(); - buf.close(std::ios_base::out).get(); - - http_request msg(mtd); - msg.set_body(buf.create_istream(), 1); - - scoped.server()->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, proxy_auth_noseek, "Ignore:Linux", "88", "Ignore:Apple", "88") { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - - // Auth header - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - - // unauthorized - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - - }); - - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); -} - -// Must specify content length with winrt client, so this test case isn't possible. -#ifndef __cplusplus_winrt -TEST_FIXTURE(uri_address, proxy_auth_unknown_contentlength, "Ignore:Linux", "88", "Ignore:Apple", "88") -{ - pplx::task t; - { - test_http_server::scoped_server scoped(m_uri); - http_client_config client_config; - web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password - client_config.set_credentials(cred); - http_client client(m_uri, client_config); + web::http::uri uri(U("http://localhost:34567/")); + test_http_server::scoped_server scoped(uri); + http_client client( + uri); // In this test, the request cannot be resent, so the username and password are not required const method mtd = methods::POST; - std::vector msg_body; - msg_body.push_back('a'); + auto buf = streams::producer_consumer_buffer(); + buf.putc('a').get(); + buf.close(std::ios_base::out).get(); http_request msg(mtd); - msg.set_body(streams::container_stream>::open_istream(std::move(msg_body))); - - auto replyFunc = [&](test_request *p_request) - { - utility::string_t contents(U("a")); - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), contents); + msg.set_body(buf.create_istream(), 1); - p_request->reply(200); - }; - - t = scoped.server()->next_request().then([&](test_request *p_request) - { + scoped.server()->next_request().then([&](test_request* p_request) { http_asserts::assert_test_request_equals(p_request, mtd, U("/")); // Auth header @@ -210,513 +193,533 @@ TEST_FIXTURE(uri_address, proxy_auth_unknown_contentlength, "Ignore:Linux", "88" // unauthorized p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - - }).then([&scoped, replyFunc]() - { - // Client resent the request - return scoped.server()->next_request().then(replyFunc); }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); } - t.get(); -} - -// Accessing a server that returns 401 with an empty user name should not resend the request with an empty password -TEST_FIXTURE(uri_address, empty_username_password) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - auto t = scoped.server()->next_request().then([&](test_request *p_request) +// Must specify content length with winrt client, so this test case isn't possible. +#ifndef __cplusplus_winrt + TEST_FIXTURE(uri_address, proxy_auth_unknown_contentlength, "Ignore:Linux", "88", "Ignore:Apple", "88") { - std::map headers; - headers[U("h1")] = U("data1"); - // Auth header - headers[U("WWW-Authenticate")] = U("Basic realm = \"myRealm\""); - // unauthorized - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "a" ); - }); - - http_response response = client.request(methods::GET).get(); - auto str_body = response.extract_vector().get(); - auto h1 = response.headers()[U("h1")]; - VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); - VERIFY_ARE_EQUAL(str_body[0], 'a'); - VERIFY_ARE_EQUAL(h1, U("data1")); - t.get(); -} -#endif + pplx::task t; + { + test_http_server::scoped_server scoped(m_uri); + http_client_config client_config; + web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password + client_config.set_credentials(cred); + http_client client(m_uri, client_config); + const method mtd = methods::POST; + + std::vector msg_body; + msg_body.push_back('a'); + + http_request msg(mtd); + msg.set_body(streams::container_stream>::open_istream(std::move(msg_body))); + + auto replyFunc = [&](test_request* p_request) { + utility::string_t contents(U("a")); + http_asserts::assert_test_request_equals( + p_request, methods::POST, U("/"), U("application/octet-stream"), contents); + + p_request->reply(200); + }; + + t = scoped.server() + ->next_request() + .then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + + // Auth header + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + + // unauthorized + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + }) + .then([&scoped, replyFunc]() { + // Client resent the request + return scoped.server()->next_request().then(replyFunc); + }); -// Fails on WinRT due to TFS 648278 -// Accessing a server that supports auth, but returns 401, even after the user has provided valid creds -// We're making sure the error is reported properly, and the response data from the second response is received -TEST_FIXTURE(uri_address, error_after_valid_credentials, "Ignore:Linux", "89", "Ignore:Apple", "89") -{ - pplx::task t; - { - web::http::uri uri(U("http://localhost:34569/")); - test_http_server::scoped_server scoped(uri); - http_client_config client_config; - web::credentials cred(U("some_user"), U("some_password")); - client_config.set_credentials(cred); - http_client client(uri, client_config); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + t.get(); + } - auto replyFunc = [&](test_request *p_request) - { - std::map headers; - // Auth header - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - headers[U("h1")] = U("data2"); - // still unauthorized after the user has resent the request with the credentials - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "def"); - }; + // Accessing a server that returns 401 with an empty user name should not resend the request with an empty password + TEST_FIXTURE(uri_address, empty_username_password) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); - t = scoped.server()->next_request().then([&](test_request *p_request) - { + auto t = scoped.server()->next_request().then([&](test_request* p_request) { std::map headers; headers[U("h1")] = U("data1"); // Auth header headers[U("WWW-Authenticate")] = U("Basic realm = \"myRealm\""); // unauthorized - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "abc"); - }).then([&scoped, &replyFunc]() - { - // Client resent the request - return scoped.server()->next_request().then(replyFunc); - }) -#ifdef __cplusplus_winrt - .then([&scoped, &replyFunc]() - { - // in winrt, client resent the request again - return scoped.server()->next_request().then(replyFunc); - }) -#endif - ; + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "a"); + }); http_response response = client.request(methods::GET).get(); auto str_body = response.extract_vector().get(); auto h1 = response.headers()[U("h1")]; VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); - VERIFY_ARE_EQUAL(str_body[0], 'd'); - VERIFY_ARE_EQUAL(str_body[1], 'e'); - VERIFY_ARE_EQUAL(str_body[2], 'f'); - VERIFY_ARE_EQUAL(h1, U("data2")); + VERIFY_ARE_EQUAL(str_body[0], 'a'); + VERIFY_ARE_EQUAL(h1, U("data1")); + t.get(); } - t.get(); -} - - -// These tests are disabled since they require a server with authentication running. -// The server portion to use is the C# AuthenticationListener. - -class server_properties -{ -public: - server_properties() {} +#endif - // Helper function to retrieve all parameters necessary for setup tests. - void load_parameters() + // Fails on WinRT due to TFS 648278 + // Accessing a server that supports auth, but returns 401, even after the user has provided valid creds + // We're making sure the error is reported properly, and the response data from the second response is received + TEST_FIXTURE(uri_address, error_after_valid_credentials, "Ignore:Linux", "89", "Ignore:Apple", "89") { - m_uri = uri(utility::conversions::to_string_t(UnitTest::GlobalSettings::Get("Server"))); - if(UnitTest::GlobalSettings::Has("UserName")) + pplx::task t; { - m_username = utility::conversions::to_string_t(UnitTest::GlobalSettings::Get("UserName")); + web::http::uri uri(U("http://localhost:34569/")); + test_http_server::scoped_server scoped(uri); + http_client_config client_config; + web::credentials cred(U("some_user"), U("some_password")); + client_config.set_credentials(cred); + http_client client(uri, client_config); + + auto replyFunc = [&](test_request* p_request) { + std::map headers; + // Auth header + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + headers[U("h1")] = U("data2"); + // still unauthorized after the user has resent the request with the credentials + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "def"); + }; + + t = scoped.server() + ->next_request() + .then([&](test_request* p_request) { + std::map headers; + headers[U("h1")] = U("data1"); + // Auth header + headers[U("WWW-Authenticate")] = U("Basic realm = \"myRealm\""); + // unauthorized + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "abc"); + }) + .then([&scoped, &replyFunc]() { + // Client resent the request + return scoped.server()->next_request().then(replyFunc); + }) +#ifdef __cplusplus_winrt + .then([&scoped, &replyFunc]() { + // in winrt, client resent the request again + return scoped.server()->next_request().then(replyFunc); + }) +#endif + ; + + http_response response = client.request(methods::GET).get(); + auto str_body = response.extract_vector().get(); + auto h1 = response.headers()[U("h1")]; + VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); + VERIFY_ARE_EQUAL(str_body[0], 'd'); + VERIFY_ARE_EQUAL(str_body[1], 'e'); + VERIFY_ARE_EQUAL(str_body[2], 'f'); + VERIFY_ARE_EQUAL(h1, U("data2")); } - if(UnitTest::GlobalSettings::Has("Password")) + t.get(); + } + + // These tests are disabled since they require a server with authentication running. + // The server portion to use is the C# AuthenticationListener. + + class server_properties + { + public: + server_properties() {} + + // Helper function to retrieve all parameters necessary for setup tests. + void load_parameters() { - m_password = utility::conversions::to_string_t(UnitTest::GlobalSettings::Get("Password")); + m_uri = uri(utility::conversions::to_string_t(UnitTest::GlobalSettings::Get("Server"))); + if (UnitTest::GlobalSettings::Has("UserName")) + { + m_username = utility::conversions::to_string_t(UnitTest::GlobalSettings::Get("UserName")); + } + if (UnitTest::GlobalSettings::Has("Password")) + { + m_password = utility::conversions::to_string_t(UnitTest::GlobalSettings::Get("Password")); + } } + + web::http::uri m_uri; + string_t m_username; + string_t m_password; + }; + + // This test should be executed for NTLM, Negotiate, IntegratedWindowsAuth, and Anonymous. + TEST_FIXTURE(server_properties, successful_auth_no_cred, "Requires", "Server") + { + load_parameters(); + + http_client client(m_uri); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); } - web::http::uri m_uri; - string_t m_username; - string_t m_password; -}; + TEST_FIXTURE(server_properties, digest_basic_auth_no_cred, "Requires", "Server") + { + load_parameters(); -// This test should be executed for NTLM, Negotiate, IntegratedWindowsAuth, and Anonymous. -TEST_FIXTURE(server_properties, successful_auth_no_cred, "Requires", "Server") -{ - load_parameters(); + http_client client(m_uri); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); + } - http_client client(m_uri); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); -} + TEST_FIXTURE(server_properties, none_auth_no_cred, "Requires", "Server") + { + load_parameters(); -TEST_FIXTURE(server_properties, digest_basic_auth_no_cred, "Requires", "Server") -{ - load_parameters(); + http_client client(m_uri); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::Forbidden, response.status_code()); + } - http_client client(m_uri); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); -} + // This test should be executed for NTLM, Negotiate, IntegratedWindowsAuth, and Digest. + TEST_FIXTURE(server_properties, unsuccessful_auth_with_basic_cred, "Requires", "Server;UserName;Password") + { + load_parameters(); -TEST_FIXTURE(server_properties, none_auth_no_cred, "Requires", "Server") -{ - load_parameters(); + http_client_config config; + config.set_credentials(web::credentials(m_username, m_password)); - http_client client(m_uri); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::Forbidden, response.status_code()); -} + http_client client(m_uri, config); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); + } -// This test should be executed for NTLM, Negotiate, IntegratedWindowsAuth, and Digest. -TEST_FIXTURE(server_properties, unsuccessful_auth_with_basic_cred, "Requires", "Server;UserName;Password") -{ - load_parameters(); + TEST_FIXTURE(server_properties, basic_anonymous_auth_with_basic_cred, "Requires", "Server;UserName;Password") + { + load_parameters(); - http_client_config config; - config.set_credentials(web::credentials(m_username, m_password)); + http_client_config config; + config.set_credentials(web::credentials(m_username, m_password)); + http_client client(m_uri, config); + http_request req(methods::GET); + req.headers().add(U("UserName"), m_username); + req.headers().add(U("Password"), m_password); + http_response response = client.request(req).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + } - http_client client(m_uri, config); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); -} + TEST_FIXTURE(server_properties, none_auth_with_cred, "Requires", "Server;UserName;Password") + { + load_parameters(); -TEST_FIXTURE(server_properties, basic_anonymous_auth_with_basic_cred, "Requires", "Server;UserName;Password") -{ - load_parameters(); - - http_client_config config; - config.set_credentials(web::credentials(m_username, m_password)); - http_client client(m_uri, config); - http_request req(methods::GET); - req.headers().add(U("UserName"), m_username); - req.headers().add(U("Password"), m_password); - http_response response = client.request(req).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); -} - -TEST_FIXTURE(server_properties, none_auth_with_cred, "Requires", "Server;UserName;Password") -{ - load_parameters(); + http_client_config config; + config.set_credentials(web::credentials(m_username, m_password)); + http_client client(m_uri, config); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::Forbidden, response.status_code()); + } - http_client_config config; - config.set_credentials(web::credentials(m_username, m_password)); - http_client client(m_uri, config); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::Forbidden, response.status_code()); -} + // This test should be executed for all authentication schemes except None. + TEST_FIXTURE(server_properties, successful_auth_with_domain_cred, "Requires", "Server;UserName;Password") + { + load_parameters(); -// This test should be executed for all authentication schemes except None. -TEST_FIXTURE(server_properties, successful_auth_with_domain_cred, "Requires", "Server;UserName;Password") -{ - load_parameters(); - - http_client_config config; - config.set_credentials(web::credentials(m_username, m_password)); - http_client client(m_uri, config); - http_request req(methods::GET); - req.headers().add(U("UserName"), m_username); - req.headers().add(U("Password"), m_password); - http_response response = client.request(req).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); -} + http_client_config config; + config.set_credentials(web::credentials(m_username, m_password)); + http_client client(m_uri, config); + http_request req(methods::GET); + req.headers().add(U("UserName"), m_username); + req.headers().add(U("Password"), m_password); + http_response response = client.request(req).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + } #ifndef __cplusplus_winrt // WinRT implementation doesn't support request buffer caching. -TEST_FIXTURE(server_properties, failed_authentication_resend_request_error, "Requires", "Server;UserName;Password") -{ - load_parameters(); + TEST_FIXTURE(server_properties, failed_authentication_resend_request_error, "Requires", "Server;UserName;Password") + { + load_parameters(); - http_client_config config; - config.set_credentials(web::credentials(m_username, m_password)); - http_client client(m_uri, config); + http_client_config config; + config.set_credentials(web::credentials(m_username, m_password)); + http_client client(m_uri, config); - const size_t rawDataSize = 8; + const size_t rawDataSize = 8; - std::vector data(rawDataSize); - memcpy(&data[0], "raw data", rawDataSize); + std::vector data(rawDataSize); + memcpy(&data[0], "raw data", rawDataSize); - http_request request; - request.set_method(methods::POST); - request.set_body(data); - http_response response = client.request(request).get(); + http_request request; + request.set_method(methods::POST); + request.set_body(data); + http_response response = client.request(request).get(); - VERIFY_ARE_EQUAL(200, response.status_code()); -} + VERIFY_ARE_EQUAL(200, response.status_code()); + } #endif #ifdef __cplusplus_winrt -TEST_FIXTURE(uri_address, set_user_options_winrt) -{ - test_http_server::scoped_server scoped(m_uri); - scoped.server()->next_request().then([](test_request *p_request) + TEST_FIXTURE(uri_address, set_user_options_winrt) { - p_request->reply(status_codes::OK); - }); - - http_client_config config; - config.set_nativehandle_options([](native_handle handle)->void{ - auto hr = handle->SetProperty(XHR_PROP_TIMEOUT, 1000); - if(!SUCCEEDED(hr)) - throw std::runtime_error("The Test Exception"); - }); - http_client client(m_uri, config); - auto response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(200, response.status_code()); -} + test_http_server::scoped_server scoped(m_uri); + scoped.server()->next_request().then([](test_request* p_request) { p_request->reply(status_codes::OK); }); + + http_client_config config; + config.set_nativehandle_options([](native_handle handle) -> void { + auto hr = handle->SetProperty(XHR_PROP_TIMEOUT, 1000); + if (!SUCCEEDED(hr)) throw std::runtime_error("The Test Exception"); + }); + http_client client(m_uri, config); + auto response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(200, response.status_code()); + } #endif // __cplusplus_winrt #ifdef _WIN32 #if !defined(__cplusplus_winrt) -TEST_FIXTURE(server_properties, set_user_options, "Requires", "Server;UserName;Password") -{ - load_parameters(); - - http_client_config config; - config.set_credentials(web::credentials(m_username, m_password)); + TEST_FIXTURE(server_properties, set_user_options, "Requires", "Server;UserName;Password") + { + load_parameters(); - config.set_nativehandle_options([&](native_handle handle)->void{ - DWORD policy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW; - if (!WinHttpSetOption(handle, - WINHTTP_OPTION_AUTOLOGON_POLICY, - &policy, - sizeof(policy))) - { - throw std::runtime_error("The Test Error"); - } - }); + http_client_config config; + config.set_credentials(web::credentials(m_username, m_password)); + + config.set_nativehandle_options([&](native_handle handle) -> void { + DWORD policy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW; + if (!WinHttpSetOption(handle, WINHTTP_OPTION_AUTOLOGON_POLICY, &policy, sizeof(policy))) + { + throw std::runtime_error("The Test Error"); + } + }); - http_client client(m_uri, config); + http_client client(m_uri, config); - const size_t rawDataSize = 8; + const size_t rawDataSize = 8; - std::vector data(rawDataSize); - memcpy(&data[0], "raw data", rawDataSize); + std::vector data(rawDataSize); + memcpy(&data[0], "raw data", rawDataSize); - http_request request; - request.set_method(methods::POST); - request.set_body(data); + http_request request; + request.set_method(methods::POST); + request.set_body(data); - VERIFY_ARE_EQUAL(200, client.request(request).get().status_code()); -} + VERIFY_ARE_EQUAL(200, client.request(request).get().status_code()); + } -TEST_FIXTURE(uri_address, auth_producer_consumer_buffer) -{ - auto buf = streams::producer_consumer_buffer(); - buf.putc('a').get(); - buf.putc('a').get(); - buf.putc('a').get(); - buf.putc('a').get(); - buf.close(std::ios_base::out).get(); - http_request msg(methods::POST); - msg.set_body(buf.create_istream()); - - http_client_config config; - VERIFY_IS_FALSE(config.buffer_request()); - config.set_buffer_request(true); - VERIFY_IS_TRUE(config.buffer_request()); - config.set_credentials(web::credentials(U("USERNAME"), U("PASSWORD"))); - - http_client client(m_uri, config); - - pplx::task t, t2; - test_http_server::scoped_server scoped(m_uri); - - t = scoped.server()->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, auth_producer_consumer_buffer) { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + auto buf = streams::producer_consumer_buffer(); + buf.putc('a').get(); + buf.putc('a').get(); + buf.putc('a').get(); + buf.putc('a').get(); + buf.close(std::ios_base::out).get(); + http_request msg(methods::POST); + msg.set_body(buf.create_istream()); - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - }); - t2 = scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); - p_request->reply(200); - }); + http_client_config config; + VERIFY_IS_FALSE(config.buffer_request()); + config.set_buffer_request(true); + VERIFY_IS_TRUE(config.buffer_request()); + config.set_credentials(web::credentials(U("USERNAME"), U("PASSWORD"))); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - scoped.server()->close(); - VERIFY_NO_THROWS(t.get()); - VERIFY_NO_THROWS(t2.get()); -} + http_client client(m_uri, config); -TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer_fail_no_cred) -{ - auto buf = streams::producer_consumer_buffer(); - buf.putc('a').get(); - buf.putc('a').get(); - buf.putc('a').get(); - buf.putc('a').get(); - buf.close(std::ios_base::out).get(); - http_request msg(methods::POST); - msg.set_body(buf.create_istream()); - - http_client client(m_uri); - - pplx::task t; - { + pplx::task t, t2; test_http_server::scoped_server scoped(m_uri); - t = scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); + + t = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); std::map headers; headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); }); + t2 = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); + p_request->reply(200); + }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + scoped.server()->close(); + VERIFY_NO_THROWS(t.get()); + VERIFY_NO_THROWS(t2.get()); } - t.get(); -} -TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer_fail) -{ - auto buf = streams::producer_consumer_buffer(); - buf.putc('a').get(); - buf.close(std::ios_base::out).get(); - http_request msg(methods::POST); - msg.set_body(buf.create_istream()); - - http_client_config config; - config.set_buffer_request(true); - config.set_credentials(web::credentials(U("USERNAME"), U("PASSWORD"))); - - http_client client(m_uri, config); - pplx::task t; + TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer_fail_no_cred) { - test_http_server::scoped_server scoped(m_uri); - - auto replyFunc = [&](test_request *p_request) + auto buf = streams::producer_consumer_buffer(); + buf.putc('a').get(); + buf.putc('a').get(); + buf.putc('a').get(); + buf.putc('a').get(); + buf.close(std::ios_base::out).get(); + http_request msg(methods::POST); + msg.set_body(buf.create_istream()); + + http_client client(m_uri); + + pplx::task t; { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("a")); - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld2\""); + test_http_server::scoped_server scoped(m_uri); + t = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - }; + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + }); - t = scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("a")); - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); + } + t.get(); + } - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - }).then([&scoped, replyFunc](){ - return scoped.server()->next_request().then(replyFunc); - }); + TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer_fail) + { + auto buf = streams::producer_consumer_buffer(); + buf.putc('a').get(); + buf.close(std::ios_base::out).get(); + http_request msg(methods::POST); + msg.set_body(buf.create_istream()); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); + http_client_config config; + config.set_buffer_request(true); + config.set_credentials(web::credentials(U("USERNAME"), U("PASSWORD"))); + + http_client client(m_uri, config); + pplx::task t; + { + test_http_server::scoped_server scoped(m_uri); + + auto replyFunc = [&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::POST, U("/"), U("application/octet-stream"), U("a")); + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld2\""); + + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + }; + + t = scoped.server() + ->next_request() + .then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::POST, U("/"), U("application/octet-stream"), U("a")); + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + }) + .then([&scoped, replyFunc]() { return scoped.server()->next_request().then(replyFunc); }); + + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); + } + VERIFY_NO_THROWS(t.get()); } - VERIFY_NO_THROWS(t.get()); -} #endif -TEST_FIXTURE(uri_address, set_user_options_exceptions) -{ - test_http_server::scoped_server scoped(m_uri); - http_client_config config; - class TestException; - config.set_nativehandle_options([](native_handle) + TEST_FIXTURE(uri_address, set_user_options_exceptions) { - throw std::runtime_error("The Test exception"); - }); - http_client client(m_uri, config); - VERIFY_THROWS(client.request(methods::GET).get(), std::runtime_error); -} + test_http_server::scoped_server scoped(m_uri); + http_client_config config; + class TestException; + config.set_nativehandle_options([](native_handle) { throw std::runtime_error("The Test exception"); }); + http_client client(m_uri, config); + VERIFY_THROWS(client.request(methods::GET).get(), std::runtime_error); + } #endif // _WIN32 -// Fix for 522831 AV after failed authentication attempt -TEST_FIXTURE(uri_address, failed_authentication_attempt, "Ignore:Linux", "89", "Ignore:Apple", "89") -{ - handle_timeout([] + // Fix for 522831 AV after failed authentication attempt + TEST_FIXTURE(uri_address, failed_authentication_attempt, "Ignore:Linux", "89", "Ignore:Apple", "89") { - http_client_config config; - web::credentials cred(U("user"), U("schmuser")); - config.set_credentials(cred); - http_client client(U("https://apis.live.net"), config); - http_response response = client.request(methods::GET, U("V5.0/me/skydrive/files")).get(); - VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); - auto v = response.extract_vector().get(); - std::string s(v.begin(), v.end()); - // The resulting data must be non-empty (an error about missing access token) - VERIFY_IS_FALSE(s.empty()); - }); -} + handle_timeout([] { + http_client_config config; + web::credentials cred(U("user"), U("schmuser")); + config.set_credentials(cred); + http_client client(U("https://apis.live.net"), config); + http_response response = client.request(methods::GET, U("V5.0/me/skydrive/files")).get(); + VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); + auto v = response.extract_vector().get(); + std::string s(v.begin(), v.end()); + // The resulting data must be non-empty (an error about missing access token) + VERIFY_IS_FALSE(s.empty()); + }); + } #if !defined(_WIN32) -// http_server does not support auth -void auth_test_impl(bool fail) -{ - std::string user("user1"), password("user1"); - auto return_code = status_codes::OK; - - if (fail) + // http_server does not support auth + void auth_test_impl(bool fail) { - password = "invalid"; - return_code = status_codes::Unauthorized; - } + std::string user("user1"), password("user1"); + auto return_code = status_codes::OK; - http_client_config client_config; - web::credentials cred(U(user), U(password)); - client_config.set_credentials(cred); - http_client client(U("http://httpbin.org/basic-auth/user1/user1"), client_config); + if (fail) + { + password = "invalid"; + return_code = status_codes::Unauthorized; + } - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(return_code, response.status_code()); -} + http_client_config client_config; + web::credentials cred(U(user), U(password)); + client_config.set_credentials(cred); + http_client client(U("http://httpbin.org/basic-auth/user1/user1"), client_config); -TEST(auth_no_data) -{ - auth_test_impl(false); -} + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(return_code, response.status_code()); + } -TEST(unsuccessful_auth_with_basic_cred) -{ - auth_test_impl(true); -} + TEST(auth_no_data) { auth_test_impl(false); } -TEST_FIXTURE(uri_address, set_user_options_asio_http) -{ - test_http_server::scoped_server scoped(m_uri); - scoped.server()->next_request().then([](test_request *p_request) - { - p_request->reply(status_codes::OK); - }); + TEST(unsuccessful_auth_with_basic_cred) { auth_test_impl(true); } - http_client_config config; - config.set_nativehandle_options([](native_handle handle) - { - boost::asio::ip::tcp::socket* socket = static_cast(handle); - // Socket shouldn't be open yet since no requests have gone out. - VERIFY_ARE_EQUAL(false, socket->is_open()); - }); - http_client client(m_uri, config); - auto response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(200, response.status_code()); -} - -TEST_FIXTURE(uri_address, set_user_options_asio_https) -{ - handle_timeout([] + TEST_FIXTURE(uri_address, set_user_options_asio_http) { + test_http_server::scoped_server scoped(m_uri); + scoped.server()->next_request().then([](test_request* p_request) { p_request->reply(status_codes::OK); }); + http_client_config config; - config.set_nativehandle_options([](native_handle handle) - { - boost::asio::ssl::stream* streamobj = - static_cast*>(handle); - const auto &tcpLayer = streamobj->lowest_layer(); - VERIFY_ARE_EQUAL(false, tcpLayer.is_open()); + config.set_nativehandle_options([](native_handle handle) { + boost::asio::ip::tcp::socket* socket = static_cast(handle); + // Socket shouldn't be open yet since no requests have gone out. + VERIFY_ARE_EQUAL(false, socket->is_open()); }); + http_client client(m_uri, config); + auto response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(200, response.status_code()); + } - http_client client(U("https://apis.live.net"), config); - http_response response = client.request(methods::GET, U("V5.0/me/skydrive/files")).get(); - VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); - auto v = response.extract_vector().get(); - // The resulting data must be non-empty (an error about missing access token) - VERIFY_IS_FALSE(v.empty()); - }); -} + TEST_FIXTURE(uri_address, set_user_options_asio_https) + { + handle_timeout([] { + http_client_config config; + config.set_nativehandle_options([](native_handle handle) { + boost::asio::ssl::stream* streamobj = + static_cast*>(handle); + const auto& tcpLayer = streamobj->lowest_layer(); + VERIFY_ARE_EQUAL(false, tcpLayer.is_open()); + }); + + http_client client(U("https://apis.live.net"), config); + http_response response = client.request(methods::GET, U("V5.0/me/skydrive/files")).get(); + VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); + auto v = response.extract_vector().get(); + // The resulting data must be non-empty (an error about missing access token) + VERIFY_IS_FALSE(v.empty()); + }); + } #endif } // SUITE(authentication_tests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/building_request_tests.cpp b/Release/tests/functional/http/client/building_request_tests.cpp index 72925b7152..4fa379c2a7 100644 --- a/Release/tests/functional/http/client/building_request_tests.cpp +++ b/Release/tests/functional/http/client/building_request_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* building_request_tests.cpp -* -* Tests cases manually building up HTTP requests. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * building_request_tests.cpp + * + * Tests cases manually building up HTTP requests. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -24,301 +24,311 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(building_request_tests) +namespace tests { - -TEST_FIXTURE(uri_address, simple_values) +namespace functional { - test_http_server::scoped_server scoped(m_uri); - pplx::task t1, t2; - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - // Set a method. - const method method = methods::OPTIONS; - http_request msg(method); - VERIFY_ARE_EQUAL(method, msg.method()); - - // Set a path once. - const utility::string_t custom_path1 = U("/hey/custom/path"); - msg.set_request_uri(custom_path1); - VERIFY_ARE_EQUAL(custom_path1, msg.relative_uri().to_string()); - t1 = p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, method, custom_path1); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - - // Set the path twice. - msg = http_request(method); - msg.set_request_uri(custom_path1); - VERIFY_ARE_EQUAL(custom_path1, msg.relative_uri().to_string()); - const utility::string_t custom_path2 = U("/yes/you/there"); - msg.set_request_uri(custom_path2); - VERIFY_ARE_EQUAL(custom_path2, msg.relative_uri().to_string()); - t2 = p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, method, custom_path2); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - p_server->close(); - try { t1.get(); } catch (...) { VERIFY_ARE_EQUAL(0, 1, "t1 failed"); } - try { t2.get(); } catch (...) { VERIFY_ARE_EQUAL(0, 2, "t2 failed"); } -} - -TEST_FIXTURE(uri_address, body_types) +namespace http { - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - // Body data types. - const method method(U("CUSTOMmethod")); - utility::string_t str_body(U("YES_BASIC_STRING BODY")); - utility::string_t str_move_body(str_body); - std::vector vector_body; - vector_body.resize(str_body.size()*sizeof(utility::char_t)); - memcpy(&vector_body[0], &str_body[0], str_body.size()*sizeof(utility::char_t)); - std::vector vector_move_body(vector_body); - utility::string_t custom_content = U("YESNOW!"); - - // vector - no content type. - http_request msg(method); - msg.set_body(std::move(vector_move_body)); - VERIFY_ARE_EQUAL(U("application/octet-stream"), msg.headers()[U("Content-Type")]); - p_server->next_request().then([&](test_request *p_request) - { - auto received = p_request->m_body; - auto sent = vector_body; - VERIFY_IS_TRUE(received == sent); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - - // vector - with content type. - msg = http_request(method); - vector_move_body = vector_body; - msg.headers().add(U("Content-Type"), custom_content); - msg.set_body(std::move(vector_move_body)); - VERIFY_ARE_EQUAL(custom_content, msg.headers()[U("Content-Type")]); - p_server->next_request().then([&](test_request *p_request) - { - auto received = p_request->m_body; - auto sent = vector_body; - VERIFY_IS_TRUE(received == sent); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - - // string - no content type. - msg = http_request(method); - msg.set_body(std::move(str_move_body)); - VERIFY_ARE_EQUAL(U("text/plain; charset=utf-8"), msg.headers()[U("Content-Type")]); - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, method, U("/"), U("text/plain; charset=utf-8"), str_body); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - - // string - with content type. - msg = http_request(method); - str_move_body = str_body; - msg.headers().add(U("Content-Type"), custom_content); - msg.set_body(std::move(str_move_body)); - VERIFY_ARE_EQUAL(custom_content, msg.headers()[U("Content-Type")]); - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, method, U("/"), custom_content, str_body); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -} - -TEST(set_body_string_with_charset) +namespace client { - http_request request; - VERIFY_THROWS(request.set_body( - ::utility::conversions::to_utf16string("body_data"), - ::utility::conversions::to_utf16string("text/plain;charset=utf-16")), std::invalid_argument); -} - -TEST_FIXTURE(uri_address, empty_bodies) +SUITE(building_request_tests) { - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - // Body data. - std::string empty_str; - std::vector vector_body; - utility::string_t str_body; - utility::string_t wstr_body; - - // empty vector. - const method method(methods::PUT); - http_request msg(method); - msg.set_body(std::move(vector_body)); - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, method, U("/"), U("application/octet-stream")); - VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - - // empty string. - msg = http_request(method); - msg.set_body(std::move(str_body)); - p_server->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, simple_values) { - http_asserts::assert_test_request_equals(p_request, method, U("/"), U("text/plain; charset=utf-8")); - VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - - // empty wstring. - msg = http_request(method); - msg.set_body(std::move(wstr_body)); - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, method, U("/"), U("text/plain; charset=utf-8")); - VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -} + test_http_server::scoped_server scoped(m_uri); + pplx::task t1, t2; + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + // Set a method. + const method method = methods::OPTIONS; + http_request msg(method); + VERIFY_ARE_EQUAL(method, msg.method()); + + // Set a path once. + const utility::string_t custom_path1 = U("/hey/custom/path"); + msg.set_request_uri(custom_path1); + VERIFY_ARE_EQUAL(custom_path1, msg.relative_uri().to_string()); + t1 = p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, method, custom_path1); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -TEST_FIXTURE(uri_address, set_body) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - const method mtd = methods::POST; - utility::string_t data(U("YOU KNOW~!!!!!")); - utility::string_t content_type = U("text/plain; charset=utf-8"); - - // without content type - http_request msg(mtd); - msg.set_body(data); - VERIFY_ARE_EQUAL(content_type, msg.headers()[U("Content-Type")]); - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, mtd, U("/"), content_type, data); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + // Set the path twice. + msg = http_request(method); + msg.set_request_uri(custom_path1); + VERIFY_ARE_EQUAL(custom_path1, msg.relative_uri().to_string()); + const utility::string_t custom_path2 = U("/yes/you/there"); + msg.set_request_uri(custom_path2); + VERIFY_ARE_EQUAL(custom_path2, msg.relative_uri().to_string()); + t2 = p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, method, custom_path2); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + p_server->close(); + try + { + t1.get(); + } + catch (...) + { + VERIFY_ARE_EQUAL(0, 1, "t1 failed"); + } + try + { + t2.get(); + } + catch (...) + { + VERIFY_ARE_EQUAL(0, 2, "t2 failed"); + } + } - // with content type - content_type = U("YESYES"); -#ifdef _UTF16_STRINGS - const utility::string_t expected_content_type = U("YESYES; charset=utf-8"); -#else - const utility::string_t expected_content_type = U("YESYES"); -#endif - msg = http_request(mtd); - msg.set_body(data, content_type); - VERIFY_ARE_EQUAL(expected_content_type, msg.headers()[U("Content-Type")]); - scoped.server()->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, body_types) { - http_asserts::assert_test_request_equals(p_request, mtd, U("/"), expected_content_type, data); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -} + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + // Body data types. + const method method(U("CUSTOMmethod")); + utility::string_t str_body(U("YES_BASIC_STRING BODY")); + utility::string_t str_move_body(str_body); + std::vector vector_body; + vector_body.resize(str_body.size() * sizeof(utility::char_t)); + memcpy(&vector_body[0], &str_body[0], str_body.size() * sizeof(utility::char_t)); + std::vector vector_move_body(vector_body); + utility::string_t custom_content = U("YESNOW!"); + + // vector - no content type. + http_request msg(method); + msg.set_body(std::move(vector_move_body)); + VERIFY_ARE_EQUAL(U("application/octet-stream"), msg.headers()[U("Content-Type")]); + p_server->next_request().then([&](test_request* p_request) { + auto received = p_request->m_body; + auto sent = vector_body; + VERIFY_IS_TRUE(received == sent); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -TEST_FIXTURE(uri_address, set_body_with_charset) -{ - http_request msg(methods::PUT); - msg.set_body("datadatadata", "text/plain;charset=us-ascii"); - VERIFY_THROWS(msg.set_body( - ::utility::conversions::to_utf16string("datadatadata"), - ::utility::conversions::to_utf16string("text/plain;charset=us-ascii")), std::invalid_argument); -} + // vector - with content type. + msg = http_request(method); + vector_move_body = vector_body; + msg.headers().add(U("Content-Type"), custom_content); + msg.set_body(std::move(vector_move_body)); + VERIFY_ARE_EQUAL(custom_content, msg.headers()[U("Content-Type")]); + p_server->next_request().then([&](test_request* p_request) { + auto received = p_request->m_body; + auto sent = vector_body; + VERIFY_IS_TRUE(received == sent); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -TEST_FIXTURE(uri_address, set_content_length_locale, "Ignore:Android", "Locale unsupported on Android") -{ - std::locale changedLocale; - try - { -#ifdef _WIN32 - changedLocale = std::locale("fr-FR"); -#else - changedLocale = std::locale("fr_FR.UTF-8"); -#endif + // string - no content type. + msg = http_request(method); + msg.set_body(std::move(str_move_body)); + VERIFY_ARE_EQUAL(U("text/plain; charset=utf-8"), msg.headers()[U("Content-Type")]); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, method, U("/"), U("text/plain; charset=utf-8"), str_body); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + + // string - with content type. + msg = http_request(method); + str_move_body = str_body; + msg.headers().add(U("Content-Type"), custom_content); + msg.set_body(std::move(str_move_body)); + VERIFY_ARE_EQUAL(custom_content, msg.headers()[U("Content-Type")]); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, method, U("/"), custom_content, str_body); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); } - catch (const std::exception &) + + TEST(set_body_string_with_charset) { - // Silently pass if locale isn't installed on the machine. - return; + http_request request; + VERIFY_THROWS(request.set_body(::utility::conversions::to_utf16string("body_data"), + ::utility::conversions::to_utf16string("text/plain;charset=utf-16")), + std::invalid_argument); } - tests::common::utilities::locale_guard loc(changedLocale); + TEST_FIXTURE(uri_address, empty_bodies) + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + // Body data. + std::string empty_str; + std::vector vector_body; + utility::string_t str_body; + utility::string_t wstr_body; + + // empty vector. + const method method(methods::PUT); + http_request msg(method); + msg.set_body(std::move(vector_body)); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, method, U("/"), U("application/octet-stream")); + VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - http_request req(methods::PUT); - req.headers().set_content_length(1000); - VERIFY_ARE_EQUAL(U("1000"), req.headers()[web::http::header_names::content_length]); // fr_RF would have 1 000 -} + // empty string. + msg = http_request(method); + msg.set_body(std::move(str_body)); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, method, U("/"), U("text/plain; charset=utf-8")); + VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -TEST_FIXTURE(uri_address, set_port_locale, "Ignore:Android", "Locale unsupported on Android") -{ - std::locale changedLocale; - try + // empty wstring. + msg = http_request(method); + msg.set_body(std::move(wstr_body)); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, method, U("/"), U("text/plain; charset=utf-8")); + VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + + TEST_FIXTURE(uri_address, set_body) { -#ifdef _WIN32 - changedLocale = std::locale("fr-FR"); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + const method mtd = methods::POST; + utility::string_t data(U("YOU KNOW~!!!!!")); + utility::string_t content_type = U("text/plain; charset=utf-8"); + + // without content type + http_request msg(mtd); + msg.set_body(data); + VERIFY_ARE_EQUAL(content_type, msg.headers()[U("Content-Type")]); + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/"), content_type, data); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + + // with content type + content_type = U("YESYES"); +#ifdef _UTF16_STRINGS + const utility::string_t expected_content_type = U("YESYES; charset=utf-8"); #else - changedLocale = std::locale("fr_FR.UTF-8"); + const utility::string_t expected_content_type = U("YESYES"); #endif + msg = http_request(mtd); + msg.set_body(data, content_type); + VERIFY_ARE_EQUAL(expected_content_type, msg.headers()[U("Content-Type")]); + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/"), expected_content_type, data); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); } - catch (const std::exception &) + + TEST_FIXTURE(uri_address, set_body_with_charset) { - // Silently pass if locale isn't installed on machine. - return; + http_request msg(methods::PUT); + msg.set_body("datadatadata", "text/plain;charset=us-ascii"); + VERIFY_THROWS(msg.set_body(::utility::conversions::to_utf16string("datadatadata"), + ::utility::conversions::to_utf16string("text/plain;charset=us-ascii")), + std::invalid_argument); } - tests::common::utilities::locale_guard loc(changedLocale); - test_http_server::scoped_server scoped(m_uri); - pplx::task t; - http_client client(m_uri); - - utility::string_t data(U("STRING data 1000")); - t = scoped.server()->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, set_content_length_locale, "Ignore:Android", "Locale unsupported on Android") { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("text/plain; charset=utf-8"), data); - p_request->reply(200); - }); - - http_request msg(methods::PUT); - msg.set_body(data); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + std::locale changedLocale; + try + { +#ifdef _WIN32 + changedLocale = std::locale("fr-FR"); +#else + changedLocale = std::locale("fr_FR.UTF-8"); +#endif + } + catch (const std::exception&) + { + // Silently pass if locale isn't installed on the machine. + return; + } - scoped.server()->close(); - t.get(); -} + tests::common::utilities::locale_guard loc(changedLocale); -TEST_FIXTURE(uri_address, reuse_request) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); + http_request req(methods::PUT); + req.headers().set_content_length(1000); + VERIFY_ARE_EQUAL(U("1000"), req.headers()[web::http::header_names::content_length]); // fr_RF would have 1 000 + } - http_request msg(methods::GET); - for (int i = 0; i < 3; ++i) + TEST_FIXTURE(uri_address, set_port_locale, "Ignore:Android", "Locale unsupported on Android") { - p_server->next_request().then([](test_request *p_request) + std::locale changedLocale; + try + { +#ifdef _WIN32 + changedLocale = std::locale("fr-FR"); +#else + changedLocale = std::locale("fr_FR.UTF-8"); +#endif + } + catch (const std::exception&) { - http_asserts::assert_test_request_equals(p_request, methods::GET, U("/")); + // Silently pass if locale isn't installed on machine. + return; + } + tests::common::utilities::locale_guard loc(changedLocale); + + test_http_server::scoped_server scoped(m_uri); + pplx::task t; + http_client client(m_uri); + + utility::string_t data(U("STRING data 1000")); + t = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::PUT, U("/"), U("text/plain; charset=utf-8"), data); p_request->reply(200); }); + + http_request msg(methods::PUT); + msg.set_body(data); http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + + scoped.server()->close(); + t.get(); } -} + TEST_FIXTURE(uri_address, reuse_request) + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + http_request msg(methods::GET); + for (int i = 0; i < 3; ++i) + { + p_server->next_request().then([](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::GET, U("/")); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + } } -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/client_construction.cpp b/Release/tests/functional/http/client/client_construction.cpp index ae2b978ae8..1229b2cfd7 100644 --- a/Release/tests/functional/http/client/client_construction.cpp +++ b/Release/tests/functional/http/client/client_construction.cpp @@ -1,17 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* client_construction.cpp -* -* Tests cases for covering creating http_clients. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * client_construction.cpp + * + * Tests cases for covering creating http_clients. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include using namespace web::http; @@ -19,220 +20,208 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(client_construction) +namespace tests { - -// Tests using different types of strings to construct an http_client. -TEST_FIXTURE(uri_address, string_types) +namespace functional { - // The goal of this test case is to make sure we can compile, - // if the URI class doesn't have the proper constructors it won't. - // So we don't need to actually do a request. - http_client c1(U("http://localhost:4567/")); - http_client c3(utility::string_t(U("http://localhost:4567/"))); -} - -// Tests different variations on specifying the URI in http_client constructor. -TEST_FIXTURE(uri_address, different_uris) +namespace http +{ +namespace client +{ +SUITE(client_construction) { - const utility::string_t paths[] = + // Tests using different types of strings to construct an http_client. + TEST_FIXTURE(uri_address, string_types) { - U(""), - U("/"), - U("/toplevel/nested"), - U("/toplevel/nested/") - }; - const utility::string_t expected_paths[] = + // The goal of this test case is to make sure we can compile, + // if the URI class doesn't have the proper constructors it won't. + // So we don't need to actually do a request. + http_client c1(U("http://localhost:4567/")); + http_client c3(utility::string_t(U("http://localhost:4567/"))); + } + + // Tests different variations on specifying the URI in http_client constructor. + TEST_FIXTURE(uri_address, different_uris) { - U("/"), - U("/"), - U("/toplevel/nested"), - U("/toplevel/nested/") - }; - const size_t num_paths = sizeof(paths) / sizeof(paths[0]); - for(size_t i = 0; i < num_paths; ++i) + const utility::string_t paths[] = {U(""), U("/"), U("/toplevel/nested"), U("/toplevel/nested/")}; + const utility::string_t expected_paths[] = {U("/"), U("/"), U("/toplevel/nested"), U("/toplevel/nested/")}; + const size_t num_paths = sizeof(paths) / sizeof(paths[0]); + for (size_t i = 0; i < num_paths; ++i) + { + uri address(U("http://localhost:55678") + paths[i]); + test_http_server::scoped_server scoped(address); + http_client client(address); + test_connection(scoped.server(), &client, expected_paths[i]); + } + } + + // Helper function verifies that when constructing an http_client with given + // URI std::invalid_argument is thrown. + static void verify_client_invalid_argument(const uri& address) { - uri address(U("http://localhost:55678") + paths[i]); - test_http_server::scoped_server scoped(address); - http_client client(address); - test_connection(scoped.server(), &client, expected_paths[i]); + try + { + http_client client(address); + VERIFY_IS_TRUE(false); + } + catch (std::invalid_argument&) + { + // expected + } } -} -// Helper function verifies that when constructing an http_client with given -// URI std::invalid_argument is thrown. -static void verify_client_invalid_argument(const uri &address) -{ - try + TEST_FIXTURE(uri_address, client_construction_error_cases) { + uri address(U("nothttp://localhost:34567/")); + + // Invalid scheme. + verify_client_invalid_argument(address); + + // empty host. + address = uri(U("http://:34567/")); + verify_client_invalid_argument(address); + } + + TEST_FIXTURE(uri_address, client_construction_no_scheme) + { + uri address(U("//localhost:34568/p/g")); + test_http_server::scoped_server scoped(m_uri); + http_client client(address); - VERIFY_IS_TRUE(false); - } catch(std::invalid_argument &) + test_connection(scoped.server(), &client, U("/p/g")); + } + + TEST_FIXTURE(uri_address, copy_assignment) { - // expected + test_http_server::scoped_server scoped(m_uri); + + // copy constructor + http_client original(m_uri); + http_client new_client(original); + test_connection(scoped.server(), &new_client, U("/")); + test_connection(scoped.server(), &original, U("/")); + + // assignment + http_client new_client2(U("http://bad:-1")); + new_client2 = original; + test_connection(scoped.server(), &new_client2, U("/")); + test_connection(scoped.server(), &original, U("/")); } -} -TEST_FIXTURE(uri_address, client_construction_error_cases) -{ - uri address(U("nothttp://localhost:34567/")); + TEST_FIXTURE(uri_address, move_not_init) + { + test_http_server::scoped_server scoped(m_uri); - // Invalid scheme. - verify_client_invalid_argument(address); - - // empty host. - address = uri(U("http://:34567/")); - verify_client_invalid_argument(address); -} + // move constructor + http_client original(m_uri); + http_client new_client = std::move(original); + test_connection(scoped.server(), &new_client, U("/")); -TEST_FIXTURE(uri_address, client_construction_no_scheme) -{ + // move assignment + original = http_client(m_uri); + test_connection(scoped.server(), &original, U("/")); + } - uri address(U("//localhost:34568/p/g")); - test_http_server::scoped_server scoped(m_uri); + TEST_FIXTURE(uri_address, move_init) + { + test_http_server::scoped_server scoped(m_uri); - http_client client(address); - test_connection(scoped.server(), &client, U("/p/g")); -} + // move constructor + http_client original(m_uri); + test_connection(scoped.server(), &original, U("/")); + http_client new_client = std::move(original); + test_connection(scoped.server(), &new_client, U("/")); -TEST_FIXTURE(uri_address, copy_assignment) -{ - test_http_server::scoped_server scoped(m_uri); - - // copy constructor - http_client original(m_uri); - http_client new_client(original); - test_connection(scoped.server(), &new_client, U("/")); - test_connection(scoped.server(), &original, U("/")); - - // assignment - http_client new_client2(U("http://bad:-1")); - new_client2 = original; - test_connection(scoped.server(), &new_client2, U("/")); - test_connection(scoped.server(), &original, U("/")); -} - -TEST_FIXTURE(uri_address, move_not_init) -{ - test_http_server::scoped_server scoped(m_uri); - - // move constructor - http_client original(m_uri); - http_client new_client = std::move(original); - test_connection(scoped.server(), &new_client, U("/")); - - // move assignment - original = http_client(m_uri); - test_connection(scoped.server(), &original, U("/")); -} - -TEST_FIXTURE(uri_address, move_init) -{ - test_http_server::scoped_server scoped(m_uri); - - // move constructor - http_client original(m_uri); - test_connection(scoped.server(), &original, U("/")); - http_client new_client = std::move(original); - test_connection(scoped.server(), &new_client, U("/")); - - // move assignment - original = http_client(m_uri); - test_connection(scoped.server(), &original, U("/")); -} - -// Verify that we can read the config from the http_client -TEST_FIXTURE(uri_address, get_client_config) -{ - test_http_server::scoped_server scoped(m_uri); - - http_client_config config; - - VERIFY_ARE_EQUAL(config.chunksize(), 64*1024); - config.set_chunksize(1024); - VERIFY_ARE_EQUAL(config.chunksize(), 1024); - - utility::seconds timeout(100); - config.set_timeout(timeout); - http_client client(m_uri, config); - - const http_client_config& config2 = client.client_config(); - VERIFY_ARE_EQUAL(config2.timeout().count(), timeout.count()); - std::chrono::milliseconds milli_timeout = config2.timeout(); - VERIFY_ARE_EQUAL(milli_timeout.count(), - std::chrono::duration_cast(timeout).count()); - auto micro_timeout = config.timeout(); - VERIFY_ARE_EQUAL(micro_timeout.count(), - std::chrono::duration_cast(timeout).count()); - - VERIFY_ARE_EQUAL(config2.chunksize(), 1024); -} - -// Verify that we can get the baseuri from http_client constructors -TEST_FIXTURE(uri_address, BaseURI_test) -{ - http_client baseclient1(m_uri); - VERIFY_ARE_EQUAL(baseclient1.base_uri(), m_uri); + // move assignment + original = http_client(m_uri); + test_connection(scoped.server(), &original, U("/")); + } - http_client_config config; - http_client baseclient2(m_uri, config); - VERIFY_ARE_EQUAL(baseclient2.base_uri(), m_uri); -} + // Verify that we can read the config from the http_client + TEST_FIXTURE(uri_address, get_client_config) + { + test_http_server::scoped_server scoped(m_uri); -#if !defined(_WIN32) && !defined(__cplusplus_winrt) + http_client_config config; -// Verify that the callback of sslcontext is called for HTTPS -TEST_FIXTURE(uri_address, ssl_context_callback_https) -{ - http_client_config config; - bool called = false; + VERIFY_ARE_EQUAL(config.chunksize(), 64 * 1024); + config.set_chunksize(1024); + VERIFY_ARE_EQUAL(config.chunksize(), 1024); - config.set_ssl_context_callback([&called](boost::asio::ssl::context& ctx) - { - called = true; - }); + utility::seconds timeout(100); + config.set_timeout(timeout); + http_client client(m_uri, config); - http_client client("https://www.google.com/", config); + const http_client_config& config2 = client.client_config(); + VERIFY_ARE_EQUAL(config2.timeout().count(), timeout.count()); + std::chrono::milliseconds milli_timeout = config2.timeout(); + VERIFY_ARE_EQUAL(milli_timeout.count(), std::chrono::duration_cast(timeout).count()); + auto micro_timeout = config.timeout(); + VERIFY_ARE_EQUAL(micro_timeout.count(), std::chrono::duration_cast(timeout).count()); - try - { - client.request(methods::GET, U("/")).get(); + VERIFY_ARE_EQUAL(config2.chunksize(), 1024); } - catch (...) + + // Verify that we can get the baseuri from http_client constructors + TEST_FIXTURE(uri_address, BaseURI_test) { - } + http_client baseclient1(m_uri); + VERIFY_ARE_EQUAL(baseclient1.base_uri(), m_uri); - VERIFY_IS_TRUE(called, "The sslcontext options is not called for HTTPS protocol"); -} + http_client_config config; + http_client baseclient2(m_uri, config); + VERIFY_ARE_EQUAL(baseclient2.base_uri(), m_uri); + } -// Verify that the callback of sslcontext is not called for HTTP -TEST_FIXTURE(uri_address, ssl_context_callback_http) -{ - http_client_config config; - bool called = false; +#if !defined(_WIN32) && !defined(__cplusplus_winrt) - config.set_ssl_context_callback([&called](boost::asio::ssl::context& ctx) + // Verify that the callback of sslcontext is called for HTTPS + TEST_FIXTURE(uri_address, ssl_context_callback_https) { - called = true; - }); + http_client_config config; + bool called = false; - http_client client("http://www.google.com/", config); + config.set_ssl_context_callback([&called](boost::asio::ssl::context& ctx) { called = true; }); - try - { - client.request(methods::GET, U("/")).get(); + http_client client("https://www.google.com/", config); + + try + { + client.request(methods::GET, U("/")).get(); + } + catch (...) + { + } + + VERIFY_IS_TRUE(called, "The sslcontext options is not called for HTTPS protocol"); } - catch (...) + + // Verify that the callback of sslcontext is not called for HTTP + TEST_FIXTURE(uri_address, ssl_context_callback_http) { - } + http_client_config config; + bool called = false; + + config.set_ssl_context_callback([&called](boost::asio::ssl::context& ctx) { called = true; }); - VERIFY_IS_FALSE(called, "The sslcontext options is called for HTTP protocol"); -} + http_client client("http://www.google.com/", config); + + try + { + client.request(methods::GET, U("/")).get(); + } + catch (...) + { + } + + VERIFY_IS_FALSE(called, "The sslcontext options is called for HTTP protocol"); + } #endif } // SUITE(client_construction) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/compression_tests.cpp b/Release/tests/functional/http/client/compression_tests.cpp index 5a08103198..128006431b 100644 --- a/Release/tests/functional/http/client/compression_tests.cpp +++ b/Release/tests/functional/http/client/compression_tests.cpp @@ -2,13 +2,13 @@ * Copyright (C) Microsoft. All rights reserved. * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * - * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * compression_tests.cpp * * Tests cases, including client/server, for the web::http::compression namespace. * - * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" @@ -1338,7 +1338,7 @@ SUITE(compression_tests) } } } // SUITE(request_helper_tests) -} -} -} -} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/connection_pool_tests.cpp b/Release/tests/functional/http/client/connection_pool_tests.cpp index 037ed69d88..10880cb0b5 100644 --- a/Release/tests/functional/http/client/connection_pool_tests.cpp +++ b/Release/tests/functional/http/client/connection_pool_tests.cpp @@ -1,17 +1,21 @@ #include "stdafx.h" -#include + #include "../../../src/http/common/connection_pool_helpers.h" +#include using namespace web::http::client::details; -SUITE(connection_pooling) { - TEST(empty_returns_nullptr) { +SUITE(connection_pooling) +{ + TEST(empty_returns_nullptr) + { connection_pool_stack connectionStack; - VERIFY_ARE_EQUAL(connectionStack.try_acquire(), std::shared_ptr{}); + VERIFY_ARE_EQUAL(connectionStack.try_acquire(), std::shared_ptr {}); } static int noisyCount = 0; - struct noisy { + struct noisy + { noisy() = delete; noisy(int) { ++noisyCount; } noisy(const noisy&) = delete; @@ -21,7 +25,8 @@ SUITE(connection_pooling) { ~noisy() { --noisyCount; } }; - TEST(cycled_connections_survive) { + TEST(cycled_connections_survive) + { connection_pool_stack connectionStack; VERIFY_ARE_EQUAL(0, noisyCount); connectionStack.release(std::make_shared(42)); @@ -30,11 +35,11 @@ SUITE(connection_pooling) { VERIFY_ARE_EQUAL(3, noisyCount); VERIFY_IS_TRUE(connectionStack.free_stale_connections()); auto tmp = connectionStack.try_acquire(); - VERIFY_ARE_NOT_EQUAL(tmp, std::shared_ptr{}); + VERIFY_ARE_NOT_EQUAL(tmp, std::shared_ptr {}); connectionStack.release(std::move(tmp)); - VERIFY_ARE_EQUAL(tmp, std::shared_ptr{}); + VERIFY_ARE_EQUAL(tmp, std::shared_ptr {}); tmp = connectionStack.try_acquire(); - VERIFY_ARE_NOT_EQUAL(tmp, std::shared_ptr{}); + VERIFY_ARE_NOT_EQUAL(tmp, std::shared_ptr {}); connectionStack.release(std::move(tmp)); VERIFY_IS_TRUE(connectionStack.free_stale_connections()); VERIFY_ARE_EQUAL(1, noisyCount); diff --git a/Release/tests/functional/http/client/connections_and_errors.cpp b/Release/tests/functional/http/client/connections_and_errors.cpp index 24e452f023..22e0fc828f 100644 --- a/Release/tests/functional/http/client/connections_and_errors.cpp +++ b/Release/tests/functional/http/client/connections_and_errors.cpp @@ -1,13 +1,14 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases for covering issues dealing with http_client lifetime, underlying TCP connections, and general connection errors. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases for covering issues dealing with http_client lifetime, underlying TCP connections, and general connection + *errors. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -26,10 +27,16 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client +{ // Test implementation for pending_requests_after_client. -static void pending_requests_after_client_impl(const uri &address) +static void pending_requests_after_client_impl(const uri& address) { std::vector> completed_requests; { @@ -53,8 +60,7 @@ static void pending_requests_after_client_impl(const uri &address) // send responses. for (size_t i = 0; i < num_requests; ++i) { - completed_requests.push_back(requests[i].then([&](test_request *request) - { + completed_requests.push_back(requests[i].then([&](test_request* request) { http_asserts::assert_test_request_equals(request, mtd, U("/")); VERIFY_ARE_EQUAL(0u, request->reply(status_codes::OK)); })); @@ -79,374 +85,372 @@ static void pending_requests_after_client_impl(const uri &address) SUITE(connections_and_errors) { + // Tests requests still outstanding after the http_client has been destroyed. + TEST_FIXTURE(uri_address, pending_requests_after_client) { pending_requests_after_client_impl(m_uri); } -// Tests requests still outstanding after the http_client has been destroyed. -TEST_FIXTURE(uri_address, pending_requests_after_client) -{ - pending_requests_after_client_impl(m_uri); -} - -TEST_FIXTURE(uri_address, server_doesnt_exist) -{ - http_client_config config; - config.set_timeout(std::chrono::seconds(1)); - http_client client(m_uri, config); - VERIFY_THROWS(client.request(methods::GET).wait(), web::http::http_exception); -} - -TEST_FIXTURE(uri_address, open_failure) -{ - http_client client(U("http://localhost323:-1")); + TEST_FIXTURE(uri_address, server_doesnt_exist) + { + http_client_config config; + config.set_timeout(std::chrono::seconds(1)); + http_client client(m_uri, config); + VERIFY_THROWS(client.request(methods::GET).wait(), web::http::http_exception); + } - // This API should not throw. The exception should be surfaced - // during task.wait/get - auto t = client.request(methods::GET); - VERIFY_THROWS(t.wait(), web::http::http_exception); -} + TEST_FIXTURE(uri_address, open_failure) + { + http_client client(U("http://localhost323:-1")); -TEST_FIXTURE(uri_address, server_close_without_responding) -{ - http_client_config config; - config.set_timeout(utility::seconds(1)); + // This API should not throw. The exception should be surfaced + // during task.wait/get + auto t = client.request(methods::GET); + VERIFY_THROWS(t.wait(), web::http::http_exception); + } - http_client client(m_uri, config); - test_http_server::scoped_server server(m_uri); - auto t = server.server()->next_request(); + TEST_FIXTURE(uri_address, server_close_without_responding) + { + http_client_config config; + config.set_timeout(utility::seconds(1)); - // Send request. - auto response = client.request(methods::PUT); + http_client client(m_uri, config); + test_http_server::scoped_server server(m_uri); + auto t = server.server()->next_request(); - // Wait for request - VERIFY_NO_THROWS(t.get()); + // Send request. + auto response = client.request(methods::PUT); - // Close server connection. - server.server()->close(); + // Wait for request + VERIFY_NO_THROWS(t.get()); - VERIFY_THROWS_HTTP_ERROR_CODE(response.wait(), std::errc::connection_aborted); + // Close server connection. + server.server()->close(); - // Try sending another request. - VERIFY_THROWS(client.request(methods::GET).wait(), web::http::http_exception); -} + VERIFY_THROWS_HTTP_ERROR_CODE(response.wait(), std::errc::connection_aborted); -TEST_FIXTURE(uri_address, request_timeout) -{ - test_http_server::scoped_server scoped(m_uri); - auto t = scoped.server()->next_request(); - http_client_config config; - config.set_timeout(utility::seconds(1)); - - http_client client(m_uri, config); - auto responseTask = client.request(methods::GET); - -#ifdef __APPLE__ - // CodePlex 295 - VERIFY_THROWS(responseTask.get(), http_exception); -#else - VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::timed_out); -#endif - t.get(); -} + // Try sending another request. + VERIFY_THROWS(client.request(methods::GET).wait(), web::http::http_exception); + } -TEST_FIXTURE(uri_address, request_timeout_microsecond) -{ - pplx::task t; + TEST_FIXTURE(uri_address, request_timeout) { test_http_server::scoped_server scoped(m_uri); - t = scoped.server()->next_request(); + auto t = scoped.server()->next_request(); http_client_config config; - config.set_timeout(std::chrono::microseconds(500)); + config.set_timeout(utility::seconds(1)); http_client client(m_uri, config); auto responseTask = client.request(methods::GET); + #ifdef __APPLE__ // CodePlex 295 VERIFY_THROWS(responseTask.get(), http_exception); #else VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::timed_out); #endif + t.get(); } - try { t.get(); } - catch (...) {} -} -TEST_FIXTURE(uri_address, invalid_method) -{ - web::http::uri uri(U("http://www.bing.com/")); - http_client client(uri); - string_t invalid_chars = U("\a\b\f\v\n\r\t\x20\x7f"); + TEST_FIXTURE(uri_address, request_timeout_microsecond) + { + pplx::task t; + { + test_http_server::scoped_server scoped(m_uri); + t = scoped.server()->next_request(); + http_client_config config; + config.set_timeout(std::chrono::microseconds(500)); + + http_client client(m_uri, config); + auto responseTask = client.request(methods::GET); +#ifdef __APPLE__ + // CodePlex 295 + VERIFY_THROWS(responseTask.get(), http_exception); +#else + VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::timed_out); +#endif + } + try + { + t.get(); + } + catch (...) + { + } + } - for (auto iter = invalid_chars.begin(); iter < invalid_chars.end(); iter++) + TEST_FIXTURE(uri_address, invalid_method) { - string_t method = U("my method"); - method[2] = *iter; - VERIFY_THROWS(client.request(method).get(), http_exception); + web::http::uri uri(U("http://www.bing.com/")); + http_client client(uri); + string_t invalid_chars = U("\a\b\f\v\n\r\t\x20\x7f"); + + for (auto iter = invalid_chars.begin(); iter < invalid_chars.end(); iter++) + { + string_t method = U("my method"); + method[2] = *iter; + VERIFY_THROWS(client.request(method).get(), http_exception); + } } -} -// This test sends an SSL request to a non-SSL server and should fail on handshaking -TEST_FIXTURE(uri_address, handshake_fail) -{ - web::http::uri ssl_uri(U("https://localhost:34568/")); + // This test sends an SSL request to a non-SSL server and should fail on handshaking + TEST_FIXTURE(uri_address, handshake_fail) + { + web::http::uri ssl_uri(U("https://localhost:34568/")); - test_http_server::scoped_server scoped(m_uri); + test_http_server::scoped_server scoped(m_uri); - http_client client(ssl_uri); - auto request = client.request(methods::GET); + http_client client(ssl_uri); + auto request = client.request(methods::GET); - VERIFY_THROWS(request.get(), http_exception); -} + VERIFY_THROWS(request.get(), http_exception); + } #if !defined(__cplusplus_winrt) -TEST_FIXTURE(uri_address, content_ready_timeout) -{ - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); + TEST_FIXTURE(uri_address, content_ready_timeout) + { + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); - streams::producer_consumer_buffer buf; + streams::producer_consumer_buffer buf; - listener.support([buf](http_request request) - { - http_response response(200); - response.set_body(streams::istream(buf), U("text/plain")); - response.headers().add(header_names::connection, U("close")); - request.reply(response); - }); + listener.support([buf](http_request request) { + http_response response(200); + response.set_body(streams::istream(buf), U("text/plain")); + response.headers().add(header_names::connection, U("close")); + request.reply(response); + }); - { - http_client_config config; - config.set_timeout(utility::seconds(1)); - http_client client(m_uri, config); - http_request msg(methods::GET); - http_response rsp = client.request(msg).get(); + { + http_client_config config; + config.set_timeout(utility::seconds(1)); + http_client client(m_uri, config); + http_request msg(methods::GET); + http_response rsp = client.request(msg).get(); - // The response body should timeout and we should receive an exception + // The response body should timeout and we should receive an exception #ifndef _WIN32 - // CodePlex 295 - VERIFY_THROWS(rsp.content_ready().wait(), http_exception); + // CodePlex 295 + VERIFY_THROWS(rsp.content_ready().wait(), http_exception); #else - VERIFY_THROWS_HTTP_ERROR_CODE(rsp.content_ready().wait(), std::errc::timed_out); + VERIFY_THROWS_HTTP_ERROR_CODE(rsp.content_ready().wait(), std::errc::timed_out); #endif - } - - buf.close(std::ios_base::out).wait(); - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, stream_timeout) -{ - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); + } - streams::producer_consumer_buffer buf; + buf.close(std::ios_base::out).wait(); + listener.close().wait(); + } - listener.support([buf](http_request request) + TEST_FIXTURE(uri_address, stream_timeout) { - http_response response(200); - response.set_body(streams::istream(buf), U("text/plain")); - response.headers().add(header_names::connection, U("close")); - request.reply(response); - }); + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); - { - http_client_config config; - config.set_timeout(utility::seconds(1)); - http_client client(m_uri, config); - http_request msg(methods::GET); - http_response rsp = client.request(msg).get(); + streams::producer_consumer_buffer buf; - // The response body should timeout and we should receive an exception - auto readTask = rsp.body().read_to_end(streams::producer_consumer_buffer()); + listener.support([buf](http_request request) { + http_response response(200); + response.set_body(streams::istream(buf), U("text/plain")); + response.headers().add(header_names::connection, U("close")); + request.reply(response); + }); + + { + http_client_config config; + config.set_timeout(utility::seconds(1)); + http_client client(m_uri, config); + http_request msg(methods::GET); + http_response rsp = client.request(msg).get(); + + // The response body should timeout and we should receive an exception + auto readTask = rsp.body().read_to_end(streams::producer_consumer_buffer()); #ifndef _WIN32 - // CodePlex 295 - VERIFY_THROWS(readTask.get(), http_exception); + // CodePlex 295 + VERIFY_THROWS(readTask.get(), http_exception); #else - VERIFY_THROWS_HTTP_ERROR_CODE(readTask.wait(), std::errc::timed_out); + VERIFY_THROWS_HTTP_ERROR_CODE(readTask.wait(), std::errc::timed_out); #endif - } + } - buf.close(std::ios_base::out).wait(); - listener.close().wait(); -} + buf.close(std::ios_base::out).wait(); + listener.close().wait(); + } #endif -TEST_FIXTURE(uri_address, cancel_before_request) -{ - test_http_server::scoped_server scoped(m_uri); - http_client c(m_uri); - pplx::cancellation_token_source source; - source.cancel(); + TEST_FIXTURE(uri_address, cancel_before_request) + { + test_http_server::scoped_server scoped(m_uri); + http_client c(m_uri); + pplx::cancellation_token_source source; + source.cancel(); - auto responseTask = c.request(methods::PUT, U("/"), source.get_token()); - VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::operation_canceled); -} + auto responseTask = c.request(methods::PUT, U("/"), source.get_token()); + VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::operation_canceled); + } // This test can't be implemented with our test server so isn't available on WinRT. #ifndef __cplusplus_winrt -TEST_FIXTURE(uri_address, cancel_after_headers) -{ - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); - http_client c(m_uri); - pplx::cancellation_token_source source; - pplx::extensibility::event_t ev; - - listener.support([&](http_request request) + TEST_FIXTURE(uri_address, cancel_after_headers) { - streams::producer_consumer_buffer buf; - http_response response(200); - response.set_body(streams::istream(buf), U("text/plain")); - request.reply(response); - ev.wait(); - buf.putc('a').wait(); - buf.putc('b').wait(); - buf.putc('c').wait(); - buf.putc('d').wait(); - buf.close(std::ios::out).wait(); - }); + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); + http_client c(m_uri); + pplx::cancellation_token_source source; + pplx::extensibility::event_t ev; + + listener.support([&](http_request request) { + streams::producer_consumer_buffer buf; + http_response response(200); + response.set_body(streams::istream(buf), U("text/plain")); + request.reply(response); + ev.wait(); + buf.putc('a').wait(); + buf.putc('b').wait(); + buf.putc('c').wait(); + buf.putc('d').wait(); + buf.close(std::ios::out).wait(); + }); + + auto responseTask = c.request(methods::GET, source.get_token()); + http_response response = responseTask.get(); + source.cancel(); + ev.set(); - auto responseTask = c.request(methods::GET, source.get_token()); - http_response response = responseTask.get(); - source.cancel(); - ev.set(); + VERIFY_THROWS_HTTP_ERROR_CODE(response.extract_string().get(), std::errc::operation_canceled); - VERIFY_THROWS_HTTP_ERROR_CODE(response.extract_string().get(), std::errc::operation_canceled); - - // Codeplex 328. + // Codeplex 328. #if !defined(_WIN32) - tests::common::utilities::os_utilities::sleep(1000); + tests::common::utilities::os_utilities::sleep(1000); #endif - - listener.close().wait(); -} + + listener.close().wait(); + } #endif -TEST_FIXTURE(uri_address, cancel_after_body) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client c(m_uri); - pplx::cancellation_token_source source; - std::map headers; - headers[U("Content-Type")] = U("text/plain; charset=utf-8"); - std::string bodyData("Hello"); - - p_server->next_request().then([&](test_request *r) + TEST_FIXTURE(uri_address, cancel_after_body) { - VERIFY_ARE_EQUAL(0u, r->reply(status_codes::OK, U("OK"), headers, bodyData)); - }); + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client c(m_uri); + pplx::cancellation_token_source source; + std::map headers; + headers[U("Content-Type")] = U("text/plain; charset=utf-8"); + std::string bodyData("Hello"); - auto response = c.request(methods::PUT, U("/"), U("data"), source.get_token()).get(); - VERIFY_ARE_EQUAL(utility::conversions::to_string_t(bodyData), response.extract_string().get()); - source.cancel(); - response.content_ready().wait(); -} + p_server->next_request().then( + [&](test_request* r) { VERIFY_ARE_EQUAL(0u, r->reply(status_codes::OK, U("OK"), headers, bodyData)); }); -TEST_FIXTURE(uri_address, cancel_with_error) -{ - http_client c(m_uri); - pplx::task responseTask; + auto response = c.request(methods::PUT, U("/"), U("data"), source.get_token()).get(); + VERIFY_ARE_EQUAL(utility::conversions::to_string_t(bodyData), response.extract_string().get()); + source.cancel(); + response.content_ready().wait(); + } + + TEST_FIXTURE(uri_address, cancel_with_error) { - test_http_server::scoped_server server(m_uri); - pplx::cancellation_token_source source; + http_client c(m_uri); + pplx::task responseTask; + { + test_http_server::scoped_server server(m_uri); + pplx::cancellation_token_source source; - responseTask = c.request(methods::GET, U("/"), source.get_token()); - source.cancel(); + responseTask = c.request(methods::GET, U("/"), source.get_token()); + source.cancel(); + } + + // All errors after cancellation are ignored. + VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::operation_canceled); } - // All errors after cancellation are ignored. - VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::operation_canceled); -} + TEST_FIXTURE(uri_address, cancel_while_uploading_data) + { + test_http_server::scoped_server scoped(m_uri); + http_client c(m_uri); + pplx::cancellation_token_source source; -TEST_FIXTURE(uri_address, cancel_while_uploading_data) -{ - test_http_server::scoped_server scoped(m_uri); - http_client c(m_uri); - pplx::cancellation_token_source source; - - auto buf = streams::producer_consumer_buffer(); - buf.putc('A').wait(); - auto responseTask = c.request(methods::PUT, U("/"), buf.create_istream(), 2, source.get_token()); - source.cancel(); - buf.putc('B').wait(); - buf.close(std::ios::out).wait(); - VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::operation_canceled); -} + auto buf = streams::producer_consumer_buffer(); + buf.putc('A').wait(); + auto responseTask = c.request(methods::PUT, U("/"), buf.create_istream(), 2, source.get_token()); + source.cancel(); + buf.putc('B').wait(); + buf.close(std::ios::out).wait(); + VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::operation_canceled); + } // This test can't be implemented with our test server since it doesn't stream data so isn't avaliable on WinRT. #ifndef __cplusplus_winrt -TEST_FIXTURE(uri_address, cancel_while_downloading_data) -{ - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); - http_client c(m_uri); - pplx::cancellation_token_source source; - - pplx::extensibility::event_t ev; - pplx::extensibility::event_t ev2; - - listener.support([&](http_request request) + TEST_FIXTURE(uri_address, cancel_while_downloading_data) { - streams::producer_consumer_buffer buf; - http_response response(200); - response.set_body(streams::istream(buf), U("text/plain")); - request.reply(response); - buf.putc('a').wait(); - buf.putc('b').wait(); - ev.set(); - ev2.wait(); - buf.putc('c').wait(); - buf.putc('d').wait(); - buf.close(std::ios::out).wait(); - }); + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); + http_client c(m_uri); + pplx::cancellation_token_source source; - auto response = c.request(methods::GET, source.get_token()).get(); - ev.wait(); - source.cancel(); - ev2.set(); + pplx::extensibility::event_t ev; + pplx::extensibility::event_t ev2; + + listener.support([&](http_request request) { + streams::producer_consumer_buffer buf; + http_response response(200); + response.set_body(streams::istream(buf), U("text/plain")); + request.reply(response); + buf.putc('a').wait(); + buf.putc('b').wait(); + ev.set(); + ev2.wait(); + buf.putc('c').wait(); + buf.putc('d').wait(); + buf.close(std::ios::out).wait(); + }); + + auto response = c.request(methods::GET, source.get_token()).get(); + ev.wait(); + source.cancel(); + ev2.set(); - VERIFY_THROWS_HTTP_ERROR_CODE(response.extract_string().get(), std::errc::operation_canceled); + VERIFY_THROWS_HTTP_ERROR_CODE(response.extract_string().get(), std::errc::operation_canceled); - // Codeplex 328. + // Codeplex 328. #if !defined(_WIN32) - tests::common::utilities::os_utilities::sleep(1000); + tests::common::utilities::os_utilities::sleep(1000); #endif - - listener.close().wait(); -} + + listener.close().wait(); + } #endif -// Try to connect to a server on a closed port and cancel the operation. -TEST_FIXTURE(uri_address, cancel_bad_port) -{ - // http_client_asio had a bug where, when canceled, it would cancel only the - // current connection but then go and try the next address from the list of - // resolved addresses, i.e., it wouldn't actually cancel as long as there - // are more addresses to try. Consequently, it would not report the task as - // being canceled. This was easiest to observe when trying to connect to a - // server that does not respond on a certain port, otherwise the timing - // might be tricky. - - // We need to connect to a URI for which there are multiple addresses - // associated (i.e., multiple A records). - web::http::uri uri(U("https://microsoft.com:442/")); - - // Send request. - http_client_config config; - config.set_timeout(std::chrono::milliseconds(1000)); - http_client c(uri, config); - web::http::http_request r; - auto cts = pplx::cancellation_token_source(); - auto ct = cts.get_token(); - auto t = c.request(r, ct); - - // Make sure that the client already finished resolving before canceling, - // otherwise the bug might not be triggered. - std::this_thread::sleep_for(std::chrono::milliseconds(400)); - cts.cancel(); - - VERIFY_THROWS_HTTP_ERROR_CODE(t.get(), std::errc::operation_canceled); -} + // Try to connect to a server on a closed port and cancel the operation. + TEST_FIXTURE(uri_address, cancel_bad_port) + { + // http_client_asio had a bug where, when canceled, it would cancel only the + // current connection but then go and try the next address from the list of + // resolved addresses, i.e., it wouldn't actually cancel as long as there + // are more addresses to try. Consequently, it would not report the task as + // being canceled. This was easiest to observe when trying to connect to a + // server that does not respond on a certain port, otherwise the timing + // might be tricky. + + // We need to connect to a URI for which there are multiple addresses + // associated (i.e., multiple A records). + web::http::uri uri(U("https://microsoft.com:442/")); + + // Send request. + http_client_config config; + config.set_timeout(std::chrono::milliseconds(1000)); + http_client c(uri, config); + web::http::http_request r; + auto cts = pplx::cancellation_token_source(); + auto ct = cts.get_token(); + auto t = c.request(r, ct); + + // Make sure that the client already finished resolving before canceling, + // otherwise the bug might not be triggered. + std::this_thread::sleep_for(std::chrono::milliseconds(400)); + cts.cancel(); + + VERIFY_THROWS_HTTP_ERROR_CODE(t.get(), std::errc::operation_canceled); + } } // SUITE(connections_and_errors) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/header_tests.cpp b/Release/tests/functional/http/client/header_tests.cpp index 1b92d3a772..4936aab36e 100644 --- a/Release/tests/functional/http/client/header_tests.cpp +++ b/Release/tests/functional/http/client/header_tests.cpp @@ -1,15 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases for http_headers. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases for http_headers. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/details/http_helpers.h" using namespace web::http; @@ -17,392 +18,388 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(outside_tests) +namespace tests { - -TEST_FIXTURE(uri_address, request_headers) +namespace functional +{ +namespace http +{ +namespace client { - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); +SUITE(outside_tests) +{ + TEST_FIXTURE(uri_address, request_headers) + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); - http_request msg(methods::POST); + http_request msg(methods::POST); #ifndef __cplusplus_winrt - // The WinRT-based HTTP stack does not support headers that have no - // value, which means that there is no point in making this particular - // header test, it is an unsupported feature on WinRT. - msg.headers().add(U("HEHE"), U("")); -#endif - - msg.headers().add(U("MyHeader"), U("hehe;blach")); - msg.headers().add(U("Yo1"), U("You, Too")); - msg.headers().add(U("Yo2"), U("You2")); - msg.headers().add(U("Yo3"), U("You3")); - msg.headers().add(U("Yo4"), U("You4")); - msg.headers().add(U("Yo5"), U("You5")); - msg.headers().add(U("Yo6"), U("You6")); - msg.headers().add(U("Yo7"), U("You7")); - msg.headers().add(U("Yo8"), U("You8")); - msg.headers().add(U("Yo9"), U("You9")); - msg.headers().add(U("Yo10"), U("You10")); - msg.headers().add(U("Yo11"), U("You11")); - msg.headers().add(U("Accept"), U("text/plain")); - VERIFY_ARE_EQUAL(U("You5"), msg.headers()[U("Yo5")]); - p_server->next_request().then([&](test_request *p_request) + // The WinRT-based HTTP stack does not support headers that have no + // value, which means that there is no point in making this particular + // header test, it is an unsupported feature on WinRT. + msg.headers().add(U("HEHE"), U("")); +#endif + + msg.headers().add(U("MyHeader"), U("hehe;blach")); + msg.headers().add(U("Yo1"), U("You, Too")); + msg.headers().add(U("Yo2"), U("You2")); + msg.headers().add(U("Yo3"), U("You3")); + msg.headers().add(U("Yo4"), U("You4")); + msg.headers().add(U("Yo5"), U("You5")); + msg.headers().add(U("Yo6"), U("You6")); + msg.headers().add(U("Yo7"), U("You7")); + msg.headers().add(U("Yo8"), U("You8")); + msg.headers().add(U("Yo9"), U("You9")); + msg.headers().add(U("Yo10"), U("You10")); + msg.headers().add(U("Yo11"), U("You11")); + msg.headers().add(U("Accept"), U("text/plain")); + VERIFY_ARE_EQUAL(U("You5"), msg.headers()[U("Yo5")]); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); + http_asserts::assert_test_request_contains_headers(p_request, msg.headers()); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + + TEST_FIXTURE(uri_address, field_name_casing) { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); - http_asserts::assert_test_request_contains_headers(p_request, msg.headers()); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -} - -TEST_FIXTURE(uri_address, field_name_casing) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - const method mtd = methods::GET; - const utility::string_t field_name1 = U("CustomHeader"); - const utility::string_t field_name2 = U("CUSTOMHEADER"); - const utility::string_t field_name3 = U("CuSTomHEAdeR"); - const utility::string_t value1 = U("value1"); - const utility::string_t value2 = U("value2"); - const utility::string_t value3 = U("value3"); - - http_request msg(mtd); - msg.headers()[field_name1] = value1; - msg.headers()[field_name2].append(U(", ") + value2); - msg.headers()[field_name3].append(U(", ") + value3); - scoped.server()->next_request().then([&](test_request *p_request) + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + const method mtd = methods::GET; + const utility::string_t field_name1 = U("CustomHeader"); + const utility::string_t field_name2 = U("CUSTOMHEADER"); + const utility::string_t field_name3 = U("CuSTomHEAdeR"); + const utility::string_t value1 = U("value1"); + const utility::string_t value2 = U("value2"); + const utility::string_t value3 = U("value3"); + + http_request msg(mtd); + msg.headers()[field_name1] = value1; + msg.headers()[field_name2].append(U(", ") + value2); + msg.headers()[field_name3].append(U(", ") + value3); + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + std::map expected_headers; + expected_headers[field_name1] = value1 + U(", ") + value2 + U(", ") + value3; + http_asserts::assert_test_request_contains_headers(p_request, expected_headers); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + + TEST_FIXTURE(uri_address, field_name_duplicate) { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - std::map expected_headers; - expected_headers[field_name1] = value1 + U(", ") + value2 + U(", ") + value3; - http_asserts::assert_test_request_contains_headers(p_request, expected_headers); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -} - - -TEST_FIXTURE(uri_address, field_name_duplicate) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - const method mtd = methods::GET; - const utility::string_t field_name1 = U("CUSTOMHEADER"); - const utility::string_t value1 = U("value1"); - const utility::string_t value2 = U("value2"); - - http_request msg(mtd); - msg.headers().add(field_name1, value1); - msg.headers().add(field_name1, value2); - scoped.server()->next_request().then([&](test_request *p_request) + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + const method mtd = methods::GET; + const utility::string_t field_name1 = U("CUSTOMHEADER"); + const utility::string_t value1 = U("value1"); + const utility::string_t value2 = U("value2"); + + http_request msg(mtd); + msg.headers().add(field_name1, value1); + msg.headers().add(field_name1, value2); + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + std::map expected_headers; + expected_headers[field_name1] = value1 + U(", ") + value2; + http_asserts::assert_test_request_contains_headers(p_request, expected_headers); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + + TEST_FIXTURE(uri_address, field_name_no_multivalue_allowed) { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - std::map expected_headers; - expected_headers[field_name1] = value1 + U(", ") + value2; - http_asserts::assert_test_request_contains_headers(p_request, expected_headers); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -} - -TEST_FIXTURE(uri_address, field_name_no_multivalue_allowed) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - const method mtd = methods::GET; + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + const method mtd = methods::GET; + + http_request msg(mtd); + + msg.headers().set_content_type(web::http::details::mime_types::text_plain); + msg.headers().set_content_type(web::http::details::mime_types::application_json); + + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + std::map expected_headers; + expected_headers[U("Content-Type")] = web::http::details::mime_types::application_json; + http_asserts::assert_test_request_contains_headers(p_request, expected_headers); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + TEST_FIXTURE(uri_address, copy_move) + { + // copy constructor + http_headers h1; + h1.add(U("key1"), U("key2")); + http_headers h2(h1); + http_asserts::assert_http_headers_equals(h1, h2); + + // move constructor + http_headers h3(std::move(h1)); + VERIFY_ARE_EQUAL(1u, h3.size()); + VERIFY_ARE_EQUAL(U("key2"), h3[U("key1")]); + + // assignment operator + h1 = h3; + VERIFY_ARE_EQUAL(1u, h1.size()); + VERIFY_ARE_EQUAL(U("key2"), h1[U("key1")]); + http_asserts::assert_http_headers_equals(h1, h3); + + // move assignment operator + h1 = http_headers(); + h1 = std::move(h2); + VERIFY_ARE_EQUAL(1u, h1.size()); + VERIFY_ARE_EQUAL(U("key2"), h1[U("key1")]); + } + + TEST_FIXTURE(uri_address, match_types) + { + // wchar + http_headers h1; + h1[U("key1")] = U("string"); + utility::char_t buf[12]; + VERIFY_IS_TRUE(h1.match(U("key1"), buf)); + VERIFY_ARE_EQUAL(U("string"), utility::string_t(buf)); + + // utility::string_t + utility::string_t wstr; + VERIFY_IS_TRUE(h1.match(U("key1"), wstr)); + VERIFY_ARE_EQUAL(U("string"), wstr); + + // int + h1[U("key2")] = U("22"); + int i; + VERIFY_IS_TRUE(h1.match(U("key2"), i)); + VERIFY_ARE_EQUAL(22, i); + + // unsigned long + unsigned long l; + VERIFY_IS_TRUE(h1.match(U("key2"), l)); + VERIFY_ARE_EQUAL(22ul, l); + } + + TEST_FIXTURE(uri_address, match_edge_cases) + { + // match with empty string + http_headers h; + h[U("here")] = U(""); + utility::string_t value(U("k")); + VERIFY_IS_TRUE(h.match(U("HeRE"), value)); + VERIFY_ARE_EQUAL(U(""), value); + + // match with string containing spaces + h.add(U("blah"), U("spaces ss")); + VERIFY_IS_TRUE(h.match(U("blah"), value)); + VERIFY_ARE_EQUAL(U("spaces ss"), value); + + // match failing + value = utility::string_t(); + VERIFY_IS_FALSE(h.match(U("hahah"), value)); + VERIFY_ARE_EQUAL(U(""), value); + } + + TEST_FIXTURE(uri_address, headers_find) + { + // Find when empty. + http_headers h; + VERIFY_ARE_EQUAL(h.end(), h.find(U("key1"))); - http_request msg(mtd); + // Find that exists. + h[U("key1")] = U("yes"); + VERIFY_ARE_EQUAL(U("yes"), h.find(U("key1"))->second); - msg.headers().set_content_type(web::http::details::mime_types::text_plain); - msg.headers().set_content_type(web::http::details::mime_types::application_json); + // Find that doesn't exist. + VERIFY_ARE_EQUAL(h.end(), h.find(U("key2"))); + } - scoped.server()->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, headers_add) { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - std::map expected_headers; - expected_headers[U("Content-Type")] = web::http::details::mime_types::application_json; - http_asserts::assert_test_request_contains_headers(p_request, expected_headers); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -} -TEST_FIXTURE(uri_address, copy_move) -{ - // copy constructor - http_headers h1; - h1.add(U("key1"), U("key2")); - http_headers h2(h1); - http_asserts::assert_http_headers_equals(h1, h2); - - // move constructor - http_headers h3(std::move(h1)); - VERIFY_ARE_EQUAL(1u, h3.size()); - VERIFY_ARE_EQUAL(U("key2"), h3[U("key1")]); - - // assignment operator - h1 = h3; - VERIFY_ARE_EQUAL(1u, h1.size()); - VERIFY_ARE_EQUAL(U("key2"), h1[U("key1")]); - http_asserts::assert_http_headers_equals(h1, h3); - - // move assignment operator - h1 = http_headers(); - h1 = std::move(h2); - VERIFY_ARE_EQUAL(1u, h1.size()); - VERIFY_ARE_EQUAL(U("key2"), h1[U("key1")]); -} - -TEST_FIXTURE(uri_address, match_types) -{ - // wchar - http_headers h1; - h1[U("key1")] = U("string"); - utility::char_t buf[12]; - VERIFY_IS_TRUE(h1.match(U("key1"), buf)); - VERIFY_ARE_EQUAL(U("string"), utility::string_t(buf)); - - // utility::string_t - utility::string_t wstr; - VERIFY_IS_TRUE(h1.match(U("key1"), wstr)); - VERIFY_ARE_EQUAL(U("string"), wstr); - - // int - h1[U("key2")] = U("22"); - int i; - VERIFY_IS_TRUE(h1.match(U("key2"), i)); - VERIFY_ARE_EQUAL(22, i); - - // unsigned long - unsigned long l; - VERIFY_IS_TRUE(h1.match(U("key2"), l)); - VERIFY_ARE_EQUAL(22ul, l); -} - -TEST_FIXTURE(uri_address, match_edge_cases) -{ - // match with empty string - http_headers h; - h[U("here")] = U(""); - utility::string_t value(U("k")); - VERIFY_IS_TRUE(h.match(U("HeRE"), value)); - VERIFY_ARE_EQUAL(U(""), value); - - // match with string containing spaces - h.add(U("blah"), U("spaces ss")); - VERIFY_IS_TRUE(h.match(U("blah"), value)); - VERIFY_ARE_EQUAL(U("spaces ss"), value); - - // match failing - value = utility::string_t(); - VERIFY_IS_FALSE(h.match(U("hahah"), value)); - VERIFY_ARE_EQUAL(U(""), value); -} - -TEST_FIXTURE(uri_address, headers_find) -{ - // Find when empty. - http_headers h; - VERIFY_ARE_EQUAL(h.end(), h.find(U("key1"))); + // Add multiple + http_headers h; + h.add(U("key1"), 22); + h.add(U("key2"), U("str2")); + VERIFY_ARE_EQUAL(U("22"), h[U("key1")]); + VERIFY_ARE_EQUAL(U("str2"), h[U("key2")]); + + // Add one that already exists + h.add(U("key2"), U("str3")); + VERIFY_ARE_EQUAL(U("str2, str3"), h[U("key2")]); + + // Add with different case + h.add(U("KEY2"), U("str4")); + VERIFY_ARE_EQUAL(U("str2, str3, str4"), h[U("keY2")]); + + // Add with spaces in string + h.add(U("key3"), U("value with spaces")); + VERIFY_ARE_EQUAL(U("value with spaces"), h[U("key3")]); + } + + TEST_FIXTURE(uri_address, headers_iterators) + { + // begin when empty + http_headers h; + VERIFY_ARE_EQUAL(h.begin(), h.end()); + + // with some values. + h.add(U("key1"), U("value1")); + h.add(U("key2"), U("value2")); + h.add(U("key3"), U("value3")); + http_headers::const_iterator iter = h.begin(); + VERIFY_ARE_EQUAL(U("value1"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("value2"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("value3"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(h.end(), iter); + } + + TEST_FIXTURE(uri_address, headers_foreach) + { + // begin when empty + http_headers h; + VERIFY_ARE_EQUAL(h.begin(), h.end()); - // Find that exists. - h[U("key1")] = U("yes"); - VERIFY_ARE_EQUAL(U("yes"), h.find(U("key1"))->second); + // with some values. + h.add(U("key1"), U("value")); + h.add(U("key2"), U("value")); + h.add(U("key3"), U("value")); - // Find that doesn't exist. - VERIFY_ARE_EQUAL(h.end(), h.find(U("key2"))); -} + std::for_each(std::begin(h), std::end(h), [=](http_headers::const_reference kv) { + VERIFY_ARE_EQUAL(U("value"), kv.second); + }); -TEST_FIXTURE(uri_address, headers_add) -{ - // Add multiple - http_headers h; - h.add(U("key1"), 22); - h.add(U("key2"), U("str2")); - VERIFY_ARE_EQUAL(U("22"), h[U("key1")]); - VERIFY_ARE_EQUAL(U("str2"), h[U("key2")]); - - // Add one that already exists - h.add(U("key2"), U("str3")); - VERIFY_ARE_EQUAL(U("str2, str3"), h[U("key2")]); - - // Add with different case - h.add(U("KEY2"), U("str4")); - VERIFY_ARE_EQUAL(U("str2, str3, str4"), h[U("keY2")]); - - // Add with spaces in string - h.add(U("key3"), U("value with spaces")); - VERIFY_ARE_EQUAL(U("value with spaces"), h[U("key3")]); -} - -TEST_FIXTURE(uri_address, headers_iterators) -{ - // begin when empty - http_headers h; - VERIFY_ARE_EQUAL(h.begin(), h.end()); - - // with some values. - h.add(U("key1"), U("value1")); - h.add(U("key2"), U("value2")); - h.add(U("key3"), U("value3")); - http_headers::const_iterator iter = h.begin(); - VERIFY_ARE_EQUAL(U("value1"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("value2"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("value3"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(h.end(), iter); -} - -TEST_FIXTURE(uri_address, headers_foreach) -{ - // begin when empty - http_headers h; - VERIFY_ARE_EQUAL(h.begin(), h.end()); - - // with some values. - h.add(U("key1"), U("value")); - h.add(U("key2"), U("value")); - h.add(U("key3"), U("value")); - - std::for_each(std::begin(h), std::end(h), - [=](http_headers::const_reference kv) - { - VERIFY_ARE_EQUAL(U("value"), kv.second); - }); + std::for_each( + std::begin(h), std::end(h), [=](http_headers::reference kv) { VERIFY_ARE_EQUAL(U("value"), kv.second); }); + } - std::for_each(std::begin(h), std::end(h), - [=](http_headers::reference kv) + TEST_FIXTURE(uri_address, response_headers) { - VERIFY_ARE_EQUAL(U("value"), kv.second); - }); -} - -TEST_FIXTURE(uri_address, response_headers) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - std::map headers; - headers[U("H1")] = U(""); - headers[U("H2")] = U("hah"); - headers[U("H3")] = U("es"); - headers[U("H4")] = U("es;kjr"); - headers[U("H5")] = U("asb"); - headers[U("H6")] = U("abc"); - headers[U("H7")] = U("eds"); - headers[U("H8")] = U("blue"); - headers[U("H9")] = U("sd"); - headers[U("H10")] = U("res"); - test_server_utilities::verify_request(&client, methods::GET, U("/"), scoped.server(), status_codes::OK, headers); -} - -TEST_FIXTURE(uri_address, cache_control_header) -{ - http_headers headers; - VERIFY_ARE_EQUAL(headers.cache_control(), U("")); - const utility::string_t value(U("custom value")); - headers.set_cache_control(value); - VERIFY_ARE_EQUAL(headers.cache_control(), value); - utility::string_t foundValue; - VERIFY_IS_TRUE(headers.match(header_names::cache_control, foundValue)); - VERIFY_ARE_EQUAL(value, foundValue); -} - -TEST_FIXTURE(uri_address, content_length_header) -{ - http_headers headers; - VERIFY_ARE_EQUAL(headers.content_length(), 0); - const size_t value = 44; - headers.set_content_length(value); - VERIFY_ARE_EQUAL(headers.content_length(), value); - size_t foundValue; - VERIFY_IS_TRUE(headers.match(header_names::content_length, foundValue)); - VERIFY_ARE_EQUAL(value, foundValue); -} - -TEST_FIXTURE(uri_address, date_header) -{ - http_headers headers; - VERIFY_ARE_EQUAL(headers.date(), U("")); - const utility::datetime value(utility::datetime::utc_now()); - headers.set_date(value); - VERIFY_ARE_EQUAL(headers.date(), value.to_string()); - utility::string_t foundValue; - VERIFY_IS_TRUE(headers.match(header_names::date, foundValue)); - VERIFY_ARE_EQUAL(value.to_string(), foundValue); -} - - -TEST_FIXTURE(uri_address, parsing_content_type_redundantsemicolon_json) -{ - test_http_server::scoped_server scoped(m_uri); - web::json::value body = web::json::value::string(U("Json body")); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); - scoped.server()->next_request().then([&](test_request *p_request){ std::map headers; - headers[header_names::content_type] = U("application/json; charset=utf-8;;;;"); - p_request->reply(200, U("OK"), headers, utility::conversions::to_utf8string(body.serialize())); - }); + headers[U("H1")] = U(""); + headers[U("H2")] = U("hah"); + headers[U("H3")] = U("es"); + headers[U("H4")] = U("es;kjr"); + headers[U("H5")] = U("asb"); + headers[U("H6")] = U("abc"); + headers[U("H7")] = U("eds"); + headers[U("H8")] = U("blue"); + headers[U("H9")] = U("sd"); + headers[U("H10")] = U("res"); + test_server_utilities::verify_request( + &client, methods::GET, U("/"), scoped.server(), status_codes::OK, headers); + } + + TEST_FIXTURE(uri_address, cache_control_header) + { + http_headers headers; + VERIFY_ARE_EQUAL(headers.cache_control(), U("")); + const utility::string_t value(U("custom value")); + headers.set_cache_control(value); + VERIFY_ARE_EQUAL(headers.cache_control(), value); + utility::string_t foundValue; + VERIFY_IS_TRUE(headers.match(header_names::cache_control, foundValue)); + VERIFY_ARE_EQUAL(value, foundValue); + } + + TEST_FIXTURE(uri_address, content_length_header) + { + http_headers headers; + VERIFY_ARE_EQUAL(headers.content_length(), 0); + const size_t value = 44; + headers.set_content_length(value); + VERIFY_ARE_EQUAL(headers.content_length(), value); + size_t foundValue; + VERIFY_IS_TRUE(headers.match(header_names::content_length, foundValue)); + VERIFY_ARE_EQUAL(value, foundValue); + } + + TEST_FIXTURE(uri_address, date_header) + { + http_headers headers; + VERIFY_ARE_EQUAL(headers.date(), U("")); + const utility::datetime value(utility::datetime::utc_now()); + headers.set_date(value); + VERIFY_ARE_EQUAL(headers.date(), value.to_string()); + utility::string_t foundValue; + VERIFY_IS_TRUE(headers.match(header_names::date, foundValue)); + VERIFY_ARE_EQUAL(value.to_string(), foundValue); + } + + TEST_FIXTURE(uri_address, parsing_content_type_redundantsemicolon_json) + { + test_http_server::scoped_server scoped(m_uri); + web::json::value body = web::json::value::string(U("Json body")); - http_client client(m_uri); - auto resp = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(resp.extract_json().get().serialize(), body.serialize()); -} + scoped.server()->next_request().then([&](test_request* p_request) { + std::map headers; + headers[header_names::content_type] = U("application/json; charset=utf-8;;;;"); + p_request->reply(200, U("OK"), headers, utility::conversions::to_utf8string(body.serialize())); + }); -TEST_FIXTURE(uri_address, parsing_content_type_redundantsemicolon_string) -{ - test_http_server::scoped_server scoped(m_uri); - std::string body("Body"); - scoped.server()->next_request().then([&](test_request *p_request){ - std::map headers; - headers[header_names::content_type] = U("text/plain; charset = UTF-8;;;; "); - p_request->reply(200, U("OK"), headers, body); - }); + http_client client(m_uri); + auto resp = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(resp.extract_json().get().serialize(), body.serialize()); + } - http_client client(m_uri); - auto resp = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(resp.extract_string().get(), utility::conversions::to_string_t(body)); -} - -TEST_FIXTURE(uri_address, overwrite_http_header) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - // Test default case of cpprestsdk setting host header as host:port - auto& host = m_uri.host(); - int port = m_uri.port(); - utility::string_t expected_default_header = host + U(":") + utility::conversions::details::to_string_t(port); - http_request default_host_headers_request(methods::GET); - scoped.server()->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, parsing_content_type_redundantsemicolon_string) { - auto headers = p_request->m_headers; - VERIFY_ARE_EQUAL(expected_default_header, headers[header_names::host]); - p_request->reply(200); - }); - - client.request(default_host_headers_request).get(); + test_http_server::scoped_server scoped(m_uri); + std::string body("Body"); + scoped.server()->next_request().then([&](test_request* p_request) { + std::map headers; + headers[header_names::content_type] = U("text/plain; charset = UTF-8;;;; "); + p_request->reply(200, U("OK"), headers, body); + }); + + http_client client(m_uri); + auto resp = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(resp.extract_string().get(), utility::conversions::to_string_t(body)); + } + + TEST_FIXTURE(uri_address, overwrite_http_header) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + // Test default case of cpprestsdk setting host header as host:port + auto& host = m_uri.host(); + int port = m_uri.port(); + utility::string_t expected_default_header = host + U(":") + utility::conversions::details::to_string_t(port); + http_request default_host_headers_request(methods::GET); + scoped.server()->next_request().then([&](test_request* p_request) { + auto headers = p_request->m_headers; + VERIFY_ARE_EQUAL(expected_default_header, headers[header_names::host]); + p_request->reply(200); + }); + + client.request(default_host_headers_request).get(); #ifndef __cplusplus_winrt - // Test case where we overwrite the host header - http_request overwritten_host_headers_request(methods::GET); - overwritten_host_headers_request.headers().add(U("Host"), host); - scoped.server()->next_request().then([&](test_request *p_request) - { - auto headers = p_request->m_headers; - VERIFY_ARE_EQUAL(host, headers[header_names::host]); - p_request->reply(200); - }); - client.request(overwritten_host_headers_request).get(); + // Test case where we overwrite the host header + http_request overwritten_host_headers_request(methods::GET); + overwritten_host_headers_request.headers().add(U("Host"), host); + scoped.server()->next_request().then([&](test_request* p_request) { + auto headers = p_request->m_headers; + VERIFY_ARE_EQUAL(host, headers[header_names::host]); + p_request->reply(200); + }); + client.request(overwritten_host_headers_request).get(); #endif -} + } } // SUITE(header_tests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/http_client_fuzz_tests.cpp b/Release/tests/functional/http/client/http_client_fuzz_tests.cpp index f9c6009614..85cb9dede8 100644 --- a/Release/tests/functional/http/client/http_client_fuzz_tests.cpp +++ b/Release/tests/functional/http/client/http_client_fuzz_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* http_client_fuzz_tests.cpp -* -* Tests cases for fuzzing http_client (headers). -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * http_client_fuzz_tests.cpp + * + * Tests cases for fuzzing http_client (headers). + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,76 +20,83 @@ using namespace concurrency::streams; using namespace utility; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - - SUITE(http_client_fuzz_tests) +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client +{ +SUITE(http_client_fuzz_tests) +{ + class fuzz_uri_address { - class fuzz_uri_address - { - public: - //Ensure that your traffic goes to port 8877 on the machine where NetFuzz is running - //Netfuzz sets an HTTP proxy at that location which your client must talk to - fuzz_uri_address() : m_uri(U("http://localhost:8877/")) {} - web::http::uri m_uri; - }; + public: + // Ensure that your traffic goes to port 8877 on the machine where NetFuzz is running + // Netfuzz sets an HTTP proxy at that location which your client must talk to + fuzz_uri_address() : m_uri(U("http://localhost:8877/")) {} + web::http::uri m_uri; + }; - TEST_FIXTURE(fuzz_uri_address, fuzz_header_basic, - "Ignore", "Manual") - { - http_client client(m_uri); - method requestMethod = methods::GET; - http_request msg(requestMethod); + TEST_FIXTURE(fuzz_uri_address, fuzz_header_basic, "Ignore", "Manual") + { + http_client client(m_uri); + method requestMethod = methods::GET; + http_request msg(requestMethod); - try - { - auto response = client.request(msg).get(); - printf("Response code:%d\n", response.status_code()); - auto response2 = response.content_ready().get(); - printf("Response2 code:%d\n", response2.status_code()); - } - catch(http_exception& e) - { - printf("Exception:%s\n", e.what()); - } + try + { + auto response = client.request(msg).get(); + printf("Response code:%d\n", response.status_code()); + auto response2 = response.content_ready().get(); + printf("Response2 code:%d\n", response2.status_code()); } - - TEST_FIXTURE(fuzz_uri_address, fuzz_request_headers, - "Ignore", "Manual") + catch (http_exception& e) { - http_client client(m_uri); - http_request msg(methods::POST); + printf("Exception:%s\n", e.what()); + } + } + + TEST_FIXTURE(fuzz_uri_address, fuzz_request_headers, "Ignore", "Manual") + { + http_client client(m_uri); + http_request msg(methods::POST); #ifndef __cplusplus_winrt - // The WinRT-based HTTP stack does not support headers that have no - // value, which means that there is no point in making this particular - // header test, it is an unsupported feature on WinRT. - msg.headers().add(U("HEHE"), U("")); -#endif + // The WinRT-based HTTP stack does not support headers that have no + // value, which means that there is no point in making this particular + // header test, it is an unsupported feature on WinRT. + msg.headers().add(U("HEHE"), U("")); +#endif - msg.headers().add(U("MyHeader"), U("hehe;blach")); - msg.headers().add(U("Yo1"), U("You, Too")); - msg.headers().add(U("Yo2"), U("You2")); - msg.headers().add(U("Yo3"), U("You3")); - msg.headers().add(U("Yo4"), U("You4")); - msg.headers().add(U("Yo5"), U("You5")); - msg.headers().add(U("Yo6"), U("You6")); - msg.headers().add(U("Yo7"), U("You7")); - msg.headers().add(U("Yo8"), U("You8")); - msg.headers().add(U("Yo9"), U("You9")); - msg.headers().add(U("Yo10"), U("You10")); - msg.headers().add(U("Yo11"), U("You11")); - msg.headers().add(U("Accept"), U("text/plain")); - VERIFY_ARE_EQUAL(U("You5"), msg.headers()[U("Yo5")]); - try - { - auto response = client.request(msg).get(); - printf("Response code:%d\n", response.status_code()); - } - catch(http_exception& e) - { - printf("Exception:%s\n", e.what()); - } + msg.headers().add(U("MyHeader"), U("hehe;blach")); + msg.headers().add(U("Yo1"), U("You, Too")); + msg.headers().add(U("Yo2"), U("You2")); + msg.headers().add(U("Yo3"), U("You3")); + msg.headers().add(U("Yo4"), U("You4")); + msg.headers().add(U("Yo5"), U("You5")); + msg.headers().add(U("Yo6"), U("You6")); + msg.headers().add(U("Yo7"), U("You7")); + msg.headers().add(U("Yo8"), U("You8")); + msg.headers().add(U("Yo9"), U("You9")); + msg.headers().add(U("Yo10"), U("You10")); + msg.headers().add(U("Yo11"), U("You11")); + msg.headers().add(U("Accept"), U("text/plain")); + VERIFY_ARE_EQUAL(U("You5"), msg.headers()[U("Yo5")]); + try + { + auto response = client.request(msg).get(); + printf("Response code:%d\n", response.status_code()); + } + catch (http_exception& e) + { + printf("Exception:%s\n", e.what()); } - } // SUITE(http_client_fuzz_tests) + } +} // SUITE(http_client_fuzz_tests) -}}}} \ No newline at end of file +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/http_client_tests.cpp b/Release/tests/functional/http/client/http_client_tests.cpp index 357ec11402..ecbec9899f 100644 --- a/Release/tests/functional/http/client/http_client_tests.cpp +++ b/Release/tests/functional/http/client/http_client_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* http_client_tests.cpp -* -* Common definitions and helper functions for http_client test cases. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * http_client_tests.cpp + * + * Common definitions and helper functions for http_client test cases. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -18,12 +18,17 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -void test_connection(test_http_server *p_server, http_client *p_client, const utility::string_t &path) +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client +{ +void test_connection(test_http_server* p_server, http_client* p_client, const utility::string_t& path) { - p_server->next_request().then([path](test_request *p_request) - { + p_server->next_request().then([path](test_request* p_request) { http_asserts::assert_test_request_equals(p_request, methods::GET, path); VERIFY_ARE_EQUAL(0u, p_request->reply(200)); }); @@ -32,14 +37,19 @@ void test_connection(test_http_server *p_server, http_client *p_client, const ut // Helper function send a simple request to test the connection. // Take in the path to request and what path should be received in the server. -void test_connection(test_http_server *p_server, http_client *p_client, const utility::string_t &request_path, const utility::string_t &expected_path) +void test_connection(test_http_server* p_server, + http_client* p_client, + const utility::string_t& request_path, + const utility::string_t& expected_path) { - p_server->next_request().then([expected_path](test_request *p_request) - { + p_server->next_request().then([expected_path](test_request* p_request) { http_asserts::assert_test_request_equals(p_request, methods::GET, expected_path); VERIFY_ARE_EQUAL(0u, p_request->reply(200)); }); http_asserts::assert_response_equals(p_client->request(methods::GET, request_path).get(), status_codes::OK); } -}}}} \ No newline at end of file +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/http_client_tests.h b/Release/tests/functional/http/client/http_client_tests.h index a00f921324..7224cb1a88 100644 --- a/Release/tests/functional/http/client/http_client_tests.h +++ b/Release/tests/functional/http/client/http_client_tests.h @@ -1,24 +1,30 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* http_client_tests.h -* -* Common declarations and helper functions for http_client test cases. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * http_client_tests.h + * + * Common declarations and helper functions for http_client test cases. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "cpprest/http_client.h" -#include "unittestpp.h" #include "http_test_utilities.h" +#include "unittestpp.h" -namespace tests { namespace functional { namespace http { namespace client { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client +{ class uri_address { public: @@ -28,10 +34,18 @@ class uri_address // Helper function to send a simple request to a server to test // the connection. -void test_connection(tests::functional::http::utilities::test_http_server *p_server, web::http::client::http_client *p_client, const utility::string_t &path); +void test_connection(tests::functional::http::utilities::test_http_server* p_server, + web::http::client::http_client* p_client, + const utility::string_t& path); // Helper function send a simple request to test the connection. // Take in the path to request and what path should be received in the server. -void test_connection(tests::functional::http::utilities::test_http_server *p_server, web::http::client::http_client *p_client, const utility::string_t &request_path, const utility::string_t &expected_path); +void test_connection(tests::functional::http::utilities::test_http_server* p_server, + web::http::client::http_client* p_client, + const utility::string_t& request_path, + const utility::string_t& expected_path); -}}}} \ No newline at end of file +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/http_methods_tests.cpp b/Release/tests/functional/http/client/http_methods_tests.cpp index cd357c50bb..b8f60c9bd5 100644 --- a/Release/tests/functional/http/client/http_methods_tests.cpp +++ b/Release/tests/functional/http/client/http_methods_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases for HTTP methods. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases for HTTP methods. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -16,92 +16,89 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(http_methods_tests) +namespace tests { - -// Tests the defined methods and custom methods. -TEST_FIXTURE(uri_address, http_methods) +namespace functional { - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - // Don't include 'CONNECT' it has a special meaning. - utility::string_t send_methods[] = +namespace http +{ +namespace client +{ +SUITE(http_methods_tests) +{ + // Tests the defined methods and custom methods. + TEST_FIXTURE(uri_address, http_methods) { - methods::GET, - U("GET"), - methods::DEL, - methods::HEAD, + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + // Don't include 'CONNECT' it has a special meaning. + utility::string_t send_methods[] = {methods::GET, + U("GET"), + methods::DEL, + methods::HEAD, #ifdef _WIN32 // - this is never passed to the listener with http_listener - methods::OPTIONS, + methods::OPTIONS, #endif - methods::POST, - methods::PUT, - methods::PATCH, + methods::POST, + methods::PUT, + methods::PATCH, #ifndef __cplusplus_winrt -# ifdef _WIN32 // - ditto - methods::TRCE, +#ifdef _WIN32 // - ditto + methods::TRCE, #endif #endif - U("CUstomMETHOD") - }; - utility::string_t recv_methods[] = - { - U("GET"), - U("GET"), - U("DELETE"), - U("HEAD"), + U("CUstomMETHOD")}; + utility::string_t recv_methods[] = {U("GET"), + U("GET"), + U("DELETE"), + U("HEAD"), #ifdef _WIN32 - U("OPTIONS"), + U("OPTIONS"), #endif - U("POST"), - U("PUT"), - U("PATCH"), + U("POST"), + U("PUT"), + U("PATCH"), #ifndef __cplusplus_winrt -# ifdef _WIN32 - U("TRACE"), +#ifdef _WIN32 + U("TRACE"), #endif #endif - U("CUstomMETHOD") - }; - const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); + U("CUstomMETHOD")}; + const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); - for(int i = 0; i < num_methods; ++i) - { - p_server->next_request().then([i, &recv_methods](test_request *p_request) + for (int i = 0; i < num_methods; ++i) { - http_asserts::assert_test_request_equals(p_request, recv_methods[i], U("/")); - VERIFY_ARE_EQUAL(0u, p_request->reply(200)); - }); - http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::OK); + p_server->next_request().then([i, &recv_methods](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, recv_methods[i], U("/")); + VERIFY_ARE_EQUAL(0u, p_request->reply(200)); + }); + http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::OK); + } } -} #ifdef __cplusplus_winrt -TEST_FIXTURE(uri_address, http_trace_fails_on_winrt) -{ - http_client client(m_uri); - VERIFY_THROWS(client.request(methods::TRCE).get(), http_exception); -} + TEST_FIXTURE(uri_address, http_trace_fails_on_winrt) + { + http_client client(m_uri); + VERIFY_THROWS(client.request(methods::TRCE).get(), http_exception); + } #endif -TEST(http_request_empty_method) -{ - VERIFY_THROWS(http_request(U("")), std::invalid_argument); -} - -TEST_FIXTURE(uri_address, empty_method) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - VERIFY_THROWS(client.request(U("")), std::invalid_argument); -} + TEST(http_request_empty_method) { VERIFY_THROWS(http_request(U("")), std::invalid_argument); } + TEST_FIXTURE(uri_address, empty_method) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + VERIFY_THROWS(client.request(U("")), std::invalid_argument); + } } -}}}} \ No newline at end of file +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/multiple_requests.cpp b/Release/tests/functional/http/client/multiple_requests.cpp index 0e643eb3e9..2f7d856340 100644 --- a/Release/tests/functional/http/client/multiple_requests.cpp +++ b/Release/tests/functional/http/client/multiple_requests.cpp @@ -1,17 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases for multiple requests and responses from an http_client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases for multiple requests and responses from an http_client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -using namespace web; using namespace utility; +using namespace web; +using namespace utility; using namespace utility::conversions; using namespace web::http; using namespace web::http::client; @@ -19,19 +20,25 @@ using namespace web::http::client; using namespace tests::common::utilities; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client +{ // Helper function to initialize an array of strings to contain 1 MB data. -static void initialize_data(std::string *data_arrays, const size_t count) +static void initialize_data(std::string* data_arrays, const size_t count) { // 10k std::string data; - for(int j = 0; j < 1024 * 10; ++j) + for (int j = 0; j < 1024 * 10; ++j) { data.push_back('A' + (j % 26)); } - for(size_t i = 0; i < count; ++i) + for (size_t i = 0; i < count; ++i) { data_arrays[i] = data; data_arrays[i].push_back('a' + (char)i); @@ -40,104 +47,107 @@ static void initialize_data(std::string *data_arrays, const size_t count) SUITE(multiple_requests) { - -TEST_FIXTURE(uri_address, requests_with_data) -{ - test_http_server::scoped_server scoped(m_uri); - http_client_config config; - http_client client(m_uri, config); - - const size_t num_requests = 20; - std::string request_body; - initialize_data(&request_body, 1); - const method method = methods::PUT; - const web::http::status_code code = status_codes::OK; - - std::vector> reqs; - // response to requests - for (size_t i = 0; i < num_requests; ++i) + TEST_FIXTURE(uri_address, requests_with_data) { - reqs.push_back(scoped.server()->next_request()); - } - - // send requests - std::vector> responses; - for(size_t i = 0; i < num_requests; ++i) - { - http_request msg(method); - msg.set_body(request_body); - responses.push_back(client.request(msg)); - } - - for (auto&& requestTask : reqs) - { - auto request = requestTask.get(); - http_asserts::assert_test_request_equals(request, method, U("/"), U("text/plain"), to_string_t(request_body)); - VERIFY_ARE_EQUAL(0u, request->reply(code)); - } + test_http_server::scoped_server scoped(m_uri); + http_client_config config; + http_client client(m_uri, config); + + const size_t num_requests = 20; + std::string request_body; + initialize_data(&request_body, 1); + const method method = methods::PUT; + const web::http::status_code code = status_codes::OK; + + std::vector> reqs; + // response to requests + for (size_t i = 0; i < num_requests; ++i) + { + reqs.push_back(scoped.server()->next_request()); + } - // wait for requests. - for(size_t i = 0; i < num_requests; ++i) - { - try + // send requests + std::vector> responses; + for (size_t i = 0; i < num_requests; ++i) { - http_asserts::assert_response_equals(responses[i].get(), code); + http_request msg(method); + msg.set_body(request_body); + responses.push_back(client.request(msg)); } - catch (...) + + for (auto&& requestTask : reqs) { - VERIFY_ARE_EQUAL(1, 0); + auto request = requestTask.get(); + http_asserts::assert_test_request_equals( + request, method, U("/"), U("text/plain"), to_string_t(request_body)); + VERIFY_ARE_EQUAL(0u, request->reply(code)); } - } -} -// Tests multiple requests with responses containing data. -TEST_FIXTURE(uri_address, responses_with_data) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - const size_t num_requests = 20; - std::string request_body; - initialize_data(&request_body, 1); - const method method = methods::PUT; - const web::http::status_code code = status_codes::OK; - std::map headers; - headers[U("Content-Type")] = U("text/plain"); - - // response to requests - auto requestTasks = scoped.server()->next_requests(num_requests); - - // send requests - std::vector> responses; - for(size_t i = 0; i < num_requests; ++i) - { - responses.push_back(client.request(method)); + // wait for requests. + for (size_t i = 0; i < num_requests; ++i) + { + try + { + http_asserts::assert_response_equals(responses[i].get(), code); + } + catch (...) + { + VERIFY_ARE_EQUAL(1, 0); + } + } } - // response to requests - for(size_t i = 0; i < num_requests; ++i) + // Tests multiple requests with responses containing data. + TEST_FIXTURE(uri_address, responses_with_data) { - test_request *request = requestTasks[i].get(); - http_asserts::assert_test_request_equals(request, method, U("/")); - VERIFY_ARE_EQUAL(0u, request->reply(code, U(""), headers, request_body)); - } + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + const size_t num_requests = 20; + std::string request_body; + initialize_data(&request_body, 1); + const method method = methods::PUT; + const web::http::status_code code = status_codes::OK; + std::map headers; + headers[U("Content-Type")] = U("text/plain"); + + // response to requests + auto requestTasks = scoped.server()->next_requests(num_requests); + + // send requests + std::vector> responses; + for (size_t i = 0; i < num_requests; ++i) + { + responses.push_back(client.request(method)); + } - // wait for requests. - for(size_t i = 0; i < num_requests; ++i) - { - try + // response to requests + for (size_t i = 0; i < num_requests; ++i) { - http_response rsp = responses[i].get(); - http_asserts::assert_response_equals(rsp, code, headers); - VERIFY_ARE_EQUAL(to_string_t(request_body), rsp.extract_string().get()); + test_request* request = requestTasks[i].get(); + http_asserts::assert_test_request_equals(request, method, U("/")); + VERIFY_ARE_EQUAL(0u, request->reply(code, U(""), headers, request_body)); } - catch (...) + + // wait for requests. + for (size_t i = 0; i < num_requests; ++i) { - VERIFY_ARE_EQUAL(1, 0); + try + { + http_response rsp = responses[i].get(); + http_asserts::assert_response_equals(rsp, code, headers); + VERIFY_ARE_EQUAL(to_string_t(request_body), rsp.extract_string().get()); + } + catch (...) + { + VERIFY_ARE_EQUAL(1, 0); + } } } -} } // SUITE(multiple_requests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/oauth1_tests.cpp b/Release/tests/functional/http/client/oauth1_tests.cpp index 918ff46506..15b0a30bed 100644 --- a/Release/tests/functional/http/client/oauth1_tests.cpp +++ b/Release/tests/functional/http/client/oauth1_tests.cpp @@ -1,15 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Test cases for oauth1. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Test cases for oauth1. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/details/http_helpers.h" using namespace web; @@ -23,103 +24,162 @@ using namespace concurrency; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(oauth1_tests) +namespace tests { - -struct oauth1_test_config +namespace functional { - oauth1_test_config() : - m_server_uri(U("http://localhost:17778/")), - m_test_token(U("test_token"), U("test_token_secret")), - m_oauth1_config(U("test_key"), U("test_secret"), - m_server_uri, m_server_uri, m_server_uri, m_server_uri, - oauth1_methods::hmac_sha1), - m_oauth1_handler(std::shared_ptr(new oauth1_config(m_oauth1_config))) - {} - - const utility::string_t m_server_uri; - const oauth1_token m_test_token; - - oauth1_config m_oauth1_config; - oauth1_handler m_oauth1_handler; -}; - -struct oauth1_token_setup : public oauth1_test_config +namespace http { - oauth1_token_setup() +namespace client +{ +SUITE(oauth1_tests) +{ + struct oauth1_test_config { - m_oauth1_config.set_token(m_test_token); - } -}; + oauth1_test_config() + : m_server_uri(U("http://localhost:17778/")) + , m_test_token(U("test_token"), U("test_token_secret")) + , m_oauth1_config(U("test_key"), + U("test_secret"), + m_server_uri, + m_server_uri, + m_server_uri, + m_server_uri, + oauth1_methods::hmac_sha1) + , m_oauth1_handler(std::shared_ptr(new oauth1_config(m_oauth1_config))) + { + } + + const utility::string_t m_server_uri; + const oauth1_token m_test_token; + + oauth1_config m_oauth1_config; + oauth1_handler m_oauth1_handler; + }; + + struct oauth1_token_setup : public oauth1_test_config + { + oauth1_token_setup() { m_oauth1_config.set_token(m_test_token); } + }; -struct oauth1_server_setup : public oauth1_test_config -{ - oauth1_server_setup() : - m_server(m_server_uri) - {} + struct oauth1_server_setup : public oauth1_test_config + { + oauth1_server_setup() : m_server(m_server_uri) {} - test_http_server::scoped_server m_server; -}; + test_http_server::scoped_server m_server; + }; -#define TEST_ACCESSOR(value_, name_) \ - t.set_ ## name_(value_); \ +#define TEST_ACCESSOR(value_, name_) \ + t.set_##name_(value_); \ VERIFY_ARE_EQUAL(value_, t.name_()); -TEST(oauth1_token_accessors) -{ - oauth1_token t(U(""), U("")); - TEST_ACCESSOR(U("a%123"), access_token) - TEST_ACCESSOR(U("b%20456"), secret) - - const auto key1 = U("abc"); - const auto value1 = U("123"); - const auto key2 = U("xyz"); - const auto value2 = U("456"); - t.set_additional_parameter(key1, value1); - t.set_additional_parameter(U("xyz"), U("456")); - const auto ¶meters = t.additional_parameters(); - VERIFY_ARE_EQUAL(parameters.at(key1), value1); - VERIFY_ARE_EQUAL(parameters.at(key2), value2); - t.clear_additional_parameters(); - VERIFY_ARE_EQUAL(0, t.additional_parameters().size()); -} - -TEST(oauth1_config_accessors) -{ - oauth1_config t(U(""), U(""), U(""), U(""), U(""), U(""), oauth1_methods::hmac_sha1); - TEST_ACCESSOR(U("Test123"), consumer_key) - TEST_ACCESSOR(U("bar456"), consumer_secret) - TEST_ACCESSOR(U("file:///123?123=a&1="), temp_endpoint) - TEST_ACCESSOR(U("x:yxw#0"), auth_endpoint) - TEST_ACCESSOR(U("baz:"), token_endpoint) - TEST_ACCESSOR(U("/xyzzy=2"), callback_uri) - TEST_ACCESSOR(oauth1_methods::plaintext, method) - TEST_ACCESSOR(U("wally.world x"), realm) - - const auto key1 = U("abc"); - const auto value1 = U("123"); - const auto key2 = U("xyz"); - const auto value2 = U("456"); - t.add_parameter(key1, value1); - t.add_parameter(U("xyz"), U("456")); - const auto parameters = t.parameters(); - VERIFY_ARE_EQUAL(parameters.at(key1), value1); - VERIFY_ARE_EQUAL(parameters.at(key2), value2); - t.clear_parameters(); - VERIFY_ARE_EQUAL(0, t.parameters().size()); - t.set_parameters(parameters); - const auto parameters2 = t.parameters(); - VERIFY_ARE_EQUAL(parameters2.at(key1), value1); - VERIFY_ARE_EQUAL(parameters2.at(key2), value2); -} + TEST(oauth1_token_accessors) + { + oauth1_token t(U(""), U("")); + TEST_ACCESSOR(U("a%123"), access_token) + TEST_ACCESSOR(U("b%20456"), secret) + + const auto key1 = U("abc"); + const auto value1 = U("123"); + const auto key2 = U("xyz"); + const auto value2 = U("456"); + t.set_additional_parameter(key1, value1); + t.set_additional_parameter(U("xyz"), U("456")); + const auto& parameters = t.additional_parameters(); + VERIFY_ARE_EQUAL(parameters.at(key1), value1); + VERIFY_ARE_EQUAL(parameters.at(key2), value2); + t.clear_additional_parameters(); + VERIFY_ARE_EQUAL(0, t.additional_parameters().size()); + } + + TEST(oauth1_config_accessors) + { + oauth1_config t(U(""), U(""), U(""), U(""), U(""), U(""), oauth1_methods::hmac_sha1); + TEST_ACCESSOR(U("Test123"), consumer_key) + TEST_ACCESSOR(U("bar456"), consumer_secret) + TEST_ACCESSOR(U("file:///123?123=a&1="), temp_endpoint) + TEST_ACCESSOR(U("x:yxw#0"), auth_endpoint) + TEST_ACCESSOR(U("baz:"), token_endpoint) + TEST_ACCESSOR(U("/xyzzy=2"), callback_uri) + TEST_ACCESSOR(oauth1_methods::plaintext, method) + TEST_ACCESSOR(U("wally.world x"), realm) + + const auto key1 = U("abc"); + const auto value1 = U("123"); + const auto key2 = U("xyz"); + const auto value2 = U("456"); + t.add_parameter(key1, value1); + t.add_parameter(U("xyz"), U("456")); + const auto parameters = t.parameters(); + VERIFY_ARE_EQUAL(parameters.at(key1), value1); + VERIFY_ARE_EQUAL(parameters.at(key2), value2); + t.clear_parameters(); + VERIFY_ARE_EQUAL(0, t.parameters().size()); + t.set_parameters(parameters); + const auto parameters2 = t.parameters(); + VERIFY_ARE_EQUAL(parameters2.at(key1), value1); + VERIFY_ARE_EQUAL(parameters2.at(key2), value2); + } #undef TEST_ACCESSOR -TEST_FIXTURE(oauth1_token_setup, oauth1_signature_base_string) -{ - // Basic base string generation. + TEST_FIXTURE(oauth1_token_setup, oauth1_signature_base_string) + { + // Basic base string generation. + { + http_request r; + r.set_method(methods::POST); + r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); // Port set to avoid default. + + auto state = m_oauth1_config._generate_auth_state(); + state.set_timestamp(U("12345678")); + state.set_nonce(U("ABCDEFGH")); + + utility::string_t base_string = m_oauth1_config._build_signature_base_string(r, state); + utility::string_t correct_base_string( + U("POST&http%3A%2F%2Fexample.com%2Frequest&a%3Db%26c%3Dd%26oauth_consumer_key%3Dtest_key%26oauth_nonce%" + "3DABCDEFGH%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D12345678%26oauth_token%3Dtest_" + "token%26oauth_version%3D1.0")); + VERIFY_ARE_EQUAL(correct_base_string, base_string); + } + + // Added "extra_param" and proper parameter normalization. + { + http_request r; + r.set_method(methods::POST); + r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); + + auto state = m_oauth1_config._generate_auth_state(U("oauth_test"), U("xyzzy")); + state.set_timestamp(U("12345678")); + state.set_nonce(U("ABCDEFGH")); + + utility::string_t base_string = m_oauth1_config._build_signature_base_string(r, state); + utility::string_t correct_base_string( + U("POST&http%3A%2F%2Fexample.com%2Frequest&a%3Db%26c%3Dd%26oauth_consumer_key%3Dtest_key%26oauth_nonce%" + "3DABCDEFGH%26oauth_signature_method%3DHMAC-SHA1%26oauth_test%3Dxyzzy%26oauth_timestamp%3D12345678%" + "26oauth_token%3Dtest_token%26oauth_version%3D1.0")); + VERIFY_ARE_EQUAL(correct_base_string, base_string); + } + + // Use application/x-www-form-urlencoded with parameters in body + { + http_request r(methods::POST); + r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); // Port set to avoid default. + r.set_body("MyVariableOne=ValueOne&MyVariableTwo=ValueTwo", "application/x-www-form-urlencoded"); + + auto state = m_oauth1_config._generate_auth_state(); + state.set_timestamp(U("12345678")); + state.set_nonce(U("ABCDEFGH")); + + utility::string_t base_string = m_oauth1_config._build_signature_base_string(r, state); + utility::string_t correct_base_string( + U("POST&http%3A%2F%2Fexample.com%2Frequest&a%3Db%26c%3Dd%26MyVariableOne%3DValueOne%26%26MyVariableTwo%" + "3DValueTwo%26oauth_consumer_key%3Dtest_key%26oauth_nonce%3DABCDEFGH%26oauth_signature_method%3DHMAC-" + "SHA1%26oauth_timestamp%3D12345678%26oauth_token%3Dtest_token%26oauth_version%3D1.0")); + } + } + + TEST_FIXTURE(oauth1_token_setup, oauth1_hmac_sha1_method) { http_request r; r.set_method(methods::POST); @@ -129,175 +189,133 @@ TEST_FIXTURE(oauth1_token_setup, oauth1_signature_base_string) state.set_timestamp(U("12345678")); state.set_nonce(U("ABCDEFGH")); - utility::string_t base_string = m_oauth1_config._build_signature_base_string(r, state); - utility::string_t correct_base_string(U( - "POST&http%3A%2F%2Fexample.com%2Frequest&a%3Db%26c%3Dd%26oauth_consumer_key%3Dtest_key%26oauth_nonce%3DABCDEFGH%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D12345678%26oauth_token%3Dtest_token%26oauth_version%3D1.0" - )); - VERIFY_ARE_EQUAL(correct_base_string, base_string); + utility::string_t signature = m_oauth1_config._build_hmac_sha1_signature(r, state); + + utility::string_t correct_signature(U("iUq3VlP39UNXoJHXlKjgSTmjEs8=")); + VERIFY_ARE_EQUAL(correct_signature, signature); } - // Added "extra_param" and proper parameter normalization. + TEST_FIXTURE(oauth1_token_setup, oauth1_plaintext_method) { - http_request r; - r.set_method(methods::POST); - r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); - - auto state = m_oauth1_config._generate_auth_state(U("oauth_test"), U("xyzzy")); - state.set_timestamp(U("12345678")); - state.set_nonce(U("ABCDEFGH")); - - utility::string_t base_string = m_oauth1_config._build_signature_base_string(r, state); - utility::string_t correct_base_string(U( - "POST&http%3A%2F%2Fexample.com%2Frequest&a%3Db%26c%3Dd%26oauth_consumer_key%3Dtest_key%26oauth_nonce%3DABCDEFGH%26oauth_signature_method%3DHMAC-SHA1%26oauth_test%3Dxyzzy%26oauth_timestamp%3D12345678%26oauth_token%3Dtest_token%26oauth_version%3D1.0" - )); - VERIFY_ARE_EQUAL(correct_base_string, base_string); + utility::string_t signature(m_oauth1_config._build_plaintext_signature()); + utility::string_t correct_signature(U("test_secret&test_token_secret")); + VERIFY_ARE_EQUAL(correct_signature, signature); } - // Use application/x-www-form-urlencoded with parameters in body + TEST_FIXTURE(oauth1_server_setup, oauth1_hmac_sha1_request) { - http_request r(methods::POST); - r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); // Port set to avoid default. - r.set_body("MyVariableOne=ValueOne&MyVariableTwo=ValueTwo", "application/x-www-form-urlencoded"); - - auto state = m_oauth1_config._generate_auth_state(); - state.set_timestamp(U("12345678")); - state.set_nonce(U("ABCDEFGH")); - - utility::string_t base_string = m_oauth1_config._build_signature_base_string(r, state); - utility::string_t correct_base_string(U( - "POST&http%3A%2F%2Fexample.com%2Frequest&a%3Db%26c%3Dd%26MyVariableOne%3DValueOne%26%26MyVariableTwo%3DValueTwo%26oauth_consumer_key%3Dtest_key%26oauth_nonce%3DABCDEFGH%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D12345678%26oauth_token%3Dtest_token%26oauth_version%3D1.0" - )); + m_oauth1_config.set_token(m_test_token); + m_oauth1_config.set_method(oauth1_methods::hmac_sha1); + + http_client_config client_config; + client_config.set_oauth1(m_oauth1_config); + http_client client(m_server_uri, client_config); + + m_server.server()->next_request().then([](test_request* request) { + const utility::string_t header_authorization(request->m_headers[header_names::authorization]); + const utility::string_t prefix( + U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_token=\"test_token\", " + "oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"")); + VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); + request->reply(status_codes::OK); + }); + + VERIFY_IS_TRUE(m_oauth1_config.token().is_valid_access_token()); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); } -} - -TEST_FIXTURE(oauth1_token_setup, oauth1_hmac_sha1_method) -{ - http_request r; - r.set_method(methods::POST); - r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); // Port set to avoid default. - - auto state = m_oauth1_config._generate_auth_state(); - state.set_timestamp(U("12345678")); - state.set_nonce(U("ABCDEFGH")); - - utility::string_t signature = m_oauth1_config._build_hmac_sha1_signature(r, state); - - utility::string_t correct_signature(U("iUq3VlP39UNXoJHXlKjgSTmjEs8=")); - VERIFY_ARE_EQUAL(correct_signature, signature); -} - -TEST_FIXTURE(oauth1_token_setup, oauth1_plaintext_method) -{ - utility::string_t signature(m_oauth1_config._build_plaintext_signature()); - utility::string_t correct_signature(U("test_secret&test_token_secret")); - VERIFY_ARE_EQUAL(correct_signature, signature); -} - -TEST_FIXTURE(oauth1_server_setup, oauth1_hmac_sha1_request) -{ - m_oauth1_config.set_token(m_test_token); - m_oauth1_config.set_method(oauth1_methods::hmac_sha1); - - http_client_config client_config; - client_config.set_oauth1(m_oauth1_config); - http_client client(m_server_uri, client_config); - m_server.server()->next_request().then([](test_request *request) + TEST_FIXTURE(oauth1_server_setup, oauth1_plaintext_request) { - const utility::string_t header_authorization(request->m_headers[header_names::authorization]); - const utility::string_t prefix(U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_token=\"test_token\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"")); - VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); - request->reply(status_codes::OK); - }); - - VERIFY_IS_TRUE(m_oauth1_config.token().is_valid_access_token()); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); -} - -TEST_FIXTURE(oauth1_server_setup, oauth1_plaintext_request) -{ - m_oauth1_config.set_token(m_test_token); - m_oauth1_config.set_method(oauth1_methods::plaintext); - - http_client_config client_config; - client_config.set_oauth1(m_oauth1_config); - http_client client(m_server_uri, client_config); + m_oauth1_config.set_token(m_test_token); + m_oauth1_config.set_method(oauth1_methods::plaintext); + + http_client_config client_config; + client_config.set_oauth1(m_oauth1_config); + http_client client(m_server_uri, client_config); + + m_server.server()->next_request().then([](test_request* request) { + const utility::string_t header_authorization(request->m_headers[header_names::authorization]); + const utility::string_t prefix( + U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_token=\"test_token\", " + "oauth_signature_method=\"PLAINTEXT\", oauth_timestamp=\"")); + VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); + request->reply(status_codes::OK); + }); + + VERIFY_IS_TRUE(m_oauth1_config.token().is_valid_access_token()); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + } - m_server.server()->next_request().then([](test_request *request) - { - const utility::string_t header_authorization(request->m_headers[header_names::authorization]); - const utility::string_t prefix(U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_token=\"test_token\", oauth_signature_method=\"PLAINTEXT\", oauth_timestamp=\"")); - VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); - request->reply(status_codes::OK); - }); - - VERIFY_IS_TRUE(m_oauth1_config.token().is_valid_access_token()); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); -} - -TEST_FIXTURE(oauth1_server_setup, oauth1_build_authorization_uri) -{ - m_server.server()->next_request().then([](test_request *request) + TEST_FIXTURE(oauth1_server_setup, oauth1_build_authorization_uri) { - const utility::string_t header_authorization(request->m_headers[header_names::authorization]); - - // Verify prefix, and without 'oauth_token'. - const utility::string_t prefix(U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"")); - VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); - - // Verify suffix with proper 'oauth_callback'. - const utility::string_t suffix(U(", oauth_callback=\"http%3A%2F%2Flocalhost%3A17778%2F\"")); - VERIFY_IS_TRUE(std::equal(suffix.rbegin(), suffix.rend(), header_authorization.rbegin())); - - // Reply with temporary token and secret. - std::map headers; - headers[header_names::content_type] = mime_types::application_x_www_form_urlencoded; - request->reply(status_codes::OK, U(""), headers, "oauth_token=testbar&oauth_token_secret=xyzzy&oauth_callback_confirmed=true"); - }); - - VERIFY_IS_FALSE(m_oauth1_config.token().is_valid_access_token()); - utility::string_t auth_uri = m_oauth1_config.build_authorization_uri().get(); - VERIFY_ARE_EQUAL(auth_uri, U("http://localhost:17778/?oauth_token=testbar")); - VERIFY_IS_FALSE(m_oauth1_config.token().is_valid_access_token()); -} - -// NOTE: This test also covers token_from_verifier(). -TEST_FIXTURE(oauth1_server_setup, oauth1_token_from_redirected_uri) -{ - m_server.server()->next_request().then([](test_request *request) + m_server.server()->next_request().then([](test_request* request) { + const utility::string_t header_authorization(request->m_headers[header_names::authorization]); + + // Verify prefix, and without 'oauth_token'. + const utility::string_t prefix(U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", " + "oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"")); + VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); + + // Verify suffix with proper 'oauth_callback'. + const utility::string_t suffix(U(", oauth_callback=\"http%3A%2F%2Flocalhost%3A17778%2F\"")); + VERIFY_IS_TRUE(std::equal(suffix.rbegin(), suffix.rend(), header_authorization.rbegin())); + + // Reply with temporary token and secret. + std::map headers; + headers[header_names::content_type] = mime_types::application_x_www_form_urlencoded; + request->reply(status_codes::OK, + U(""), + headers, + "oauth_token=testbar&oauth_token_secret=xyzzy&oauth_callback_confirmed=true"); + }); + + VERIFY_IS_FALSE(m_oauth1_config.token().is_valid_access_token()); + utility::string_t auth_uri = m_oauth1_config.build_authorization_uri().get(); + VERIFY_ARE_EQUAL(auth_uri, U("http://localhost:17778/?oauth_token=testbar")); + VERIFY_IS_FALSE(m_oauth1_config.token().is_valid_access_token()); + } + + // NOTE: This test also covers token_from_verifier(). + TEST_FIXTURE(oauth1_server_setup, oauth1_token_from_redirected_uri) { - const utility::string_t header_authorization(request->m_headers[header_names::authorization]); + m_server.server()->next_request().then([](test_request* request) { + const utility::string_t header_authorization(request->m_headers[header_names::authorization]); - // Verify temporary token prefix. - const utility::string_t prefix(U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_token=\"xyzzy\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"")); - VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); + // Verify temporary token prefix. + const utility::string_t prefix( + U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_token=\"xyzzy\", " + "oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"")); + VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); - // Verify suffix with 'oauth_verifier'. - const utility::string_t suffix(U(", oauth_verifier=\"simsalabim\"")); - VERIFY_IS_TRUE(std::equal(suffix.rbegin(), suffix.rend(), header_authorization.rbegin())); + // Verify suffix with 'oauth_verifier'. + const utility::string_t suffix(U(", oauth_verifier=\"simsalabim\"")); + VERIFY_IS_TRUE(std::equal(suffix.rbegin(), suffix.rend(), header_authorization.rbegin())); - // Verify we have 'oauth_nonce' and 'oauth_signature'. - VERIFY_ARE_NOT_EQUAL(utility::string_t::npos, header_authorization.find(U("oauth_nonce"))); - VERIFY_ARE_NOT_EQUAL(utility::string_t::npos, header_authorization.find(U("oauth_signature"))); + // Verify we have 'oauth_nonce' and 'oauth_signature'. + VERIFY_ARE_NOT_EQUAL(utility::string_t::npos, header_authorization.find(U("oauth_nonce"))); + VERIFY_ARE_NOT_EQUAL(utility::string_t::npos, header_authorization.find(U("oauth_signature"))); - // Reply with access token and secret. - std::map headers; - headers[header_names::content_type] = mime_types::application_x_www_form_urlencoded; - request->reply(status_codes::OK, U(""), headers, "oauth_token=test&oauth_token_secret=bar"); - }); + // Reply with access token and secret. + std::map headers; + headers[header_names::content_type] = mime_types::application_x_www_form_urlencoded; + request->reply(status_codes::OK, U(""), headers, "oauth_token=test&oauth_token_secret=bar"); + }); - m_oauth1_config.set_token(oauth1_token(U("xyzzy"), U(""))); // Simulate temporary token. + m_oauth1_config.set_token(oauth1_token(U("xyzzy"), U(""))); // Simulate temporary token. - const web::http::uri redirected_uri(U("http://localhost:17778/?oauth_token=xyzzy&oauth_verifier=simsalabim")); - m_oauth1_config.token_from_redirected_uri(redirected_uri).wait(); + const web::http::uri redirected_uri(U("http://localhost:17778/?oauth_token=xyzzy&oauth_verifier=simsalabim")); + m_oauth1_config.token_from_redirected_uri(redirected_uri).wait(); - VERIFY_IS_TRUE(m_oauth1_config.token().is_valid_access_token()); - VERIFY_ARE_EQUAL(m_oauth1_config.token().access_token(), U("test")); - VERIFY_ARE_EQUAL(m_oauth1_config.token().secret(), U("bar")); -} + VERIFY_IS_TRUE(m_oauth1_config.token().is_valid_access_token()); + VERIFY_ARE_EQUAL(m_oauth1_config.token().access_token(), U("test")); + VERIFY_ARE_EQUAL(m_oauth1_config.token().secret(), U("bar")); + } } // SUITE(oauth1_tests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/oauth2_tests.cpp b/Release/tests/functional/http/client/oauth2_tests.cpp index d641631ad9..6d050ffb88 100644 --- a/Release/tests/functional/http/client/oauth2_tests.cpp +++ b/Release/tests/functional/http/client/oauth2_tests.cpp @@ -1,15 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Test cases for oauth2. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Test cases for oauth2. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/details/http_helpers.h" using namespace web; @@ -21,367 +22,375 @@ using namespace utility; using namespace concurrency; using namespace tests::functional::http::utilities; -extern utility::string_t _to_base64(const unsigned char *ptr, size_t size); +extern utility::string_t _to_base64(const unsigned char* ptr, size_t size); -namespace tests { namespace functional { namespace http { namespace client +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client { - static std::vector to_body_data(utility::string_t str) { const std::string utf8(conversions::to_utf8string(std::move(str))); return std::vector(utf8.data(), utf8.data() + utf8.size()); } -static bool is_application_x_www_form_urlencoded(test_request *request) +static bool is_application_x_www_form_urlencoded(test_request* request) { const auto content_type(request->m_headers[header_names::content_type]); return (0 == content_type.find(mime_types::application_x_www_form_urlencoded)); } -static utility::string_t get_request_user_agent(test_request *request) +static utility::string_t get_request_user_agent(test_request* request) { if (request->m_headers.find(header_names::user_agent) != request->m_headers.end()) { return request->m_headers[header_names::user_agent]; } - + return utility::string_t(); } SUITE(oauth2_tests) { + struct oauth2_test_setup + { + oauth2_test_setup() + : m_uri(U("http://localhost:16743/")) + , m_oauth2_config(U("123ABC"), U("456DEF"), U("https://test1"), m_uri.to_string(), U("https://bar")) + , m_scoped(m_uri) + { + } -struct oauth2_test_setup -{ - oauth2_test_setup() : - m_uri(U("http://localhost:16743/")), - m_oauth2_config(U("123ABC"), U("456DEF"), U("https://test1"), m_uri.to_string(), U("https://bar")), - m_scoped(m_uri) - {} - - web::http::uri m_uri; - oauth2_config m_oauth2_config; - test_http_server::scoped_server m_scoped; -}; - -#define TEST_ACCESSOR(value_, name_) \ - t.set_ ## name_(value_); \ - VERIFY_ARE_EQUAL(value_, t.name_()); - -TEST(oauth2_token_accessors) -{ - oauth2_token t; - TEST_ACCESSOR(U("b%20456"), access_token) - TEST_ACCESSOR(U("a%123"), refresh_token) - TEST_ACCESSOR(U("b%20456"), token_type) - TEST_ACCESSOR(U("ad.ww xyz"), scope) - TEST_ACCESSOR(0, expires_in) - TEST_ACCESSOR(123, expires_in) -} - -TEST(oauth2_config_accessors) -{ - oauth2_config t(U(""), U(""), U(""), U(""), U("")); - TEST_ACCESSOR(U("ABC123abc"), client_key) - TEST_ACCESSOR(U("123abcABC"), client_secret) - TEST_ACCESSOR(U("x:/t/a?q=c&a#3"), auth_endpoint) - TEST_ACCESSOR(U("y:///?a=21#1=2"), token_endpoint) - TEST_ACCESSOR(U("z://?=#"), redirect_uri) - TEST_ACCESSOR(U("xyzw=stuv"), scope) - TEST_ACCESSOR(U("1234567890"), state) - TEST_ACCESSOR(U("keyx"), access_token_key) - TEST_ACCESSOR(true, implicit_grant) - TEST_ACCESSOR(false, implicit_grant) - TEST_ACCESSOR(true, bearer_auth) - TEST_ACCESSOR(false, bearer_auth) - TEST_ACCESSOR(true, http_basic_auth) - TEST_ACCESSOR(false, http_basic_auth) -} - -#undef TEST_ACCESSOR + web::http::uri m_uri; + oauth2_config m_oauth2_config; + test_http_server::scoped_server m_scoped; + }; -TEST(oauth2_build_authorization_uri) -{ - oauth2_config config(U(""), U(""), U(""), U(""), U("")); - config.set_state(U("xyzzy")); - config.set_implicit_grant(false); +#define TEST_ACCESSOR(value_, name_) \ + t.set_##name_(value_); \ + VERIFY_ARE_EQUAL(value_, t.name_()); - // Empty authorization URI. + TEST(oauth2_token_accessors) { - VERIFY_ARE_EQUAL(U("/?response_type=code&client_id=&redirect_uri=&state=xyzzy"), - config.build_authorization_uri(false)); + oauth2_token t; + TEST_ACCESSOR(U("b%20456"), access_token) + TEST_ACCESSOR(U("a%123"), refresh_token) + TEST_ACCESSOR(U("b%20456"), token_type) + TEST_ACCESSOR(U("ad.ww xyz"), scope) + TEST_ACCESSOR(0, expires_in) + TEST_ACCESSOR(123, expires_in) } - // Authorization URI with scope parameter. + TEST(oauth2_config_accessors) { - config.set_scope(U("testing_123")); - VERIFY_ARE_EQUAL(U("/?response_type=code&client_id=&redirect_uri=&state=xyzzy&scope=testing_123"), - config.build_authorization_uri(false)); + oauth2_config t(U(""), U(""), U(""), U(""), U("")); + TEST_ACCESSOR(U("ABC123abc"), client_key) + TEST_ACCESSOR(U("123abcABC"), client_secret) + TEST_ACCESSOR(U("x:/t/a?q=c&a#3"), auth_endpoint) + TEST_ACCESSOR(U("y:///?a=21#1=2"), token_endpoint) + TEST_ACCESSOR(U("z://?=#"), redirect_uri) + TEST_ACCESSOR(U("xyzw=stuv"), scope) + TEST_ACCESSOR(U("1234567890"), state) + TEST_ACCESSOR(U("keyx"), access_token_key) + TEST_ACCESSOR(true, implicit_grant) + TEST_ACCESSOR(false, implicit_grant) + TEST_ACCESSOR(true, bearer_auth) + TEST_ACCESSOR(false, bearer_auth) + TEST_ACCESSOR(true, http_basic_auth) + TEST_ACCESSOR(false, http_basic_auth) } - // Full authorization URI with scope. - { - config.set_client_key(U("4567abcd")); - config.set_auth_endpoint(U("https://test1")); - config.set_redirect_uri(U("http://localhost:8080")); - VERIFY_ARE_EQUAL(U("https://test1/?response_type=code&client_id=4567abcd&redirect_uri=http://localhost:8080&state=xyzzy&scope=testing_123"), - config.build_authorization_uri(false)); - } +#undef TEST_ACCESSOR - // Verify again with implicit grant. + TEST(oauth2_build_authorization_uri) { - config.set_implicit_grant(true); - VERIFY_ARE_EQUAL(U("https://test1/?response_type=token&client_id=4567abcd&redirect_uri=http://localhost:8080&state=xyzzy&scope=testing_123"), - config.build_authorization_uri(false)); - } + oauth2_config config(U(""), U(""), U(""), U(""), U("")); + config.set_state(U("xyzzy")); + config.set_implicit_grant(false); - // Verify that a new state() will be generated. - { - const uri auth_uri(config.build_authorization_uri(true)); - auto params = uri::split_query(auth_uri.query()); - VERIFY_ARE_NOT_EQUAL(params[U("state")], U("xyzzy")); - } -} + // Empty authorization URI. + { + VERIFY_ARE_EQUAL(U("/?response_type=code&client_id=&redirect_uri=&state=xyzzy"), + config.build_authorization_uri(false)); + } -TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_code) -{ - VERIFY_IS_FALSE(m_oauth2_config.is_enabled()); + // Authorization URI with scope parameter. + { + config.set_scope(U("testing_123")); + VERIFY_ARE_EQUAL(U("/?response_type=code&client_id=&redirect_uri=&state=xyzzy&scope=testing_123"), + config.build_authorization_uri(false)); + } - m_oauth2_config.set_user_agent(U("test_user_agent")); + // Full authorization URI with scope. + { + config.set_client_key(U("4567abcd")); + config.set_auth_endpoint(U("https://test1")); + config.set_redirect_uri(U("http://localhost:8080")); + VERIFY_ARE_EQUAL(U("https://test1/?response_type=code&client_id=4567abcd&redirect_uri=http://" + "localhost:8080&state=xyzzy&scope=testing_123"), + config.build_authorization_uri(false)); + } + + // Verify again with implicit grant. + { + config.set_implicit_grant(true); + VERIFY_ARE_EQUAL(U("https://test1/?response_type=token&client_id=4567abcd&redirect_uri=http://" + "localhost:8080&state=xyzzy&scope=testing_123"), + config.build_authorization_uri(false)); + } - // Fetch using HTTP Basic authentication. + // Verify that a new state() will be generated. + { + const uri auth_uri(config.build_authorization_uri(true)); + auto params = uri::split_query(auth_uri.query()); + VERIFY_ARE_NOT_EQUAL(params[U("state")], U("xyzzy")); + } + } + + TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_code) { - m_scoped.server()->next_request().then([](test_request *request) + VERIFY_IS_FALSE(m_oauth2_config.is_enabled()); + + m_oauth2_config.set_user_agent(U("test_user_agent")); + + // Fetch using HTTP Basic authentication. { - VERIFY_ARE_EQUAL(request->m_method, methods::POST); - - VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); + m_scoped.server()->next_request().then([](test_request* request) { + VERIFY_ARE_EQUAL(request->m_method, methods::POST); - VERIFY_ARE_EQUAL(U("Basic MTIzQUJDOjQ1NkRFRg=="), request->m_headers[header_names::authorization]); + VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); - VERIFY_ARE_EQUAL(to_body_data( - U("grant_type=authorization_code&code=789GHI&redirect_uri=https%3A%2F%2Fbar")), + VERIFY_ARE_EQUAL(U("Basic MTIzQUJDOjQ1NkRFRg=="), request->m_headers[header_names::authorization]); + + VERIFY_ARE_EQUAL( + to_body_data(U("grant_type=authorization_code&code=789GHI&redirect_uri=https%3A%2F%2Fbar")), request->m_body); - VERIFY_ARE_EQUAL(U("test_user_agent"), get_request_user_agent(request)); + VERIFY_ARE_EQUAL(U("test_user_agent"), get_request_user_agent(request)); - std::map headers; - headers[header_names::content_type] = mime_types::application_json; - request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"xyzzy123\",\"token_type\":\"bearer\"}"); - }); + std::map headers; + headers[header_names::content_type] = mime_types::application_json; + request->reply( + status_codes::OK, U(""), headers, "{\"access_token\":\"xyzzy123\",\"token_type\":\"bearer\"}"); + }); - m_oauth2_config.token_from_code(U("789GHI")).wait(); - VERIFY_ARE_EQUAL(U("xyzzy123"), m_oauth2_config.token().access_token()); - VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); - } + m_oauth2_config.token_from_code(U("789GHI")).wait(); + VERIFY_ARE_EQUAL(U("xyzzy123"), m_oauth2_config.token().access_token()); + VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); + } - // Fetch using client key & secret in request body (x-www-form-urlencoded). - { - m_scoped.server()->next_request().then([](test_request *request) + // Fetch using client key & secret in request body (x-www-form-urlencoded). { - VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); + m_scoped.server()->next_request().then([](test_request* request) { + VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); - VERIFY_ARE_EQUAL(U(""), request->m_headers[header_names::authorization]); + VERIFY_ARE_EQUAL(U(""), request->m_headers[header_names::authorization]); - VERIFY_ARE_EQUAL(to_body_data( - U("grant_type=authorization_code&code=789GHI&redirect_uri=https%3A%2F%2Fbar&client_id=123ABC&client_secret=456DEF")), - request->m_body); + VERIFY_ARE_EQUAL(to_body_data(U("grant_type=authorization_code&code=789GHI&redirect_uri=https%3A%2F%" + "2Fbar&client_id=123ABC&client_secret=456DEF")), + request->m_body); - VERIFY_ARE_EQUAL(U("test_user_agent"), get_request_user_agent(request)); + VERIFY_ARE_EQUAL(U("test_user_agent"), get_request_user_agent(request)); - std::map headers; - headers[header_names::content_type] = mime_types::application_json; - request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"xyzzy123\",\"token_type\":\"bearer\"}"); - }); + std::map headers; + headers[header_names::content_type] = mime_types::application_json; + request->reply( + status_codes::OK, U(""), headers, "{\"access_token\":\"xyzzy123\",\"token_type\":\"bearer\"}"); + }); - m_oauth2_config.set_token(oauth2_token()); // Clear token. - VERIFY_IS_FALSE(m_oauth2_config.is_enabled()); + m_oauth2_config.set_token(oauth2_token()); // Clear token. + VERIFY_IS_FALSE(m_oauth2_config.is_enabled()); - m_oauth2_config.set_http_basic_auth(false); - m_oauth2_config.token_from_code(U("789GHI")).wait(); + m_oauth2_config.set_http_basic_auth(false); + m_oauth2_config.token_from_code(U("789GHI")).wait(); - VERIFY_ARE_EQUAL(U("xyzzy123"), m_oauth2_config.token().access_token()); - VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); + VERIFY_ARE_EQUAL(U("xyzzy123"), m_oauth2_config.token().access_token()); + VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); + } } -} -TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_redirected_uri) -{ - // Authorization code grant. + TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_redirected_uri) { - m_scoped.server()->next_request().then([](test_request *request) + // Authorization code grant. { - std::map headers; - headers[header_names::content_type] = mime_types::application_json; - request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"test1\",\"token_type\":\"bearer\"}"); - }); - - m_oauth2_config.set_implicit_grant(false); - m_oauth2_config.set_state(U("xyzzy")); + m_scoped.server()->next_request().then([](test_request* request) { + std::map headers; + headers[header_names::content_type] = mime_types::application_json; + request->reply( + status_codes::OK, U(""), headers, "{\"access_token\":\"test1\",\"token_type\":\"bearer\"}"); + }); - const web::http::uri redirected_uri(m_uri.to_string() + U("?code=sesame&state=xyzzy")); - m_oauth2_config.token_from_redirected_uri(redirected_uri).wait(); + m_oauth2_config.set_implicit_grant(false); + m_oauth2_config.set_state(U("xyzzy")); - VERIFY_IS_TRUE(m_oauth2_config.token().is_valid_access_token()); - VERIFY_ARE_EQUAL(m_oauth2_config.token().access_token(), U("test1")); - } + const web::http::uri redirected_uri(m_uri.to_string() + U("?code=sesame&state=xyzzy")); + m_oauth2_config.token_from_redirected_uri(redirected_uri).wait(); - // Implicit grant. - { - m_oauth2_config.set_implicit_grant(true); - const web::http::uri redirected_uri(m_uri.to_string() + U("#access_token=abcd1234&state=xyzzy")); - m_oauth2_config.token_from_redirected_uri(redirected_uri).wait(); + VERIFY_IS_TRUE(m_oauth2_config.token().is_valid_access_token()); + VERIFY_ARE_EQUAL(m_oauth2_config.token().access_token(), U("test1")); + } - VERIFY_IS_TRUE(m_oauth2_config.token().is_valid_access_token()); - VERIFY_ARE_EQUAL(m_oauth2_config.token().access_token(), U("abcd1234")); - } -} + // Implicit grant. + { + m_oauth2_config.set_implicit_grant(true); + const web::http::uri redirected_uri(m_uri.to_string() + U("#access_token=abcd1234&state=xyzzy")); + m_oauth2_config.token_from_redirected_uri(redirected_uri).wait(); -TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_refresh) -{ - oauth2_token token(U("accessing")); - token.set_refresh_token(U("refreshing")); - m_oauth2_config.set_token(token); - VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); + VERIFY_IS_TRUE(m_oauth2_config.token().is_valid_access_token()); + VERIFY_ARE_EQUAL(m_oauth2_config.token().access_token(), U("abcd1234")); + } + } - // Verify token refresh without scope. - m_scoped.server()->next_request().then([](test_request *request) + TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_refresh) { - VERIFY_ARE_EQUAL(request->m_method, methods::POST); + oauth2_token token(U("accessing")); + token.set_refresh_token(U("refreshing")); + m_oauth2_config.set_token(token); + VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); - VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); + // Verify token refresh without scope. + m_scoped.server()->next_request().then([](test_request* request) { + VERIFY_ARE_EQUAL(request->m_method, methods::POST); - VERIFY_ARE_EQUAL(U("Basic MTIzQUJDOjQ1NkRFRg=="), request->m_headers[header_names::authorization]); + VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); - VERIFY_ARE_EQUAL(to_body_data( - U("grant_type=refresh_token&refresh_token=refreshing")), - request->m_body); + VERIFY_ARE_EQUAL(U("Basic MTIzQUJDOjQ1NkRFRg=="), request->m_headers[header_names::authorization]); - std::map headers; - headers[header_names::content_type] = mime_types::application_json; - request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"ABBA\",\"refresh_token\":\"BAZ\",\"token_type\":\"bearer\"}"); - }); + VERIFY_ARE_EQUAL(to_body_data(U("grant_type=refresh_token&refresh_token=refreshing")), request->m_body); - m_oauth2_config.token_from_refresh().wait(); - VERIFY_ARE_EQUAL(U("ABBA"), m_oauth2_config.token().access_token()); - VERIFY_ARE_EQUAL(U("BAZ"), m_oauth2_config.token().refresh_token()); + std::map headers; + headers[header_names::content_type] = mime_types::application_json; + request->reply(status_codes::OK, + U(""), + headers, + "{\"access_token\":\"ABBA\",\"refresh_token\":\"BAZ\",\"token_type\":\"bearer\"}"); + }); - // Verify chaining refresh tokens and refresh with scope. - m_scoped.server()->next_request().then([](test_request *request) - { - VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); - - VERIFY_ARE_EQUAL(to_body_data( - U("grant_type=refresh_token&refresh_token=BAZ&scope=xyzzy")), - request->m_body); - - std::map headers; - headers[header_names::content_type] = mime_types::application_json; - request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"done\",\"token_type\":\"bearer\"}"); - }); - - m_oauth2_config.set_scope(U("xyzzy")); - m_oauth2_config.token_from_refresh().wait(); - VERIFY_ARE_EQUAL(U("done"), m_oauth2_config.token().access_token()); -} + m_oauth2_config.token_from_refresh().wait(); + VERIFY_ARE_EQUAL(U("ABBA"), m_oauth2_config.token().access_token()); + VERIFY_ARE_EQUAL(U("BAZ"), m_oauth2_config.token().refresh_token()); -TEST_FIXTURE(oauth2_test_setup, oauth2_bearer_token) -{ - m_oauth2_config.set_token(oauth2_token(U("12345678"))); - http_client_config config; + // Verify chaining refresh tokens and refresh with scope. + m_scoped.server()->next_request().then([](test_request* request) { + VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); - // Default, bearer token in "Authorization" header (bearer_auth() == true) - { - config.set_oauth2(m_oauth2_config); + VERIFY_ARE_EQUAL(to_body_data(U("grant_type=refresh_token&refresh_token=BAZ&scope=xyzzy")), + request->m_body); - http_client client(m_uri, config); - m_scoped.server()->next_request().then([](test_request *request) - { - VERIFY_ARE_EQUAL(U("Bearer 12345678"), request->m_headers[header_names::authorization]); - VERIFY_ARE_EQUAL(U("/"), request->m_path); - request->reply(status_codes::OK); + std::map headers; + headers[header_names::content_type] = mime_types::application_json; + request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"done\",\"token_type\":\"bearer\"}"); }); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + m_oauth2_config.set_scope(U("xyzzy")); + m_oauth2_config.token_from_refresh().wait(); + VERIFY_ARE_EQUAL(U("done"), m_oauth2_config.token().access_token()); } - // Bearer token in query, default access token key (bearer_auth() == false) + TEST_FIXTURE(oauth2_test_setup, oauth2_bearer_token) { - m_oauth2_config.set_bearer_auth(false); - config.set_oauth2(m_oauth2_config); + m_oauth2_config.set_token(oauth2_token(U("12345678"))); + http_client_config config; - http_client client(m_uri, config); - m_scoped.server()->next_request().then([](test_request *request) + // Default, bearer token in "Authorization" header (bearer_auth() == true) { - VERIFY_ARE_EQUAL(U(""), request->m_headers[header_names::authorization]); - VERIFY_ARE_EQUAL(U("/?access_token=12345678"), request->m_path); - request->reply(status_codes::OK); - }); + config.set_oauth2(m_oauth2_config); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - } + http_client client(m_uri, config); + m_scoped.server()->next_request().then([](test_request* request) { + VERIFY_ARE_EQUAL(U("Bearer 12345678"), request->m_headers[header_names::authorization]); + VERIFY_ARE_EQUAL(U("/"), request->m_path); + request->reply(status_codes::OK); + }); - // Bearer token in query, updated token, custom access token key (bearer_auth() == false) - { - m_oauth2_config.set_bearer_auth(false); - m_oauth2_config.set_access_token_key(U("open")); - m_oauth2_config.set_token(oauth2_token(U("Sesame"))); - config.set_oauth2(m_oauth2_config); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + } - http_client client(m_uri, config); - m_scoped.server()->next_request().then([](test_request *request) + // Bearer token in query, default access token key (bearer_auth() == false) { - VERIFY_ARE_EQUAL(U(""), request->m_headers[header_names::authorization]); - VERIFY_ARE_EQUAL(U("/?open=Sesame"), request->m_path); - request->reply(status_codes::OK); - }); + m_oauth2_config.set_bearer_auth(false); + config.set_oauth2(m_oauth2_config); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - } -} + http_client client(m_uri, config); + m_scoped.server()->next_request().then([](test_request* request) { + VERIFY_ARE_EQUAL(U(""), request->m_headers[header_names::authorization]); + VERIFY_ARE_EQUAL(U("/?access_token=12345678"), request->m_path); + request->reply(status_codes::OK); + }); -TEST_FIXTURE(oauth2_test_setup, oauth2_token_parsing) -{ - VERIFY_IS_FALSE(m_oauth2_config.is_enabled()); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + } - // Verify reply JSON 'access_token', 'refresh_token', 'expires_in' and 'scope'. - { - m_scoped.server()->next_request().then([](test_request *request) + // Bearer token in query, updated token, custom access token key (bearer_auth() == false) { - std::map headers; - headers[header_names::content_type] = mime_types::application_json; - request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"123\",\"refresh_token\":\"ABC\",\"token_type\":\"bearer\",\"expires_in\":12345678,\"scope\":\"baz\"}"); - }); - - m_oauth2_config.token_from_code(U("")).wait(); - VERIFY_ARE_EQUAL(U("123"), m_oauth2_config.token().access_token()); - VERIFY_ARE_EQUAL(U("ABC"), m_oauth2_config.token().refresh_token()); - VERIFY_ARE_EQUAL(12345678, m_oauth2_config.token().expires_in()); - VERIFY_ARE_EQUAL(U("baz"), m_oauth2_config.token().scope()); - VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); + m_oauth2_config.set_bearer_auth(false); + m_oauth2_config.set_access_token_key(U("open")); + m_oauth2_config.set_token(oauth2_token(U("Sesame"))); + config.set_oauth2(m_oauth2_config); + + http_client client(m_uri, config); + m_scoped.server()->next_request().then([](test_request* request) { + VERIFY_ARE_EQUAL(U(""), request->m_headers[header_names::authorization]); + VERIFY_ARE_EQUAL(U("/?open=Sesame"), request->m_path); + request->reply(status_codes::OK); + }); + + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + } } - // Verify undefined 'expires_in' and 'scope'. + TEST_FIXTURE(oauth2_test_setup, oauth2_token_parsing) { - m_scoped.server()->next_request().then([](test_request *request) - { - std::map headers; - headers[header_names::content_type] = mime_types::application_json; - request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"123\",\"token_type\":\"bearer\"}"); - }); - - const utility::string_t test_scope(U("wally world")); - m_oauth2_config.set_scope(test_scope); + VERIFY_IS_FALSE(m_oauth2_config.is_enabled()); - m_oauth2_config.token_from_code(U("")).wait(); - VERIFY_ARE_EQUAL(oauth2_token::undefined_expiration, m_oauth2_config.token().expires_in()); - VERIFY_ARE_EQUAL(test_scope, m_oauth2_config.token().scope()); + // Verify reply JSON 'access_token', 'refresh_token', 'expires_in' and 'scope'. + { + m_scoped.server()->next_request().then([](test_request* request) { + std::map headers; + headers[header_names::content_type] = mime_types::application_json; + request->reply(status_codes::OK, + U(""), + headers, + "{\"access_token\":\"123\",\"refresh_token\":\"ABC\",\"token_type\":\"bearer\"," + "\"expires_in\":12345678,\"scope\":\"baz\"}"); + }); + + m_oauth2_config.token_from_code(U("")).wait(); + VERIFY_ARE_EQUAL(U("123"), m_oauth2_config.token().access_token()); + VERIFY_ARE_EQUAL(U("ABC"), m_oauth2_config.token().refresh_token()); + VERIFY_ARE_EQUAL(12345678, m_oauth2_config.token().expires_in()); + VERIFY_ARE_EQUAL(U("baz"), m_oauth2_config.token().scope()); + VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); + } + + // Verify undefined 'expires_in' and 'scope'. + { + m_scoped.server()->next_request().then([](test_request* request) { + std::map headers; + headers[header_names::content_type] = mime_types::application_json; + request->reply( + status_codes::OK, U(""), headers, "{\"access_token\":\"123\",\"token_type\":\"bearer\"}"); + }); + + const utility::string_t test_scope(U("wally world")); + m_oauth2_config.set_scope(test_scope); + + m_oauth2_config.token_from_code(U("")).wait(); + VERIFY_ARE_EQUAL(oauth2_token::undefined_expiration, m_oauth2_config.token().expires_in()); + VERIFY_ARE_EQUAL(test_scope, m_oauth2_config.token().scope()); + } } -} } // SUITE(oauth2_tests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index bb5909d35e..e19a0f4119 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -1,23 +1,24 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases for using http_clients to outside websites. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases for using http_clients to outside websites. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" #if defined(_MSC_VER) && !defined(__cplusplus_winrt) #define WIN32_LEAN_AND_MEAN #include + #include #pragma comment(lib, "winhttp") #endif -#include "cpprest/rawptrstream.h" #include "cpprest/details/http_helpers.h" +#include "cpprest/rawptrstream.h" #include "os_utilities.h" #include @@ -30,368 +31,340 @@ using namespace web::http::client; using namespace tests::common::utilities; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(outside_tests) +namespace tests { - -TEST_FIXTURE(uri_address, outside_cnn_dot_com) +namespace functional { - handle_timeout([] - { - // http://www.cnn.com redirects users from countries outside of the US to the "http://edition.cnn.com/" drop location - http_client client(U("http://edition.cnn.com")); - - // CNN's main page doesn't use chunked transfer encoding. - http_response response = client.request(methods::GET).get(); - auto code = response.status_code(); - VERIFY_IS_TRUE(code == status_codes::OK || code == status_codes::MovedPermanently); - response.content_ready().wait(); - - // CNN's other pages do use chunked transfer encoding. - response = client.request(methods::GET, U("us")).get(); - code = response.status_code(); - VERIFY_IS_TRUE(code == status_codes::OK || code == status_codes::MovedPermanently); - response.content_ready().wait(); - }); -} - -TEST_FIXTURE(uri_address, outside_wikipedia_compressed_http_response) +namespace http +{ +namespace client { - if (web::http::compression::builtin::supported() == false) +SUITE(outside_tests) +{ + TEST_FIXTURE(uri_address, outside_cnn_dot_com) { - // On platforms which do not support compressed http, nothing to check. - return; + handle_timeout([] { + // http://www.cnn.com redirects users from countries outside of the US to the "http://edition.cnn.com/" drop + // location + http_client client(U("http://edition.cnn.com")); + + // CNN's main page doesn't use chunked transfer encoding. + http_response response = client.request(methods::GET).get(); + auto code = response.status_code(); + VERIFY_IS_TRUE(code == status_codes::OK || code == status_codes::MovedPermanently); + response.content_ready().wait(); + + // CNN's other pages do use chunked transfer encoding. + response = client.request(methods::GET, U("us")).get(); + code = response.status_code(); + VERIFY_IS_TRUE(code == status_codes::OK || code == status_codes::MovedPermanently); + response.content_ready().wait(); + }); } - http_client_config config; - config.set_request_compressed_response(true); - http_client client(U("https://en.wikipedia.org/wiki/HTTP_compression"), config); - http_request httpRequest(methods::GET); + TEST_FIXTURE(uri_address, outside_wikipedia_compressed_http_response) + { + if (web::http::compression::builtin::supported() == false) + { + // On platforms which do not support compressed http, nothing to check. + return; + } + http_client_config config; + config.set_request_compressed_response(true); - http_response response = client.request(httpRequest).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - response.content_ready().wait(); + http_client client(U("https://en.wikipedia.org/wiki/HTTP_compression"), config); + http_request httpRequest(methods::GET); - auto s = response.extract_utf8string().get(); - VERIFY_IS_FALSE(s.empty()); + http_response response = client.request(httpRequest).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + response.content_ready().wait(); - utility::string_t encoding; - VERIFY_IS_TRUE(response.headers().match(web::http::header_names::content_encoding, encoding)); + auto s = response.extract_utf8string().get(); + VERIFY_IS_FALSE(s.empty()); - VERIFY_ARE_EQUAL(encoding, U("gzip")); -} + utility::string_t encoding; + VERIFY_IS_TRUE(response.headers().match(web::http::header_names::content_encoding, encoding)); -TEST_FIXTURE(uri_address, outside_google_dot_com) -{ - // Use code.google.com instead of www.google.com, which redirects - http_client client(U("http://code.google.com")); - http_request request(methods::GET); - for (int i = 0; i < 2; ++i) - { - http_response response = client.request(request).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + VERIFY_ARE_EQUAL(encoding, U("gzip")); } -} -TEST_FIXTURE(uri_address, multiple_https_requests) -{ - handle_timeout([&] + TEST_FIXTURE(uri_address, outside_google_dot_com) { // Use code.google.com instead of www.google.com, which redirects - http_client client(U("https://code.google.com")); - - http_response response; - for(int i = 0; i < 5; ++i) + http_client client(U("http://code.google.com")); + http_request request(methods::GET); + for (int i = 0; i < 2; ++i) { - response = client.request(methods::GET).get(); + http_response response = client.request(request).get(); VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - response.content_ready().wait(); } - }); -} + } + + TEST_FIXTURE(uri_address, multiple_https_requests) + { + handle_timeout([&] { + // Use code.google.com instead of www.google.com, which redirects + http_client client(U("https://code.google.com")); + + http_response response; + for (int i = 0; i < 5; ++i) + { + response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + response.content_ready().wait(); + } + }); + } #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX -TEST_FIXTURE(uri_address, multiple_https_requests_sync_scheduler) -{ - struct sync_scheduler : public scheduler_interface + TEST_FIXTURE(uri_address, multiple_https_requests_sync_scheduler) { - public: - virtual void schedule(TaskProc_t function, PVOID context) override + struct sync_scheduler : public scheduler_interface { - function(context); - } - }; + public: + virtual void schedule(TaskProc_t function, PVOID context) override { function(context); } + }; - // Save the current ambient scheduler - const auto scheduler = get_cpprestsdk_ambient_scheduler(); + // Save the current ambient scheduler + const auto scheduler = get_cpprestsdk_ambient_scheduler(); - // Change the ambient scheduler to one that schedules synchronously - static std::shared_ptr syncScheduler = std::make_shared(); - set_cpprestsdk_ambient_scheduler(syncScheduler); + // Change the ambient scheduler to one that schedules synchronously + static std::shared_ptr syncScheduler = std::make_shared(); + set_cpprestsdk_ambient_scheduler(syncScheduler); - handle_timeout([&] { - // Use code.google.com instead of www.google.com, which redirects - http_client client(U("https://code.google.com")); + handle_timeout([&] { + // Use code.google.com instead of www.google.com, which redirects + http_client client(U("https://code.google.com")); - http_response response; - for (int i = 0; i < 5; ++i) - { - response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - response.content_ready().wait(); - } - }); + http_response response; + for (int i = 0; i < 5; ++i) + { + response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + response.content_ready().wait(); + } + }); - // Revert to the original scheduler - set_cpprestsdk_ambient_scheduler(scheduler); -} + // Revert to the original scheduler + set_cpprestsdk_ambient_scheduler(scheduler); + } #endif -TEST_FIXTURE(uri_address, reading_google_stream) -{ - handle_timeout([&] + TEST_FIXTURE(uri_address, reading_google_stream) { - // Use code.google.com instead of www.google.com, which redirects - http_client simpleclient(U("http://code.google.com")); - utility::string_t path = m_uri.query(); - http_response response = simpleclient.request(::http::methods::GET).get(); - - uint8_t chars[71]; - memset(chars, 0, sizeof(chars)); - - streams::rawptr_buffer temp(chars, sizeof(chars)); - - VERIFY_ARE_EQUAL(response.body().read(temp, 70).get(), 70); - // Uncomment the following line to output the chars. - // std::cout << chars << '\n'; - VERIFY_ARE_EQUAL(strcmp((const char *) chars, "\n \n temp(chars, sizeof(chars)); + + VERIFY_ARE_EQUAL(response.body().read(temp, 70).get(), 70); + // Uncomment the following line to output the chars. + // std::cout << chars << '\n'; + VERIFY_ARE_EQUAL(strcmp((const char*)chars, + "\n \n 0); - }).wait(); - }); -} - -// Note additional sites for testing can be found at: -// https://badssl.com/ -// https://www.ssllabs.com/ssltest/ -// http://www.internetsociety.org/deploy360/resources/dane-test-sites/ -// https://onlinessl.netlock.hu/# -static void test_failed_ssl_cert(const uri& base_uri) -{ - handle_timeout([&base_uri] + handle_timeout([] { + http_client client( + U("http://ws.audioscrobbler.com/2.0/" + "?method=artist.gettoptracks&artist=cher&api_key=6fcd59047568e89b1615975081258990&format=json")); + + client.request(methods::GET) + .then([](http_response response) { + VERIFY_ARE_EQUAL(response.status_code(), status_codes::OK); + VERIFY_IS_FALSE(response.headers().has(header_names::content_length) && + response.headers().has(header_names::transfer_encoding)); + return response.extract_string(); + }) + .then([](string_t result) { + // Verify that the body size isn't empty. + VERIFY_IS_TRUE(result.size() > 0); + }) + .wait(); + }); + } + + // Note additional sites for testing can be found at: + // https://badssl.com/ + // https://www.ssllabs.com/ssltest/ + // http://www.internetsociety.org/deploy360/resources/dane-test-sites/ + // https://onlinessl.netlock.hu/# + static void test_failed_ssl_cert(const uri& base_uri) { - http_client client(base_uri); - auto requestTask = client.request(methods::GET); - VERIFY_THROWS(requestTask.get(), http_exception); - }); -} + handle_timeout([&base_uri] { + http_client client(base_uri); + auto requestTask = client.request(methods::GET); + VERIFY_THROWS(requestTask.get(), http_exception); + }); + } #if !defined(__cplusplus_winrt) -static void test_ignored_ssl_cert(const uri& base_uri) -{ - handle_timeout([&base_uri] + static void test_ignored_ssl_cert(const uri& base_uri) { - http_client_config config; - config.set_validate_certificates(false); - http_client client(base_uri, config); - auto response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - }); -} + handle_timeout([&base_uri] { + http_client_config config; + config.set_validate_certificates(false); + http_client client(base_uri, config); + auto response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + }); + } #endif // !defined(__cplusplus_winrt) -TEST(server_selfsigned_cert) -{ - test_failed_ssl_cert(U("https://self-signed.badssl.com/")); -} + TEST(server_selfsigned_cert) { test_failed_ssl_cert(U("https://self-signed.badssl.com/")); } #if !defined(__cplusplus_winrt) -TEST(server_selfsigned_cert_ignored) -{ - test_ignored_ssl_cert(U("https://self-signed.badssl.com/")); -} + TEST(server_selfsigned_cert_ignored) { test_ignored_ssl_cert(U("https://self-signed.badssl.com/")); } #endif // !defined(__cplusplus_winrt) -TEST(server_hostname_mismatch) -{ - test_failed_ssl_cert(U("https://wrong.host.badssl.com/")); -} + TEST(server_hostname_mismatch) { test_failed_ssl_cert(U("https://wrong.host.badssl.com/")); } #if !defined(__cplusplus_winrt) -TEST(server_hostname_host_override) -{ - handle_timeout([] + TEST(server_hostname_host_override) { - http_client client(U("https://wrong.host.badssl.com/")); - http_request req(methods::GET); - req.headers().add(U("Host"), U("badssl.com")); - auto response = client.request(req).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - }); -} + handle_timeout([] { + http_client client(U("https://wrong.host.badssl.com/")); + http_request req(methods::GET); + req.headers().add(U("Host"), U("badssl.com")); + auto response = client.request(req).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + }); + } -TEST(server_hostname_mismatch_ignored) -{ - test_ignored_ssl_cert(U("https://wrong.host.badssl.com/")); -} + TEST(server_hostname_mismatch_ignored) { test_ignored_ssl_cert(U("https://wrong.host.badssl.com/")); } -TEST(server_hostname_host_override_after_upgrade) -{ - http_client client(U("http://198.35.26.96/")); - http_request req(methods::GET); - req.headers().add(U("Host"), U("en.wikipedia.org")); - auto response = client.request(req).get(); - // WinHTTP will transparently follow the HTTP 301 upgrade request redirect, - // ASIO does not and will return the 301 directly. - const auto statusCode = response.status_code(); - CHECK(statusCode == status_codes::OK || statusCode == status_codes::MovedPermanently); -} + TEST(server_hostname_host_override_after_upgrade) + { + http_client client(U("http://198.35.26.96/")); + http_request req(methods::GET); + req.headers().add(U("Host"), U("en.wikipedia.org")); + auto response = client.request(req).get(); + // WinHTTP will transparently follow the HTTP 301 upgrade request redirect, + // ASIO does not and will return the 301 directly. + const auto statusCode = response.status_code(); + CHECK(statusCode == status_codes::OK || statusCode == status_codes::MovedPermanently); + } #endif // !defined(__cplusplus_winrt) -TEST(server_cert_expired) -{ - test_failed_ssl_cert(U("https://expired.badssl.com/")); -} + TEST(server_cert_expired) { test_failed_ssl_cert(U("https://expired.badssl.com/")); } #if !defined(__cplusplus_winrt) -TEST(server_cert_expired_ignored) -{ - test_ignored_ssl_cert(U("https://expired.badssl.com/")); -} + TEST(server_cert_expired_ignored) { test_ignored_ssl_cert(U("https://expired.badssl.com/")); } #endif // !defined(__cplusplus_winrt) -TEST(server_cert_revoked, - "Ignore:Android", "229", - "Ignore:Apple", "229", - "Ignore:Linux", "229") -{ - test_failed_ssl_cert(U("https://revoked.badssl.com/")); -} + TEST(server_cert_revoked, "Ignore:Android", "229", "Ignore:Apple", "229", "Ignore:Linux", "229") + { + test_failed_ssl_cert(U("https://revoked.badssl.com/")); + } #if !defined(__cplusplus_winrt) -TEST(server_cert_revoked_ignored) -{ - test_ignored_ssl_cert(U("https://revoked.badssl.com/")); -} + TEST(server_cert_revoked_ignored) { test_ignored_ssl_cert(U("https://revoked.badssl.com/")); } #endif // !defined(__cplusplus_winrt) -TEST(server_cert_untrusted) -{ - test_failed_ssl_cert(U("https://untrusted-root.badssl.com/")); -} + TEST(server_cert_untrusted) { test_failed_ssl_cert(U("https://untrusted-root.badssl.com/")); } #if !defined(__cplusplus_winrt) -TEST(server_cert_untrusted_ignored) -{ - test_ignored_ssl_cert(U("https://untrusted-root.badssl.com/")); -} + TEST(server_cert_untrusted_ignored) { test_ignored_ssl_cert(U("https://untrusted-root.badssl.com/")); } #endif // !defined(__cplusplus_winrt) #if !defined(__cplusplus_winrt) -TEST(ignore_server_cert_invalid, - "Ignore:Android", "229", - "Ignore:Apple", "229", - "Ignore:Linux", "229") -{ - handle_timeout([] + TEST(ignore_server_cert_invalid, "Ignore:Android", "229", "Ignore:Apple", "229", "Ignore:Linux", "229") { - http_client_config config; - config.set_validate_certificates(false); - config.set_timeout(std::chrono::seconds(1)); - http_client client(U("https://expired.badssl.com/"), config); - - auto request = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, request.status_code()); - }); -} + handle_timeout([] { + http_client_config config; + config.set_validate_certificates(false); + config.set_timeout(std::chrono::seconds(1)); + http_client client(U("https://expired.badssl.com/"), config); + + auto request = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, request.status_code()); + }); + } #endif // !defined(__cplusplus_winrt) -TEST_FIXTURE(uri_address, outside_ssl_json) -{ - // Create URI for: - // https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=UUF1hMUVwlrvlVMjUGOZExgg&key=AIzaSyAviHxf_y0SzNoAq3iKqvWVE4KQ0yylsnk - uri_builder playlistUri(U("https://www.googleapis.com/youtube/v3/playlistItems?")); - playlistUri.append_query(U("part"),U("snippet")); - playlistUri.append_query(U("playlistId"), U("UUF1hMUVwlrvlVMjUGOZExgg")); - playlistUri.append_query(U("key"), U("AIzaSyAviHxf_y0SzNoAq3iKqvWVE4KQ0yylsnk")); - - // Send request - web::http::client::http_client playlistClient(playlistUri.to_uri()); - - handle_timeout([&] + TEST_FIXTURE(uri_address, outside_ssl_json) { - // Retry up to 4 times. - for (int i = 0; i < 4; ++i) - { - try + // Create URI for: + // https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=UUF1hMUVwlrvlVMjUGOZExgg&key=AIzaSyAviHxf_y0SzNoAq3iKqvWVE4KQ0yylsnk + uri_builder playlistUri(U("https://www.googleapis.com/youtube/v3/playlistItems?")); + playlistUri.append_query(U("part"), U("snippet")); + playlistUri.append_query(U("playlistId"), U("UUF1hMUVwlrvlVMjUGOZExgg")); + playlistUri.append_query(U("key"), U("AIzaSyAviHxf_y0SzNoAq3iKqvWVE4KQ0yylsnk")); + + // Send request + web::http::client::http_client playlistClient(playlistUri.to_uri()); + + handle_timeout([&] { + // Retry up to 4 times. + for (int i = 0; i < 4; ++i) { - playlistClient.request(methods::GET).then([=](http_response playlistResponse) -> pplx::task < json::value > + try { - return playlistResponse.extract_json(); - }).then([=](json::value v) + playlistClient.request(methods::GET) + .then([=](http_response playlistResponse) -> pplx::task { + return playlistResponse.extract_json(); + }) + .then([=](json::value v) { + int count = 0; + auto& obj = v.as_object(); + + VERIFY_ARE_NOT_EQUAL(obj.find(U("pageInfo")), obj.end()); + VERIFY_ARE_NOT_EQUAL(obj.find(U("items")), obj.end()); + + auto& items = obj[U("items")]; + + for (auto iter = items.as_array().cbegin(); iter != items.as_array().cend(); ++iter) + { + const auto& item = *iter; + auto iSnippet = item.as_object().find(U("snippet")); + if (iSnippet == item.as_object().end()) + { + throw std::runtime_error("snippet key not found"); + } + auto iTitle = iSnippet->second.as_object().find(U("title")); + if (iTitle == iSnippet->second.as_object().end()) + { + throw std::runtime_error("title key not found"); + } + auto name = iTitle->second.serialize(); + count++; + } + VERIFY_ARE_EQUAL(3, count); // Update this accordingly, if the number of items changes + }) + .wait(); + break; + } + catch (web::http::http_exception const& e) { - int count = 0; - auto& obj = v.as_object(); - - VERIFY_ARE_NOT_EQUAL(obj.find(U("pageInfo")), obj.end()); - VERIFY_ARE_NOT_EQUAL(obj.find(U("items")), obj.end()); - - auto& items = obj[U("items")]; - - for (auto iter = items.as_array().cbegin(); iter != items.as_array().cend(); ++iter) +#if defined(_MSC_VER) && !defined(__cplusplus_winrt) + if (e.error_code().value() != API_QUERY_DATA_AVAILABLE || i == 3) { - const auto& item = *iter; - auto iSnippet = item.as_object().find(U("snippet")); - if (iSnippet == item.as_object().end()) - { - throw std::runtime_error("snippet key not found"); - } - auto iTitle = iSnippet->second.as_object().find(U("title")); - if (iTitle == iSnippet->second.as_object().end()) - { - throw std::runtime_error("title key not found"); - } - auto name = iTitle->second.serialize(); - count++; + // If we didn't get a "connection broken" error (or we are on the last retry), rethrow it + throw; } - VERIFY_ARE_EQUAL(3, count); // Update this accordingly, if the number of items changes - }).wait(); - break; - } - catch (web::http::http_exception const& e) - { -#if defined(_MSC_VER) && !defined(__cplusplus_winrt) - if (e.error_code().value() != API_QUERY_DATA_AVAILABLE || i == 3) - { - // If we didn't get a "connection broken" error (or we are on the last retry), rethrow it - throw; - } #else - CASABLANCA_UNREFERENCED_PARAMETER(e); - throw; + CASABLANCA_UNREFERENCED_PARAMETER(e); + throw; #endif - os_utilities::sleep(1000); + os_utilities::sleep(1000); + } } - } - }); -} + }); + } } // SUITE(outside_tests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/pipeline_stage_tests.cpp b/Release/tests/functional/http/client/pipeline_stage_tests.cpp index 7d16d7a2d7..a13fa9a275 100644 --- a/Release/tests/functional/http/client/pipeline_stage_tests.cpp +++ b/Release/tests/functional/http/client/pipeline_stage_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* pipeline_stage_tests.cpp -* -* Tests cases using pipeline stages on an http_client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * pipeline_stage_tests.cpp + * + * Tests cases using pipeline stages on an http_client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -18,261 +18,243 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(pipeline_stage_tests) +namespace tests { - -TEST_FIXTURE(uri_address, http_counting_methods) +namespace functional +{ +namespace http { - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); +namespace client +{ +SUITE(pipeline_stage_tests) +{ + TEST_FIXTURE(uri_address, http_counting_methods) + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); - size_t count = 0; + size_t count = 0; - auto response_counter = - [&count](pplx::task r_task) -> pplx::task - { + auto response_counter = [&count](pplx::task r_task) -> pplx::task { ++count; - return r_task; + return r_task; }; - auto request_counter = - [&count,response_counter](http_request request, std::shared_ptr next_stage) -> pplx::task - { + auto request_counter = + [&count, response_counter](http_request request, + std::shared_ptr next_stage) -> pplx::task { ++count; return next_stage->propagate(request).then(response_counter); }; - http_client client(m_uri); - client.add_handler(request_counter); + http_client client(m_uri); + client.add_handler(request_counter); - // Don't include 'CONNECT' it has a special meaning. - utility::string_t send_methods[] = - { - methods::GET, - U("GET"), - methods::DEL, - methods::HEAD, + // Don't include 'CONNECT' it has a special meaning. + utility::string_t send_methods[] = {methods::GET, + U("GET"), + methods::DEL, + methods::HEAD, #ifdef _WIN32 // this is never passed to the listener - methods::OPTIONS, + methods::OPTIONS, #endif - methods::POST, - methods::PUT, - methods::PATCH, - U("CUstomMETHOD") - }; - utility::string_t recv_methods[] = - { - U("GET"), - U("GET"), - U("DELETE"), - U("HEAD"), + methods::POST, + methods::PUT, + methods::PATCH, + U("CUstomMETHOD")}; + utility::string_t recv_methods[] = {U("GET"), + U("GET"), + U("DELETE"), + U("HEAD"), #ifdef _WIN32 - U("OPTIONS"), + U("OPTIONS"), #endif - U("POST"), - U("PUT"), - U("PATCH"), - U("CUstomMETHOD") - }; - const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); + U("POST"), + U("PUT"), + U("PATCH"), + U("CUstomMETHOD")}; + const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); - for(int i = 0; i < num_methods; ++i) - { - p_server->next_request().then([i, &recv_methods](test_request *p_request) + for (int i = 0; i < num_methods; ++i) { - http_asserts::assert_test_request_equals(p_request, recv_methods[i], U("/")); - VERIFY_ARE_EQUAL(0u, p_request->reply(200)); - }); - http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::OK); + p_server->next_request().then([i, &recv_methods](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, recv_methods[i], U("/")); + VERIFY_ARE_EQUAL(0u, p_request->reply(200)); + }); + http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::OK); + } + + VERIFY_ARE_EQUAL(num_methods * 2, count); } - VERIFY_ARE_EQUAL(num_methods*2, count); -} - -TEST_FIXTURE(uri_address, http_short_circuit) -{ - size_t count = 0; + TEST_FIXTURE(uri_address, http_short_circuit) + { + size_t count = 0; - auto request_counter = - [&count](http_request request, std::shared_ptr next_stage) -> pplx::task - { + auto request_counter = [&count](http_request request, + std::shared_ptr next_stage) -> pplx::task { ++count; request.reply(status_codes::Forbidden); return request.get_response(); }; - http_client client(m_uri); - client.add_handler(request_counter); - - // Don't include 'CONNECT' it has a special meaning. - utility::string_t send_methods[] = - { - methods::GET, - U("GET"), - methods::DEL, - methods::HEAD, - methods::OPTIONS, - methods::POST, - methods::PUT, - methods::PATCH, - U("CUstomMETHOD") - }; - const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); + http_client client(m_uri); + client.add_handler(request_counter); + + // Don't include 'CONNECT' it has a special meaning. + utility::string_t send_methods[] = {methods::GET, + U("GET"), + methods::DEL, + methods::HEAD, + methods::OPTIONS, + methods::POST, + methods::PUT, + methods::PATCH, + U("CUstomMETHOD")}; + const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); + + for (int i = 0; i < num_methods; ++i) + { + http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::Forbidden); + } - for(int i = 0; i < num_methods; ++i) - { - http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::Forbidden); + VERIFY_ARE_EQUAL(num_methods, count); } - VERIFY_ARE_EQUAL(num_methods, count); -} - -TEST_FIXTURE(uri_address, http_short_circuit_multiple) -{ - size_t count = 0; + TEST_FIXTURE(uri_address, http_short_circuit_multiple) + { + size_t count = 0; - auto reply_stage = - [](http_request request, std::shared_ptr next_stage) -> pplx::task - { + auto reply_stage = [](http_request request, + std::shared_ptr next_stage) -> pplx::task { request.reply(status_codes::Forbidden); return request.get_response(); }; - auto count_stage = - [&count](http_request request, std::shared_ptr next_stage) -> pplx::task - { + auto count_stage = [&count](http_request request, + std::shared_ptr next_stage) -> pplx::task { count++; return next_stage->propagate(request); }; - http_client client(m_uri); - client.add_handler(count_stage); - client.add_handler(count_stage); - client.add_handler(reply_stage); - - // Don't include 'CONNECT' it has a special meaning. - utility::string_t send_methods[] = - { - methods::GET, - U("GET"), - methods::DEL, - methods::HEAD, - methods::OPTIONS, - methods::POST, - methods::PUT, - methods::PATCH, - U("CUstomMETHOD") - }; - const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); + http_client client(m_uri); + client.add_handler(count_stage); + client.add_handler(count_stage); + client.add_handler(reply_stage); + + // Don't include 'CONNECT' it has a special meaning. + utility::string_t send_methods[] = {methods::GET, + U("GET"), + methods::DEL, + methods::HEAD, + methods::OPTIONS, + methods::POST, + methods::PUT, + methods::PATCH, + U("CUstomMETHOD")}; + const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); + + for (int i = 0; i < num_methods; ++i) + { + http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::Forbidden); + } - for(int i = 0; i < num_methods; ++i) - { - http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::Forbidden); + VERIFY_ARE_EQUAL(num_methods * 2, count); } - VERIFY_ARE_EQUAL(num_methods*2, count); -} - -TEST_FIXTURE(uri_address, http_short_circuit_no_count) -{ - size_t count = 0; + TEST_FIXTURE(uri_address, http_short_circuit_no_count) + { + size_t count = 0; - auto reply_stage = - [](http_request request, std::shared_ptr next_stage) -> pplx::task - { + auto reply_stage = [](http_request request, + std::shared_ptr next_stage) -> pplx::task { request.reply(status_codes::Forbidden); return request.get_response(); }; - auto count_stage = - [&count](http_request request, std::shared_ptr next_stage) -> pplx::task - { + auto count_stage = [&count](http_request request, + std::shared_ptr next_stage) -> pplx::task { count++; return next_stage->propagate(request); }; - // The counting is prevented from happening, because the short-circuit come before the count. - http_client client(m_uri); - client.add_handler(reply_stage); - client.add_handler(count_stage); - - // Don't include 'CONNECT' it has a special meaning. - utility::string_t send_methods[] = - { - methods::GET, - U("GET"), - methods::DEL, - methods::HEAD, - methods::OPTIONS, - methods::POST, - methods::PUT, - methods::PATCH, - U("CUstomMETHOD") - }; - const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); + // The counting is prevented from happening, because the short-circuit come before the count. + http_client client(m_uri); + client.add_handler(reply_stage); + client.add_handler(count_stage); + + // Don't include 'CONNECT' it has a special meaning. + utility::string_t send_methods[] = {methods::GET, + U("GET"), + methods::DEL, + methods::HEAD, + methods::OPTIONS, + methods::POST, + methods::PUT, + methods::PATCH, + U("CUstomMETHOD")}; + const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); + + for (int i = 0; i < num_methods; ++i) + { + http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::Forbidden); + } - for(int i = 0; i < num_methods; ++i) - { - http_asserts::assert_response_equals(client.request(send_methods[i]).get(), status_codes::Forbidden); + VERIFY_ARE_EQUAL(0u, count); } - VERIFY_ARE_EQUAL(0u, count); -} - -/// -/// Pipeline stage used for pipeline_stage_inspect_response. -/// -class modify_count_responses_stage : public http_pipeline_stage -{ -public: - modify_count_responses_stage() : m_Count(0) {} - - virtual pplx::task propagate(http_request request) + /// + /// Pipeline stage used for pipeline_stage_inspect_response. + /// + class modify_count_responses_stage : public http_pipeline_stage { - request.headers().set_content_type(U("modified content type")); + public: + modify_count_responses_stage() : m_Count(0) {} - auto currentStage = this->shared_from_this(); - return next_stage()->propagate(request).then([currentStage](http_response response) -> http_response + virtual pplx::task propagate(http_request request) { - - int prevCount = 0; - response.headers().match(U("My Header"), prevCount); - utility::stringstream_t data; - data << prevCount + ++std::dynamic_pointer_cast(currentStage)->m_Count; - response.headers().add(U("My Header"), data.str()); - return response; - }); - } - -private: - int m_Count; -}; - -TEST_FIXTURE(uri_address, pipeline_stage_inspect_response) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); + request.headers().set_content_type(U("modified content type")); + + auto currentStage = this->shared_from_this(); + return next_stage()->propagate(request).then([currentStage](http_response response) -> http_response { + int prevCount = 0; + response.headers().match(U("My Header"), prevCount); + utility::stringstream_t data; + data << prevCount + ++std::dynamic_pointer_cast(currentStage)->m_Count; + response.headers().add(U("My Header"), data.str()); + return response; + }); + } + + private: + int m_Count; + }; - scoped.server()->next_request().then([](test_request *request) + TEST_FIXTURE(uri_address, pipeline_stage_inspect_response) { - http_asserts::assert_test_request_equals(request, methods::GET, U("/"), U("modified content type")); - request->reply(status_codes::OK); - }); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); - // Put in nested scope so we lose the reference on the shared pointer. - { - std::shared_ptr countStage = std::make_shared(); - client.add_handler(countStage); - std::shared_ptr countStage2 = std::make_shared(); - client.add_handler(countStage2); - } + scoped.server()->next_request().then([](test_request* request) { + http_asserts::assert_test_request_equals(request, methods::GET, U("/"), U("modified content type")); + request->reply(status_codes::OK); + }); - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - VERIFY_ARE_EQUAL(U("1, 2"), response.headers()[U("My Header")]); -} + // Put in nested scope so we lose the reference on the shared pointer. + { + std::shared_ptr countStage = std::make_shared(); + client.add_handler(countStage); + std::shared_ptr countStage2 = std::make_shared(); + client.add_handler(countStage2); + } + + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + VERIFY_ARE_EQUAL(U("1, 2"), response.headers()[U("My Header")]); + } } // SUITE(pipeline_stage_tests) -}}}} \ No newline at end of file +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/progress_handler_tests.cpp b/Release/tests/functional/http/client/progress_handler_tests.cpp index a4e1c8a968..320bcc5cee 100644 --- a/Release/tests/functional/http/client/progress_handler_tests.cpp +++ b/Release/tests/functional/http/client/progress_handler_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases manually building up HTTP requests with progress handlers. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases manually building up HTTP requests with progress handlers. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,25 +20,28 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(progress_handler_tests) +namespace tests { - -TEST_FIXTURE(uri_address, set_progress_handler_no_bodies) +namespace functional +{ +namespace http +{ +namespace client +{ +SUITE(progress_handler_tests) { - http_client_config config; - config.set_chunksize(512); + TEST_FIXTURE(uri_address, set_progress_handler_no_bodies) + { + http_client_config config; + config.set_chunksize(512); - http_client client(m_uri, config); - const method mtd = methods::GET; - utility::size64_t upsize = 4711u, downsize = 4711u; - int calls = 0; + http_client client(m_uri, config); + const method mtd = methods::GET; + utility::size64_t upsize = 4711u, downsize = 4711u; + int calls = 0; - http_request msg(mtd); - msg.set_progress_handler( - [&](message_direction::direction direction, utility::size64_t so_far) - { + http_request msg(mtd); + msg.set_progress_handler([&](message_direction::direction direction, utility::size64_t so_far) { calls += 1; if (direction == message_direction::upload) upsize = so_far; @@ -46,46 +49,43 @@ TEST_FIXTURE(uri_address, set_progress_handler_no_bodies) downsize = so_far; }); - test_http_server::scoped_server scoped(m_uri); - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - std::map headers; - p_request->reply(200, utility::string_t(U("OK")), headers); - }); + test_http_server::scoped_server scoped(m_uri); + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + std::map headers; + p_request->reply(200, utility::string_t(U("OK")), headers); + }); - auto response = client.request(msg).get(); - http_asserts::assert_response_equals(response, status_codes::OK); + auto response = client.request(msg).get(); + http_asserts::assert_response_equals(response, status_codes::OK); - VERIFY_ARE_EQUAL(0, upsize); + VERIFY_ARE_EQUAL(0, upsize); - response.content_ready().wait(); + response.content_ready().wait(); - VERIFY_ARE_EQUAL(0, downsize); - VERIFY_ARE_EQUAL(2, calls); -} + VERIFY_ARE_EQUAL(0, downsize); + VERIFY_ARE_EQUAL(2, calls); + } -TEST_FIXTURE(uri_address, set_progress_handler_upload) -{ - http_client_config config; - config.set_chunksize(512); + TEST_FIXTURE(uri_address, set_progress_handler_upload) + { + http_client_config config; + config.set_chunksize(512); - http_client client(m_uri, config); - const method mtd = methods::POST; - utility::string_t data; - utility::string_t content_type = U("text/plain; charset=utf-8"); + http_client client(m_uri, config); + const method mtd = methods::POST; + utility::string_t data; + utility::string_t content_type = U("text/plain; charset=utf-8"); - const size_t repeats = 5500; - for (size_t i = 0; i < repeats; ++i) - data.append(U("abcdefghihklmnopqrstuvwxyz")); + const size_t repeats = 5500; + for (size_t i = 0; i < repeats; ++i) + data.append(U("abcdefghihklmnopqrstuvwxyz")); - utility::size64_t upsize = 4711u, downsize = 4711u; - int calls = 0; + utility::size64_t upsize = 4711u, downsize = 4711u; + int calls = 0; - http_request msg(mtd); - msg.set_progress_handler( - [&](message_direction::direction direction, utility::size64_t so_far) - { + http_request msg(mtd); + msg.set_progress_handler([&](message_direction::direction direction, utility::size64_t so_far) { calls += 1; if (direction == message_direction::upload) upsize = so_far; @@ -93,44 +93,41 @@ TEST_FIXTURE(uri_address, set_progress_handler_upload) downsize = so_far; }); - msg.set_body(data); + msg.set_body(data); - test_http_server::scoped_server scoped(m_uri); - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, mtd, U("/"), content_type, data); - std::map headers; - p_request->reply(200, utility::string_t(U("OK")), headers); - }); + test_http_server::scoped_server scoped(m_uri); + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/"), content_type, data); + std::map headers; + p_request->reply(200, utility::string_t(U("OK")), headers); + }); - auto response = client.request(msg).get(); - http_asserts::assert_response_equals(response, status_codes::OK); + auto response = client.request(msg).get(); + http_asserts::assert_response_equals(response, status_codes::OK); - VERIFY_ARE_EQUAL(26u*repeats, upsize); + VERIFY_ARE_EQUAL(26u * repeats, upsize); - response.content_ready().wait(); + response.content_ready().wait(); - VERIFY_ARE_EQUAL(0, downsize); - // We don't have very precise control over how much of a message is transferred - // in each chunk being sent or received, so we can't make an exact comparison here. - VERIFY_IS_TRUE(calls >= 3); -} + VERIFY_ARE_EQUAL(0, downsize); + // We don't have very precise control over how much of a message is transferred + // in each chunk being sent or received, so we can't make an exact comparison here. + VERIFY_IS_TRUE(calls >= 3); + } -TEST_FIXTURE(uri_address, set_progress_handler_download) -{ - http_client_config config; - config.set_chunksize(512); + TEST_FIXTURE(uri_address, set_progress_handler_download) + { + http_client_config config; + config.set_chunksize(512); - http_client client(m_uri, config); - const method mtd = methods::GET; + http_client client(m_uri, config); + const method mtd = methods::GET; - utility::size64_t upsize = 4711u, downsize = 4711u; - int calls = 0; + utility::size64_t upsize = 4711u, downsize = 4711u; + int calls = 0; - http_request msg(mtd); - msg.set_progress_handler( - [&](message_direction::direction direction, utility::size64_t so_far) - { + http_request msg(mtd); + msg.set_progress_handler([&](message_direction::direction direction, utility::size64_t so_far) { calls += 1; if (direction == message_direction::upload) upsize = so_far; @@ -138,55 +135,52 @@ TEST_FIXTURE(uri_address, set_progress_handler_download) downsize = so_far; }); - const size_t repeats = 6000; - - test_http_server::scoped_server scoped(m_uri); - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - std::string resp_data; - for (size_t i = 0; i < repeats; ++i) - resp_data.append("abcdefghihklmnopqrstuvwxyz"); + const size_t repeats = 6000; - std::map headers; - headers[U("Content-Type")] = U("text/plain"); - p_request->reply(200, utility::string_t(U("OK")), headers, resp_data); - }); + test_http_server::scoped_server scoped(m_uri); + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + std::string resp_data; + for (size_t i = 0; i < repeats; ++i) + resp_data.append("abcdefghihklmnopqrstuvwxyz"); + + std::map headers; + headers[U("Content-Type")] = U("text/plain"); + p_request->reply(200, utility::string_t(U("OK")), headers, resp_data); + }); - auto response = client.request(msg).get(); - http_asserts::assert_response_equals(response, status_codes::OK); + auto response = client.request(msg).get(); + http_asserts::assert_response_equals(response, status_codes::OK); - VERIFY_ARE_EQUAL(0, upsize); + VERIFY_ARE_EQUAL(0, upsize); - response.content_ready().wait(); + response.content_ready().wait(); - VERIFY_ARE_EQUAL(26u*repeats, downsize); - // We don't have very precise control over how much of a message is transferred - // in each chunk being sent or received, so we can't make an exact comparison here. - VERIFY_IS_TRUE(calls > 4); -} + VERIFY_ARE_EQUAL(26u * repeats, downsize); + // We don't have very precise control over how much of a message is transferred + // in each chunk being sent or received, so we can't make an exact comparison here. + VERIFY_IS_TRUE(calls > 4); + } -TEST_FIXTURE(uri_address, set_progress_handler_upload_and_download) -{ - http_client_config config; - config.set_chunksize(512); + TEST_FIXTURE(uri_address, set_progress_handler_upload_and_download) + { + http_client_config config; + config.set_chunksize(512); - http_client client(m_uri, config); - const method mtd = methods::POST; - utility::string_t data; - utility::string_t content_type = U("text/plain; charset=utf-8"); + http_client client(m_uri, config); + const method mtd = methods::POST; + utility::string_t data; + utility::string_t content_type = U("text/plain; charset=utf-8"); - const size_t repeats = 5500; - for (size_t i = 0; i < repeats; ++i) - data.append(U("abcdefghihklmnopqrstuvwxyz")); + const size_t repeats = 5500; + for (size_t i = 0; i < repeats; ++i) + data.append(U("abcdefghihklmnopqrstuvwxyz")); - utility::size64_t upsize = 4711u, downsize = 4711u; - int calls = 0; + utility::size64_t upsize = 4711u, downsize = 4711u; + int calls = 0; - http_request msg(mtd); - msg.set_progress_handler( - [&](message_direction::direction direction, utility::size64_t so_far) - { + http_request msg(mtd); + msg.set_progress_handler([&](message_direction::direction direction, utility::size64_t so_far) { calls += 1; if (direction == message_direction::upload) upsize = so_far; @@ -194,54 +188,51 @@ TEST_FIXTURE(uri_address, set_progress_handler_upload_and_download) downsize = so_far; }); - msg.set_body(data); + msg.set_body(data); - test_http_server::scoped_server scoped(m_uri); - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, mtd, U("/"), content_type, data); - std::string resp_data; - for (size_t i = 0; i < repeats*2; ++i) - resp_data.append("abcdefghihklmnopqrstuvwxyz"); - - std::map headers; - headers[U("Content-Type")] = U("text/plain"); - p_request->reply(200, utility::string_t(U("OK")), headers, resp_data); - }); + test_http_server::scoped_server scoped(m_uri); + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, mtd, U("/"), content_type, data); + std::string resp_data; + for (size_t i = 0; i < repeats * 2; ++i) + resp_data.append("abcdefghihklmnopqrstuvwxyz"); + + std::map headers; + headers[U("Content-Type")] = U("text/plain"); + p_request->reply(200, utility::string_t(U("OK")), headers, resp_data); + }); - auto response = client.request(msg).get(); - http_asserts::assert_response_equals(response, status_codes::OK); + auto response = client.request(msg).get(); + http_asserts::assert_response_equals(response, status_codes::OK); - VERIFY_ARE_EQUAL(26u*repeats, upsize); + VERIFY_ARE_EQUAL(26u * repeats, upsize); - response.content_ready().wait(); + response.content_ready().wait(); - VERIFY_ARE_EQUAL(26u*repeats*2, downsize); - // We don't have very precise control over how much of a message is transferred - // in each chunk being sent or received, so we can't make an exact comparison here. - VERIFY_IS_TRUE(calls > 4); -} + VERIFY_ARE_EQUAL(26u * repeats * 2, downsize); + // We don't have very precise control over how much of a message is transferred + // in each chunk being sent or received, so we can't make an exact comparison here. + VERIFY_IS_TRUE(calls > 4); + } -TEST_FIXTURE(uri_address, set_progress_handler_open_failure) -{ - http_client client(U("http://localhost323:-1")); + TEST_FIXTURE(uri_address, set_progress_handler_open_failure) + { + http_client client(U("http://localhost323:-1")); - const method mtd = methods::POST; - utility::string_t data; - utility::string_t content_type = U("text/plain; charset=utf-8"); + const method mtd = methods::POST; + utility::string_t data; + utility::string_t content_type = U("text/plain; charset=utf-8"); - const size_t repeats = 5500; - for (size_t i = 0; i < repeats; ++i) - data.append(U("abcdefghihklmnopqrstuvwxyz")); + const size_t repeats = 5500; + for (size_t i = 0; i < repeats; ++i) + data.append(U("abcdefghihklmnopqrstuvwxyz")); - utility::size64_t upsize = 4711u, downsize = 4711u; - int calls = 0; + utility::size64_t upsize = 4711u, downsize = 4711u; + int calls = 0; - http_request msg(mtd); - // We should never see this handler called. - msg.set_progress_handler( - [&](message_direction::direction direction, utility::size64_t so_far) - { + http_request msg(mtd); + // We should never see this handler called. + msg.set_progress_handler([&](message_direction::direction direction, utility::size64_t so_far) { calls += 1; if (direction == message_direction::upload) upsize = so_far; @@ -249,41 +240,39 @@ TEST_FIXTURE(uri_address, set_progress_handler_open_failure) downsize = so_far; }); - msg.set_body(data); + msg.set_body(data); - auto response = client.request(msg); - VERIFY_THROWS(response.get(), web::http::http_exception); - VERIFY_ARE_EQUAL(4711u, upsize); - VERIFY_ARE_EQUAL(4711u, downsize); - VERIFY_ARE_EQUAL(0, calls); -} + auto response = client.request(msg); + VERIFY_THROWS(response.get(), web::http::http_exception); + VERIFY_ARE_EQUAL(4711u, upsize); + VERIFY_ARE_EQUAL(4711u, downsize); + VERIFY_ARE_EQUAL(0, calls); + } -TEST_FIXTURE(uri_address, set_progress_handler_request_timeout) -{ - test_http_server::scoped_server scoped(m_uri); - http_client_config config; - config.set_chunksize(512); - config.set_timeout(utility::seconds(1)); + TEST_FIXTURE(uri_address, set_progress_handler_request_timeout) + { + test_http_server::scoped_server scoped(m_uri); + http_client_config config; + config.set_chunksize(512); + config.set_timeout(utility::seconds(1)); - http_client client(m_uri, config); + http_client client(m_uri, config); - const method mtd = methods::POST; - utility::string_t data; - utility::string_t content_type = U("text/plain; charset=utf-8"); + const method mtd = methods::POST; + utility::string_t data; + utility::string_t content_type = U("text/plain; charset=utf-8"); - const size_t repeats = 5500; - for (size_t i = 0; i < repeats; ++i) - data.append(U("abcdefghihklmnopqrstuvwxyz")); + const size_t repeats = 5500; + for (size_t i = 0; i < repeats; ++i) + data.append(U("abcdefghihklmnopqrstuvwxyz")); - utility::size64_t upsize = 4711u, downsize = 4711u; - int calls = 0; + utility::size64_t upsize = 4711u, downsize = 4711u; + int calls = 0; - http_request msg(mtd); - // We should never see this handler called for download, but for upload should still happen, since - // there's a server (just not a very responsive one) and we're sending data to it. - msg.set_progress_handler( - [&](message_direction::direction direction, utility::size64_t so_far) - { + http_request msg(mtd); + // We should never see this handler called for download, but for upload should still happen, since + // there's a server (just not a very responsive one) and we're sending data to it. + msg.set_progress_handler([&](message_direction::direction direction, utility::size64_t so_far) { calls += 1; if (direction == message_direction::upload) upsize = so_far; @@ -291,129 +280,123 @@ TEST_FIXTURE(uri_address, set_progress_handler_request_timeout) downsize = so_far; }); - msg.set_body(data); - auto t = scoped.server()->next_request(); - auto response = client.request(msg); + msg.set_body(data); + auto t = scoped.server()->next_request(); + auto response = client.request(msg); #ifdef __APPLE__ - // CodePlex 295 - VERIFY_THROWS(response.get(), http_exception); + // CodePlex 295 + VERIFY_THROWS(response.get(), http_exception); #else - VERIFY_THROWS_HTTP_ERROR_CODE(response.get(), std::errc::timed_out); + VERIFY_THROWS_HTTP_ERROR_CODE(response.get(), std::errc::timed_out); #endif - VERIFY_ARE_EQUAL(26u*repeats, upsize); - VERIFY_ARE_EQUAL(4711u, downsize); - // We don't have very precise control over how much of the message is transferred - // before the exception occurs, so we can't make an exact comparison here. - VERIFY_IS_TRUE(calls >= 2); - t.get(); -} - -TEST_FIXTURE(uri_address, upload_nobody_exception) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - http_request msg(methods::GET); + VERIFY_ARE_EQUAL(26u * repeats, upsize); + VERIFY_ARE_EQUAL(4711u, downsize); + // We don't have very precise control over how much of the message is transferred + // before the exception occurs, so we can't make an exact comparison here. + VERIFY_IS_TRUE(calls >= 2); + t.get(); + } - auto t = scoped.server()->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, upload_nobody_exception) { - p_request->reply(200, utility::string_t(U("OK"))); - }); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + http_request msg(methods::GET); - msg.set_progress_handler([](message_direction::direction, utility::size64_t) - { - // First all is for data upload completion - throw std::invalid_argument("fake error"); - }); + auto t = scoped.server()->next_request().then( + [&](test_request* p_request) { p_request->reply(200, utility::string_t(U("OK"))); }); - VERIFY_THROWS(client.request(msg).get(), std::invalid_argument); + msg.set_progress_handler([](message_direction::direction, utility::size64_t) { + // First all is for data upload completion + throw std::invalid_argument("fake error"); + }); - t.get(); -} + VERIFY_THROWS(client.request(msg).get(), std::invalid_argument); -TEST_FIXTURE(uri_address, download_nobody_exception) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - http_request msg(methods::GET); + t.get(); + } - scoped.server()->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, download_nobody_exception) { - p_request->reply(200, utility::string_t(U("OK"))); - }); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + http_request msg(methods::GET); + + scoped.server()->next_request().then( + [&](test_request* p_request) { p_request->reply(200, utility::string_t(U("OK"))); }); + + int numCalls = 0; + msg.set_progress_handler([&](message_direction::direction, utility::size64_t) { + if (++numCalls == 2) + { + // second is for data download + throw std::invalid_argument("fake error"); + } + }); - int numCalls = 0; - msg.set_progress_handler([&](message_direction::direction, utility::size64_t) - { - if(++numCalls == 2) - { - // second is for data download - throw std::invalid_argument("fake error"); - } - }); + VERIFY_THROWS(client.request(msg).get().content_ready().get(), std::invalid_argument); + } - VERIFY_THROWS(client.request(msg).get().content_ready().get(), std::invalid_argument); -} + TEST_FIXTURE(uri_address, data_upload_exception) + { + http_client client(m_uri); + http_request msg(methods::PUT); + msg.set_body(U("A")); -TEST_FIXTURE(uri_address, data_upload_exception) -{ - http_client client(m_uri); - http_request msg(methods::PUT); - msg.set_body(U("A")); + msg.set_progress_handler( + [&](message_direction::direction, utility::size64_t) { throw std::invalid_argument("fake error"); }); - msg.set_progress_handler([&](message_direction::direction, utility::size64_t) - { - throw std::invalid_argument("fake error"); - }); + pplx::task t; + { + test_http_server::scoped_server scoped(m_uri); + t = scoped.server()->next_request(); + VERIFY_THROWS(client.request(msg).get(), std::invalid_argument); + } + try + { + t.get(); + } + catch (const std::runtime_error&) + { /* It is ok if the request does not complete before the server is shutdown */ + } + } - pplx::task t; + TEST_FIXTURE(uri_address, data_download_exception, "Ignore:Windows", "395") { test_http_server::scoped_server scoped(m_uri); - t = scoped.server()->next_request(); - VERIFY_THROWS(client.request(msg).get(), std::invalid_argument); - } - try { t.get(); } - catch (const std::runtime_error&) { /* It is ok if the request does not complete before the server is shutdown */ } -} + http_client client(m_uri); + http_request msg(methods::GET); + + auto t = scoped.server()->next_request().then([&](test_request* p_request) { + std::string resp_data("abc"); + std::map headers; + headers[U("Content-Type")] = U("text/plain"); + p_request->reply(200, utility::string_t(U("OK")), headers, resp_data); + }); -TEST_FIXTURE(uri_address, data_download_exception, "Ignore:Windows", "395") -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - http_request msg(methods::GET); + int numCalls = 0; + msg.set_progress_handler([&](message_direction::direction, utility::size64_t) { + if (++numCalls == 2) + { + // 2rd is for data download + throw std::invalid_argument("fake error"); + } + }); - auto t = scoped.server()->next_request().then([&](test_request *p_request) - { - std::string resp_data("abc"); - std::map headers; - headers[U("Content-Type")] = U("text/plain"); - p_request->reply(200, utility::string_t(U("OK")), headers, resp_data); - }); - - int numCalls = 0; - msg.set_progress_handler([&](message_direction::direction, utility::size64_t) - { - if(++numCalls == 2) + try { - // 2rd is for data download - throw std::invalid_argument("fake error"); + handle_timeout([&] { client.request(msg).get().content_ready().get(); }); } - }); - - try - { - handle_timeout([&] + catch (std::invalid_argument const&) { - client.request(msg).get().content_ready().get(); - }); - } - catch (std::invalid_argument const &) - { - // Expected. + // Expected. + } + t.get(); } - t.get(); -} - } -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/proxy_tests.cpp b/Release/tests/functional/http/client/proxy_tests.cpp index 72fa201352..9a6c52069f 100644 --- a/Release/tests/functional/http/client/proxy_tests.cpp +++ b/Release/tests/functional/http/client/proxy_tests.cpp @@ -1,16 +1,16 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* proxy_tests.cpp -* -* Tests cases for using proxies with http_clients. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ +/*** + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * proxy_tests.cpp + * + * Tests cases for using proxies with http_clients. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -19,185 +19,204 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -// In order to run this test, replace this proxy uri with one that you have access to. -static const auto proxy_uri = U("http://netproxy.redmond.corp.microsoft.com"); - -SUITE(proxy_tests) -{ - -TEST_FIXTURE(uri_address, web_proxy_uri) -{ - uri u(proxy_uri); - - web_proxy uri_proxy(u); - VERIFY_IS_TRUE(uri_proxy.is_specified()); - VERIFY_IS_FALSE(uri_proxy.is_disabled()); - VERIFY_IS_FALSE(uri_proxy.is_auto_discovery()); - VERIFY_IS_FALSE(uri_proxy.is_default()); - VERIFY_ARE_EQUAL(u, uri_proxy.address()); -} - -TEST_FIXTURE(uri_address, web_proxy_disabled) +namespace tests { - web_proxy disabled_proxy(web_proxy::disabled); - VERIFY_IS_FALSE(disabled_proxy.is_specified()); - VERIFY_IS_TRUE(disabled_proxy.is_disabled()); - VERIFY_IS_FALSE(disabled_proxy.is_auto_discovery()); - VERIFY_IS_FALSE(disabled_proxy.is_default()); -} - -TEST_FIXTURE(uri_address, web_proxy_discover) +namespace functional { - web_proxy discover_proxy(web_proxy::use_auto_discovery); - VERIFY_IS_FALSE(discover_proxy.is_specified()); - VERIFY_IS_FALSE(discover_proxy.is_disabled()); - VERIFY_IS_TRUE(discover_proxy.is_auto_discovery()); - VERIFY_IS_FALSE(discover_proxy.is_default()); -} - -TEST_FIXTURE(uri_address, web_proxy_default) +namespace http { - web_proxy default_proxy(web_proxy::use_default); - VERIFY_IS_FALSE(default_proxy.is_specified()); - VERIFY_IS_FALSE(default_proxy.is_disabled()); - VERIFY_IS_FALSE(default_proxy.is_auto_discovery()); - VERIFY_IS_TRUE(default_proxy.is_default()); -} - -TEST_FIXTURE(uri_address, web_proxy_default_construct) +namespace client { - web_proxy default_proxy_2; - VERIFY_IS_FALSE(default_proxy_2.is_specified()); - VERIFY_IS_FALSE(default_proxy_2.is_disabled()); - VERIFY_IS_FALSE(default_proxy_2.is_auto_discovery()); - VERIFY_IS_TRUE(default_proxy_2.is_default()); -} - -TEST_FIXTURE(uri_address, http_client_config_set_proxy) -{ - http_client_config hconfig; - VERIFY_IS_TRUE(hconfig.proxy().is_default()); +// In order to run this test, replace this proxy uri with one that you have access to. +static const auto proxy_uri = U("http://netproxy.redmond.corp.microsoft.com"); - uri u = U("http://x"); +SUITE(proxy_tests) +{ + TEST_FIXTURE(uri_address, web_proxy_uri) + { + uri u(proxy_uri); - hconfig.set_proxy(web_proxy(u)); - VERIFY_ARE_EQUAL(u, hconfig.proxy().address()); -} + web_proxy uri_proxy(u); + VERIFY_IS_TRUE(uri_proxy.is_specified()); + VERIFY_IS_FALSE(uri_proxy.is_disabled()); + VERIFY_IS_FALSE(uri_proxy.is_auto_discovery()); + VERIFY_IS_FALSE(uri_proxy.is_default()); + VERIFY_ARE_EQUAL(u, uri_proxy.address()); + } -#ifndef __cplusplus_winrt -// IXHR2 does not allow the proxy settings to be changed -TEST_FIXTURE(uri_address, auto_discovery_proxy) -{ - test_http_server::scoped_server scoped(m_uri); - auto t = scoped.server()->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, web_proxy_disabled) + { + web_proxy disabled_proxy(web_proxy::disabled); + VERIFY_IS_FALSE(disabled_proxy.is_specified()); + VERIFY_IS_TRUE(disabled_proxy.is_disabled()); + VERIFY_IS_FALSE(disabled_proxy.is_auto_discovery()); + VERIFY_IS_FALSE(disabled_proxy.is_default()); + } + + TEST_FIXTURE(uri_address, web_proxy_discover) + { + web_proxy discover_proxy(web_proxy::use_auto_discovery); + VERIFY_IS_FALSE(discover_proxy.is_specified()); + VERIFY_IS_FALSE(discover_proxy.is_disabled()); + VERIFY_IS_TRUE(discover_proxy.is_auto_discovery()); + VERIFY_IS_FALSE(discover_proxy.is_default()); + } + + TEST_FIXTURE(uri_address, web_proxy_default) { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("text/plain"), U("this is a test")); - p_request->reply(status_codes::OK); - }); - http_client_config config; - config.set_proxy(web_proxy::use_auto_discovery); + web_proxy default_proxy(web_proxy::use_default); + VERIFY_IS_FALSE(default_proxy.is_specified()); + VERIFY_IS_FALSE(default_proxy.is_disabled()); + VERIFY_IS_FALSE(default_proxy.is_auto_discovery()); + VERIFY_IS_TRUE(default_proxy.is_default()); + } + + TEST_FIXTURE(uri_address, web_proxy_default_construct) + { + web_proxy default_proxy_2; + VERIFY_IS_FALSE(default_proxy_2.is_specified()); + VERIFY_IS_FALSE(default_proxy_2.is_disabled()); + VERIFY_IS_FALSE(default_proxy_2.is_auto_discovery()); + VERIFY_IS_TRUE(default_proxy_2.is_default()); + } + + TEST_FIXTURE(uri_address, http_client_config_set_proxy) + { + http_client_config hconfig; + VERIFY_IS_TRUE(hconfig.proxy().is_default()); - http_client client(m_uri, config); - http_asserts::assert_response_equals(client.request(methods::PUT, U("/"), U("this is a test")).get(), status_codes::OK); + uri u = U("http://x"); - t.get(); -} + hconfig.set_proxy(web_proxy(u)); + VERIFY_ARE_EQUAL(u, hconfig.proxy().address()); + } -TEST_FIXTURE(uri_address, disabled_proxy) -{ - test_http_server::scoped_server scoped(m_uri); - auto t = scoped.server()->next_request().then([&](test_request *p_request) +#ifndef __cplusplus_winrt + // IXHR2 does not allow the proxy settings to be changed + TEST_FIXTURE(uri_address, auto_discovery_proxy) { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("text/plain"), U("sample data")); - p_request->reply(status_codes::OK); - }); + test_http_server::scoped_server scoped(m_uri); + auto t = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::PUT, U("/"), U("text/plain"), U("this is a test")); + p_request->reply(status_codes::OK); + }); + http_client_config config; + config.set_proxy(web_proxy::use_auto_discovery); + + http_client client(m_uri, config); + http_asserts::assert_response_equals(client.request(methods::PUT, U("/"), U("this is a test")).get(), + status_codes::OK); + + t.get(); + } + + TEST_FIXTURE(uri_address, disabled_proxy) + { + test_http_server::scoped_server scoped(m_uri); + auto t = scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::PUT, U("/"), U("text/plain"), U("sample data")); + p_request->reply(status_codes::OK); + }); - http_client_config config; - config.set_proxy(web_proxy::disabled); + http_client_config config; + config.set_proxy(web_proxy::disabled); - http_client client(m_uri, config); - http_asserts::assert_response_equals(client.request(methods::PUT, U("/"), U("sample data")).get(), status_codes::OK); + http_client client(m_uri, config); + http_asserts::assert_response_equals(client.request(methods::PUT, U("/"), U("sample data")).get(), + status_codes::OK); - t.get(); -} + t.get(); + } #endif // __cplusplus_winrt #ifdef __cplusplus_winrt -TEST_FIXTURE(uri_address, no_proxy_options_on_winrt) -{ - http_client_config config; - config.set_proxy(web_proxy::use_auto_discovery); - http_client client(m_uri, config); + TEST_FIXTURE(uri_address, no_proxy_options_on_winrt) + { + http_client_config config; + config.set_proxy(web_proxy::use_auto_discovery); + http_client client(m_uri, config); - VERIFY_THROWS(client.request(methods::GET, U("/")).get(), http_exception); -} + VERIFY_THROWS(client.request(methods::GET, U("/")).get(), http_exception); + } #endif #ifndef __cplusplus_winrt -// Can't specify a proxy with WinRT implementation. - TEST_FIXTURE(uri_address, http_proxy_with_credentials, "Ignore:Linux", "Github 53", "Ignore:Apple", "Github 53", "Ignore:Android", "Github 53", "Ignore:IOS", "Github 53", "Ignore", "Manual") -{ - web_proxy proxy(proxy_uri); - web::credentials cred(U("artur"), U("fred")); // relax, this is not my real password - proxy.set_credentials(cred); - - http_client_config config; - config.set_proxy(proxy); - - // Access to this server will succeed because the first request will not be challenged and hence - // my bogus credentials will not be supplied. - http_client client(U("http://www.microsoft.com"), config); - - try - { - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - response.content_ready().wait(); - } - catch (web::http::http_exception const& e) - { - if (e.error_code().value() == 12007) { - // The above "netproxy.redmond.corp.microsoft.com" is an internal site not generally accessible. - // This will cause a failure to resolve the URL. - // This is ok. - return; - } - throw; - } -} - -TEST_FIXTURE(uri_address, http_proxy, "Ignore", "Manual") -{ - - http_client_config config; - config.set_proxy(web_proxy(proxy_uri)); - - http_client client(U("http://httpbin.org"), config); - - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - response.content_ready().wait(); -} - - -TEST_FIXTURE(uri_address, https_proxy, "Ignore", "Manual") -{ - http_client_config config; - config.set_proxy(web_proxy(proxy_uri)); - - http_client client(U("https://httpbin.org"), config); - - http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - response.content_ready().wait(); -} + // Can't specify a proxy with WinRT implementation. + TEST_FIXTURE(uri_address, + http_proxy_with_credentials, + "Ignore:Linux", + "Github 53", + "Ignore:Apple", + "Github 53", + "Ignore:Android", + "Github 53", + "Ignore:IOS", + "Github 53", + "Ignore", + "Manual") + { + web_proxy proxy(proxy_uri); + web::credentials cred(U("artur"), U("fred")); // relax, this is not my real password + proxy.set_credentials(cred); + + http_client_config config; + config.set_proxy(proxy); + + // Access to this server will succeed because the first request will not be challenged and hence + // my bogus credentials will not be supplied. + http_client client(U("http://www.microsoft.com"), config); + + try + { + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + response.content_ready().wait(); + } + catch (web::http::http_exception const& e) + { + if (e.error_code().value() == 12007) + { + // The above "netproxy.redmond.corp.microsoft.com" is an internal site not generally accessible. + // This will cause a failure to resolve the URL. + // This is ok. + return; + } + throw; + } + } + + TEST_FIXTURE(uri_address, http_proxy, "Ignore", "Manual") + { + http_client_config config; + config.set_proxy(web_proxy(proxy_uri)); + + http_client client(U("http://httpbin.org"), config); + + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + response.content_ready().wait(); + } + + TEST_FIXTURE(uri_address, https_proxy, "Ignore", "Manual") + { + http_client_config config; + config.set_proxy(web_proxy(proxy_uri)); + + http_client client(U("https://httpbin.org"), config); + http_response response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + response.content_ready().wait(); + } #endif } // SUITE(proxy_tests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/request_helper_tests.cpp b/Release/tests/functional/http/client/request_helper_tests.cpp index ee4ff762b6..6c8ef5e087 100644 --- a/Release/tests/functional/http/client/request_helper_tests.cpp +++ b/Release/tests/functional/http/client/request_helper_tests.cpp @@ -1,261 +1,277 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* request_helper_tests.cpp -* -* Tests cases for the convenience helper functions for making requests on http_client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * request_helper_tests.cpp + * + * Tests cases for the convenience helper functions for making requests on http_client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include - -#include "cpprest/version.h" #include "cpprest/details/http_helpers.h" +#include "cpprest/version.h" +#include -using namespace web; +using namespace web; using namespace utility; using namespace web::http; using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(request_helper_tests) +namespace tests { - -TEST_FIXTURE(uri_address, do_not_fail_on_content_encoding_when_not_requested) +namespace functional { - test_http_server::scoped_server scoped(m_uri); - auto& server = *scoped.server(); - http_client client(m_uri); - - server.next_request().then([](test_request *p_request) { - p_request->reply(200, U("OK"), { {header_names::content_encoding, U("chunked")} }); - }); - - http_asserts::assert_response_equals(client.request(methods::GET).get(), status_codes::OK); -} - -TEST_FIXTURE(uri_address, fail_on_content_encoding_if_unsupported) +namespace http +{ +namespace client +{ +SUITE(request_helper_tests) { - if (web::http::compression::builtin::supported()) + TEST_FIXTURE(uri_address, do_not_fail_on_content_encoding_when_not_requested) { test_http_server::scoped_server scoped(m_uri); auto& server = *scoped.server(); - http_client_config config; - config.set_request_compressed_response(true); - http_client client(m_uri, config); + http_client client(m_uri); - server.next_request().then([](test_request *p_request) { - p_request->reply(200, U("OK"), { {header_names::content_encoding, U("unsupported-algorithm")} }); + server.next_request().then([](test_request* p_request) { + p_request->reply(200, U("OK"), {{header_names::content_encoding, U("chunked")}}); }); - VERIFY_THROWS(client.request(methods::GET).get(), web::http::http_exception); + http_asserts::assert_response_equals(client.request(methods::GET).get(), status_codes::OK); } -} -TEST_FIXTURE(uri_address, send_accept_encoding) -{ - if (web::http::compression::builtin::supported()) + TEST_FIXTURE(uri_address, fail_on_content_encoding_if_unsupported) + { + if (web::http::compression::builtin::supported()) + { + test_http_server::scoped_server scoped(m_uri); + auto& server = *scoped.server(); + http_client_config config; + config.set_request_compressed_response(true); + http_client client(m_uri, config); + + server.next_request().then([](test_request* p_request) { + p_request->reply(200, U("OK"), {{header_names::content_encoding, U("unsupported-algorithm")}}); + }); + + VERIFY_THROWS(client.request(methods::GET).get(), web::http::http_exception); + } + } + + TEST_FIXTURE(uri_address, send_accept_encoding) + { + if (web::http::compression::builtin::supported()) + { + test_http_server::scoped_server scoped(m_uri); + auto& server = *scoped.server(); + http_client_config config; + config.set_request_compressed_response(true); + http_client client(m_uri, config); + + std::atomic found_accept_encoding(false); + + server.next_request().then([&found_accept_encoding](test_request* p_request) { + found_accept_encoding = + p_request->m_headers.find(header_names::accept_encoding) != p_request->m_headers.end(); + p_request->reply(200, U("OK")); + }); + + client.request(methods::GET).get(); + + VERIFY_IS_TRUE(found_accept_encoding); + } + } + + TEST_FIXTURE(uri_address, do_not_send_accept_encoding) { test_http_server::scoped_server scoped(m_uri); auto& server = *scoped.server(); - http_client_config config; - config.set_request_compressed_response(true); - http_client client(m_uri, config); + http_client client(m_uri); - std::atomic found_accept_encoding(false); + std::atomic found_accept_encoding(true); - server.next_request().then([&found_accept_encoding](test_request *p_request) { - found_accept_encoding = p_request->m_headers.find(header_names::accept_encoding) != p_request->m_headers.end(); + server.next_request().then([&found_accept_encoding](test_request* p_request) { + utility::string_t header; + + // On Windows, someone along the way (not us!) adds "Accept-Encoding: peerdist" + found_accept_encoding = + p_request->match_header(header_names::accept_encoding, header) && header != _XPLATSTR("peerdist"); p_request->reply(200, U("OK")); }); client.request(methods::GET).get(); - VERIFY_IS_TRUE(found_accept_encoding); + VERIFY_IS_FALSE(found_accept_encoding); } -} -TEST_FIXTURE(uri_address, do_not_send_accept_encoding) -{ - test_http_server::scoped_server scoped(m_uri); - auto& server = *scoped.server(); - http_client client(m_uri); + TEST_FIXTURE(uri_address, non_rvalue_bodies) + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + // Without content type. + utility::string_t send_body = U("YES NOW SEND THE TROOPS!"); + p_server->next_request().then([&send_body](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::PUT, U("/"), U("text/plain; charset=utf-8"), send_body); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(methods::PUT, U(""), send_body).get(), status_codes::OK); + + // With content type. + utility::string_t content_type = U("custom_content"); + test_server_utilities::verify_request( + &client, methods::PUT, U("/"), content_type, send_body, p_server, status_codes::OK, U("OK")); + + // Empty body type + send_body.clear(); + content_type = U("haha_type"); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), content_type); + VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); + VERIFY_ARE_EQUAL(0u, p_request->reply(status_codes::OK, U("OK"))); + }); + http_asserts::assert_response_equals( + client.request(methods::PUT, U("/"), send_body, content_type).get(), status_codes::OK, U("OK")); + } - std::atomic found_accept_encoding(true); + TEST_FIXTURE(uri_address, rvalue_bodies) + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + // Without content type. + utility::string_t send_body = U("YES NOW SEND THE TROOPS!"); + utility::string_t move_body = send_body; + p_server->next_request().then([&send_body](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::PUT, U("/"), U("text/plain; charset=utf-8"), send_body); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(methods::PUT, U(""), std::move(move_body)).get(), + status_codes::OK); + + // With content type. + utility::string_t content_type = U("custom_content"); + move_body = send_body; + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), content_type, send_body); + p_request->reply(200); + }); + http_asserts::assert_response_equals( + client.request(methods::PUT, U(""), std::move(move_body), content_type).get(), status_codes::OK); + + // Empty body. + content_type = U("haha_type"); + send_body.clear(); + move_body = send_body; + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), content_type); + VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); + p_request->reply(200); + }); + http_asserts::assert_response_equals( + client.request(methods::PUT, U(""), std::move(move_body), content_type).get(), status_codes::OK); + } - server.next_request().then([&found_accept_encoding](test_request *p_request) { - utility::string_t header; + TEST_FIXTURE(uri_address, json_bodies) + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + // JSON bool value. + json::value bool_value = json::value::boolean(true); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::PUT, U("/"), U("application/json"), bool_value.serialize()); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(methods::PUT, U("/"), bool_value).get(), status_codes::OK); + + // JSON null value. + json::value null_value = json::value::null(); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals( + p_request, methods::PUT, U("/"), U("application/json"), null_value.serialize()); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(methods::PUT, U(""), null_value).get(), status_codes::OK); + } - // On Windows, someone along the way (not us!) adds "Accept-Encoding: peerdist" - found_accept_encoding = - p_request->match_header(header_names::accept_encoding, header) && header != _XPLATSTR("peerdist"); - p_request->reply(200, U("OK")); - }); + TEST_FIXTURE(uri_address, non_rvalue_2k_body) + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + std::string body; + for (int i = 0; i < 2048; ++i) + { + body.append(1, (char)('A' + (i % 26))); + } + test_server_utilities::verify_request(&client, + methods::PUT, + U("/"), + U("text/plain"), + ::utility::conversions::to_string_t(body), + p_server, + status_codes::OK, + U("OK")); + } - client.request(methods::GET).get(); + TEST_FIXTURE(uri_address, default_user_agent) + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + p_server->next_request().then([&](test_request* p_request) { + utility::stringstream_t stream; + stream << _XPLATSTR("cpprestsdk/") << CPPREST_VERSION_MAJOR << _XPLATSTR(".") << CPPREST_VERSION_MINOR + << _XPLATSTR(".") << CPPREST_VERSION_REVISION; + utility::string_t foundHeader; + p_request->match_header(U("User-Agent"), foundHeader); + VERIFY_ARE_EQUAL(stream.str(), foundHeader); + + p_request->reply(200); + }); - VERIFY_IS_FALSE(found_accept_encoding); -} + http_asserts::assert_response_equals(client.request(methods::GET).get(), status_codes::OK); + } -TEST_FIXTURE(uri_address, non_rvalue_bodies) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - // Without content type. - utility::string_t send_body = U("YES NOW SEND THE TROOPS!"); - p_server->next_request().then([&send_body](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("text/plain; charset=utf-8"), send_body); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(methods::PUT, U(""), send_body).get(), status_codes::OK); - - // With content type. - utility::string_t content_type = U("custom_content"); - test_server_utilities::verify_request(&client, methods::PUT, U("/"), content_type, send_body, p_server, status_codes::OK, U("OK")); - - // Empty body type - send_body.clear(); - content_type = U("haha_type"); - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), content_type); - VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); - VERIFY_ARE_EQUAL(0u, p_request->reply(status_codes::OK, U("OK"))); - }); - http_asserts::assert_response_equals(client.request(methods::PUT, U("/"), send_body, content_type).get(), status_codes::OK, U("OK")); -} - -TEST_FIXTURE(uri_address, rvalue_bodies) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - // Without content type. - utility::string_t send_body = U("YES NOW SEND THE TROOPS!"); - utility::string_t move_body = send_body; - p_server->next_request().then([&send_body](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("text/plain; charset=utf-8"), send_body); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(methods::PUT, U(""), std::move(move_body)).get(), status_codes::OK); - - // With content type. - utility::string_t content_type = U("custom_content"); - move_body = send_body; - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), content_type, send_body); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(methods::PUT, U(""), std::move(move_body), content_type).get(), status_codes::OK); - - // Empty body. - content_type = U("haha_type"); - send_body.clear(); - move_body = send_body; - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), content_type); - VERIFY_ARE_EQUAL(0u, p_request->m_body.size()); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(methods::PUT, U(""), std::move(move_body), content_type).get(), status_codes::OK); -} - -TEST_FIXTURE(uri_address, json_bodies) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - // JSON bool value. - json::value bool_value = json::value::boolean(true); - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("application/json"), bool_value.serialize()); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(methods::PUT, U("/"), bool_value).get(), status_codes::OK); - - // JSON null value. - json::value null_value = json::value::null(); - p_server->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, overwrite_user_agent) { - http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("application/json"), null_value.serialize()); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(methods::PUT, U(""), null_value).get(), status_codes::OK); -} + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); -TEST_FIXTURE(uri_address, non_rvalue_2k_body) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); + utility::string_t customUserAgent(U("MyAgent")); + p_server->next_request().then([&](test_request* p_request) { + utility::string_t foundHeader; + p_request->match_header(U("User-Agent"), foundHeader); + VERIFY_ARE_EQUAL(customUserAgent, foundHeader); - std::string body; - for(int i = 0; i < 2048; ++i) - { - body.append(1, (char)('A' + (i % 26))); - } - test_server_utilities::verify_request(&client, methods::PUT, U("/"), U("text/plain"), ::utility::conversions::to_string_t(body), p_server, status_codes::OK, U("OK")); -} + p_request->reply(200); + }); -TEST_FIXTURE(uri_address, default_user_agent) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - p_server->next_request().then([&](test_request *p_request) - { - utility::stringstream_t stream; - stream << _XPLATSTR("cpprestsdk/") << CPPREST_VERSION_MAJOR << _XPLATSTR(".") << CPPREST_VERSION_MINOR << _XPLATSTR(".") << CPPREST_VERSION_REVISION; - utility::string_t foundHeader; - p_request->match_header(U("User-Agent"), foundHeader); - VERIFY_ARE_EQUAL(stream.str(), foundHeader); - - p_request->reply(200); - }); - - http_asserts::assert_response_equals(client.request(methods::GET).get(), status_codes::OK); -} - -TEST_FIXTURE(uri_address, overwrite_user_agent) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - utility::string_t customUserAgent(U("MyAgent")); - p_server->next_request().then([&](test_request *p_request) - { - utility::string_t foundHeader; - p_request->match_header(U("User-Agent"), foundHeader); - VERIFY_ARE_EQUAL(customUserAgent, foundHeader); - - p_request->reply(200); - }); - - http_request request(methods::GET); - request.headers()[U("User-Agent")] = customUserAgent; - http_asserts::assert_response_equals(client.request(request).get(), status_codes::OK); -} + http_request request(methods::GET); + request.headers()[U("User-Agent")] = customUserAgent; + http_asserts::assert_response_equals(client.request(request).get(), status_codes::OK); + } } // SUITE(request_helper_tests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/request_stream_tests.cpp b/Release/tests/functional/http/client/request_stream_tests.cpp index 692c8142a9..6d38072805 100644 --- a/Release/tests/functional/http/client/request_stream_tests.cpp +++ b/Release/tests/functional/http/client/request_stream_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases covering using streams with HTTP request with http_client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases covering using streams with HTTP request with http_client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -23,16 +23,22 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -utility::string_t get_full_name(const utility::string_t &name) +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client +{ +utility::string_t get_full_name(const utility::string_t& name) { #if defined(__cplusplus_winrt) // On WinRT, we must compensate for the fact that we will be accessing files in the // Documents folder - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->CreateFileAsync( - ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)).get(); + auto file = pplx::create_task(KnownFolders::DocumentsLibrary->CreateFileAsync( + ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)) + .get(); return file->Path->Data(); #else return name; @@ -40,13 +46,13 @@ utility::string_t get_full_name(const utility::string_t &name) } template -pplx::task> OPEN_R(const utility::string_t &name) +pplx::task> OPEN_R(const utility::string_t& name) { #if !defined(__cplusplus_winrt) return streams::file_buffer<_CharType>::open(name, std::ios_base::in); #else - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); + auto file = + pplx::create_task(KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); return streams::file_buffer<_CharType>::open(file, std::ios_base::in); #endif @@ -54,401 +60,396 @@ pplx::task> OPEN_R(const utility::string_t &name) SUITE(request_stream_tests) { + // Used to prepare data for stream tests + void fill_file(const utility::string_t& name, size_t repetitions = 1) + { + std::fstream stream(get_full_name(name), std::ios_base::out | std::ios_base::trunc); -// Used to prepare data for stream tests -void fill_file(const utility::string_t &name, size_t repetitions = 1) -{ - std::fstream stream(get_full_name(name), std::ios_base::out | std::ios_base::trunc); - - for (size_t i = 0; i < repetitions; i++) - stream << "abcdefghijklmnopqrstuvwxyz"; -} + for (size_t i = 0; i < repetitions; i++) + stream << "abcdefghijklmnopqrstuvwxyz"; + } -void fill_buffer(streams::streambuf rbuf, size_t repetitions = 1) -{ - const char *text = "abcdefghijklmnopqrstuvwxyz"; - size_t len = strlen(text); - for (size_t i = 0; i < repetitions; i++) - rbuf.putn_nocopy((const uint8_t *)text, len); -} + void fill_buffer(streams::streambuf rbuf, size_t repetitions = 1) + { + const char* text = "abcdefghijklmnopqrstuvwxyz"; + size_t len = strlen(text); + for (size_t i = 0; i < repetitions; i++) + rbuf.putn_nocopy((const uint8_t*)text, len); + } #if defined(__cplusplus_winrt) -TEST_FIXTURE(uri_address, ixhr2_transfer_encoding) -{ - // Transfer encoding chunked is not supported. Not specifying the - // content length should cause an exception from the task. Verify - // that there is no unobserved exception + TEST_FIXTURE(uri_address, ixhr2_transfer_encoding) + { + // Transfer encoding chunked is not supported. Not specifying the + // content length should cause an exception from the task. Verify + // that there is no unobserved exception - http_client client(m_uri); + http_client client(m_uri); - auto buf = streams::producer_consumer_buffer(); - buf.putc(22).wait(); - buf.close(std::ios_base::out).wait(); + auto buf = streams::producer_consumer_buffer(); + buf.putc(22).wait(); + buf.close(std::ios_base::out).wait(); - http_request reqG(methods::PUT); - reqG.set_body(buf.create_istream()); - VERIFY_THROWS(client.request(reqG).get(), http_exception); + http_request reqG(methods::PUT); + reqG.set_body(buf.create_istream()); + VERIFY_THROWS(client.request(reqG).get(), http_exception); - VERIFY_THROWS(client.request(methods::POST, U(""), buf.create_istream(), 1).get(), http_exception); -} + VERIFY_THROWS(client.request(methods::POST, U(""), buf.create_istream(), 1).get(), http_exception); + } #endif -TEST_FIXTURE(uri_address, set_body_stream_1) -{ - utility::string_t fname = U("set_body_stream_1.txt"); - fill_file(fname); + TEST_FIXTURE(uri_address, set_body_stream_1) + { + utility::string_t fname = U("set_body_stream_1.txt"); + fill_file(fname); - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); - auto stream = OPEN_R(fname).get(); - http_request msg(methods::POST); - msg.set_body(stream); + auto stream = OPEN_R(fname).get(); + http_request msg(methods::POST); + msg.set_body(stream); #if defined(__cplusplus_winrt) - msg.headers().set_content_length(26); + msg.headers().set_content_length(26); #endif - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); - VERIFY_ARE_EQUAL(26u, p_request->m_body.size()); - std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); - VERIFY_ARE_EQUAL(U("abcdefghijklmnopqrstuvwxyz"), ::utility::conversions::to_string_t(str_body)); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - stream.close().wait(); -} + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); + VERIFY_ARE_EQUAL(26u, p_request->m_body.size()); + std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); + VERIFY_ARE_EQUAL(U("abcdefghijklmnopqrstuvwxyz"), ::utility::conversions::to_string_t(str_body)); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + stream.close().wait(); + } -TEST_FIXTURE(uri_address, set_body_stream_2) -{ - utility::string_t fname = U("set_body_stream_2.txt"); - fill_file(fname); + TEST_FIXTURE(uri_address, set_body_stream_2) + { + utility::string_t fname = U("set_body_stream_2.txt"); + fill_file(fname); - http_client_config config; - config.set_chunksize(16*1024); + http_client_config config; + config.set_chunksize(16 * 1024); - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri, config); + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri, config); - auto stream = OPEN_R(fname).get(); - http_request msg(methods::POST); - msg.set_body(stream); + auto stream = OPEN_R(fname).get(); + http_request msg(methods::POST); + msg.set_body(stream); #if defined(__cplusplus_winrt) - msg.headers().set_content_length(26); + msg.headers().set_content_length(26); #endif - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); - VERIFY_ARE_EQUAL(26u, p_request->m_body.size()); - std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); - VERIFY_ARE_EQUAL(U("abcdefghijklmnopqrstuvwxyz"), ::utility::conversions::to_string_t(str_body)); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - stream.close().wait(); -} - -// Implementation for request with stream test case. -static void stream_request_impl(const uri &address, bool withContentLength, size_t chunksize, utility::string_t fname) -{ - fill_file(fname); - //(withContentLength); - http_client_config config; - config.set_chunksize(chunksize); - - test_http_server::scoped_server scoped(address); - test_http_server * p_server = scoped.server(); - http_client client(address, config); - - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); - VERIFY_ARE_EQUAL(26u, p_request->m_body.size()); - std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); - VERIFY_ARE_EQUAL(U("abcdefghijklmnopqrstuvwxyz"), ::utility::conversions::to_string_t(str_body)); - p_request->reply(200); - }); - - auto stream = OPEN_R(fname).get(); - - if(withContentLength) - { - http_asserts::assert_response_equals(client.request(methods::POST, U(""), stream, 26, U("text/plain")).get(), status_codes::OK); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); + VERIFY_ARE_EQUAL(26u, p_request->m_body.size()); + std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); + VERIFY_ARE_EQUAL(U("abcdefghijklmnopqrstuvwxyz"), ::utility::conversions::to_string_t(str_body)); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + stream.close().wait(); } - else + + // Implementation for request with stream test case. + static void stream_request_impl( + const uri& address, bool withContentLength, size_t chunksize, utility::string_t fname) { + fill_file(fname); + //(withContentLength); + http_client_config config; + config.set_chunksize(chunksize); + + test_http_server::scoped_server scoped(address); + test_http_server* p_server = scoped.server(); + http_client client(address, config); + + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); + VERIFY_ARE_EQUAL(26u, p_request->m_body.size()); + std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); + VERIFY_ARE_EQUAL(U("abcdefghijklmnopqrstuvwxyz"), ::utility::conversions::to_string_t(str_body)); + p_request->reply(200); + }); + + auto stream = OPEN_R(fname).get(); + + if (withContentLength) + { + http_asserts::assert_response_equals( + client.request(methods::POST, U(""), stream, 26, U("text/plain")).get(), status_codes::OK); + } + else + { #if defined __cplusplus_winrt - http_asserts::assert_response_equals(client.request(methods::POST, U(""), stream, 26, U("text/plain")).get(), status_codes::OK); + http_asserts::assert_response_equals( + client.request(methods::POST, U(""), stream, 26, U("text/plain")).get(), status_codes::OK); #else - http_asserts::assert_response_equals(client.request(methods::POST, U(""), stream, U("text/plain")).get(), status_codes::OK); + http_asserts::assert_response_equals(client.request(methods::POST, U(""), stream, U("text/plain")).get(), + status_codes::OK); #endif - } + } - stream.close().wait(); -} + stream.close().wait(); + } #if !defined(__cplusplus_winrt) -TEST_FIXTURE(uri_address, without_content_length_1) -{ - stream_request_impl(m_uri, false, 64*1024, U("without_content_length_1.txt")); -} + TEST_FIXTURE(uri_address, without_content_length_1) + { + stream_request_impl(m_uri, false, 64 * 1024, U("without_content_length_1.txt")); + } -TEST_FIXTURE(uri_address, without_content_length_2) -{ - stream_request_impl(m_uri, false, 1024, U("without_content_length_2.txt")); -} + TEST_FIXTURE(uri_address, without_content_length_2) + { + stream_request_impl(m_uri, false, 1024, U("without_content_length_2.txt")); + } #endif -TEST_FIXTURE(uri_address, with_content_length_1) -{ - stream_request_impl(m_uri, true, 64*1024, U("with_content_length_1.txt")); -} - -TEST_FIXTURE(uri_address, producer_consumer_buffer_with_content_length) -{ - streams::producer_consumer_buffer rbuf; - fill_buffer(rbuf); - rbuf.close(std::ios_base::out); - - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - http_request msg(methods::POST); - msg.set_body(streams::istream(rbuf)); - msg.headers().set_content_length(26); - - p_server->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, with_content_length_1) { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); - VERIFY_ARE_EQUAL(26u, p_request->m_body.size()); - std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); - VERIFY_ARE_EQUAL(U("abcdefghijklmnopqrstuvwxyz"), ::utility::conversions::to_string_t(str_body)); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -} - -TEST_FIXTURE(uri_address, stream_partial_from_start) -{ - utility::string_t fname = U("stream_partial_from_start.txt"); - fill_file(fname, 200); - - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - http_request msg(methods::POST); - auto stream = OPEN_R(fname).get().create_istream(); - msg.set_body(stream); - msg.headers().set_content_length(4500); + stream_request_impl(m_uri, true, 64 * 1024, U("with_content_length_1.txt")); + } - p_server->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, producer_consumer_buffer_with_content_length) { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); - VERIFY_ARE_EQUAL(4500u, p_request->m_body.size()); - std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - - // We should only have read the first 4500 bytes. - auto length = stream.seek(0, std::ios_base::cur); - VERIFY_ARE_EQUAL((size_t)length, (size_t)4500); - - stream.close().get(); -} - -TEST_FIXTURE(uri_address, stream_partial_from_middle) -{ - utility::string_t fname = U("stream_partial_from_middle.txt"); - fill_file(fname,100); - - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - http_request msg(methods::POST); - auto stream = OPEN_R(fname).get().create_istream(); - msg.set_body(stream); - msg.headers().set_content_length(13); - - stream.seek(13, std::ios_base::cur); + streams::producer_consumer_buffer rbuf; + fill_buffer(rbuf); + rbuf.close(std::ios_base::out); + + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + http_request msg(methods::POST); + msg.set_body(streams::istream(rbuf)); + msg.headers().set_content_length(26); + + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); + VERIFY_ARE_EQUAL(26u, p_request->m_body.size()); + std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); + VERIFY_ARE_EQUAL(U("abcdefghijklmnopqrstuvwxyz"), ::utility::conversions::to_string_t(str_body)); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } - p_server->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, stream_partial_from_start) { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); - VERIFY_ARE_EQUAL(13u, p_request->m_body.size()); - std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); - VERIFY_ARE_EQUAL(str_body, "nopqrstuvwxyz"); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - - // We should only have read the first 26 bytes. - auto length = stream.seek(0, std::ios_base::cur); - VERIFY_ARE_EQUAL((int)length, 26); - - stream.close().get(); -} + utility::string_t fname = U("stream_partial_from_start.txt"); + fill_file(fname, 200); + + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + http_request msg(methods::POST); + auto stream = OPEN_R(fname).get().create_istream(); + msg.set_body(stream); + msg.headers().set_content_length(4500); + + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); + VERIFY_ARE_EQUAL(4500u, p_request->m_body.size()); + std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + + // We should only have read the first 4500 bytes. + auto length = stream.seek(0, std::ios_base::cur); + VERIFY_ARE_EQUAL((size_t)length, (size_t)4500); + + stream.close().get(); + } -class test_exception : public std::exception -{ -public: - test_exception() + TEST_FIXTURE(uri_address, stream_partial_from_middle) { + utility::string_t fname = U("stream_partial_from_middle.txt"); + fill_file(fname, 100); + + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + http_request msg(methods::POST); + auto stream = OPEN_R(fname).get().create_istream(); + msg.set_body(stream); + msg.headers().set_content_length(13); + + stream.seek(13, std::ios_base::cur); + + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); + VERIFY_ARE_EQUAL(13u, p_request->m_body.size()); + std::string str_body(std::begin(p_request->m_body), std::end(p_request->m_body)); + VERIFY_ARE_EQUAL(str_body, "nopqrstuvwxyz"); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + + // We should only have read the first 26 bytes. + auto length = stream.seek(0, std::ios_base::cur); + VERIFY_ARE_EQUAL((int)length, 26); + + stream.close().get(); } -}; + + class test_exception : public std::exception + { + public: + test_exception() {} + }; // Ignore on WinRT CodePlex 144 #if !defined(__cplusplus_winrt) -TEST_FIXTURE(uri_address, set_body_stream_exception) -{ - test_http_server::scoped_server scoped(m_uri); - scoped.server(); - http_client client(m_uri); + TEST_FIXTURE(uri_address, set_body_stream_exception) + { + test_http_server::scoped_server scoped(m_uri); + scoped.server(); + http_client client(m_uri); - streams::producer_consumer_buffer buf; - const char *data = "abcdefghijklmnopqrstuvwxyz"; - buf.putn_nocopy(reinterpret_cast(data), 26).wait(); + streams::producer_consumer_buffer buf; + const char* data = "abcdefghijklmnopqrstuvwxyz"; + buf.putn_nocopy(reinterpret_cast(data), 26).wait(); - http_request msg(methods::POST); - msg.set_body(buf.create_istream()); - msg.headers().set_content_length(26); + http_request msg(methods::POST); + msg.set_body(buf.create_istream()); + msg.headers().set_content_length(26); - buf.close(std::ios::in, std::make_exception_ptr(test_exception())).wait(); + buf.close(std::ios::in, std::make_exception_ptr(test_exception())).wait(); - VERIFY_THROWS(client.request(msg).get(), test_exception); + VERIFY_THROWS(client.request(msg).get(), test_exception); - // Codeplex 328. + // Codeplex 328. #if !defined(_WIN32) - tests::common::utilities::os_utilities::sleep(1000); + tests::common::utilities::os_utilities::sleep(1000); #endif -} + } #endif // These tests aren't possible on WinRT because they don't // specify a Content-Length. #if !defined(__cplusplus_winrt) -TEST_FIXTURE(uri_address, stream_close_early) -{ - http_client client(m_uri); - test_http_server::scoped_server scoped(m_uri); - scoped.server()->next_request().then([](test_request *request) + TEST_FIXTURE(uri_address, stream_close_early) { - request->reply(status_codes::OK); - }); + http_client client(m_uri); + test_http_server::scoped_server scoped(m_uri); + scoped.server()->next_request().then([](test_request* request) { request->reply(status_codes::OK); }); - // Make request. - streams::producer_consumer_buffer buf; - auto responseTask = client.request(methods::PUT, U(""), buf.create_istream()); + // Make request. + streams::producer_consumer_buffer buf; + auto responseTask = client.request(methods::PUT, U(""), buf.create_istream()); - // Write a bit of data then close the stream early. - unsigned char data[5] = { '1', '2', '3', '4', '5' }; - buf.putn_nocopy(&data[0], 5).wait(); + // Write a bit of data then close the stream early. + unsigned char data[5] = {'1', '2', '3', '4', '5'}; + buf.putn_nocopy(&data[0], 5).wait(); - buf.close(std::ios::out).wait(); + buf.close(std::ios::out).wait(); - // Verify that the task completes successfully - http_asserts::assert_response_equals(responseTask.get(), status_codes::OK); -} + // Verify that the task completes successfully + http_asserts::assert_response_equals(responseTask.get(), status_codes::OK); + } -TEST_FIXTURE(uri_address, stream_close_early_with_exception) -{ - http_client client(m_uri); - test_http_server::scoped_server scoped(m_uri); + TEST_FIXTURE(uri_address, stream_close_early_with_exception) + { + http_client client(m_uri); + test_http_server::scoped_server scoped(m_uri); - // Make request. - streams::producer_consumer_buffer buf; - auto responseTask = client.request(methods::PUT, U(""), buf.create_istream()); + // Make request. + streams::producer_consumer_buffer buf; + auto responseTask = client.request(methods::PUT, U(""), buf.create_istream()); - // Write a bit of data then close the stream early. - unsigned char data[5] = { '1', '2', '3', '4', '5' }; - buf.putn_nocopy(&data[0], 5).wait(); + // Write a bit of data then close the stream early. + unsigned char data[5] = {'1', '2', '3', '4', '5'}; + buf.putn_nocopy(&data[0], 5).wait(); - buf.close(std::ios::out, std::make_exception_ptr(test_exception())).wait(); + buf.close(std::ios::out, std::make_exception_ptr(test_exception())).wait(); - // Verify that the responseTask throws the exception set when closing the stream - VERIFY_THROWS(responseTask.get(), test_exception); + // Verify that the responseTask throws the exception set when closing the stream + VERIFY_THROWS(responseTask.get(), test_exception); - // Codeplex 328. + // Codeplex 328. #if !defined(_WIN32) - tests::common::utilities::os_utilities::sleep(1000); + tests::common::utilities::os_utilities::sleep(1000); #endif -} + } #endif - // Ignore on WinRT only CodePlex 144 + // Ignore on WinRT only CodePlex 144 #if !defined(__cplusplus_winrt) -TEST_FIXTURE(uri_address, stream_close_early_with_exception_and_contentlength) -{ - http_client client(m_uri); - test_http_server::scoped_server scoped(m_uri); + TEST_FIXTURE(uri_address, stream_close_early_with_exception_and_contentlength) + { + http_client client(m_uri); + test_http_server::scoped_server scoped(m_uri); - // Make request. - streams::producer_consumer_buffer buf; - auto responseTask = client.request(methods::PUT, U(""), buf.create_istream(), 10); + // Make request. + streams::producer_consumer_buffer buf; + auto responseTask = client.request(methods::PUT, U(""), buf.create_istream(), 10); - // Write a bit of data then close the stream early. - unsigned char data[5] = { '1', '2', '3', '4', '5' }; - buf.putn_nocopy(&data[0], 5).wait(); + // Write a bit of data then close the stream early. + unsigned char data[5] = {'1', '2', '3', '4', '5'}; + buf.putn_nocopy(&data[0], 5).wait(); - buf.close(std::ios::out, std::make_exception_ptr(test_exception())).wait(); + buf.close(std::ios::out, std::make_exception_ptr(test_exception())).wait(); - // Verify that the responseTask throws the exception set when closing the stream - VERIFY_THROWS(responseTask.get(), test_exception); + // Verify that the responseTask throws the exception set when closing the stream + VERIFY_THROWS(responseTask.get(), test_exception); - // Codeplex 328. + // Codeplex 328. #if !defined(_WIN32) - tests::common::utilities::os_utilities::sleep(1000); + tests::common::utilities::os_utilities::sleep(1000); #endif -} + } #endif // Ignore on WinRT only CodePlex 144 #if !defined(__cplusplus_winrt) -TEST_FIXTURE(uri_address, stream_close_early_with_contentlength, "Ignore:Apple", "328") -{ - http_client client(m_uri); - test_http_server::scoped_server scoped(m_uri); + TEST_FIXTURE(uri_address, stream_close_early_with_contentlength, "Ignore:Apple", "328") + { + http_client client(m_uri); + test_http_server::scoped_server scoped(m_uri); - // Make request. - streams::producer_consumer_buffer buf; - auto responseTask = client.request(methods::PUT, U(""), buf.create_istream(), 10); + // Make request. + streams::producer_consumer_buffer buf; + auto responseTask = client.request(methods::PUT, U(""), buf.create_istream(), 10); - // Write a bit of data then close the stream early. - unsigned char data[5] = { '1', '2', '3', '4', '5' }; - buf.putn_nocopy(&data[0], 5).wait(); + // Write a bit of data then close the stream early. + unsigned char data[5] = {'1', '2', '3', '4', '5'}; + buf.putn_nocopy(&data[0], 5).wait(); - buf.close(std::ios::out).wait(); + buf.close(std::ios::out).wait(); - // Verify that the responseTask throws the exception set when closing the stream - VERIFY_THROWS(responseTask.get(), http_exception); + // Verify that the responseTask throws the exception set when closing the stream + VERIFY_THROWS(responseTask.get(), http_exception); - // Codeplex 328. + // Codeplex 328. #if !defined(_WIN32) - tests::common::utilities::os_utilities::sleep(1000); + tests::common::utilities::os_utilities::sleep(1000); #endif -} + } #endif -TEST_FIXTURE(uri_address, get_with_body_nono) -{ - http_client client(m_uri); + TEST_FIXTURE(uri_address, get_with_body_nono) + { + http_client client(m_uri); - streams::producer_consumer_buffer buf; + streams::producer_consumer_buffer buf; - http_request reqG(methods::GET); - reqG.set_body(buf.create_istream()); - VERIFY_THROWS(client.request(reqG).get(), http_exception); + http_request reqG(methods::GET); + reqG.set_body(buf.create_istream()); + VERIFY_THROWS(client.request(reqG).get(), http_exception); - http_request reqH(methods::HEAD); - reqH.set_body(buf.create_istream()); - VERIFY_THROWS(client.request(reqH).get(), http_exception); -} + http_request reqH(methods::HEAD); + reqH.set_body(buf.create_istream()); + VERIFY_THROWS(client.request(reqH).get(), http_exception); + } } // SUITE(request_stream_tests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/request_uri_tests.cpp b/Release/tests/functional/http/client/request_uri_tests.cpp index 5ac24cb68b..c856b600e3 100644 --- a/Release/tests/functional/http/client/request_uri_tests.cpp +++ b/Release/tests/functional/http/client/request_uri_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* request_uri_tests.cpp -* -* Tests cases covering various kinds of request URIs with http_client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * request_uri_tests.cpp + * + * Tests cases covering various kinds of request URIs with http_client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -18,152 +18,159 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(request_uri_tests) +namespace tests { - -// Tests path specified in requests with non-empty base path in client constructor. -TEST_FIXTURE(uri_address, path_non_empty_ctor) +namespace functional { - uri address(U("http://localhost:45678/base_path/")); - - // Path not starting with '/'. +namespace http +{ +namespace client +{ +SUITE(request_uri_tests) +{ + // Tests path specified in requests with non-empty base path in client constructor. + TEST_FIXTURE(uri_address, path_non_empty_ctor) { - test_http_server::scoped_server scoped(address); - http_client client(address); - test_connection(scoped.server(), &client, U("next_level"), U("/base_path/next_level")); + uri address(U("http://localhost:45678/base_path/")); + + // Path not starting with '/'. + { + test_http_server::scoped_server scoped(address); + http_client client(address); + test_connection(scoped.server(), &client, U("next_level"), U("/base_path/next_level")); + } + + // Path starting with '/'. + { + test_http_server::scoped_server scoped(address); + http_client client(address); + test_connection(scoped.server(), &client, U("/next_level"), U("/base_path/next_level")); + } } - // Path starting with '/'. + // Tests path specified in requests with empty base path in client constructor. + TEST_FIXTURE(uri_address, path_empty_ctor) { - test_http_server::scoped_server scoped(address); - http_client client(address); - test_connection(scoped.server(), &client, U("/next_level"), U("/base_path/next_level")); - } -} + uri address(U("http://localhost:45678")); -// Tests path specified in requests with empty base path in client constructor. -TEST_FIXTURE(uri_address, path_empty_ctor) -{ - uri address(U("http://localhost:45678")); + // NON empty path. + { + test_http_server::scoped_server scoped(address); + http_client client(address); + test_connection(scoped.server(), &client, U("next_level"), U("/next_level")); + } - // NON empty path. - { - test_http_server::scoped_server scoped(address); - http_client client(address); - test_connection(scoped.server(), &client, U("next_level"), U("/next_level")); - } + // Request path of '*' + { + test_http_server::scoped_server scoped(address); + http_client client(address); + test_connection(scoped.server(), &client, U("*"), U("/*")); + } - // Request path of '*' - { - test_http_server::scoped_server scoped(address); - http_client client(address); - test_connection(scoped.server(), &client, U("*"), U("/*")); + // Empty base of '/' with request path starting with '/'. + address = uri(U("http://localhost:45678/")); + { + test_http_server::scoped_server scoped(address); + http_client client(address); + test_connection(scoped.server(), &client, U("/hehehe"), U("/hehehe")); + } } - // Empty base of '/' with request path starting with '/'. - address = uri(U("http://localhost:45678/")); + TEST_FIXTURE(uri_address, with_query_fragment) { - test_http_server::scoped_server scoped(address); - http_client client(address); - test_connection(scoped.server(), &client, U("/hehehe"), U("/hehehe")); - } -} - -TEST_FIXTURE(uri_address, with_query_fragment) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); - // query - test_connection(scoped.server(), &client, U("/hehehe?key1=value2&"), U("/hehehe?key1=value2&")); + // query + test_connection(scoped.server(), &client, U("/hehehe?key1=value2&"), U("/hehehe?key1=value2&")); - // fragment + // fragment - // WinRT implementation percent encodes the '#'. - utility::string_t expected_value = U("/heheh?key1=value2#fragment"); + // WinRT implementation percent encodes the '#'. + utility::string_t expected_value = U("/heheh?key1=value2#fragment"); #ifdef __cplusplus_winrt - expected_value = percent_encode_pound(expected_value); + expected_value = percent_encode_pound(expected_value); #endif - test_connection(scoped.server(), &client, U("/heheh?key1=value2#fragment"), expected_value); -} + test_connection(scoped.server(), &client, U("/heheh?key1=value2#fragment"), expected_value); + } -TEST_FIXTURE(uri_address, uri_encoding) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - // try with encoding string. - http_request msg(methods::GET); - msg.set_request_uri(U("/path1!!alreadyencoded")); - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::GET, U("/path1!!alreadyencoded")); - http_asserts::assert_test_request_contains_headers(p_request, msg.headers()); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - - // verify encoding actual happens with plain. - msg = http_request(methods::GET); - msg.set_request_uri(web::http::uri::encode_uri(U("/path1 /encode"))); - VERIFY_ARE_EQUAL(U("/path1%20/encode"), msg.relative_uri().to_string()); - p_server->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::GET, U("/path1%20/encode")); - http_asserts::assert_test_request_contains_headers(p_request, msg.headers()); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); -} - -// Tests combining case URI query/fragments with relative URI query/fragments. -TEST_FIXTURE(uri_address, append_query_fragment) -{ - // Try with query. - const utility::string_t base_uri_with_query = web::http::uri_builder(m_uri).append(U("/path1?key1=value1")).to_string(); + TEST_FIXTURE(uri_address, uri_encoding) { test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(base_uri_with_query); - - p_server->next_request().then([&](test_request *p_request) - { - // WinRT implementation percent encodes the '#'. - utility::string_t expected_value = U("/path1?key1=value1&key2=value2#frag"); -#ifdef __cplusplus_winrt - expected_value = percent_encode_pound(expected_value); -#endif - http_asserts::assert_test_request_equals(p_request, methods::GET, expected_value); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); + + // try with encoding string. + http_request msg(methods::GET); + msg.set_request_uri(U("/path1!!alreadyencoded")); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::GET, U("/path1!!alreadyencoded")); + http_asserts::assert_test_request_contains_headers(p_request, msg.headers()); p_request->reply(200); }); - http_asserts::assert_response_equals(client.request(methods::GET, U("?key2=value2#frag")).get(), status_codes::OK); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + + // verify encoding actual happens with plain. + msg = http_request(methods::GET); + msg.set_request_uri(web::http::uri::encode_uri(U("/path1 /encode"))); + VERIFY_ARE_EQUAL(U("/path1%20/encode"), msg.relative_uri().to_string()); + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, methods::GET, U("/path1%20/encode")); + http_asserts::assert_test_request_contains_headers(p_request, msg.headers()); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); } - // Try with fragment. - const utility::string_t base_uri_with_frag(m_uri.to_string() + U("path1#fragment")); + // Tests combining case URI query/fragments with relative URI query/fragments. + TEST_FIXTURE(uri_address, append_query_fragment) { - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(base_uri_with_frag); - - p_server->next_request().then([&](test_request *p_request) + // Try with query. + const utility::string_t base_uri_with_query = + web::http::uri_builder(m_uri).append(U("/path1?key1=value1")).to_string(); { - // WinRT implementation percent encodes the '#'. - utility::string_t expected_value = U("/path1/path2?key2=value2#fragmentfg2"); + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(base_uri_with_query); + + p_server->next_request().then([&](test_request* p_request) { + // WinRT implementation percent encodes the '#'. + utility::string_t expected_value = U("/path1?key1=value1&key2=value2#frag"); #ifdef __cplusplus_winrt - expected_value = percent_encode_pound(expected_value); + expected_value = percent_encode_pound(expected_value); #endif - http_asserts::assert_test_request_equals(p_request, methods::GET, expected_value); - p_request->reply(200); - }); - http_asserts::assert_response_equals(client.request(methods::GET, U("path2?key2=value2#fg2")).get(), status_codes::OK); + http_asserts::assert_test_request_equals(p_request, methods::GET, expected_value); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(methods::GET, U("?key2=value2#frag")).get(), + status_codes::OK); + } + + // Try with fragment. + const utility::string_t base_uri_with_frag(m_uri.to_string() + U("path1#fragment")); + { + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(base_uri_with_frag); + + p_server->next_request().then([&](test_request* p_request) { + // WinRT implementation percent encodes the '#'. + utility::string_t expected_value = U("/path1/path2?key2=value2#fragmentfg2"); +#ifdef __cplusplus_winrt + expected_value = percent_encode_pound(expected_value); +#endif + http_asserts::assert_test_request_equals(p_request, methods::GET, expected_value); + p_request->reply(200); + }); + http_asserts::assert_response_equals(client.request(methods::GET, U("path2?key2=value2#fg2")).get(), + status_codes::OK); + } } -} } // SUITE(request_uri_tests) -}}}} \ No newline at end of file +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/response_extract_tests.cpp b/Release/tests/functional/http/client/response_extract_tests.cpp index d164e08085..f269f62b8a 100644 --- a/Release/tests/functional/http/client/response_extract_tests.cpp +++ b/Release/tests/functional/http/client/response_extract_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* response_extract_tests.cpp -* -* Tests cases covering extract functions on HTTP response. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * response_extract_tests.cpp + * + * Tests cases covering extract functions on HTTP response. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -17,7 +17,7 @@ #include "cpprest/http_listener.h" #endif -using namespace web; +using namespace web; using namespace utility; using namespace concurrency; using namespace utility::conversions; @@ -26,514 +26,521 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(response_extract_tests) +namespace tests { - -// Helper function to send a request and response with given values. -template -static http_response send_request_response( - test_http_server *p_server, - http_client * p_client, - const utility::string_t&content_type, - const std::basic_string &data) +namespace functional +{ +namespace http +{ +namespace client +{ +SUITE(response_extract_tests) { - const method method = methods::GET; - const ::http::status_code code = status_codes::OK; - std::map headers; - if(!content_type.empty()) + // Helper function to send a request and response with given values. + template + static http_response send_request_response(test_http_server * p_server, + http_client * p_client, + const utility::string_t& content_type, + const std::basic_string& data) { - headers[U("Content-Type")] = content_type; + const method method = methods::GET; + const ::http::status_code code = status_codes::OK; + std::map headers; + if (!content_type.empty()) + { + headers[U("Content-Type")] = content_type; + } + p_server->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, method, U("/")); + VERIFY_ARE_EQUAL(0u, p_request->reply(code, U(""), headers, data)); + }); + http_response rsp = p_client->request(method).get(); + http_asserts::assert_response_equals(rsp, code, headers); + return rsp; } - p_server->next_request().then([&](test_request *p_request) + + utf16string switch_endian_ness(const utf16string& src_str) { - http_asserts::assert_test_request_equals(p_request, method, U("/")); - VERIFY_ARE_EQUAL(0u, p_request->reply(code, U(""), headers, data)); - }); - http_response rsp = p_client->request(method).get(); - http_asserts::assert_response_equals(rsp, code, headers); - return rsp; -} - -utf16string switch_endian_ness(const utf16string &src_str) -{ - utf16string dest_str; - dest_str.resize(src_str.size()); - unsigned char *src = (unsigned char *)&src_str[0]; - unsigned char *dest = (unsigned char *)&dest_str[0]; - for(size_t i = 0; i < dest_str.size() * 2; i+=2) + utf16string dest_str; + dest_str.resize(src_str.size()); + unsigned char* src = (unsigned char*)&src_str[0]; + unsigned char* dest = (unsigned char*)&dest_str[0]; + for (size_t i = 0; i < dest_str.size() * 2; i += 2) + { + dest[i] = src[i + 1]; + dest[i + 1] = src[i]; + } + return dest_str; + } + + TEST_FIXTURE(uri_address, extract_string) { - dest[i] = src[i + 1]; - dest[i + 1] = src[i]; + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + // default encoding (Latin1) + std::string data("YOU KNOW ITITITITI"); + http_response rsp = send_request_response(scoped.server(), &client, U("text/plain"), data); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); + + // us-ascii + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset= us-AscIi"), data); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); + + // Latin1 + rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=iso-8859-1"), data); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); + + // utf-8 + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset = UTF-8"), data); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); + + // "utf-8" - quoted charset + rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=\"utf-8\""), data); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); + + // no content length + rsp = send_request_response(scoped.server(), &client, U(""), utility::string_t()); + auto str = rsp.to_string(); + // If there is no Content-Type in the response, make sure it won't throw when we ask for string + if (str.find(U("Content-Type")) == std::string::npos) + { + VERIFY_ARE_EQUAL(utility::string_t(U("")), rsp.extract_string().get()); + } + + // utf-16le + data = "YES NOW, HERHEHE****"; + utf16string wdata(utf8_to_utf16(data)); + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16le"), wdata); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); + + // utf-16be + wdata = switch_endian_ness(wdata); + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16be"), wdata); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); + + // utf-16 no BOM (utf-16be) + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); + + // utf-16 big endian BOM. + wdata.insert(wdata.begin(), ('\0')); + unsigned char* start = (unsigned char*)&wdata[0]; + start[0] = 0xFE; + start[1] = 0xFF; + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); + + // utf-16 little endian BOM. + wdata = utf8_to_utf16("YOU KNOW THIS **********KICKS"); + data = utf16_to_utf8(wdata); + wdata.insert(wdata.begin(), '\0'); + start = (unsigned char*)&wdata[0]; + start[0] = 0xFF; + start[1] = 0xFE; + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); } - return dest_str; -} -TEST_FIXTURE(uri_address, extract_string) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - // default encoding (Latin1) - std::string data("YOU KNOW ITITITITI"); - http_response rsp = send_request_response(scoped.server(), &client, U("text/plain"), data); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); - - // us-ascii - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset= us-AscIi"), data); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); - - // Latin1 - rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=iso-8859-1"), data); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); - - // utf-8 - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset = UTF-8"), data); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); - - // "utf-8" - quoted charset - rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=\"utf-8\""), data); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); - - // no content length - rsp = send_request_response(scoped.server(), &client, U(""), utility::string_t()); - auto str = rsp.to_string(); - // If there is no Content-Type in the response, make sure it won't throw when we ask for string - if(str.find(U("Content-Type")) == std::string::npos) + TEST_FIXTURE(uri_address, extract_utf8string) { - VERIFY_ARE_EQUAL(utility::string_t(U("")), rsp.extract_string().get()); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + // default encoding (Latin1) + std::string data("YOU KNOW ITITITITI"); + http_response rsp = send_request_response(scoped.server(), &client, U("text/plain"), data); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); + + // us-ascii + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset= us-AscIi"), data); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); + + // Latin1 + rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=iso-8859-1"), data); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); + + // utf-8 + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset = UTF-8"), data); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); + + // "utf-8" - quoted charset + rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=\"utf-8\""), data); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); + + // no content length + rsp = send_request_response(scoped.server(), &client, U(""), utility::string_t()); + auto str = rsp.to_string(); + // If there is no Content-Type in the response, make sure it won't throw when we ask for string + if (str.find(U("Content-Type")) == std::string::npos) + { + VERIFY_ARE_EQUAL("", rsp.extract_utf8string().get()); + } + + // utf-16le + data = "YES NOW, HERHEHE****"; + utf16string wdata(utf8_to_utf16(data)); + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16le"), wdata); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); + + // utf-16be + wdata = switch_endian_ness(wdata); + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16be"), wdata); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); + + // utf-16 no BOM (utf-16be) + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); + + // utf-16 big endian BOM. + wdata.insert(wdata.begin(), ('\0')); + unsigned char* start = (unsigned char*)&wdata[0]; + start[0] = 0xFE; + start[1] = 0xFF; + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); + + // utf-16 little endian BOM. + wdata = utf8_to_utf16("YOU KNOW THIS **********KICKS"); + data = utf16_to_utf8(wdata); + wdata.insert(wdata.begin(), '\0'); + start = (unsigned char*)&wdata[0]; + start[0] = 0xFF; + start[1] = 0xFE; + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); } - // utf-16le - data = "YES NOW, HERHEHE****"; - utf16string wdata(utf8_to_utf16(data)); - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16le"), wdata); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); - - // utf-16be - wdata = switch_endian_ness(wdata); - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16be"), wdata); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); - - // utf-16 no BOM (utf-16be) - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); - - // utf-16 big endian BOM. - wdata.insert(wdata.begin(), ('\0')); - unsigned char * start = (unsigned char *)&wdata[0]; - start[0] = 0xFE; - start[1] = 0xFF; - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); - - // utf-16 little endian BOM. - wdata = utf8_to_utf16("YOU KNOW THIS **********KICKS"); - data = utf16_to_utf8(wdata); - wdata.insert(wdata.begin(), '\0'); - start = (unsigned char *)&wdata[0]; - start[0] = 0xFF; - start[1] = 0xFE; - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string().get()); -} - -TEST_FIXTURE(uri_address, extract_utf8string) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - // default encoding (Latin1) - std::string data("YOU KNOW ITITITITI"); - http_response rsp = send_request_response(scoped.server(), &client, U("text/plain"), data); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); - - // us-ascii - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset= us-AscIi"), data); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); - - // Latin1 - rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=iso-8859-1"), data); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); - - // utf-8 - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset = UTF-8"), data); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); - - // "utf-8" - quoted charset - rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=\"utf-8\""), data); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); - - // no content length - rsp = send_request_response(scoped.server(), &client, U(""), utility::string_t()); - auto str = rsp.to_string(); - // If there is no Content-Type in the response, make sure it won't throw when we ask for string - if (str.find(U("Content-Type")) == std::string::npos) + TEST_FIXTURE(uri_address, extract_utf16string) { - VERIFY_ARE_EQUAL("", rsp.extract_utf8string().get()); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + // default encoding (Latin1) + std::string data("YOU KNOW ITITITITI"); + utf16string wdata(utf8_to_utf16(data)); + http_response rsp = send_request_response(scoped.server(), &client, U("text/plain"), data); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); + + // us-ascii + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset= us-AscIi"), data); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); + + // Latin1 + rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=iso-8859-1"), data); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); + + // utf-8 + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset = UTF-8"), data); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); + + // "utf-8" - quoted charset + rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=\"utf-8\""), data); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); + + // no content length + rsp = send_request_response(scoped.server(), &client, U(""), utility::string_t()); + auto str = rsp.to_string(); + // If there is no Content-Type in the response, make sure it won't throw when we ask for string + if (str.find(U("Content-Type")) == std::string::npos) + { + VERIFY_ARE_EQUAL(utf16string(), rsp.extract_utf16string().get()); + } + + // utf-16le + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16le"), wdata); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); + + // utf-16be + auto wdatabe = switch_endian_ness(wdata); + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16be"), wdatabe); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); + + // utf-16 no BOM (utf-16be) + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdatabe); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); + + // utf-16 big endian BOM. + wdatabe.insert(wdatabe.begin(), ('\0')); + unsigned char* start = (unsigned char*)&wdatabe[0]; + start[0] = 0xFE; + start[1] = 0xFF; + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdatabe); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); + + // utf-16 little endian BOM. + auto wdatale = wdata; + wdatale.insert(wdatale.begin(), '\0'); + start = (unsigned char*)&wdatale[0]; + start[0] = 0xFF; + start[1] = 0xFE; + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdatale); + VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); } - // utf-16le - data = "YES NOW, HERHEHE****"; - utf16string wdata(utf8_to_utf16(data)); - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16le"), wdata); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); - - // utf-16be - wdata = switch_endian_ness(wdata); - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16be"), wdata); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); - - // utf-16 no BOM (utf-16be) - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); - - // utf-16 big endian BOM. - wdata.insert(wdata.begin(), ('\0')); - unsigned char * start = (unsigned char *) &wdata[0]; - start[0] = 0xFE; - start[1] = 0xFF; - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); - - // utf-16 little endian BOM. - wdata = utf8_to_utf16("YOU KNOW THIS **********KICKS"); - data = utf16_to_utf8(wdata); - wdata.insert(wdata.begin(), '\0'); - start = (unsigned char *) &wdata[0]; - start[0] = 0xFF; - start[1] = 0xFE; - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdata); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string().get()); -} - -TEST_FIXTURE(uri_address, extract_utf16string) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - // default encoding (Latin1) - std::string data("YOU KNOW ITITITITI"); - utf16string wdata(utf8_to_utf16(data)); - http_response rsp = send_request_response(scoped.server(), &client, U("text/plain"), data); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); - - // us-ascii - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset= us-AscIi"), data); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); - - // Latin1 - rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=iso-8859-1"), data); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); - - // utf-8 - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset = UTF-8"), data); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); - - // "utf-8" - quoted charset - rsp = send_request_response(scoped.server(), &client, U("text/plain;charset=\"utf-8\""), data); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); - - // no content length - rsp = send_request_response(scoped.server(), &client, U(""), utility::string_t()); - auto str = rsp.to_string(); - // If there is no Content-Type in the response, make sure it won't throw when we ask for string - if (str.find(U("Content-Type")) == std::string::npos) + TEST_FIXTURE(uri_address, extract_string_force) { - VERIFY_ARE_EQUAL(utf16string(), rsp.extract_utf16string().get()); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + std::string data("YOU KNOW ITITITITI"); + http_response rsp = send_request_response(scoped.server(), &client, U("bad unknown charset"), data); + VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string(true).get()); + rsp = send_request_response(scoped.server(), &client, U("bad unknown charset"), data); + VERIFY_ARE_EQUAL(data, rsp.extract_utf8string(true).get()); + rsp = send_request_response(scoped.server(), &client, U("bad unknown charset"), data); + VERIFY_ARE_EQUAL(to_utf16string(data), rsp.extract_utf16string(true).get()); } - // utf-16le - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16le"), wdata); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); - - // utf-16be - auto wdatabe = switch_endian_ness(wdata); - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16be"), wdatabe); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); - - // utf-16 no BOM (utf-16be) - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdatabe); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); - - // utf-16 big endian BOM. - wdatabe.insert(wdatabe.begin(), ('\0')); - unsigned char * start = (unsigned char *) &wdatabe[0]; - start[0] = 0xFE; - start[1] = 0xFF; - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdatabe); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); - - // utf-16 little endian BOM. - auto wdatale = wdata; - wdatale.insert(wdatale.begin(), '\0'); - start = (unsigned char *) &wdatale[0]; - start[0] = 0xFF; - start[1] = 0xFE; - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), wdatale); - VERIFY_ARE_EQUAL(wdata, rsp.extract_utf16string().get()); -} - -TEST_FIXTURE(uri_address, extract_string_force) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - std::string data("YOU KNOW ITITITITI"); - http_response rsp = send_request_response(scoped.server(), &client, U("bad unknown charset"), data); - VERIFY_ARE_EQUAL(to_string_t(data), rsp.extract_string(true).get()); - rsp = send_request_response(scoped.server(), &client, U("bad unknown charset"), data); - VERIFY_ARE_EQUAL(data, rsp.extract_utf8string(true).get()); - rsp = send_request_response(scoped.server(), &client, U("bad unknown charset"), data); - VERIFY_ARE_EQUAL(to_utf16string(data), rsp.extract_utf16string(true).get()); -} - -TEST_FIXTURE(uri_address, extract_string_incorrect) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); + TEST_FIXTURE(uri_address, extract_string_incorrect) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); - // with non matching content type. - const std::string data("YOU KNOW ITITITITI"); - http_response rsp = send_request_response(scoped.server(), &client, U("non_text"), data); - VERIFY_THROWS(rsp.extract_string().get(), http_exception); + // with non matching content type. + const std::string data("YOU KNOW ITITITITI"); + http_response rsp = send_request_response(scoped.server(), &client, U("non_text"), data); + VERIFY_THROWS(rsp.extract_string().get(), http_exception); - // with unknown charset - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=uis-ascii"), data); - VERIFY_THROWS(rsp.extract_string().get(), http_exception); -} + // with unknown charset + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=uis-ascii"), data); + VERIFY_THROWS(rsp.extract_string().get(), http_exception); + } #ifndef __cplusplus_winrt -TEST_FIXTURE(uri_address, extract_empty_string) -{ - web::http::experimental::listener::http_listener listener(m_uri); - http_client client(m_uri); - listener.support([](http_request msg) + TEST_FIXTURE(uri_address, extract_empty_string) { - auto ResponseStreamBuf = streams::producer_consumer_buffer(); - ResponseStreamBuf.close(std::ios_base::out).wait(); - http_response response(status_codes::OK); - response.set_body(ResponseStreamBuf.create_istream(), U("text/plain")); - response.headers().add(header_names::connection, U("close")); - msg.reply(response).wait(); - }); - - listener.open().wait(); - - auto response = client.request(methods::GET).get(); - auto data = response.extract_string().get(); - - VERIFY_ARE_EQUAL(0, data.size()); - listener.close().wait(); -} + web::http::experimental::listener::http_listener listener(m_uri); + http_client client(m_uri); + listener.support([](http_request msg) { + auto ResponseStreamBuf = streams::producer_consumer_buffer(); + ResponseStreamBuf.close(std::ios_base::out).wait(); + http_response response(status_codes::OK); + response.set_body(ResponseStreamBuf.create_istream(), U("text/plain")); + response.headers().add(header_names::connection, U("close")); + msg.reply(response).wait(); + }); + + listener.open().wait(); + + auto response = client.request(methods::GET).get(); + auto data = response.extract_string().get(); + + VERIFY_ARE_EQUAL(0, data.size()); + listener.close().wait(); + } #endif -TEST_FIXTURE(uri_address, extract_json) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - // default encoding (Latin1) - json::value data = json::value::string(U("JSON string object")); - http_response rsp = send_request_response(scoped.server(), &client, U("application/json"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - - // us-ascii - rsp = send_request_response(scoped.server(), &client, U("application/json; charset= us-AscIi"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - - // Latin1 - rsp = send_request_response(scoped.server(), &client, U("application/json;charset=iso-8859-1"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - - // utf-8 - rsp = send_request_response(scoped.server(), &client, U("application/json; charset = UTF-8"), to_utf8string((data.serialize()))); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - - rsp = send_request_response(scoped.server(), &client, U(""), utility::string_t()); - auto str = rsp.to_string(); - // If there is no Content-Type in the response, make sure it won't throw when we ask for json - if(str.find(U("Content-Type")) == std::string::npos) + TEST_FIXTURE(uri_address, extract_json) { - VERIFY_ARE_EQUAL(utility::string_t(U("null")), rsp.extract_json().get().serialize()); - } + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + // default encoding (Latin1) + json::value data = json::value::string(U("JSON string object")); + http_response rsp = + send_request_response(scoped.server(), &client, U("application/json"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + + // us-ascii + rsp = send_request_response( + scoped.server(), &client, U("application/json; charset= us-AscIi"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + + // Latin1 + rsp = send_request_response( + scoped.server(), &client, U("application/json;charset=iso-8859-1"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + + // utf-8 + rsp = send_request_response( + scoped.server(), &client, U("application/json; charset = UTF-8"), to_utf8string((data.serialize()))); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + + rsp = send_request_response(scoped.server(), &client, U(""), utility::string_t()); + auto str = rsp.to_string(); + // If there is no Content-Type in the response, make sure it won't throw when we ask for json + if (str.find(U("Content-Type")) == std::string::npos) + { + VERIFY_ARE_EQUAL(utility::string_t(U("null")), rsp.extract_json().get().serialize()); + } #ifdef _WIN32 - // utf-16le - auto utf16str = data.serialize(); - rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16le"), utf16str); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - - // utf-16be - utf16string modified_data = data.serialize(); - modified_data = switch_endian_ness(modified_data); - rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16be"), modified_data); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - - // utf-16 no BOM (utf-16be) - rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16"), modified_data); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - - // utf-16 big endian BOM. - modified_data.insert(modified_data.begin(), U('\0')); - unsigned char * start = (unsigned char *)&modified_data[0]; - start[0] = 0xFE; - start[1] = 0xFF; - rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16"), modified_data); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - - // utf-16 little endian BOM. - modified_data = data.serialize(); - modified_data.insert(modified_data.begin(), U('\0')); - start = (unsigned char *)&modified_data[0]; - start[0] = 0xFF; - start[1] = 0xFE; - rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16"), modified_data); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + // utf-16le + auto utf16str = data.serialize(); + rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16le"), utf16str); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + + // utf-16be + utf16string modified_data = data.serialize(); + modified_data = switch_endian_ness(modified_data); + rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16be"), modified_data); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + + // utf-16 no BOM (utf-16be) + rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16"), modified_data); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + + // utf-16 big endian BOM. + modified_data.insert(modified_data.begin(), U('\0')); + unsigned char* start = (unsigned char*)&modified_data[0]; + start[0] = 0xFE; + start[1] = 0xFF; + rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16"), modified_data); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + + // utf-16 little endian BOM. + modified_data = data.serialize(); + modified_data.insert(modified_data.begin(), U('\0')); + start = (unsigned char*)&modified_data[0]; + start[0] = 0xFF; + start[1] = 0xFE; + rsp = send_request_response(scoped.server(), &client, U("application/json; charset=utf-16"), modified_data); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); #endif - // unofficial JSON MIME types - rsp = send_request_response(scoped.server(), &client, U("text/json"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - rsp = send_request_response(scoped.server(), &client, U("text/x-json"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - rsp = send_request_response(scoped.server(), &client, U("text/javascript"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - rsp = send_request_response(scoped.server(), &client, U("text/x-javascript"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - rsp = send_request_response(scoped.server(), &client, U("application/javascript"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); - rsp = send_request_response(scoped.server(), &client, U("application/x-javascript"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); -} - -TEST_FIXTURE(uri_address, extract_json_force) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - json::value data = json::value::string(U("JSON string object")); - http_response rsp = send_request_response(scoped.server(), &client, U("bad charset"), to_utf8string(data.serialize())); - VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json(true).get().serialize()); -} - -TEST_FIXTURE(uri_address, extract_json_incorrect) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - // with non matching content type. - json::value json_data = json::value::string(U("JSON string object")); - http_response rsp = send_request_response(scoped.server(), &client, U("bad guy"), json_data.serialize()); - VERIFY_THROWS(rsp.extract_json().get(), http_exception); + // unofficial JSON MIME types + rsp = send_request_response(scoped.server(), &client, U("text/json"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + rsp = send_request_response(scoped.server(), &client, U("text/x-json"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + rsp = send_request_response(scoped.server(), &client, U("text/javascript"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + rsp = send_request_response(scoped.server(), &client, U("text/x-javascript"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + rsp = send_request_response( + scoped.server(), &client, U("application/javascript"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + rsp = send_request_response( + scoped.server(), &client, U("application/x-javascript"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json().get().serialize()); + } - // with unknown charset. - rsp = send_request_response(scoped.server(), &client, U("application/json; charset=us-askjhcii"), json_data.serialize()); - VERIFY_THROWS(rsp.extract_json().get(), http_exception); -} + TEST_FIXTURE(uri_address, extract_json_force) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); -TEST_FIXTURE(uri_address, set_stream_try_extract_json) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); + json::value data = json::value::string(U("JSON string object")); + http_response rsp = + send_request_response(scoped.server(), &client, U("bad charset"), to_utf8string(data.serialize())); + VERIFY_ARE_EQUAL(data.serialize(), rsp.extract_json(true).get().serialize()); + } - http_request request(methods::GET); - streams::ostream responseStream = streams::bytestream::open_ostream>(); - request.set_response_stream(responseStream); - scoped.server()->next_request().then([](test_request *req) + TEST_FIXTURE(uri_address, extract_json_incorrect) { - std::map headers; - headers[header_names::content_type] = U("application/json"); - req->reply(status_codes::OK, U("OK"), headers, U("{true}")); - }); - - http_response response = client.request(request).get(); - VERIFY_THROWS(response.extract_json().get(), http_exception); -} - -TEST_FIXTURE(uri_address, extract_vector) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + // with non matching content type. + json::value json_data = json::value::string(U("JSON string object")); + http_response rsp = send_request_response(scoped.server(), &client, U("bad guy"), json_data.serialize()); + VERIFY_THROWS(rsp.extract_json().get(), http_exception); + + // with unknown charset. + rsp = send_request_response( + scoped.server(), &client, U("application/json; charset=us-askjhcii"), json_data.serialize()); + VERIFY_THROWS(rsp.extract_json().get(), http_exception); + } - // textual content type - with unknown charset - std::string data("YOU KNOW ITITITITI"); - std::vector vector_data; - std::for_each(data.begin(), data.end(), [&](char ch) + TEST_FIXTURE(uri_address, set_stream_try_extract_json) { - vector_data.push_back((unsigned char)ch); - }); - http_response rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=unknown"), data); - VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); - - // textual type with us-ascii - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset= us-AscIi"), data); - VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); - - // textual type with Latin1 - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=iso-8859-1"), data); - VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); - - // textual type with utf-8 - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-8"), data); - VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); - - // textual type with utf-16le - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16LE"), data); - VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); - - // textual type with utf-16be - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=UTF-16be"), data); - VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); - - // textual type with utf-16 - rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), data); - VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + http_request request(methods::GET); + streams::ostream responseStream = streams::bytestream::open_ostream>(); + request.set_response_stream(responseStream); + scoped.server()->next_request().then([](test_request* req) { + std::map headers; + headers[header_names::content_type] = U("application/json"); + req->reply(status_codes::OK, U("OK"), headers, U("{true}")); + }); + + http_response response = client.request(request).get(); + VERIFY_THROWS(response.extract_json().get(), http_exception); + } - // non textual content type - rsp = send_request_response(scoped.server(), &client, U("blah; charset=utf-16"), data); - VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); -} + TEST_FIXTURE(uri_address, extract_vector) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + // textual content type - with unknown charset + std::string data("YOU KNOW ITITITITI"); + std::vector vector_data; + std::for_each(data.begin(), data.end(), [&](char ch) { vector_data.push_back((unsigned char)ch); }); + http_response rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=unknown"), data); + VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); + + // textual type with us-ascii + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset= us-AscIi"), data); + VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); + + // textual type with Latin1 + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=iso-8859-1"), data); + VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); + + // textual type with utf-8 + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-8"), data); + VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); + + // textual type with utf-16le + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16LE"), data); + VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); + + // textual type with utf-16be + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=UTF-16be"), data); + VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); + + // textual type with utf-16 + rsp = send_request_response(scoped.server(), &client, U("text/plain; charset=utf-16"), data); + VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); + + // non textual content type + rsp = send_request_response(scoped.server(), &client, U("blah; charset=utf-16"), data); + VERIFY_ARE_EQUAL(vector_data, rsp.extract_vector().get()); + } -TEST_FIXTURE(uri_address, set_stream_try_extract_vector) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); + TEST_FIXTURE(uri_address, set_stream_try_extract_vector) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + http_request request(methods::GET); + streams::ostream responseStream = streams::bytestream::open_ostream>(); + request.set_response_stream(responseStream); + scoped.server()->next_request().then([](test_request* req) { + std::map headers; + headers[header_names::content_type] = U("text/plain"); + req->reply(status_codes::OK, U("OK"), headers, U("data")); + }); + + http_response response = client.request(request).get(); + VERIFY_THROWS(response.extract_vector().get(), http_exception); + } - http_request request(methods::GET); - streams::ostream responseStream = streams::bytestream::open_ostream>(); - request.set_response_stream(responseStream); - scoped.server()->next_request().then([](test_request *req) + TEST_FIXTURE(uri_address, head_response) { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + + const method method = methods::HEAD; + const ::http::status_code code = status_codes::OK; std::map headers; - headers[header_names::content_type] = U("text/plain"); - req->reply(status_codes::OK, U("OK"), headers, U("data")); - }); - - http_response response = client.request(request).get(); - VERIFY_THROWS(response.extract_vector().get(), http_exception); -} - -TEST_FIXTURE(uri_address, head_response) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - - const method method = methods::HEAD; - const ::http::status_code code = status_codes::OK; - std::map headers; - headers[U("Content-Type")] = U("text/plain"); - headers[U("Content-Length")] = U("100"); - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, method, U("/")); - VERIFY_ARE_EQUAL(0u, p_request->reply(code, U(""), headers)); - }); - http_response rsp = client.request(method).get(); - VERIFY_ARE_EQUAL(0u, rsp.body().streambuf().in_avail()); -} + headers[U("Content-Type")] = U("text/plain"); + headers[U("Content-Length")] = U("100"); + scoped.server()->next_request().then([&](test_request* p_request) { + http_asserts::assert_test_request_equals(p_request, method, U("/")); + VERIFY_ARE_EQUAL(0u, p_request->reply(code, U(""), headers)); + }); + http_response rsp = client.request(method).get(); + VERIFY_ARE_EQUAL(0u, rsp.body().streambuf().in_avail()); + } } // SUITE(response_extract_tests) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/response_stream_tests.cpp b/Release/tests/functional/http/client/response_stream_tests.cpp index 04cecb0a05..9806d79d5b 100644 --- a/Release/tests/functional/http/client/response_stream_tests.cpp +++ b/Release/tests/functional/http/client/response_stream_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* response_stream_tests.cpp -* -* Tests cases for covering receiving various responses as a stream with http_client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * response_stream_tests.cpp + * + * Tests cases for covering receiving various responses as a stream with http_client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -29,461 +29,472 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client +{ template -pplx::task> OPENSTR_R(const utility::string_t &name) +pplx::task> OPENSTR_R(const utility::string_t& name) { #if !defined(__cplusplus_winrt) return streams::file_buffer<_CharType>::open(name, std::ios_base::in); #else - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); + auto file = + pplx::create_task(KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); return streams::file_buffer<_CharType>::open(file, std::ios_base::in); #endif } template -pplx::task> OPENSTR_W(const utility::string_t &name, std::ios_base::openmode mode = std::ios_base::out) +pplx::task> OPENSTR_W(const utility::string_t& name, + std::ios_base::openmode mode = std::ios_base::out) { #if !defined(__cplusplus_winrt) return Concurrency::streams::file_stream<_CharType>::open_ostream(name, mode); #else - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->CreateFileAsync( - ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)).get(); + auto file = pplx::create_task(KnownFolders::DocumentsLibrary->CreateFileAsync( + ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)) + .get(); return Concurrency::streams::file_stream<_CharType>::open_ostream(file, mode); #endif } SUITE(response_stream_tests) { - -TEST_FIXTURE(uri_address, set_response_stream_producer_consumer_buffer) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); - - p_server->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, set_response_stream_producer_consumer_buffer) { - std::map headers; - headers[U("Content-Type")] = U("text/plain"); - p_request->reply(200, U(""), headers, "This is just a bit of a string"); - }); + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); - streams::producer_consumer_buffer rwbuf; - auto ostr = streams::ostream(rwbuf); + p_server->next_request().then([&](test_request* p_request) { + std::map headers; + headers[U("Content-Type")] = U("text/plain"); + p_request->reply(200, U(""), headers, "This is just a bit of a string"); + }); - http_request msg(methods::GET); - msg.set_response_stream(ostr); - http_response rsp = client.request(msg).get(); + streams::producer_consumer_buffer rwbuf; + auto ostr = streams::ostream(rwbuf); - rsp.content_ready().get(); - VERIFY_ARE_EQUAL(rwbuf.in_avail(), 30u); + http_request msg(methods::GET); + msg.set_response_stream(ostr); + http_response rsp = client.request(msg).get(); - VERIFY_THROWS(rsp.extract_string().get(), http_exception); + rsp.content_ready().get(); + VERIFY_ARE_EQUAL(rwbuf.in_avail(), 30u); - char chars[128]; - memset(chars, 0, sizeof(chars)); + VERIFY_THROWS(rsp.extract_string().get(), http_exception); - rwbuf.getn((unsigned char *)chars, rwbuf.in_avail()).get(); - VERIFY_ARE_EQUAL(0, strcmp("This is just a bit of a string", chars)); -} + char chars[128]; + memset(chars, 0, sizeof(chars)); -TEST_FIXTURE(uri_address, set_response_stream_container_buffer) -{ - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); + rwbuf.getn((unsigned char*)chars, rwbuf.in_avail()).get(); + VERIFY_ARE_EQUAL(0, strcmp("This is just a bit of a string", chars)); + } - p_server->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, set_response_stream_container_buffer) { - std::map headers; - headers[U("Content-Type")] = U("text/plain"); - p_request->reply(200, U(""), headers, "This is just a bit of a string"); - }); + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); - { - streams::container_buffer> buf; + p_server->next_request().then([&](test_request* p_request) { + std::map headers; + headers[U("Content-Type")] = U("text/plain"); + p_request->reply(200, U(""), headers, "This is just a bit of a string"); + }); - http_request msg(methods::GET); - msg.set_response_stream(buf.create_ostream()); - http_response rsp = client.request(msg).get(); + { + streams::container_buffer> buf; - rsp.content_ready().get(); - VERIFY_ARE_EQUAL(buf.collection().size(), 30); + http_request msg(methods::GET); + msg.set_response_stream(buf.create_ostream()); + http_response rsp = client.request(msg).get(); - char bufStr[31]; - memset(bufStr, 0, sizeof(bufStr)); - memcpy(&bufStr[0], &(buf.collection())[0], 30); - VERIFY_ARE_EQUAL(bufStr, "This is just a bit of a string"); + rsp.content_ready().get(); + VERIFY_ARE_EQUAL(buf.collection().size(), 30); - VERIFY_THROWS(rsp.extract_string().get(), http_exception); + char bufStr[31]; + memset(bufStr, 0, sizeof(bufStr)); + memcpy(&bufStr[0], &(buf.collection())[0], 30); + VERIFY_ARE_EQUAL(bufStr, "This is just a bit of a string"); + + VERIFY_THROWS(rsp.extract_string().get(), http_exception); + } } -} -TEST_FIXTURE(uri_address, response_stream_file_stream) -{ - std::string message = "A world without string is chaos."; + TEST_FIXTURE(uri_address, response_stream_file_stream) + { + std::string message = "A world without string is chaos."; - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - http_client client(m_uri); + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + http_client client(m_uri); - p_server->next_request().then([&](test_request *p_request) - { - std::map headers; - headers[U("Content-Type")] = U("text/plain"); - p_request->reply(200, U(""), headers, message); - }); + p_server->next_request().then([&](test_request* p_request) { + std::map headers; + headers[U("Content-Type")] = U("text/plain"); + p_request->reply(200, U(""), headers, message); + }); - { - auto fstream = OPENSTR_W(U("response_stream.txt")).get(); + { + auto fstream = OPENSTR_W(U("response_stream.txt")).get(); - // Write the response into the file - http_request msg(methods::GET); - msg.set_response_stream(fstream); - http_response rsp = client.request(msg).get(); + // Write the response into the file + http_request msg(methods::GET); + msg.set_response_stream(fstream); + http_response rsp = client.request(msg).get(); - rsp.content_ready().get(); - VERIFY_IS_TRUE(fstream.streambuf().is_open()); - fstream.close().get(); + rsp.content_ready().get(); + VERIFY_IS_TRUE(fstream.streambuf().is_open()); + fstream.close().get(); - char chars[128]; - memset(chars,0,sizeof(chars)); + char chars[128]; + memset(chars, 0, sizeof(chars)); - streams::rawptr_buffer buffer(reinterpret_cast(chars), sizeof(chars)); + streams::rawptr_buffer buffer(reinterpret_cast(chars), sizeof(chars)); - streams::basic_istream fistream = OPENSTR_R(U("response_stream.txt")).get(); - VERIFY_ARE_EQUAL(message.length(), fistream.read_line(buffer).get()); - VERIFY_ARE_EQUAL(message, std::string(chars)); - fistream.close().get(); + streams::basic_istream fistream = OPENSTR_R(U("response_stream.txt")).get(); + VERIFY_ARE_EQUAL(message.length(), fistream.read_line(buffer).get()); + VERIFY_ARE_EQUAL(message, std::string(chars)); + fistream.close().get(); + } } -} - -TEST_FIXTURE(uri_address, response_stream_file_stream_close_early) -{ - // The test needs to be a little different between desktop and WinRT. - // In the latter case, the server will not see a message, and so the - // test will hang. In order to prevent that from happening, we will - // not have a server listening on WinRT. -#if !defined(__cplusplus_winrt) - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); - p_server->next_request().then([&](test_request *p_request) + TEST_FIXTURE(uri_address, response_stream_file_stream_close_early) { - std::map headers; - headers[U("Content-Type")] = U("text/plain"); - p_request->reply(200, U(""), headers, "A world without string is chaos."); - }); + // The test needs to be a little different between desktop and WinRT. + // In the latter case, the server will not see a message, and so the + // test will hang. In order to prevent that from happening, we will + // not have a server listening on WinRT. +#if !defined(__cplusplus_winrt) + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); + + p_server->next_request().then([&](test_request* p_request) { + std::map headers; + headers[U("Content-Type")] = U("text/plain"); + p_request->reply(200, U(""), headers, "A world without string is chaos."); + }); #endif - auto fstream = OPENSTR_W(U("response_stream_file_stream_close_early.txt")).get(); + auto fstream = OPENSTR_W(U("response_stream_file_stream_close_early.txt")).get(); - http_client client(m_uri); + http_client client(m_uri); - http_request msg(methods::GET); - msg.set_response_stream(fstream); - fstream.close(std::make_exception_ptr(std::exception())).wait(); + http_request msg(methods::GET); + msg.set_response_stream(fstream); + fstream.close(std::make_exception_ptr(std::exception())).wait(); - http_response resp; + http_response resp; - VERIFY_THROWS((resp = client.request(msg).get(), resp.content_ready().get()), std::exception); -} + VERIFY_THROWS((resp = client.request(msg).get(), resp.content_ready().get()), std::exception); + } -TEST_FIXTURE(uri_address, response_stream_large_file_stream) -{ - // Send a 100 KB data in the response body, the server will send this in multiple chunks - // This data will get sent with content-length - const size_t workload_size = 100 * 1024; - utility::string_t fname(U("response_stream_large_file_stream.txt")); - std::string responseData; - responseData.resize(workload_size, 'a'); + TEST_FIXTURE(uri_address, response_stream_large_file_stream) + { + // Send a 100 KB data in the response body, the server will send this in multiple chunks + // This data will get sent with content-length + const size_t workload_size = 100 * 1024; + utility::string_t fname(U("response_stream_large_file_stream.txt")); + std::string responseData; + responseData.resize(workload_size, 'a'); - test_http_server::scoped_server scoped(m_uri); - test_http_server * p_server = scoped.server(); + test_http_server::scoped_server scoped(m_uri); + test_http_server* p_server = scoped.server(); - http_client client(m_uri); + http_client client(m_uri); - p_server->next_request().then([&](test_request *p_request) - { - std::map headers; - headers[U("Content-Type")] = U("text/plain"); + p_server->next_request().then([&](test_request* p_request) { + std::map headers; + headers[U("Content-Type")] = U("text/plain"); - p_request->reply(200, U(""), headers, responseData); - }); + p_request->reply(200, U(""), headers, responseData); + }); - { - auto fstream = OPENSTR_W(fname).get(); + { + auto fstream = OPENSTR_W(fname).get(); - http_request msg(methods::GET); - msg.set_response_stream(fstream); - http_response rsp = client.request(msg).get(); + http_request msg(methods::GET); + msg.set_response_stream(fstream); + http_response rsp = client.request(msg).get(); - rsp.content_ready().get(); - VERIFY_IS_TRUE(fstream.streambuf().is_open()); - fstream.close().get(); + rsp.content_ready().get(); + VERIFY_IS_TRUE(fstream.streambuf().is_open()); + fstream.close().get(); - std::string rsp_string; - rsp_string.resize(workload_size, 0); - streams::rawptr_buffer buffer(&rsp_string[0], rsp_string.size()); - streams::basic_istream fistream = OPENSTR_R(fname).get(); + std::string rsp_string; + rsp_string.resize(workload_size, 0); + streams::rawptr_buffer buffer(&rsp_string[0], rsp_string.size()); + streams::basic_istream fistream = OPENSTR_R(fname).get(); - VERIFY_ARE_EQUAL(fistream.read_to_end(buffer).get(), workload_size); - VERIFY_ARE_EQUAL(rsp_string, responseData); - fistream.close().get(); + VERIFY_ARE_EQUAL(fistream.read_to_end(buffer).get(), workload_size); + VERIFY_ARE_EQUAL(rsp_string, responseData); + fistream.close().get(); + } } -} #if !defined(__cplusplus_winrt) -template -class basic_throws_buffer : public streams::details::streambuf_state_manager -{ -public: - basic_throws_buffer() : streams::details::streambuf_state_manager(std::ios_base::out) {} - - typedef typename streams::details::basic_streambuf::int_type int_type; - typedef typename streams::details::basic_streambuf::pos_type pos_type; - typedef typename streams::details::basic_streambuf::off_type off_type; - - bool can_seek() const override { return true; } - bool has_size() const override { return false; } - size_t buffer_size(std::ios_base::openmode) const override { return 0; } - void set_buffer_size(size_t, std::ios_base::openmode) override {} - size_t in_avail() const override { return 0; } - pos_type getpos(std::ios_base::openmode) const override { return 0; } - pos_type seekpos(pos_type, std::ios_base::openmode) override { return 0; } - pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode) override { return 0; } - bool acquire(_Out_writes_(count) CharType*&, _In_ size_t&) override { return false; } - void release(_Out_writes_(count) CharType *, _In_ size_t) override {} - -protected: - pplx::task _putc(CharType) override { throw std::runtime_error("error"); } - pplx::task _putn(const CharType *, size_t) override { throw std::runtime_error("error"); } - pplx::task _bumpc() override { throw std::runtime_error("error"); } - int_type _sbumpc() override { throw std::runtime_error("error"); } - pplx::task _getc() override { throw std::runtime_error("error"); } - int_type _sgetc() override { throw std::runtime_error("error"); } - pplx::task _nextc() override { throw std::runtime_error("error"); } - pplx::task _ungetc() override { throw std::runtime_error("error"); } - pplx::task _getn(_Out_writes_(count) CharType *, _In_ size_t) override { throw std::runtime_error("error"); } - size_t _scopy(_Out_writes_(count) CharType *, _In_ size_t) override { throw std::runtime_error("error"); } - pplx::task _sync() override { throw std::runtime_error("error"); } - CharType* _alloc(size_t) override { throw std::runtime_error("error"); } - void _commit(size_t) override { throw std::runtime_error("error"); } - - pplx::task _close_write() override + template + class basic_throws_buffer : public streams::details::streambuf_state_manager { - return pplx::task_from_exception(std::invalid_argument("test")); - } -}; - -template -class close_throws_buffer : public streams::streambuf -{ -public: - close_throws_buffer() : streams::streambuf(std::shared_ptr>(new basic_throws_buffer())) {} -}; - -// Tests if an exception occurs and close throws an exception that the close -// one is ignored and doesn't bring down the process. -TEST_FIXTURE(uri_address, response_stream_close_throws_with_exception) -{ - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); - - streams::producer_consumer_buffer buf; + public: + basic_throws_buffer() : streams::details::streambuf_state_manager(std::ios_base::out) {} + + typedef typename streams::details::basic_streambuf::int_type int_type; + typedef typename streams::details::basic_streambuf::pos_type pos_type; + typedef typename streams::details::basic_streambuf::off_type off_type; + + bool can_seek() const override { return true; } + bool has_size() const override { return false; } + size_t buffer_size(std::ios_base::openmode) const override { return 0; } + void set_buffer_size(size_t, std::ios_base::openmode) override {} + size_t in_avail() const override { return 0; } + pos_type getpos(std::ios_base::openmode) const override { return 0; } + pos_type seekpos(pos_type, std::ios_base::openmode) override { return 0; } + pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode) override { return 0; } + bool acquire(_Out_writes_(count) CharType*&, _In_ size_t&) override { return false; } + void release(_Out_writes_(count) CharType*, _In_ size_t) override {} + + protected: + pplx::task _putc(CharType) override { throw std::runtime_error("error"); } + pplx::task _putn(const CharType*, size_t) override { throw std::runtime_error("error"); } + pplx::task _bumpc() override { throw std::runtime_error("error"); } + int_type _sbumpc() override { throw std::runtime_error("error"); } + pplx::task _getc() override { throw std::runtime_error("error"); } + int_type _sgetc() override { throw std::runtime_error("error"); } + pplx::task _nextc() override { throw std::runtime_error("error"); } + pplx::task _ungetc() override { throw std::runtime_error("error"); } + pplx::task _getn(_Out_writes_(count) CharType*, _In_ size_t) override + { + throw std::runtime_error("error"); + } + size_t _scopy(_Out_writes_(count) CharType*, _In_ size_t) override { throw std::runtime_error("error"); } + pplx::task _sync() override { throw std::runtime_error("error"); } + CharType* _alloc(size_t) override { throw std::runtime_error("error"); } + void _commit(size_t) override { throw std::runtime_error("error"); } + + pplx::task _close_write() override + { + return pplx::task_from_exception(std::invalid_argument("test")); + } + }; - listener.support([buf](http_request request) + template + class close_throws_buffer : public streams::streambuf { - http_response response(200); - response.set_body(streams::istream(buf), U("text/plain")); - response.headers().add(header_names::connection, U("close")); - request.reply(response); - }); - - http_client_config config; - config.set_timeout(utility::seconds(1)); - http_client client(m_uri, config); - - close_throws_buffer responseBody; - http_request msg(methods::GET); - msg.set_response_stream(responseBody.create_ostream()); - http_response rsp = client.request(msg).get(); - VERIFY_THROWS(rsp.content_ready().get(), http_exception); - - buf.close(std::ios_base::out).wait(); - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, content_ready) -{ - http_client client(m_uri); - std::string responseData("Hello world"); + public: + close_throws_buffer() + : streams::streambuf( + std::shared_ptr>(new basic_throws_buffer())) + { + } + }; - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); - listener.support([responseData](http_request request) + // Tests if an exception occurs and close throws an exception that the close + // one is ignored and doesn't bring down the process. + TEST_FIXTURE(uri_address, response_stream_close_throws_with_exception) { + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); + streams::producer_consumer_buffer buf; - http_response response(200); - response.set_body(buf.create_istream(), U("text/plain")); - response.headers().add(header_names::connection, U("close")); - request.reply(response); + listener.support([buf](http_request request) { + http_response response(200); + response.set_body(streams::istream(buf), U("text/plain")); + response.headers().add(header_names::connection, U("close")); + request.reply(response); + }); - VERIFY_ARE_EQUAL(buf.putn_nocopy((const uint8_t *)responseData.data(), responseData.size()).get(), responseData.size()); - buf.close(std::ios_base::out).get(); - }); + http_client_config config; + config.set_timeout(utility::seconds(1)); + http_client client(m_uri, config); - { + close_throws_buffer responseBody; http_request msg(methods::GET); - http_response rsp = client.request(msg).get().content_ready().get(); + msg.set_response_stream(responseBody.create_ostream()); + http_response rsp = client.request(msg).get(); + VERIFY_THROWS(rsp.content_ready().get(), http_exception); - auto extract_string_task = rsp.extract_string(); - VERIFY_ARE_EQUAL(extract_string_task.get(), ::utility::conversions::to_string_t(responseData)); - rsp.content_ready().wait(); + buf.close(std::ios_base::out).wait(); + listener.close().wait(); } - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, xfer_chunked_with_length) -{ - http_client client(m_uri); - utility::string_t responseData(U("Hello world")); - - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); - listener.support([responseData](http_request request) + TEST_FIXTURE(uri_address, content_ready) { - http_response response(200); + http_client client(m_uri); + std::string responseData("Hello world"); - // This sets the content_length - response.set_body(responseData); + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); + listener.support([responseData](http_request request) { + streams::producer_consumer_buffer buf; + http_response response(200); + response.set_body(buf.create_istream(), U("text/plain")); + response.headers().add(header_names::connection, U("close")); - // overwrite content_length to 0 - response.headers().add(header_names::content_length, 0); + request.reply(response); - // add chunked transfer encoding - response.headers().add(header_names::transfer_encoding, U("chunked")); + VERIFY_ARE_EQUAL(buf.putn_nocopy((const uint8_t*)responseData.data(), responseData.size()).get(), + responseData.size()); + buf.close(std::ios_base::out).get(); + }); - // add connection=close header, connection SHOULD NOT be considered persistent' after the current request/response is complete - response.headers().add(header_names::connection, U("close")); + { + http_request msg(methods::GET); + http_response rsp = client.request(msg).get().content_ready().get(); + + auto extract_string_task = rsp.extract_string(); + VERIFY_ARE_EQUAL(extract_string_task.get(), ::utility::conversions::to_string_t(responseData)); + rsp.content_ready().wait(); + } - // respond - request.reply(response); - }); + listener.close().wait(); + } + TEST_FIXTURE(uri_address, xfer_chunked_with_length) { - http_request msg(methods::GET); - http_response rsp = client.request(msg).get(); + http_client client(m_uri); + utility::string_t responseData(U("Hello world")); - auto rsp_string = rsp.extract_string().get(); - VERIFY_ARE_EQUAL(rsp_string, responseData); - } + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); + listener.support([responseData](http_request request) { + http_response response(200); - listener.close().wait(); -} + // This sets the content_length + response.set_body(responseData); -TEST_FIXTURE(uri_address, get_resp_stream) -{ - http_client client(m_uri); - std::string responseData("Hello world"); + // overwrite content_length to 0 + response.headers().add(header_names::content_length, 0); - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); - listener.support([responseData](http_request request) - { - streams::producer_consumer_buffer buf; + // add chunked transfer encoding + response.headers().add(header_names::transfer_encoding, U("chunked")); - http_response response(200); - response.set_body(buf.create_istream(), U("text/plain")); - response.headers().add(header_names::connection, U("close")); - request.reply(response); + // add connection=close header, connection SHOULD NOT be considered persistent' after the current + // request/response is complete + response.headers().add(header_names::connection, U("close")); + + // respond + request.reply(response); + }); + + { + http_request msg(methods::GET); + http_response rsp = client.request(msg).get(); - VERIFY_ARE_EQUAL(buf.putn_nocopy((const uint8_t *)responseData.data(), responseData.size()).get(), responseData.size()); - buf.close(std::ios_base::out).get(); - }); + auto rsp_string = rsp.extract_string().get(); + VERIFY_ARE_EQUAL(rsp_string, responseData); + } + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, get_resp_stream) { - http_request msg(methods::GET); - http_response rsp = client.request(msg).get(); + http_client client(m_uri); + std::string responseData("Hello world"); + + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); + listener.support([responseData](http_request request) { + streams::producer_consumer_buffer buf; - streams::stringstreambuf data; + http_response response(200); + response.set_body(buf.create_istream(), U("text/plain")); + response.headers().add(header_names::connection, U("close")); + request.reply(response); - auto t = rsp.body().read_to_delim(data, (uint8_t)(' ')); + VERIFY_ARE_EQUAL(buf.putn_nocopy((const uint8_t*)responseData.data(), responseData.size()).get(), + responseData.size()); + buf.close(std::ios_base::out).get(); + }); - t.then([&data](size_t size) { - VERIFY_ARE_EQUAL(size, 5); - auto s = data.collection(); - VERIFY_ARE_EQUAL(s, std::string("Hello")); - }).wait(); - rsp.content_ready().wait(); - } + http_request msg(methods::GET); + http_response rsp = client.request(msg).get(); - listener.close().wait(); -} + streams::stringstreambuf data; -TEST_FIXTURE(uri_address, xfer_chunked_multiple_chunks) -{ - // With chunked transfer-encoding, send 2 chunks of different sizes in the response - http_client client(m_uri); + auto t = rsp.body().read_to_delim(data, (uint8_t)(' ')); - // Send two chunks, note: second chunk is bigger than the first. - std::string firstChunk("abcdefghijklmnopqrst"); - std::string secondChunk("abcdefghijklmnopqrstuvwxyz"); + t.then([&data](size_t size) { + VERIFY_ARE_EQUAL(size, 5); + auto s = data.collection(); + VERIFY_ARE_EQUAL(s, std::string("Hello")); + }) + .wait(); + rsp.content_ready().wait(); + } + + listener.close().wait(); + } - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); - listener.support([firstChunk, secondChunk](http_request request) + TEST_FIXTURE(uri_address, xfer_chunked_multiple_chunks) { - streams::producer_consumer_buffer buf; + // With chunked transfer-encoding, send 2 chunks of different sizes in the response + http_client client(m_uri); + + // Send two chunks, note: second chunk is bigger than the first. + std::string firstChunk("abcdefghijklmnopqrst"); + std::string secondChunk("abcdefghijklmnopqrstuvwxyz"); + + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); + listener.support([firstChunk, secondChunk](http_request request) { + streams::producer_consumer_buffer buf; + + http_response response(200); + response.set_body(buf.create_istream(), U("text/plain")); + response.headers().add(header_names::connection, U("close")); + request.reply(response); + + VERIFY_ARE_EQUAL(buf.putn_nocopy((const uint8_t*)firstChunk.data(), firstChunk.size()).get(), + firstChunk.size()); + buf.sync().get(); + VERIFY_ARE_EQUAL(buf.putn_nocopy((const uint8_t*)secondChunk.data(), secondChunk.size()).get(), + secondChunk.size()); + buf.close(std::ios_base::out).get(); + }); - http_response response(200); - response.set_body(buf.create_istream(), U("text/plain")); - response.headers().add(header_names::connection, U("close")); - request.reply(response); + { + utility::string_t fname(U("xfer_chunked_multiple_chunks.txt")); + auto fstream = OPENSTR_W(fname).get(); - VERIFY_ARE_EQUAL(buf.putn_nocopy((const uint8_t *)firstChunk.data(), firstChunk.size()).get(), firstChunk.size()); - buf.sync().get(); - VERIFY_ARE_EQUAL(buf.putn_nocopy((const uint8_t *)secondChunk.data(), secondChunk.size()).get(), secondChunk.size()); - buf.close(std::ios_base::out).get(); - }); + http_request msg(methods::GET); + msg.set_response_stream(fstream); + http_response rsp = client.request(msg).get(); - { - utility::string_t fname(U("xfer_chunked_multiple_chunks.txt")); - auto fstream = OPENSTR_W(fname).get(); + rsp.content_ready().wait(); + VERIFY_IS_TRUE(fstream.streambuf().is_open()); + fstream.close().get(); - http_request msg(methods::GET); - msg.set_response_stream(fstream); - http_response rsp = client.request(msg).get(); + std::string rsp_string; + size_t workload_size = firstChunk.size() + secondChunk.size(); + rsp_string.resize(workload_size, 0); + streams::rawptr_buffer buffer(reinterpret_cast(&rsp_string[0]), rsp_string.size()); + streams::basic_istream fistream = OPENSTR_R(fname).get(); - rsp.content_ready().wait(); - VERIFY_IS_TRUE(fstream.streambuf().is_open()); - fstream.close().get(); + VERIFY_ARE_EQUAL(fistream.read_to_end(buffer).get(), workload_size); + VERIFY_ARE_EQUAL(rsp_string, firstChunk + secondChunk); + fistream.close().get(); + } - std::string rsp_string; - size_t workload_size = firstChunk.size() + secondChunk.size(); - rsp_string.resize(workload_size, 0); - streams::rawptr_buffer buffer(reinterpret_cast(&rsp_string[0]), rsp_string.size()); - streams::basic_istream fistream = OPENSTR_R(fname).get(); - - VERIFY_ARE_EQUAL(fistream.read_to_end(buffer).get(), workload_size); - VERIFY_ARE_EQUAL(rsp_string, firstChunk + secondChunk); - fistream.close().get(); + listener.close().wait(); } - listener.close().wait(); -} - #endif } // SUITE(responses) -}}}} +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/status_code_reason_phrase_tests.cpp b/Release/tests/functional/http/client/status_code_reason_phrase_tests.cpp index 6a280fd433..a059db5f57 100644 --- a/Release/tests/functional/http/client/status_code_reason_phrase_tests.cpp +++ b/Release/tests/functional/http/client/status_code_reason_phrase_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* status_code_reason_phrase_tests.cpp -* -* Tests cases for covering HTTP status codes and reason phrases. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * status_code_reason_phrase_tests.cpp + * + * Tests cases for covering HTTP status codes and reason phrases. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -18,28 +18,37 @@ using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(status_code_reason_phrase_tests) +namespace tests { - -TEST_FIXTURE(uri_address, status_code) +namespace functional +{ +namespace http { - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); +namespace client +{ +SUITE(status_code_reason_phrase_tests) +{ + TEST_FIXTURE(uri_address, status_code) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); - // custom status code. - test_server_utilities::verify_request(&client, methods::GET, U("/"), scoped.server(), 666); -} + // custom status code. + test_server_utilities::verify_request(&client, methods::GET, U("/"), scoped.server(), 666); + } -TEST_FIXTURE(uri_address, reason_phrase) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); + TEST_FIXTURE(uri_address, reason_phrase) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); - test_server_utilities::verify_request(&client, methods::GET, U("/"), scoped.server(), status_codes::OK, U("Reasons!!")); -} + test_server_utilities::verify_request( + &client, methods::GET, U("/"), scoped.server(), status_codes::OK, U("Reasons!!")); + } } // SUITE(status_code_reason_phrase_tests) -}}}} \ No newline at end of file +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/stdafx.cpp b/Release/tests/functional/http/client/stdafx.cpp index 34ab72c03a..a518dbdc78 100644 --- a/Release/tests/functional/http/client/stdafx.cpp +++ b/Release/tests/functional/http/client/stdafx.cpp @@ -1,14 +1,14 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ -// stdafx.cpp : + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ +// stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" #if WIN32 __declspec(dllexport) int httpclient_test_generate_lib = 0; -#endif \ No newline at end of file +#endif diff --git a/Release/tests/functional/http/client/stdafx.h b/Release/tests/functional/http/client/stdafx.h index b5b77d04c0..8a7ad8b23b 100644 --- a/Release/tests/functional/http/client/stdafx.h +++ b/Release/tests/functional/http/client/stdafx.h @@ -1,25 +1,24 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include "cpprest/http_client.h" #include "cpprest/asyncrt_utils.h" -#include "cpprest/rawptrstream.h" #include "cpprest/containerstream.h" -#include "cpprest/producerconsumerstream.h" #include "cpprest/filestream.h" - +#include "cpprest/http_client.h" +#include "cpprest/producerconsumerstream.h" +#include "cpprest/rawptrstream.h" #include "http_client_tests.h" #include "http_test_utilities.h" -#include "unittestpp.h" #include "os_utilities.h" #include "timeout_handler.h" +#include "unittestpp.h" diff --git a/Release/tests/functional/http/client/timeout_handler.h b/Release/tests/functional/http/client/timeout_handler.h index f391e35ba4..4b22d21959 100644 --- a/Release/tests/functional/http/client/timeout_handler.h +++ b/Release/tests/functional/http/client/timeout_handler.h @@ -1,22 +1,28 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Simple utility for handling timeouts with http client test cases. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Simple utility for handling timeouts with http client test cases. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "cpprest/http_client.h" -namespace tests { namespace functional { namespace http { namespace client { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client +{ // helper function to check if failure is due to timeout. -inline bool is_timeout(const std::string &msg) +inline bool is_timeout(const std::string& msg) { if (msg.find("The operation timed out") != std::string::npos /* WinHTTP */ || msg.find("The operation was timed out") != std::string::npos /* IXmlHttpRequest2 */) @@ -26,14 +32,14 @@ inline bool is_timeout(const std::string &msg) return false; } -template -void handle_timeout(const Func &f) +template +void handle_timeout(const Func& f) { try { f(); } - catch (const web::http::http_exception &e) + catch (const web::http::http_exception& e) { if (is_timeout(e.what())) { @@ -45,4 +51,7 @@ void handle_timeout(const Func &f) } } -}}}} \ No newline at end of file +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/client/to_string_tests.cpp b/Release/tests/functional/http/client/to_string_tests.cpp index d85b7e1ffc..8ae964f780 100644 --- a/Release/tests/functional/http/client/to_string_tests.cpp +++ b/Release/tests/functional/http/client/to_string_tests.cpp @@ -1,147 +1,133 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases for to_string APIs on HTTP request and responses. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases for to_string APIs on HTTP request and responses. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -using namespace web; using namespace utility; +using namespace web; +using namespace utility; using namespace web::http; using namespace web::http::client; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace client { - -SUITE(to_string_tests) +namespace tests { - -TEST_FIXTURE(uri_address, request_to_string_without_body) +namespace functional { - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - const method mtd = methods::GET; - const utility::string_t path = U("/pathbaby/"); - const utility::string_t content_type = U("text/plain; charset= utf-8"); - - // to_string - http_request msg(mtd); - msg.set_request_uri(path); - msg.headers()[U("Content-Type")] = content_type; - - std::map expected_headers; - expected_headers[U("Content-Type")] = content_type; - http_asserts::assert_request_string_equals( - msg.to_string(), - mtd, - path, - U("HTTP/1.1"), - expected_headers, - U("")); -} - -TEST_FIXTURE(uri_address, request_to_string_with_body) +namespace http { - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - const method mtd = methods::POST; - const utility::string_t path = U("/path baby/"); - const utility::string_t content_type = U("text/plain;charset=utf-8"); - const utility::string_t body = U("YES THIS IS THE MSG BODY!!!!!"); - - // to_string - http_request msg(mtd); - msg.set_request_uri(uri::encode_uri(path, uri::components::path)); - msg.headers()[U("Content-Type")] = content_type; - msg.set_body(body); - - std::map expected_headers; - expected_headers[U("Content-Type")] = content_type; - expected_headers[U("Content-Length")] = U("29"); - http_asserts::assert_request_string_equals( - msg.to_string(), - mtd, - U("/path%20baby/"), - U("HTTP/1.1"), - expected_headers, - body); -} - -TEST_FIXTURE(uri_address, response_to_string_without_body) +namespace client { - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - const web::http::status_code code = status_codes::OK; - const utility::string_t reason = U("OK YEAH!"); - const utility::string_t content_type = U("not; charset= utf-8"); - - // to_string - scoped.server()->next_request().then([&](test_request *request) +SUITE(to_string_tests) +{ + TEST_FIXTURE(uri_address, request_to_string_without_body) { - std::map headers; - headers[U("Content-Type")] = content_type; - request->reply(code, reason, headers); - }); - http_response rsp = client.request(methods::GET).get(); - - std::map expected_headers; - expected_headers[U("Content-Length")] = U("0"); - expected_headers[U("Content-Type")] = content_type; - http_asserts::assert_response_string_equals( - rsp.to_string(), - U("HTTP/1.1"), - code, - U("OK"), - expected_headers, - U("")); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + const method mtd = methods::GET; + const utility::string_t path = U("/pathbaby/"); + const utility::string_t content_type = U("text/plain; charset= utf-8"); + + // to_string + http_request msg(mtd); + msg.set_request_uri(path); + msg.headers()[U("Content-Type")] = content_type; + + std::map expected_headers; + expected_headers[U("Content-Type")] = content_type; + http_asserts::assert_request_string_equals(msg.to_string(), mtd, path, U("HTTP/1.1"), expected_headers, U("")); + } -#ifdef _WIN32 - // Don't verify the values of each of these headers, but make sure they exist. - if(!rsp.headers().has(U("Date")) || !rsp.headers().has(U("Cache-Control")) || !rsp.headers().has(U("Server"))) + TEST_FIXTURE(uri_address, request_to_string_with_body) { - CHECK(false); + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + const method mtd = methods::POST; + const utility::string_t path = U("/path baby/"); + const utility::string_t content_type = U("text/plain;charset=utf-8"); + const utility::string_t body = U("YES THIS IS THE MSG BODY!!!!!"); + + // to_string + http_request msg(mtd); + msg.set_request_uri(uri::encode_uri(path, uri::components::path)); + msg.headers()[U("Content-Type")] = content_type; + msg.set_body(body); + + std::map expected_headers; + expected_headers[U("Content-Type")] = content_type; + expected_headers[U("Content-Length")] = U("29"); + http_asserts::assert_request_string_equals( + msg.to_string(), mtd, U("/path%20baby/"), U("HTTP/1.1"), expected_headers, body); } + + TEST_FIXTURE(uri_address, response_to_string_without_body) + { + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + const web::http::status_code code = status_codes::OK; + const utility::string_t reason = U("OK YEAH!"); + const utility::string_t content_type = U("not; charset= utf-8"); + + // to_string + scoped.server()->next_request().then([&](test_request* request) { + std::map headers; + headers[U("Content-Type")] = content_type; + request->reply(code, reason, headers); + }); + http_response rsp = client.request(methods::GET).get(); + + std::map expected_headers; + expected_headers[U("Content-Length")] = U("0"); + expected_headers[U("Content-Type")] = content_type; + http_asserts::assert_response_string_equals( + rsp.to_string(), U("HTTP/1.1"), code, U("OK"), expected_headers, U("")); + +#ifdef _WIN32 + // Don't verify the values of each of these headers, but make sure they exist. + if (!rsp.headers().has(U("Date")) || !rsp.headers().has(U("Cache-Control")) || !rsp.headers().has(U("Server"))) + { + CHECK(false); + } #endif -} + } -TEST_FIXTURE(uri_address, response_to_string_with_body) -{ - test_http_server::scoped_server scoped(m_uri); - http_client client(m_uri); - const ::http::status_code code = status_codes::OK; - const utility::string_t reason = U("OK YEAH!"); - const std::string data = "HERE IS THE RESPONSE body!"; - const utility::string_t content_type = U("text/yeah;charset=utf-8"); - - // to_string - scoped.server()->next_request().then([&](test_request *request) + TEST_FIXTURE(uri_address, response_to_string_with_body) { - std::map headers; - headers[U("Content-Type")] = content_type; - request->reply(code, reason, headers, data); - }); - - http_response rsp = client.request(methods::GET).get(); - rsp.content_ready().wait(); - - std::map expected_headers; - expected_headers[U("Content-Length")] = U("26"); - expected_headers[U("Content-Type")] = content_type; - http_asserts::assert_response_string_equals( - rsp.to_string(), - U("HTTP/1.1"), - code, - U("OK"), - expected_headers, - ::utility::conversions::to_string_t(data)); -} + test_http_server::scoped_server scoped(m_uri); + http_client client(m_uri); + const ::http::status_code code = status_codes::OK; + const utility::string_t reason = U("OK YEAH!"); + const std::string data = "HERE IS THE RESPONSE body!"; + const utility::string_t content_type = U("text/yeah;charset=utf-8"); + + // to_string + scoped.server()->next_request().then([&](test_request* request) { + std::map headers; + headers[U("Content-Type")] = content_type; + request->reply(code, reason, headers, data); + }); + + http_response rsp = client.request(methods::GET).get(); + rsp.content_ready().wait(); + + std::map expected_headers; + expected_headers[U("Content-Length")] = U("26"); + expected_headers[U("Content-Type")] = content_type; + http_asserts::assert_response_string_equals( + rsp.to_string(), U("HTTP/1.1"), code, U("OK"), expected_headers, ::utility::conversions::to_string_t(data)); + } } // SUITE(to_string_tests) -}}}} \ No newline at end of file +} // namespace client +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/building_response_tests.cpp b/Release/tests/functional/http/listener/building_response_tests.cpp index 6df397d6da..a41e80d544 100644 --- a/Release/tests/functional/http/listener/building_response_tests.cpp +++ b/Release/tests/functional/http/listener/building_response_tests.cpp @@ -1,142 +1,154 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* building_response_tests.cpp -* -* Tests cases for manually building up HTTP responses with http_listener. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * building_response_tests.cpp + * + * Tests cases for manually building up HTTP responses with http_listener. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -using namespace web; using namespace utility; +using namespace web; +using namespace utility; using namespace web::http; using namespace web::http::experimental::listener; using namespace tests::common::utilities; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(building_response_tests) +namespace tests { - -TEST_FIXTURE(uri_address, set_body_with_content_type) +namespace functional { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - http_response response(status_codes::OK); - response.set_body(U("test string"), U("text")); - request.reply(response).wait(); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) +namespace http +{ +namespace listener +{ +SUITE(building_response_tests) +{ + TEST_FIXTURE(uri_address, set_body_with_content_type) { + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + http_response response(status_codes::OK); + response.set_body(U("test string"), U("text")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { #ifdef _UTF16_STRINGS - const ::utility::string_t expectedContentType(U("text; charset=utf-8")); + const ::utility::string_t expectedContentType(U("text; charset=utf-8")); #else - const ::utility::string_t expectedContentType(U("text")); + const ::utility::string_t expectedContentType(U("text")); #endif - http_asserts::assert_test_response_equals(p_response, status_codes::OK, expectedContentType, U("test string")); - }).wait(); - - listener.close().wait(); -} + http_asserts::assert_test_response_equals( + p_response, status_codes::OK, expectedContentType, U("test string")); + }) + .wait(); -TEST_FIXTURE(uri_address, set_body_without_content_type) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + listener.close().wait(); + } - listener.support([&](http_request request) + TEST_FIXTURE(uri_address, set_body_without_content_type) { - http_response response(status_codes::OK); - response.set_body(U("test string")); - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(response).wait(); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + listener.support([&](http_request request) { + http_response response(status_codes::OK); + response.set_body(U("test string")); + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals( + p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("test string")); + }) + .wait(); + + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, set_body_string) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("test string")); - }).wait(); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, set_body_string) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - listener.support([&](http_request request) + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + http_response response(status_codes::OK); + utility::string_t data(U("test data")); + response.set_body(std::move(data)); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals( + p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("test data")); + }) + .wait(); + + listener.close().wait(); + } + + TEST(set_body_string_with_charset) { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - http_response response(status_codes::OK); - utility::string_t data(U("test data")); - response.set_body(std::move(data)); - request.reply(response).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("test data")); - }).wait(); - - listener.close().wait(); -} - -TEST(set_body_string_with_charset) -{ - http_response response; - VERIFY_THROWS(response.set_body( - ::utility::conversions::to_utf16string("body_data"), - ::utility::conversions::to_utf16string("text/plain;charset=utf-16")), std::invalid_argument); -} - -TEST_FIXTURE(uri_address, set_body_vector) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + http_response response; + VERIFY_THROWS(response.set_body(::utility::conversions::to_utf16string("body_data"), + ::utility::conversions::to_utf16string("text/plain;charset=utf-16")), + std::invalid_argument); + } - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - http_response response(status_codes::OK); - std::vector v_body; - v_body.push_back('A'); - v_body.push_back('B'); - v_body.push_back('C'); - response.set_body(std::move(v_body)); - request.reply(response).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) + TEST_FIXTURE(uri_address, set_body_vector) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("application/octet-stream"), U("ABC")); - }).wait(); - - listener.close().wait(); -} - + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + http_response response(status_codes::OK); + std::vector v_body; + v_body.push_back('A'); + v_body.push_back('B'); + v_body.push_back('C'); + response.set_body(std::move(v_body)); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals( + p_response, status_codes::OK, U("application/octet-stream"), U("ABC")); + }) + .wait(); + + listener.close().wait(); + } } -}}}} +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/connections_and_errors.cpp b/Release/tests/functional/http/listener/connections_and_errors.cpp index 124ea7f829..b3076e4974 100644 --- a/Release/tests/functional/http/listener/connections_and_errors.cpp +++ b/Release/tests/functional/http/listener/connections_and_errors.cpp @@ -1,17 +1,17 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* connections_and_errors.cpp -* -* Tests cases the underlying connections and error cases with the connection using then http_listener. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * connections_and_errors.cpp + * + * Tests cases the underlying connections and error cases with the connection using then http_listener. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -29,385 +29,392 @@ using namespace web::http::experimental::listener; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace listener +{ SUITE(connections_and_errors) { + TEST_FIXTURE(uri_address, close_listener_race, "Ignore", "825350") + { + ::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); -TEST_FIXTURE(uri_address, close_listener_race, "Ignore", "825350") -{ - ::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); + listener.support([](http_request) { + // Let the connection timeout + }); - listener.support([](http_request) - { - // Let the connection timeout - }); + // close() racing with a new connection + auto closeTask = pplx::create_task([&listener]() { listener.close().wait(); }); - // close() racing with a new connection - auto closeTask = pplx::create_task([&listener]() - { - listener.close().wait(); - }); + auto clientTask = pplx::create_task([this] { + ::http::client::http_client_config config; + config.set_timeout(utility::seconds(1)); + ::http::client::http_client client(m_uri, config); + + try + { + // Depending on timing this might not succeed. The + // exception will be caught and ignored below + auto rsp = client.request(methods::GET).get(); + + // The response body should timeout and we should recieve an exception + rsp.content_ready().wait(); + + // If we reach here then it is an error + VERIFY_IS_FALSE(true); + } + catch (std::exception) + { + } + }); + + (closeTask && clientTask).wait(); + } - auto clientTask = pplx::create_task([this] + // Note: Run with admin privileges to listen on default port. + // This test will fail with "Access denied: attempting to add Address.." exception if it is not run as admin. + TEST(default_port_close, "Ignore", "Manual") { - ::http::client::http_client_config config; - config.set_timeout(utility::seconds(1)); - ::http::client::http_client client(m_uri, config); - + uri address(U("http://localhost/portnotspecified")); + http_listener listener(address); + try { - // Depending on timing this might not succeed. The - // exception will be caught and ignored below - auto rsp = client.request(methods::GET).get(); - - // The response body should timeout and we should recieve an exception - rsp.content_ready().wait(); - - // If we reach here then it is an error - VERIFY_IS_FALSE(true); + listener.open().wait(); } - catch(std::exception) + catch (const http_exception& ex) { + VERIFY_IS_FALSE(true, ex.what()); + return; } - }); - (closeTask && clientTask).wait(); -} - -// Note: Run with admin privileges to listen on default port. -// This test will fail with "Access denied: attempting to add Address.." exception if it is not run as admin. -TEST(default_port_close, "Ignore", "Manual") -{ - uri address(U("http://localhost/portnotspecified")); - http_listener listener(address); + // Verify close does not throw an exception while listening on default port + listener.close().wait(); + } - try + TEST_FIXTURE(uri_address, send_response_later) { + http_listener listener(m_uri); listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + std::vector requests; + pplx::extensibility::event_t request_event; + listener.support([&](http_request r) { + requests.push_back(r); + request_event.set(); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + request_event.wait(); + requests[0].reply(status_codes::OK, "HEHEHE").wait(); + requests.clear(); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals( + p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("HEHEHE")); + }) + .wait(); + + listener.close().wait(); } - catch(const http_exception& ex) + + TEST_FIXTURE(uri_address, save_request_reply) { - VERIFY_IS_FALSE(true, ex.what()); - return; - } + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + http_request request; + pplx::extensibility::event_t request_event; + listener.support([&](http_request r) { + request = r; + request_event.set(); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + request_event.wait(); + request.reply(status_codes::OK).wait(); - // Verify close does not throw an exception while listening on default port - listener.close().wait(); -} + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + listener.close().wait(); + } -TEST_FIXTURE(uri_address, send_response_later) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - std::vector requests; - pplx::extensibility::event_t request_event; - listener.support([&](http_request r) - { - requests.push_back(r); - request_event.set(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - request_event.wait(); - requests[0].reply(status_codes::OK, "HEHEHE").wait(); - requests.clear(); - p_client->next_response().then([&](test_response *p_response) +#if defined(_WIN32) && _MSC_VER < 1900 + TEST_FIXTURE(uri_address, single_core_request) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("HEHEHE")); - }).wait(); + // Fake having a scheduler with only 1 core. + concurrency::CurrentScheduler::Create( + concurrency::SchedulerPolicy(2, 1, Concurrency::MinConcurrency, 1, Concurrency::MaxConcurrency)); - listener.close().wait(); -} + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + listener.support([](http_request request) { request.reply(status_codes::OK).get(); }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + + // Don't wait on the task otherwise it could inline allowing other tasks to run on the scheduler. + std::atomic_flag responseEvent = ATOMIC_FLAG_INIT; + responseEvent.test_and_set(); + p_client->next_response().then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + responseEvent.clear(); + }); + while (responseEvent.test_and_set()) + { + } -TEST_FIXTURE(uri_address, save_request_reply) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - http_request request; - pplx::extensibility::event_t request_event; - listener.support([&](http_request r) - { - request = r; - request_event.set(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - request_event.wait(); - request.reply(status_codes::OK).wait(); - - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - listener.close().wait(); -} + listener.close().wait(); -#if defined(_WIN32) && _MSC_VER < 1900 -TEST_FIXTURE(uri_address, single_core_request) -{ - // Fake having a scheduler with only 1 core. - concurrency::CurrentScheduler::Create(concurrency::SchedulerPolicy(2, 1, Concurrency::MinConcurrency, 1, Concurrency::MaxConcurrency)); - - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - listener.support([](http_request request) - { - request.reply(status_codes::OK).get(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - - // Don't wait on the task otherwise it could inline allowing other tasks to run on the scheduler. - std::atomic_flag responseEvent = ATOMIC_FLAG_INIT; - responseEvent.test_and_set(); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - responseEvent.clear(); - }); - while (responseEvent.test_and_set()) {} - - listener.close().wait(); - - concurrency::CurrentScheduler::Detach(); -} + concurrency::CurrentScheduler::Detach(); + } #endif -TEST_FIXTURE(uri_address, save_request_response) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - http_request request; - pplx::extensibility::event_t request_event; - listener.support([&](http_request r) - { - request = r; - request_event.set(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - request_event.wait(); - http_response response(status_codes::OK); - request.reply(response).wait(); - - p_client->next_response().then([](test_response *p_response) + TEST_FIXTURE(uri_address, save_request_response) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, reply_twice) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + http_request request; + pplx::extensibility::event_t request_event; + listener.support([&](http_request r) { + request = r; + request_event.set(); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + request_event.wait(); + http_response response(status_codes::OK); + request.reply(response).wait(); + + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + listener.close().wait(); + } - listener.support([](http_request request) + TEST_FIXTURE(uri_address, reply_twice) { - request.reply(status_codes::OK); - VERIFY_THROWS(request.reply(status_codes::Accepted).get(), http_exception); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - -// This test case is manual becuase it requires to be run under and account without admin access. -TEST(default_port_admin_access, "Ignore", "Manual") -{ - uri address(U("http://localhost/")); - http_listener listener(address); - VERIFY_THROWS(listener.open().wait(), http_exception); -} - -TEST_FIXTURE(uri_address, try_port_already_in_use, "Ignore:Linux", "Bug 879077", "Ignore:Apple", "Bug 879077") -{ - test_http_server::scoped_server scoped(m_uri); - http_listener listener(m_uri); - VERIFY_THROWS(listener.open().wait(), http_exception); -} + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + listener.support([](http_request request) { + request.reply(status_codes::OK); + VERIFY_THROWS(request.reply(status_codes::Accepted).get(), http_exception); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); -TEST_FIXTURE(uri_address, reply_after_starting_close, "Ignore", "901808") -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + listener.close().wait(); + } - listener.support([&](http_request request) + // This test case is manual becuase it requires to be run under and account without admin access. + TEST(default_port_admin_access, "Ignore", "Manual") { - // Start closing the listener and then send reply. - listener.close(); - request.reply(status_codes::OK).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path"))); + uri address(U("http://localhost/")); + http_listener listener(address); + VERIFY_THROWS(listener.open().wait(), http_exception); + } - p_client->next_response().then([](test_response *p_response) + TEST_FIXTURE(uri_address, try_port_already_in_use, "Ignore:Linux", "Bug 879077", "Ignore:Apple", "Bug 879077") { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); -} + test_http_server::scoped_server scoped(m_uri); + http_listener listener(m_uri); + VERIFY_THROWS(listener.open().wait(), http_exception); + } -static void close_stream_early_with_length_impl(const uri &u, bool useException) -{ - http_listener listener(u); - listener.open().wait(); - listener.support([=](http_request request) + TEST_FIXTURE(uri_address, reply_after_starting_close, "Ignore", "901808") { - concurrency::streams::producer_consumer_buffer body; - concurrency::streams::istream instream = body.create_istream(); - body.putc('A').wait(); - body.putc('B').wait(); - auto responseTask = request.reply(status_codes::OK, instream, 4); - - if(useException) - { - body.close(std::ios::out, std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); - VERIFY_THROWS(responseTask.get(), std::invalid_argument); - } - else - { - body.close(std::ios::out).wait(); - VERIFY_THROWS(responseTask.get(), http_exception); - } - }); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + listener.support([&](http_request request) { + // Start closing the listener and then send reply. + listener.close(); + request.reply(status_codes::OK).wait(); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path"))); + + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + } - web::http::client::http_client client(u); - client.request(methods::GET, U("/path")).then([](http_response response) -> pplx::task> + static void close_stream_early_with_length_impl(const uri& u, bool useException) { - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - return response.extract_vector(); - }).then([=](pplx::task> bodyTask) - { - VERIFY_THROWS(bodyTask.get(), http_exception); - }).wait(); + http_listener listener(u); + listener.open().wait(); + listener.support([=](http_request request) { + concurrency::streams::producer_consumer_buffer body; + concurrency::streams::istream instream = body.create_istream(); + body.putc('A').wait(); + body.putc('B').wait(); + auto responseTask = request.reply(status_codes::OK, instream, 4); + + if (useException) + { + body.close(std::ios::out, std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); + VERIFY_THROWS(responseTask.get(), std::invalid_argument); + } + else + { + body.close(std::ios::out).wait(); + VERIFY_THROWS(responseTask.get(), http_exception); + } + }); + + web::http::client::http_client client(u); + client.request(methods::GET, U("/path")) + .then([](http_response response) -> pplx::task> { + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + return response.extract_vector(); + }) + .then( + [=](pplx::task> bodyTask) { VERIFY_THROWS(bodyTask.get(), http_exception); }) + .wait(); - listener.close().wait(); -} + listener.close().wait(); + } -TEST_FIXTURE(uri_address, close_stream_early_with_length) -{ - close_stream_early_with_length_impl(m_uri, true); - close_stream_early_with_length_impl(m_uri, false); -} + TEST_FIXTURE(uri_address, close_stream_early_with_length) + { + close_stream_early_with_length_impl(m_uri, true); + close_stream_early_with_length_impl(m_uri, false); + } -static void close_stream_early_impl(const uri &u, bool useException) -{ - http_listener listener(u); - listener.open().wait(); - listener.support([=](http_request request) + static void close_stream_early_impl(const uri& u, bool useException) { - concurrency::streams::producer_consumer_buffer body; - concurrency::streams::istream instream = body.create_istream(); - body.putc('A').wait(); - body.putc('B').wait(); - auto responseTask = request.reply(status_codes::OK, instream); - - if(useException) - { - body.close(std::ios::out, std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); - VERIFY_THROWS(responseTask.get(), std::invalid_argument); - } - else - { - body.close(std::ios::out).wait(); - responseTask.get(); - } - }); + http_listener listener(u); + listener.open().wait(); + listener.support([=](http_request request) { + concurrency::streams::producer_consumer_buffer body; + concurrency::streams::istream instream = body.create_istream(); + body.putc('A').wait(); + body.putc('B').wait(); + auto responseTask = request.reply(status_codes::OK, instream); + + if (useException) + { + body.close(std::ios::out, std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); + VERIFY_THROWS(responseTask.get(), std::invalid_argument); + } + else + { + body.close(std::ios::out).wait(); + responseTask.get(); + } + }); + + web::http::client::http_client client(u); + client.request(methods::GET, U("/path")) + .then([](http_response response) -> pplx::task> { + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + return response.extract_vector(); + }) + .then([=](pplx::task> bodyTask) { + if (useException) + { + VERIFY_THROWS(bodyTask.get(), http_exception); + } + else + { + std::vector body = bodyTask.get(); + VERIFY_ARE_EQUAL(2, body.size()); + VERIFY_ARE_EQUAL('A', body[0]); + VERIFY_ARE_EQUAL('B', body[1]); + } + }) + .wait(); + + listener.close().wait(); + } - web::http::client::http_client client(u); - client.request(methods::GET, U("/path")).then([](http_response response) -> pplx::task> + TEST_FIXTURE(uri_address, close_stream_with_exception) { - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); - return response.extract_vector(); - }).then([=](pplx::task> bodyTask) + close_stream_early_impl(m_uri, true); + close_stream_early_impl(m_uri, false); + } + + // Helper function to verify http_exception and return the error code value. + template + int verify_http_exception(Func f) { - if(useException) + int errorCode = 0; + try { - VERIFY_THROWS(bodyTask.get(), http_exception); + f(); + VERIFY_IS_TRUE(false); } - else + catch (const http_exception& e) { - std::vector body = bodyTask.get(); - VERIFY_ARE_EQUAL(2, body.size()); - VERIFY_ARE_EQUAL('A', body[0]); - VERIFY_ARE_EQUAL('B', body[1]); + errorCode = e.error_code().value(); } - }).wait(); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, close_stream_with_exception) -{ - close_stream_early_impl(m_uri, true); - close_stream_early_impl(m_uri, false); -} - -// Helper function to verify http_exception and return the error code value. -template -int verify_http_exception(Func f) -{ - int errorCode = 0; - try - { - f(); - VERIFY_IS_TRUE(false); - } catch (const http_exception &e) - { - errorCode = e.error_code().value(); + return errorCode; } - return errorCode; -} -TEST_FIXTURE(uri_address, request_content_ready_timeout, "Ignore:Linux", "Unsuitable until 813276", "Ignore:Apple", "Unsuitable until 813276") -{ + TEST_FIXTURE(uri_address, + request_content_ready_timeout, + "Ignore:Linux", + "Unsuitable until 813276", + "Ignore:Apple", + "Unsuitable until 813276") + { #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) - throw std::runtime_error("Unsuitable until 813276 -- http_listener on ASIO does not support timeouts nor chunk sizes"); + throw std::runtime_error( + "Unsuitable until 813276 -- http_listener on ASIO does not support timeouts nor chunk sizes"); #endif - http_listener_config config; - config.set_timeout(utility::seconds(1)); - http_listener listener(m_uri, config); - pplx::extensibility::event_t timedOutEvent; - listener.support([&](http_request req) - { - const int e1 = verify_http_exception([=](){ req.content_ready().wait(); }); - const int e2 = verify_http_exception([=](){ req.body().read().wait(); }); - const int e3 = verify_http_exception([=](){ req.reply(status_codes::OK).wait(); }); - VERIFY_ARE_EQUAL(e1, e2); - VERIFY_ARE_EQUAL(e2, e3); - timedOutEvent.set(); - }); - listener.open().wait(); - - // Using our production http_client here because it - // allows separation of sending headers and body. - ::web::http::client::http_client client(m_uri); - concurrency::streams::producer_consumer_buffer body; - auto responseTask = client.request(methods::PUT, U(""), body.create_istream()); - timedOutEvent.wait(); - body.close().wait(); - VERIFY_THROWS(responseTask.get(), http_exception); - - listener.close().wait(); -} + http_listener_config config; + config.set_timeout(utility::seconds(1)); + http_listener listener(m_uri, config); + pplx::extensibility::event_t timedOutEvent; + listener.support([&](http_request req) { + const int e1 = verify_http_exception([=]() { req.content_ready().wait(); }); + const int e2 = verify_http_exception([=]() { req.body().read().wait(); }); + const int e3 = verify_http_exception([=]() { req.reply(status_codes::OK).wait(); }); + VERIFY_ARE_EQUAL(e1, e2); + VERIFY_ARE_EQUAL(e2, e3); + timedOutEvent.set(); + }); + listener.open().wait(); + // Using our production http_client here because it + // allows separation of sending headers and body. + ::web::http::client::http_client client(m_uri); + concurrency::streams::producer_consumer_buffer body; + auto responseTask = client.request(methods::PUT, U(""), body.create_istream()); + timedOutEvent.wait(); + body.close().wait(); + VERIFY_THROWS(responseTask.get(), http_exception); + + listener.close().wait(); + } } -}}}} +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/header_tests.cpp b/Release/tests/functional/http/listener/header_tests.cpp index 548e5be4ce..a3cff2e2e1 100644 --- a/Release/tests/functional/http/listener/header_tests.cpp +++ b/Release/tests/functional/http/listener/header_tests.cpp @@ -1,17 +1,17 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* header_tests.cpp -* -* Tests cases for using HTTP requests/response headers with http_listener. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * header_tests.cpp + * + * Tests cases for using HTTP requests/response headers with http_listener. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,176 +20,183 @@ using namespace web::http::experimental::listener; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(header_tests) +namespace tests { - -TEST_FIXTURE(uri_address, request_headers) +namespace functional { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - const utility::string_t mtd = methods::GET; - std::map headers; - - // single header value. - headers[U("Header1")] = U("Value1"); - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, mtd, U("/"), headers); - request.reply(status_codes::OK).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(mtd, U(""), headers)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - // empty header value. - headers.clear(); - headers[U("Key1")] = U(""); - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, mtd, U("/"), headers); - request.reply(status_codes::OK).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(mtd, U(""), headers)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - // 10 headers. - headers.clear(); - headers[U("MyHeader")] = U("hehe;blach"); - headers[U("Yo1")] = U("You, Too"); - headers[U("Yo2")] = U("You2"); - headers[U("Yo3")] = U("You3"); - headers[U("Yo4")] = U("You4"); - headers[U("Yo5")] = U("You5"); - headers[U("Yo6")] = U("You6"); - headers[U("Yo7")] = U("You7"); - headers[U("Yo8")] = U("You8"); - headers[U("Yo9")] = U("You9"); - headers[U("Yo10")] = U("You10"); - headers[U("Yo11")] = U("You11"); - headers[U("Accept")] = U("text/plain"); - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, mtd, U("/"), headers); - request.reply(status_codes::OK).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(mtd, U(""), headers)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - // several headers different casings. - headers.clear(); - headers[U("CUSTOMHEADER")] = U("value1"); - headers[U("customHEADER")] = U("value2"); - headers[U("CUSTOMheaDER")] = U("value3"); - listener.support([&](http_request request) - { - std::map h; - h[U("CUSTOMHEADER")] = U("value1, value3, value2"); - http_asserts::assert_request_equals(request, mtd, U("/"), h); - request.reply(status_codes::OK).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(mtd, U(""), headers)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, response_headers) +namespace http { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - // No http_request/response classes can be around for close to complete. +namespace listener +{ +SUITE(header_tests) +{ + TEST_FIXTURE(uri_address, request_headers) { - // header with empty value - http_response response(status_codes::OK); - response.headers()[U("Key1")] = U(""); - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(response).wait(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + const utility::string_t mtd = methods::GET; + std::map headers; + + // single header value. + headers[U("Header1")] = U("Value1"); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, mtd, U("/"), headers); + request.reply(status_codes::OK).wait(); }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, response.headers()); - }).wait(); - - // 10 headers - response = http_response(status_codes::Accepted); - response.headers()[U("MyHeader")] = U("hehe;blach"); - response.headers()[U("Yo1")] = U("You, Too"); - response.headers()[U("Yo2")] = U("You2"); - response.headers()[U("Yo3")] = U("You3"); - response.headers()[U("Yo4")] = U("You4"); - response.headers()[U("Yo5")] = U("You5"); - response.headers()[U("Yo6")] = U("You6"); - response.headers()[U("Yo7")] = U("You7"); - response.headers()[U("Yo8")] = U("You8"); - response.headers()[U("Yo9")] = U("You9"); - response.headers()[U("Yo10")] = U("You10"); - response.headers()[U("Yo11")] = U("You11"); - response.headers()[U("Accept")] = U("text/plain"); - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(response).wait(); + VERIFY_ARE_EQUAL(0, p_client->request(mtd, U(""), headers)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // empty header value. + headers.clear(); + headers[U("Key1")] = U(""); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, mtd, U("/"), headers); + request.reply(status_codes::OK).wait(); }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::Accepted, response.headers()); - }).wait(); - - // several headers in different casings - response = http_response(status_codes::BadGateway); - response.headers().add(U("Key1"), U("value1")); - response.headers()[U("KEY1")] += U("value2"); - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(response).wait(); + VERIFY_ARE_EQUAL(0, p_client->request(mtd, U(""), headers)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // 10 headers. + headers.clear(); + headers[U("MyHeader")] = U("hehe;blach"); + headers[U("Yo1")] = U("You, Too"); + headers[U("Yo2")] = U("You2"); + headers[U("Yo3")] = U("You3"); + headers[U("Yo4")] = U("You4"); + headers[U("Yo5")] = U("You5"); + headers[U("Yo6")] = U("You6"); + headers[U("Yo7")] = U("You7"); + headers[U("Yo8")] = U("You8"); + headers[U("Yo9")] = U("You9"); + headers[U("Yo10")] = U("You10"); + headers[U("Yo11")] = U("You11"); + headers[U("Accept")] = U("text/plain"); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, mtd, U("/"), headers); + request.reply(status_codes::OK).wait(); }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::BadGateway, response.headers()); - }).wait(); - - // duplicate headers fields - response = http_response(status_codes::BadGateway); - response.headers().add(U("Key1"), U("value1")); - response.headers().add(U("Key1"), U("value2")); - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(response).wait(); + VERIFY_ARE_EQUAL(0, p_client->request(mtd, U(""), headers)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // several headers different casings. + headers.clear(); + headers[U("CUSTOMHEADER")] = U("value1"); + headers[U("customHEADER")] = U("value2"); + headers[U("CUSTOMheaDER")] = U("value3"); + listener.support([&](http_request request) { + std::map h; + h[U("CUSTOMHEADER")] = U("value1, value3, value2"); + http_asserts::assert_request_equals(request, mtd, U("/"), h); + request.reply(status_codes::OK).wait(); }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::BadGateway, response.headers()); - }).wait(); + VERIFY_ARE_EQUAL(0, p_client->request(mtd, U(""), headers)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + listener.close().wait(); } - listener.close().wait(); -} + TEST_FIXTURE(uri_address, response_headers) + { + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + // No http_request/response classes can be around for close to complete. + { + // header with empty value + http_response response(status_codes::OK); + response.headers()[U("Key1")] = U(""); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK, response.headers()); + }) + .wait(); + + // 10 headers + response = http_response(status_codes::Accepted); + response.headers()[U("MyHeader")] = U("hehe;blach"); + response.headers()[U("Yo1")] = U("You, Too"); + response.headers()[U("Yo2")] = U("You2"); + response.headers()[U("Yo3")] = U("You3"); + response.headers()[U("Yo4")] = U("You4"); + response.headers()[U("Yo5")] = U("You5"); + response.headers()[U("Yo6")] = U("You6"); + response.headers()[U("Yo7")] = U("You7"); + response.headers()[U("Yo8")] = U("You8"); + response.headers()[U("Yo9")] = U("You9"); + response.headers()[U("Yo10")] = U("You10"); + response.headers()[U("Yo11")] = U("You11"); + response.headers()[U("Accept")] = U("text/plain"); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::Accepted, response.headers()); + }) + .wait(); + + // several headers in different casings + response = http_response(status_codes::BadGateway); + response.headers().add(U("Key1"), U("value1")); + response.headers()[U("KEY1")] += U("value2"); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::BadGateway, response.headers()); + }) + .wait(); + + // duplicate headers fields + response = http_response(status_codes::BadGateway); + response.headers().add(U("Key1"), U("value1")); + response.headers().add(U("Key1"), U("value2")); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::BadGateway, response.headers()); + }) + .wait(); + } + + listener.close().wait(); + } } -}}}} \ No newline at end of file +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/http_listener_tests.h b/Release/tests/functional/http/listener/http_listener_tests.h index ac19953a8c..5e50a58114 100644 --- a/Release/tests/functional/http/listener/http_listener_tests.h +++ b/Release/tests/functional/http/listener/http_listener_tests.h @@ -1,33 +1,38 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* http_listener_tests.h -* -* Common declarations and helper functions for http_listener test cases. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * http_listener_tests.h + * + * Common declarations and helper functions for http_listener test cases. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "cpprest/http_listener.h" -namespace tests { namespace functional { namespace http { namespace listener { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace listener +{ class uri_address { public: - uri_address() : - m_uri(U("http://localhost:34567/")), - m_secure_uri(U("https://localhost:8443/")) + uri_address() : m_uri(U("http://localhost:34567/")), m_secure_uri(U("https://localhost:8443/")) { if (!s_dummy_listener) - s_dummy_listener = std::make_shared(U("http://localhost:30000/")); + s_dummy_listener = + std::make_shared(U("http://localhost:30000/")); } // By introducing an additional listener, we can avoid having to close the @@ -38,4 +43,7 @@ class uri_address web::http::uri m_secure_uri; }; -}}}} \ No newline at end of file +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/listener_construction_tests.cpp b/Release/tests/functional/http/listener/listener_construction_tests.cpp index 1bf31ffa88..1e93ef56ae 100644 --- a/Release/tests/functional/http/listener/listener_construction_tests.cpp +++ b/Release/tests/functional/http/listener/listener_construction_tests.cpp @@ -1,17 +1,17 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* listener_construction_tests.cpp -* -* Tests cases for covering creating http_listeners in various ways. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * listener_construction_tests.cpp + * + * Tests cases for covering creating http_listeners in various ways. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -21,420 +21,415 @@ using namespace web::http::experimental::listener; using namespace tests::common::utilities; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(listener_construction_tests) +namespace tests { - -TEST_FIXTURE(uri_address, default_constructor) +namespace functional { - // Test that the default ctor works. - http_listener listener; - - VERIFY_IS_TRUE(listener.uri().is_empty()); - VERIFY_THROWS(listener.open().wait(), std::invalid_argument); -} - -TEST_FIXTURE(uri_address, move_operations) +namespace http { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - // move constructor - http_listener listener2 = std::move(listener); - listener2.support(methods::PUT, [](http_request request) - { - http_asserts::assert_request_equals(request, U("PUT"), U("/")); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(U("PUT"), U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - // move assignment - listener = std::move(listener2); - listener.support(methods::PUT, [](http_request request) - { - http_asserts::assert_request_equals(request, U("PUT"), U("/")); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(U("PUT"), U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, various_uris) +namespace listener { - http_listener listener(web::http::uri_builder(m_uri).append_path(U("path1")).to_uri()); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - // Path that matches exactly - listener.support([](http_request request) - { - http_asserts::assert_request_equals(request, U("GET"), U("")); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/"))); - p_client->next_response().then([](test_response *p_response) +SUITE(listener_construction_tests) +{ + TEST_FIXTURE(uri_address, default_constructor) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + // Test that the default ctor works. + http_listener listener; - // Path that matches but is more specific. - listener.support([](http_request request) - { - http_asserts::assert_request_equals(request, U("GET"), U("/path2")); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/path2"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + VERIFY_IS_TRUE(listener.uri().is_empty()); + VERIFY_THROWS(listener.open().wait(), std::invalid_argument); + } - // Try a request with a path that doesn't match. - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path3/path2"))); - p_client->next_response().then([](test_response *p_response) + TEST_FIXTURE(uri_address, move_operations) { - http_asserts::assert_test_response_equals(p_response, status_codes::NotFound); - }).wait(); - - listener.close().wait(); -} + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); -TEST_FIXTURE(uri_address, uri_routing) -{ - http_listener listener1(web::http::uri_builder(m_uri).append_path(U("path1")).to_uri()); - http_listener listener2(web::http::uri_builder(m_uri).append_path(U("path2")).to_uri()); - http_listener listener3(web::http::uri_builder(m_uri).append_path(U("path1/path2")).to_uri()); + // move constructor + http_listener listener2 = std::move(listener); + listener2.support(methods::PUT, [](http_request request) { + http_asserts::assert_request_equals(request, U("PUT"), U("/")); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(U("PUT"), U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // move assignment + listener = std::move(listener2); + listener.support(methods::PUT, [](http_request request) { + http_asserts::assert_request_equals(request, U("PUT"), U("/")); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(U("PUT"), U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + listener.close().wait(); + } - // Path that matches exactly - listener1.support([](http_request request) + TEST_FIXTURE(uri_address, various_uris) { - request.reply(status_codes::OK); - }); - listener1.open().wait(); + http_listener listener(web::http::uri_builder(m_uri).append_path(U("path1")).to_uri()); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - listener2.support([](http_request request) - { - request.reply(status_codes::Created); - }); - listener2.open().wait(); + // Path that matches exactly + listener.support([](http_request request) { + http_asserts::assert_request_equals(request, U("GET"), U("")); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // Path that matches but is more specific. + listener.support([](http_request request) { + http_asserts::assert_request_equals(request, U("GET"), U("/path2")); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/path2"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // Try a request with a path that doesn't match. + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path3/path2"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::NotFound); + }) + .wait(); - listener3.support([](http_request request) - { - request.reply(status_codes::Accepted); - }); - listener3.open().wait(); + listener.close().wait(); + } - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path2"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::Created); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/path2"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::Accepted); - }).wait(); + TEST_FIXTURE(uri_address, uri_routing) + { + http_listener listener1(web::http::uri_builder(m_uri).append_path(U("path1")).to_uri()); + http_listener listener2(web::http::uri_builder(m_uri).append_path(U("path2")).to_uri()); + http_listener listener3(web::http::uri_builder(m_uri).append_path(U("path1/path2")).to_uri()); + + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + // Path that matches exactly + listener1.support([](http_request request) { request.reply(status_codes::OK); }); + listener1.open().wait(); + + listener2.support([](http_request request) { request.reply(status_codes::Created); }); + listener2.open().wait(); + + listener3.support([](http_request request) { request.reply(status_codes::Accepted); }); + listener3.open().wait(); + + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path2"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::Created); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/path2"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::Accepted); + }) + .wait(); + + // Try a request with a path that doesn't match. + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path3/path2"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::NotFound); + }) + .wait(); + + listener1.close().wait(); + listener2.close().wait(); + listener3.close().wait(); + } - // Try a request with a path that doesn't match. - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path3/path2"))); - p_client->next_response().then([](test_response *p_response) + TEST_FIXTURE(uri_address, uri_error_cases) { - http_asserts::assert_test_response_equals(p_response, status_codes::NotFound); - }).wait(); + // non HTTP scheme + VERIFY_THROWS(http_listener(U("ftp://localhost:456/")), std::invalid_argument); - listener1.close().wait(); - listener2.close().wait(); - listener3.close().wait(); -} + // empty HTTP host + VERIFY_THROWS(http_listener(U("http://:456/")), std::invalid_argument); -TEST_FIXTURE(uri_address, uri_error_cases) -{ - // non HTTP scheme - VERIFY_THROWS(http_listener(U("ftp://localhost:456/")), std::invalid_argument); + // try specifying a query + VERIFY_THROWS(http_listener(U("http://localhost:45678/path?key1=value")), std::invalid_argument); - // empty HTTP host - VERIFY_THROWS(http_listener(U("http://:456/")), std::invalid_argument); - - // try specifying a query - VERIFY_THROWS(http_listener(U("http://localhost:45678/path?key1=value")), std::invalid_argument); + // try specifing a fragment + VERIFY_THROWS(http_listener(U("http://localhost:4563/path?key1=value#frag")), std::invalid_argument); + } - // try specifing a fragment - VERIFY_THROWS(http_listener(U("http://localhost:4563/path?key1=value#frag")), std::invalid_argument); -} + TEST_FIXTURE(uri_address, create_listener_get) + { + http_listener listener(m_uri); -TEST_FIXTURE(uri_address, create_listener_get) -{ - http_listener listener(m_uri); - - listener.support(methods::GET, - [](http_request request) - { + listener.support(methods::GET, [](http_request request) { http_asserts::assert_request_equals(request, methods::GET, U("/")); request.reply(status_codes::OK); }); - - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); - }).wait(); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); + }) + .wait(); - listener.close().wait(); -} + listener.close().wait(); + } -TEST_FIXTURE(uri_address, create_listener_get_put) -{ - http_listener listener(m_uri); - - listener.support(methods::GET, - [](http_request request) - { + TEST_FIXTURE(uri_address, create_listener_get_put) + { + http_listener listener(m_uri); + + listener.support(methods::GET, [](http_request request) { http_asserts::assert_request_equals(request, methods::GET, U("/")); request.reply(status_codes::OK); }); - - listener.support(methods::PUT, - [](http_request request) - { + + listener.support(methods::PUT, [](http_request request) { http_asserts::assert_request_equals(request, methods::PUT, U("/")); request.reply(status_codes::OK); }); - - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); - }).wait(); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); + }) + .wait(); - listener.close().wait(); -} + listener.close().wait(); + } -TEST_FIXTURE(uri_address, create_listener_get_put_post) -{ - http_listener listener(m_uri); - - listener.support(methods::GET, - [](http_request request) - { + TEST_FIXTURE(uri_address, create_listener_get_put_post) + { + http_listener listener(m_uri); + + listener.support(methods::GET, [](http_request request) { http_asserts::assert_request_equals(request, methods::GET, U("/")); request.reply(status_codes::OK); }); - - listener.support(methods::PUT, - [](http_request request) - { + + listener.support(methods::PUT, [](http_request request) { http_asserts::assert_request_equals(request, methods::PUT, U("/")); request.reply(status_codes::OK); }); - - listener.support(methods::POST, - [](http_request request) - { + + listener.support(methods::POST, [](http_request request) { http_asserts::assert_request_equals(request, methods::POST, U("/")); request.reply(status_codes::OK); }); - - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::DEL, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); - }).wait(); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::DEL, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); + }) + .wait(); - listener.close().wait(); -} + listener.close().wait(); + } -TEST_FIXTURE(uri_address, create_listener_get_put_post_delete) -{ - http_listener listener(m_uri); - - listener.support(methods::GET, - [](http_request request) - { - http_asserts::assert_request_equals(request, methods::GET, U("/")); - request.reply(status_codes::OK); - }); - - listener.support(methods::PUT, - [](http_request request) + TEST_FIXTURE(uri_address, create_listener_get_put_post_delete) { - http_asserts::assert_request_equals(request, methods::PUT, U("/")); - request.reply(status_codes::OK); - }); - - listener.support(methods::POST, - [](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(status_codes::OK); - }); - - listener.support(methods::DEL, - [](http_request request) - { - http_asserts::assert_request_equals(request, methods::DEL, U("/")); - request.reply(status_codes::OK); - }); - - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::DEL, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::HEAD, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); - }).wait(); + http_listener listener(m_uri); - listener.close().wait(); -} + listener.support(methods::GET, [](http_request request) { + http_asserts::assert_request_equals(request, methods::GET, U("/")); + request.reply(status_codes::OK); + }); -TEST_FIXTURE(uri_address, get_listener_config) -{ - // Verify default configuration. - { - http_listener listener(m_uri); - VERIFY_ARE_EQUAL(utility::seconds(120), listener.configuration().timeout()); - listener.open().wait(); - listener.close().wait(); - } + listener.support(methods::PUT, [](http_request request) { + http_asserts::assert_request_equals(request, methods::PUT, U("/")); + request.reply(status_codes::OK); + }); + + listener.support(methods::POST, [](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(status_codes::OK); + }); + + listener.support(methods::DEL, [](http_request request) { + http_asserts::assert_request_equals(request, methods::DEL, U("/")); + request.reply(status_codes::OK); + }); - // Verify specified config values. - { - http_listener_config config; - utility::seconds t(1); - config.set_timeout(t); - http_listener listener(m_uri, config); listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::DEL, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::HEAD, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); + }) + .wait(); + listener.close().wait(); - VERIFY_ARE_EQUAL(t, listener.configuration().timeout()); } -} -TEST_FIXTURE(uri_address, listener_config_creation) -{ - // copy constructor + TEST_FIXTURE(uri_address, get_listener_config) { - http_listener_config config; - config.set_timeout(utility::seconds(2)); - http_listener_config copy(config); - VERIFY_ARE_EQUAL(utility::seconds(2), copy.timeout()); - } + // Verify default configuration. + { + http_listener listener(m_uri); + VERIFY_ARE_EQUAL(utility::seconds(120), listener.configuration().timeout()); + listener.open().wait(); + listener.close().wait(); + } - // move constructor - { - http_listener_config config; - config.set_timeout(utility::seconds(2)); - http_listener_config ctorMove(std::move(config)); - VERIFY_ARE_EQUAL(utility::seconds(2), ctorMove.timeout()); + // Verify specified config values. + { + http_listener_config config; + utility::seconds t(1); + config.set_timeout(t); + http_listener listener(m_uri, config); + listener.open().wait(); + listener.close().wait(); + VERIFY_ARE_EQUAL(t, listener.configuration().timeout()); + } } - // assignment + TEST_FIXTURE(uri_address, listener_config_creation) { - http_listener_config config; - config.set_timeout(utility::seconds(2)); - http_listener_config assign; - assign = config; - VERIFY_ARE_EQUAL(utility::seconds(2), assign.timeout()); - } + // copy constructor + { + http_listener_config config; + config.set_timeout(utility::seconds(2)); + http_listener_config copy(config); + VERIFY_ARE_EQUAL(utility::seconds(2), copy.timeout()); + } - // move assignment - { - http_listener_config config; - config.set_timeout(utility::seconds(2)); - http_listener_config assignMove; - assignMove = std::move(config); - VERIFY_ARE_EQUAL(utility::seconds(2), assignMove.timeout()); + // move constructor + { + http_listener_config config; + config.set_timeout(utility::seconds(2)); + http_listener_config ctorMove(std::move(config)); + VERIFY_ARE_EQUAL(utility::seconds(2), ctorMove.timeout()); + } + + // assignment + { + http_listener_config config; + config.set_timeout(utility::seconds(2)); + http_listener_config assign; + assign = config; + VERIFY_ARE_EQUAL(utility::seconds(2), assign.timeout()); + } + + // move assignment + { + http_listener_config config; + config.set_timeout(utility::seconds(2)); + http_listener_config assignMove; + assignMove = std::move(config); + VERIFY_ARE_EQUAL(utility::seconds(2), assignMove.timeout()); + } } -} #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) -TEST_FIXTURE(uri_address, create_https_listener_get, "Ignore", "github 209") -{ - const char * self_signed_cert = R"( + TEST_FIXTURE(uri_address, create_https_listener_get, "Ignore", "github 209") + { + const char* self_signed_cert = R"( -----BEGIN CERTIFICATE----- MIIDlzCCAn+gAwIBAgIJAP9ZV+1X94UjMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV BAYTAkNOMQswCQYDVQQIDAJTSDELMAkGA1UEBwwCU0gxEjAQBgNVBAoMCU1JQ1JP @@ -458,7 +453,7 @@ aNAom7bdENU8uivd+vrLnG2fKvFSssjVfaXpFLKAICfTJY9A3/CWnZ1AcbE5El7A adctopihoUrlAb0= -----END CERTIFICATE----- )"; - const char * private_key = R"( + const char* private_key = R"( -----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCy7+wAD2vuMGKW vt7anPRyB4YfJL/zKVdg5vqChtu4h8zroDDQD6i8zAGlgsw0csNuyPoz0t6cwALu @@ -489,58 +484,55 @@ XzJTD4slrGSJrcpLt/g/Jqqdjg== -----END PRIVATE KEY----- )"; - auto body = utility::string_t{U("body content")}; - http_headers all_headers; - all_headers.add(U("Accept"), U("text/plain")); - all_headers.add(U("Accept-Charset"), U("utf-8")); - all_headers.add(U("Accept-Encoding"), U("gzip, deflate")); - all_headers.add(U("Accept-Language"), U("en-US")); - all_headers.add(U("Accept-Datetime"), U("Thu, 31 May 2007 20:35:00 GMT")); - all_headers.add(U("Authorization"), U("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==")); - all_headers.add(U("Cache-Control"), U("no-cache")); - all_headers.add(U("Cookie"), U("$Version=1; Skin=new;")); - all_headers.add(U("Content-Length"), body.size()); - all_headers.add(U("Content-MD5"), U("Q2hlY2sgSW50ZWdyaXR5IQ==")); - all_headers.add(U("Content-Type"), U("application/x-www-form-urlencoded")); - all_headers.add(U("Date"), U("Tue, 15 Nov 1994 08:12:31 GMT")); - all_headers.add(U("Expect"), U("100-continue")); - all_headers.add(U("Forwarded"), U("for=192.0.2.60;proto=http;by=203.0.113.43Forwarded: for=192.0.2.43, for=198.51.100.17")); - all_headers.add(U("From"), U("user@example.com")); - all_headers.add(U("Host"), U("en.wikipedia.org")); - all_headers.add(U("If-Match"), U("\"737060cd8c284d8af7ad3082f209582d\"")); - all_headers.add(U("If-Modified-Since"), U("Sat, 29 Oct 1994 19:43:31 GMT")); - all_headers.add(U("If-None-Match"), U("\"737060cd8c284d8af7ad3082f209582d\"")); - all_headers.add(U("If-Range"), U("\"737060cd8c284d8af7ad3082f209582d\"")); - all_headers.add(U("If-Unmodified-Since"), U("Sat, 29 Oct 1994 19:43:31 GMT")); - all_headers.add(U("Max-Forwards"), U("10")); - all_headers.add(U("Origin"), U("http://www.example-social-network.com")); - all_headers.add(U("Pragma"), U("no-cache")); - all_headers.add(U("Proxy-Authorization"), U("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==")); - all_headers.add(U("Range"), U("bytes=500-999")); - all_headers.add(U("Referer"), U("http://en.wikipedia.org/wiki/Main_Page")); - all_headers.add(U("TE"), U("trailers, deflate")); - all_headers.add(U("User-Agent"), U("Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0")); - all_headers.add(U("Upgrade"), U("HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11")); - all_headers.add(U("Via"), U("1.0 fred, 1.1 example.com (Apache/1.1)")); - all_headers.add(U("Warning"), U("199 Miscellaneous warning")); - - boost::asio::const_buffer cert(self_signed_cert, std::strlen(self_signed_cert)); - boost::asio::const_buffer key(private_key, std::strlen(private_key)); - - http_listener_config server_config; - server_config.set_ssl_context_callback( - [&](boost::asio::ssl::context& ctx) - { + auto body = utility::string_t {U("body content")}; + http_headers all_headers; + all_headers.add(U("Accept"), U("text/plain")); + all_headers.add(U("Accept-Charset"), U("utf-8")); + all_headers.add(U("Accept-Encoding"), U("gzip, deflate")); + all_headers.add(U("Accept-Language"), U("en-US")); + all_headers.add(U("Accept-Datetime"), U("Thu, 31 May 2007 20:35:00 GMT")); + all_headers.add(U("Authorization"), U("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==")); + all_headers.add(U("Cache-Control"), U("no-cache")); + all_headers.add(U("Cookie"), U("$Version=1; Skin=new;")); + all_headers.add(U("Content-Length"), body.size()); + all_headers.add(U("Content-MD5"), U("Q2hlY2sgSW50ZWdyaXR5IQ==")); + all_headers.add(U("Content-Type"), U("application/x-www-form-urlencoded")); + all_headers.add(U("Date"), U("Tue, 15 Nov 1994 08:12:31 GMT")); + all_headers.add(U("Expect"), U("100-continue")); + all_headers.add(U("Forwarded"), + U("for=192.0.2.60;proto=http;by=203.0.113.43Forwarded: for=192.0.2.43, for=198.51.100.17")); + all_headers.add(U("From"), U("user@example.com")); + all_headers.add(U("Host"), U("en.wikipedia.org")); + all_headers.add(U("If-Match"), U("\"737060cd8c284d8af7ad3082f209582d\"")); + all_headers.add(U("If-Modified-Since"), U("Sat, 29 Oct 1994 19:43:31 GMT")); + all_headers.add(U("If-None-Match"), U("\"737060cd8c284d8af7ad3082f209582d\"")); + all_headers.add(U("If-Range"), U("\"737060cd8c284d8af7ad3082f209582d\"")); + all_headers.add(U("If-Unmodified-Since"), U("Sat, 29 Oct 1994 19:43:31 GMT")); + all_headers.add(U("Max-Forwards"), U("10")); + all_headers.add(U("Origin"), U("http://www.example-social-network.com")); + all_headers.add(U("Pragma"), U("no-cache")); + all_headers.add(U("Proxy-Authorization"), U("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==")); + all_headers.add(U("Range"), U("bytes=500-999")); + all_headers.add(U("Referer"), U("http://en.wikipedia.org/wiki/Main_Page")); + all_headers.add(U("TE"), U("trailers, deflate")); + all_headers.add(U("User-Agent"), U("Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0")); + all_headers.add(U("Upgrade"), U("HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11")); + all_headers.add(U("Via"), U("1.0 fred, 1.1 example.com (Apache/1.1)")); + all_headers.add(U("Warning"), U("199 Miscellaneous warning")); + + boost::asio::const_buffer cert(self_signed_cert, std::strlen(self_signed_cert)); + boost::asio::const_buffer key(private_key, std::strlen(private_key)); + + http_listener_config server_config; + server_config.set_ssl_context_callback([&](boost::asio::ssl::context& ctx) { ctx.set_options(boost::asio::ssl::context::default_workarounds); ctx.use_certificate_chain(cert); ctx.use_private_key(key, boost::asio::ssl::context::pem); }); - http_listener listener(m_secure_uri, server_config); + http_listener listener(m_secure_uri, server_config); - listener.support(methods::GET, - [&](http_request request) - { + listener.support(methods::GET, [&](http_request request) { http_asserts::assert_request_equals(request, methods::GET, U("/")); for (auto&& h : all_headers) @@ -554,27 +546,27 @@ XzJTD4slrGSJrcpLt/g/Jqqdjg== request.reply(status_codes::OK); }); - listener.open().wait(); + listener.open().wait(); - client::http_client_config client_config; - client_config.set_ssl_context_callback( - [&](boost::asio::ssl::context& ctx) - { - ctx.add_certificate_authority(cert); - }); + client::http_client_config client_config; + client_config.set_ssl_context_callback( + [&](boost::asio::ssl::context& ctx) { ctx.add_certificate_authority(cert); }); - client::http_client client(m_secure_uri, client_config); - http_request msg(methods::GET); - msg.set_request_uri(U("/")); + client::http_client client(m_secure_uri, client_config); + http_request msg(methods::GET); + msg.set_request_uri(U("/")); - msg.headers() = all_headers; - msg.set_body(body); + msg.headers() = all_headers; + msg.set_body(body); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - listener.close().wait(); -} + listener.close().wait(); + } #endif } -}}}} +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/reply_helper_tests.cpp b/Release/tests/functional/http/listener/reply_helper_tests.cpp index d7a8ef5f29..0eb6733b2e 100644 --- a/Release/tests/functional/http/listener/reply_helper_tests.cpp +++ b/Release/tests/functional/http/listener/reply_helper_tests.cpp @@ -1,96 +1,104 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* reply_helper_tests.cpp -* -* Tests cases covering the reply helper functions on HTTP response. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * reply_helper_tests.cpp + * + * Tests cases covering the reply helper functions on HTTP response. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace utility; -using namespace web; +using namespace web; using namespace web::http; using namespace web::http::experimental::listener; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(reply_helper_tests) +namespace tests { - -TEST_FIXTURE(uri_address, json) +namespace functional { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - listener.support([](http_request request) - { - request.reply(status_codes::OK, json::value::parse(U("true"))).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) +namespace http +{ +namespace listener +{ +SUITE(reply_helper_tests) +{ + TEST_FIXTURE(uri_address, json) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("application/json"), U("true")); - }).wait(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - listener.close().wait(); -} + listener.support( + [](http_request request) { request.reply(status_codes::OK, json::value::parse(U("true"))).wait(); }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals( + p_response, status_codes::OK, U("application/json"), U("true")); + }) + .wait(); -TEST_FIXTURE(uri_address, string) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + listener.close().wait(); + } - listener.support([](http_request request) + TEST_FIXTURE(uri_address, string) { - std::string body("test str"); - request.reply(status_codes::OK, body).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("test str")); - }).wait(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - // content type and string body - listener.support([](http_request request) - { - utility::string_t s(U("test str")); - request.reply(status_codes::OK, s, U("custom content")).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("custom content"), U("test str")); - }).wait(); + listener.support([](http_request request) { + std::string body("test str"); + request.reply(status_codes::OK, body).wait(); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals( + p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("test str")); + }) + .wait(); - // content type and rvalue reference string body - listener.support([](http_request request) - { - request.reply(status_codes::OK, "test str", "text/plain").wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("text/plain"), U("test str")); - }).wait(); + // content type and string body + listener.support([](http_request request) { + utility::string_t s(U("test str")); + request.reply(status_codes::OK, s, U("custom content")).wait(); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals( + p_response, status_codes::OK, U("custom content"), U("test str")); + }) + .wait(); - listener.close().wait(); -} + // content type and rvalue reference string body + listener.support( + [](http_request request) { request.reply(status_codes::OK, "test str", "text/plain").wait(); }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("text/plain"), U("test str")); + }) + .wait(); + listener.close().wait(); + } } -}}}} \ No newline at end of file +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/request_extract_tests.cpp b/Release/tests/functional/http/listener/request_extract_tests.cpp index af06412c83..910c979258 100644 --- a/Release/tests/functional/http/listener/request_extract_tests.cpp +++ b/Release/tests/functional/http/listener/request_extract_tests.cpp @@ -1,17 +1,17 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* request_extract_tests.cpp -* -* Tests cases for covering calling extract_ overloads on HTTP request. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * request_extract_tests.cpp + * + * Tests cases for covering calling extract_ overloads on HTTP request. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -24,162 +24,169 @@ using namespace utility::conversions; using namespace tests::common::utilities; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(request_extract_tests) +namespace tests { - -TEST_FIXTURE(uri_address, extract_string) +namespace functional { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - std::string data("HEHEHE"); - - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, U("PUT"), U("/"), to_string_t(data)); - VERIFY_ARE_EQUAL(U("text/plain"), request.headers().content_type()); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("text/plain"), data)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, extract_string_force) +namespace http { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - std::string data("HEHEHE"); - - listener.support([&](http_request request) - { - VERIFY_ARE_EQUAL(to_string_t(data), request.extract_string(true).get()); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("unknown charset"), data)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, extract_json) +namespace listener { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - json::value j(true); - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, U("PUT"), U("/")); - VERIFY_ARE_EQUAL(U("application/json"), request.headers().content_type()); - const json::value j_found = request.extract_json().get(); - VERIFY_ARE_EQUAL(j.serialize(), j_found.serialize()); - request.reply(status_codes::OK); - }); - std::string data = to_utf8string(j.serialize()); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("application/json"), data)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, extract_json_force) +SUITE(request_extract_tests) { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - json::value j(true); - listener.support([&](http_request request) + TEST_FIXTURE(uri_address, extract_string) { - const json::value j_found = request.extract_json(true).get(); - VERIFY_ARE_EQUAL(j.serialize(), j_found.serialize()); - request.reply(status_codes::OK); - }); - std::string data = to_utf8string(j.serialize()); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("unknown charset"), data)); - p_client->next_response().then([](test_response *p_response) + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + std::string data("HEHEHE"); + + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, U("PUT"), U("/"), to_string_t(data)); + VERIFY_ARE_EQUAL(U("text/plain"), request.headers().content_type()); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("text/plain"), data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, extract_string_force) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, empty_vector) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - std::string data(""); - - listener.support([&](http_request request) + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + std::string data("HEHEHE"); + + listener.support([&](http_request request) { + VERIFY_ARE_EQUAL(to_string_t(data), request.extract_string(true).get()); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("unknown charset"), data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, extract_json) { - http_asserts::assert_request_equals(request, U("PUT"), U("/")); - VERIFY_ARE_EQUAL(U("text/plain"), request.headers().content_type()); - std::vector vec = request.extract_vector().get(); - VERIFY_ARE_EQUAL(vec.size(), 0); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("text/plain"), data)); - p_client->next_response().then([](test_response *p_response) + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + json::value j(true); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, U("PUT"), U("/")); + VERIFY_ARE_EQUAL(U("application/json"), request.headers().content_type()); + const json::value j_found = request.extract_json().get(); + VERIFY_ARE_EQUAL(j.serialize(), j_found.serialize()); + request.reply(status_codes::OK); + }); + std::string data = to_utf8string(j.serialize()); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("application/json"), data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, extract_json_force) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, extract_vector) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - std::string data("HEHEHE"); - - listener.support([&](http_request request) + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + json::value j(true); + listener.support([&](http_request request) { + const json::value j_found = request.extract_json(true).get(); + VERIFY_ARE_EQUAL(j.serialize(), j_found.serialize()); + request.reply(status_codes::OK); + }); + std::string data = to_utf8string(j.serialize()); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("unknown charset"), data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, empty_vector) { - http_asserts::assert_request_equals(request, U("PUT"), U("/")); - VERIFY_ARE_EQUAL(U("text/plain"), request.headers().content_type()); - std::vector vec = request.extract_vector().get(); - VERIFY_ARE_EQUAL(vec.size(), data.size()); - VERIFY_ARE_EQUAL('H', vec[0]); - VERIFY_ARE_EQUAL('E', vec[1]); - VERIFY_ARE_EQUAL('H', vec[2]); - VERIFY_ARE_EQUAL('E', vec[3]); - VERIFY_ARE_EQUAL('H', vec[4]); - VERIFY_ARE_EQUAL('E', vec[5]); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("text/plain"), data)); - p_client->next_response().then([](test_response *p_response) + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + std::string data(""); + + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, U("PUT"), U("/")); + VERIFY_ARE_EQUAL(U("text/plain"), request.headers().content_type()); + std::vector vec = request.extract_vector().get(); + VERIFY_ARE_EQUAL(vec.size(), 0); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("text/plain"), data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, extract_vector) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + std::string data("HEHEHE"); + + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, U("PUT"), U("/")); + VERIFY_ARE_EQUAL(U("text/plain"), request.headers().content_type()); + std::vector vec = request.extract_vector().get(); + VERIFY_ARE_EQUAL(vec.size(), data.size()); + VERIFY_ARE_EQUAL('H', vec[0]); + VERIFY_ARE_EQUAL('E', vec[1]); + VERIFY_ARE_EQUAL('H', vec[2]); + VERIFY_ARE_EQUAL('E', vec[3]); + VERIFY_ARE_EQUAL('H', vec[4]); + VERIFY_ARE_EQUAL('E', vec[5]); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""), U("text/plain"), data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + listener.close().wait(); + } } -}}}} \ No newline at end of file +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/request_handler_tests.cpp b/Release/tests/functional/http/listener/request_handler_tests.cpp index 74137193ae..f0442d0a9f 100644 --- a/Release/tests/functional/http/listener/request_handler_tests.cpp +++ b/Release/tests/functional/http/listener/request_handler_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases for covering the http_listener class itself. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases for covering the http_listener class itself. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,525 +20,542 @@ using namespace web::http::experimental::listener; using namespace tests::common::utilities; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -std::shared_ptr uri_address::s_dummy_listener; - -SUITE(request_handler_tests) +namespace tests { - -TEST_FIXTURE(uri_address, support) +namespace functional { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - listener.support(U("CUSTOM"), [](http_request request) - { - http_asserts::assert_request_equals(request, U("CUSTOM"), U("/")); - request.reply(status_codes::OK); - }); - listener.support(methods::PUT, [](http_request request) - { - http_asserts::assert_request_equals(request, methods::PUT, U("/")); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::DEL, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(U("CUSTOM"), U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - // Add one with a different case. - listener.support(U("CUSToM"), [](http_request request) - { - http_asserts::assert_request_equals(request, U("CUSToM"), U("/")); - request.reply(status_codes::Gone); - }); - VERIFY_ARE_EQUAL(0, p_client->request(U("CUSToM"), U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::Gone); - }).wait(); - - // Add a general handler - listener.support([](http_request request) - { - http_asserts::assert_request_equals(request, U("CuSToM"), U("/")); - request.reply(status_codes::Created); - }); - VERIFY_ARE_EQUAL(0, p_client->request(U("CUSToM"), U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::Gone); - }).wait(); - VERIFY_ARE_EQUAL(0, p_client->request(U("CuSToM"), U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::Created); - }).wait(); - listener.close().wait(); -} +namespace http +{ +namespace listener +{ +std::shared_ptr uri_address::s_dummy_listener; -TEST_FIXTURE(uri_address, exceptions_in_handler) +SUITE(request_handler_tests) { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + TEST_FIXTURE(uri_address, support) + { + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + listener.support(U("CUSTOM"), [](http_request request) { + http_asserts::assert_request_equals(request, U("CUSTOM"), U("/")); + request.reply(status_codes::OK); + }); + listener.support(methods::PUT, [](http_request request) { + http_asserts::assert_request_equals(request, methods::PUT, U("/")); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(methods::DEL, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::MethodNotAllowed); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(U("CUSTOM"), U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // Add one with a different case. + listener.support(U("CUSToM"), [](http_request request) { + http_asserts::assert_request_equals(request, U("CUSToM"), U("/")); + request.reply(status_codes::Gone); + }); + VERIFY_ARE_EQUAL(0, p_client->request(U("CUSToM"), U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::Gone); + }) + .wait(); + + // Add a general handler + listener.support([](http_request request) { + http_asserts::assert_request_equals(request, U("CuSToM"), U("/")); + request.reply(status_codes::Created); + }); + VERIFY_ARE_EQUAL(0, p_client->request(U("CUSToM"), U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::Gone); + }) + .wait(); + VERIFY_ARE_EQUAL(0, p_client->request(U("CuSToM"), U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::Created); + }) + .wait(); + listener.close().wait(); + } - // throw exception - listener.support(methods::GET, [](http_request request) - { - http_asserts::assert_request_equals(request, U("GET"), U("/")); - throw std::runtime_error(""); - }); - VERIFY_ARE_EQUAL(0, p_client->request(U("GET"), U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::InternalError); - }).wait(); + TEST_FIXTURE(uri_address, exceptions_in_handler) + { + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + // throw exception + listener.support(methods::GET, [](http_request request) { + http_asserts::assert_request_equals(request, U("GET"), U("/")); + throw std::runtime_error(""); + }); + VERIFY_ARE_EQUAL(0, p_client->request(U("GET"), U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::InternalError); + }) + .wait(); + + // throw exception, after replying first + listener.support(methods::PUT, [](http_request request) { + http_asserts::assert_request_equals(request, U("PUT"), U("/")); + request.reply(status_codes::OK); + throw 55; + }); + VERIFY_ARE_EQUAL(0, p_client->request(U("PUT"), U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + listener.close().wait(); + } - // throw exception, after replying first - listener.support(methods::PUT, [](http_request request) + TEST_FIXTURE(uri_address, handle_options) { - http_asserts::assert_request_equals(request, U("PUT"), U("/")); - request.reply(status_codes::OK); - throw 55; - }); - VERIFY_ARE_EQUAL(0, p_client->request(U("PUT"), U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - listener.close().wait(); -} + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); -TEST_FIXTURE(uri_address, handle_options) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - listener.support(methods::GET, [](http_request){}); - listener.support(methods::PUT, [](http_request){}); - VERIFY_ARE_EQUAL(0, p_client->request(methods::OPTIONS, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - VERIFY_ARE_EQUAL(U("GET, PUT"), p_response->m_headers[U("Allow")]); - }).wait(); + listener.support(methods::GET, [](http_request) {}); + listener.support(methods::PUT, [](http_request) {}); + VERIFY_ARE_EQUAL(0, p_client->request(methods::OPTIONS, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + VERIFY_ARE_EQUAL(U("GET, PUT"), p_response->m_headers[U("Allow")]); + }) + .wait(); + + // try overridding the default OPTIONS handler + listener.support(methods::OPTIONS, [](http_request request) { + http_asserts::assert_request_equals(request, methods::OPTIONS, U("/")); + request.reply(status_codes::NoContent); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::OPTIONS, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); + }) + .wait(); + listener.close().wait(); + } - // try overridding the default OPTIONS handler - listener.support(methods::OPTIONS, [](http_request request) + TEST_FIXTURE(uri_address, handle_trace) { - http_asserts::assert_request_equals(request, methods::OPTIONS, U("/")); - request.reply(status_codes::NoContent); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::OPTIONS, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); - }).wait(); - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, handle_trace) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - VERIFY_ARE_EQUAL(0, p_client->request(methods::TRCE, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - std::string utf8_response; - utf8_response.assign(p_response->m_data.begin(), p_response->m_data.end()); + VERIFY_ARE_EQUAL(0, p_client->request(methods::TRCE, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + std::string utf8_response; + utf8_response.assign(p_response->m_data.begin(), p_response->m_data.end()); #ifdef _WIN32 - VERIFY_ARE_EQUAL("TRACE / HTTP/1.1\r\nConnection: Keep-Alive\r\nHost: localhost:34567\r\nUser-Agent: test_http_client\r\n\r\n", utf8_response); + VERIFY_ARE_EQUAL("TRACE / HTTP/1.1\r\nConnection: Keep-Alive\r\nHost: localhost:34567\r\nUser-Agent: " + "test_http_client\r\n\r\n", + utf8_response); #else - VERIFY_ARE_EQUAL("TRACE / HTTP/1.1\r\nConnection: Keep-Alive\r\nContent-Length: 0\r\nContent-Type: text/plain; charset=utf-8\r\nHost: localhost:34567\r\nUser-Agent: test_http_client\r\n\r\n", utf8_response); + VERIFY_ARE_EQUAL( + "TRACE / HTTP/1.1\r\nConnection: Keep-Alive\r\nContent-Length: 0\r\nContent-Type: text/plain; " + "charset=utf-8\r\nHost: localhost:34567\r\nUser-Agent: test_http_client\r\n\r\n", + utf8_response); #endif - }).wait(); - - // try overridding the default OPTIONS handler - listener.support(methods::TRCE, [](http_request request) - { - http_asserts::assert_request_equals(request, methods::TRCE, U("/")); - request.reply(status_codes::NoContent); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::TRCE, U("/"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); - }).wait(); - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, async_request_handler) -{ - http_listener listener(m_uri); - pplx::extensibility::event_t e; - listener.support([&e](http_request request) - { - e.set(); - request.reply(status_codes::OK).wait(); - }); - listener.open().wait(); - - client::http_client client(m_uri); - auto buf = streams::producer_consumer_buffer(); - pplx::task response = client.request(methods::PUT, U("/"), buf.create_istream(), U("text/plain")); - - e.wait(); - buf.close(std::ios_base::out).wait(); - response.wait(); - listener.close().wait(); -} - - -TEST_FIXTURE(uri_address, multiple_listeners) -{ - http_listener listener1(U("http://localhost:45678/path1")); - http_listener listener2(U("http://localhost:45678/path1/path2")); - http_listener listener3(U("http://localhost:45678/path3")); - listener1.open().wait(); - listener2.open().wait(); - listener3.open().wait(); - - test_http_client::scoped_client client(U("http://localhost:45678")); - test_http_client * p_client = client.client(); - - // send a request to the first listener - listener1.support(methods::GET, [](http_request request) - { - http_asserts::assert_request_equals(request, methods::GET, U("/")); - request.reply(status_codes::NoContent); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); - }).wait(); - - // send a request to the second listener - listener2.support(methods::PUT, [](http_request request) - { - http_asserts::assert_request_equals(request, methods::PUT, U("/path4")); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/path1/path2/path4"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - // send a request to the third listener - listener3.support(methods::POST, [](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(status_codes::Created); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U("/path3"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::Created); - }).wait(); - - // Remove the second listener and send a request again. - listener2.close().wait(); - listener1.support(methods::GET, [](http_request request) - { - http_asserts::assert_request_equals(request, methods::GET, U("/path2/path4")); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/path2/path4"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + }) + .wait(); + + // try overridding the default OPTIONS handler + listener.support(methods::TRCE, [](http_request request) { + http_asserts::assert_request_equals(request, methods::TRCE, U("/")); + request.reply(status_codes::NoContent); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::TRCE, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); + }) + .wait(); + listener.close().wait(); + } - listener3.close().wait(); - listener1.close().wait(); -} + TEST_FIXTURE(uri_address, async_request_handler) + { + http_listener listener(m_uri); + pplx::extensibility::event_t e; + listener.support([&e](http_request request) { + e.set(); + request.reply(status_codes::OK).wait(); + }); + listener.open().wait(); + + client::http_client client(m_uri); + auto buf = streams::producer_consumer_buffer(); + pplx::task response = + client.request(methods::PUT, U("/"), buf.create_istream(), U("text/plain")); + + e.wait(); + buf.close(std::ios_base::out).wait(); + response.wait(); + listener.close().wait(); + } -TEST_FIXTURE(uri_address, unregister_while_processing) -{ - http_listener listener1(U("http://localhost:45679/path1")); - http_listener listener2(U("http://localhost:45679/path1/path2")); - listener1.open().wait(); - listener2.open().wait(); - - test_http_client::scoped_client client1(U("http://localhost:45679")); - test_http_client * p_client1 = client1.client(); - test_http_client::scoped_client client2(U("http://localhost:45679")); - test_http_client * p_client2 = client2.client(); - - // first listener is used to wait until a request comes into the second - // and then will try to close the second. - pplx::extensibility::event_t secondRequest; - listener1.support(methods::GET, [&](http_request request) - { - http_asserts::assert_request_equals(request, methods::GET, U("/")); - secondRequest.wait(); + TEST_FIXTURE(uri_address, multiple_listeners) + { + http_listener listener1(U("http://localhost:45678/path1")); + http_listener listener2(U("http://localhost:45678/path1/path2")); + http_listener listener3(U("http://localhost:45678/path3")); + listener1.open().wait(); + listener2.open().wait(); + listener3.open().wait(); + + test_http_client::scoped_client client(U("http://localhost:45678")); + test_http_client* p_client = client.client(); + + // send a request to the first listener + listener1.support(methods::GET, [](http_request request) { + http_asserts::assert_request_equals(request, methods::GET, U("/")); + request.reply(status_codes::NoContent); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); + }) + .wait(); + + // send a request to the second listener + listener2.support(methods::PUT, [](http_request request) { + http_asserts::assert_request_equals(request, methods::PUT, U("/path4")); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/path1/path2/path4"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // send a request to the third listener + listener3.support(methods::POST, [](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(status_codes::Created); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::POST, U("/path3"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::Created); + }) + .wait(); + + // Remove the second listener and send a request again. listener2.close().wait(); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client1->request(methods::GET, U("/path1"))); - listener2.support(methods::GET, [&](http_request request) - { - http_asserts::assert_request_equals(request, methods::GET, U("/")); - secondRequest.set(); - os_utilities::sleep(200); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client2->request(methods::GET, U("/path1/path2/"))); - p_client1->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - p_client2->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - listener1.close().wait(); -} - -TEST_FIXTURE(uri_address, multiple_requests) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - test_http_client::scoped_client client2(m_uri); - test_http_client * p_client2 = client2.client(); - test_http_client::scoped_client client3(m_uri); - test_http_client * p_client3 = client3.client(); - - volatile unsigned long requestCount = 0; - listener.support(methods::GET, [&](http_request request) - { - http_asserts::assert_request_equals(request, methods::GET, U("/path1")); - os_utilities::interlocked_increment(&requestCount); - while(requestCount != 3) - { - os_utilities::sleep(1); - } - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); - VERIFY_ARE_EQUAL(0, p_client2->request(methods::GET, U("/path1"))); - VERIFY_ARE_EQUAL(0, p_client3->request(methods::GET, U("/path1"))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - p_client2->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - p_client3->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + listener1.support(methods::GET, [](http_request request) { + http_asserts::assert_request_equals(request, methods::GET, U("/path2/path4")); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1/path2/path4"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); - listener.close().wait(); -} + listener3.close().wait(); + listener1.close().wait(); + } -TEST_FIXTURE(uri_address, multiple_clients_multiple_requests) -{ - http_listener listener(m_uri); - listener.open().wait(); - const size_t NUM_CLIENTS = 10; - std::vector> clients; - for(size_t i = 0; i < NUM_CLIENTS; ++i) - { - std::unique_ptr client(new test_http_client(m_uri)); - VERIFY_ARE_EQUAL(0, client->open()); - clients.push_back(std::move(client)); + TEST_FIXTURE(uri_address, unregister_while_processing) + { + http_listener listener1(U("http://localhost:45679/path1")); + http_listener listener2(U("http://localhost:45679/path1/path2")); + listener1.open().wait(); + listener2.open().wait(); + + test_http_client::scoped_client client1(U("http://localhost:45679")); + test_http_client* p_client1 = client1.client(); + test_http_client::scoped_client client2(U("http://localhost:45679")); + test_http_client* p_client2 = client2.client(); + + // first listener is used to wait until a request comes into the second + // and then will try to close the second. + pplx::extensibility::event_t secondRequest; + listener1.support(methods::GET, [&](http_request request) { + http_asserts::assert_request_equals(request, methods::GET, U("/")); + secondRequest.wait(); + listener2.close().wait(); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client1->request(methods::GET, U("/path1"))); + listener2.support(methods::GET, [&](http_request request) { + http_asserts::assert_request_equals(request, methods::GET, U("/")); + secondRequest.set(); + os_utilities::sleep(200); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client2->request(methods::GET, U("/path1/path2/"))); + p_client1->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + p_client2->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + listener1.close().wait(); } - listener.support(methods::GET, [&](http_request request) - { - http_asserts::assert_request_equals(request, methods::GET, U("/")); - request.reply(status_codes::OK); - }); - for(size_t j = 0; j < 10; ++j) - { - std::vector> requests; - for(size_t i = 0; i < NUM_CLIENTS; ++i) - { - VERIFY_ARE_EQUAL(0, clients[i]->request(methods::GET, U("/"))); - requests.push_back(clients[i]->next_response().then([&](test_response *p_response) + TEST_FIXTURE(uri_address, multiple_requests) + { + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + test_http_client::scoped_client client2(m_uri); + test_http_client* p_client2 = client2.client(); + test_http_client::scoped_client client3(m_uri); + test_http_client* p_client3 = client3.client(); + + volatile unsigned long requestCount = 0; + listener.support(methods::GET, [&](http_request request) { + http_asserts::assert_request_equals(request, methods::GET, U("/path1")); + os_utilities::interlocked_increment(&requestCount); + while (requestCount != 3) { + os_utilities::sleep(1); + } + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); + VERIFY_ARE_EQUAL(0, p_client2->request(methods::GET, U("/path1"))); + VERIFY_ARE_EQUAL(0, p_client3->request(methods::GET, U("/path1"))); + p_client->next_response() + .then([](test_response* p_response) { http_asserts::assert_test_response_equals(p_response, status_codes::OK); - })); - } - pplx::when_all(requests.begin(), requests.end()).wait(); - } + }) + .wait(); + p_client2->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + p_client3->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); - for(size_t i = 0; i < NUM_CLIENTS; ++i) - { - VERIFY_ARE_EQUAL(0, clients[i]->close()); + listener.close().wait(); } - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, test_leaks) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - // pick a large number to see leaks easier - const size_t nbytes = 1024*1000; - listener.support(methods::PUT, [&](http_request message) + TEST_FIXTURE(uri_address, multiple_clients_multiple_requests) { - while(message.body().streambuf().in_avail() < nbytes); - - utility::string_t request = U("unknown"); - auto it = message.headers().find(U("ClientID")); - if( it != message.headers().end() ) + http_listener listener(m_uri); + listener.open().wait(); + const size_t NUM_CLIENTS = 10; + std::vector> clients; + for (size_t i = 0; i < NUM_CLIENTS; ++i) { - message.reply(status_codes::OK, U("Unknown command")); + std::unique_ptr client(new test_http_client(m_uri)); + VERIFY_ARE_EQUAL(0, client->open()); + clients.push_back(std::move(client)); } - else + + listener.support(methods::GET, [&](http_request request) { + http_asserts::assert_request_equals(request, methods::GET, U("/")); + request.reply(status_codes::OK); + }); + for (size_t j = 0; j < 10; ++j) { - message.reply(status_codes::OK, U("ClientID missing")); + std::vector> requests; + for (size_t i = 0; i < NUM_CLIENTS; ++i) + { + VERIFY_ARE_EQUAL(0, clients[i]->request(methods::GET, U("/"))); + requests.push_back(clients[i]->next_response().then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + })); + } + pplx::when_all(requests.begin(), requests.end()).wait(); } - }); - - const int N = 1; // use large number of iterations to test for leaks - for(int i = 0; i < N; ++i) - { - std::map headers; - headers[U("ClientID")] = U("123"); - headers[U("Request")] = U("Upload"); - headers[U("ImgNr")] = U("1"); - - utility::char_t* pdata = new utility::char_t[nbytes]; - // this help recognizing the leaked memory in the CRT/VLD dump - for(int j = 0; j < nbytes; j++) pdata[j] = U('a') + (j % 26); - std::string data(pdata, pdata + nbytes); - delete[] pdata; - - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/path1"), headers, data)); - p_client->next_response().then([](test_response *p_response) + for (size_t i = 0; i < NUM_CLIENTS; ++i) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + VERIFY_ARE_EQUAL(0, clients[i]->close()); + } + listener.close().wait(); } - listener.close().wait(); -} -TEST_FIXTURE(uri_address, http_version) -{ - // formatting should succeed - VERIFY_IS_TRUE("HTTP/0.9" == http_versions::HTTP_0_9.to_utf8string()); - VERIFY_IS_TRUE("HTTP/1.0" == http_versions::HTTP_1_0.to_utf8string()); - VERIFY_IS_TRUE("HTTP/1.1" == http_versions::HTTP_1_1.to_utf8string()); - VERIFY_IS_TRUE("HTTP/12.3" == (http_version{ 12, 3 }).to_utf8string()); - // parsing should succeed - VERIFY_IS_TRUE(http_version::from_string("HTTP/0.9") == http_versions::HTTP_0_9); - VERIFY_IS_TRUE(http_version::from_string("HTTP/1.0") == http_versions::HTTP_1_0); - VERIFY_IS_TRUE(http_version::from_string("HTTP/1.1") == http_versions::HTTP_1_1); - VERIFY_IS_TRUE((http_version::from_string("HTTP/12.3") == http_version{ 12, 3 })); - // parsing should fail - http_version unknown = { 0, 0 }; - VERIFY_IS_TRUE(http_version::from_string("http/12.3") == unknown); - VERIFY_IS_TRUE(http_version::from_string("HTTP/12.3foo") == unknown); - VERIFY_IS_TRUE(http_version::from_string("HTTP/12.") == unknown); - VERIFY_IS_TRUE(http_version::from_string("HTTP/12") == unknown); - VERIFY_IS_TRUE(http_version::from_string("HTTP/.3") == unknown); - VERIFY_IS_TRUE(http_version::from_string("HTTP/") == unknown); - VERIFY_IS_TRUE(http_version::from_string("HTTP") == unknown); - VERIFY_IS_TRUE(http_version::from_string("HTTP") == unknown); - VERIFY_IS_TRUE(http_version::from_string("foo") == unknown); - VERIFY_IS_TRUE(http_version::from_string("") == unknown); - - http_listener listener(U("http://localhost:45678/path1")); - listener.open().wait(); - - test_http_client::scoped_client client(U("http://localhost:45678")); - test_http_client * p_client = client.client(); - - volatile unsigned long requestCount = 0; - - listener.support(methods::GET, [&requestCount](http_request request) + TEST_FIXTURE(uri_address, test_leaks) { - const auto& httpVersion = request.http_version(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - // All clients currently use HTTP/1.1 - VERIFY_IS_TRUE(httpVersion == http_versions::HTTP_1_1); + // pick a large number to see leaks easier + const size_t nbytes = 1024 * 1000; - os_utilities::interlocked_increment(&requestCount); - request.reply(status_codes::NoContent); - }); + listener.support(methods::PUT, [&](http_request message) { + while (message.body().streambuf().in_avail() < nbytes) + ; - // Send a request to the listener - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); - - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); - }).wait(); + utility::string_t request = U("unknown"); + auto it = message.headers().find(U("ClientID")); + if (it != message.headers().end()) + { + message.reply(status_codes::OK, U("Unknown command")); + } + else + { + message.reply(status_codes::OK, U("ClientID missing")); + } + }); - VERIFY_IS_TRUE(requestCount >= 1); - listener.close().wait(); -} + const int N = 1; // use large number of iterations to test for leaks + for (int i = 0; i < N; ++i) + { + std::map headers; + headers[U("ClientID")] = U("123"); + headers[U("Request")] = U("Upload"); + headers[U("ImgNr")] = U("1"); + + utility::char_t* pdata = new utility::char_t[nbytes]; + + // this help recognizing the leaked memory in the CRT/VLD dump + for (int j = 0; j < nbytes; j++) + pdata[j] = U('a') + (j % 26); + std::string data(pdata, pdata + nbytes); + delete[] pdata; + + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U("/path1"), headers, data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + } + listener.close().wait(); + } -TEST_FIXTURE(uri_address, remote_address) -{ - http_listener listener(U("http://localhost:45678/path1")); - listener.open().wait(); + TEST_FIXTURE(uri_address, http_version) + { + // formatting should succeed + VERIFY_IS_TRUE("HTTP/0.9" == http_versions::HTTP_0_9.to_utf8string()); + VERIFY_IS_TRUE("HTTP/1.0" == http_versions::HTTP_1_0.to_utf8string()); + VERIFY_IS_TRUE("HTTP/1.1" == http_versions::HTTP_1_1.to_utf8string()); + VERIFY_IS_TRUE("HTTP/12.3" == (http_version {12, 3}).to_utf8string()); + // parsing should succeed + VERIFY_IS_TRUE(http_version::from_string("HTTP/0.9") == http_versions::HTTP_0_9); + VERIFY_IS_TRUE(http_version::from_string("HTTP/1.0") == http_versions::HTTP_1_0); + VERIFY_IS_TRUE(http_version::from_string("HTTP/1.1") == http_versions::HTTP_1_1); + VERIFY_IS_TRUE((http_version::from_string("HTTP/12.3") == http_version {12, 3})); + // parsing should fail + http_version unknown = {0, 0}; + VERIFY_IS_TRUE(http_version::from_string("http/12.3") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/12.3foo") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/12.") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/12") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/.3") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP") == unknown); + VERIFY_IS_TRUE(http_version::from_string("foo") == unknown); + VERIFY_IS_TRUE(http_version::from_string("") == unknown); + + http_listener listener(U("http://localhost:45678/path1")); + listener.open().wait(); + + test_http_client::scoped_client client(U("http://localhost:45678")); + test_http_client* p_client = client.client(); + + volatile unsigned long requestCount = 0; + + listener.support(methods::GET, [&requestCount](http_request request) { + const auto& httpVersion = request.http_version(); + + // All clients currently use HTTP/1.1 + VERIFY_IS_TRUE(httpVersion == http_versions::HTTP_1_1); + + os_utilities::interlocked_increment(&requestCount); + request.reply(status_codes::NoContent); + }); + + // Send a request to the listener + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); + + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); + }) + .wait(); + + VERIFY_IS_TRUE(requestCount >= 1); + listener.close().wait(); + } - test_http_client::scoped_client client(U("http://localhost:45678")); - test_http_client * p_client = client.client(); + TEST_FIXTURE(uri_address, remote_address) + { + http_listener listener(U("http://localhost:45678/path1")); + listener.open().wait(); - volatile unsigned long requestCount = 0; + test_http_client::scoped_client client(U("http://localhost:45678")); + test_http_client* p_client = client.client(); - listener.support(methods::GET, [&requestCount](http_request request) - { - const string_t& remoteAddr = request.remote_address(); - const string_t& localhost4 = string_t(U("127.0.0.1")); - const string_t& localhost6 = string_t(U("::1")); + volatile unsigned long requestCount = 0; - // We can't guarantee that the host has both IPv4 and IPv6 available, so check for either IP - VERIFY_IS_TRUE((remoteAddr == localhost4) || (remoteAddr == localhost6)); + listener.support(methods::GET, [&requestCount](http_request request) { + const string_t& remoteAddr = request.remote_address(); + const string_t& localhost4 = string_t(U("127.0.0.1")); + const string_t& localhost6 = string_t(U("::1")); - os_utilities::interlocked_increment(&requestCount); - request.reply(status_codes::NoContent); - }); + // We can't guarantee that the host has both IPv4 and IPv6 available, so check for either IP + VERIFY_IS_TRUE((remoteAddr == localhost4) || (remoteAddr == localhost6)); - // Send a request to the listener - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); + os_utilities::interlocked_increment(&requestCount); + request.reply(status_codes::NoContent); + }); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); - }).wait(); + // Send a request to the listener + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); - VERIFY_IS_TRUE(requestCount >= 1); - listener.close().wait(); -} + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); + }) + .wait(); + VERIFY_IS_TRUE(requestCount >= 1); + listener.close().wait(); + } } -}}}} +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/request_relative_uri_tests.cpp b/Release/tests/functional/http/listener/request_relative_uri_tests.cpp index 5ea969b547..4b8aaf0903 100644 --- a/Release/tests/functional/http/listener/request_relative_uri_tests.cpp +++ b/Release/tests/functional/http/listener/request_relative_uri_tests.cpp @@ -1,17 +1,17 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* request_relative_uri_tests.cpp -* -* Tests cases the combinations of base uri and relative uri with incoming requests to the http_listener. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * request_relative_uri_tests.cpp + * + * Tests cases the combinations of base uri and relative uri with incoming requests to the http_listener. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,122 +20,125 @@ using namespace web::http::experimental::listener; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(request_relative_uri_tests) +namespace tests { - -TEST_FIXTURE(uri_address, empty_base_uri) +namespace functional { - // listen on empty, request /path1/path2 - http_listener listener(m_uri); - listener.open().wait(); - test_http_client client(m_uri); - VERIFY_ARE_EQUAL(0, client.open()); - listener.support([](http_request request) - { - VERIFY_ARE_EQUAL(U("/path1/path2"), request.request_uri().path()); - VERIFY_ARE_EQUAL(U("/path1/path2"), request.relative_uri().to_string()); - request.reply(status_codes::OK).wait(); - }); - VERIFY_ARE_EQUAL(0, client.request(methods::GET, U("/path1/path2"))); - client.next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, client.close()); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, nested_paths) +namespace http { - // listen on /path1, request /path1/path2 - http_listener listener(web::http::uri_builder(m_uri).append_path(U("/path1")).to_uri()); - listener.open().wait(); - test_http_client client(m_uri); - VERIFY_ARE_EQUAL(0, client.open()); - listener.support([](http_request request) - { - VERIFY_ARE_EQUAL(U("/path1/path2"), request.request_uri().path()); - VERIFY_ARE_EQUAL(U("/path2"), request.relative_uri().to_string()); - request.reply(status_codes::OK).wait(); - }); - VERIFY_ARE_EQUAL(0, client.request(methods::GET, U("/path1/path2"))); - client.next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, client.close()); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, nested_paths_encoding) +namespace listener { - // listen on /path1%20/path2%20, request /path1%20/path2%20/path%203 - http_listener listener(web::http::uri_builder(m_uri).append_path(U("/path1%20/path2%20")).to_uri()); - listener.open().wait(); - test_http_client client(m_uri); - VERIFY_ARE_EQUAL(0, client.open()); - listener.support([](http_request request) - { - VERIFY_ARE_EQUAL(U("/path1%20/path2%20/path3%20"), request.request_uri().path()); - VERIFY_ARE_EQUAL(U("/path3 "), web::http::uri::decode(request.relative_uri().to_string())); - request.reply(status_codes::OK).wait(); - }); - VERIFY_ARE_EQUAL(0, client.request(methods::GET, U("/path1%20/path2%20/path3%20"))); - client.next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - VERIFY_ARE_EQUAL(0, client.close()); - - listener.close().wait(); -} - -TEST(listener_uri_empty_path) +SUITE(request_relative_uri_tests) { - uri address(U("http://localhost:45678")); - http_listener listener(address); - listener.open().wait(); - test_http_client::scoped_client client(address); - test_http_client * p_client = client.client(); - - listener.support([](http_request request) + TEST_FIXTURE(uri_address, empty_base_uri) { - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); - p_client->next_response().then([](test_response *p_response) + // listen on empty, request /path1/path2 + http_listener listener(m_uri); + listener.open().wait(); + test_http_client client(m_uri); + VERIFY_ARE_EQUAL(0, client.open()); + listener.support([](http_request request) { + VERIFY_ARE_EQUAL(U("/path1/path2"), request.request_uri().path()); + VERIFY_ARE_EQUAL(U("/path1/path2"), request.relative_uri().to_string()); + request.reply(status_codes::OK).wait(); + }); + VERIFY_ARE_EQUAL(0, client.request(methods::GET, U("/path1/path2"))); + client.next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, client.close()); + + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, nested_paths) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - -TEST(listener_invalid_encoded_uri) -{ - uri address(U("http://localhost:45678")); - http_listener listener(address); - listener.open().wait(); - test_http_client::scoped_client client(address); - test_http_client * p_client = client.client(); - - listener.support([](http_request request) + // listen on /path1, request /path1/path2 + http_listener listener(web::http::uri_builder(m_uri).append_path(U("/path1")).to_uri()); + listener.open().wait(); + test_http_client client(m_uri); + VERIFY_ARE_EQUAL(0, client.open()); + listener.support([](http_request request) { + VERIFY_ARE_EQUAL(U("/path1/path2"), request.request_uri().path()); + VERIFY_ARE_EQUAL(U("/path2"), request.relative_uri().to_string()); + request.reply(status_codes::OK).wait(); + }); + VERIFY_ARE_EQUAL(0, client.request(methods::GET, U("/path1/path2"))); + client.next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, client.close()); + + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, nested_paths_encoding) { - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/%invalid/uri"))); - p_client->next_response().then([](test_response *p_response) + // listen on /path1%20/path2%20, request /path1%20/path2%20/path%203 + http_listener listener(web::http::uri_builder(m_uri).append_path(U("/path1%20/path2%20")).to_uri()); + listener.open().wait(); + test_http_client client(m_uri); + VERIFY_ARE_EQUAL(0, client.open()); + listener.support([](http_request request) { + VERIFY_ARE_EQUAL(U("/path1%20/path2%20/path3%20"), request.request_uri().path()); + VERIFY_ARE_EQUAL(U("/path3 "), web::http::uri::decode(request.relative_uri().to_string())); + request.reply(status_codes::OK).wait(); + }); + VERIFY_ARE_EQUAL(0, client.request(methods::GET, U("/path1%20/path2%20/path3%20"))); + client.next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + VERIFY_ARE_EQUAL(0, client.close()); + + listener.close().wait(); + } + + TEST(listener_uri_empty_path) { - http_asserts::assert_test_response_equals(p_response, status_codes::BadRequest); - }).wait(); - - listener.close().wait(); -} - + uri address(U("http://localhost:45678")); + http_listener listener(address); + listener.open().wait(); + test_http_client::scoped_client client(address); + test_http_client* p_client = client.client(); + + listener.support([](http_request request) { request.reply(status_codes::OK); }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + listener.close().wait(); + } + + TEST(listener_invalid_encoded_uri) + { + uri address(U("http://localhost:45678")); + http_listener listener(address); + listener.open().wait(); + test_http_client::scoped_client client(address); + test_http_client* p_client = client.client(); + + listener.support([](http_request request) { request.reply(status_codes::OK); }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/%invalid/uri"))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::BadRequest); + }) + .wait(); + + listener.close().wait(); + } } -}}}} \ No newline at end of file +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/request_stream_tests.cpp b/Release/tests/functional/http/listener/request_stream_tests.cpp index 6033936461..052f317fb8 100644 --- a/Release/tests/functional/http/listener/request_stream_tests.cpp +++ b/Release/tests/functional/http/listener/request_stream_tests.cpp @@ -1,17 +1,17 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* request_stream_tests.cpp -* -* Tests cases for streaming HTTP requests with http_listener. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * request_stream_tests.cpp + * + * Tests cases for streaming HTTP requests with http_listener. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -23,76 +23,81 @@ using namespace web::http::experimental::listener; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(request_stream_tests) +namespace tests { - -TEST_FIXTURE(uri_address, large_body) +namespace functional { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - std::string data_piece("abcdefghijklmnopqrstuvwxyz"); - std::string send_data; - // 26 * 160 is greater than 4k which is the chunk size. - for(int i = 0; i < 160; ++i) +namespace http +{ +namespace listener +{ +SUITE(request_stream_tests) +{ + TEST_FIXTURE(uri_address, large_body) { - send_data.append(data_piece); - } - size_t length = send_data.size(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - listener.support([&](http_request request) - { - auto stream = request.body(); - streams::stringstreambuf strbuf; - - VERIFY_ARE_EQUAL(stream.read_to_end(strbuf).get(), length); - VERIFY_ARE_EQUAL(strbuf.collection(), send_data); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), U("text/plain"), send_data)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + std::string data_piece("abcdefghijklmnopqrstuvwxyz"); + std::string send_data; + // 26 * 160 is greater than 4k which is the chunk size. + for (int i = 0; i < 160; ++i) + { + send_data.append(data_piece); + } + size_t length = send_data.size(); - listener.close().wait(); -} + listener.support([&](http_request request) { + auto stream = request.body(); + streams::stringstreambuf strbuf; -TEST_FIXTURE(uri_address, test_chunked_transfer) -{ - const size_t num_bytes = 1024 * 1024 * 10; - http_listener listener(m_uri); - listener.support([num_bytes](http_request request) - { - request.reply(status_codes::OK); - }); - listener.open().wait(); + VERIFY_ARE_EQUAL(stream.read_to_end(strbuf).get(), length); + VERIFY_ARE_EQUAL(strbuf.collection(), send_data); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), U("text/plain"), send_data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); - ::http::client::http_client client(m_uri); - auto buf = streams::producer_consumer_buffer(); - pplx::task response = client.request(methods::PUT, U("/"), buf.create_istream(), U("text/plain")); + listener.close().wait(); + } - const size_t four_mb = 1024 * 1024 * 4; - std::vector buffer; - buffer.resize(num_bytes); - memset(&buffer[0], (int)'A', num_bytes); - size_t start = 0, end; - while(start < num_bytes) + TEST_FIXTURE(uri_address, test_chunked_transfer) { - end = start + four_mb < num_bytes ? four_mb : num_bytes - start; - size_t num_written = buf.putn_nocopy(&buffer[start], end).get(); - start += num_written; - } - buf.close(std::ios_base::out).wait(); + const size_t num_bytes = 1024 * 1024 * 10; + http_listener listener(m_uri); + listener.support([num_bytes](http_request request) { request.reply(status_codes::OK); }); + listener.open().wait(); - response.wait(); - listener.close().wait(); -} + ::http::client::http_client client(m_uri); + auto buf = streams::producer_consumer_buffer(); + pplx::task response = + client.request(methods::PUT, U("/"), buf.create_istream(), U("text/plain")); + const size_t four_mb = 1024 * 1024 * 4; + std::vector buffer; + buffer.resize(num_bytes); + memset(&buffer[0], (int)'A', num_bytes); + size_t start = 0, end; + while (start < num_bytes) + { + end = start + four_mb < num_bytes ? four_mb : num_bytes - start; + size_t num_written = buf.putn_nocopy(&buffer[start], end).get(); + start += num_written; + } + buf.close(std::ios_base::out).wait(); + + response.wait(); + listener.close().wait(); + } } -}}}} +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/requests_tests.cpp b/Release/tests/functional/http/listener/requests_tests.cpp index be3317d67e..db2935986d 100644 --- a/Release/tests/functional/http/listener/requests_tests.cpp +++ b/Release/tests/functional/http/listener/requests_tests.cpp @@ -1,19 +1,20 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* requests_tests.cpp -* -* Tests cases for covering sending various requests to http_listener. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * requests_tests.cpp + * + * Tests cases for covering sending various requests to http_listener. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include using namespace web::http; @@ -21,264 +22,257 @@ using namespace web::http::experimental::listener; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(requests_tests) +namespace tests { - -TEST_FIXTURE(uri_address, http_methods) +namespace functional { - http_listener listener(m_uri); - - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - // Don't include 'CONNECT' it has a special meaning. - utility::string_t send_methods[] = - { - methods::GET, - U("GET"), - methods::DEL, - methods::HEAD, - U("HeAd"), - methods::POST, - methods::PUT, - U("CUstomMETHOD") - }; - utility::string_t recv_methods[] = - { - U("GET"), - U("GET"), - U("DELETE"), - U("HEAD"), - U("HEAD"), - U("POST"), - U("PUT"), - U("CUstomMETHOD") - }; - const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); - - utility::string_t actual_method; - listener.support([&](http_request request) - { - actual_method = request.method(); - request.reply(status_codes::OK).wait(); - }); - - for(int i = 0; i < num_methods; ++i) +namespace http +{ +namespace listener +{ +SUITE(requests_tests) +{ + TEST_FIXTURE(uri_address, http_methods) { - pplx::extensibility::event_t ev; - VERIFY_ARE_EQUAL(0, p_client->request(send_methods[i], U(""))); - p_client->next_response().then([&ev](test_response *p_response) + http_listener listener(m_uri); + + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + // Don't include 'CONNECT' it has a special meaning. + utility::string_t send_methods[] = {methods::GET, + U("GET"), + methods::DEL, + methods::HEAD, + U("HeAd"), + methods::POST, + methods::PUT, + U("CUstomMETHOD")}; + utility::string_t recv_methods[] = { + U("GET"), U("GET"), U("DELETE"), U("HEAD"), U("HEAD"), U("POST"), U("PUT"), U("CUstomMETHOD")}; + const size_t num_methods = sizeof(send_methods) / sizeof(send_methods[0]); + + utility::string_t actual_method; + listener.support([&](http_request request) { + actual_method = request.method(); + request.reply(status_codes::OK).wait(); + }); + + for (int i = 0; i < num_methods; ++i) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - ev.set(); - }).wait(); - VERIFY_ARE_EQUAL(recv_methods[i], actual_method); - ev.wait(); + pplx::extensibility::event_t ev; + VERIFY_ARE_EQUAL(0, p_client->request(send_methods[i], U(""))); + p_client->next_response() + .then([&ev](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + ev.set(); + }) + .wait(); + VERIFY_ARE_EQUAL(recv_methods[i], actual_method); + ev.wait(); + } + + listener.close().wait(); } - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, http_body_and_body_size) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - // request with no body - listener.support([](http_request request) + TEST_FIXTURE(uri_address, http_body_and_body_size) { - http_asserts::assert_request_equals(request, U("GET"), U("/")); - VERIFY_ARE_EQUAL(0, request.body().streambuf().in_avail()); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + // request with no body + listener.support([](http_request request) { + http_asserts::assert_request_equals(request, U("GET"), U("/")); + VERIFY_ARE_EQUAL(0, request.body().streambuf().in_avail()); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // request with body size explicitly 0 + listener.support([](http_request request) { + http_asserts::assert_request_equals(request, U("GET"), U("/")); + VERIFY_ARE_EQUAL(0, request.body().streambuf().in_avail()); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), "")); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + // request with body data + std::string data("HEHE"); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, U("GET"), U("/")); + + auto stream = request.body(); + VERIFY_IS_TRUE(stream.is_valid()); + auto buf = stream.streambuf(); + VERIFY_IS_TRUE(buf); + + request.content_ready().wait(); + + VERIFY_ARE_EQUAL(data.size(), buf.in_avail()); + VERIFY_ARE_EQUAL('H', (char)buf.sbumpc()); + VERIFY_ARE_EQUAL('E', (char)buf.sbumpc()); + VERIFY_ARE_EQUAL('H', (char)buf.sbumpc()); + VERIFY_ARE_EQUAL('E', (char)buf.sbumpc()); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + listener.close().wait(); + } - // request with body size explicitly 0 - listener.support([](http_request request) - { - http_asserts::assert_request_equals(request, U("GET"), U("/")); - VERIFY_ARE_EQUAL(0, request.body().streambuf().in_avail()); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), "")); - p_client->next_response().then([](test_response *p_response) + TEST_FIXTURE(uri_address, large_body) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + std::string data_piece("abcdefghijklmnopqrstuvwxyz"); + std::string send_data; + // 26 * 160 is greater than 4k which is the chunk size. + for (int i = 0; i < 160; ++i) + { + send_data.append(data_piece); + } + listener.support([&](http_request request) { + std::string recv_data = utility::conversions::to_utf8string(request.extract_string().get()); + VERIFY_ARE_EQUAL(send_data, recv_data); + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), U("text/plain"), send_data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + + listener.close().wait(); + } - // request with body data - std::string data("HEHE"); - listener.support([&](http_request request) + TEST_FIXTURE(uri_address, response_order) { - http_asserts::assert_request_equals(request, U("GET"), U("/")); - - auto stream = request.body(); - VERIFY_IS_TRUE(stream.is_valid()); - auto buf = stream.streambuf(); - VERIFY_IS_TRUE(buf); - - request.content_ready().wait(); - - VERIFY_ARE_EQUAL(data.size(), buf.in_avail()); - VERIFY_ARE_EQUAL('H', (char)buf.sbumpc()); - VERIFY_ARE_EQUAL('E', (char)buf.sbumpc()); - VERIFY_ARE_EQUAL('H', (char)buf.sbumpc()); - VERIFY_ARE_EQUAL('E', (char)buf.sbumpc()); - request.reply(status_codes::OK); - - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), data)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + http_listener listener(m_uri); + listener.open().wait(); - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, large_body) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - std::string data_piece("abcdefghijklmnopqrstuvwxyz"); - std::string send_data; - // 26 * 160 is greater than 4k which is the chunk size. - for(int i = 0; i < 160; ++i) - { - send_data.append(data_piece); - } - listener.support([&](http_request request) - { - std::string recv_data = utility::conversions::to_utf8string(request.extract_string().get()); - VERIFY_ARE_EQUAL(send_data, recv_data); - request.reply(status_codes::OK); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""), U("text/plain"), send_data)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + client::http_client_config config; + // our product client would be able to pipe multiple requests on one connection + client::http_client client(m_uri, config); - listener.close().wait(); -} + const int num_requests = 50; -TEST_FIXTURE(uri_address, response_order) -{ - http_listener listener(m_uri); - listener.open().wait(); + listener.support([](http_request request) { + auto str = request.extract_string().get(); + // intentionally break order + if (str == U("0")) tests::common::utilities::os_utilities::sleep(500); + request.reply(status_codes::OK, str); + }); - client::http_client_config config; - // our product client would be able to pipe multiple requests on one connection - client::http_client client(m_uri, config); + std::vector> responses; - const int num_requests = 50; + for (int i = 0; i < num_requests; ++i) + { + utility::ostringstream_t ss; + ss << i; + responses.push_back(client.request(web::http::methods::PUT, U(""), ss.str())); + } - listener.support([](http_request request) - { - auto str = request.extract_string().get(); - // intentionally break order - if (str == U("0")) - tests::common::utilities::os_utilities::sleep(500); - request.reply(status_codes::OK, str); - }); + // wait for requests. + for (size_t i = 0; i < num_requests; ++i) + { + utility::ostringstream_t ss; + ss << i; + auto response = responses[i].get(); - std::vector> responses; + // verify the requests and responses are still match + VERIFY_ARE_EQUAL(response.status_code(), status_codes::OK); + VERIFY_ARE_EQUAL(response.extract_string().get(), ss.str()); + } - for (int i = 0; i < num_requests; ++i) - { - utility::ostringstream_t ss; - ss << i; - responses.push_back(client.request(web::http::methods::PUT, U(""), ss.str())); + listener.close().wait(); } - // wait for requests. - for(size_t i = 0; i < num_requests; ++i) + TEST_FIXTURE(uri_address, uri_encoding, "Ignore", "Codeplex 201") { - utility::ostringstream_t ss; - ss << i; - auto response = responses[i].get(); - - // verify the requests and responses are still match - VERIFY_ARE_EQUAL(response.status_code(), status_codes::OK); - VERIFY_ARE_EQUAL(response.extract_string().get(), ss.str()); + http_listener listener(m_uri); + listener.open().wait(); + client::http_client client(m_uri); + utility::string_t encoded_uri; + + listener.support([&](http_request request) { + VERIFY_ARE_EQUAL(encoded_uri, request.relative_uri().to_string()); + request.reply(status_codes::OK); + }); + + // Wrap in try catch to print out more information to help with a sporadic failure. + try + { + encoded_uri = uri::encode_uri(U("/path 1/path 2")); // Path component contains encoded characters + client.request(methods::GET, encoded_uri).wait(); + encoded_uri = uri::encode_uri( + U("/test?Text=J'ai besoin de trouver un personnage")); // Query string contains encoded characters + client.request(methods::GET, encoded_uri).wait(); + encoded_uri = uri::encode_uri(U("/path 1/path 2#fragment1")); // URI has path and fragment components + client.request(methods::GET, encoded_uri).wait(); + encoded_uri = uri::encode_uri( + U("/path 1/path 2?key1=val1 val2#fragment1")); // URI has path, query and fragment components + client.request(methods::GET, encoded_uri).wait(); + } + catch (const http_exception& e) + { + std::cout << "http_exception caught" << std::endl + << "what():" << e.what() << std::endl + << "error_code msg:" << e.error_code().message() << std::endl + << "error_code value:" << e.error_code().value() << std::endl; + VERIFY_IS_TRUE(false); + } + + listener.close().wait(); } - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, uri_encoding, "Ignore", "Codeplex 201") -{ - http_listener listener(m_uri); - listener.open().wait(); - client::http_client client(m_uri); - utility::string_t encoded_uri; - - listener.support([&](http_request request) - { - VERIFY_ARE_EQUAL(encoded_uri, request.relative_uri().to_string()); - request.reply(status_codes::OK); - }); - - // Wrap in try catch to print out more information to help with a sporadic failure. - try + TEST_FIXTURE(uri_address, https_listener, "Ignore", "Manual") { - encoded_uri = uri::encode_uri(U("/path 1/path 2")); // Path component contains encoded characters - client.request(methods::GET, encoded_uri).wait(); - encoded_uri = uri::encode_uri(U("/test?Text=J'ai besoin de trouver un personnage")); // Query string contains encoded characters - client.request(methods::GET, encoded_uri).wait(); - encoded_uri = uri::encode_uri(U("/path 1/path 2#fragment1")); // URI has path and fragment components - client.request(methods::GET, encoded_uri).wait(); - encoded_uri = uri::encode_uri(U("/path 1/path 2?key1=val1 val2#fragment1")); // URI has path, query and fragment components - client.request(methods::GET, encoded_uri).wait(); + // Requires a certificate for execution. + // Here are instructions for creating a self signed cert. Full instructions can be located here: + // http://blogs.msdn.com/b/haoxu/archive/2009/04/30/one-time-set-up-for-wwsapi-security-examples.aspx + // From an elevated admin prompt: + // 1. MakeCert.exe -ss Root -sr LocalMachine -n "CN=Fake-Test-CA" -cy authority -r -sk "CAKeyContainer" + // 2. MakeCert.exe -ss My -sr LocalMachine -n "CN=localhost" -sky exchange -is Root -ir LocalMachine -in + // Fake-Test-CA -sk "ServerKeyContainer" + // 3. Find corresponding SHA-1 hash with CertUtil.exe -store My localhost + // 4. Netsh.exe http add sslcert ipport=0.0.0.0:8443 appid={00112233-4455-6677-8899-AABBCCDDEEFF} + // certhash=<40CharacterThumbprintWithNoSpaces> + + http_listener listener(m_secure_uri); + listener.open().wait(); + client::http_client client(m_secure_uri); + + listener.support([&](http_request request) { request.reply(status_codes::OK); }); + + http_asserts::assert_response_equals(client.request(methods::GET, U("")).get(), status_codes::OK); + + listener.close().wait(); } - catch (const http_exception &e) - { - std::cout << "http_exception caught" << std::endl << - "what():" << e.what() << std::endl << - "error_code msg:" << e.error_code().message() << std::endl << - "error_code value:" << e.error_code().value() << std::endl; - VERIFY_IS_TRUE(false); - } - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, https_listener, "Ignore", "Manual") -{ - // Requires a certificate for execution. - // Here are instructions for creating a self signed cert. Full instructions can be located here: - // http://blogs.msdn.com/b/haoxu/archive/2009/04/30/one-time-set-up-for-wwsapi-security-examples.aspx - // From an elevated admin prompt: - // 1. MakeCert.exe -ss Root -sr LocalMachine -n "CN=Fake-Test-CA" -cy authority -r -sk "CAKeyContainer" - // 2. MakeCert.exe -ss My -sr LocalMachine -n "CN=localhost" -sky exchange -is Root -ir LocalMachine -in Fake-Test-CA -sk "ServerKeyContainer" - // 3. Find corresponding SHA-1 hash with CertUtil.exe -store My localhost - // 4. Netsh.exe http add sslcert ipport=0.0.0.0:8443 appid={00112233-4455-6677-8899-AABBCCDDEEFF} certhash=<40CharacterThumbprintWithNoSpaces> - - http_listener listener(m_secure_uri); - listener.open().wait(); - client::http_client client(m_secure_uri); - - listener.support([&](http_request request) - { - request.reply(status_codes::OK); - }); - - http_asserts::assert_response_equals(client.request(methods::GET, U("")).get(), status_codes::OK); - - listener.close().wait(); -} } -}}}} +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/response_stream_tests.cpp b/Release/tests/functional/http/listener/response_stream_tests.cpp index 9ec39ae213..a16a9fd005 100644 --- a/Release/tests/functional/http/listener/response_stream_tests.cpp +++ b/Release/tests/functional/http/listener/response_stream_tests.cpp @@ -1,19 +1,20 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* response_stream_tests.cpp -* -* Tests cases for streaming with HTTP response with http_listener. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * response_stream_tests.cpp + * + * Tests cases for streaming with HTTP response with http_listener. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/rawptrstream.h" using namespace web; @@ -25,285 +26,291 @@ using namespace web::http::experimental::listener; using namespace tests::common::utilities; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(response_stream_tests) +namespace tests { - -// Used to prepare data for read tests -void fill_file(const utility::string_t &name, size_t repetitions = 1) +namespace functional { - std::fstream stream(name, std::ios_base::out | std::ios_base::trunc); - - for (size_t i = 0; i < repetitions; i++) - stream << "abcdefghijklmnopqrstuvwxyz"; -} - -TEST_FIXTURE(uri_address, set_body_stream_small) +namespace http { - utility::string_t fname = U("set_response_stream_small.txt"); - fill_file(fname); - - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - // Try sending data straight from a file. - http_response response(status_codes::OK); - - auto stream = streams::file_stream::open_istream(fname).get(); - response.set_body(stream); - - auto length = stream.seek(0, std::ios_base::end); - stream.seek(0); - - response.headers().set_content_type(U("text/plain; charset=utf-8")); - response.headers().set_content_length((size_t)length); - - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(response).wait(); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) +namespace listener +{ +SUITE(response_stream_tests) +{ + // Used to prepare data for read tests + void fill_file(const utility::string_t& name, size_t repetitions = 1) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("abcdefghijklmnopqrstuvwxyz")); - }).wait(); + std::fstream stream(name, std::ios_base::out | std::ios_base::trunc); - stream.close().get(); -} + for (size_t i = 0; i < repetitions; i++) + stream << "abcdefghijklmnopqrstuvwxyz"; + } -TEST_FIXTURE(uri_address, set_body_stream_large) -{ - utility::string_t fname = U("set_response_stream_large.txt"); - fill_file(fname,200); + TEST_FIXTURE(uri_address, set_body_stream_small) + { + utility::string_t fname = U("set_response_stream_small.txt"); + fill_file(fname); - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - // Try sending data straight from a file. - http_response response(status_codes::OK); + // Try sending data straight from a file. + http_response response(status_codes::OK); - auto stream = streams::file_stream::open_istream(fname).get(); - response.set_body(stream); - - auto length = stream.seek(0, std::ios_base::end); - stream.seek(0); + auto stream = streams::file_stream::open_istream(fname).get(); + response.set_body(stream); - response.headers().set_content_type(U("text/plain; charset=utf-8")); - response.headers().set_content_length((size_t)length); + auto length = stream.seek(0, std::ios_base::end); + stream.seek(0); + + response.headers().set_content_type(U("text/plain; charset=utf-8")); + response.headers().set_content_length((size_t)length); + + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals( + p_response, status_codes::OK, U("text/plain; charset=utf-8"), U("abcdefghijklmnopqrstuvwxyz")); + }) + .wait(); + + stream.close().get(); + } - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(response).wait(); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) + TEST_FIXTURE(uri_address, set_body_stream_large) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - VERIFY_ARE_EQUAL((size_t)length, p_response->m_data.size()); - }).wait(); + utility::string_t fname = U("set_response_stream_large.txt"); + fill_file(fname, 200); - stream.close().get(); -} - -TEST_FIXTURE(uri_address, set_body_stream_partial) -{ - utility::string_t fname = U("set_response_stream_partial.txt"); - fill_file(fname,200); - - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - // Try sending data straight from a file. - http_response response(status_codes::OK); + // Try sending data straight from a file. + http_response response(status_codes::OK); - auto stream = streams::file_stream::open_istream(fname).get(); - response.set_body(stream); - - response.headers().set_content_type(U("text/plain; charset=utf-8")); - response.headers().set_content_length(4500); + auto stream = streams::file_stream::open_istream(fname).get(); + response.set_body(stream); - // We shouldn't be sending more than the content-length. + auto length = stream.seek(0, std::ios_base::end); + stream.seek(0); + + response.headers().set_content_type(U("text/plain; charset=utf-8")); + response.headers().set_content_length((size_t)length); + + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + VERIFY_ARE_EQUAL((size_t)length, p_response->m_data.size()); + }) + .wait(); + + stream.close().get(); + } - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(response).wait(); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) + TEST_FIXTURE(uri_address, set_body_stream_partial) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - VERIFY_ARE_EQUAL(4500, p_response->m_data.size()); - }).wait(); + utility::string_t fname = U("set_response_stream_partial.txt"); + fill_file(fname, 200); - // We should only have read the first 4500 bytes. - auto length = stream.seek(0, std::ios_base::cur); - VERIFY_ARE_EQUAL((size_t)length, (size_t)4500); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - stream.close().get(); -} + // Try sending data straight from a file. + http_response response(status_codes::OK); -TEST_FIXTURE(uri_address, set_body_filestream_chunked) -{ - utility::string_t fname = U("set_response_stream_chunked.txt"); - fill_file(fname,200); + auto stream = streams::file_stream::open_istream(fname).get(); + response.set_body(stream); - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + response.headers().set_content_type(U("text/plain; charset=utf-8")); + response.headers().set_content_length(4500); - // Try sending data straight from a file. - http_response response(status_codes::OK); + // We shouldn't be sending more than the content-length. - auto stream = streams::file_stream::open_istream(fname).get(); - response.set_body(stream); - - auto length = stream.seek(0, std::ios_base::end); - stream.seek(0); + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + VERIFY_ARE_EQUAL(4500, p_response->m_data.size()); + }) + .wait(); - response.headers().set_content_type(U("text/plain; charset=utf-8")); - // Not setting the content length forces "transfer-encoding: chunked" + // We should only have read the first 4500 bytes. + auto length = stream.seek(0, std::ios_base::cur); + VERIFY_ARE_EQUAL((size_t)length, (size_t)4500); - listener.support([&](http_request request) - { - http_asserts::assert_request_equals(request, methods::POST, U("/")); - request.reply(response).wait(); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) + stream.close().get(); + } + + TEST_FIXTURE(uri_address, set_body_filestream_chunked) { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - VERIFY_ARE_EQUAL((size_t)length, p_response->m_data.size()); - }).wait(); + utility::string_t fname = U("set_response_stream_chunked.txt"); + fill_file(fname, 200); - stream.close().get(); -} + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); -TEST_FIXTURE(uri_address, set_body_memorystream_chunked) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); + // Try sending data straight from a file. + http_response response(status_codes::OK); - // Try sending data straight from a file. - http_response response(status_codes::OK); - - std::string text1 = "This is a test"; - size_t length = text1.size(); + auto stream = streams::file_stream::open_istream(fname).get(); + response.set_body(stream); - response.headers().set_content_type(U("text/plain; charset=utf-8")); - // Not setting the content length forces "transfer-encoding: chunked" + auto length = stream.seek(0, std::ios_base::end); + stream.seek(0); + + response.headers().set_content_type(U("text/plain; charset=utf-8")); + // Not setting the content length forces "transfer-encoding: chunked" + + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + VERIFY_ARE_EQUAL((size_t)length, p_response->m_data.size()); + }) + .wait(); + + stream.close().get(); + } - listener.support([&](http_request request) + TEST_FIXTURE(uri_address, set_body_memorystream_chunked) { - http_asserts::assert_request_equals(request, methods::POST, U("/")); + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - streams::producer_consumer_buffer rwbuf; - - streams::basic_istream stream(rwbuf); - response.set_body(stream); + // Try sending data straight from a file. + http_response response(status_codes::OK); - auto rep = request.reply(response); + std::string text1 = "This is a test"; + size_t length = text1.size(); - os_utilities::sleep(100); + response.headers().set_content_type(U("text/plain; charset=utf-8")); + // Not setting the content length forces "transfer-encoding: chunked" - rwbuf.putn_nocopy(&text1[0], length).wait(); - rwbuf.putn_nocopy(&text1[0], length).wait(); - rwbuf.sync().wait(); - rwbuf.putn_nocopy(&text1[0], length).wait(); - rwbuf.close(std::ios_base::out).wait(); - - rep.wait(); - }); - - VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - VERIFY_ARE_EQUAL((size_t)length*3, p_response->m_data.size()); - }).wait(); -} + listener.support([&](http_request request) { + http_asserts::assert_request_equals(request, methods::POST, U("/")); -TEST_FIXTURE(uri_address, reply_transfer_encoding_4k) -{ - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); + streams::producer_consumer_buffer rwbuf; - streams::container_buffer> buf; + streams::basic_istream stream(rwbuf); + response.set_body(stream); - // Write 4K - the exact internal chunk size - unsigned char ptr[4* 1024] = {'a', 'b', 'c'}; - VERIFY_ARE_EQUAL(buf.putn_nocopy(ptr, sizeof(ptr)).get(), sizeof(ptr)); + auto rep = request.reply(response); - listener.support([&buf](http_request request) - { - // Ensure that it is transfer-encoded - auto collection = buf.collection(); - streams::container_buffer> buf2(std::move(collection), std::ios_base::in); - request.reply(200, streams::istream(buf2), U("text/plain")); - buf.close(std::ios_base::out); - }); + os_utilities::sleep(100); - { - ::http::client::http_client client(m_uri); - http_request msg(methods::GET); + rwbuf.putn_nocopy(&text1[0], length).wait(); + rwbuf.putn_nocopy(&text1[0], length).wait(); + rwbuf.sync().wait(); + rwbuf.putn_nocopy(&text1[0], length).wait(); + rwbuf.close(std::ios_base::out).wait(); - // Wait for headers - auto resp = client.request(msg).get(); + rep.wait(); + }); - // Wait for data - resp.content_ready().wait(); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::POST, U(""))); + p_client->next_response() + .then([&](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + VERIFY_ARE_EQUAL((size_t)length * 3, p_response->m_data.size()); + }) + .wait(); + } - // Now verify that we've got the right data - auto s = resp.extract_string().get(); - VERIFY_ARE_EQUAL(s.c_str(), U("abc")); + TEST_FIXTURE(uri_address, reply_transfer_encoding_4k) + { + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); + + streams::container_buffer> buf; + + // Write 4K - the exact internal chunk size + unsigned char ptr[4 * 1024] = {'a', 'b', 'c'}; + VERIFY_ARE_EQUAL(buf.putn_nocopy(ptr, sizeof(ptr)).get(), sizeof(ptr)); + + listener.support([&buf](http_request request) { + // Ensure that it is transfer-encoded + auto collection = buf.collection(); + streams::container_buffer> buf2(std::move(collection), std::ios_base::in); + request.reply(200, streams::istream(buf2), U("text/plain")); + buf.close(std::ios_base::out); + }); + + { + ::http::client::http_client client(m_uri); + http_request msg(methods::GET); + + // Wait for headers + auto resp = client.request(msg).get(); + + // Wait for data + resp.content_ready().wait(); + + // Now verify that we've got the right data + auto s = resp.extract_string().get(); + VERIFY_ARE_EQUAL(s.c_str(), U("abc")); + } + listener.close().wait(); } - listener.close().wait(); -} -// Fails sporadically, Codeplex #158 -TEST_FIXTURE(uri_address, reply_chunked_4k, "Ignore", "Codeplex 158") -{ - web::http::experimental::listener::http_listener listener(m_uri); - listener.open().wait(); + // Fails sporadically, Codeplex #158 + TEST_FIXTURE(uri_address, reply_chunked_4k, "Ignore", "Codeplex 158") + { + web::http::experimental::listener::http_listener listener(m_uri); + listener.open().wait(); - streams::producer_consumer_buffer buf; + streams::producer_consumer_buffer buf; - // Write 4K - the exact internal chunk size - unsigned char ptr[4* 1024]; - VERIFY_ARE_EQUAL(buf.putn_nocopy(ptr, sizeof(ptr)).get(), sizeof(ptr)); - buf.close(std::ios_base::out); + // Write 4K - the exact internal chunk size + unsigned char ptr[4 * 1024]; + VERIFY_ARE_EQUAL(buf.putn_nocopy(ptr, sizeof(ptr)).get(), sizeof(ptr)); + buf.close(std::ios_base::out); - listener.support([&buf](http_request request) - { - // Ensure that it is transfer-encoded - request.reply(200, streams::istream(buf), 4096, U("text/plain")); - }); + listener.support([&buf](http_request request) { + // Ensure that it is transfer-encoded + request.reply(200, streams::istream(buf), 4096, U("text/plain")); + }); - { - ::http::client::http_client client(m_uri); - http_request msg(methods::GET); + { + ::http::client::http_client client(m_uri); + http_request msg(methods::GET); - // Wait for headers - auto resp = client.request(msg).get(); + // Wait for headers + auto resp = client.request(msg).get(); - // Wait for data - resp.content_ready().wait(); + // Wait for data + resp.content_ready().wait(); + } + listener.close().wait(); } - listener.close().wait(); -} - } -}}}} \ No newline at end of file +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/status_code_reason_phrase_tests.cpp b/Release/tests/functional/http/listener/status_code_reason_phrase_tests.cpp index e503571fd0..b555a826ba 100644 --- a/Release/tests/functional/http/listener/status_code_reason_phrase_tests.cpp +++ b/Release/tests/functional/http/listener/status_code_reason_phrase_tests.cpp @@ -1,17 +1,17 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* status_code_reason_phrase_tests.cpp -* -* Tests cases for using HTTP status codes and reason phrases with http_listener. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * status_code_reason_phrase_tests.cpp + * + * Tests cases for using HTTP status codes and reason phrases with http_listener. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,91 +20,88 @@ using namespace web::http::experimental::listener; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(status_code_reason_phrase_tests) +namespace tests { - -TEST_FIXTURE(uri_address, status_codes) +namespace functional { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - // known status code - listener.support([&](http_request request) - { - request.reply(status_codes::Conflict).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::Conflict); - }).wait(); - - // user defined status code - listener.support([&](http_request request) - { - request.reply(867).wait(); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::PUT, U(""))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, 867); - }).wait(); - - listener.close().wait(); -} - -TEST_FIXTURE(uri_address, reason_phrase) +namespace http { - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - // standard status code, no reason phrase - listener.support([](http_request request) - { - request.reply(status_codes::NotModified).wait(); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::PUT, U(""))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::NotModified); - VERIFY_ARE_EQUAL(U("Not Modified"), p_response->m_reason_phrase); - }).wait(); - - // standard status code, with reason phrase - listener.support([](http_request request) - { - http_response response(status_codes::NotModified); - response.set_reason_phrase(U("Custom")); - request.reply(response).wait(); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::PUT, U(""))); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::NotModified); - VERIFY_ARE_EQUAL(U("Custom"), p_response->m_reason_phrase); - }).wait(); - - // non standard status code, no reason phrase - listener.support([](http_request request) +namespace listener +{ +SUITE(status_code_reason_phrase_tests) +{ + TEST_FIXTURE(uri_address, status_codes) { - request.reply(987); - }); - VERIFY_ARE_EQUAL(0u, p_client->request(methods::PUT, U(""))); - p_client->next_response().then([](test_response *p_response) + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + // known status code + listener.support([&](http_request request) { request.reply(status_codes::Conflict).wait(); }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::PUT, U(""))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::Conflict); + }) + .wait(); + + // user defined status code + listener.support([&](http_request request) { request.reply(867).wait(); }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::PUT, U(""))); + p_client->next_response() + .then([](test_response* p_response) { http_asserts::assert_test_response_equals(p_response, 867); }) + .wait(); + + listener.close().wait(); + } + + TEST_FIXTURE(uri_address, reason_phrase) { - http_asserts::assert_test_response_equals(p_response, 987); - VERIFY_ARE_EQUAL(U(""), p_response->m_reason_phrase); - }).wait(); - - listener.close().wait(); -} - + http_listener listener(m_uri); + listener.open().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); + + // standard status code, no reason phrase + listener.support([](http_request request) { request.reply(status_codes::NotModified).wait(); }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::PUT, U(""))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::NotModified); + VERIFY_ARE_EQUAL(U("Not Modified"), p_response->m_reason_phrase); + }) + .wait(); + + // standard status code, with reason phrase + listener.support([](http_request request) { + http_response response(status_codes::NotModified); + response.set_reason_phrase(U("Custom")); + request.reply(response).wait(); + }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::PUT, U(""))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::NotModified); + VERIFY_ARE_EQUAL(U("Custom"), p_response->m_reason_phrase); + }) + .wait(); + + // non standard status code, no reason phrase + listener.support([](http_request request) { request.reply(987); }); + VERIFY_ARE_EQUAL(0u, p_client->request(methods::PUT, U(""))); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, 987); + VERIFY_ARE_EQUAL(U(""), p_response->m_reason_phrase); + }) + .wait(); + + listener.close().wait(); + } } -}}}} \ No newline at end of file +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/listener/stdafx.cpp b/Release/tests/functional/http/listener/stdafx.cpp index cc89710770..b17ac3df2a 100644 --- a/Release/tests/functional/http/listener/stdafx.cpp +++ b/Release/tests/functional/http/listener/stdafx.cpp @@ -1,4 +1,4 @@ -// stdafx.cpp : +// stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" diff --git a/Release/tests/functional/http/listener/stdafx.h b/Release/tests/functional/http/listener/stdafx.h index 102b15bbb5..26e4636873 100644 --- a/Release/tests/functional/http/listener/stdafx.h +++ b/Release/tests/functional/http/listener/stdafx.h @@ -1,29 +1,27 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.h + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include - -#include "cpprest/http_listener.h" -#include "cpprest/http_client.h" #include "cpprest/asyncrt_utils.h" -#include "cpprest/producerconsumerstream.h" #include "cpprest/filestream.h" - +#include "cpprest/http_client.h" +#include "cpprest/http_listener.h" +#include "cpprest/producerconsumerstream.h" #include "http_listener_tests.h" #include "http_test_utilities.h" +#include "os_utilities.h" #include "unittestpp.h" -#include "os_utilities.h" \ No newline at end of file +#include diff --git a/Release/tests/functional/http/listener/to_string_tests.cpp b/Release/tests/functional/http/listener/to_string_tests.cpp index b086c30aa3..617be3a10e 100644 --- a/Release/tests/functional/http/listener/to_string_tests.cpp +++ b/Release/tests/functional/http/listener/to_string_tests.cpp @@ -1,17 +1,17 @@ /*** -* ==++== -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* to_string_tests.cpp -* -* Tests cases for to_string on HTTP requests/responses with http_listener. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * ==++== + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * ==--== + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * to_string_tests.cpp + * + * Tests cases for to_string on HTTP requests/responses with http_listener. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -21,62 +21,64 @@ using namespace web::http::experimental::listener; using namespace tests::common::utilities; using namespace tests::functional::http::utilities; -namespace tests { namespace functional { namespace http { namespace listener { - -SUITE(to_string_tests) +namespace tests { - -TEST_FIXTURE(uri_address, response_to_string) +namespace functional { - // to string - http_response resp(status_codes::PartialContent); - resp.set_body(U("data")); - VERIFY_ARE_EQUAL( - U("HTTP/1.1 206 Partial Content\r\nContent-Length: 4\r\nContent-Type: text/plain; charset=utf-8\r\n\r\ndata"), - resp.to_string()); -} - -TEST_FIXTURE(uri_address, request_to_string) +namespace http +{ +namespace listener { - http_listener listener(m_uri); - listener.open().wait(); - - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); +SUITE(to_string_tests) +{ + TEST_FIXTURE(uri_address, response_to_string) + { + // to string + http_response resp(status_codes::PartialContent); + resp.set_body(U("data")); + VERIFY_ARE_EQUAL(U("HTTP/1.1 206 Partial Content\r\nContent-Length: 4\r\nContent-Type: text/plain; " + "charset=utf-8\r\n\r\ndata"), + resp.to_string()); + } - // to_string - std::string data("hehehe"); - listener.support([&](http_request request) + TEST_FIXTURE(uri_address, request_to_string) { - std::map expected_headers; - expected_headers[U("Connection")] = U("Keep-Alive"); - expected_headers[U("Content-Length")] = U("6"); - expected_headers[U("Content-Type")] = U("text/plain"); - expected_headers[U("Host")] = U("localhost:34567"); - expected_headers[U("User-Agent")] = U("test_http_client"); + http_listener listener(m_uri); + listener.open().wait(); - // maybe to_string() should wait for the request to complete? - // in the mean time... - request.content_ready().wait(); + test_http_client::scoped_client client(m_uri); + test_http_client* p_client = client.client(); - http_asserts::assert_request_string_equals( - request.to_string(), - U("GET"), - U("/pa%20th1"), - U("HTTP/1.1"), - expected_headers, - U("hehehe")); - request.reply(status_codes::OK).wait(); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("pa%20th1"), U("text/plain"), data)); - p_client->next_response().then([](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); + // to_string + std::string data("hehehe"); + listener.support([&](http_request request) { + std::map expected_headers; + expected_headers[U("Connection")] = U("Keep-Alive"); + expected_headers[U("Content-Length")] = U("6"); + expected_headers[U("Content-Type")] = U("text/plain"); + expected_headers[U("Host")] = U("localhost:34567"); + expected_headers[U("User-Agent")] = U("test_http_client"); - listener.close().wait(); -} + // maybe to_string() should wait for the request to complete? + // in the mean time... + request.content_ready().wait(); + + http_asserts::assert_request_string_equals( + request.to_string(), U("GET"), U("/pa%20th1"), U("HTTP/1.1"), expected_headers, U("hehehe")); + request.reply(status_codes::OK).wait(); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("pa%20th1"), U("text/plain"), data)); + p_client->next_response() + .then([](test_response* p_response) { + http_asserts::assert_test_response_equals(p_response, status_codes::OK); + }) + .wait(); + listener.close().wait(); + } } -}}}} \ No newline at end of file +} // namespace listener +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/utilities/http_asserts.cpp b/Release/tests/functional/http/utilities/http_asserts.cpp index 001d2b37a4..7dc626d4e3 100644 --- a/Release/tests/functional/http/utilities/http_asserts.cpp +++ b/Release/tests/functional/http/utilities/http_asserts.cpp @@ -1,24 +1,31 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* http_asserts.cpp - Utility class to help verify assertions about http requests and responses. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * http_asserts.cpp - Utility class to help verify assertions about http requests and responses. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -using namespace web; using namespace utility; +using namespace web; +using namespace utility; using namespace utility::conversions; -namespace tests { namespace functional { namespace http { namespace utilities { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace utilities +{ utility::string_t percent_encode_pound(utility::string_t str) { size_t index; - while((index = str.find_first_of(U("#"))) != str.npos) + while ((index = str.find_first_of(U("#"))) != str.npos) { str.insert(index, U("%23")); str.erase(index + 3, 1); @@ -27,22 +34,21 @@ utility::string_t percent_encode_pound(utility::string_t str) } // Helper function to verify all given headers are present. -template -static void verify_headers(const T1 &expected, const T2 &actual) +template +static void verify_headers(const T1& expected, const T2& actual) { - for(auto iter = expected.begin(); iter != expected.end(); ++iter) + for (auto iter = expected.begin(); iter != expected.end(); ++iter) { VERIFY_ARE_EQUAL(iter->second, actual.find(iter->first)->second); } } -void http_asserts::assert_request_equals( - ::http::http_request request, - const ::http::method &mtd, - const utility::string_t & relative_path) +void http_asserts::assert_request_equals(::http::http_request request, + const ::http::method& mtd, + const utility::string_t& relative_path) { VERIFY_ARE_EQUAL(mtd, request.method()); - if(relative_path == U("")) + if (relative_path == U("")) { VERIFY_ARE_EQUAL(U("/"), request.relative_uri().to_string()); } @@ -52,80 +58,70 @@ void http_asserts::assert_request_equals( } } -void http_asserts::assert_request_equals( - ::http::http_request request, - const ::http::method &mtd, - const utility::string_t & relative_uri, - const std::map &headers) +void http_asserts::assert_request_equals(::http::http_request request, + const ::http::method& mtd, + const utility::string_t& relative_uri, + const std::map& headers) { assert_request_equals(request, mtd, relative_uri); verify_headers(headers, request.headers()); } -void http_asserts::assert_request_equals( - ::http::http_request request, - const ::http::method &mtd, - const utility::string_t & relative_path, - const utility::string_t & body) +void http_asserts::assert_request_equals(::http::http_request request, + const ::http::method& mtd, + const utility::string_t& relative_path, + const utility::string_t& body) { assert_request_equals(request, mtd, relative_path); auto request_data = request.extract_string().get(); VERIFY_ARE_EQUAL(body, request_data); } -void http_asserts::assert_response_equals( - ::http::http_response response, - const ::http::status_code &code) +void http_asserts::assert_response_equals(::http::http_response response, const ::http::status_code& code) { VERIFY_ARE_EQUAL(response.status_code(), code); } -void http_asserts::assert_response_equals( - ::http::http_response response, - const ::http::status_code &code, - const utility::string_t &reason) +void http_asserts::assert_response_equals(::http::http_response response, + const ::http::status_code& code, + const utility::string_t& reason) { - VERIFY_ARE_EQUAL(code, response.status_code()); - VERIFY_ARE_EQUAL(reason, response.reason_phrase()); + VERIFY_ARE_EQUAL(code, response.status_code()); + VERIFY_ARE_EQUAL(reason, response.reason_phrase()); } -void http_asserts::assert_response_equals( - ::http::http_response response, - const ::http::status_code &code, - const std::map &headers) +void http_asserts::assert_response_equals(::http::http_response response, + const ::http::status_code& code, + const std::map& headers) { VERIFY_ARE_EQUAL(code, response.status_code()); verify_headers(headers, response.headers()); } -void http_asserts::assert_http_headers_equals( - const ::http::http_headers &actual, - const ::http::http_headers &expected) +void http_asserts::assert_http_headers_equals(const ::http::http_headers& actual, const ::http::http_headers& expected) { verify_headers(actual, expected); } -void http_asserts::assert_test_request_equals( - const test_request *const p_request, - const ::http::method &mtd, - const utility::string_t &path) +void http_asserts::assert_test_request_equals(const test_request* const p_request, + const ::http::method& mtd, + const utility::string_t& path) { VERIFY_ARE_EQUAL(mtd, p_request->m_method); VERIFY_ARE_EQUAL(path, p_request->m_path); } -void http_asserts::assert_test_request_equals( - const test_request *const p_request, - const ::http::method &mtd, - const utility::string_t &path, - const utility::string_t &content_type) +void http_asserts::assert_test_request_equals(const test_request* const p_request, + const ::http::method& mtd, + const utility::string_t& path, + const utility::string_t& content_type) { VERIFY_ARE_EQUAL(mtd, p_request->m_method); VERIFY_ARE_EQUAL(path, p_request->m_path); // verify that content-type key exists in the header and the value matches the one provided auto iter = p_request->m_headers.find(U("Content-Type")); - if(content_type.empty()) + if (content_type.empty()) { VERIFY_ARE_EQUAL(iter, p_request->m_headers.end()); } @@ -136,27 +132,25 @@ void http_asserts::assert_test_request_equals( } } -void http_asserts::assert_test_request_contains_headers( - const test_request *const p_request, - const ::http::http_headers &headers) +void http_asserts::assert_test_request_contains_headers(const test_request* const p_request, + const ::http::http_headers& headers) { verify_headers(headers, p_request->m_headers); } -void http_asserts::assert_test_request_contains_headers( - const test_request *const p_request, - const std::map &headers) +void http_asserts::assert_test_request_contains_headers(const test_request* const p_request, + const std::map& headers) { verify_headers(headers, p_request->m_headers); } // Helper function to parse HTTP headers from a stringstream. -static std::map parse_headers(utility::istringstream_t &ss) +static std::map parse_headers(utility::istringstream_t& ss) { // Keep parsing until CRLF is encountered. std::map headers; utility::string_t header_line; - while(getline(ss, header_line).good()) + while (getline(ss, header_line).good()) { const size_t colon_index = header_line.find(U(":")); const utility::string_t header_name = header_line.substr(0, colon_index); @@ -165,7 +159,7 @@ static std::map parse_headers(utility::ist headers[header_name] = header_value; char c1 = (char)ss.get(), c2 = (char)ss.get(); - if(c1 == '\r' && c2 == '\n') + if (c1 == '\r' && c2 == '\n') { break; } @@ -175,13 +169,12 @@ static std::map parse_headers(utility::ist return headers; } -void http_asserts::assert_request_string_equals( - const utility::string_t &request, - const ::http::method &mtd, - const utility::string_t &path, - const utility::string_t &version, - const std::map &headers, - const utility::string_t &body) +void http_asserts::assert_request_string_equals(const utility::string_t& request, + const ::http::method& mtd, + const utility::string_t& path, + const utility::string_t& version, + const std::map& headers, + const utility::string_t& body) { utility::istringstream_t ss(request); @@ -204,13 +197,12 @@ void http_asserts::assert_request_string_equals( VERIFY_ARE_EQUAL(body, actual_body); } -void http_asserts::assert_response_string_equals( - const utility::string_t &response, - const utility::string_t &version, - const ::http::status_code &code, - const utility::string_t &phrase, - const std::map &headers, - const utility::string_t &body) +void http_asserts::assert_response_string_equals(const utility::string_t& response, + const utility::string_t& version, + const ::http::status_code& code, + const utility::string_t& phrase, + const std::map& headers, + const utility::string_t& body) { utility::istringstream_t ss(response); @@ -234,12 +226,11 @@ void http_asserts::assert_response_string_equals( VERIFY_ARE_EQUAL(body, actual_body); } -void http_asserts::assert_test_request_equals( - const test_request *const p_request, - const ::http::method &mtd, - const utility::string_t &path, - const utility::string_t &content_type, - const utility::string_t &body) +void http_asserts::assert_test_request_equals(const test_request* const p_request, + const ::http::method& mtd, + const utility::string_t& path, + const utility::string_t& content_type, + const utility::string_t& body) { assert_test_request_equals(p_request, mtd, path, content_type); // Textual response is always sent as UTF-8, hence the converison to string_t @@ -249,35 +240,30 @@ void http_asserts::assert_test_request_equals( VERIFY_ARE_EQUAL(body, extracted_body); } -void http_asserts::assert_test_response_equals( - const test_response * const p_response, - const ::http::status_code &code) +void http_asserts::assert_test_response_equals(const test_response* const p_response, const ::http::status_code& code) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); } -void http_asserts::assert_test_response_equals( - const test_response * const p_response, - const ::http::status_code &code, - const std::map &headers) +void http_asserts::assert_test_response_equals(const test_response* const p_response, + const ::http::status_code& code, + const std::map& headers) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); verify_headers(headers, p_response->m_headers); } -void http_asserts::assert_test_response_equals( - const test_response * const p_response, - const ::http::status_code &code, - const ::http::http_headers &headers) +void http_asserts::assert_test_response_equals(const test_response* const p_response, + const ::http::status_code& code, + const ::http::http_headers& headers) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); verify_headers(headers, p_response->m_headers); } -void http_asserts::assert_test_response_equals( - test_response * p_response, - const ::http::status_code &code, - const utility::string_t &content_type) +void http_asserts::assert_test_response_equals(test_response* p_response, + const ::http::status_code& code, + const utility::string_t& content_type) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); utility::string_t found_content; @@ -285,11 +271,10 @@ void http_asserts::assert_test_response_equals( VERIFY_ARE_EQUAL(content_type, found_content); } -void http_asserts::assert_test_response_equals( - test_response * p_response, - const ::http::status_code &code, - const utility::string_t &content_type, - const utility::string_t data) +void http_asserts::assert_test_response_equals(test_response* p_response, + const ::http::status_code& code, + const utility::string_t& content_type, + const utility::string_t data) { VERIFY_ARE_EQUAL(code, p_response->m_status_code); utility::string_t found_content; @@ -298,20 +283,21 @@ void http_asserts::assert_test_response_equals( // Beware: what kind of string this is? <-- stringhack until we tighten up wide/narrow string business utility::string_t extracted_body; - if(p_response->m_data.size() == 0) + if (p_response->m_data.size() == 0) { extracted_body = U(""); } else { auto actualRawData = (char*)&p_response->m_data[0]; - if(p_response->m_data.size() > 1 && *(actualRawData+1) == '\0' ) + if (p_response->m_data.size() > 1 && *(actualRawData + 1) == '\0') { // We have more than one byte of data, but it's null-terminated at byte 1. // Therefore, this is a wide string - extracted_body.assign((utility::char_t*)actualRawData, p_response->m_data.size()/sizeof(utility::char_t)); + extracted_body.assign((utility::char_t*)actualRawData, p_response->m_data.size() / sizeof(utility::char_t)); } - else{ + else + { std::string s(actualRawData, p_response->m_data.size()); extracted_body = to_string_t(s); } @@ -320,4 +306,7 @@ void http_asserts::assert_test_response_equals( VERIFY_ARE_EQUAL(data, extracted_body); } -}}}} +} // namespace utilities +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/utilities/include/http_asserts.h b/Release/tests/functional/http/utilities/include/http_asserts.h index 9291a936ce..79aee00d41 100644 --- a/Release/tests/functional/http/utilities/include/http_asserts.h +++ b/Release/tests/functional/http/utilities/include/http_asserts.h @@ -1,32 +1,39 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* http_asserts.h - Utility class to help verify assertions about http requests and responses. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * http_asserts.h - Utility class to help verify assertions about http requests and responses. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include "test_http_server.h" -#include "test_http_client.h" - #include "http_test_utilities_public.h" +#include "test_http_client.h" +#include "test_http_server.h" -namespace tests { namespace functional { namespace http { namespace utilities { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace utilities +{ template -void trim_whitespace(std::basic_string &str) +void trim_whitespace(std::basic_string& str) { size_t index; // trim left whitespace - for (index = 0; index < str.size() && isspace(str[index]); ++index); + for (index = 0; index < str.size() && isspace(str[index]); ++index) + ; str.erase(0, index); // trim right whitespace - for (index = str.size(); index > 0 && isspace(str[index - 1]); --index); + for (index = str.size(); index > 0 && isspace(str[index - 1]); --index) + ; str.erase(index); } @@ -42,143 +49,128 @@ TEST_UTILITY_API utility::string_t __cdecl percent_encode_pound(utility::string_ class http_asserts { public: - /// /// Asserts that the specified request is equal to given arguments. /// - TEST_UTILITY_API static void __cdecl assert_request_equals( - web::http::http_request request, - const web::http::method &mtd, - const utility::string_t & relative_uri); + TEST_UTILITY_API static void __cdecl assert_request_equals(web::http::http_request request, + const web::http::method& mtd, + const utility::string_t& relative_uri); TEST_UTILITY_API static void __cdecl assert_request_equals( - web::http::http_request request, - const web::http::method &mtd, - const utility::string_t &relative_uri, - const std::map &headers); + web::http::http_request request, + const web::http::method& mtd, + const utility::string_t& relative_uri, + const std::map& headers); - TEST_UTILITY_API static void __cdecl assert_request_equals( - web::http::http_request request, - const web::http::method &mtd, - const utility::string_t & relative_uri, - const utility::string_t & body); + TEST_UTILITY_API static void __cdecl assert_request_equals(web::http::http_request request, + const web::http::method& mtd, + const utility::string_t& relative_uri, + const utility::string_t& body); /// /// Asserts that the specified response is equal to given arguments. /// - TEST_UTILITY_API static void __cdecl assert_response_equals( - web::http::http_response response, - const web::http::status_code &code); + TEST_UTILITY_API static void __cdecl assert_response_equals(web::http::http_response response, + const web::http::status_code& code); - TEST_UTILITY_API static void __cdecl assert_response_equals( - web::http::http_response response, - const web::http::status_code &code, - const utility::string_t &reason); + TEST_UTILITY_API static void __cdecl assert_response_equals(web::http::http_response response, + const web::http::status_code& code, + const utility::string_t& reason); TEST_UTILITY_API static void __cdecl assert_response_equals( web::http::http_response response, - const web::http::status_code &code, - const std::map &headers); + const web::http::status_code& code, + const std::map& headers); /// /// Asserts the given http_headers contains the given values. /// - TEST_UTILITY_API static void __cdecl assert_http_headers_equals( - const web::http::http_headers &actual, - const web::http::http_headers &expected); + TEST_UTILITY_API static void __cdecl assert_http_headers_equals(const web::http::http_headers& actual, + const web::http::http_headers& expected); /// /// Asserts the specified test_request is equal to its arguments. /// - TEST_UTILITY_API static void __cdecl assert_test_request_equals( - const test_request *const p_request, - const web::http::method &mtd, - const utility::string_t &path); + TEST_UTILITY_API static void __cdecl assert_test_request_equals(const test_request* const p_request, + const web::http::method& mtd, + const utility::string_t& path); /// /// Asserts the specified test_request is equal to its arguments. /// - TEST_UTILITY_API static void __cdecl assert_test_request_equals( - const test_request *const p_request, - const web::http::method &mtd, - const utility::string_t &path, - const utility::string_t &content_type); + TEST_UTILITY_API static void __cdecl assert_test_request_equals(const test_request* const p_request, + const web::http::method& mtd, + const utility::string_t& path, + const utility::string_t& content_type); /// /// Asserts the specified test_request is equal to its arguments. /// - TEST_UTILITY_API static void __cdecl assert_test_request_contains_headers( - const test_request *const p_request, - const web::http::http_headers &headers); + TEST_UTILITY_API static void __cdecl assert_test_request_contains_headers(const test_request* const p_request, + const web::http::http_headers& headers); /// /// Asserts the specified test_request is equal to its arguments. /// TEST_UTILITY_API static void __cdecl assert_test_request_contains_headers( - const test_request *const p_request, - const std::map &headers); + const test_request* const p_request, const std::map& headers); /// /// Asserts the given HTTP request string is equal to its arguments. /// NOTE: this function only makes sure the specified headers exist, not that they are the only ones. /// TEST_UTILITY_API static void __cdecl assert_request_string_equals( - const utility::string_t &request, - const web::http::method &mtd, - const utility::string_t &path, - const utility::string_t &version, - const std::map &headers, - const utility::string_t &body); + const utility::string_t& request, + const web::http::method& mtd, + const utility::string_t& path, + const utility::string_t& version, + const std::map& headers, + const utility::string_t& body); /// /// Asserts the given HTTP response string is equal to its arguments. /// NOTE: this function only makes sure the specified headers exist, not that they are the only ones. /// TEST_UTILITY_API static void __cdecl assert_response_string_equals( - const utility::string_t &response, - const utility::string_t &version, - const web::http::status_code &code, - const utility::string_t &phrase, - const std::map &headers, - const utility::string_t &body); + const utility::string_t& response, + const utility::string_t& version, + const web::http::status_code& code, + const utility::string_t& phrase, + const std::map& headers, + const utility::string_t& body); /// /// Asserts the specified test_request is equal to its arguments. /// - TEST_UTILITY_API static void __cdecl assert_test_request_equals( - const test_request *const p_request, - const web::http::method &mtd, - const utility::string_t &path, - const utility::string_t &content_type, - const utility::string_t &body); + TEST_UTILITY_API static void __cdecl assert_test_request_equals(const test_request* const p_request, + const web::http::method& mtd, + const utility::string_t& path, + const utility::string_t& content_type, + const utility::string_t& body); /// /// Asserts the specified test_response is equal to its arguments. /// - TEST_UTILITY_API static void __cdecl assert_test_response_equals( - const test_response * const p_response, - const web::http::status_code &code); + TEST_UTILITY_API static void __cdecl assert_test_response_equals(const test_response* const p_response, + const web::http::status_code& code); TEST_UTILITY_API static void __cdecl assert_test_response_equals( - const test_response * const p_response, - const web::http::status_code &code, - const std::map &headers); + const test_response* const p_response, + const web::http::status_code& code, + const std::map& headers); - TEST_UTILITY_API static void __cdecl assert_test_response_equals( - const test_response * const p_response, - const web::http::status_code &code, - const web::http::http_headers &headers); + TEST_UTILITY_API static void __cdecl assert_test_response_equals(const test_response* const p_response, + const web::http::status_code& code, + const web::http::http_headers& headers); - TEST_UTILITY_API static void __cdecl assert_test_response_equals( - test_response * p_response, - const web::http::status_code &code, - const utility::string_t &content_type); + TEST_UTILITY_API static void __cdecl assert_test_response_equals(test_response* p_response, + const web::http::status_code& code, + const utility::string_t& content_type); - TEST_UTILITY_API static void __cdecl assert_test_response_equals( - test_response * p_response, - const web::http::status_code &code, - const utility::string_t &content_type, - const utility::string_t data); + TEST_UTILITY_API static void __cdecl assert_test_response_equals(test_response* p_response, + const web::http::status_code& code, + const utility::string_t& content_type, + const utility::string_t data); private: http_asserts() {} @@ -193,39 +185,54 @@ class http_asserts // Relax verification for now. #define HTTP_ERROR_CHECK_IMPL(__code) #else -#define HTTP_ERROR_CHECK_IMPL(__code) if(__code != _exc.error_code()) { VERIFY_IS_TRUE(false, "Unexpected error code encountered."); } +#define HTTP_ERROR_CHECK_IMPL(__code) \ + if (__code != _exc.error_code()) \ + { \ + VERIFY_IS_TRUE(false, "Unexpected error code encountered."); \ + } #endif #else // The reason we can't directly compare with the given std::errc code is because -// on Windows the STL implementation of error categories are NOT unique across +// on Windows the STL implementation of error categories are NOT unique across // dll boundaries, until VS2015. -#define HTTP_ERROR_CHECK_IMPL(__code) VERIFY_ARE_EQUAL(static_cast(__code), _exc.error_code().default_error_condition().value()); +#define HTTP_ERROR_CHECK_IMPL(__code) \ + VERIFY_ARE_EQUAL(static_cast(__code), _exc.error_code().default_error_condition().value()); #endif #else #define HTTP_ERROR_CHECK_IMPL(__code) VERIFY_ARE_EQUAL(_exc.error_code(), __code, "Unexpected error code encountered.") #endif - // Helper function to verify http_exception is thrown with correct error code -#define VERIFY_THROWS_HTTP_ERROR_CODE(__expression, __code) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - try \ - { \ - __expression; \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), "Expected exception: \"web::http::http_exception\" not thrown"); \ - } \ - catch (const web::http::http_exception& _exc) \ - { \ - VERIFY_IS_TRUE(std::string(_exc.what()).size() > 0); \ - HTTP_ERROR_CHECK_IMPL(__code); \ - } catch(const std::exception & _exc) { \ - std::string _msg("(" #__expression ") threw exception: "); \ - _msg.append(_exc.what()); \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ - } catch (...) { \ - std::string _msg("(" #__expression ") threw exception: <...>"); \ - UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ - } \ +#define VERIFY_THROWS_HTTP_ERROR_CODE(__expression, __code) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + try \ + { \ + __expression; \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Expected exception: \"web::http::http_exception\" not thrown"); \ + } \ + catch (const web::http::http_exception& _exc) \ + { \ + VERIFY_IS_TRUE(std::string(_exc.what()).size() > 0); \ + HTTP_ERROR_CHECK_IMPL(__code); \ + } \ + catch (const std::exception& _exc) \ + { \ + std::string _msg("(" #__expression ") threw exception: "); \ + _msg.append(_exc.what()); \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ + } \ + catch (...) \ + { \ + std::string _msg("(" #__expression ") threw exception: <...>"); \ + UnitTest::CurrentTest::Results()->OnTestFailure( \ + UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ + } \ UNITTEST_MULTILINE_MACRO_END -}}}} +} // namespace utilities +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/utilities/include/http_test_utilities.h b/Release/tests/functional/http/utilities/include/http_test_utilities.h index 9c2b6f667c..2f66e56a88 100644 --- a/Release/tests/functional/http/utilities/include/http_test_utilities.h +++ b/Release/tests/functional/http/utilities/include/http_test_utilities.h @@ -1,18 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* httpt_test_utilities.h -- This is the "one-stop-shop" header for including http test dependencies -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * httpt_test_utilities.h -- This is the "one-stop-shop" header for including http test dependencies + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include "http_test_utilities_public.h" #include "http_asserts.h" +#include "http_test_utilities_public.h" +#include "test_http_client.h" #include "test_http_server.h" #include "test_server_utilities.h" -#include "test_http_client.h" diff --git a/Release/tests/functional/http/utilities/include/http_test_utilities_public.h b/Release/tests/functional/http/utilities/include/http_test_utilities_public.h index 0025327104..9e2821c80d 100644 --- a/Release/tests/functional/http/utilities/include/http_test_utilities_public.h +++ b/Release/tests/functional/http/utilities/include/http_test_utilities_public.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* http_test_utilities_public.h -- Common definitions for public http test utility headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * http_test_utilities_public.h -- Common definitions for public http test utility headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once diff --git a/Release/tests/functional/http/utilities/include/test_http_client.h b/Release/tests/functional/http/utilities/include/test_http_client.h index 91d2c4416f..0e840e5fc3 100644 --- a/Release/tests/functional/http/utilities/include/test_http_client.h +++ b/Release/tests/functional/http/utilities/include/test_http_client.h @@ -1,23 +1,30 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* test_http_client.h -- Defines a test client to handle requests and sending responses. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * test_http_client.h -- Defines a test client to handle requests and sending responses. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include -#include #include "cpprest/uri.h" #include "http_test_utilities_public.h" +#include +#include +#include -namespace tests { namespace functional { namespace http { namespace utilities { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace utilities +{ class _test_http_client; /// @@ -26,11 +33,11 @@ class _test_http_client; class test_response { public: - test_response(_test_http_client *client) : m_client(client) {} - + test_response(_test_http_client* client) : m_client(client) {} + // API to check if a specific header exists and get it. - template - bool match_header(const utility::string_t & header_name, T & header_value) + template + bool match_header(const utility::string_t& header_name, T& header_value) { auto iter = m_headers.find(header_name); @@ -50,10 +57,10 @@ class test_response } } - bool match_header(const utility::string_t & header_name, utility::string_t & header_value) + bool match_header(const utility::string_t& header_name, utility::string_t& header_value) { auto iter = m_headers.find(header_name); - if(iter != m_headers.end()) + if (iter != m_headers.end()) { header_value = m_headers[header_name]; return true; @@ -68,7 +75,7 @@ class test_response std::vector m_data; friend class _test_http_client; - _test_http_client * m_client; + _test_http_client* m_client; }; /// @@ -79,48 +86,43 @@ class test_response class test_http_client { public: - TEST_UTILITY_API test_http_client(const web::http::uri &uri); + TEST_UTILITY_API test_http_client(const web::http::uri& uri); TEST_UTILITY_API ~test_http_client(); - TEST_UTILITY_API test_http_client(test_http_client &&other); - TEST_UTILITY_API test_http_client & operator=(test_http_client &&other); + TEST_UTILITY_API test_http_client(test_http_client&& other); + TEST_UTILITY_API test_http_client& operator=(test_http_client&& other); // APIs to open and close requests. TEST_UTILITY_API unsigned long open(); TEST_UTILITY_API unsigned long close(); // APIs to send requests. - TEST_UTILITY_API unsigned long request(const utility::string_t &method, const utility::string_t &path); - TEST_UTILITY_API unsigned long request( - const utility::string_t &method, - const utility::string_t &path, - const std::map &headers); - TEST_UTILITY_API unsigned long request( - const utility::string_t &method, - const utility::string_t &path, - const std::string &data); - TEST_UTILITY_API unsigned long request( - const utility::string_t &method, - const utility::string_t &path, - const utility::string_t &content_type, - const std::string &data); - TEST_UTILITY_API unsigned long request( - const utility::string_t &method, - const utility::string_t &path, - const std::map &headers, - const std::string &data); - + TEST_UTILITY_API unsigned long request(const utility::string_t& method, const utility::string_t& path); + TEST_UTILITY_API unsigned long request(const utility::string_t& method, + const utility::string_t& path, + const std::map& headers); + TEST_UTILITY_API unsigned long request(const utility::string_t& method, + const utility::string_t& path, + const std::string& data); + TEST_UTILITY_API unsigned long request(const utility::string_t& method, + const utility::string_t& path, + const utility::string_t& content_type, + const std::string& data); + TEST_UTILITY_API unsigned long request(const utility::string_t& method, + const utility::string_t& path, + const std::map& headers, + const std::string& data); // APIs to receive responses. - TEST_UTILITY_API test_response * wait_for_response(); - TEST_UTILITY_API pplx::task next_response(); - TEST_UTILITY_API std::vector wait_for_responses(const size_t count); - TEST_UTILITY_API std::vector> next_responses(const size_t count); + TEST_UTILITY_API test_response* wait_for_response(); + TEST_UTILITY_API pplx::task next_response(); + TEST_UTILITY_API std::vector wait_for_responses(const size_t count); + TEST_UTILITY_API std::vector> next_responses(const size_t count); // RAII pattern for test_http_client. class scoped_client { public: - scoped_client(const web::http::uri &uri) + scoped_client(const web::http::uri& uri) { m_p_client = new test_http_client(uri); VERIFY_ARE_EQUAL(0u, m_p_client->open()); @@ -130,16 +132,20 @@ class test_http_client VERIFY_ARE_EQUAL(0u, m_p_client->close()); delete m_p_client; } - test_http_client *client() { return m_p_client; } + test_http_client* client() { return m_p_client; } + private: - test_http_client * m_p_client; + test_http_client* m_p_client; }; private: - test_http_client & operator=(const test_http_client &); - test_http_client(const test_http_client &); + test_http_client& operator=(const test_http_client&); + test_http_client(const test_http_client&); std::unique_ptr<_test_http_client> m_impl; }; -}}}} +} // namespace utilities +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/utilities/include/test_http_server.h b/Release/tests/functional/http/utilities/include/test_http_server.h index 8220f0b331..872fd5909f 100644 --- a/Release/tests/functional/http/utilities/include/test_http_server.h +++ b/Release/tests/functional/http/utilities/include/test_http_server.h @@ -1,25 +1,30 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* test_http_server.h -- Defines a test server to handle requests and sending responses. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * test_http_server.h -- Defines a test server to handle requests and sending responses. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include -#include - -#include "unittestpp.h" #include "cpprest/uri.h" #include "http_test_utilities_public.h" +#include "unittestpp.h" +#include +#include -namespace tests { namespace functional { namespace http { namespace utilities { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace utilities +{ /// /// Actual implementation of test_http_server is in this class. /// This wrapping is done to hide the fact we are using Windows HTTP Server APIs @@ -33,46 +38,45 @@ class _test_http_server; class test_request { friend class _test_http_server; + public: test_request(unsigned long long reqid, _test_http_server* p_server) : m_request_id(reqid), m_p_server(p_server) {} // APIs to send responses. - unsigned long reply( - const unsigned short status_code, - const utility::string_t &reason_phrase = U(""), - const std::map &headers = std::map(), - const utf8string &data = "") + unsigned long reply(const unsigned short status_code, + const utility::string_t& reason_phrase = U(""), + const std::map& headers = + std::map(), + const utf8string& data = "") { - return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size() * sizeof(utf8char)); + return reply_impl(status_code, reason_phrase, headers, (void*)&data[0], data.size() * sizeof(utf8char)); } - unsigned long reply( - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - const std::vector &data) + unsigned long reply(const unsigned short status_code, + const utility::string_t& reason_phrase, + const std::map& headers, + const std::vector& data) { - return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size()); + return reply_impl(status_code, reason_phrase, headers, (void*)&data[0], data.size()); } - unsigned long reply( - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - const utf16string &data) + unsigned long reply(const unsigned short status_code, + const utility::string_t& reason_phrase, + const std::map& headers, + const utf16string& data) { - return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size() * sizeof(utf16char)); + return reply_impl(status_code, reason_phrase, headers, (void*)&data[0], data.size() * sizeof(utf16char)); } // API to check if a specific header exists and get it. - template - bool match_header(const utility::string_t & header_name, T & header_value) + template + bool match_header(const utility::string_t& header_name, T& header_value) { auto iter = m_headers.find(header_name); if (iter == m_headers.end()) - { - return false; - } + { + return false; + } return web::http::details::bind_impl(iter->second, header_value) || iter->second.empty(); } @@ -82,18 +86,18 @@ class test_request utility::string_t m_path; std::map m_headers; std::vector m_body; + private: // This is the HTTP Server API Request Id, we don't want to bring in the header file. unsigned long long m_request_id; - _test_http_server * m_p_server; + _test_http_server* m_p_server; // Helper to send replies. - TEST_UTILITY_API unsigned long reply_impl( - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - void * data, - size_t data_length); + TEST_UTILITY_API unsigned long reply_impl(const unsigned short status_code, + const utility::string_t& reason_phrase, + const std::map& headers, + void* data, + size_t data_length); }; /// @@ -104,12 +108,12 @@ class test_request class test_http_server { public: - TEST_UTILITY_API test_http_server(const web::http::uri &uri); + TEST_UTILITY_API test_http_server(const web::http::uri& uri); TEST_UTILITY_API ~test_http_server(); // APIs to receive requests. - TEST_UTILITY_API pplx::task next_request(); - TEST_UTILITY_API std::vector> next_requests(const size_t count); + TEST_UTILITY_API pplx::task next_request(); + TEST_UTILITY_API std::vector> next_requests(const size_t count); // Enable early close TEST_UTILITY_API void close(); @@ -124,10 +128,14 @@ class test_http_server class test_http_server::scoped_server { public: - scoped_server(const web::http::uri &uri) : m_p_server(uri) {} - test_http_server *server() { return &m_p_server; } + scoped_server(const web::http::uri& uri) : m_p_server(uri) {} + test_http_server* server() { return &m_p_server; } + private: test_http_server m_p_server; }; -}}}} +} // namespace utilities +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/utilities/include/test_server_utilities.h b/Release/tests/functional/http/utilities/include/test_server_utilities.h index 8b3744c8d3..06559b7fc7 100644 --- a/Release/tests/functional/http/utilities/include/test_server_utilities.h +++ b/Release/tests/functional/http/utilities/include/test_server_utilities.h @@ -1,63 +1,67 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* test_server_utilities.h - Utility class to send and verify requests and responses working with the http_test_server. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * test_server_utilities.h - Utility class to send and verify requests and responses working with the http_test_server. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "cpprest/http_client.h" -#include "test_http_server.h" - #include "http_test_utilities_public.h" +#include "test_http_server.h" -namespace tests { namespace functional { namespace http { namespace utilities { - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace utilities +{ class test_server_utilities { public: - /// /// Sends request with specified values using given http_client and verifies /// they are properly received by the test server. /// - TEST_UTILITY_API static void __cdecl verify_request( - web::http::client::http_client *p_client, - const utility::string_t &method, - const utility::string_t &path, - test_http_server *p_server, - unsigned short code); - - TEST_UTILITY_API static void __cdecl verify_request( - web::http::client::http_client *p_client, - const utility::string_t &method, - const utility::string_t &path, - test_http_server *p_server, - unsigned short code, - const utility::string_t &reason); + TEST_UTILITY_API static void __cdecl verify_request(web::http::client::http_client* p_client, + const utility::string_t& method, + const utility::string_t& path, + test_http_server* p_server, + unsigned short code); - TEST_UTILITY_API static void __cdecl verify_request( - web::http::client::http_client *p_client, - const utility::string_t &method, - const utility::string_t &path, - const utility::string_t &request_content_type, - const utility::string_t &request_data, - test_http_server *p_server, - unsigned short code, - const utility::string_t &reason); + TEST_UTILITY_API static void __cdecl verify_request(web::http::client::http_client* p_client, + const utility::string_t& method, + const utility::string_t& path, + test_http_server* p_server, + unsigned short code, + const utility::string_t& reason); + + TEST_UTILITY_API static void __cdecl verify_request(web::http::client::http_client* p_client, + const utility::string_t& method, + const utility::string_t& path, + const utility::string_t& request_content_type, + const utility::string_t& request_data, + test_http_server* p_server, + unsigned short code, + const utility::string_t& reason); TEST_UTILITY_API static void __cdecl verify_request( - web::http::client::http_client *p_client, - const utility::string_t &method, - const utility::string_t &path, - test_http_server *p_server, + web::http::client::http_client* p_client, + const utility::string_t& method, + const utility::string_t& path, + test_http_server* p_server, unsigned short code, - const std::map &response_headers); + const std::map& response_headers); }; -}}}} \ No newline at end of file +} // namespace utilities +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/utilities/stdafx.cpp b/Release/tests/functional/http/utilities/stdafx.cpp index bc2dfe733c..c8f4d74525 100644 --- a/Release/tests/functional/http/utilities/stdafx.cpp +++ b/Release/tests/functional/http/utilities/stdafx.cpp @@ -1,10 +1,10 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ -// stdafx.cpp : + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ +// stdafx.cpp : // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" diff --git a/Release/tests/functional/http/utilities/stdafx.h b/Release/tests/functional/http/utilities/stdafx.h index 2991724c35..9ce41e4b72 100644 --- a/Release/tests/functional/http/utilities/stdafx.h +++ b/Release/tests/functional/http/utilities/stdafx.h @@ -1,28 +1,27 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define NOMINMAX #include + #include #endif +#include "cpprest/asyncrt_utils.h" #include "cpprest/http_client.h" - #include "cpprest/http_msg.h" #include "cpprest/uri.h" -#include "cpprest/asyncrt_utils.h" - -#include "unittestpp.h" #include "include/http_asserts.h" +#include "unittestpp.h" diff --git a/Release/tests/functional/http/utilities/test_http_client.cpp b/Release/tests/functional/http/utilities/test_http_client.cpp index ab188f7b60..40736917b0 100644 --- a/Release/tests/functional/http/utilities/test_http_client.cpp +++ b/Release/tests/functional/http/utilities/test_http_client.cpp @@ -1,37 +1,45 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Defines a test client to handle requests and sending responses. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Defines a test client to handle requests and sending responses. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include "cpprest/uri.h" -#include "cpprest/details/http_helpers.h" #include "test_http_client.h" + +#include "cpprest/details/http_helpers.h" +#include "cpprest/uri.h" #ifdef _WIN32 #include #pragma comment(lib, "winhttp.lib") -#pragma warning ( push ) -#pragma warning ( disable : 4457 ) +#pragma warning(push) +#pragma warning(disable : 4457) #include -#pragma warning ( pop ) +#pragma warning(pop) #endif -using namespace web; using namespace utility; - -namespace tests { namespace functional { namespace http { namespace utilities { +using namespace web; +using namespace utility; +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace utilities +{ // Flatten the http_headers into a name:value pairs separated by a carriage return and line feed. -utility::string_t flatten_http_headers(const std::map &headers) +utility::string_t flatten_http_headers(const std::map& headers) { utility::string_t flattened_headers; - for(auto iter = headers.begin(); iter != headers.end(); ++iter) + for (auto iter = headers.begin(); iter != headers.end(); ++iter) { utility::string_t temp((*iter).first + U(":") + (*iter).second + U("\r\n")); flattened_headers.append(utility::string_t(temp.begin(), temp.end())); @@ -42,58 +50,57 @@ utility::string_t flatten_http_headers(const std::map 0 && str[index - 1] == 0; --index); + for (index = str.size(); index > 0 && str[index - 1] == 0; --index) + ; str.erase(index); } // Helper function to get the reason phrase from a WinHTTP response. -static void parse_reason_phrase(HINTERNET request_handle, utility::string_t &phrase) +static void parse_reason_phrase(HINTERNET request_handle, utility::string_t& phrase) { DWORD length = 0; query_header_length(request_handle, WINHTTP_QUERY_STATUS_TEXT, length); phrase.resize(length); - WinHttpQueryHeaders( - request_handle, - WINHTTP_QUERY_STATUS_TEXT, - WINHTTP_HEADER_NAME_BY_INDEX, - &phrase[0], - &length, - WINHTTP_NO_HEADER_INDEX); + WinHttpQueryHeaders(request_handle, + WINHTTP_QUERY_STATUS_TEXT, + WINHTTP_HEADER_NAME_BY_INDEX, + &phrase[0], + &length, + WINHTTP_NO_HEADER_INDEX); // WinHTTP reports back the wrong length, trim any null characters. trim_nulls(phrase); } @@ -101,19 +108,19 @@ static void parse_reason_phrase(HINTERNET request_handle, utility::string_t &phr /// /// Parses a string containing Http headers. /// -static void parse_winhttp_headers(HINTERNET request_handle, utf16char *headersStr, test_response *p_response) +static void parse_winhttp_headers(HINTERNET request_handle, utf16char* headersStr, test_response* p_response) { // Status code and reason phrase. parse_status_code(request_handle, p_response->m_status_code); parse_reason_phrase(request_handle, p_response->m_reason_phrase); - utf16char *context = nullptr; - utf16char *line = wcstok_s(headersStr, U("\r\n"), &context); - while(line != nullptr) + utf16char* context = nullptr; + utf16char* line = wcstok_s(headersStr, U("\r\n"), &context); + while (line != nullptr) { const utility::string_t header_line(line); const size_t colonIndex = header_line.find_first_of(U(":")); - if(colonIndex != utility::string_t::npos) + if (colonIndex != utility::string_t::npos) { utility::string_t key = header_line.substr(0, colonIndex); utility::string_t value = header_line.substr(colonIndex + 1, header_line.length() - colonIndex - 1); @@ -128,45 +135,40 @@ static void parse_winhttp_headers(HINTERNET request_handle, utf16char *headersSt class _test_http_client { public: - _test_http_client(const utility::string_t &uri) - : m_uri(uri), m_hSession(nullptr), m_hConnection(nullptr) - {} + _test_http_client(const utility::string_t& uri) : m_uri(uri), m_hSession(nullptr), m_hConnection(nullptr) {} unsigned long open() { // Open session. - m_hSession = WinHttpOpen( - U("test_http_client"), - WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - WINHTTP_FLAG_ASYNC); - if(!m_hSession) + m_hSession = WinHttpOpen(U("test_http_client"), + WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + WINHTTP_FLAG_ASYNC); + if (!m_hSession) { return GetLastError(); } - // Set timeouts. - int multiplier=10; - if(!WinHttpSetTimeouts(m_hSession, 60000*multiplier, 60000*multiplier, 30000*multiplier, 30000*multiplier)) + int multiplier = 10; + if (!WinHttpSetTimeouts( + m_hSession, 60000 * multiplier, 60000 * multiplier, 30000 * multiplier, 30000 * multiplier)) { return GetLastError(); } // Set max connection to use per server to 1. DWORD maxConnections = 1; - if(!WinHttpSetOption(m_hSession, WINHTTP_OPTION_MAX_CONNS_PER_SERVER, &maxConnections, sizeof(maxConnections))) + if (!WinHttpSetOption(m_hSession, WINHTTP_OPTION_MAX_CONNS_PER_SERVER, &maxConnections, sizeof(maxConnections))) { return GetLastError(); } // Register asynchronous callback. - if(WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback( - m_hSession, - &_test_http_client::completion_callback, - WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS, - 0)) + if (WINHTTP_INVALID_STATUS_CALLBACK == + WinHttpSetStatusCallback( + m_hSession, &_test_http_client::completion_callback, WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS, 0)) { return GetLastError(); } @@ -174,12 +176,8 @@ class _test_http_client // Open connection. ::http::uri u(m_uri); unsigned int port = u.is_port_default() ? INTERNET_DEFAULT_PORT : u.port(); - m_hConnection = WinHttpConnect( - m_hSession, - u.host().c_str(), - (INTERNET_PORT)port, - 0); - if(m_hConnection == nullptr) + m_hConnection = WinHttpConnect(m_hSession, u.host().c_str(), (INTERNET_PORT)port, 0); + if (m_hConnection == nullptr) { return GetLastError(); } @@ -189,32 +187,26 @@ class _test_http_client unsigned long close() { // Release memory for each request. - std::for_each(m_responses_memory.begin(), m_responses_memory.end(), [](test_response *p_response) - { - delete p_response; - }); + std::for_each( + m_responses_memory.begin(), m_responses_memory.end(), [](test_response* p_response) { delete p_response; }); - if(m_hConnection != nullptr) + if (m_hConnection != nullptr) { - if(WinHttpCloseHandle(m_hConnection) == NULL) + if (WinHttpCloseHandle(m_hConnection) == NULL) { return GetLastError(); } } - if(m_hSession != nullptr) + if (m_hSession != nullptr) { // Unregister the callback. - if(!WinHttpSetStatusCallback( - m_hSession, - NULL, - WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, - NULL)) + if (!WinHttpSetStatusCallback(m_hSession, NULL, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL)) { return GetLastError(); } - if(WinHttpCloseHandle(m_hSession) == NULL) + if (WinHttpCloseHandle(m_hSession) == NULL) { return GetLastError(); } @@ -222,89 +214,73 @@ class _test_http_client return 0; } - unsigned long request( - const utility::string_t &method, - const utility::string_t &path, - const std::map headers, - void * data, - size_t data_length) + unsigned long request(const utility::string_t& method, + const utility::string_t& path, + const std::map headers, + void* data, + size_t data_length) { HINTERNET request_handle = WinHttpOpenRequest( - m_hConnection, - method.c_str(), - path.c_str(), - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - 0); - if(request_handle == nullptr) + m_hConnection, method.c_str(), path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + if (request_handle == nullptr) { return GetLastError(); } // Add headers. - if(!headers.empty()) + if (!headers.empty()) { utility::string_t flattened_headers = flatten_http_headers(headers); - if(!WinHttpAddRequestHeaders( - request_handle, - flattened_headers.c_str(), - (DWORD)flattened_headers.length(), - WINHTTP_ADDREQ_FLAG_ADD)) + if (!WinHttpAddRequestHeaders(request_handle, + flattened_headers.c_str(), + (DWORD)flattened_headers.length(), + WINHTTP_ADDREQ_FLAG_ADD)) { return GetLastError(); } } - if(!WinHttpSendRequest( - request_handle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - data, - (DWORD)data_length, - (DWORD)data_length, - (DWORD_PTR)new test_response(this))) + if (!WinHttpSendRequest(request_handle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + data, + (DWORD)data_length, + (DWORD)data_length, + (DWORD_PTR) new test_response(this))) { return GetLastError(); } return 0; } - test_response * wait_for_response() - { - return wait_for_responses(1)[0]; - } - - pplx::task next_response() + test_response* wait_for_response() { return wait_for_responses(1)[0]; } + + pplx::task next_response() { - return pplx::create_task([this]() -> test_response * - { - return wait_for_response(); - }); + return pplx::create_task([this]() -> test_response* { return wait_for_response(); }); } - - std::vector wait_for_responses(const size_t count) + + std::vector wait_for_responses(const size_t count) { - std::vector m_test_responses; - for(size_t i = 0; i < count; ++i) + std::vector m_test_responses; + for (size_t i = 0; i < count; ++i) { m_test_responses.push_back(Concurrency::receive(m_responses)); } return m_test_responses; } - - std::vector> next_responses(const size_t count) + + std::vector> next_responses(const size_t count) { - std::vector> events; - std::vector> responses; - for(size_t i = 0; i < count; ++i) + std::vector> events; + std::vector> responses; + for (size_t i = 0; i < count; ++i) { - events.push_back(pplx::task_completion_event()); + events.push_back(pplx::task_completion_event()); responses.push_back(pplx::create_task(events[i])); } - pplx::create_task([this, count, events]() - { - for(size_t i = 0; i < count; ++i) + pplx::create_task([this, count, events]() { + for (size_t i = 0; i < count; ++i) { events[i].set(wait_for_response()); } @@ -313,79 +289,68 @@ class _test_http_client } private: - // WinHTTP callback. - static void CALLBACK completion_callback( - HINTERNET hRequestHandle, - DWORD_PTR context, - DWORD statusCode, - void* statusInfo, - DWORD) + static void CALLBACK + completion_callback(HINTERNET hRequestHandle, DWORD_PTR context, DWORD statusCode, void* statusInfo, DWORD) { - test_response * p_response = reinterpret_cast(context); - if(p_response != nullptr) + test_response* p_response = reinterpret_cast(context); + if (p_response != nullptr) { - if(statusCode == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) + if (statusCode == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) { - WINHTTP_ASYNC_RESULT *pStatusInfo = static_cast(statusInfo); + WINHTTP_ASYNC_RESULT* pStatusInfo = static_cast(statusInfo); pStatusInfo; throw std::exception("Error in WinHTTP callback"); } - else if(statusCode == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) + else if (statusCode == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) { - if(!WinHttpReceiveResponse(hRequestHandle, NULL)) + if (!WinHttpReceiveResponse(hRequestHandle, NULL)) { throw std::exception("Error receiving response"); } } - else if(statusCode == WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE) + else if (statusCode == WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE) { DWORD headers_length; - WinHttpQueryHeaders( - hRequestHandle, - WINHTTP_QUERY_RAW_HEADERS_CRLF, - WINHTTP_HEADER_NAME_BY_INDEX, - WINHTTP_NO_OUTPUT_BUFFER, - &headers_length, - WINHTTP_NO_HEADER_INDEX); + WinHttpQueryHeaders(hRequestHandle, + WINHTTP_QUERY_RAW_HEADERS_CRLF, + WINHTTP_HEADER_NAME_BY_INDEX, + WINHTTP_NO_OUTPUT_BUFFER, + &headers_length, + WINHTTP_NO_HEADER_INDEX); // Now allocate buffer for headers and query for them. std::vector header_raw_buffer; header_raw_buffer.resize(headers_length); - utf16char * header_buffer = reinterpret_cast(&header_raw_buffer[0]); - if(!WinHttpQueryHeaders( - hRequestHandle, - WINHTTP_QUERY_RAW_HEADERS_CRLF, - WINHTTP_HEADER_NAME_BY_INDEX, - header_buffer, - &headers_length, - WINHTTP_NO_HEADER_INDEX)) + utf16char* header_buffer = reinterpret_cast(&header_raw_buffer[0]); + if (!WinHttpQueryHeaders(hRequestHandle, + WINHTTP_QUERY_RAW_HEADERS_CRLF, + WINHTTP_HEADER_NAME_BY_INDEX, + header_buffer, + &headers_length, + WINHTTP_NO_HEADER_INDEX)) { throw std::exception("Error querying for headers"); } parse_winhttp_headers(hRequestHandle, header_buffer, p_response); // Check to see if the response has a body or not. - if(!WinHttpQueryDataAvailable(hRequestHandle, nullptr)) + if (!WinHttpQueryDataAvailable(hRequestHandle, nullptr)) { throw std::exception("Error reading response body"); } } - else if(statusCode == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE) + else if (statusCode == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE) { DWORD num_bytes = *(PDWORD)statusInfo; - if ( num_bytes > 0 ) + if (num_bytes > 0) { - size_t current_size = p_response->m_data.size(); - p_response->m_data.resize(current_size+(size_t)num_bytes); - + size_t current_size = p_response->m_data.size(); + p_response->m_data.resize(current_size + (size_t)num_bytes); + // Actual WinHTTP call to read in body. - if(!WinHttpReadData( - hRequestHandle, - &p_response->m_data[current_size], - (DWORD)num_bytes, - NULL)) + if (!WinHttpReadData(hRequestHandle, &p_response->m_data[current_size], (DWORD)num_bytes, NULL)) { throw std::exception("Error reading response body"); } @@ -397,9 +362,9 @@ class _test_http_client Concurrency::asend(p_response->m_client->m_responses, p_response); } } - else if(statusCode == WINHTTP_CALLBACK_STATUS_READ_COMPLETE) + else if (statusCode == WINHTTP_CALLBACK_STATUS_READ_COMPLETE) { - if(!WinHttpQueryDataAvailable(hRequestHandle, nullptr)) + if (!WinHttpQueryDataAvailable(hRequestHandle, nullptr)) { throw std::exception("Error reading response body"); } @@ -407,10 +372,10 @@ class _test_http_client } } - Concurrency::unbounded_buffer m_responses; + Concurrency::unbounded_buffer m_responses; // Used to store all requests to simplify memory management. - std::vector m_responses_memory; + std::vector m_responses_memory; const utility::string_t m_uri; HINTERNET m_hSession; @@ -424,19 +389,18 @@ class _test_http_client typename web::http::client::http_client m_client; std::vector> m_responses; std::vector m_test_responses; - + public: _test_http_client(utility::string_t uri) : m_uri(web::http::uri::encode_uri(uri)), m_client(m_uri.authority()) {} - unsigned long open() { return 0; } + unsigned long open() { return 0; } unsigned long close() { return 0; } - unsigned long request( - const utility::string_t &method, - const utility::string_t &path, - const std::map& headers, - void * data, - size_t data_length) + unsigned long request(const utility::string_t& method, + const utility::string_t& path, + const std::map& headers, + void* data, + size_t data_length) { auto localHeaders = headers; localHeaders["User-Agent"] = "test_http_client"; @@ -458,26 +422,19 @@ class _test_http_client return 0; } - test_response * wait_for_response() - { - return wait_for_responses(1)[0]; - } - - pplx::task next_response() + test_response* wait_for_response() { return wait_for_responses(1)[0]; } + + pplx::task next_response() { - return pplx::create_task([this]() -> test_response * - { - return wait_for_response(); - }); + return pplx::create_task([this]() -> test_response* { return wait_for_response(); }); } - - std::vector wait_for_responses(const size_t count) + + std::vector wait_for_responses(const size_t count) { - if (count > m_responses.size()) - throw std::logic_error("count too big"); + if (count > m_responses.size()) throw std::logic_error("count too big"); - std::vector m_test_responses; - for(size_t i = 0; i < count; ++i) + std::vector m_test_responses; + for (size_t i = 0; i < count; ++i) { auto response = m_responses[0].get(); @@ -495,10 +452,10 @@ class _test_http_client } return m_test_responses; } - - std::vector> next_responses(const size_t count) + + std::vector> next_responses(const size_t count) { - std::vector> result; + std::vector> result; for (size_t i = 0; i < count; ++i) { result.push_back(next_response()); @@ -508,20 +465,18 @@ class _test_http_client }; #endif -test_http_client::test_http_client(const web::http::uri &uri) +test_http_client::test_http_client(const web::http::uri& uri) { m_impl = std::unique_ptr<_test_http_client>(new _test_http_client(uri.to_string())); } -test_http_client::~test_http_client() -{ -} +test_http_client::~test_http_client() {} -test_http_client::test_http_client(test_http_client &&other) : m_impl(std::move(other.m_impl)) {} +test_http_client::test_http_client(test_http_client&& other) : m_impl(std::move(other.m_impl)) {} -test_http_client & test_http_client::operator=(test_http_client &&other) +test_http_client& test_http_client::operator=(test_http_client&& other) { - if(this != &other) + if (this != &other) { this->m_impl = std::move(other.m_impl); } @@ -531,47 +486,52 @@ test_http_client & test_http_client::operator=(test_http_client &&other) unsigned long test_http_client::open() { return m_impl->open(); } unsigned long test_http_client::close() { return m_impl->close(); } -unsigned long test_http_client::request(const utility::string_t &method, const utility::string_t &path) +unsigned long test_http_client::request(const utility::string_t& method, const utility::string_t& path) { return request(method, path, std::map()); } -unsigned long test_http_client::request( - const utility::string_t &method, - const utility::string_t &path, - const std::map &headers) +unsigned long test_http_client::request(const utility::string_t& method, + const utility::string_t& path, + const std::map& headers) { return request(method, path, headers, std::string()); } -unsigned long test_http_client::request( - const utility::string_t &method, - const utility::string_t &path, - const std::string &data) +unsigned long test_http_client::request(const utility::string_t& method, + const utility::string_t& path, + const std::string& data) { return request(method, path, std::map(), data); } -unsigned long test_http_client::request( - const utility::string_t &method, - const utility::string_t &path, - const utility::string_t &content_type, - const std::string &data) +unsigned long test_http_client::request(const utility::string_t& method, + const utility::string_t& path, + const utility::string_t& content_type, + const std::string& data) { std::map headers; headers[U("Content-Type")] = content_type; return request(method, path, headers, data); } -unsigned long test_http_client::request( - const utility::string_t &method, - const utility::string_t &path, - const std::map &headers, - const std::string &data) +unsigned long test_http_client::request(const utility::string_t& method, + const utility::string_t& path, + const std::map& headers, + const std::string& data) { - return m_impl->request(method, path, headers, (void *)&data[0], data.size()); + return m_impl->request(method, path, headers, (void*)&data[0], data.size()); } -test_response * test_http_client::wait_for_response() { return m_impl->wait_for_response(); } -pplx::task test_http_client::next_response() { return m_impl->next_response(); } -std::vector test_http_client::wait_for_responses(const size_t count) { return m_impl->wait_for_responses(count); } -std::vector> test_http_client::next_responses(const size_t count) { return m_impl->next_responses(count); } +test_response* test_http_client::wait_for_response() { return m_impl->wait_for_response(); } +pplx::task test_http_client::next_response() { return m_impl->next_response(); } +std::vector test_http_client::wait_for_responses(const size_t count) +{ + return m_impl->wait_for_responses(count); +} +std::vector> test_http_client::next_responses(const size_t count) +{ + return m_impl->next_responses(count); +} -}}}} +} // namespace utilities +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/utilities/test_http_server.cpp b/Release/tests/functional/http/utilities/test_http_server.cpp index c4f848c009..48a5d59115 100644 --- a/Release/tests/functional/http/utilities/test_http_server.cpp +++ b/Release/tests/functional/http/utilities/test_http_server.cpp @@ -1,41 +1,44 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Defines a test server to handle requests and sending responses. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Defines a test server to handle requests and sending responses. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" #ifdef _WIN32 #include #pragma comment(lib, "httpapi.lib") -#pragma warning ( push ) -#pragma warning ( disable : 4457 ) +#pragma warning(push) +#pragma warning(disable : 4457) #include -#pragma warning ( pop ) +#pragma warning(pop) #else #include "cpprest/http_listener.h" #endif -#include - #include "cpprest/uri.h" #include "test_http_server.h" - -#include +#include #include +#include #include -using namespace web; +using namespace web; using namespace utility; using namespace utility::conversions; -namespace tests { namespace functional { namespace http { namespace utilities { - - +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace utilities +{ struct test_server_queue { std::mutex m_lock; @@ -49,24 +52,20 @@ struct test_server_queue tce.set_exception(std::runtime_error("test_http_server closed.")); } - ~test_server_queue() - { - close(); - } + ~test_server_queue() { close(); } void on_request(std::unique_ptr req) { std::lock_guard lk(m_lock); VERIFY_IS_FALSE(m_requests.empty(), "There are no pending calls to next_request."); - if (m_requests.empty()) - return; + if (m_requests.empty()) return; auto tce = std::move(m_requests.front()); m_requests.pop_front(); m_requests_memory.push_back(std::move(req)); tce.set(m_requests_memory.back().get()); } - pplx::task next_request() + pplx::task next_request() { pplx::task_completion_event tce; std::lock_guard lock(m_lock); @@ -77,42 +76,23 @@ struct test_server_queue #if defined(_WIN32) // Helper function to parse verb from Windows HTTP Server API. -static utility::string_t parse_verb(const HTTP_REQUEST *p_http_request) +static utility::string_t parse_verb(const HTTP_REQUEST* p_http_request) { utility::string_t method; std::string temp; - switch(p_http_request->Verb) - { - case HttpVerbGET: - method = U("GET"); - break; - case HttpVerbPOST: - method = U("POST"); - break; - case HttpVerbPUT: - method = U("PUT"); - break; - case HttpVerbDELETE: - method = U("DELETE"); - break; - case HttpVerbHEAD: - method = U("HEAD"); - break; - case HttpVerbOPTIONS: - method = U("OPTIONS"); - break; - case HttpVerbTRACE: - method = U("TRACE"); - break; - case HttpVerbCONNECT: - method = U("CONNECT"); - break; - case HttpVerbUnknown: - temp = p_http_request->pUnknownVerb; - method = utility::string_t(temp.begin(), temp.end()); - default: - break; - } + switch (p_http_request->Verb) + { + case HttpVerbGET: method = U("GET"); break; + case HttpVerbPOST: method = U("POST"); break; + case HttpVerbPUT: method = U("PUT"); break; + case HttpVerbDELETE: method = U("DELETE"); break; + case HttpVerbHEAD: method = U("HEAD"); break; + case HttpVerbOPTIONS: method = U("OPTIONS"); break; + case HttpVerbTRACE: method = U("TRACE"); break; + case HttpVerbCONNECT: method = U("CONNECT"); break; + case HttpVerbUnknown: temp = p_http_request->pUnknownVerb; method = utility::string_t(temp.begin(), temp.end()); + default: break; + } return method; } @@ -120,66 +100,63 @@ static utility::string_t parse_verb(const HTTP_REQUEST *p_http_request) /// String values for all HTTP Server API known headers. /// NOTE: the order here is important it is from the _HTTP_HEADER_ID enum. /// -static utility::string_t HttpServerAPIKnownHeaders[] = +static utility::string_t HttpServerAPIKnownHeaders[] = {U("Cache-Control"), + U("Connection"), + U("Data"), + U("Keep-Alive"), + U("Pragma"), + U("Trailer"), + U("Transfer-Encoding"), + U("Upgrade"), + U("Via"), + U("Warning"), + U("Allow"), + U("Content-Length"), + U("Content-Type"), + U("Content-Encoding"), + U("Content-Language"), + U("Content-Location"), + U("Content-Md5"), + U("Content-Range"), + U("Expires"), + U("Last-Modified"), + U("Accept"), + U("Accept-Charset"), + U("Accept-Encoding"), + U("Accept-Language"), + U("Authorization"), + U("Cookie"), + U("Expect"), + U("From"), + U("Host"), + U("If-Match"), + U("If-Modified-Since"), + U("If-None-Match"), + U("If-Range"), + U("If-Unmodified-Since"), + U("Max-Forwards"), + U("Proxy-Authorization"), + U("Referer"), + U("Range"), + U("TE"), + U("Translate"), + U("User-Agent"), + U("Request-Maximum"), + U("Accept-Ranges"), + U("Age"), + U("Etag"), + U("Location"), + U("Proxy-Authenticate"), + U("Retry-After"), + U("Server"), + U("Set-Cookie"), + U("Vary"), + U("Www-Authenticate"), + U("Response-Maximum")}; + +static utility::string_t char_to_wstring(const char* src) { - U("Cache-Control"), - U("Connection"), - U("Data"), - U("Keep-Alive"), - U("Pragma"), - U("Trailer"), - U("Transfer-Encoding"), - U("Upgrade"), - U("Via"), - U("Warning"), - U("Allow"), - U("Content-Length"), - U("Content-Type"), - U("Content-Encoding"), - U("Content-Language"), - U("Content-Location"), - U("Content-Md5"), - U("Content-Range"), - U("Expires"), - U("Last-Modified"), - U("Accept"), - U("Accept-Charset"), - U("Accept-Encoding"), - U("Accept-Language"), - U("Authorization"), - U("Cookie"), - U("Expect"), - U("From"), - U("Host"), - U("If-Match"), - U("If-Modified-Since"), - U("If-None-Match"), - U("If-Range"), - U("If-Unmodified-Since"), - U("Max-Forwards"), - U("Proxy-Authorization"), - U("Referer"), - U("Range"), - U("TE"), - U("Translate"), - U("User-Agent"), - U("Request-Maximum"), - U("Accept-Ranges"), - U("Age"), - U("Etag"), - U("Location"), - U("Proxy-Authenticate"), - U("Retry-After"), - U("Server"), - U("Set-Cookie"), - U("Vary"), - U("Www-Authenticate"), - U("Response-Maximum") -}; - -static utility::string_t char_to_wstring(const char * src) -{ - if(src == nullptr) + if (src == nullptr) { return utility::string_t(); } @@ -187,16 +164,17 @@ static utility::string_t char_to_wstring(const char * src) return utility::string_t(temp.begin(), temp.end()); } -static std::map parse_http_headers(const HTTP_REQUEST_HEADERS &headers) +static std::map parse_http_headers(const HTTP_REQUEST_HEADERS& headers) { std::map headers_map; - for(USHORT i = 0; i < headers.UnknownHeaderCount; ++i) + for (USHORT i = 0; i < headers.UnknownHeaderCount; ++i) { - headers_map[char_to_wstring(headers.pUnknownHeaders[i].pName)] = char_to_wstring(headers.pUnknownHeaders[i].pRawValue); + headers_map[char_to_wstring(headers.pUnknownHeaders[i].pName)] = + char_to_wstring(headers.pUnknownHeaders[i].pRawValue); } - for(int i = 0; i < HttpHeaderMaximum; ++i) + for (int i = 0; i < HttpHeaderMaximum; ++i) { - if(headers.KnownHeaders[i].RawValueLength != 0) + if (headers.KnownHeaders[i].RawValueLength != 0) { headers_map[HttpServerAPIKnownHeaders[i]] = char_to_wstring(headers.KnownHeaders[i].pRawValue); } @@ -206,12 +184,14 @@ static std::map parse_http_headers(const H struct ConcRTOversubscribe { - ConcRTOversubscribe() { + ConcRTOversubscribe() + { #if _MSC_VER >= 1800 concurrency::Context::Oversubscribe(true); #endif } - ~ConcRTOversubscribe() { + ~ConcRTOversubscribe() + { #if _MSC_VER >= 1800 concurrency::Context::Oversubscribe(false); #endif @@ -222,11 +202,12 @@ class _test_http_server { inline bool is_error_code(ULONG error_code) { - return error_code == ERROR_OPERATION_ABORTED || error_code == ERROR_CONNECTION_INVALID || error_code == ERROR_NETNAME_DELETED || m_closing == 1; + return error_code == ERROR_OPERATION_ABORTED || error_code == ERROR_CONNECTION_INVALID || + error_code == ERROR_NETNAME_DELETED || m_closing == 1; } + public: - _test_http_server(const web::uri &uri) - : m_uri(uri), m_session(0), m_url_group(0), m_request_queue(nullptr) + _test_http_server(const web::uri& uri) : m_uri(uri), m_session(0), m_url_group(0), m_request_queue(nullptr) { // Open server session. HTTPAPI_VERSION httpApiVersion = HTTPAPI_VERSION_2; @@ -253,7 +234,8 @@ class _test_http_server // Windows HTTP Server API will not accept a uri with an empty path, it must have a '/'. auto host_uri = uri.to_string(); - if (uri.is_path_empty() && host_uri[host_uri.length() - 1] != '/' && uri.query().empty() && uri.fragment().empty()) + if (uri.is_path_empty() && host_uri[host_uri.length() - 1] != '/' && uri.query().empty() && + uri.fragment().empty()) { host_uri.append(U("/")); } @@ -269,26 +251,29 @@ class _test_http_server HTTP_BINDING_INFO bindingInfo; bindingInfo.RequestQueueHandle = m_request_queue; bindingInfo.Flags.Present = 1; - error_code = HttpSetUrlGroupProperty(m_url_group, HttpServerBindingProperty, &bindingInfo, sizeof(HTTP_BINDING_INFO)); + error_code = + HttpSetUrlGroupProperty(m_url_group, HttpServerBindingProperty, &bindingInfo, sizeof(HTTP_BINDING_INFO)); if (error_code) { throw std::runtime_error("error code: " + std::to_string(error_code)); } // Launch listener thread - m_thread = std::thread([](_test_http_server* self) { - for (;;) - { - auto req = self->sync_get_request(); - if (req == nullptr) - break; - - self->m_queue.on_request(std::move(req)); - } - }, this); + m_thread = std::thread( + [](_test_http_server* self) { + for (;;) + { + auto req = self->sync_get_request(); + if (req == nullptr) break; + + self->m_queue.on_request(std::move(req)); + } + }, + this); } - ~_test_http_server() { + ~_test_http_server() + { close(); m_thread.join(); @@ -302,17 +287,11 @@ class _test_http_server const ULONG buffer_length = 1024 * 4; char buffer[buffer_length]; ULONG bytes_received = 0; - HTTP_REQUEST *p_http_request = (HTTP_REQUEST *)buffer; + HTTP_REQUEST* p_http_request = (HTTP_REQUEST*)buffer; // Read in everything except the body. - ULONG error_code2 = HttpReceiveHttpRequest( - m_request_queue, - HTTP_NULL_ID, - 0, - p_http_request, - buffer_length, - &bytes_received, - 0); + ULONG error_code2 = + HttpReceiveHttpRequest(m_request_queue, HTTP_NULL_ID, 0, p_http_request, buffer_length, &bytes_received, 0); if (error_code2 != 0) { return nullptr; @@ -327,20 +306,17 @@ class _test_http_server // Read in request body. ULONG content_length; const bool has_content_length = p_test_request->match_header(U("Content-Length"), content_length); - if(has_content_length && content_length > 0) + if (has_content_length && content_length > 0) { p_test_request->m_body.resize(content_length); - auto result = - HttpReceiveRequestEntityBody( - m_request_queue, - p_http_request->RequestId, - HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, - &p_test_request->m_body[0], - content_length, - &bytes_received, - NULL); - if (result != 0) - return nullptr; + auto result = HttpReceiveRequestEntityBody(m_request_queue, + p_http_request->RequestId, + HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, + &p_test_request->m_body[0], + content_length, + &bytes_received, + NULL); + if (result != 0) return nullptr; } utility::string_t transfer_encoding; @@ -349,15 +325,13 @@ class _test_http_server { content_length = 0; char buf[4096]; - auto result = - HttpReceiveRequestEntityBody( - m_request_queue, - p_http_request->RequestId, - HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, - (LPVOID)buf, - 4096, - &bytes_received, - NULL); + auto result = HttpReceiveRequestEntityBody(m_request_queue, + p_http_request->RequestId, + HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, + (LPVOID)buf, + 4096, + &bytes_received, + NULL); while (result == NO_ERROR) { @@ -365,15 +339,13 @@ class _test_http_server p_test_request->m_body.resize(content_length); memcpy(&p_test_request->m_body[content_length - bytes_received], buf, bytes_received); - result = - HttpReceiveRequestEntityBody( - m_request_queue, - p_http_request->RequestId, - HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, - (LPVOID)buf, - 4096, - &bytes_received, - NULL); + result = HttpReceiveRequestEntityBody(m_request_queue, + p_http_request->RequestId, + HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, + (LPVOID)buf, + 4096, + &bytes_received, + NULL); } if (is_error_code(result)) @@ -391,21 +363,22 @@ class _test_http_server // Windows HTTP Server API will not accept a uri with an empty path, it must have a '/'. utility::string_t host_uri = m_uri.to_string(); - if(m_uri.is_path_empty() && host_uri[host_uri.length() - 1] != '/' && m_uri.query().empty() && m_uri.fragment().empty()) + if (m_uri.is_path_empty() && host_uri[host_uri.length() - 1] != '/' && m_uri.query().empty() && + m_uri.fragment().empty()) { host_uri.append(U("/")); } - + // Remove Url. ULONG error_code = HttpRemoveUrlFromUrlGroup(m_url_group, host_uri.c_str(), 0); - if(error_code) + if (error_code) { return error_code; } // Stop request queue. error_code = HttpShutdownRequestQueue(m_request_queue); - if(error_code) + if (error_code) { return error_code; } @@ -420,13 +393,12 @@ class _test_http_server return 0; } - unsigned long send_reply( - const unsigned long long request_id, - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - void * data, - size_t data_length) + unsigned long send_reply(const unsigned long long request_id, + const unsigned short status_code, + const utility::string_t& reason_phrase, + const std::map& headers, + void* data, + size_t data_length) { ConcRTOversubscribe osubs; // Oversubscription for long running ConcRT tasks HTTP_RESPONSE response; @@ -460,13 +432,15 @@ class _test_http_server headers_buffer[headerIndex * 2 + 1] = utf16_to_utf8(iter->second); // TFS 624150 -#pragma warning (push) -#pragma warning (disable : 6386) - response.Headers.pUnknownHeaders[headerIndex].NameLength = (USHORT)headers_buffer[headerIndex * 2].size(); -#pragma warning (pop) +#pragma warning(push) +#pragma warning(disable : 6386) + response.Headers.pUnknownHeaders[headerIndex].NameLength = + (USHORT)headers_buffer[headerIndex * 2].size(); +#pragma warning(pop) response.Headers.pUnknownHeaders[headerIndex].pName = headers_buffer[headerIndex * 2].c_str(); - response.Headers.pUnknownHeaders[headerIndex].RawValueLength = (USHORT)headers_buffer[headerIndex * 2 + 1].size(); + response.Headers.pUnknownHeaders[headerIndex].RawValueLength = + (USHORT)headers_buffer[headerIndex * 2 + 1].size(); response.Headers.pUnknownHeaders[headerIndex].pRawValue = headers_buffer[headerIndex * 2 + 1].c_str(); } } @@ -478,23 +452,22 @@ class _test_http_server { response.EntityChunkCount = 1; dataChunk.DataChunkType = HttpDataChunkFromMemory; - dataChunk.FromMemory.pBuffer = (void *)data; + dataChunk.FromMemory.pBuffer = (void*)data; dataChunk.FromMemory.BufferLength = (ULONG)data_length; response.pEntityChunks = &dataChunk; } // Synchronously sending the request. - unsigned long error_code = HttpSendHttpResponse( - m_request_queue, - request_id, - HTTP_SEND_RESPONSE_FLAG_DISCONNECT, - &response, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); + unsigned long error_code = HttpSendHttpResponse(m_request_queue, + request_id, + HTTP_SEND_RESPONSE_FLAG_DISCONNECT, + &response, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); // Free memory needed for headers. if (response.Headers.UnknownHeaderCount != 0) @@ -533,17 +506,13 @@ class _test_http_server std::unordered_map m_responding_requests; public: - _test_http_server(const web::uri& uri) - : m_listener(uri) - , m_last_request_id(0) + _test_http_server(const web::uri& uri) : m_listener(uri), m_last_request_id(0) { - auto handler = [this](web::http::http_request result) -> void - { + auto handler = [this](web::http::http_request result) -> void { auto tr = std::unique_ptr(new test_request(this->m_last_request_id++, this)); tr->m_method = result.method(); tr->m_path = result.request_uri().resource().to_string(); - if (tr->m_path.empty()) - tr->m_path = U("/"); + if (tr->m_path.empty()) tr->m_path = U("/"); for (auto it = result.headers().begin(); it != result.headers().end(); ++it) tr->m_headers[it->first] = it->second; @@ -564,10 +533,7 @@ class _test_http_server m_listener.open().wait(); } - ~_test_http_server() - { - close(); - } + ~_test_http_server() { close(); } void close() { @@ -575,20 +541,18 @@ class _test_http_server m_queue.close(); } - unsigned long send_reply( - unsigned long long request_id, - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - void * data, - size_t data_length) + unsigned long send_reply(unsigned long long request_id, + const unsigned short status_code, + const utility::string_t& reason_phrase, + const std::map& headers, + void* data, + size_t data_length) { web::http::http_request request; { std::lock_guard lock(m_response_lock); auto it = m_responding_requests.find(request_id); - if (it == m_responding_requests.end()) - throw std::runtime_error("no such request awaiting response"); + if (it == m_responding_requests.end()) throw std::runtime_error("no such request awaiting response"); request = it->second; m_responding_requests.erase(it); } @@ -600,7 +564,7 @@ class _test_http_server for (auto it = headers.begin(); it != headers.end(); ++it) response.headers().add(it->first, it->second); - unsigned char * data_bytes = reinterpret_cast(data); + unsigned char* data_bytes = reinterpret_cast(data); std::vector body_data(data_bytes, data_bytes + data_length); response.set_body(std::move(body_data)); @@ -611,28 +575,27 @@ class _test_http_server }; #endif -unsigned long test_request::reply_impl( - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - void * data, - size_t data_length) +unsigned long test_request::reply_impl(const unsigned short status_code, + const utility::string_t& reason_phrase, + const std::map& headers, + void* data, + size_t data_length) { return m_p_server->send_reply(m_request_id, status_code, reason_phrase, headers, data, data_length); } -test_http_server::test_http_server(const web::http::uri &uri) +test_http_server::test_http_server(const web::http::uri& uri) { m_p_impl = std::unique_ptr<_test_http_server>(new _test_http_server(uri)); } -test_http_server::~test_http_server() { } +test_http_server::~test_http_server() {} -pplx::task test_http_server::next_request() { return m_p_impl->m_queue.next_request(); } +pplx::task test_http_server::next_request() { return m_p_impl->m_queue.next_request(); } -std::vector> test_http_server::next_requests(const size_t count) +std::vector> test_http_server::next_requests(const size_t count) { - std::vector> ret; + std::vector> ret; ret.reserve(count); for (size_t x = 0; x < count; ++x) ret.push_back(next_request()); @@ -641,4 +604,7 @@ std::vector> test_http_server::next_requests(const si void test_http_server::close() { m_p_impl->close(); } -}}}} +} // namespace utilities +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/http/utilities/test_server_utilities.cpp b/Release/tests/functional/http/utilities/test_server_utilities.cpp index 0141e1abbf..d3456ec85b 100644 --- a/Release/tests/functional/http/utilities/test_server_utilities.cpp +++ b/Release/tests/functional/http/utilities/test_server_utilities.cpp @@ -1,86 +1,90 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* test_server_utilities.h - Utility class to send and verify requests and responses working with the http_test_server. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * test_server_utilities.h - Utility class to send and verify requests and responses working with the http_test_server. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" #include "test_server_utilities.h" -#include "http_asserts.h" -using namespace web; using namespace utility; +#include "http_asserts.h" -namespace tests { namespace functional { namespace http { namespace utilities { +using namespace web; +using namespace utility; -void test_server_utilities::verify_request( - ::http::client::http_client *p_client, - const utility::string_t &method, - const utility::string_t &path, - test_http_server *p_server, - unsigned short code) +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace utilities +{ +void test_server_utilities::verify_request(::http::client::http_client* p_client, + const utility::string_t& method, + const utility::string_t& path, + test_http_server* p_server, + unsigned short code) { - p_server->next_request().then([&](test_request *p_request) - { + p_server->next_request().then([&](test_request* p_request) { http_asserts::assert_test_request_equals(p_request, method, path); VERIFY_ARE_EQUAL(0, p_request->reply(code)); }); http_asserts::assert_response_equals(p_client->request(method, path).get(), code); } -void test_server_utilities::verify_request( - ::http::client::http_client *p_client, - const utility::string_t &method, - const utility::string_t &path, - test_http_server *p_server, - unsigned short code, - const utility::string_t &reason) +void test_server_utilities::verify_request(::http::client::http_client* p_client, + const utility::string_t& method, + const utility::string_t& path, + test_http_server* p_server, + unsigned short code, + const utility::string_t& reason) { - p_server->next_request().then([&](test_request *p_request) - { + p_server->next_request().then([&](test_request* p_request) { http_asserts::assert_test_request_equals(p_request, method, path); VERIFY_ARE_EQUAL(0, p_request->reply(code, reason)); }); http_asserts::assert_response_equals(p_client->request(method, path).get(), code, reason); } -void test_server_utilities::verify_request( - ::http::client::http_client *p_client, - const utility::string_t &method, - const utility::string_t &path, - const utility::string_t &request_content_type, - const utility::string_t &request_data, - test_http_server *p_server, - unsigned short code, - const utility::string_t &reason) +void test_server_utilities::verify_request(::http::client::http_client* p_client, + const utility::string_t& method, + const utility::string_t& path, + const utility::string_t& request_content_type, + const utility::string_t& request_data, + test_http_server* p_server, + unsigned short code, + const utility::string_t& reason) { - p_server->next_request().then([&](test_request *p_request) - { + p_server->next_request().then([&](test_request* p_request) { http_asserts::assert_test_request_equals(p_request, method, path, request_content_type, request_data); VERIFY_ARE_EQUAL(0, p_request->reply(code, reason)); }); - http_asserts::assert_response_equals(p_client->request(method, path, request_data, request_content_type).get(), code, reason); + http_asserts::assert_response_equals( + p_client->request(method, path, request_data, request_content_type).get(), code, reason); } -void test_server_utilities::verify_request( - ::http::client::http_client *p_client, - const utility::string_t &method, - const utility::string_t &path, - test_http_server *p_server, - unsigned short code, - const std::map &response_headers) +void test_server_utilities::verify_request(::http::client::http_client* p_client, + const utility::string_t& method, + const utility::string_t& path, + test_http_server* p_server, + unsigned short code, + const std::map& response_headers) { - p_server->next_request().then([&](test_request *p_request) - { + p_server->next_request().then([&](test_request* p_request) { http_asserts::assert_test_request_equals(p_request, method, path); VERIFY_ARE_EQUAL(0, p_request->reply(code, U(""), response_headers)); }); http_asserts::assert_response_equals(p_client->request(method, path).get(), code, response_headers); } -}}}} +} // namespace utilities +} // namespace http +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/json/construction_tests.cpp b/Release/tests/functional/json/construction_tests.cpp index 1153dd9088..ee5d9cbbce 100644 --- a/Release/tests/functional/json/construction_tests.cpp +++ b/Release/tests/functional/json/construction_tests.cpp @@ -1,496 +1,500 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* construction_tests.cpp -* -* Tests creating JSON values. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * construction_tests.cpp + * + * Tests creating JSON values. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -using namespace web; using namespace utility; +using namespace web; +using namespace utility; -namespace tests { namespace functional { namespace json_tests { - -SUITE(construction_tests) +namespace tests { - -#if defined(__cplusplus_winrt) - -TEST(winrt_platform_string) -{ - Platform::String ^platformStr = "Hello!"; - json::value jstr = json::value::string(platformStr->Data()); - CHECK(jstr.is_string()); - CHECK_EQUAL(jstr.serialize(), U("\"Hello!\"")); -} - -#endif - -TEST(assignment_op) +namespace functional { - json::value arr = json::value::array(); - arr[0] = json::value(true); - - json::value ass_copy = arr; - VERIFY_IS_TRUE(ass_copy.is_array()); - VERIFY_ARE_EQUAL(U("true"), ass_copy[0].serialize()); - ass_copy[1] = json::value(false); - VERIFY_ARE_EQUAL(U("false"), ass_copy[1].serialize()); - VERIFY_ARE_EQUAL(U("null"), arr[1].serialize()); -} - -TEST(copy_ctor_array) +namespace json_tests { - json::value arr = json::value::array(); - arr[0] = json::value(true); - - json::value copy(arr); - VERIFY_IS_TRUE(copy.is_array()); - VERIFY_ARE_EQUAL(U("true"), copy[0].serialize()); - copy[1] = json::value(false); - VERIFY_ARE_EQUAL(U("false"), copy[1].serialize()); - VERIFY_ARE_EQUAL(U("null"), arr[1].serialize()); -} - -TEST(copy_ctor_object) -{ - json::value obj = json::value::object(); - utility::string_t keyName(U("key")); - obj[keyName] = json::value(false); - - // Copy object that has values added. - json::value copy(obj); - VERIFY_IS_TRUE(copy.is_object()); - VERIFY_ARE_EQUAL(U("false"), copy[keyName].serialize()); - obj[keyName] = json::value(true); - VERIFY_ARE_EQUAL(U("false"), copy[keyName].serialize()); - VERIFY_ARE_EQUAL(U("true"), obj[keyName].serialize()); - - // Copy object that parses with value, but none additional added. - obj = json::value::parse(U("{\"key\": true}")); - json::value copy2(obj); - VERIFY_IS_TRUE(copy2.is_object()); - obj[keyName] = json::value(false); - VERIFY_IS_TRUE(copy2.size() == 1); - VERIFY_ARE_EQUAL(U("false"), obj[keyName].serialize()); - VERIFY_ARE_EQUAL(U("true"), copy2[keyName].serialize()); -} - -TEST(copy_ctor_string) -{ - utility::string_t strValue(U("teststr")); - json::value str = json::value::string(strValue); - - json::value copy(str); - VERIFY_IS_TRUE(copy.is_string()); - VERIFY_ARE_EQUAL(strValue, copy.as_string()); - str = json::value::string(U("teststr2")); - VERIFY_ARE_EQUAL(strValue, copy.as_string()); - VERIFY_ARE_EQUAL(U("teststr2"), str.as_string()); -} - -TEST(copy_ctor_with_escaped) -{ - auto str = json::value::parse(U("\"\\n\"")); - VERIFY_ARE_EQUAL(U("\n"), str.as_string()); - - auto copy = str; - VERIFY_ARE_EQUAL(U("\n"), copy.as_string()); -} - -TEST(move_ctor) -{ - json::value obj; - obj[U("A")] = json::value(true); - - json::value moved(std::move(obj)); - VERIFY_IS_TRUE(moved.is_object()); - VERIFY_ARE_EQUAL(U("true"), moved[U("A")].serialize()); - moved[U("B")] = json::value(false); - VERIFY_ARE_EQUAL(U("false"), moved[U("B")].serialize()); -} - -TEST(move_assignment_op) -{ - json::value obj; - obj[U("A")] = json::value(true); - - json::value moved; - moved = std::move(obj); - VERIFY_IS_TRUE(moved.is_object()); - VERIFY_ARE_EQUAL(U("true"), moved[U("A")].serialize()); - moved[U("B")] = json::value(false); - VERIFY_ARE_EQUAL(U("false"), moved[U("B")].serialize()); -} - -TEST(constructor_overloads) -{ - json::value v0; - json::value v1(17); - json::value v2(3.1415); - json::value v3(true); - const utility::char_t* p4 = U("Hello!"); - json::value v4(p4); - - json::value v5(U("Hello Again!")); - json::value v6(U("YES YOU KNOW IT")); - json::value v7(U("HERE ID IS")); - - const utility::char_t* p9 = U("Hello not-escaped!"); - json::value v8(p9, true); - json::value v9(p9, false); - - VERIFY_ARE_EQUAL(v0.type(), json::value::Null); - VERIFY_IS_TRUE(v0.is_null()); - VERIFY_ARE_EQUAL(v1.type(), json::value::Number); - VERIFY_IS_TRUE(v1.is_number()); - VERIFY_IS_TRUE(v1.is_integer()); - VERIFY_IS_FALSE(v1.is_double()); - VERIFY_ARE_EQUAL(v2.type(), json::value::Number); - VERIFY_IS_TRUE(v2.is_number()); - VERIFY_IS_TRUE(v2.is_double()); - VERIFY_IS_FALSE(v2.is_integer()); - VERIFY_ARE_EQUAL(v3.type(), json::value::Boolean); - VERIFY_IS_TRUE(v3.is_boolean()); - VERIFY_ARE_EQUAL(v4.type(), json::value::String); - VERIFY_IS_TRUE(v4.is_string()); - VERIFY_ARE_EQUAL(v5.type(), json::value::String); - VERIFY_IS_TRUE(v5.is_string()); - VERIFY_ARE_EQUAL(v6.type(), json::value::String); - VERIFY_IS_TRUE(v6.is_string()); - VERIFY_ARE_EQUAL(v7.type(), json::value::String); - VERIFY_IS_TRUE(v7.is_string()); - VERIFY_ARE_EQUAL(v8.type(), json::value::String); - VERIFY_IS_TRUE(v8.is_string()); - VERIFY_ARE_EQUAL(v9.type(), json::value::String); - VERIFY_IS_TRUE(v9.is_string()); -} - -TEST(factory_overloads) -{ - json::value v0 = json::value::null(); - json::value v1 = json::value::number(17); - json::value v2 = json::value::number(3.1415); - json::value v3 = json::value::boolean(true); - json::value v4 = json::value::string(U("Hello!")); - json::value v5 = json::value::string(U("Hello Again!")); - json::value v6 = json::value::string(U("Hello!")); - json::value v7 = json::value::string(U("Hello Again!")); - json::value v8 = json::value::string(U("Hello not-escaped!"), true); - json::value v9 = json::value::string(U("Hello not-escaped!"), false); - json::value v10 = json::value::object(); - json::value v11 = json::value::array(); - - - VERIFY_ARE_EQUAL(v0.type(), json::value::Null); - VERIFY_ARE_EQUAL(v1.type(), json::value::Number); - VERIFY_ARE_EQUAL(v2.type(), json::value::Number); - VERIFY_ARE_EQUAL(v3.type(), json::value::Boolean); - VERIFY_ARE_EQUAL(v4.type(), json::value::String); - VERIFY_ARE_EQUAL(v5.type(), json::value::String); - VERIFY_ARE_EQUAL(v6.type(), json::value::String); - VERIFY_ARE_EQUAL(v7.type(), json::value::String); - VERIFY_ARE_EQUAL(v8.type(), json::value::String); - VERIFY_ARE_EQUAL(v9.type(), json::value::String); - VERIFY_ARE_EQUAL(v10.type(), json::value::Object); - VERIFY_IS_TRUE(v10.is_object()); - VERIFY_ARE_EQUAL(v11.type(), json::value::Array); - VERIFY_IS_TRUE(v11.is_array()); -} - -TEST(object_construction) -{ - // Factory which takes a vector. - std::vector> f; - f.push_back(std::make_pair(U("abc"), json::value(true))); - f.push_back(std::make_pair(U("xyz"), json::value(44))); - json::value obj = json::value::object(f); - - VERIFY_ARE_EQUAL(f.size(), obj.size()); - - obj[U("abc")] = json::value::string(U("str")); - obj[U("123")] = json::value(false); - - VERIFY_ARE_NOT_EQUAL(f.size(), obj.size()); - VERIFY_ARE_EQUAL(json::value::string(U("str")).serialize(), obj[U("abc")].serialize()); - VERIFY_ARE_EQUAL(json::value(false).serialize(), obj[U("123")].serialize()); - - // Tests constructing empty and adding. - auto val1 = json::value::object(); - val1[U("A")] = 44; - val1[U("hahah")] = json::value(true); - VERIFY_ARE_EQUAL(2u, val1.size()); - VERIFY_ARE_EQUAL(U("44"), val1[U("A")].serialize()); - VERIFY_ARE_EQUAL(U("true"), val1[U("hahah")].serialize()); - - // Construct as null value, then turn into object. - json::value val2; - VERIFY_IS_TRUE(val2.is_null()); - val2[U("A")] = 44; - val2[U("hahah")] = json::value(true); - VERIFY_ARE_EQUAL(2u, val2.size()); - VERIFY_ARE_EQUAL(U("44"), val2[U("A")].serialize()); - VERIFY_ARE_EQUAL(U("true"), val2[U("hahah")].serialize()); -} - -TEST(object_construction_keep_order) +SUITE(construction_tests) { - std::vector> f; - f.push_back(std::make_pair(U("x"), json::value(0))); - f.push_back(std::make_pair(U("a"), json::value(1))); - - auto obj1 = json::value::object(f, /*keep_order==*/ true); - VERIFY_ARE_EQUAL(obj1.as_object().begin()->first, U("x")); - - auto obj2 = json::value::object(f, /*keep_order==*/ false); - VERIFY_ARE_EQUAL(obj2.as_object().begin()->first, U("a")); -} +#if defined(__cplusplus_winrt) -TEST(object_construction_from_null_keep_order) -{ - struct restore { - ~restore() { - json::keep_object_element_order(false); - } - }_; + TEST(winrt_platform_string) + { + Platform::String ^ platformStr = "Hello!"; + json::value jstr = json::value::string(platformStr->Data()); + CHECK(jstr.is_string()); + CHECK_EQUAL(jstr.serialize(), U("\"Hello!\"")); + } - json::keep_object_element_order(true); +#endif - auto val1 = json::value::null(); - val1[U("B")] = 1; - val1[U("A")] = 1; - VERIFY_ARE_EQUAL(val1.as_object().begin()->first, U("B")); + TEST(assignment_op) + { + json::value arr = json::value::array(); + arr[0] = json::value(true); + + json::value ass_copy = arr; + VERIFY_IS_TRUE(ass_copy.is_array()); + VERIFY_ARE_EQUAL(U("true"), ass_copy[0].serialize()); + ass_copy[1] = json::value(false); + VERIFY_ARE_EQUAL(U("false"), ass_copy[1].serialize()); + VERIFY_ARE_EQUAL(U("null"), arr[1].serialize()); + } - json::keep_object_element_order(false); + TEST(copy_ctor_array) + { + json::value arr = json::value::array(); + arr[0] = json::value(true); + + json::value copy(arr); + VERIFY_IS_TRUE(copy.is_array()); + VERIFY_ARE_EQUAL(U("true"), copy[0].serialize()); + copy[1] = json::value(false); + VERIFY_ARE_EQUAL(U("false"), copy[1].serialize()); + VERIFY_ARE_EQUAL(U("null"), arr[1].serialize()); + } - auto val2 = json::value::null(); - val2[U("B")] = 1; - val2[U("A")] = 1; - VERIFY_ARE_EQUAL(val2.as_object().begin()->first, U("A")); -} + TEST(copy_ctor_object) + { + json::value obj = json::value::object(); + utility::string_t keyName(U("key")); + obj[keyName] = json::value(false); + + // Copy object that has values added. + json::value copy(obj); + VERIFY_IS_TRUE(copy.is_object()); + VERIFY_ARE_EQUAL(U("false"), copy[keyName].serialize()); + obj[keyName] = json::value(true); + VERIFY_ARE_EQUAL(U("false"), copy[keyName].serialize()); + VERIFY_ARE_EQUAL(U("true"), obj[keyName].serialize()); + + // Copy object that parses with value, but none additional added. + obj = json::value::parse(U("{\"key\": true}")); + json::value copy2(obj); + VERIFY_IS_TRUE(copy2.is_object()); + obj[keyName] = json::value(false); + VERIFY_IS_TRUE(copy2.size() == 1); + VERIFY_ARE_EQUAL(U("false"), obj[keyName].serialize()); + VERIFY_ARE_EQUAL(U("true"), copy2[keyName].serialize()); + } -TEST(array_construction) -{ - // Constructor which takes a vector. - std::vector e; - e.push_back(json::value(false)); - e.push_back(json::value::string(U("hehe"))); - json::value arr = json::value::array(e); - VERIFY_ARE_EQUAL(e.size(), arr.size()); - VERIFY_ARE_EQUAL(U("false"), arr[0].serialize()); - arr[3] = json::value(22); - VERIFY_ARE_NOT_EQUAL(e.size(), arr.size()); - VERIFY_ARE_EQUAL(U("22"), arr[3].serialize()); - - // Test empty factory and adding. - auto arr2 = json::value::array(); - arr2[1] = json::value(false); - arr2[0] = json::value::object(); - arr2[0][U("A")] = json::value::string(U("HE")); - VERIFY_ARE_EQUAL(2u, arr2.size()); - VERIFY_ARE_EQUAL(U("false"), arr2[1].serialize()); - VERIFY_ARE_EQUAL(U("\"HE\""), arr2[0][U("A")].serialize()); - - // Construct as null value and then add elements. - json::value arr3; - VERIFY_IS_TRUE(arr3.is_null()); - arr3[1] = json::value(false); - // Element [0] should already behave as an object. - arr3[0][U("A")] = json::value::string(U("HE")); - VERIFY_ARE_EQUAL(2u, arr3.size()); - VERIFY_ARE_EQUAL(U("false"), arr3[1].serialize()); - VERIFY_ARE_EQUAL(U("\"HE\""), arr3[0][U("A")].serialize()); - - // Test factory which takes a size. - auto arr4 = json::value::array(2); - VERIFY_IS_TRUE(arr4[0].is_null()); - VERIFY_IS_TRUE(arr4[1].is_null()); - arr4[2] = json::value(true); - arr4[0] = json::value(false); - VERIFY_ARE_EQUAL(U("false"), arr4[0].serialize()); - VERIFY_ARE_EQUAL(U("true"), arr4[2].serialize()); -} - -TEST(array_test) -{ - json::value arr = json::value::array(); - const json::value& carr = arr; - arr[0] = json::value(3.14); - arr[1] = json::value(true); - arr[2] = json::value("Yes"); - int count; - json::array& array = arr.as_array(); - const json::array& carray = arr.as_array(); - - VERIFY_THROWS(array.at(4), json::json_exception); - VERIFY_THROWS(carray.at(5), json::json_exception); - VERIFY_THROWS(arr.at(6), json::json_exception); - VERIFY_THROWS(carr.at(7), json::json_exception); - - // The begin and end iterators on non-const instances - count = 0; - for(auto iter = array.begin(); iter != array.end(); ++iter) + TEST(copy_ctor_string) { - VERIFY_IS_TRUE((*iter) == array[count]); - VERIFY_IS_TRUE((*iter) == array.at(count)); - VERIFY_IS_TRUE((*iter) == carray.at(count)); - count++; + utility::string_t strValue(U("teststr")); + json::value str = json::value::string(strValue); + + json::value copy(str); + VERIFY_IS_TRUE(copy.is_string()); + VERIFY_ARE_EQUAL(strValue, copy.as_string()); + str = json::value::string(U("teststr2")); + VERIFY_ARE_EQUAL(strValue, copy.as_string()); + VERIFY_ARE_EQUAL(U("teststr2"), str.as_string()); } - VERIFY_ARE_EQUAL(array.size(), count); - count = 0; - for(auto iter = array.cbegin(); iter != array.cend(); ++iter) + TEST(copy_ctor_with_escaped) { - VERIFY_IS_TRUE((*iter) == array[count]); - VERIFY_IS_TRUE((*iter) == array.at(count)); - count++; + auto str = json::value::parse(U("\"\\n\"")); + VERIFY_ARE_EQUAL(U("\n"), str.as_string()); + + auto copy = str; + VERIFY_ARE_EQUAL(U("\n"), copy.as_string()); } - VERIFY_ARE_EQUAL(array.size(), count); - count = 0; - for(auto iter = array.rbegin(); iter != array.rend(); ++iter) + TEST(move_ctor) { - VERIFY_IS_TRUE((*iter) == array[array.size()-1-count]); - VERIFY_IS_TRUE((*iter) == array.at(array.size()-1-count)); - VERIFY_IS_TRUE((*iter) == carray.at(array.size()-1-count)); - count++; + json::value obj; + obj[U("A")] = json::value(true); + + json::value moved(std::move(obj)); + VERIFY_IS_TRUE(moved.is_object()); + VERIFY_ARE_EQUAL(U("true"), moved[U("A")].serialize()); + moved[U("B")] = json::value(false); + VERIFY_ARE_EQUAL(U("false"), moved[U("B")].serialize()); } - VERIFY_ARE_EQUAL(array.size(), count); - count = 0; - for(auto iter = array.crbegin(); iter != array.crend(); ++iter) + TEST(move_assignment_op) { - VERIFY_IS_TRUE((*iter) == array[array.size()-1-count]); - VERIFY_IS_TRUE((*iter) == arr[array.size()-1-count]); - VERIFY_IS_TRUE((*iter) == array.at(array.size()-1-count)); - VERIFY_IS_TRUE((*iter) == arr.at(array.size()-1-count)); - count++; + json::value obj; + obj[U("A")] = json::value(true); + + json::value moved; + moved = std::move(obj); + VERIFY_IS_TRUE(moved.is_object()); + VERIFY_ARE_EQUAL(U("true"), moved[U("A")].serialize()); + moved[U("B")] = json::value(false); + VERIFY_ARE_EQUAL(U("false"), moved[U("B")].serialize()); } - VERIFY_ARE_EQUAL(array.size(), count); - // The begin and end iterators on const instances - count = 0; - for(auto iter = carray.begin(); iter != carray.end(); ++iter) + TEST(constructor_overloads) { - VERIFY_IS_TRUE((*iter) == carray.at(count)); - VERIFY_IS_TRUE((*iter) == carr.at(count)); - count++; + json::value v0; + json::value v1(17); + json::value v2(3.1415); + json::value v3(true); + const utility::char_t* p4 = U("Hello!"); + json::value v4(p4); + + json::value v5(U("Hello Again!")); + json::value v6(U("YES YOU KNOW IT")); + json::value v7(U("HERE ID IS")); + + const utility::char_t* p9 = U("Hello not-escaped!"); + json::value v8(p9, true); + json::value v9(p9, false); + + VERIFY_ARE_EQUAL(v0.type(), json::value::Null); + VERIFY_IS_TRUE(v0.is_null()); + VERIFY_ARE_EQUAL(v1.type(), json::value::Number); + VERIFY_IS_TRUE(v1.is_number()); + VERIFY_IS_TRUE(v1.is_integer()); + VERIFY_IS_FALSE(v1.is_double()); + VERIFY_ARE_EQUAL(v2.type(), json::value::Number); + VERIFY_IS_TRUE(v2.is_number()); + VERIFY_IS_TRUE(v2.is_double()); + VERIFY_IS_FALSE(v2.is_integer()); + VERIFY_ARE_EQUAL(v3.type(), json::value::Boolean); + VERIFY_IS_TRUE(v3.is_boolean()); + VERIFY_ARE_EQUAL(v4.type(), json::value::String); + VERIFY_IS_TRUE(v4.is_string()); + VERIFY_ARE_EQUAL(v5.type(), json::value::String); + VERIFY_IS_TRUE(v5.is_string()); + VERIFY_ARE_EQUAL(v6.type(), json::value::String); + VERIFY_IS_TRUE(v6.is_string()); + VERIFY_ARE_EQUAL(v7.type(), json::value::String); + VERIFY_IS_TRUE(v7.is_string()); + VERIFY_ARE_EQUAL(v8.type(), json::value::String); + VERIFY_IS_TRUE(v8.is_string()); + VERIFY_ARE_EQUAL(v9.type(), json::value::String); + VERIFY_IS_TRUE(v9.is_string()); } - VERIFY_ARE_EQUAL(array.size(), count); - count = 0; - for(auto iter = carray.rbegin(); iter != carray.rend(); ++iter) + TEST(factory_overloads) { - VERIFY_IS_TRUE((*iter) == carray.at(array.size()-1-count)); - VERIFY_IS_TRUE((*iter) == carr.at(array.size()-1-count)); - count++; + json::value v0 = json::value::null(); + json::value v1 = json::value::number(17); + json::value v2 = json::value::number(3.1415); + json::value v3 = json::value::boolean(true); + json::value v4 = json::value::string(U("Hello!")); + json::value v5 = json::value::string(U("Hello Again!")); + json::value v6 = json::value::string(U("Hello!")); + json::value v7 = json::value::string(U("Hello Again!")); + json::value v8 = json::value::string(U("Hello not-escaped!"), true); + json::value v9 = json::value::string(U("Hello not-escaped!"), false); + json::value v10 = json::value::object(); + json::value v11 = json::value::array(); + + VERIFY_ARE_EQUAL(v0.type(), json::value::Null); + VERIFY_ARE_EQUAL(v1.type(), json::value::Number); + VERIFY_ARE_EQUAL(v2.type(), json::value::Number); + VERIFY_ARE_EQUAL(v3.type(), json::value::Boolean); + VERIFY_ARE_EQUAL(v4.type(), json::value::String); + VERIFY_ARE_EQUAL(v5.type(), json::value::String); + VERIFY_ARE_EQUAL(v6.type(), json::value::String); + VERIFY_ARE_EQUAL(v7.type(), json::value::String); + VERIFY_ARE_EQUAL(v8.type(), json::value::String); + VERIFY_ARE_EQUAL(v9.type(), json::value::String); + VERIFY_ARE_EQUAL(v10.type(), json::value::Object); + VERIFY_IS_TRUE(v10.is_object()); + VERIFY_ARE_EQUAL(v11.type(), json::value::Array); + VERIFY_IS_TRUE(v11.is_array()); } - VERIFY_ARE_EQUAL(array.size(), count); -} -TEST(object_test) -{ - json::value obj = json::value::object(); - const json::value& cobj = obj; - json::object& object = obj.as_object(); - const json::object& cobject = obj.as_object(); - - VERIFY_IS_TRUE(object.empty()); - - obj[U("name")] = json::value(U("John")); - obj[U("surname")] = json::value(U("Smith")); - obj[U("height")] = json::value(5.9); - obj[U("vegetarian")] = json::value(true); - int count; - - //Test at() - VERIFY_ARE_EQUAL(U("John"), obj.at(U("name")).as_string()); - VERIFY_ARE_EQUAL(U("John"), cobj.at(U("name")).as_string()); - VERIFY_ARE_EQUAL(U("Smith"), object.at(U("surname")).as_string()); - VERIFY_ARE_EQUAL(U("Smith"), cobject.at(U("surname")).as_string()); - VERIFY_THROWS(obj.at(U("wrong key")), json::json_exception); - VERIFY_THROWS(cobj.at(U("wrong key")), json::json_exception); - - //Test find() + TEST(object_construction) { - auto iter = object.find(U("height")); - VERIFY_ARE_NOT_EQUAL(object.end(), iter); - VERIFY_IS_TRUE(iter->second.is_number()); - VERIFY_ARE_EQUAL(5.9, iter->second.as_number().to_double()); - VERIFY_ARE_EQUAL(object.end(), object.find(U("wrong_key"))); + // Factory which takes a vector. + std::vector> f; + f.push_back(std::make_pair(U("abc"), json::value(true))); + f.push_back(std::make_pair(U("xyz"), json::value(44))); + json::value obj = json::value::object(f); + + VERIFY_ARE_EQUAL(f.size(), obj.size()); + + obj[U("abc")] = json::value::string(U("str")); + obj[U("123")] = json::value(false); + + VERIFY_ARE_NOT_EQUAL(f.size(), obj.size()); + VERIFY_ARE_EQUAL(json::value::string(U("str")).serialize(), obj[U("abc")].serialize()); + VERIFY_ARE_EQUAL(json::value(false).serialize(), obj[U("123")].serialize()); + + // Tests constructing empty and adding. + auto val1 = json::value::object(); + val1[U("A")] = 44; + val1[U("hahah")] = json::value(true); + VERIFY_ARE_EQUAL(2u, val1.size()); + VERIFY_ARE_EQUAL(U("44"), val1[U("A")].serialize()); + VERIFY_ARE_EQUAL(U("true"), val1[U("hahah")].serialize()); + + // Construct as null value, then turn into object. + json::value val2; + VERIFY_IS_TRUE(val2.is_null()); + val2[U("A")] = 44; + val2[U("hahah")] = json::value(true); + VERIFY_ARE_EQUAL(2u, val2.size()); + VERIFY_ARE_EQUAL(U("44"), val2[U("A")].serialize()); + VERIFY_ARE_EQUAL(U("true"), val2[U("hahah")].serialize()); } - //Test find() const - auto citer = cobject.find(U("height")); - VERIFY_ARE_NOT_EQUAL(cobject.end(), citer); - VERIFY_IS_TRUE(citer->second.is_number()); - VERIFY_ARE_EQUAL(5.9, citer->second.as_number().to_double()); - VERIFY_ARE_EQUAL(cobject.end(), cobject.find(U("wrong_key"))); + TEST(object_construction_keep_order) + { + std::vector> f; + f.push_back(std::make_pair(U("x"), json::value(0))); + f.push_back(std::make_pair(U("a"), json::value(1))); - VERIFY_IS_FALSE(object.empty()); + auto obj1 = json::value::object(f, /*keep_order==*/true); + VERIFY_ARE_EQUAL(obj1.as_object().begin()->first, U("x")); - // The begin and end iterators on non-const instances - count = 0; - for(auto iter = object.begin(); iter != object.end(); ++iter) - { - VERIFY_ARE_EQUAL(object[iter->first], iter->second); - count++; + auto obj2 = json::value::object(f, /*keep_order==*/false); + VERIFY_ARE_EQUAL(obj2.as_object().begin()->first, U("a")); } - VERIFY_ARE_EQUAL(object.size(), count); - count = 0; - for(auto iter = object.rbegin(); iter != object.rend(); ++iter) + TEST(object_construction_from_null_keep_order) { - VERIFY_ARE_EQUAL(object[iter->first], iter->second); - count++; + struct restore + { + ~restore() { json::keep_object_element_order(false); } + } _; + + json::keep_object_element_order(true); + + auto val1 = json::value::null(); + val1[U("B")] = 1; + val1[U("A")] = 1; + VERIFY_ARE_EQUAL(val1.as_object().begin()->first, U("B")); + + json::keep_object_element_order(false); + + auto val2 = json::value::null(); + val2[U("B")] = 1; + val2[U("A")] = 1; + VERIFY_ARE_EQUAL(val2.as_object().begin()->first, U("A")); } - VERIFY_ARE_EQUAL(object.size(), count); - count = 0; - for(auto iter = object.cbegin(); iter != object.cend(); ++iter) + TEST(array_construction) { - VERIFY_ARE_EQUAL(object[iter->first], iter->second); - count++; + // Constructor which takes a vector. + std::vector e; + e.push_back(json::value(false)); + e.push_back(json::value::string(U("hehe"))); + json::value arr = json::value::array(e); + VERIFY_ARE_EQUAL(e.size(), arr.size()); + VERIFY_ARE_EQUAL(U("false"), arr[0].serialize()); + arr[3] = json::value(22); + VERIFY_ARE_NOT_EQUAL(e.size(), arr.size()); + VERIFY_ARE_EQUAL(U("22"), arr[3].serialize()); + + // Test empty factory and adding. + auto arr2 = json::value::array(); + arr2[1] = json::value(false); + arr2[0] = json::value::object(); + arr2[0][U("A")] = json::value::string(U("HE")); + VERIFY_ARE_EQUAL(2u, arr2.size()); + VERIFY_ARE_EQUAL(U("false"), arr2[1].serialize()); + VERIFY_ARE_EQUAL(U("\"HE\""), arr2[0][U("A")].serialize()); + + // Construct as null value and then add elements. + json::value arr3; + VERIFY_IS_TRUE(arr3.is_null()); + arr3[1] = json::value(false); + // Element [0] should already behave as an object. + arr3[0][U("A")] = json::value::string(U("HE")); + VERIFY_ARE_EQUAL(2u, arr3.size()); + VERIFY_ARE_EQUAL(U("false"), arr3[1].serialize()); + VERIFY_ARE_EQUAL(U("\"HE\""), arr3[0][U("A")].serialize()); + + // Test factory which takes a size. + auto arr4 = json::value::array(2); + VERIFY_IS_TRUE(arr4[0].is_null()); + VERIFY_IS_TRUE(arr4[1].is_null()); + arr4[2] = json::value(true); + arr4[0] = json::value(false); + VERIFY_ARE_EQUAL(U("false"), arr4[0].serialize()); + VERIFY_ARE_EQUAL(U("true"), arr4[2].serialize()); } - VERIFY_ARE_EQUAL(object.size(), count); - count = 0; - for(auto iter = object.crbegin(); iter != object.crend(); ++iter) + TEST(array_test) { - VERIFY_ARE_EQUAL(object[iter->first], iter->second); - count++; + json::value arr = json::value::array(); + const json::value& carr = arr; + arr[0] = json::value(3.14); + arr[1] = json::value(true); + arr[2] = json::value("Yes"); + int count; + json::array& array = arr.as_array(); + const json::array& carray = arr.as_array(); + + VERIFY_THROWS(array.at(4), json::json_exception); + VERIFY_THROWS(carray.at(5), json::json_exception); + VERIFY_THROWS(arr.at(6), json::json_exception); + VERIFY_THROWS(carr.at(7), json::json_exception); + + // The begin and end iterators on non-const instances + count = 0; + for (auto iter = array.begin(); iter != array.end(); ++iter) + { + VERIFY_IS_TRUE((*iter) == array[count]); + VERIFY_IS_TRUE((*iter) == array.at(count)); + VERIFY_IS_TRUE((*iter) == carray.at(count)); + count++; + } + VERIFY_ARE_EQUAL(array.size(), count); + + count = 0; + for (auto iter = array.cbegin(); iter != array.cend(); ++iter) + { + VERIFY_IS_TRUE((*iter) == array[count]); + VERIFY_IS_TRUE((*iter) == array.at(count)); + count++; + } + VERIFY_ARE_EQUAL(array.size(), count); + + count = 0; + for (auto iter = array.rbegin(); iter != array.rend(); ++iter) + { + VERIFY_IS_TRUE((*iter) == array[array.size() - 1 - count]); + VERIFY_IS_TRUE((*iter) == array.at(array.size() - 1 - count)); + VERIFY_IS_TRUE((*iter) == carray.at(array.size() - 1 - count)); + count++; + } + VERIFY_ARE_EQUAL(array.size(), count); + + count = 0; + for (auto iter = array.crbegin(); iter != array.crend(); ++iter) + { + VERIFY_IS_TRUE((*iter) == array[array.size() - 1 - count]); + VERIFY_IS_TRUE((*iter) == arr[array.size() - 1 - count]); + VERIFY_IS_TRUE((*iter) == array.at(array.size() - 1 - count)); + VERIFY_IS_TRUE((*iter) == arr.at(array.size() - 1 - count)); + count++; + } + VERIFY_ARE_EQUAL(array.size(), count); + + // The begin and end iterators on const instances + count = 0; + for (auto iter = carray.begin(); iter != carray.end(); ++iter) + { + VERIFY_IS_TRUE((*iter) == carray.at(count)); + VERIFY_IS_TRUE((*iter) == carr.at(count)); + count++; + } + VERIFY_ARE_EQUAL(array.size(), count); + + count = 0; + for (auto iter = carray.rbegin(); iter != carray.rend(); ++iter) + { + VERIFY_IS_TRUE((*iter) == carray.at(array.size() - 1 - count)); + VERIFY_IS_TRUE((*iter) == carr.at(array.size() - 1 - count)); + count++; + } + VERIFY_ARE_EQUAL(array.size(), count); } - VERIFY_ARE_EQUAL(object.size(), count); - // The begin and end iterators on const instances - count = 0; - for(auto iter = cobject.begin(); iter != cobject.end(); ++iter) + TEST(object_test) { - VERIFY_ARE_EQUAL(cobject.find(iter->first)->second, iter->second); - count++; + json::value obj = json::value::object(); + const json::value& cobj = obj; + json::object& object = obj.as_object(); + const json::object& cobject = obj.as_object(); + + VERIFY_IS_TRUE(object.empty()); + + obj[U("name")] = json::value(U("John")); + obj[U("surname")] = json::value(U("Smith")); + obj[U("height")] = json::value(5.9); + obj[U("vegetarian")] = json::value(true); + int count; + + // Test at() + VERIFY_ARE_EQUAL(U("John"), obj.at(U("name")).as_string()); + VERIFY_ARE_EQUAL(U("John"), cobj.at(U("name")).as_string()); + VERIFY_ARE_EQUAL(U("Smith"), object.at(U("surname")).as_string()); + VERIFY_ARE_EQUAL(U("Smith"), cobject.at(U("surname")).as_string()); + VERIFY_THROWS(obj.at(U("wrong key")), json::json_exception); + VERIFY_THROWS(cobj.at(U("wrong key")), json::json_exception); + + // Test find() + { + auto iter = object.find(U("height")); + VERIFY_ARE_NOT_EQUAL(object.end(), iter); + VERIFY_IS_TRUE(iter->second.is_number()); + VERIFY_ARE_EQUAL(5.9, iter->second.as_number().to_double()); + VERIFY_ARE_EQUAL(object.end(), object.find(U("wrong_key"))); + } + + // Test find() const + auto citer = cobject.find(U("height")); + VERIFY_ARE_NOT_EQUAL(cobject.end(), citer); + VERIFY_IS_TRUE(citer->second.is_number()); + VERIFY_ARE_EQUAL(5.9, citer->second.as_number().to_double()); + VERIFY_ARE_EQUAL(cobject.end(), cobject.find(U("wrong_key"))); + + VERIFY_IS_FALSE(object.empty()); + + // The begin and end iterators on non-const instances + count = 0; + for (auto iter = object.begin(); iter != object.end(); ++iter) + { + VERIFY_ARE_EQUAL(object[iter->first], iter->second); + count++; + } + VERIFY_ARE_EQUAL(object.size(), count); + + count = 0; + for (auto iter = object.rbegin(); iter != object.rend(); ++iter) + { + VERIFY_ARE_EQUAL(object[iter->first], iter->second); + count++; + } + VERIFY_ARE_EQUAL(object.size(), count); + + count = 0; + for (auto iter = object.cbegin(); iter != object.cend(); ++iter) + { + VERIFY_ARE_EQUAL(object[iter->first], iter->second); + count++; + } + VERIFY_ARE_EQUAL(object.size(), count); + + count = 0; + for (auto iter = object.crbegin(); iter != object.crend(); ++iter) + { + VERIFY_ARE_EQUAL(object[iter->first], iter->second); + count++; + } + VERIFY_ARE_EQUAL(object.size(), count); + + // The begin and end iterators on const instances + count = 0; + for (auto iter = cobject.begin(); iter != cobject.end(); ++iter) + { + VERIFY_ARE_EQUAL(cobject.find(iter->first)->second, iter->second); + count++; + } + VERIFY_ARE_EQUAL(cobject.size(), count); + + count = 0; + for (auto iter = cobject.rbegin(); iter != cobject.rend(); ++iter) + { + VERIFY_ARE_EQUAL(cobject.find(iter->first)->second, iter->second); + count++; + } + VERIFY_ARE_EQUAL(cobject.size(), count); } - VERIFY_ARE_EQUAL(cobject.size(), count); - count = 0; - for(auto iter = cobject.rbegin(); iter != cobject.rend(); ++iter) + TEST(github_asan_989) { - VERIFY_ARE_EQUAL(cobject.find(iter->first)->second, iter->second); - count++; + ::web::json::value::parse(_XPLATSTR(R"([ { "k1" : "v" }, { "k2" : "v" }, { "k3" : "v" }, { "k4" : "v" } ])")); } - VERIFY_ARE_EQUAL(cobject.size(), count); -} - -TEST(github_asan_989) -{ - ::web::json::value::parse( _XPLATSTR(R"([ { "k1" : "v" }, { "k2" : "v" }, { "k3" : "v" }, { "k4" : "v" } ])") ); -} } // SUITE(construction_tests) -}}} +} // namespace json_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/json/fuzz_tests.cpp b/Release/tests/functional/json/fuzz_tests.cpp index fefd408a4d..a925bf9dfb 100644 --- a/Release/tests/functional/json/fuzz_tests.cpp +++ b/Release/tests/functional/json/fuzz_tests.cpp @@ -1,77 +1,83 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* fuzz_tests.cpp -* -* Fuzz tests for the JSON library. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * fuzz_tests.cpp + * + * Fuzz tests for the JSON library. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include "cpprest/filestream.h" + #include "cpprest/containerstream.h" +#include "cpprest/filestream.h" using namespace web; -namespace tests { namespace functional { namespace json_tests { - +namespace tests +{ +namespace functional +{ +namespace json_tests +{ #ifdef _WIN32 SUITE(json_fuzz_tests) { -std::string get_fuzzed_file_path() -{ - std::string ipfile; - - if(UnitTest::GlobalSettings::Has("fuzzedinputfile")) + std::string get_fuzzed_file_path() { - ipfile = UnitTest::GlobalSettings::Get("fuzzedinputfile"); - } + std::string ipfile; - return ipfile; -} + if (UnitTest::GlobalSettings::Has("fuzzedinputfile")) + { + ipfile = UnitTest::GlobalSettings::Get("fuzzedinputfile"); + } -TEST(fuzz_json_parser, "Requires", "fuzzedinputfile") -{ - std::wstring ipfile = utility::conversions::to_utf16string(get_fuzzed_file_path()); - if (true == ipfile.empty()) - { - VERIFY_IS_TRUE(false, "Input file is empty"); - return; + return ipfile; } - auto fs = Concurrency::streams::file_stream::open_istream(ipfile).get(); - concurrency::streams::container_buffer cbuf; - fs.read_to_end(cbuf).get(); - fs.close().get(); - auto json_str = cbuf.collection(); - - // Look for UTF-8 BOM - if ((uint8_t)json_str[0] != 0xEF || (uint8_t)json_str[1] != 0xBB || (uint8_t)json_str[2] != 0xBF) + TEST(fuzz_json_parser, "Requires", "fuzzedinputfile") { - VERIFY_IS_TRUE(false, "Input file encoding is not UTF-8. Test will not parse the file."); - return; - } + std::wstring ipfile = utility::conversions::to_utf16string(get_fuzzed_file_path()); + if (true == ipfile.empty()) + { + VERIFY_IS_TRUE(false, "Input file is empty"); + return; + } - auto utf16_json_str = utility::conversions::utf8_to_utf16(json_str); - // UTF8 to UTF16 conversion will retain the BOM, remove it. - if (utf16_json_str.front() == 0xFEFF) - utf16_json_str.erase(0, 1); + auto fs = Concurrency::streams::file_stream::open_istream(ipfile).get(); + concurrency::streams::container_buffer cbuf; + fs.read_to_end(cbuf).get(); + fs.close().get(); + auto json_str = cbuf.collection(); - try - { - json::value::parse(std::move(utf16_json_str)); - std::cout << "Input file parsed successfully."; - } - catch(const json::json_exception& ex) - { - std::cout << "json exception:" << ex.what(); + // Look for UTF-8 BOM + if ((uint8_t)json_str[0] != 0xEF || (uint8_t)json_str[1] != 0xBB || (uint8_t)json_str[2] != 0xBF) + { + VERIFY_IS_TRUE(false, "Input file encoding is not UTF-8. Test will not parse the file."); + return; + } + + auto utf16_json_str = utility::conversions::utf8_to_utf16(json_str); + // UTF8 to UTF16 conversion will retain the BOM, remove it. + if (utf16_json_str.front() == 0xFEFF) utf16_json_str.erase(0, 1); + + try + { + json::value::parse(std::move(utf16_json_str)); + std::cout << "Input file parsed successfully."; + } + catch (const json::json_exception& ex) + { + std::cout << "json exception:" << ex.what(); + } } } -} #endif -}}} \ No newline at end of file +} // namespace json_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/json/iterator_tests.cpp b/Release/tests/functional/json/iterator_tests.cpp index 6efc52c20d..e6c8e60ec3 100644 --- a/Release/tests/functional/json/iterator_tests.cpp +++ b/Release/tests/functional/json/iterator_tests.cpp @@ -1,312 +1,308 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* iterator_tests.cpp -* -* Tests iterating over JSON values -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * iterator_tests.cpp + * + * Tests iterating over JSON values + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include -using namespace web; using namespace utility; +#include -namespace tests { namespace functional { namespace json_tests { +using namespace web; +using namespace utility; -SUITE(iterator_tests) +namespace tests { - -void validate_array_and_object_throw(json::value value) +namespace functional { - VERIFY_THROWS(value.as_array(), web::json::json_exception); - VERIFY_THROWS(value.as_object(), web::json::json_exception); -} - -TEST(non_composites_member_preincrement) +namespace json_tests { - validate_array_and_object_throw(json::value::null()); - validate_array_and_object_throw(json::value::number(17)); - validate_array_and_object_throw(json::value::boolean(true)); - validate_array_and_object_throw(json::value::string(U("Hello!"))); -} - -TEST(objects_constructed) +SUITE(iterator_tests) { - json::value val1; - val1[U("a")] = 44; - val1[U("b")] = json::value(true); - val1[U("c")] = json::value(false); - - VERIFY_ARE_EQUAL(3, val1.size()); + void validate_array_and_object_throw(json::value value) + { + VERIFY_THROWS(value.as_array(), web::json::json_exception); + VERIFY_THROWS(value.as_object(), web::json::json_exception); + } - size_t count = 0; - for (auto iter = std::begin(val1.as_object()); iter != std::end(val1.as_object()); ++iter) + TEST(non_composites_member_preincrement) { - auto key = iter->first; - auto& value = iter->second; - switch(count) - { - case 0: - VERIFY_ARE_EQUAL(U("a"), key); - VERIFY_IS_TRUE(value.is_number()); - break; - case 1: - VERIFY_ARE_EQUAL(U("b"), key); - VERIFY_IS_TRUE(value.is_boolean()); - break; - case 2: - VERIFY_ARE_EQUAL(U("c"), key); - VERIFY_IS_TRUE(value.is_boolean()); - break; - } - count++; + validate_array_and_object_throw(json::value::null()); + validate_array_and_object_throw(json::value::number(17)); + validate_array_and_object_throw(json::value::boolean(true)); + validate_array_and_object_throw(json::value::string(U("Hello!"))); } - VERIFY_ARE_EQUAL(3, count); -} -TEST(objects_parsed) -{ - json::value val1 = json::value::parse(U("{\"a\": 44, \"b\": true, \"c\": false}")); + TEST(objects_constructed) + { + json::value val1; + val1[U("a")] = 44; + val1[U("b")] = json::value(true); + val1[U("c")] = json::value(false); - VERIFY_ARE_EQUAL(3, val1.size()); + VERIFY_ARE_EQUAL(3, val1.size()); - size_t count = 0; - for (auto iter = std::begin(val1.as_object()); iter != std::end(val1.as_object()); ++iter) - { - auto key = iter->first; - auto& value = iter->second; - switch(count) + size_t count = 0; + for (auto iter = std::begin(val1.as_object()); iter != std::end(val1.as_object()); ++iter) { - default: - VERIFY_IS_TRUE(value.is_null()); - break; - case 0: - VERIFY_ARE_EQUAL(U("a"), key); - VERIFY_IS_TRUE(value.is_number()); - VERIFY_ARE_EQUAL(44, value.as_integer()); - break; - case 1: - VERIFY_ARE_EQUAL(U("b"), key); - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_TRUE(value.as_bool()); - break; - case 2: - VERIFY_ARE_EQUAL(U("c"), key); - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_FALSE(value.as_bool()); - break; + auto key = iter->first; + auto& value = iter->second; + switch (count) + { + case 0: + VERIFY_ARE_EQUAL(U("a"), key); + VERIFY_IS_TRUE(value.is_number()); + break; + case 1: + VERIFY_ARE_EQUAL(U("b"), key); + VERIFY_IS_TRUE(value.is_boolean()); + break; + case 2: + VERIFY_ARE_EQUAL(U("c"), key); + VERIFY_IS_TRUE(value.is_boolean()); + break; + } + count++; } - count++; + VERIFY_ARE_EQUAL(3, count); } - VERIFY_ARE_EQUAL(3, count); -} -TEST(objects_reverse) -{ - json::value val1 = json::value::parse(U("{\"a\": 44, \"b\": true, \"c\": false}")); + TEST(objects_parsed) + { + json::value val1 = json::value::parse(U("{\"a\": 44, \"b\": true, \"c\": false}")); - VERIFY_ARE_EQUAL(3, val1.size()); - VERIFY_ARE_EQUAL(3, val1.as_object().size()); + VERIFY_ARE_EQUAL(3, val1.size()); - size_t count = 0; - for (auto iter = val1.as_object().rbegin(); iter != val1.as_object().rend(); ++iter) - { - auto key = iter->first; - auto& value = iter->second; - switch(count) + size_t count = 0; + for (auto iter = std::begin(val1.as_object()); iter != std::end(val1.as_object()); ++iter) { - case 2: - VERIFY_ARE_EQUAL(U("a"), key); - VERIFY_IS_TRUE(value.is_number()); - VERIFY_ARE_EQUAL(44, value.as_integer()); - break; - case 1: - VERIFY_ARE_EQUAL(U("b"), key); - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_TRUE(value.as_bool()); - break; - case 0: - VERIFY_ARE_EQUAL(U("c"), key); - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_FALSE(value.as_bool()); - break; + auto key = iter->first; + auto& value = iter->second; + switch (count) + { + default: VERIFY_IS_TRUE(value.is_null()); break; + case 0: + VERIFY_ARE_EQUAL(U("a"), key); + VERIFY_IS_TRUE(value.is_number()); + VERIFY_ARE_EQUAL(44, value.as_integer()); + break; + case 1: + VERIFY_ARE_EQUAL(U("b"), key); + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_TRUE(value.as_bool()); + break; + case 2: + VERIFY_ARE_EQUAL(U("c"), key); + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_FALSE(value.as_bool()); + break; + } + count++; } - count++; + VERIFY_ARE_EQUAL(3, count); } - VERIFY_ARE_EQUAL(3, count); -} -TEST(arrays_constructed) -{ - json::value val1; - val1[0] = 44; - val1[2] = json::value(true); - val1[5] = json::value(true); + TEST(objects_reverse) + { + json::value val1 = json::value::parse(U("{\"a\": 44, \"b\": true, \"c\": false}")); - VERIFY_ARE_EQUAL(6, val1.size()); + VERIFY_ARE_EQUAL(3, val1.size()); + VERIFY_ARE_EQUAL(3, val1.as_object().size()); - size_t count = 0; - for (auto value : val1.as_array()) - { - switch(count) + size_t count = 0; + for (auto iter = val1.as_object().rbegin(); iter != val1.as_object().rend(); ++iter) { - case 0: - VERIFY_IS_TRUE(value.is_number()); - VERIFY_ARE_EQUAL(44, value.as_integer()); - break; - case 2: - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_TRUE(value.as_bool()); - break; - case 5: - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_TRUE(value.as_bool()); - break; + auto key = iter->first; + auto& value = iter->second; + switch (count) + { + case 2: + VERIFY_ARE_EQUAL(U("a"), key); + VERIFY_IS_TRUE(value.is_number()); + VERIFY_ARE_EQUAL(44, value.as_integer()); + break; + case 1: + VERIFY_ARE_EQUAL(U("b"), key); + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_TRUE(value.as_bool()); + break; + case 0: + VERIFY_ARE_EQUAL(U("c"), key); + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_FALSE(value.as_bool()); + break; + } + count++; } - count++; + VERIFY_ARE_EQUAL(3, count); } - VERIFY_ARE_EQUAL(6, count); -} -TEST(arrays_parsed) -{ - json::value val1 = json::value::parse(U("[44, true, false]")); + TEST(arrays_constructed) + { + json::value val1; + val1[0] = 44; + val1[2] = json::value(true); + val1[5] = json::value(true); - VERIFY_ARE_EQUAL(3, val1.size()); + VERIFY_ARE_EQUAL(6, val1.size()); - size_t count = 0; - for (auto &value : val1.as_array()) - { - switch(count) + size_t count = 0; + for (auto value : val1.as_array()) { - case 0: - VERIFY_IS_TRUE(value.is_number()); - VERIFY_ARE_EQUAL(44, value.as_integer()); - break; - case 1: - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_TRUE(value.as_bool()); - break; - case 2: - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_FALSE(value.as_bool()); - break; + switch (count) + { + case 0: + VERIFY_IS_TRUE(value.is_number()); + VERIFY_ARE_EQUAL(44, value.as_integer()); + break; + case 2: + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_TRUE(value.as_bool()); + break; + case 5: + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_TRUE(value.as_bool()); + break; + } + count++; } - count++; + VERIFY_ARE_EQUAL(6, count); } - VERIFY_ARE_EQUAL(3, count); -} -TEST(arrays_reversed) -{ - json::value val1 = json::value::parse(U("[44, true, false]")); + TEST(arrays_parsed) + { + json::value val1 = json::value::parse(U("[44, true, false]")); - VERIFY_ARE_EQUAL(3, val1.size()); + VERIFY_ARE_EQUAL(3, val1.size()); - size_t count = 0; - for (auto iter = val1.as_array().rbegin(); iter != val1.as_array().rend(); ++iter) - { - auto value = *iter; - switch(count) + size_t count = 0; + for (auto& value : val1.as_array()) { - case 2: - VERIFY_IS_TRUE(value.is_number()); - VERIFY_ARE_EQUAL(44, value.as_integer()); - break; - case 1: - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_TRUE(value.as_bool()); - break; - case 0: - VERIFY_IS_TRUE(value.is_boolean()); - VERIFY_IS_FALSE(value.as_bool()); - break; + switch (count) + { + case 0: + VERIFY_IS_TRUE(value.is_number()); + VERIFY_ARE_EQUAL(44, value.as_integer()); + break; + case 1: + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_TRUE(value.as_bool()); + break; + case 2: + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_FALSE(value.as_bool()); + break; + } + count++; } - count++; + VERIFY_ARE_EQUAL(3, count); } - VERIFY_ARE_EQUAL(3, count); -} -TEST(comparison) -{ - json::value val1; - val1[U("a")] = 44; - val1[U("b")] = json::value(true); - val1[U("c")] = json::value(false); - - auto first = std::begin(val1.as_object()); - auto f = first; - auto f_1 = first++; - auto f_2 = ++first; - - VERIFY_ARE_EQUAL(f, f_1); - VERIFY_ARE_NOT_EQUAL(f_1, f_2); -} - -TEST(std_algorithms) -{ + TEST(arrays_reversed) { - // for_each + json::value val1 = json::value::parse(U("[44, true, false]")); + + VERIFY_ARE_EQUAL(3, val1.size()); + size_t count = 0; - json::value v_array = json::value::parse(U("[44, true, false]")); - std::for_each(std::begin(v_array.as_array()), std::end(v_array.as_array()), - [&](json::array::iterator::value_type) + for (auto iter = val1.as_array().rbegin(); iter != val1.as_array().rend(); ++iter) + { + auto value = *iter; + switch (count) { - count++; - }); + case 2: + VERIFY_IS_TRUE(value.is_number()); + VERIFY_ARE_EQUAL(44, value.as_integer()); + break; + case 1: + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_TRUE(value.as_bool()); + break; + case 0: + VERIFY_IS_TRUE(value.is_boolean()); + VERIFY_IS_FALSE(value.as_bool()); + break; + } + count++; + } VERIFY_ARE_EQUAL(3, count); } - { - // find_if - json::value v_array = json::value::parse(U("[44, true, false]")); - auto _where = - std::find_if(std::begin(v_array.as_array()), std::end(v_array.as_array()), - [&](json::array::iterator::value_type value) - { - return value.is_boolean(); - }); - - VERIFY_ARE_NOT_EQUAL(_where, std::end(v_array.as_array())); - VERIFY_ARE_EQUAL(_where->as_bool(), true); - } + TEST(comparison) { - // copy_if - json::value v_array = json::value::parse(U("[44, true, false]")); - std::vector v_target(v_array.size()); - auto _where = - std::copy_if(std::begin(v_array.as_array()), std::end(v_array.as_array()), std::begin(v_target), - [&](json::array::iterator::value_type value) - { - return value.is_boolean(); - }); - VERIFY_ARE_EQUAL(2, _where-std::begin(v_target)); - VERIFY_IS_FALSE(v_array.as_array().begin()[1].is_number()); + json::value val1; + val1[U("a")] = 44; + val1[U("b")] = json::value(true); + val1[U("c")] = json::value(false); + + auto first = std::begin(val1.as_object()); + auto f = first; + auto f_1 = first++; + auto f_2 = ++first; + + VERIFY_ARE_EQUAL(f, f_1); + VERIFY_ARE_NOT_EQUAL(f_1, f_2); } + + TEST(std_algorithms) { - // transform - json::value v_array = json::value::parse(U("[44, true, false]")); - std::vector v_target(v_array.size()); - std::transform(std::begin(v_array.as_array()), std::end(v_array.as_array()), std::begin(v_target), - [&](json::array::iterator::value_type) -> json::value - { - return json::value::number(17); - }); + { + // for_each + size_t count = 0; + json::value v_array = json::value::parse(U("[44, true, false]")); + std::for_each(std::begin(v_array.as_array()), + std::end(v_array.as_array()), + [&](json::array::iterator::value_type) { count++; }); + VERIFY_ARE_EQUAL(3, count); + } + { + // find_if + json::value v_array = json::value::parse(U("[44, true, false]")); + auto _where = std::find_if(std::begin(v_array.as_array()), + std::end(v_array.as_array()), + [&](json::array::iterator::value_type value) { return value.is_boolean(); }); - VERIFY_ARE_EQUAL(3, v_target.size()); + VERIFY_ARE_NOT_EQUAL(_where, std::end(v_array.as_array())); - for (auto iter = std::begin(v_target); iter != std::end(v_target); ++iter) + VERIFY_ARE_EQUAL(_where->as_bool(), true); + } { - VERIFY_IS_FALSE(iter->is_null()); + // copy_if + json::value v_array = json::value::parse(U("[44, true, false]")); + std::vector v_target(v_array.size()); + auto _where = std::copy_if(std::begin(v_array.as_array()), + std::end(v_array.as_array()), + std::begin(v_target), + [&](json::array::iterator::value_type value) { return value.is_boolean(); }); + VERIFY_ARE_EQUAL(2, _where - std::begin(v_target)); + VERIFY_IS_FALSE(v_array.as_array().begin()[1].is_number()); } - } -} + { + // transform + json::value v_array = json::value::parse(U("[44, true, false]")); + std::vector v_target(v_array.size()); + std::transform(std::begin(v_array.as_array()), + std::end(v_array.as_array()), + std::begin(v_target), + [&](json::array::iterator::value_type) -> json::value { return json::value::number(17); }); + VERIFY_ARE_EQUAL(3, v_target.size()); + + for (auto iter = std::begin(v_target); iter != std::end(v_target); ++iter) + { + VERIFY_IS_FALSE(iter->is_null()); + } + } + } } -}}} \ No newline at end of file +} // namespace json_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/json/json_numbers_tests.cpp b/Release/tests/functional/json/json_numbers_tests.cpp index 8034c551c5..4935a6af27 100644 --- a/Release/tests/functional/json/json_numbers_tests.cpp +++ b/Release/tests/functional/json/json_numbers_tests.cpp @@ -1,308 +1,324 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* json_numbers_tests.cpp -* -* Tests parsing numbers and json::number class -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * json_numbers_tests.cpp + * + * Tests parsing numbers and json::number class + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include -#include -using namespace web; using namespace utility; +#include +#include -namespace tests { namespace functional { namespace json_tests { +using namespace web; +using namespace utility; +namespace tests +{ +namespace functional +{ +namespace json_tests +{ SUITE(json_numbers_tests) { + TEST(numbers) + { + json::value num = json::value::parse(U("-22")); + VERIFY_ARE_EQUAL(-22, num.as_double()); + VERIFY_ARE_EQUAL(-22, num.as_integer()); -TEST(numbers) -{ - json::value num = json::value::parse(U("-22")); - VERIFY_ARE_EQUAL(-22, num.as_double()); - VERIFY_ARE_EQUAL(-22, num.as_integer()); + num = json::value::parse(U("-1.45E2")); + VERIFY_IS_TRUE(num.is_number()); - num = json::value::parse(U("-1.45E2")); - VERIFY_IS_TRUE(num.is_number()); + num = json::value::parse(U("-1.45E+1")); + VERIFY_IS_TRUE(num.is_number()); - num = json::value::parse(U("-1.45E+1")); - VERIFY_IS_TRUE(num.is_number()); + num = json::value::parse(U("-1.45E-10")); + VERIFY_IS_TRUE(num.is_number()); - num = json::value::parse(U("-1.45E-10")); - VERIFY_IS_TRUE(num.is_number()); + num = json::value::parse(U("1e01")); + VERIFY_IS_TRUE(num.is_number()); + } - num = json::value::parse(U("1e01")); - VERIFY_IS_TRUE(num.is_number()); -} + // Test both positive and negative number + void test_int64(int64_t number) + { + stringstream_t ss; + ss << number; + json::value num = json::value::parse(ss); + VERIFY_ARE_EQUAL(number, num.as_number().to_int64()); + VERIFY_IS_TRUE(num.is_integer()); + num = json::value::number(number); + VERIFY_ARE_EQUAL(number, num.as_number().to_int64()); + VERIFY_IS_TRUE(num.is_integer()); + + // Check that the number is convertible to signed int64 + VERIFY_IS_TRUE(num.as_number().is_int64()); + + // Check for other integral conversions + VERIFY_ARE_EQUAL(number >= INT_MIN && number <= INT_MAX, num.as_number().is_int32()); + VERIFY_ARE_EQUAL(number >= 0 && number <= UINT_MAX, num.as_number().is_uint32()); + VERIFY_ARE_EQUAL(number >= 0, num.as_number().is_uint64()); + } -// Test both positive and negative number -void test_int64(int64_t number) -{ - stringstream_t ss; - ss << number; - json::value num = json::value::parse(ss); - VERIFY_ARE_EQUAL(number, num.as_number().to_int64()); - VERIFY_IS_TRUE(num.is_integer()); - num = json::value::number(number); - VERIFY_ARE_EQUAL(number, num.as_number().to_int64()); - VERIFY_IS_TRUE(num.is_integer()); - - // Check that the number is convertible to signed int64 - VERIFY_IS_TRUE(num.as_number().is_int64()); - - // Check for other integral conversions - VERIFY_ARE_EQUAL(number >= INT_MIN && number <= INT_MAX, num.as_number().is_int32()); - VERIFY_ARE_EQUAL(number>=0 && number<=UINT_MAX, num.as_number().is_uint32()); - VERIFY_ARE_EQUAL(number>=0, num.as_number().is_uint64()); -} - -TEST(parse_int64) -{ - // Negative limits - test_int64(int64_t(LLONG_MIN)); - test_int64(int64_t(LLONG_MIN)+1); - test_int64(int64_t(INT_MIN)-1); - test_int64(int64_t(INT_MIN)); - test_int64(int64_t(INT_MIN)+1); - - // Around zero - test_int64(int64_t(-1)); - test_int64(int64_t(0)); - test_int64(int64_t(1)); - - // Positive limits - test_int64(int64_t(INT_MAX)); - test_int64(int64_t(INT_MAX)+1); - test_int64(int64_t(UINT_MAX)); - test_int64(int64_t(UINT_MAX)+1); - - // Outside 32-bits limits - test_int64(int64_t(INT_MAX) * 13 + 5); // a number out of the int32 range - test_int64(uint64_t(LLONG_MAX/2)); -} - -void test_int64(uint64_t number) -{ - stringstream_t ss; - ss << number; - json::value num = json::value::parse(ss); - VERIFY_ARE_EQUAL(number, num.as_number().to_uint64()); - VERIFY_IS_TRUE(num.is_integer()); - num = json::value::number(number); - VERIFY_ARE_EQUAL(number, num.as_number().to_uint64()); - VERIFY_IS_TRUE(num.is_integer()); - - // Check that the number is convertible to unsigned int64 - VERIFY_IS_TRUE(num.as_number().is_uint64()); - - // Check for other integral conversions - VERIFY_ARE_EQUAL(number <= INT_MAX, num.as_number().is_int32()); - VERIFY_ARE_EQUAL(number <= UINT_MAX, num.as_number().is_uint32()); - VERIFY_ARE_EQUAL(number <= LLONG_MAX, num.as_number().is_int64()); -} - -TEST(parse_uint64) -{ - test_int64(int64_t(0)); - test_int64(int64_t(1)); + TEST(parse_int64) + { + // Negative limits + test_int64(int64_t(LLONG_MIN)); + test_int64(int64_t(LLONG_MIN) + 1); + test_int64(int64_t(INT_MIN) - 1); + test_int64(int64_t(INT_MIN)); + test_int64(int64_t(INT_MIN) + 1); + + // Around zero + test_int64(int64_t(-1)); + test_int64(int64_t(0)); + test_int64(int64_t(1)); + + // Positive limits + test_int64(int64_t(INT_MAX)); + test_int64(int64_t(INT_MAX) + 1); + test_int64(int64_t(UINT_MAX)); + test_int64(int64_t(UINT_MAX) + 1); + + // Outside 32-bits limits + test_int64(int64_t(INT_MAX) * 13 + 5); // a number out of the int32 range + test_int64(uint64_t(LLONG_MAX / 2)); + } - test_int64(uint64_t(LLONG_MAX)-1); - test_int64(uint64_t(LLONG_MAX)); - test_int64(uint64_t(LLONG_MAX)+1); - test_int64(uint64_t(ULLONG_MAX)); - test_int64(uint64_t(ULLONG_MAX)-1); -} + void test_int64(uint64_t number) + { + stringstream_t ss; + ss << number; + json::value num = json::value::parse(ss); + VERIFY_ARE_EQUAL(number, num.as_number().to_uint64()); + VERIFY_IS_TRUE(num.is_integer()); + num = json::value::number(number); + VERIFY_ARE_EQUAL(number, num.as_number().to_uint64()); + VERIFY_IS_TRUE(num.is_integer()); + + // Check that the number is convertible to unsigned int64 + VERIFY_IS_TRUE(num.as_number().is_uint64()); + + // Check for other integral conversions + VERIFY_ARE_EQUAL(number <= INT_MAX, num.as_number().is_int32()); + VERIFY_ARE_EQUAL(number <= UINT_MAX, num.as_number().is_uint32()); + VERIFY_ARE_EQUAL(number <= LLONG_MAX, num.as_number().is_int64()); + } -const int DOUBLE_DIGITS = std::numeric_limits::digits10 + 7; //7 = length of "1." and "e+123" which is the begining and the end of the double representation + TEST(parse_uint64) + { + test_int64(int64_t(0)); + test_int64(int64_t(1)); + + test_int64(uint64_t(LLONG_MAX) - 1); + test_int64(uint64_t(LLONG_MAX)); + test_int64(uint64_t(LLONG_MAX) + 1); + test_int64(uint64_t(ULLONG_MAX)); + test_int64(uint64_t(ULLONG_MAX) - 1); + } -void test_double(double number, string_t str_rep) -{ - stringstream_t ss; - ss << str_rep; - - json::value num = json::value::parse(ss); - VERIFY_ARE_EQUAL(number, num.as_double()); - VERIFY_ARE_EQUAL(number, num.as_number().to_double()); - - // If the number is within integral types limit and not decimal, it should be stored as one of the integral types - VERIFY_ARE_EQUAL(number > LLONG_MIN && number < ULLONG_MAX && number==floor(number), num.is_integer()); - - // If it is outside the range, these methods should return false. - // Note that at this point there is no guarantee that the number was stored as double. - - if (number < INT_MIN || number > INT_MAX || number!=floor(number)) - VERIFY_IS_FALSE(num.as_number().is_int32()); - - if (number < 0 || number > UINT_MAX || number!=floor(number)) - VERIFY_IS_FALSE(num.as_number().is_uint32()); - - if (number < LLONG_MIN || number > LLONG_MAX || number!=floor(number)) - VERIFY_IS_FALSE(num.as_number().is_int64()); - - if (number < 0 || number > ULLONG_MAX || number!=floor(number)) - VERIFY_IS_FALSE(num.as_number().is_uint64()); -} - -void test_double(double d) -{ - ::std::basic_stringstream ss; - ss << ::std::setprecision(DOUBLE_DIGITS); - ss << d; - test_double(d, ss.str()); -} + const int DOUBLE_DIGITS = + std::numeric_limits::digits10 + + 7; // 7 = length of "1." and "e+123" which is the begining and the end of the double representation -TEST(parsing_doubles_into_longs) -{ - test_double(2.0); - test_double(pow(2.0, 10.0)); - test_double(pow(2.0, 20.0)); - test_double(pow(2.0, 60.0)); - test_double(pow(2.0, 63.0)); -} - -TEST(parsing_doubles) -{ - test_double(3.14); - test_double(-9.81); + void test_double(double number, string_t str_rep) + { + stringstream_t ss; + ss << str_rep; - // Note: this should not parse to a ullong because of rounding - test_double(static_cast(ULLONG_MAX)); + json::value num = json::value::parse(ss); + VERIFY_ARE_EQUAL(number, num.as_double()); + VERIFY_ARE_EQUAL(number, num.as_number().to_double()); - test_double(0 - static_cast(ULLONG_MAX)); - test_double(static_cast(ULLONG_MAX)+(2<<(64-52))); // the lowest number that will be represented as double due to overflowing unsigned int64 (52bits fraction in double-precision) - test_double(0 - pow(2.0, 63.0) * 1.5); // between 0-ULLONG_MAX and LLONGMIN -} + // If the number is within integral types limit and not decimal, it should be stored as one of the integral + // types + VERIFY_ARE_EQUAL(number > LLONG_MIN && number < ULLONG_MAX && number == floor(number), num.is_integer()); -TEST(parsing_doubles_setlocale, "Ignore:Android", "Locale not supported on Android", - "Ignore:Linux", "Fails due to double conversion issues", - "Ignore:Apple", "Fails due to double conversion issues") -{ - // JSON uses the C locale always and should therefore not be impacted by the process locale + // If it is outside the range, these methods should return false. + // Note that at this point there is no guarantee that the number was stored as double. + + if (number < INT_MIN || number > INT_MAX || number != floor(number)) + VERIFY_IS_FALSE(num.as_number().is_int32()); + + if (number < 0 || number > UINT_MAX || number != floor(number)) VERIFY_IS_FALSE(num.as_number().is_uint32()); + + if (number < LLONG_MIN || number > LLONG_MAX || number != floor(number)) + VERIFY_IS_FALSE(num.as_number().is_int64()); + + if (number < 0 || number > ULLONG_MAX || number != floor(number)) VERIFY_IS_FALSE(num.as_number().is_uint64()); + } + + void test_double(double d) + { + ::std::basic_stringstream ss; + ss << ::std::setprecision(DOUBLE_DIGITS); + ss << d; + test_double(d, ss.str()); + } + + TEST(parsing_doubles_into_longs) + { + test_double(2.0); + test_double(pow(2.0, 10.0)); + test_double(pow(2.0, 20.0)); + test_double(pow(2.0, 60.0)); + test_double(pow(2.0, 63.0)); + } + + TEST(parsing_doubles) + { + test_double(3.14); + test_double(-9.81); + + // Note: this should not parse to a ullong because of rounding + test_double(static_cast(ULLONG_MAX)); + + test_double(0 - static_cast(ULLONG_MAX)); + test_double(static_cast(ULLONG_MAX) + + (2 << (64 - 52))); // the lowest number that will be represented as double due to overflowing + // unsigned int64 (52bits fraction in double-precision) + test_double(0 - pow(2.0, 63.0) * 1.5); // between 0-ULLONG_MAX and LLONGMIN + } + + TEST(parsing_doubles_setlocale, + "Ignore:Android", + "Locale not supported on Android", + "Ignore:Linux", + "Fails due to double conversion issues", + "Ignore:Apple", + "Fails due to double conversion issues") + { + // JSON uses the C locale always and should therefore not be impacted by the process locale #ifdef _WIN32 - std::string changedLocale("fr-FR"); + std::string changedLocale("fr-FR"); #else - std::string changedLocale("fr_FR.UTF-8"); + std::string changedLocale("fr_FR.UTF-8"); #endif - // If locale isn't installed on system just silently pass. - if (setlocale(LC_ALL, changedLocale.c_str()) != nullptr) - { - test_double(1.91563); - test_double(2.0e93); - setlocale(LC_ALL, "C"); + // If locale isn't installed on system just silently pass. + if (setlocale(LC_ALL, changedLocale.c_str()) != nullptr) + { + test_double(1.91563); + test_double(2.0e93); + setlocale(LC_ALL, "C"); + } } -} -TEST(parsing_very_large_doubles) -{ - test_double(pow(2.0, 64.0)); - test_double(pow(2.0, 70.0)); - test_double(pow(2.0, 80.0)); - test_double(pow(2.0, 120.0)); - test_double(pow(2.0, 240.0)); - test_double(pow(2.0, 300.0)); -} - -TEST(parsing_very_small_doubles) -{ - test_double(2.34e-308); - test_double(1e-308); -} + TEST(parsing_very_large_doubles) + { + test_double(pow(2.0, 64.0)); + test_double(pow(2.0, 70.0)); + test_double(pow(2.0, 80.0)); + test_double(pow(2.0, 120.0)); + test_double(pow(2.0, 240.0)); + test_double(pow(2.0, 300.0)); + } -void test_integral(int number) -{ - stringstream_t ss; - ss << number; - json::value num = json::value::parse(ss); - VERIFY_IS_TRUE(num.as_number().is_int32()); - VERIFY_IS_TRUE(num.as_number().is_uint32()); - VERIFY_IS_TRUE(num.as_number().is_int64()); - VERIFY_IS_TRUE(num.as_number().is_uint64()); - - VERIFY_ARE_EQUAL(number, num.as_number().to_int32()); - VERIFY_ARE_EQUAL(number, num.as_number().to_uint32()); - VERIFY_ARE_EQUAL(number, num.as_number().to_int64()); - VERIFY_ARE_EQUAL(number, num.as_number().to_uint64()); -} - -TEST(parsing_integral_types) -{ - test_integral(0); - test_integral(1); - test_integral(INT_MAX/2); - test_integral(INT_MAX); -} + TEST(parsing_very_small_doubles) + { + test_double(2.34e-308); + test_double(1e-308); + } -TEST(int_double_limits) -{ - utility::stringstream_t stream(utility::stringstream_t::in | utility::stringstream_t::out); - utility::stringstream_t oracleStream(utility::stringstream_t::in | utility::stringstream_t::out); - - // unsigned int64 max - oracleStream.precision(std::numeric_limits::digits10 + 2); - oracleStream << std::numeric_limits::max(); - json::value iMax(std::numeric_limits::max()); - VERIFY_ARE_EQUAL(oracleStream.str(), iMax.serialize()); - iMax.serialize(stream); - VERIFY_ARE_EQUAL(oracleStream.str(), stream.str()); - - // signed int64 min - stream.str(U("")); - oracleStream.str(U("")); - oracleStream.clear(); - oracleStream << std::numeric_limits::min(); - json::value iMin(std::numeric_limits::min()); - VERIFY_ARE_EQUAL(oracleStream.str(), iMin.serialize()); - iMin.serialize(stream); - VERIFY_ARE_EQUAL(oracleStream.str(), stream.str()); - - // double max - stream.str(U("")); - oracleStream.str(U("")); - oracleStream.precision(std::numeric_limits::digits10 + 2); - oracleStream << std::numeric_limits::max(); - json::value dMax(std::numeric_limits::max()); - VERIFY_ARE_EQUAL(oracleStream.str(), dMax.serialize()); - dMax.serialize(stream); - VERIFY_ARE_EQUAL(oracleStream.str(), stream.str()); - - // double min - stream.str(U("")); - oracleStream.str(U("")); - oracleStream << std::numeric_limits::min(); - json::value dMin(std::numeric_limits::min()); - VERIFY_ARE_EQUAL(oracleStream.str(), dMin.serialize()); - dMin.serialize(stream); - VERIFY_ARE_EQUAL(oracleStream.str(), stream.str()); -} - -TEST(compare_numbers) -{ - // Make sure these are equal - VERIFY_ARE_EQUAL(json::value(3.14), json::value::parse(U("3.14"))); - VERIFY_ARE_EQUAL(json::value(uint64_t(1234)), json::value::parse(U("1234"))); - VERIFY_ARE_EQUAL(json::value(uint32_t(10)), json::value::parse(U("10"))); + void test_integral(int number) + { + stringstream_t ss; + ss << number; + json::value num = json::value::parse(ss); + VERIFY_IS_TRUE(num.as_number().is_int32()); + VERIFY_IS_TRUE(num.as_number().is_uint32()); + VERIFY_IS_TRUE(num.as_number().is_int64()); + VERIFY_IS_TRUE(num.as_number().is_uint64()); + + VERIFY_ARE_EQUAL(number, num.as_number().to_int32()); + VERIFY_ARE_EQUAL(number, num.as_number().to_uint32()); + VERIFY_ARE_EQUAL(number, num.as_number().to_int64()); + VERIFY_ARE_EQUAL(number, num.as_number().to_uint64()); + } - // These two are to verify that explicitly stated signed int was stored as unsigned int as we store all non-negative numbers as unsigned int - VERIFY_ARE_EQUAL(json::value(int32_t(10)), json::value::parse(U("10"))); - VERIFY_ARE_EQUAL(json::value(int64_t(1234)), json::value::parse(U("1234"))); + TEST(parsing_integral_types) + { + test_integral(0); + test_integral(1); + test_integral(INT_MAX / 2); + test_integral(INT_MAX); + } - // These numbers would be equal if converted to double first. That is how we compared them before we had int64 support. - VERIFY_ARE_NOT_EQUAL(json::value(int64_t(LLONG_MIN)), json::value(int64_t(LLONG_MIN+1))); - VERIFY_ARE_NOT_EQUAL(json::value(uint64_t(ULLONG_MAX)), json::value(uint64_t(ULLONG_MAX-1))); + TEST(int_double_limits) + { + utility::stringstream_t stream(utility::stringstream_t::in | utility::stringstream_t::out); + utility::stringstream_t oracleStream(utility::stringstream_t::in | utility::stringstream_t::out); + + // unsigned int64 max + oracleStream.precision(std::numeric_limits::digits10 + 2); + oracleStream << std::numeric_limits::max(); + json::value iMax(std::numeric_limits::max()); + VERIFY_ARE_EQUAL(oracleStream.str(), iMax.serialize()); + iMax.serialize(stream); + VERIFY_ARE_EQUAL(oracleStream.str(), stream.str()); + + // signed int64 min + stream.str(U("")); + oracleStream.str(U("")); + oracleStream.clear(); + oracleStream << std::numeric_limits::min(); + json::value iMin(std::numeric_limits::min()); + VERIFY_ARE_EQUAL(oracleStream.str(), iMin.serialize()); + iMin.serialize(stream); + VERIFY_ARE_EQUAL(oracleStream.str(), stream.str()); + + // double max + stream.str(U("")); + oracleStream.str(U("")); + oracleStream.precision(std::numeric_limits::digits10 + 2); + oracleStream << std::numeric_limits::max(); + json::value dMax(std::numeric_limits::max()); + VERIFY_ARE_EQUAL(oracleStream.str(), dMax.serialize()); + dMax.serialize(stream); + VERIFY_ARE_EQUAL(oracleStream.str(), stream.str()); + + // double min + stream.str(U("")); + oracleStream.str(U("")); + oracleStream << std::numeric_limits::min(); + json::value dMin(std::numeric_limits::min()); + VERIFY_ARE_EQUAL(oracleStream.str(), dMin.serialize()); + dMin.serialize(stream); + VERIFY_ARE_EQUAL(oracleStream.str(), stream.str()); + } - // Checking boundary condition - zero - VERIFY_ARE_EQUAL(json::value(int32_t(0)), json::value::parse(U("-0"))); - VERIFY_ARE_EQUAL(json::value(int64_t(0)), json::value::parse(U("-0"))); - VERIFY_ARE_EQUAL(json::value::parse(U("0")), json::value::parse(U("-0"))); -} + TEST(compare_numbers) + { + // Make sure these are equal + VERIFY_ARE_EQUAL(json::value(3.14), json::value::parse(U("3.14"))); + VERIFY_ARE_EQUAL(json::value(uint64_t(1234)), json::value::parse(U("1234"))); + VERIFY_ARE_EQUAL(json::value(uint32_t(10)), json::value::parse(U("10"))); + + // These two are to verify that explicitly stated signed int was stored as unsigned int as we store all + // non-negative numbers as unsigned int + VERIFY_ARE_EQUAL(json::value(int32_t(10)), json::value::parse(U("10"))); + VERIFY_ARE_EQUAL(json::value(int64_t(1234)), json::value::parse(U("1234"))); + + // These numbers would be equal if converted to double first. That is how we compared them before we had int64 + // support. + VERIFY_ARE_NOT_EQUAL(json::value(int64_t(LLONG_MIN)), json::value(int64_t(LLONG_MIN + 1))); + VERIFY_ARE_NOT_EQUAL(json::value(uint64_t(ULLONG_MAX)), json::value(uint64_t(ULLONG_MAX - 1))); + + // Checking boundary condition - zero + VERIFY_ARE_EQUAL(json::value(int32_t(0)), json::value::parse(U("-0"))); + VERIFY_ARE_EQUAL(json::value(int64_t(0)), json::value::parse(U("-0"))); + VERIFY_ARE_EQUAL(json::value::parse(U("0")), json::value::parse(U("-0"))); + } } // SUITE(json_numbers_tests) -}}} \ No newline at end of file +} // namespace json_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/json/json_tests.h b/Release/tests/functional/json/json_tests.h index f711587ba7..2d0bac62d1 100644 --- a/Release/tests/functional/json/json_tests.h +++ b/Release/tests/functional/json/json_tests.h @@ -1,20 +1,25 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* json_tests.h -* -* Common utilities and helper functions for JSON tests. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * json_tests.h + * + * Common utilities and helper functions for JSON tests. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "cpprest/json.h" - #include "unittestpp.h" -namespace tests { namespace functional { namespace json_tests { - -}}} \ No newline at end of file +namespace tests +{ +namespace functional +{ +namespace json_tests +{ +} +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/json/negative_parsing_tests.cpp b/Release/tests/functional/json/negative_parsing_tests.cpp index 8ebf71da7f..33a678ab16 100644 --- a/Release/tests/functional/json/negative_parsing_tests.cpp +++ b/Release/tests/functional/json/negative_parsing_tests.cpp @@ -1,24 +1,28 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* negative_parsing_tests.cpp -* -* Negative tests for JSON parsing. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * negative_parsing_tests.cpp + * + * Negative tests for JSON parsing. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; using namespace utility; -namespace tests { namespace functional { namespace json_tests { - -template -void verify_json_throws(T &parseString) +namespace tests +{ +namespace functional +{ +namespace json_tests +{ +template +void verify_json_throws(T& parseString) { std::error_code ec; VERIFY_THROWS(json::value::parse(parseString), json::json_exception); @@ -29,161 +33,152 @@ void verify_json_throws(T &parseString) SUITE(negative_parsing_tests) { - -TEST(string_t) -{ - verify_json_throws(U("\"\\k\"")); - verify_json_throws(U("\" \" \"")); - verify_json_throws(U("\"\\u23A\"")); - verify_json_throws(U("\"\\uXY1A\"")); - verify_json_throws(U("\"asdf")); - verify_json_throws(U("\\asdf")); - verify_json_throws(U("\"\"\"\"")); - - // '\', '"', and control characters must be escaped (0x1F and below). - verify_json_throws(U("\"\\\"")); - verify_json_throws(U("\"")); - utility::string_t str(U("\"")); - str.append(1, 0x1F); - str.append(U("\"")); - verify_json_throws(str); -} - -TEST(numbers) -{ - verify_json_throws(U("-")); - verify_json_throws(U("-.")); - verify_json_throws(U("-e1")); - verify_json_throws(U("-1e")); - verify_json_throws(U("+1.1")); - verify_json_throws(U("1.1 E")); - verify_json_throws(U("1.1E-")); - verify_json_throws(U("1.1E.1")); - verify_json_throws(U("1.1E1.1")); - verify_json_throws(U("001.1")); - verify_json_throws(U("-.100")); - verify_json_throws(U("-.001")); - verify_json_throws(U(".1")); - verify_json_throws(U("0.1.1")); -} - -// TFS 535589 -void parse_help(utility::string_t str) -{ - utility::stringstream_t ss1; - ss1 << str; - verify_json_throws(ss1); -} - -TEST(objects) -{ - verify_json_throws(U("}")); - parse_help(U("{")); - parse_help(U("{ 1, 10 }")); - parse_help(U("{ : }")); - parse_help(U("{ \"}")); - verify_json_throws(U("{")); - verify_json_throws(U("{ 1")); - verify_json_throws(U("{ \"}")); - verify_json_throws(U("{\"2\":")); - verify_json_throws(U("{\"2\":}")); - verify_json_throws(U("{\"2\": true")); - verify_json_throws(U("{\"2\": true false")); - verify_json_throws(U("{\"2\": true :false")); - verify_json_throws(U("{\"2\": false,}")); -} - -TEST(arrays) -{ - verify_json_throws(U("]")); - verify_json_throws(U("[")); - verify_json_throws(U("[ 1")); - verify_json_throws(U("[ 1,")); - verify_json_throws(U("[ 1,]")); - verify_json_throws(U("[ 1 2]")); - verify_json_throws(U("[ \"1\" : 2]")); - parse_help(U("[,]")); - parse_help(U("[ \"]")); - parse_help(U("[\"2\", false,]")); -} - -TEST(literals_not_lower_case) -{ - verify_json_throws(U("NULL")); - verify_json_throws(U("FAlse")); - verify_json_throws(U("TRue")); -} - -TEST(incomplete_literals) -{ - verify_json_throws(U("nul")); - verify_json_throws(U("fal")); - verify_json_throws(U("tru")); -} - -// TFS#501321 -TEST(exception_string) -{ - utility::string_t json_ip_str=U(""); - verify_json_throws(json_ip_str); -} - -TEST(boundary_chars) -{ - utility::string_t str(U("\"")); - str.append(1, 0x1F); - str.append(U("\"")); - parse_help(str); -} - -TEST(stream_left_over_chars) -{ - std::stringbuf buf; - buf.sputn("[false]false", 12); - std::istream stream(&buf); - verify_json_throws(stream); -} + TEST(string_t) + { + verify_json_throws(U("\"\\k\"")); + verify_json_throws(U("\" \" \"")); + verify_json_throws(U("\"\\u23A\"")); + verify_json_throws(U("\"\\uXY1A\"")); + verify_json_throws(U("\"asdf")); + verify_json_throws(U("\\asdf")); + verify_json_throws(U("\"\"\"\"")); + + // '\', '"', and control characters must be escaped (0x1F and below). + verify_json_throws(U("\"\\\"")); + verify_json_throws(U("\"")); + utility::string_t str(U("\"")); + str.append(1, 0x1F); + str.append(U("\"")); + verify_json_throws(str); + } + + TEST(numbers) + { + verify_json_throws(U("-")); + verify_json_throws(U("-.")); + verify_json_throws(U("-e1")); + verify_json_throws(U("-1e")); + verify_json_throws(U("+1.1")); + verify_json_throws(U("1.1 E")); + verify_json_throws(U("1.1E-")); + verify_json_throws(U("1.1E.1")); + verify_json_throws(U("1.1E1.1")); + verify_json_throws(U("001.1")); + verify_json_throws(U("-.100")); + verify_json_throws(U("-.001")); + verify_json_throws(U(".1")); + verify_json_throws(U("0.1.1")); + } + + // TFS 535589 + void parse_help(utility::string_t str) + { + utility::stringstream_t ss1; + ss1 << str; + verify_json_throws(ss1); + } + + TEST(objects) + { + verify_json_throws(U("}")); + parse_help(U("{")); + parse_help(U("{ 1, 10 }")); + parse_help(U("{ : }")); + parse_help(U("{ \"}")); + verify_json_throws(U("{")); + verify_json_throws(U("{ 1")); + verify_json_throws(U("{ \"}")); + verify_json_throws(U("{\"2\":")); + verify_json_throws(U("{\"2\":}")); + verify_json_throws(U("{\"2\": true")); + verify_json_throws(U("{\"2\": true false")); + verify_json_throws(U("{\"2\": true :false")); + verify_json_throws(U("{\"2\": false,}")); + } + + TEST(arrays) + { + verify_json_throws(U("]")); + verify_json_throws(U("[")); + verify_json_throws(U("[ 1")); + verify_json_throws(U("[ 1,")); + verify_json_throws(U("[ 1,]")); + verify_json_throws(U("[ 1 2]")); + verify_json_throws(U("[ \"1\" : 2]")); + parse_help(U("[,]")); + parse_help(U("[ \"]")); + parse_help(U("[\"2\", false,]")); + } + + TEST(literals_not_lower_case) + { + verify_json_throws(U("NULL")); + verify_json_throws(U("FAlse")); + verify_json_throws(U("TRue")); + } + + TEST(incomplete_literals) + { + verify_json_throws(U("nul")); + verify_json_throws(U("fal")); + verify_json_throws(U("tru")); + } + + // TFS#501321 + TEST(exception_string) + { + utility::string_t json_ip_str = U(""); + verify_json_throws(json_ip_str); + } + + TEST(boundary_chars) + { + utility::string_t str(U("\"")); + str.append(1, 0x1F); + str.append(U("\"")); + parse_help(str); + } + + TEST(stream_left_over_chars) + { + std::stringbuf buf; + buf.sputn("[false]false", 12); + std::istream stream(&buf); + verify_json_throws(stream); + } // Test using Windows only API. #ifdef _WIN32 -TEST(wstream_left_over_chars) -{ - std::wstringbuf buf; - buf.sputn(L"[false]false", 12); - std::wistream stream(&buf); - verify_json_throws(stream); -} + TEST(wstream_left_over_chars) + { + std::wstringbuf buf; + buf.sputn(L"[false]false", 12); + std::wistream stream(&buf); + verify_json_throws(stream); + } #endif -void garbage_impl(wchar_t ch) -{ - utility::string_t ss(U("{\"a\" : 10, \"b\":")); + void garbage_impl(wchar_t ch) + { + utility::string_t ss(U("{\"a\" : 10, \"b\":")); - std::random_device rd; - std::mt19937 eng(rd()); - std::uniform_int_distribution dist(0, ch); + std::random_device rd; + std::mt19937 eng(rd()); + std::uniform_int_distribution dist(0, ch); - for (int i = 0; i < 2500; i++) - ss.push_back(static_cast(dist(eng))); + for (int i = 0; i < 2500; i++) + ss.push_back(static_cast(dist(eng))); - verify_json_throws(ss); -} + verify_json_throws(ss); + } -TEST(garbage_1) -{ - garbage_impl(0x7F); -} + TEST(garbage_1) { garbage_impl(0x7F); } -TEST(garbage_2) -{ - garbage_impl(0xFF); -} - -TEST(garbage_3) -{ - garbage_impl(0xFFFF); -} + TEST(garbage_2) { garbage_impl(0xFF); } + TEST(garbage_3) { garbage_impl(0xFFFF); } } -}}} \ No newline at end of file +} // namespace json_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/json/parsing_tests.cpp b/Release/tests/functional/json/parsing_tests.cpp index c1cc7a8305..f235893af2 100644 --- a/Release/tests/functional/json/parsing_tests.cpp +++ b/Release/tests/functional/json/parsing_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests for JSON parsing. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests for JSON parsing. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -22,730 +22,736 @@ #include #endif -using namespace web; using namespace utility; +using namespace web; +using namespace utility; using namespace utility::conversions; -namespace tests { namespace functional { namespace json_tests { - - inline bool verify_parsing_error_msg(const std::string &str) - { +namespace tests +{ +namespace functional +{ +namespace json_tests +{ +inline bool verify_parsing_error_msg(const std::string& str) +{ #if defined(_WIN32) || defined(__APPLE__) - auto spattern = "^\\* Line \\d+, Column \\d+ Syntax error: .+"; - static std::regex pattern(spattern); - return std::regex_match(str, pattern, std::regex_constants::match_flag_type::match_not_null); + auto spattern = "^\\* Line \\d+, Column \\d+ Syntax error: .+"; + static std::regex pattern(spattern); + return std::regex_match(str, pattern, std::regex_constants::match_flag_type::match_not_null); #elif (defined(ANDROID) || defined(__ANDROID__)) - return str.find("Syntax error: ") != std::string::npos; + return str.find("Syntax error: ") != std::string::npos; #else - auto spattern = "^\\* Line \\d+, Column \\d+ Syntax error: .+"; - static boost::regex pattern(spattern); - return boost::regex_match(str, pattern, boost::regex_constants::match_flag_type::match_not_null); + auto spattern = "^\\* Line \\d+, Column \\d+ Syntax error: .+"; + static boost::regex pattern(spattern); + return boost::regex_match(str, pattern, boost::regex_constants::match_flag_type::match_not_null); #endif - } +} #if defined(_MSC_VER) -#pragma warning (disable: 4127) // const expression +#pragma warning(disable : 4127) // const expression #endif -#define VERIFY_PARSING_THROW(target) \ -do { \ - try { \ - target; \ - VERIFY_IS_TRUE(false); \ - } \ - catch (const json::json_exception &e) { \ - VERIFY_IS_TRUE(verify_parsing_error_msg(e.what())); \ - } \ - catch (...) { \ - VERIFY_IS_TRUE(false); \ - } \ -} while (false) +#define VERIFY_PARSING_THROW(target) \ + do \ + { \ + try \ + { \ + target; \ + VERIFY_IS_TRUE(false); \ + } \ + catch (const json::json_exception& e) \ + { \ + VERIFY_IS_TRUE(verify_parsing_error_msg(e.what())); \ + } \ + catch (...) \ + { \ + VERIFY_IS_TRUE(false); \ + } \ + } while (false) SUITE(parsing_tests) { + TEST(stringstream_t) + { + utility::stringstream_t ss0; + ss0 << U("null"); + json::value v0 = json::value::parse(ss0); + + utility::stringstream_t ss1; + ss1 << U("17"); + json::value v1 = json::value::parse(ss1); + + utility::stringstream_t ss2; + ss2 << U("3.1415"); + json::value v2 = json::value::parse(ss2); + + utility::stringstream_t ss3; + ss3 << U("true"); + json::value v3 = json::value::parse(ss3); + + utility::stringstream_t ss4; + ss4 << U("\"Hello!\""); + json::value v4 = json::value::parse(ss4); + + utility::stringstream_t ss8; + ss8 << U("{ \"a\" : 10 }"); + json::value v8 = json::value::parse(ss8); + + utility::stringstream_t ss9; + ss9 << U("[1,2,3,true]"); + json::value v9 = json::value::parse(ss9); + + VERIFY_ARE_EQUAL(v1.type(), json::value::Number); + VERIFY_ARE_EQUAL(v2.type(), json::value::Number); + VERIFY_ARE_EQUAL(v3.type(), json::value::Boolean); + VERIFY_ARE_EQUAL(v4.type(), json::value::String); + VERIFY_ARE_EQUAL(v8.type(), json::value::Object); + VERIFY_ARE_EQUAL(v9.type(), json::value::Array); + } -TEST(stringstream_t) -{ - utility::stringstream_t ss0; - ss0 << U("null"); - json::value v0 = json::value::parse(ss0); - - utility::stringstream_t ss1; - ss1 << U("17"); - json::value v1 = json::value::parse(ss1); - - utility::stringstream_t ss2; - ss2 << U("3.1415"); - json::value v2 = json::value::parse(ss2); - - utility::stringstream_t ss3; - ss3 << U("true"); - json::value v3 = json::value::parse(ss3); - - utility::stringstream_t ss4; - ss4 << U("\"Hello!\""); - json::value v4 = json::value::parse(ss4); - - utility::stringstream_t ss8; - ss8 << U("{ \"a\" : 10 }"); - json::value v8 = json::value::parse(ss8); - - utility::stringstream_t ss9; - ss9 << U("[1,2,3,true]"); - json::value v9 = json::value::parse(ss9); - - VERIFY_ARE_EQUAL(v1.type(), json::value::Number); - VERIFY_ARE_EQUAL(v2.type(), json::value::Number); - VERIFY_ARE_EQUAL(v3.type(), json::value::Boolean); - VERIFY_ARE_EQUAL(v4.type(), json::value::String); - VERIFY_ARE_EQUAL(v8.type(), json::value::Object); - VERIFY_ARE_EQUAL(v9.type(), json::value::Array); -} - -TEST(whitespace_failure) -{ - VERIFY_PARSING_THROW(json::value::parse(U(" "))); -} - -static const std::array whitespace_chars = { { 0x20, 0x09, 0x0A, 0x0D } }; + TEST(whitespace_failure) { VERIFY_PARSING_THROW(json::value::parse(U(" "))); } -TEST(whitespace_array) -{ - // Try all the whitespace characters before/after all the structural characters - // whitespace characters according to RFC4627: space, horizontal tab, line feed or new line, carriage return - // structural characters: [{]}:, + static const std::array whitespace_chars = {{0x20, 0x09, 0x0A, 0x0D}}; - // [,] - for(auto ch : whitespace_chars) + TEST(whitespace_array) { - utility::string_t input; - input.append(2, ch); - input.append(U("[")); - input.append(2, ch); - input.append(U("1")); - input.append(1, ch); - input.append(U(",")); - input.append(4, ch); - input.append(U("2")); - input.append(1, ch); - input.append(U("]")); - input.append(2, ch); - json::value val = json::value::parse(input); - VERIFY_IS_TRUE(val.is_array()); - VERIFY_ARE_EQUAL(U("1"), val[0].serialize()); - VERIFY_ARE_EQUAL(U("2"), val[1].serialize()); + // Try all the whitespace characters before/after all the structural characters + // whitespace characters according to RFC4627: space, horizontal tab, line feed or new line, carriage return + // structural characters: [{]}:, + + // [,] + for (auto ch : whitespace_chars) + { + utility::string_t input; + input.append(2, ch); + input.append(U("[")); + input.append(2, ch); + input.append(U("1")); + input.append(1, ch); + input.append(U(",")); + input.append(4, ch); + input.append(U("2")); + input.append(1, ch); + input.append(U("]")); + input.append(2, ch); + json::value val = json::value::parse(input); + VERIFY_IS_TRUE(val.is_array()); + VERIFY_ARE_EQUAL(U("1"), val[0].serialize()); + VERIFY_ARE_EQUAL(U("2"), val[1].serialize()); + } } -} -TEST(whitespace_object) -{ - // {:} - for(auto ch : whitespace_chars) + TEST(whitespace_object) { - utility::string_t input; - input.append(2, ch); - input.append(U("{")); - input.append(2, ch); - input.append(U("\"1\"")); - input.append(1, ch); - input.append(U(":")); - input.append(4, ch); - input.append(U("2")); - input.append(1, ch); - input.append(U("}")); - input.append(2, ch); - json::value val = json::value::parse(input); - VERIFY_IS_TRUE(val.is_object()); + // {:} + for (auto ch : whitespace_chars) + { + utility::string_t input; + input.append(2, ch); + input.append(U("{")); + input.append(2, ch); + input.append(U("\"1\"")); + input.append(1, ch); + input.append(U(":")); + input.append(4, ch); + input.append(U("2")); + input.append(1, ch); + input.append(U("}")); + input.append(2, ch); + json::value val = json::value::parse(input); + VERIFY_IS_TRUE(val.is_object()); VERIFY_ARE_EQUAL(U("2"), val[U("1"]).serialize()); + } } -} -TEST(string_t) -{ - json::value str = json::value::parse(U("\"\\\"\"")); - VERIFY_ARE_EQUAL(U("\""), str.as_string()); + TEST(string_t) + { + json::value str = json::value::parse(U("\"\\\"\"")); + VERIFY_ARE_EQUAL(U("\""), str.as_string()); - str = json::value::parse(U("\"\"")); - VERIFY_ARE_EQUAL(U(""), str.as_string()); + str = json::value::parse(U("\"\"")); + VERIFY_ARE_EQUAL(U(""), str.as_string()); - str = json::value::parse(U("\"\\\"ds\"")); - VERIFY_ARE_EQUAL(U("\"ds"), str.as_string()); + str = json::value::parse(U("\"\\\"ds\"")); + VERIFY_ARE_EQUAL(U("\"ds"), str.as_string()); - str = json::value::parse(U("\"\\\"\\\"\"")); - VERIFY_ARE_EQUAL(U("\"\""), str.as_string()); + str = json::value::parse(U("\"\\\"\\\"\"")); + VERIFY_ARE_EQUAL(U("\"\""), str.as_string()); - // two character escapes - str = json::value::parse(U("\"\\\\\"")); - VERIFY_ARE_EQUAL(U("\\"), str.as_string()); + // two character escapes + str = json::value::parse(U("\"\\\\\"")); + VERIFY_ARE_EQUAL(U("\\"), str.as_string()); - str = json::value::parse(U("\"\\/\"")); - VERIFY_ARE_EQUAL(U("/"), str.as_string()); + str = json::value::parse(U("\"\\/\"")); + VERIFY_ARE_EQUAL(U("/"), str.as_string()); - str = json::value::parse(U("\"\\b\"")); - VERIFY_ARE_EQUAL(U("\b"), str.as_string()); + str = json::value::parse(U("\"\\b\"")); + VERIFY_ARE_EQUAL(U("\b"), str.as_string()); - str = json::value::parse(U("\"\\f\"")); - VERIFY_ARE_EQUAL(U("\f"), str.as_string()); + str = json::value::parse(U("\"\\f\"")); + VERIFY_ARE_EQUAL(U("\f"), str.as_string()); - str = json::value::parse(U("\"\\n\"")); - VERIFY_ARE_EQUAL(U("\n"), str.as_string()); + str = json::value::parse(U("\"\\n\"")); + VERIFY_ARE_EQUAL(U("\n"), str.as_string()); - str = json::value::parse(U("\"\\r\"")); - VERIFY_ARE_EQUAL(U("\r"), str.as_string()); + str = json::value::parse(U("\"\\r\"")); + VERIFY_ARE_EQUAL(U("\r"), str.as_string()); - str = json::value::parse(U("\"\\t\"")); - VERIFY_ARE_EQUAL(U("\t"), str.as_string()); -} + str = json::value::parse(U("\"\\t\"")); + VERIFY_ARE_EQUAL(U("\t"), str.as_string()); + } -TEST(escaped_unicode_string) -{ - auto str = json::value::parse(U("\"\\u0041\"")); - VERIFY_ARE_EQUAL(U("A"), str.as_string()); + TEST(escaped_unicode_string) + { + auto str = json::value::parse(U("\"\\u0041\"")); + VERIFY_ARE_EQUAL(U("A"), str.as_string()); - str = json::value::parse(U("\"\\u004B\"")); - VERIFY_ARE_EQUAL(U("K"), str.as_string()); + str = json::value::parse(U("\"\\u004B\"")); + VERIFY_ARE_EQUAL(U("K"), str.as_string()); - str = json::value::parse(U("\"\\u20AC\"")); - // Euro sign as a hexidecmial UTF-8 - const auto euro = to_string_t("\xE2\x82\xAC"); - VERIFY_ARE_EQUAL(euro, str.as_string()); + str = json::value::parse(U("\"\\u20AC\"")); + // Euro sign as a hexidecmial UTF-8 + const auto euro = to_string_t("\xE2\x82\xAC"); + VERIFY_ARE_EQUAL(euro, str.as_string()); - VERIFY_PARSING_THROW(json::value::parse(U("\"\\u0klB\""))); -} + VERIFY_PARSING_THROW(json::value::parse(U("\"\\u0klB\""))); + } -TEST(escaping_control_characters) -{ - std::vector chars; - for (int i = 0; i <= 0x1F; ++i) + TEST(escaping_control_characters) { - chars.push_back(i); + std::vector chars; + for (int i = 0; i <= 0x1F; ++i) + { + chars.push_back(i); + } + chars.push_back(0x5C); // backslash '\' + chars.push_back(0x22); // quotation '"' + + for (int i : chars) + { + utility::stringstream_t ss; + ss << U("\"\\u") << std::uppercase << std::setfill(U('0')) << std::setw(4) << std::hex << i << U("\""); + const auto& str = ss.str(); + auto expectedStr = str; + if (i == 0x08) + { + expectedStr = U("\"\\b\""); + } + else if (i == 0x09) + { + expectedStr = U("\"\\t\""); + } + else if (i == 0x0A) + { + expectedStr = U("\"\\n\""); + } + else if (i == 0x0C) + { + expectedStr = U("\"\\f\""); + } + else if (i == 0x0D) + { + expectedStr = U("\"\\r\""); + } + else if (i == 0x5C) + { + expectedStr = U("\"\\\\\""); + } + else if (i == 0x22) + { + expectedStr = U("\"\\\"\""); + } + + // Try constructing a json string value directly. + utility::string_t schar; + schar.push_back(static_cast(i)); + const auto& sv = json::value::string(schar); + VERIFY_ARE_EQUAL(expectedStr, sv.serialize()); + + // Try parsing a string + const auto& v = json::value::parse(str); + VERIFY_IS_TRUE(v.is_string()); + VERIFY_ARE_EQUAL(expectedStr, v.serialize()); + + // Try parsing a stringstream. + const auto& ssv = json::value::parse(ss); + VERIFY_ARE_EQUAL(expectedStr, ssv.serialize()); + } } - chars.push_back(0x5C); // backslash '\' - chars.push_back(0x22); // quotation '"' - for (int i : chars) + TEST(comments_string) { - utility::stringstream_t ss; - ss << U("\"\\u") << std::uppercase << std::setfill(U('0')) << std::setw(4) << std::hex << i << U("\""); - const auto &str = ss.str(); - auto expectedStr = str; - if (i == 0x08) + // Nothing but a comment + VERIFY_PARSING_THROW(json::value::parse(U(" /* There's nothing but a comment here */ "))); + VERIFY_PARSING_THROW(json::value::parse(U(" // There's nothing but a comment here\n"))); + + // Some invalid comments + VERIFY_PARSING_THROW(json::value::parse(U(" -22 /*/"))); + VERIFY_PARSING_THROW(json::value::parse(U(" -22 /* /* nested */ */"))); + + // Correctly placed comments + json::value num1 = json::value::parse(U("-22 // This is a trailing comment\n")); + VERIFY_ARE_EQUAL(-22, num1.as_double()); + num1 = json::value::parse(U(" -22 /* This is a trailing comment with a // nested\n comment */")); + VERIFY_ARE_EQUAL(-22, num1.as_double()); + json::value num2 = json::value::parse(U("// This is a leading comment\n -22")); + VERIFY_ARE_EQUAL(-22, num2.as_double()); + json::value num3 = json::value::parse(U("-22 /* This is a trailing comment */")); + VERIFY_ARE_EQUAL(-22, num3.as_double()); + json::value num4 = json::value::parse(U("/* This is a leading comment */ -22")); + VERIFY_ARE_EQUAL(-22, num4.as_double()); + json::value num5 = json::value::parse(U("-22 /***/")); + VERIFY_ARE_EQUAL(-22, num5.as_double()); + + json::value obj1 = json::value::parse(U("{// A comment in the middle of an empty object\n}")); + VERIFY_IS_TRUE(obj1.is_object()); + VERIFY_ARE_EQUAL(0u, obj1.size()); + json::value obj2 = json::value::parse(U("{/* A comment in the middle of an empty object */}")); + VERIFY_IS_TRUE(obj2.is_object()); + VERIFY_ARE_EQUAL(0u, obj2.size()); + json::value obj3 = json::value::parse(U("{ \"test\" : // A comment in the middle of a non-empty object\n 2}")); + VERIFY_IS_TRUE(obj3.is_object()); + VERIFY_ARE_EQUAL(1u, obj3.size()); + json::value obj4 = json::value::parse(U("{ \"test\" : /* A comment in the middle of a non-empty object */ 2}")); + VERIFY_IS_TRUE(obj4.is_object()); + VERIFY_ARE_EQUAL(1u, obj4.size()); + + json::value arr1 = json::value::parse(U("[// A comment in the middle of an empty array\n]")); + VERIFY_IS_TRUE(arr1.is_array()); + VERIFY_ARE_EQUAL(0u, arr1.size()); + json::value arr2 = json::value::parse(U("[/* A comment in the middle of an empty array */]")); + VERIFY_IS_TRUE(arr2.is_array()); + VERIFY_ARE_EQUAL(0u, arr2.size()); + json::value arr3 = json::value::parse(U("[ 1, // A comment in the middle of a non-array\n 2]")); + VERIFY_IS_TRUE(arr3.is_array()); + VERIFY_ARE_EQUAL(2u, arr3.size()); + json::value arr4 = json::value::parse(U("[ 1, /* A comment in the middle of a non-empty array */ 2]")); + VERIFY_IS_TRUE(arr4.is_array()); + VERIFY_ARE_EQUAL(2u, arr4.size()); + } + + TEST(comments_stream) + { + // Nothing but a comment { - expectedStr = U("\"\\b\""); + std::basic_stringstream stream; + stream << U(" /* There's nothing but a comment here */ "); + VERIFY_PARSING_THROW(json::value::parse(stream)); } - else if (i == 0x09) { - expectedStr = U("\"\\t\""); + std::basic_stringstream stream; + stream << U(" // There's nothing but a comment here\n "); + VERIFY_PARSING_THROW(json::value::parse(stream)); } - else if (i == 0x0A) + + // Some invalid comments { - expectedStr = U("\"\\n\""); + std::basic_stringstream stream; + stream << U(" -22 /*/"); + VERIFY_PARSING_THROW(json::value::parse(stream)); } - else if (i == 0x0C) { - expectedStr = U("\"\\f\""); + std::basic_stringstream stream; + stream << U(" -22 /* /* nested */ */"); + VERIFY_PARSING_THROW(json::value::parse(stream)); } - else if (i == 0x0D) + + // Correctly placed comments { - expectedStr = U("\"\\r\""); + std::basic_stringstream stream; + stream << U("-22 // This is a trailing comment\n"); + json::value num1 = json::value::parse(stream); + VERIFY_ARE_EQUAL(-22, num1.as_double()); } - else if (i == 0x5C) { - expectedStr = U("\"\\\\\""); + std::basic_stringstream stream; + stream << U(" -22 /* This is a trailing comment with a // nested\n comment */"); + json::value num1 = json::value::parse(stream); + VERIFY_ARE_EQUAL(-22, num1.as_double()); } - else if (i == 0x22) { - expectedStr = U("\"\\\"\""); + std::basic_stringstream stream; + stream << U("// This is a leading comment\n -22"); + json::value num2 = json::value::parse(stream); + VERIFY_ARE_EQUAL(-22, num2.as_double()); + } + { + std::basic_stringstream stream; + stream << U("-22 /* This is a trailing comment */"); + json::value num3 = json::value::parse(stream); + VERIFY_ARE_EQUAL(-22, num3.as_double()); + } + { + std::basic_stringstream stream; + stream << U("/* This is a leading comment */ -22"); + json::value num4 = json::value::parse(stream); + VERIFY_ARE_EQUAL(-22, num4.as_double()); + } + { + std::basic_stringstream stream; + stream << U("-22 /***/"); + json::value num4 = json::value::parse(stream); + VERIFY_ARE_EQUAL(-22, num4.as_double()); } - // Try constructing a json string value directly. - utility::string_t schar; - schar.push_back(static_cast(i)); - const auto &sv = json::value::string(schar); - VERIFY_ARE_EQUAL(expectedStr, sv.serialize()); - - // Try parsing a string - const auto &v = json::value::parse(str); - VERIFY_IS_TRUE(v.is_string()); - VERIFY_ARE_EQUAL(expectedStr, v.serialize()); - - // Try parsing a stringstream. - const auto &ssv = json::value::parse(ss); - VERIFY_ARE_EQUAL(expectedStr, ssv.serialize()); - } -} - -TEST(comments_string) -{ - // Nothing but a comment - VERIFY_PARSING_THROW(json::value::parse(U(" /* There's nothing but a comment here */ "))); - VERIFY_PARSING_THROW(json::value::parse(U(" // There's nothing but a comment here\n"))); - - // Some invalid comments - VERIFY_PARSING_THROW(json::value::parse(U(" -22 /*/"))); - VERIFY_PARSING_THROW(json::value::parse(U(" -22 /* /* nested */ */"))); - - // Correctly placed comments - json::value num1 = json::value::parse(U("-22 // This is a trailing comment\n")); - VERIFY_ARE_EQUAL(-22, num1.as_double()); - num1 = json::value::parse(U(" -22 /* This is a trailing comment with a // nested\n comment */")); - VERIFY_ARE_EQUAL(-22, num1.as_double()); - json::value num2 = json::value::parse(U("// This is a leading comment\n -22")); - VERIFY_ARE_EQUAL(-22, num2.as_double()); - json::value num3 = json::value::parse(U("-22 /* This is a trailing comment */")); - VERIFY_ARE_EQUAL(-22, num3.as_double()); - json::value num4 = json::value::parse(U("/* This is a leading comment */ -22")); - VERIFY_ARE_EQUAL(-22, num4.as_double()); - json::value num5 = json::value::parse(U("-22 /***/")); - VERIFY_ARE_EQUAL(-22, num5.as_double()); - - json::value obj1 = json::value::parse(U("{// A comment in the middle of an empty object\n}")); - VERIFY_IS_TRUE(obj1.is_object()); - VERIFY_ARE_EQUAL(0u, obj1.size()); - json::value obj2 = json::value::parse(U("{/* A comment in the middle of an empty object */}")); - VERIFY_IS_TRUE(obj2.is_object()); - VERIFY_ARE_EQUAL(0u, obj2.size()); - json::value obj3 = json::value::parse(U("{ \"test\" : // A comment in the middle of a non-empty object\n 2}")); - VERIFY_IS_TRUE(obj3.is_object()); - VERIFY_ARE_EQUAL(1u, obj3.size()); - json::value obj4 = json::value::parse(U("{ \"test\" : /* A comment in the middle of a non-empty object */ 2}")); - VERIFY_IS_TRUE(obj4.is_object()); - VERIFY_ARE_EQUAL(1u, obj4.size()); - - json::value arr1 = json::value::parse(U("[// A comment in the middle of an empty array\n]")); - VERIFY_IS_TRUE(arr1.is_array()); - VERIFY_ARE_EQUAL(0u, arr1.size()); - json::value arr2 = json::value::parse(U("[/* A comment in the middle of an empty array */]")); - VERIFY_IS_TRUE(arr2.is_array()); - VERIFY_ARE_EQUAL(0u, arr2.size()); - json::value arr3 = json::value::parse(U("[ 1, // A comment in the middle of a non-array\n 2]")); - VERIFY_IS_TRUE(arr3.is_array()); - VERIFY_ARE_EQUAL(2u, arr3.size()); - json::value arr4 = json::value::parse(U("[ 1, /* A comment in the middle of a non-empty array */ 2]")); - VERIFY_IS_TRUE(arr4.is_array()); - VERIFY_ARE_EQUAL(2u, arr4.size()); -} - -TEST(comments_stream) -{ - // Nothing but a comment - { - std::basic_stringstream stream; - stream << U(" /* There's nothing but a comment here */ "); - VERIFY_PARSING_THROW(json::value::parse(stream)); - } - { - std::basic_stringstream stream; - stream << U(" // There's nothing but a comment here\n "); - VERIFY_PARSING_THROW(json::value::parse(stream)); - } + { + std::basic_stringstream stream; + stream << U("{// A comment in the middle of an empty object\n}"); + json::value obj1 = json::value::parse(stream); + VERIFY_IS_TRUE(obj1.is_object()); + VERIFY_ARE_EQUAL(0u, obj1.size()); + } + { + std::basic_stringstream stream; + stream << U("{/* A comment in the middle of an empty object */}"); + json::value obj2 = json::value::parse(stream); + VERIFY_IS_TRUE(obj2.is_object()); + VERIFY_ARE_EQUAL(0u, obj2.size()); + } + { + std::basic_stringstream stream; + stream << U("{ \"test1\" : // A comment in the middle of a non-empty object\n 2}"); + json::value obj3 = json::value::parse(stream); + VERIFY_IS_TRUE(obj3.is_object()); + VERIFY_ARE_EQUAL(1u, obj3.size()); + } + { + std::basic_stringstream stream; + stream << U("{ \"test1\" : /* A comment in the middle of a non-empty object */ 2}"); + json::value obj4 = json::value::parse(stream); + VERIFY_IS_TRUE(obj4.is_object()); + VERIFY_ARE_EQUAL(1u, obj4.size()); + } - // Some invalid comments - { - std::basic_stringstream stream; - stream << U(" -22 /*/"); - VERIFY_PARSING_THROW(json::value::parse(stream)); - } - { - std::basic_stringstream stream; - stream << U(" -22 /* /* nested */ */"); - VERIFY_PARSING_THROW(json::value::parse(stream)); + { + std::basic_stringstream stream; + stream << U("[// A comment in the middle of an empty array\n]"); + json::value arr1 = json::value::parse(stream); + VERIFY_IS_TRUE(arr1.is_array()); + VERIFY_ARE_EQUAL(0u, arr1.size()); + } + { + std::basic_stringstream stream; + stream << U("[/* A comment in the middle of an empty array */]"); + json::value arr2 = json::value::parse(stream); + VERIFY_IS_TRUE(arr2.is_array()); + VERIFY_ARE_EQUAL(0u, arr2.size()); + } + { + std::basic_stringstream stream; + stream << U("[ 1, // A comment in the middle of a non-array\n 2]"); + json::value arr3 = json::value::parse(stream); + VERIFY_IS_TRUE(arr3.is_array()); + VERIFY_ARE_EQUAL(2u, arr3.size()); + } + { + std::basic_stringstream stream; + stream << U("[ 1, /* A comment in the middle of a non-empty array */ 2]"); + json::value arr4 = json::value::parse(stream); + VERIFY_IS_TRUE(arr4.is_array()); + VERIFY_ARE_EQUAL(2u, arr4.size()); + } } - // Correctly placed comments - { - std::basic_stringstream stream; - stream << U("-22 // This is a trailing comment\n"); - json::value num1 = json::value::parse(stream); - VERIFY_ARE_EQUAL(-22, num1.as_double()); - } - { - std::basic_stringstream stream; - stream << U(" -22 /* This is a trailing comment with a // nested\n comment */"); - json::value num1 = json::value::parse(stream); - VERIFY_ARE_EQUAL(-22, num1.as_double()); - } - { - std::basic_stringstream stream; - stream << U("// This is a leading comment\n -22"); - json::value num2 = json::value::parse(stream); - VERIFY_ARE_EQUAL(-22, num2.as_double()); - } - { - std::basic_stringstream stream; - stream << U("-22 /* This is a trailing comment */"); - json::value num3 = json::value::parse(stream); - VERIFY_ARE_EQUAL(-22, num3.as_double()); - } + TEST(empty_object_array) { - std::basic_stringstream stream; - stream << U("/* This is a leading comment */ -22"); - json::value num4 = json::value::parse(stream); - VERIFY_ARE_EQUAL(-22, num4.as_double()); - } - { - std::basic_stringstream stream; - stream << U("-22 /***/"); - json::value num4 = json::value::parse(stream); - VERIFY_ARE_EQUAL(-22, num4.as_double()); - } + json::value obj = json::value::parse(U("{}")); + VERIFY_IS_TRUE(obj.is_object()); + VERIFY_ARE_EQUAL(0u, obj.size()); - { - std::basic_stringstream stream; - stream << U("{// A comment in the middle of an empty object\n}"); - json::value obj1 = json::value::parse(stream); - VERIFY_IS_TRUE(obj1.is_object()); - VERIFY_ARE_EQUAL(0u, obj1.size()); - } - { - std::basic_stringstream stream; - stream << U("{/* A comment in the middle of an empty object */}"); - json::value obj2 = json::value::parse(stream); - VERIFY_IS_TRUE(obj2.is_object()); - VERIFY_ARE_EQUAL(0u, obj2.size()); - } - { - std::basic_stringstream stream; - stream << U("{ \"test1\" : // A comment in the middle of a non-empty object\n 2}"); - json::value obj3 = json::value::parse(stream); - VERIFY_IS_TRUE(obj3.is_object()); - VERIFY_ARE_EQUAL(1u, obj3.size()); - } - { - std::basic_stringstream stream; - stream << U("{ \"test1\" : /* A comment in the middle of a non-empty object */ 2}"); - json::value obj4 = json::value::parse(stream); - VERIFY_IS_TRUE(obj4.is_object()); - VERIFY_ARE_EQUAL(1u, obj4.size()); + json::value arr = json::value::parse(U("[]")); + VERIFY_IS_TRUE(arr.is_array()); + VERIFY_ARE_EQUAL(0u, arr.size()); } + TEST(bug_416116) { - std::basic_stringstream stream; - stream << U("[// A comment in the middle of an empty array\n]"); - json::value arr1 = json::value::parse(stream); - VERIFY_IS_TRUE(arr1.is_array()); - VERIFY_ARE_EQUAL(0u, arr1.size()); - } - { - std::basic_stringstream stream; - stream << U("[/* A comment in the middle of an empty array */]"); - json::value arr2 = json::value::parse(stream); - VERIFY_IS_TRUE(arr2.is_array()); - VERIFY_ARE_EQUAL(0u, arr2.size()); - } - { - std::basic_stringstream stream; - stream << U("[ 1, // A comment in the middle of a non-array\n 2]"); - json::value arr3 = json::value::parse(stream); - VERIFY_IS_TRUE(arr3.is_array()); - VERIFY_ARE_EQUAL(2u, arr3.size()); - } - { - std::basic_stringstream stream; - stream << U("[ 1, /* A comment in the middle of a non-empty array */ 2]"); - json::value arr4 = json::value::parse(stream); - VERIFY_IS_TRUE(arr4.is_array()); - VERIFY_ARE_EQUAL(2u, arr4.size()); - } -} - -TEST(empty_object_array) -{ - json::value obj = json::value::parse(U("{}")); - VERIFY_IS_TRUE(obj.is_object()); - VERIFY_ARE_EQUAL(0u, obj.size()); - - json::value arr = json::value::parse(U("[]")); - VERIFY_IS_TRUE(arr.is_array()); - VERIFY_ARE_EQUAL(0u, arr.size()); -} - -TEST(bug_416116) -{ - json::value data2 = json::value::parse(U("\"δοκιμή\"")); - auto s = data2.serialize(); + json::value data2 = json::value::parse(U("\"δοκιμή\"")); + auto s = data2.serialize(); #if defined(_MSC_VER) -#pragma warning( push ) -#pragma warning( disable : 4566 ) +#pragma warning(push) +#pragma warning(disable : 4566) #endif - VERIFY_ARE_EQUAL(s, U("\"δοκιμή\"")); + VERIFY_ARE_EQUAL(s, U("\"δοκιμή\"")); #if defined(_MSC_VER) -#pragma warning( pop ) +#pragma warning(pop) #endif -} - -TEST(byte_ptr_parsing_array) -{ - char s[] = "[ \"test1\",true]"; - std::stringstream ss; - ss << s; - json::value v = json::value::parse(ss); - auto s2 = v.serialize(); + } - VERIFY_ARE_EQUAL(s2, U("[\"test1\",true]")); + TEST(byte_ptr_parsing_array) + { + char s[] = "[ \"test1\",true]"; + std::stringstream ss; + ss << s; + json::value v = json::value::parse(ss); + auto s2 = v.serialize(); - std::stringstream os; - v.serialize(os); - VERIFY_ARE_EQUAL(s2, to_string_t(os.str())); -} + VERIFY_ARE_EQUAL(s2, U("[\"test1\",true]")); -TEST(byte_ptr_parsing_object) -{ - char s[] = "{\"test1\":true }"; - std::stringstream ss; - ss << s; - json::value v = json::value::parse(ss); - auto s2 = v.serialize(); + std::stringstream os; + v.serialize(os); + VERIFY_ARE_EQUAL(s2, to_string_t(os.str())); + } - VERIFY_ARE_EQUAL(s2, U("{\"test1\":true}")); + TEST(byte_ptr_parsing_object) + { + char s[] = "{\"test1\":true }"; + std::stringstream ss; + ss << s; + json::value v = json::value::parse(ss); + auto s2 = v.serialize(); - std::stringstream os; - v.serialize(os); - VERIFY_ARE_EQUAL(s2, to_string_t(os.str())); -} + VERIFY_ARE_EQUAL(s2, U("{\"test1\":true}")); -TEST(Japanese) -{ - utility::string_t ws = U("\"こんにちは\""); - std::string s = to_utf8string(ws); + std::stringstream os; + v.serialize(os); + VERIFY_ARE_EQUAL(s2, to_string_t(os.str())); + } - std::stringstream ss; - ss << s; - json::value v = json::value::parse(ss); - auto s2 = v.serialize(); + TEST(Japanese) + { + utility::string_t ws = U("\"こんにちは\""); + std::string s = to_utf8string(ws); - VERIFY_ARE_EQUAL(s2, ws); + std::stringstream ss; + ss << s; + json::value v = json::value::parse(ss); + auto s2 = v.serialize(); - std::stringstream os; - v.serialize(os); - VERIFY_ARE_EQUAL(s2, to_string_t(os.str())); -} + VERIFY_ARE_EQUAL(s2, ws); -TEST(Russian) -{ - utility::string_t ws = U("{\"results\":[{\"id\":272655310,\"name\":\"Андрей Ив´анов\"}]}"); - json::value v1 = json::value::parse(ws); - auto s2 = v1.serialize(); + std::stringstream os; + v.serialize(os); + VERIFY_ARE_EQUAL(s2, to_string_t(os.str())); + } - VERIFY_ARE_EQUAL(s2, ws); + TEST(Russian) + { + utility::string_t ws = U("{\"results\":[{\"id\":272655310,\"name\":\"Андрей Ив´анов\"}]}"); + json::value v1 = json::value::parse(ws); + auto s2 = v1.serialize(); - std::string s = to_utf8string(ws); + VERIFY_ARE_EQUAL(s2, ws); - std::stringstream ss; - ss << s; - json::value v2 = json::value::parse(ss); - auto s3 = v2.serialize(); + std::string s = to_utf8string(ws); - VERIFY_ARE_EQUAL(s3, ws); -} + std::stringstream ss; + ss << s; + json::value v2 = json::value::parse(ss); + auto s3 = v2.serialize(); -utility::string_t make_deep_json_string(size_t depth) -{ - utility::string_t strval; - for(size_t i=0; i& p1, - const std::pair& p2) - { - return p1.first < p2.first; - } + static bool compare_pairs(const std::pair& p1, + const std::pair& p2) + { + return p1.first < p2.first; + } -TEST(unsorted_object_parsing) -{ - utility::stringstream_t ss; - ss << U("{\"z\":2, \"a\":1}"); - json::value v = json::value::parse(ss); - auto& obj = v.as_object(); - - VERIFY_ARE_NOT_EQUAL(obj.find(U("a")), obj.end()); - VERIFY_ARE_NOT_EQUAL(obj.find(U("z")), obj.end()); - VERIFY_ARE_EQUAL(obj[U("a")], 1); - VERIFY_ARE_EQUAL(obj[U("z")], 2); - VERIFY_ARE_EQUAL(obj.size(), 2); - - VERIFY_IS_TRUE(::std::is_sorted(obj.begin(), obj.end(), compare_pairs)); -} + TEST(unsorted_object_parsing) + { + utility::stringstream_t ss; + ss << U("{\"z\":2, \"a\":1}"); + json::value v = json::value::parse(ss); + auto& obj = v.as_object(); -TEST(keep_order_while_parsing) -{ - utility::stringstream_t ss; - ss << U("{\"k\":3, \"j\":2, \"i\":1}"); + VERIFY_ARE_NOT_EQUAL(obj.find(U("a")), obj.end()); + VERIFY_ARE_NOT_EQUAL(obj.find(U("z")), obj.end()); + VERIFY_ARE_EQUAL(obj[U("a")], 1); + VERIFY_ARE_EQUAL(obj[U("z")], 2); + VERIFY_ARE_EQUAL(obj.size(), 2); - json::keep_object_element_order(true); - struct restore { - ~restore() { - json::keep_object_element_order(false); - } - }_; - - json::value v = json::value::parse(ss); - auto& obj = v.as_object(); - - // Make sure collection stays unsorted: - auto b = obj.begin(); - VERIFY_ARE_EQUAL(b[0].first, U("k")); - VERIFY_ARE_EQUAL(b[1].first, U("j")); - VERIFY_ARE_EQUAL(b[2].first, U("i")); - - // Make sure lookup still works: - auto val_i = obj[U("i")]; - VERIFY_ARE_EQUAL(val_i.as_integer(), 1); - - auto val_j = obj[U("j")]; - VERIFY_ARE_EQUAL(val_j.as_integer(), 2); - - // Make sure 'a' goes to the back of the collection, and - // can be looked up - obj[U("a")] = 4; - b = obj.begin(); - VERIFY_ARE_EQUAL(b[3].first, U("a")); - VERIFY_ARE_EQUAL(obj[U("a")].as_integer(), 4); -} + VERIFY_IS_TRUE(::std::is_sorted(obj.begin(), obj.end(), compare_pairs)); + } -TEST(non_default_locale, "Ignore:Android", "Locale unsupported on Android") -{ - std::string originalLocale = setlocale(LC_ALL, nullptr); + TEST(keep_order_while_parsing) + { + utility::stringstream_t ss; + ss << U("{\"k\":3, \"j\":2, \"i\":1}"); + + json::keep_object_element_order(true); + struct restore + { + ~restore() { json::keep_object_element_order(false); } + } _; + + json::value v = json::value::parse(ss); + auto& obj = v.as_object(); + + // Make sure collection stays unsorted: + auto b = obj.begin(); + VERIFY_ARE_EQUAL(b[0].first, U("k")); + VERIFY_ARE_EQUAL(b[1].first, U("j")); + VERIFY_ARE_EQUAL(b[2].first, U("i")); + + // Make sure lookup still works: + auto val_i = obj[U("i")]; + VERIFY_ARE_EQUAL(val_i.as_integer(), 1); + + auto val_j = obj[U("j")]; + VERIFY_ARE_EQUAL(val_j.as_integer(), 2); + + // Make sure 'a' goes to the back of the collection, and + // can be looked up + obj[U("a")] = 4; + b = obj.begin(); + VERIFY_ARE_EQUAL(b[3].first, U("a")); + VERIFY_ARE_EQUAL(obj[U("a")].as_integer(), 4); + } + + TEST(non_default_locale, "Ignore:Android", "Locale unsupported on Android") + { + std::string originalLocale = setlocale(LC_ALL, nullptr); #ifdef _WIN32 - std::string changedLocale("fr-FR"); + std::string changedLocale("fr-FR"); #else - std::string changedLocale("fr_FR.utf8"); + std::string changedLocale("fr_FR.utf8"); #endif - // If locale isn't installed on system just silently pass. - if(setlocale(LC_ALL, changedLocale.c_str()) != nullptr) - { - // string serialize - utility::string_t str(U("[true,false,-1.55,5,null,{\"abc\":5555}]")); - json::value v = json::value::parse(str); - VERIFY_ARE_EQUAL(changedLocale, setlocale(LC_ALL, nullptr)); - VERIFY_ARE_EQUAL(str, v.serialize()); - VERIFY_ARE_EQUAL(changedLocale, setlocale(LC_ALL, nullptr)); - - setlocale(LC_ALL, originalLocale.c_str()); - setlocale(LC_NUMERIC, changedLocale.c_str()); - - // cpprestsdk stream serialize - utility::stringstream_t stream; - stream << v; - utility::string_t serializedStr; - stream >> serializedStr; - VERIFY_ARE_EQUAL(str, serializedStr); - - // std stream serialize - std::stringstream stdStream; - v.serialize(stdStream); - std::string stdStr; - stdStream >> stdStr; - VERIFY_ARE_EQUAL(str, utility::conversions::to_string_t(stdStr)); - - setlocale(LC_ALL, originalLocale.c_str()); + // If locale isn't installed on system just silently pass. + if (setlocale(LC_ALL, changedLocale.c_str()) != nullptr) + { + // string serialize + utility::string_t str(U("[true,false,-1.55,5,null,{\"abc\":5555}]")); + json::value v = json::value::parse(str); + VERIFY_ARE_EQUAL(changedLocale, setlocale(LC_ALL, nullptr)); + VERIFY_ARE_EQUAL(str, v.serialize()); + VERIFY_ARE_EQUAL(changedLocale, setlocale(LC_ALL, nullptr)); + + setlocale(LC_ALL, originalLocale.c_str()); + setlocale(LC_NUMERIC, changedLocale.c_str()); + + // cpprestsdk stream serialize + utility::stringstream_t stream; + stream << v; + utility::string_t serializedStr; + stream >> serializedStr; + VERIFY_ARE_EQUAL(str, serializedStr); + + // std stream serialize + std::stringstream stdStream; + v.serialize(stdStream); + std::string stdStr; + stdStream >> stdStr; + VERIFY_ARE_EQUAL(str, utility::conversions::to_string_t(stdStr)); + + setlocale(LC_ALL, originalLocale.c_str()); + } } -} -template -void error_code_helper(T &jsonData) -{ - std::error_code err; - auto parsedObject = web::json::value::parse(jsonData, err); - VERIFY_IS_TRUE(err.value() == 0); - VERIFY_IS_TRUE(!parsedObject.is_null()); -} + template + void error_code_helper(T & jsonData) + { + std::error_code err; + auto parsedObject = web::json::value::parse(jsonData, err); + VERIFY_IS_TRUE(err.value() == 0); + VERIFY_IS_TRUE(!parsedObject.is_null()); + } -TEST(parse_overload_success) -{ - std::error_code err; - utility::string_t valueStr(U("\"JSONString\"")); - utility::string_t arrStr(U("[true,false,-1.55,5,null,{\"abc\":5555}]")); - utility::string_t objStr(U("{\"k\":3, \"j\":2, \"i\":1}")); + TEST(parse_overload_success) + { + std::error_code err; + utility::string_t valueStr(U("\"JSONString\"")); + utility::string_t arrStr(U("[true,false,-1.55,5,null,{\"abc\":5555}]")); + utility::string_t objStr(U("{\"k\":3, \"j\":2, \"i\":1}")); - error_code_helper(valueStr); - error_code_helper(arrStr); - error_code_helper(objStr); + error_code_helper(valueStr); + error_code_helper(arrStr); + error_code_helper(objStr); - utility::stringstream_t valueStringStream; - utility::stringstream_t arrayStringStream; - utility::stringstream_t objStringStream; + utility::stringstream_t valueStringStream; + utility::stringstream_t arrayStringStream; + utility::stringstream_t objStringStream; - valueStringStream << valueStr; - arrayStringStream << arrStr; - objStringStream << objStr; + valueStringStream << valueStr; + arrayStringStream << arrStr; + objStringStream << objStr; - error_code_helper(valueStringStream); - error_code_helper(arrayStringStream); - error_code_helper(objStringStream); + error_code_helper(valueStringStream); + error_code_helper(arrayStringStream); + error_code_helper(objStringStream); #ifdef _WIN32 - std::wstringbuf buf; + std::wstringbuf buf; - buf.sputn(valueStr.c_str(), valueStr.size()); - std::wistream valStream(&buf); - error_code_helper(valStream); + buf.sputn(valueStr.c_str(), valueStr.size()); + std::wistream valStream(&buf); + error_code_helper(valStream); - buf.sputn(arrStr.c_str(), arrStr.size()); - std::wistream arrStream(&buf); - error_code_helper(arrStream); + buf.sputn(arrStr.c_str(), arrStr.size()); + std::wistream arrStream(&buf); + error_code_helper(arrStream); - buf.sputn(objStr.c_str(), objStr.size()); - std::wistream objStream(&buf); - error_code_helper(objStream); + buf.sputn(objStr.c_str(), objStr.size()); + std::wistream objStream(&buf); + error_code_helper(objStream); #endif -} + } -TEST(parse_overload_failed) -{ - std::error_code err, streamErr, iStreamErr; - utility::string_t str(U("JSONString")); - utility::string_t arrStr(U("[true, false")); - json::value parsedObject = json::value::parse(str, err); + TEST(parse_overload_failed) + { + std::error_code err, streamErr, iStreamErr; + utility::string_t str(U("JSONString")); + utility::string_t arrStr(U("[true, false")); + json::value parsedObject = json::value::parse(str, err); + + VERIFY_IS_TRUE(err.value() > 0); + VERIFY_IS_TRUE(parsedObject.is_null()); - VERIFY_IS_TRUE(err.value() > 0); - VERIFY_IS_TRUE(parsedObject.is_null()); + utility::stringstream_t stream; + stream << str; - utility::stringstream_t stream; - stream << str; - - parsedObject = json::value::parse(arrStr, streamErr); - VERIFY_IS_TRUE(streamErr.value() > 0); - VERIFY_IS_TRUE(parsedObject.is_null()); + parsedObject = json::value::parse(arrStr, streamErr); + VERIFY_IS_TRUE(streamErr.value() > 0); + VERIFY_IS_TRUE(parsedObject.is_null()); #ifdef _WIN32 - std::wstringbuf buf; - buf.sputn(str.c_str(), str.size()); - std::wistream iStream(&buf); - parsedObject = json::value::parse(str, iStreamErr); - VERIFY_IS_TRUE(iStreamErr.value() > 0); - VERIFY_IS_TRUE(parsedObject.is_null()); + std::wstringbuf buf; + buf.sputn(str.c_str(), str.size()); + std::wistream iStream(&buf); + parsedObject = json::value::parse(str, iStreamErr); + VERIFY_IS_TRUE(iStreamErr.value() > 0); + VERIFY_IS_TRUE(parsedObject.is_null()); #endif -} + } } // SUITE(parsing_tests) -}}} +} // namespace json_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/json/stdafx.cpp b/Release/tests/functional/json/stdafx.cpp index bf3a8ed5ac..48b9655134 100644 --- a/Release/tests/functional/json/stdafx.cpp +++ b/Release/tests/functional/json/stdafx.cpp @@ -1,14 +1,14 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ -// stdafx.cpp : + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ +// stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" #if WIN32 __declspec(dllexport) int json_test_generate_lib = 0; -#endif \ No newline at end of file +#endif diff --git a/Release/tests/functional/json/stdafx.h b/Release/tests/functional/json/stdafx.h index 9f6bb03dd2..bb65303dca 100644 --- a/Release/tests/functional/json/stdafx.h +++ b/Release/tests/functional/json/stdafx.h @@ -1,20 +1,19 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.h + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "unittestpp.h" - #include #define NOMINMAX diff --git a/Release/tests/functional/json/to_as_and_operators_tests.cpp b/Release/tests/functional/json/to_as_and_operators_tests.cpp index eb1dc4f71b..6103adf6a4 100644 --- a/Release/tests/functional/json/to_as_and_operators_tests.cpp +++ b/Release/tests/functional/json/to_as_and_operators_tests.cpp @@ -1,510 +1,514 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests for to_*, as_*, and operators on JSON values. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests for to_*, as_*, and operators on JSON values. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -using namespace web; using namespace utility; +using namespace web; +using namespace utility; -namespace tests { namespace functional { namespace json_tests { - -SUITE(to_as_and_operators_tests) -{ - -TEST(to_string) -{ - utility::stringstream_t stream(utility::stringstream_t::in | utility::stringstream_t::out); - - // null - json::value n; - VERIFY_ARE_EQUAL(U("null"), n.serialize()); - n.serialize(stream); - VERIFY_ARE_EQUAL(U("null"), stream.str()); - - // bool - true - stream.str(U("")); - json::value b(true); - VERIFY_ARE_EQUAL(U("true"), b.serialize()); - b.serialize(stream); - VERIFY_ARE_EQUAL(U("true"), stream.str()); - - // bool - false - stream.str(U("")); - json::value b2(false); - VERIFY_ARE_EQUAL(U("false"), b2.serialize()); - b2.serialize(stream); - VERIFY_ARE_EQUAL(U("false"), stream.str()); - - // number - int - stream.str(U("")); - json::value num(44); - VERIFY_ARE_EQUAL(U("44"), num.serialize()); - num.serialize(stream); - VERIFY_ARE_EQUAL(U("44"), stream.str()); - - // number - double - stream.str(U("")); - json::value dNum(11.5); - VERIFY_ARE_EQUAL(U("11.5"), dNum.serialize()); - dNum.serialize(stream); - VERIFY_ARE_EQUAL(U("11.5"), stream.str()); - - // string - stream.str(U("")); - json::value string = json::value::string(U("hehehe")); - VERIFY_ARE_EQUAL(U("\"hehehe\""), string.serialize()); - string.serialize(stream); - VERIFY_ARE_EQUAL(U("\"hehehe\""), stream.str()); - - // object - with values created from parsing - stream.str(U("")); - const utility::string_t strValue1(U("{ \"key\" : true }")); - const utility::string_t strValue2(U("{\"key\":true}")); - json::value obj1 = json::value::parse(strValue1); - VERIFY_ARE_EQUAL(strValue2, obj1.serialize()); - json::value obj2 = json::value::parse(strValue2); - VERIFY_ARE_EQUAL(strValue2, obj2.serialize()); - obj1.serialize(stream); - VERIFY_ARE_EQUAL(strValue2, stream.str()); - - // object - with values added - stream.str(U("")); - json::value obj3 = json::value::object(); - obj3[U("key")] = json::value(true); - VERIFY_ARE_EQUAL(strValue2, obj3.serialize()); - obj3.serialize(stream); - VERIFY_ARE_EQUAL(strValue2, stream.str()); - - // array - stream.str(U("")); - json::value arr = json::value::array(); - arr[0] = json::value::string(U("Here")); - arr[1] = json::value(true); - VERIFY_ARE_EQUAL(U("[\"Here\",true]"), arr.serialize()); - VERIFY_ARE_EQUAL(U("[\"Here\",true]"), arr.serialize()); - arr.serialize(stream); - VERIFY_ARE_EQUAL(U("[\"Here\",true]"), stream.str()); -} - -TEST(empty_arrays_objects) -{ - // array - auto arr = json::value::parse(U("[ ]")); - VERIFY_ARE_EQUAL(U("[]"), arr.serialize()); - - // object - auto obj = json::value::parse(U("{ }")); - VERIFY_ARE_EQUAL(U("{}"), obj.serialize()); -} - -void verify_escaped_chars(const utility::string_t& str1, const utility::string_t& str2) -{ - json::value j1 = json::value::string(str1); - VERIFY_ARE_EQUAL(str2, j1.serialize()); -} - -void verify_unescaped_chars(const utility::string_t& str1, const utility::string_t& str2) -{ - json::value j1 = json::value::string(str1, false); - VERIFY_ARE_EQUAL(str2, j1.serialize()); -} - -TEST(to_string_escaped_chars) +namespace tests { - verify_escaped_chars(U(" \" "), U("\" \\\" \"")); - verify_escaped_chars(U(" \b "), U("\" \\b \"")); - verify_escaped_chars(U(" \f "), U("\" \\f \"")); - verify_escaped_chars(U(" \n "), U("\" \\n \"")); - verify_escaped_chars(U(" \r "), U("\" \\r \"")); - verify_escaped_chars(U(" \t "), U("\" \\t \"")); - - json::value obj = json::value::object(); - obj[U(" \t ")] = json::value::string(U(" \b ")); - - json::value arr = json::value::array(); - arr[0] = json::value::string(U(" \f ")); - - VERIFY_ARE_EQUAL(U("{\" \\t \":\" \\b \"}"), obj.serialize()); - VERIFY_ARE_EQUAL(U("[\" \\f \"]"), arr.serialize()); - - utility::string_t str(U("{\"hello\":\" \\\"here's looking at you kid\\\" \\r \"}")); - json::value obj2 = json::value::parse(str); - - VERIFY_ARE_EQUAL(str, obj2.serialize()); -} - -TEST(to_string_unescaped_chars) +namespace functional { - verify_unescaped_chars(U(" \" "), U("\" \" \"")); - verify_unescaped_chars(U(" \b "), U("\" \b \"")); - verify_unescaped_chars(U(" \f "), U("\" \f \"")); - verify_unescaped_chars(U(" \n "), U("\" \n \"")); - verify_unescaped_chars(U(" \r "), U("\" \r \"")); - verify_unescaped_chars(U(" \t "), U("\" \t \"")); - - json::value obj = json::value::object(); - obj[U(" \t ")] = json::value::string(U(" \b "), false); - - json::value arr = json::value::array(); - arr[0] = json::value::string(U(" \f "), false); - - VERIFY_ARE_EQUAL(U("{\" \\t \":\" \b \"}"), obj.serialize()); - VERIFY_ARE_EQUAL(U("[\" \f \"]"), arr.serialize()); -} - -TEST(as_string) +namespace json_tests { - json::value b(false); - VERIFY_THROWS(b.as_string(), json::json_exception); - VERIFY_THROWS(b.as_string(), json::json_exception); - - utility::string_t data(U("HERE IS A STRING")); - utility::string_t wdata(data.begin(), data.end()); - json::value str = json::value::string(data); - VERIFY_ARE_EQUAL(data, str.as_string()); - VERIFY_ARE_EQUAL(wdata, str.as_string()); -} - -TEST(as_copy_constructor) -{ - auto arr = json::value::array(); - arr[0] = json::value::number(44); - arr[1] = json::value::string(U("abc")); - json::array arrCopy = arr.as_array(); - VERIFY_ARE_EQUAL(2, arrCopy.size()); - VERIFY_ARE_EQUAL(2, arr.size()); - VERIFY_ARE_EQUAL(44, arrCopy[0].as_integer()); - VERIFY_ARE_EQUAL(U("abc"), arrCopy[1].as_string()); - VERIFY_ARE_EQUAL(44, arr[0].as_integer()); - VERIFY_ARE_EQUAL(U("abc"), arr[1].as_string()); - - auto obj = json::value::object(); - obj[U("abc")] = json::value::number(123); - json::object objCopy = obj.as_object(); - VERIFY_ARE_EQUAL(1, objCopy.size()); - VERIFY_ARE_EQUAL(1, obj.size()); - VERIFY_ARE_EQUAL(123, objCopy[U("abc")].as_integer()); - VERIFY_ARE_EQUAL(123, obj[U("abc")].as_integer()); - - auto num = json::value::number(44); - json::number numCopy = num.as_number(); - VERIFY_ARE_EQUAL(44, num.as_integer()); - VERIFY_ARE_EQUAL(44, numCopy.to_int32()); -} - -TEST(as_bool_as_double_as_string) -{ - utility::stringstream_t ss1; - ss1 << U("17"); - json::value v1 = json::value::parse(ss1); - - utility::stringstream_t ss2; - ss2 << U("3.1415"); - json::value v2 = json::value::parse(ss2); - - utility::stringstream_t ss3; - ss3 << U("true"); - json::value v3 = json::value::parse(ss3); - - utility::stringstream_t ss4; - ss4 << U("\"Hello!\""); - json::value v4 = json::value::parse(ss4); - - utility::stringstream_t ss8; - ss8 << U("{ \"a\" : 10, \"b\" : 4711.17, \"c\" : false }"); - json::value v8 = json::value::parse(ss8); - - utility::stringstream_t ss9; - ss9 << U("[1,2,3,true]"); - json::value v9 = json::value::parse(ss9); - - VERIFY_ARE_EQUAL(v1.as_double(), 17); - VERIFY_ARE_EQUAL(v2.as_double(), 3.1415); - VERIFY_IS_TRUE(v3.as_bool()); - VERIFY_ARE_EQUAL(v4.as_string(), U("Hello!")); - VERIFY_ARE_EQUAL(v4.as_string(), U("Hello!")); - - VERIFY_ARE_EQUAL(v8[U("a")].as_double(), 10); - VERIFY_ARE_EQUAL(v8[U("b")].as_double(), 4711.17); - VERIFY_ARE_EQUAL(v8[U("a")].as_integer(), 10); - VERIFY_IS_FALSE(v8[U("c")].as_bool()); - - VERIFY_ARE_EQUAL(v9[0].as_double(), 1); - VERIFY_ARE_EQUAL(v9[1].as_double(), 2); - VERIFY_ARE_EQUAL(v9[2].as_double(), 3); - VERIFY_IS_TRUE(v9[3].as_bool()); -} - -TEST(to_stream_operator) -{ - utility::string_t str(U("\"JSON STRING\"")); - json::value value = json::value::parse(str); - utility::stringstream_t stream; - stream << value; - VERIFY_ARE_EQUAL(str, stream.str()); -} - -TEST(from_stream_operator) -{ - utility::string_t str(U("\"JSON STRING!\"")); - utility::stringstream_t stream; - stream << str; - json::value value; - stream >> value; - VERIFY_IS_TRUE(value.is_string()); - VERIFY_ARE_EQUAL(str, value.serialize()); -} - -TEST(negative_is_tests) -{ - json::value b(true); - json::value str(U("string")); - json::value d(22.5); - json::value n; - json::value a = json::value::array(2); - json::value o = json::value::object(); - - VERIFY_IS_FALSE(b.is_number()); - VERIFY_IS_FALSE(str.is_boolean()); - VERIFY_IS_FALSE(d.is_string()); - VERIFY_IS_FALSE(a.is_object()); - VERIFY_IS_FALSE(o.is_array()); - VERIFY_IS_FALSE(n.is_string()); - VERIFY_IS_FALSE(str.is_null()); -} - -TEST(negative_index_operator_boolean) -{ - json::value v = json::value::boolean(true); - - VERIFY_THROWS(v[0], json::json_exception); - VERIFY_THROWS(v[U("H")], json::json_exception); - VERIFY_THROWS(v[U("A")], json::json_exception); -} - -TEST(negative_get_field_object) -{ - json::value v; - - v[U("a")] = json::value::number(1); - VERIFY_IS_TRUE(v.is_object()); - VERIFY_ARE_EQUAL(v[U("a")].as_integer(), 1); - VERIFY_IS_TRUE(v[U("b")].is_null()); - VERIFY_THROWS(v[0], json::json_exception); -} - -TEST(negative_get_element_array) -{ - json::value v; - - v[0] = json::value::number(1); - VERIFY_ARE_EQUAL(v[0].as_integer(), 1); - VERIFY_IS_TRUE(v[1].is_null()); - VERIFY_THROWS(v[U("a")], json::json_exception); -} - -TEST(has_field_object) -{ - - - json::value v1; - - v1[U("a")] = json::value::number(1); - v1[U("b")] = json::value::boolean(true); - v1[U("c")] = json::value::string(U("a string")); - v1[U("d")] = json::value::array({}); - json::value sub_field; - sub_field[U("x")] = json::value::number(1); - v1[U("e")] = sub_field; - - VERIFY_IS_TRUE(v1.has_field(U("a"))); - VERIFY_IS_TRUE(v1.has_field(U("b"))); - VERIFY_IS_TRUE(v1.has_field(U("c"))); - VERIFY_IS_TRUE(v1.has_field(U("d"))); - VERIFY_IS_TRUE(v1.has_field(U("e"))); - VERIFY_IS_FALSE(v1.has_field(U("f"))); - - VERIFY_IS_TRUE(v1.has_number_field(U("a"))); - VERIFY_IS_TRUE(v1.has_integer_field(U("a"))); - VERIFY_IS_FALSE(v1.has_double_field(U("a"))); - VERIFY_IS_FALSE(v1.has_boolean_field(U("a"))); - VERIFY_IS_FALSE(v1.has_string_field(U("a"))); - VERIFY_IS_FALSE(v1.has_array_field(U("a"))); - VERIFY_IS_FALSE(v1.has_object_field(U("a"))); - - VERIFY_IS_TRUE(v1.has_boolean_field(U("b"))); - VERIFY_IS_FALSE(v1.has_number_field(U("b"))); - VERIFY_IS_FALSE(v1.has_integer_field(U("b"))); - VERIFY_IS_FALSE(v1.has_double_field(U("b"))); - VERIFY_IS_FALSE(v1.has_string_field(U("b"))); - VERIFY_IS_FALSE(v1.has_array_field(U("b"))); - VERIFY_IS_FALSE(v1.has_object_field(U("b"))); - - VERIFY_IS_TRUE(v1.has_string_field(U("c"))); - VERIFY_IS_FALSE(v1.has_boolean_field(U("c"))); - VERIFY_IS_FALSE(v1.has_number_field(U("c"))); - VERIFY_IS_FALSE(v1.has_integer_field(U("c"))); - VERIFY_IS_FALSE(v1.has_double_field(U("c"))); - VERIFY_IS_FALSE(v1.has_array_field(U("c"))); - VERIFY_IS_FALSE(v1.has_object_field(U("c"))); - - VERIFY_IS_TRUE(v1.has_array_field(U("d"))); - VERIFY_IS_FALSE(v1.has_string_field(U("d"))); - VERIFY_IS_FALSE(v1.has_boolean_field(U("d"))); - VERIFY_IS_FALSE(v1.has_number_field(U("d"))); - VERIFY_IS_FALSE(v1.has_integer_field(U("d"))); - VERIFY_IS_FALSE(v1.has_double_field(U("d"))); - VERIFY_IS_FALSE(v1.has_object_field(U("d"))); - - VERIFY_IS_TRUE(v1.has_object_field(U("e"))); - VERIFY_IS_FALSE(v1.has_array_field(U("e"))); - VERIFY_IS_FALSE(v1.has_string_field(U("e"))); - VERIFY_IS_FALSE(v1.has_boolean_field(U("e"))); - VERIFY_IS_FALSE(v1.has_number_field(U("e"))); - VERIFY_IS_FALSE(v1.has_integer_field(U("e"))); - VERIFY_IS_FALSE(v1.has_double_field(U("e"))); - - json::value v2; - - v2[0] = json::value::number(1); - VERIFY_IS_FALSE(v2.has_field(U("0"))); - VERIFY_IS_FALSE(v2.has_field(U("b"))); -} - -TEST(negative_as_tests) -{ - json::value b(true); - VERIFY_THROWS(b.as_double(), json::json_exception); - VERIFY_THROWS(b.as_integer(), json::json_exception); - VERIFY_THROWS(b.as_string(), json::json_exception); - - json::value str = json::value::string(U("string")); - VERIFY_THROWS(str.as_double(), json::json_exception); - VERIFY_THROWS(str.as_bool(), json::json_exception); - VERIFY_THROWS(str.as_integer(), json::json_exception); - - json::value d(2.0f); - VERIFY_THROWS(d.as_string(), json::json_exception); - VERIFY_THROWS(d.as_bool(), json::json_exception); - - json::value i(11); - VERIFY_THROWS(i.as_bool(), json::json_exception); - VERIFY_THROWS(i.as_string(), json::json_exception); -} - -TEST(erase_array_index) -{ - json::value a = json::value::array(4); - a[0] = json::value(1); - a[1] = json::value(2); - a[2] = json::value(3); - a[3] = json::value(4); - - a.erase(1); - VERIFY_ARE_EQUAL(3, a.size()); - VERIFY_ARE_EQUAL(1, a[0].as_integer()); - VERIFY_ARE_EQUAL(3, a[1].as_integer()); - VERIFY_ARE_EQUAL(4, a[2].as_integer()); - a.as_array().erase(2); - VERIFY_ARE_EQUAL(2, a.size()); - VERIFY_ARE_EQUAL(1, a[0].as_integer()); - VERIFY_ARE_EQUAL(3, a[1].as_integer()); -} - -TEST(erase_array_iter) -{ - json::value a = json::value::array(3); - a[0] = json::value(1); - a[1] = json::value(2); - a[2] = json::value(3); - - auto iter = a.as_array().begin() + 1; - auto afterLoc = a.as_array().erase(iter); - VERIFY_ARE_EQUAL(3, afterLoc->as_integer()); - VERIFY_ARE_EQUAL(2, a.size()); - VERIFY_ARE_EQUAL(1, a[0].as_integer()); - VERIFY_ARE_EQUAL(3, a[1].as_integer()); - - iter = a.as_array().begin() + 1; - afterLoc = a.as_array().erase(iter); - VERIFY_ARE_EQUAL(a.as_array().end(), afterLoc); - VERIFY_ARE_EQUAL(1, a.size()); - VERIFY_ARE_EQUAL(1, a[0].as_integer()); -} - -TEST(erase_object_key) -{ - auto o = json::value::object(); - o[U("a")] = json::value(1); - o[U("b")] = json::value(2); - o[U("c")] = json::value(3); - o[U("d")] = json::value(4); - - o.erase(U("a")); - VERIFY_ARE_EQUAL(3, o.size()); - VERIFY_ARE_EQUAL(2, o[U("b")].as_integer()); - VERIFY_ARE_EQUAL(3, o[U("c")].as_integer()); - VERIFY_ARE_EQUAL(4, o[U("d")].as_integer()); - - o.as_object().erase(U("d")); - VERIFY_ARE_EQUAL(2, o.size()); - VERIFY_ARE_EQUAL(2, o[U("b")].as_integer()); - VERIFY_ARE_EQUAL(3, o[U("c")].as_integer()); -} - -TEST(erase_object_iter) -{ - auto o = json::value::object(); - o[U("a")] = json::value(1); - o[U("b")] = json::value(2); - o[U("c")] = json::value(3); - o[U("d")] = json::value(4); - - auto iter = o.as_object().begin() + 1; - auto afterLoc = o.as_object().erase(iter); - VERIFY_ARE_EQUAL(3, o.size()); - VERIFY_ARE_EQUAL(3, afterLoc->second.as_integer()); - VERIFY_ARE_EQUAL(1, o[U("a")].as_integer()); - VERIFY_ARE_EQUAL(3, o[U("c")].as_integer()); - VERIFY_ARE_EQUAL(4, o[U("d")].as_integer()); - - iter = o.as_object().begin() + 2; - afterLoc = o.as_object().erase(iter); - VERIFY_ARE_EQUAL(2, o.size()); - VERIFY_ARE_EQUAL(o.as_object().end(), afterLoc); - VERIFY_ARE_EQUAL(1, o[U("a")].as_integer()); - VERIFY_ARE_EQUAL(3, o[U("c")].as_integer()); -} - -TEST(floating_number_serialize) +SUITE(to_as_and_operators_tests) { - // This number will have the longest serializaton possible (lenght of the string): - // Sign, exponent, decimal comma, longest mantisa and exponent make so. - auto value = json::value(-3.123456789012345678901234567890E-123); - - // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) - const auto len = std::numeric_limits::digits10 + 9; - - // Check narrow string implementation - std::stringstream ss; - value.serialize(ss); - VERIFY_ARE_EQUAL(len, ss.str().length()); + TEST(to_string) + { + utility::stringstream_t stream(utility::stringstream_t::in | utility::stringstream_t::out); + + // null + json::value n; + VERIFY_ARE_EQUAL(U("null"), n.serialize()); + n.serialize(stream); + VERIFY_ARE_EQUAL(U("null"), stream.str()); + + // bool - true + stream.str(U("")); + json::value b(true); + VERIFY_ARE_EQUAL(U("true"), b.serialize()); + b.serialize(stream); + VERIFY_ARE_EQUAL(U("true"), stream.str()); + + // bool - false + stream.str(U("")); + json::value b2(false); + VERIFY_ARE_EQUAL(U("false"), b2.serialize()); + b2.serialize(stream); + VERIFY_ARE_EQUAL(U("false"), stream.str()); + + // number - int + stream.str(U("")); + json::value num(44); + VERIFY_ARE_EQUAL(U("44"), num.serialize()); + num.serialize(stream); + VERIFY_ARE_EQUAL(U("44"), stream.str()); + + // number - double + stream.str(U("")); + json::value dNum(11.5); + VERIFY_ARE_EQUAL(U("11.5"), dNum.serialize()); + dNum.serialize(stream); + VERIFY_ARE_EQUAL(U("11.5"), stream.str()); + + // string + stream.str(U("")); + json::value string = json::value::string(U("hehehe")); + VERIFY_ARE_EQUAL(U("\"hehehe\""), string.serialize()); + string.serialize(stream); + VERIFY_ARE_EQUAL(U("\"hehehe\""), stream.str()); + + // object - with values created from parsing + stream.str(U("")); + const utility::string_t strValue1(U("{ \"key\" : true }")); + const utility::string_t strValue2(U("{\"key\":true}")); + json::value obj1 = json::value::parse(strValue1); + VERIFY_ARE_EQUAL(strValue2, obj1.serialize()); + json::value obj2 = json::value::parse(strValue2); + VERIFY_ARE_EQUAL(strValue2, obj2.serialize()); + obj1.serialize(stream); + VERIFY_ARE_EQUAL(strValue2, stream.str()); + + // object - with values added + stream.str(U("")); + json::value obj3 = json::value::object(); + obj3[U("key")] = json::value(true); + VERIFY_ARE_EQUAL(strValue2, obj3.serialize()); + obj3.serialize(stream); + VERIFY_ARE_EQUAL(strValue2, stream.str()); + + // array + stream.str(U("")); + json::value arr = json::value::array(); + arr[0] = json::value::string(U("Here")); + arr[1] = json::value(true); + VERIFY_ARE_EQUAL(U("[\"Here\",true]"), arr.serialize()); + VERIFY_ARE_EQUAL(U("[\"Here\",true]"), arr.serialize()); + arr.serialize(stream); + VERIFY_ARE_EQUAL(U("[\"Here\",true]"), stream.str()); + } + + TEST(empty_arrays_objects) + { + // array + auto arr = json::value::parse(U("[ ]")); + VERIFY_ARE_EQUAL(U("[]"), arr.serialize()); + + // object + auto obj = json::value::parse(U("{ }")); + VERIFY_ARE_EQUAL(U("{}"), obj.serialize()); + } + + void verify_escaped_chars(const utility::string_t& str1, const utility::string_t& str2) + { + json::value j1 = json::value::string(str1); + VERIFY_ARE_EQUAL(str2, j1.serialize()); + } + + void verify_unescaped_chars(const utility::string_t& str1, const utility::string_t& str2) + { + json::value j1 = json::value::string(str1, false); + VERIFY_ARE_EQUAL(str2, j1.serialize()); + } + + TEST(to_string_escaped_chars) + { + verify_escaped_chars(U(" \" "), U("\" \\\" \"")); + verify_escaped_chars(U(" \b "), U("\" \\b \"")); + verify_escaped_chars(U(" \f "), U("\" \\f \"")); + verify_escaped_chars(U(" \n "), U("\" \\n \"")); + verify_escaped_chars(U(" \r "), U("\" \\r \"")); + verify_escaped_chars(U(" \t "), U("\" \\t \"")); + + json::value obj = json::value::object(); + obj[U(" \t ")] = json::value::string(U(" \b ")); + + json::value arr = json::value::array(); + arr[0] = json::value::string(U(" \f ")); + + VERIFY_ARE_EQUAL(U("{\" \\t \":\" \\b \"}"), obj.serialize()); + VERIFY_ARE_EQUAL(U("[\" \\f \"]"), arr.serialize()); + + utility::string_t str(U("{\"hello\":\" \\\"here's looking at you kid\\\" \\r \"}")); + json::value obj2 = json::value::parse(str); + + VERIFY_ARE_EQUAL(str, obj2.serialize()); + } + + TEST(to_string_unescaped_chars) + { + verify_unescaped_chars(U(" \" "), U("\" \" \"")); + verify_unescaped_chars(U(" \b "), U("\" \b \"")); + verify_unescaped_chars(U(" \f "), U("\" \f \"")); + verify_unescaped_chars(U(" \n "), U("\" \n \"")); + verify_unescaped_chars(U(" \r "), U("\" \r \"")); + verify_unescaped_chars(U(" \t "), U("\" \t \"")); + + json::value obj = json::value::object(); + obj[U(" \t ")] = json::value::string(U(" \b "), false); + + json::value arr = json::value::array(); + arr[0] = json::value::string(U(" \f "), false); + + VERIFY_ARE_EQUAL(U("{\" \\t \":\" \b \"}"), obj.serialize()); + VERIFY_ARE_EQUAL(U("[\" \f \"]"), arr.serialize()); + } + + TEST(as_string) + { + json::value b(false); + VERIFY_THROWS(b.as_string(), json::json_exception); + VERIFY_THROWS(b.as_string(), json::json_exception); + + utility::string_t data(U("HERE IS A STRING")); + utility::string_t wdata(data.begin(), data.end()); + json::value str = json::value::string(data); + VERIFY_ARE_EQUAL(data, str.as_string()); + VERIFY_ARE_EQUAL(wdata, str.as_string()); + } + + TEST(as_copy_constructor) + { + auto arr = json::value::array(); + arr[0] = json::value::number(44); + arr[1] = json::value::string(U("abc")); + json::array arrCopy = arr.as_array(); + VERIFY_ARE_EQUAL(2, arrCopy.size()); + VERIFY_ARE_EQUAL(2, arr.size()); + VERIFY_ARE_EQUAL(44, arrCopy[0].as_integer()); + VERIFY_ARE_EQUAL(U("abc"), arrCopy[1].as_string()); + VERIFY_ARE_EQUAL(44, arr[0].as_integer()); + VERIFY_ARE_EQUAL(U("abc"), arr[1].as_string()); + + auto obj = json::value::object(); + obj[U("abc")] = json::value::number(123); + json::object objCopy = obj.as_object(); + VERIFY_ARE_EQUAL(1, objCopy.size()); + VERIFY_ARE_EQUAL(1, obj.size()); + VERIFY_ARE_EQUAL(123, objCopy[U("abc")].as_integer()); + VERIFY_ARE_EQUAL(123, obj[U("abc")].as_integer()); + + auto num = json::value::number(44); + json::number numCopy = num.as_number(); + VERIFY_ARE_EQUAL(44, num.as_integer()); + VERIFY_ARE_EQUAL(44, numCopy.to_int32()); + } + + TEST(as_bool_as_double_as_string) + { + utility::stringstream_t ss1; + ss1 << U("17"); + json::value v1 = json::value::parse(ss1); + + utility::stringstream_t ss2; + ss2 << U("3.1415"); + json::value v2 = json::value::parse(ss2); + + utility::stringstream_t ss3; + ss3 << U("true"); + json::value v3 = json::value::parse(ss3); + + utility::stringstream_t ss4; + ss4 << U("\"Hello!\""); + json::value v4 = json::value::parse(ss4); + + utility::stringstream_t ss8; + ss8 << U("{ \"a\" : 10, \"b\" : 4711.17, \"c\" : false }"); + json::value v8 = json::value::parse(ss8); + + utility::stringstream_t ss9; + ss9 << U("[1,2,3,true]"); + json::value v9 = json::value::parse(ss9); + + VERIFY_ARE_EQUAL(v1.as_double(), 17); + VERIFY_ARE_EQUAL(v2.as_double(), 3.1415); + VERIFY_IS_TRUE(v3.as_bool()); + VERIFY_ARE_EQUAL(v4.as_string(), U("Hello!")); + VERIFY_ARE_EQUAL(v4.as_string(), U("Hello!")); + + VERIFY_ARE_EQUAL(v8[U("a")].as_double(), 10); + VERIFY_ARE_EQUAL(v8[U("b")].as_double(), 4711.17); + VERIFY_ARE_EQUAL(v8[U("a")].as_integer(), 10); + VERIFY_IS_FALSE(v8[U("c")].as_bool()); + + VERIFY_ARE_EQUAL(v9[0].as_double(), 1); + VERIFY_ARE_EQUAL(v9[1].as_double(), 2); + VERIFY_ARE_EQUAL(v9[2].as_double(), 3); + VERIFY_IS_TRUE(v9[3].as_bool()); + } + + TEST(to_stream_operator) + { + utility::string_t str(U("\"JSON STRING\"")); + json::value value = json::value::parse(str); + utility::stringstream_t stream; + stream << value; + VERIFY_ARE_EQUAL(str, stream.str()); + } + + TEST(from_stream_operator) + { + utility::string_t str(U("\"JSON STRING!\"")); + utility::stringstream_t stream; + stream << str; + json::value value; + stream >> value; + VERIFY_IS_TRUE(value.is_string()); + VERIFY_ARE_EQUAL(str, value.serialize()); + } + + TEST(negative_is_tests) + { + json::value b(true); + json::value str(U("string")); + json::value d(22.5); + json::value n; + json::value a = json::value::array(2); + json::value o = json::value::object(); + + VERIFY_IS_FALSE(b.is_number()); + VERIFY_IS_FALSE(str.is_boolean()); + VERIFY_IS_FALSE(d.is_string()); + VERIFY_IS_FALSE(a.is_object()); + VERIFY_IS_FALSE(o.is_array()); + VERIFY_IS_FALSE(n.is_string()); + VERIFY_IS_FALSE(str.is_null()); + } + + TEST(negative_index_operator_boolean) + { + json::value v = json::value::boolean(true); + + VERIFY_THROWS(v[0], json::json_exception); + VERIFY_THROWS(v[U("H")], json::json_exception); + VERIFY_THROWS(v[U("A")], json::json_exception); + } + + TEST(negative_get_field_object) + { + json::value v; + + v[U("a")] = json::value::number(1); + VERIFY_IS_TRUE(v.is_object()); + VERIFY_ARE_EQUAL(v[U("a")].as_integer(), 1); + VERIFY_IS_TRUE(v[U("b")].is_null()); + VERIFY_THROWS(v[0], json::json_exception); + } + + TEST(negative_get_element_array) + { + json::value v; + + v[0] = json::value::number(1); + VERIFY_ARE_EQUAL(v[0].as_integer(), 1); + VERIFY_IS_TRUE(v[1].is_null()); + VERIFY_THROWS(v[U("a")], json::json_exception); + } + + TEST(has_field_object) + { + json::value v1; + + v1[U("a")] = json::value::number(1); + v1[U("b")] = json::value::boolean(true); + v1[U("c")] = json::value::string(U("a string")); + v1[U("d")] = json::value::array({}); + json::value sub_field; + sub_field[U("x")] = json::value::number(1); + v1[U("e")] = sub_field; + + VERIFY_IS_TRUE(v1.has_field(U("a"))); + VERIFY_IS_TRUE(v1.has_field(U("b"))); + VERIFY_IS_TRUE(v1.has_field(U("c"))); + VERIFY_IS_TRUE(v1.has_field(U("d"))); + VERIFY_IS_TRUE(v1.has_field(U("e"))); + VERIFY_IS_FALSE(v1.has_field(U("f"))); + + VERIFY_IS_TRUE(v1.has_number_field(U("a"))); + VERIFY_IS_TRUE(v1.has_integer_field(U("a"))); + VERIFY_IS_FALSE(v1.has_double_field(U("a"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("a"))); + VERIFY_IS_FALSE(v1.has_string_field(U("a"))); + VERIFY_IS_FALSE(v1.has_array_field(U("a"))); + VERIFY_IS_FALSE(v1.has_object_field(U("a"))); + + VERIFY_IS_TRUE(v1.has_boolean_field(U("b"))); + VERIFY_IS_FALSE(v1.has_number_field(U("b"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("b"))); + VERIFY_IS_FALSE(v1.has_double_field(U("b"))); + VERIFY_IS_FALSE(v1.has_string_field(U("b"))); + VERIFY_IS_FALSE(v1.has_array_field(U("b"))); + VERIFY_IS_FALSE(v1.has_object_field(U("b"))); + + VERIFY_IS_TRUE(v1.has_string_field(U("c"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("c"))); + VERIFY_IS_FALSE(v1.has_number_field(U("c"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("c"))); + VERIFY_IS_FALSE(v1.has_double_field(U("c"))); + VERIFY_IS_FALSE(v1.has_array_field(U("c"))); + VERIFY_IS_FALSE(v1.has_object_field(U("c"))); + + VERIFY_IS_TRUE(v1.has_array_field(U("d"))); + VERIFY_IS_FALSE(v1.has_string_field(U("d"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("d"))); + VERIFY_IS_FALSE(v1.has_number_field(U("d"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("d"))); + VERIFY_IS_FALSE(v1.has_double_field(U("d"))); + VERIFY_IS_FALSE(v1.has_object_field(U("d"))); + + VERIFY_IS_TRUE(v1.has_object_field(U("e"))); + VERIFY_IS_FALSE(v1.has_array_field(U("e"))); + VERIFY_IS_FALSE(v1.has_string_field(U("e"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("e"))); + VERIFY_IS_FALSE(v1.has_number_field(U("e"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("e"))); + VERIFY_IS_FALSE(v1.has_double_field(U("e"))); + + json::value v2; + + v2[0] = json::value::number(1); + VERIFY_IS_FALSE(v2.has_field(U("0"))); + VERIFY_IS_FALSE(v2.has_field(U("b"))); + } + + TEST(negative_as_tests) + { + json::value b(true); + VERIFY_THROWS(b.as_double(), json::json_exception); + VERIFY_THROWS(b.as_integer(), json::json_exception); + VERIFY_THROWS(b.as_string(), json::json_exception); + + json::value str = json::value::string(U("string")); + VERIFY_THROWS(str.as_double(), json::json_exception); + VERIFY_THROWS(str.as_bool(), json::json_exception); + VERIFY_THROWS(str.as_integer(), json::json_exception); + + json::value d(2.0f); + VERIFY_THROWS(d.as_string(), json::json_exception); + VERIFY_THROWS(d.as_bool(), json::json_exception); + + json::value i(11); + VERIFY_THROWS(i.as_bool(), json::json_exception); + VERIFY_THROWS(i.as_string(), json::json_exception); + } + + TEST(erase_array_index) + { + json::value a = json::value::array(4); + a[0] = json::value(1); + a[1] = json::value(2); + a[2] = json::value(3); + a[3] = json::value(4); + + a.erase(1); + VERIFY_ARE_EQUAL(3, a.size()); + VERIFY_ARE_EQUAL(1, a[0].as_integer()); + VERIFY_ARE_EQUAL(3, a[1].as_integer()); + VERIFY_ARE_EQUAL(4, a[2].as_integer()); + a.as_array().erase(2); + VERIFY_ARE_EQUAL(2, a.size()); + VERIFY_ARE_EQUAL(1, a[0].as_integer()); + VERIFY_ARE_EQUAL(3, a[1].as_integer()); + } + + TEST(erase_array_iter) + { + json::value a = json::value::array(3); + a[0] = json::value(1); + a[1] = json::value(2); + a[2] = json::value(3); + + auto iter = a.as_array().begin() + 1; + auto afterLoc = a.as_array().erase(iter); + VERIFY_ARE_EQUAL(3, afterLoc->as_integer()); + VERIFY_ARE_EQUAL(2, a.size()); + VERIFY_ARE_EQUAL(1, a[0].as_integer()); + VERIFY_ARE_EQUAL(3, a[1].as_integer()); + + iter = a.as_array().begin() + 1; + afterLoc = a.as_array().erase(iter); + VERIFY_ARE_EQUAL(a.as_array().end(), afterLoc); + VERIFY_ARE_EQUAL(1, a.size()); + VERIFY_ARE_EQUAL(1, a[0].as_integer()); + } + + TEST(erase_object_key) + { + auto o = json::value::object(); + o[U("a")] = json::value(1); + o[U("b")] = json::value(2); + o[U("c")] = json::value(3); + o[U("d")] = json::value(4); + + o.erase(U("a")); + VERIFY_ARE_EQUAL(3, o.size()); + VERIFY_ARE_EQUAL(2, o[U("b")].as_integer()); + VERIFY_ARE_EQUAL(3, o[U("c")].as_integer()); + VERIFY_ARE_EQUAL(4, o[U("d")].as_integer()); + + o.as_object().erase(U("d")); + VERIFY_ARE_EQUAL(2, o.size()); + VERIFY_ARE_EQUAL(2, o[U("b")].as_integer()); + VERIFY_ARE_EQUAL(3, o[U("c")].as_integer()); + } + + TEST(erase_object_iter) + { + auto o = json::value::object(); + o[U("a")] = json::value(1); + o[U("b")] = json::value(2); + o[U("c")] = json::value(3); + o[U("d")] = json::value(4); + + auto iter = o.as_object().begin() + 1; + auto afterLoc = o.as_object().erase(iter); + VERIFY_ARE_EQUAL(3, o.size()); + VERIFY_ARE_EQUAL(3, afterLoc->second.as_integer()); + VERIFY_ARE_EQUAL(1, o[U("a")].as_integer()); + VERIFY_ARE_EQUAL(3, o[U("c")].as_integer()); + VERIFY_ARE_EQUAL(4, o[U("d")].as_integer()); + + iter = o.as_object().begin() + 2; + afterLoc = o.as_object().erase(iter); + VERIFY_ARE_EQUAL(2, o.size()); + VERIFY_ARE_EQUAL(o.as_object().end(), afterLoc); + VERIFY_ARE_EQUAL(1, o[U("a")].as_integer()); + VERIFY_ARE_EQUAL(3, o[U("c")].as_integer()); + } + + TEST(floating_number_serialize) + { + // This number will have the longest serializaton possible (lenght of the string): + // Sign, exponent, decimal comma, longest mantisa and exponent make so. + auto value = json::value(-3.123456789012345678901234567890E-123); + + // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + const auto len = std::numeric_limits::digits10 + 9; + + // Check narrow string implementation + std::stringstream ss; + value.serialize(ss); + VERIFY_ARE_EQUAL(len, ss.str().length()); #ifdef _WIN32 - // Check wide string implementation - std::basic_stringstream wss; - value.serialize(wss); - VERIFY_ARE_EQUAL(len, wss.str().length()); + // Check wide string implementation + std::basic_stringstream wss; + value.serialize(wss); + VERIFY_ARE_EQUAL(len, wss.str().length()); #endif -} + } } // SUITE(to_as_and_operators_tests) -}}} +} // namespace json_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/misc/atl_headers/Resource.h b/Release/tests/functional/misc/atl_headers/Resource.h index d7da822d9c..4ab6fffa8b 100644 --- a/Release/tests/functional/misc/atl_headers/Resource.h +++ b/Release/tests/functional/misc/atl_headers/Resource.h @@ -3,15 +3,15 @@ // Used by header_test.rc // -#define IDS_APP_TITLE 103 +#define IDS_APP_TITLE 103 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/Release/tests/functional/misc/atl_headers/header_test1.cpp b/Release/tests/functional/misc/atl_headers/header_test1.cpp index 8b2ba93443..46d54ff2e3 100644 --- a/Release/tests/functional/misc/atl_headers/header_test1.cpp +++ b/Release/tests/functional/misc/atl_headers/header_test1.cpp @@ -1,62 +1,63 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests to include headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests to include headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ // Include ATL headers before casablanca headers -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #define NOMINMAX -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit #ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers #endif // These MFC headers are not code analysis clean. #pragma warning(push) #pragma warning(disable : 6387) #include -#include // MFC core and standard components -#include // MFC extensions +#include // MFC extensions +#include // MFC core and standard components #ifndef _AFX_NO_OLE_SUPPORT -#include // MFC support for Internet Explorer 4 Common Controls +#include // MFC support for Internet Explorer 4 Common Controls #endif #ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT #pragma warning(pop) #include // Windows Header Files: #include - -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -#include -#include +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit #include "cpprest/http_client.h" - #include "unittestpp.h" +#include +#include -namespace tests { namespace functional { namespace misc { namespace atl_headers { - -SUITE(header_test1) +namespace tests { - -TEST(HeaderTest) +namespace functional +{ +namespace misc +{ +namespace atl_headers { - web::http::client::http_client client(U("http://www.cnn.com")); -} +SUITE(header_test1) +{ + TEST(HeaderTest) { web::http::client::http_client client(U("http://www.cnn.com")); } } // SUITE(header_test1) -}}}} - +} // namespace atl_headers +} // namespace misc +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/misc/atl_headers/header_test2.cpp b/Release/tests/functional/misc/atl_headers/header_test2.cpp index a24ba3d8cc..91cf63fbc6 100644 --- a/Release/tests/functional/misc/atl_headers/header_test2.cpp +++ b/Release/tests/functional/misc/atl_headers/header_test2.cpp @@ -1,62 +1,64 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests to include headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests to include headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #define NOMINMAX #include "cpprest/http_client.h" // Include ATL headers after casablanca headers -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit #ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers #endif // These MFC headers are not code analysis clean. #pragma warning(push) #pragma warning(disable : 6387) #include -#include // MFC core and standard components -#include // MFC extensions +#include // MFC extensions +#include // MFC core and standard components #ifndef _AFX_NO_OLE_SUPPORT -#include // MFC support for Internet Explorer 4 Common Controls +#include // MFC support for Internet Explorer 4 Common Controls #endif #ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT #pragma warning(pop) #include // Windows Header Files: #include +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - +#include "unittestpp.h" #include #include -#include "unittestpp.h" - -namespace tests { namespace functional { namespace misc { namespace atl_headers { - -SUITE(header_test2) +namespace tests { - -TEST(HeaderTest) +namespace functional +{ +namespace misc +{ +namespace atl_headers { - web::http::client::http_client client(U("http://www.cnn.com")); -} +SUITE(header_test2) +{ + TEST(HeaderTest) { web::http::client::http_client client(U("http://www.cnn.com")); } } // SUITE(header_test2) -}}}} - +} // namespace atl_headers +} // namespace misc +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp b/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp index 8dea473918..82b10a7b41 100644 --- a/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp +++ b/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests for PPLX operations. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests for PPLX operations. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,12 +20,9 @@ class pplx_dflt_scheduler : public pplx::scheduler_interface struct _Scheduler_Param { pplx::TaskProc_t m_proc; - void * m_param; + void* m_param; - _Scheduler_Param(pplx::TaskProc_t proc, void * param) - : m_proc(proc), m_param(param) - { - } + _Scheduler_Param(pplx::TaskProc_t proc, void* param) : m_proc(proc), m_param(param) {} }; static void CALLBACK DefaultWorkCallbackTest(PTP_CALLBACK_INSTANCE, PVOID pContext, PTP_WORK) @@ -55,10 +52,8 @@ class pplx_dflt_scheduler : public pplx::scheduler_interface #else class pplx_dflt_scheduler : public pplx::scheduler_interface { - std::unique_ptr m_pool; - virtual void schedule(pplx::TaskProc_t proc, void* param) { pplx::details::atomic_increment(s_flag); @@ -70,307 +65,297 @@ class pplx_dflt_scheduler : public pplx::scheduler_interface }; #endif -namespace tests { namespace functional { namespace pplx_tests { - +namespace tests +{ +namespace functional +{ +namespace pplx_tests +{ SUITE(pplx_op_tests) { + TEST(task_from_value) + { + auto val = pplx::task_from_result(17); -TEST(task_from_value) -{ - auto val = pplx::task_from_result(17); + VERIFY_ARE_EQUAL(val.get(), 17); + } - VERIFY_ARE_EQUAL(val.get(), 17); -} + TEST(task_from_value_with_continuation) + { + auto val = pplx::task_from_result(17); -TEST(task_from_value_with_continuation) -{ - auto val = pplx::task_from_result(17); + int v = 0; - int v = 0; + auto t = val.then([&](int x) { v = x; }); + t.wait(); - auto t = val.then([&](int x) { v = x; }); - t.wait(); + VERIFY_ARE_EQUAL(v, 17); + } - VERIFY_ARE_EQUAL(v, 17); -} + TEST(create_task) + { + auto val = pplx::create_task([]() { return 17; }); -TEST(create_task) -{ - auto val = pplx::create_task([]() { return 17; }); + VERIFY_ARE_EQUAL(val.get(), 17); + } - VERIFY_ARE_EQUAL(val.get(), 17); -} + TEST(create_task_with_continuation) + { + auto val = pplx::create_task([]() { return 17; }); -TEST(create_task_with_continuation) -{ - auto val = pplx::create_task([]() { return 17; }); + int v = 0; - int v = 0; + auto t = val.then([&](int x) { v = x; }); + t.wait(); - auto t = val.then([&](int x) { v = x; }); - t.wait(); + VERIFY_ARE_EQUAL(v, 17); + } - VERIFY_ARE_EQUAL(v, 17); -} + TEST(task_from_event) + { + pplx::task_completion_event tce; + auto val = pplx::create_task(tce); + tce.set(17); -TEST(task_from_event) -{ - pplx::task_completion_event tce; - auto val = pplx::create_task(tce); - tce.set(17); + VERIFY_ARE_EQUAL(val.get(), 17); + } - VERIFY_ARE_EQUAL(val.get(), 17); -} + TEST(task_from_event_with_continuation) + { + pplx::task_completion_event tce; + auto val = pplx::create_task(tce); -TEST(task_from_event_with_continuation) -{ - pplx::task_completion_event tce; - auto val = pplx::create_task(tce); + int v = 0; - int v = 0; + auto t = val.then([&](int x) { v = x; }); - auto t = val.then( - [&](int x) { v = x; }); + tce.set(17); + t.wait(); - tce.set(17); - t.wait(); + VERIFY_ARE_EQUAL(v, 17); + } - VERIFY_ARE_EQUAL(v, 17); -} + TEST(task_from_event_is_done) + { + pplx::task_completion_event tce; + auto val = pplx::create_task(tce); -TEST(task_from_event_is_done) -{ - pplx::task_completion_event tce; - auto val = pplx::create_task(tce); + pplx::details::atomic_long v(0); - pplx::details::atomic_long v(0); + auto t = val.then([&](long x) { pplx::details::atomic_exchange(v, x); }); - auto t = val.then( - [&](long x) { pplx::details::atomic_exchange(v, x); }); + // The task should not have started yet. + bool isDone = t.is_done(); + VERIFY_ARE_EQUAL(isDone, false); - // The task should not have started yet. - bool isDone = t.is_done(); - VERIFY_ARE_EQUAL(isDone, false); + // Start the task + tce.set(17); - // Start the task - tce.set(17); + // Wait for the lambda to finish running + while (!t.is_done()) + { + // Yield. + } - // Wait for the lambda to finish running - while (!t.is_done()) - { - // Yield. - } + // Verify that the lambda did run + VERIFY_ARE_EQUAL(v, 17); - // Verify that the lambda did run - VERIFY_ARE_EQUAL(v, 17); + // Wait for the task. + t.wait(); - // Wait for the task. - t.wait(); + VERIFY_ARE_EQUAL(v, 17); + } - VERIFY_ARE_EQUAL(v, 17); -} + TEST(task_from_event_with_exception) + { + pplx::task_completion_event tce; + auto val = pplx::create_task(tce); -TEST(task_from_event_with_exception) -{ - pplx::task_completion_event tce; - auto val = pplx::create_task(tce); + pplx::details::atomic_long v(0); - pplx::details::atomic_long v(0); + auto t = val.then([&](long x) { pplx::details::atomic_exchange(v, x); }); - auto t = val.then( - [&](long x) { pplx::details::atomic_exchange(v, x); }); + // Start the task + tce.set_exception(pplx::invalid_operation()); - // Start the task - tce.set_exception(pplx::invalid_operation()); + // Wait for the lambda to finish running + while (!t.is_done()) + { + // Yield. + } - // Wait for the lambda to finish running - while (!t.is_done()) - { - // Yield. - } + // Verify that the lambda did run + VERIFY_ARE_EQUAL(v, 0); - // Verify that the lambda did run - VERIFY_ARE_EQUAL(v, 0); + // Wait for the task. + try + { + t.wait(); + } + catch (pplx::invalid_operation) + { + } + catch (std::exception_ptr) + { + v = 1; + } - // Wait for the task. - try - { - t.wait(); + VERIFY_ARE_EQUAL(v, 0); } - catch (pplx::invalid_operation) - { - } - catch(std::exception_ptr) + + TEST(schedule_task_hold_then_release) { - v = 1; - } + pplx::details::atomic_long flag(0); - VERIFY_ARE_EQUAL(v, 0); -} + pplx::task t1([&flag]() { + while (flag == 0) + ; + }); -TEST(schedule_task_hold_then_release) -{ - pplx::details::atomic_long flag(0); + pplx::details::atomic_exchange(flag, 1L); + t1.wait(); + } - pplx::task t1([&flag]() { - while (flag == 0); - }); + // TFS # 521911 + TEST(schedule_two_tasks) + { + pplx_dflt_scheduler sched; + pplx::details::atomic_exchange(s_flag, 0L); - pplx::details::atomic_exchange(flag, 1L); - t1.wait(); -} + auto nowork = []() {}; -// TFS # 521911 -TEST(schedule_two_tasks) -{ - pplx_dflt_scheduler sched; - pplx::details::atomic_exchange(s_flag, 0L); + auto defaultTask = pplx::create_task(nowork); + defaultTask.wait(); + VERIFY_ARE_EQUAL(s_flag, 0); - auto nowork = [](){}; + pplx::task_completion_event tce; + auto t = pplx::create_task(tce, sched); - auto defaultTask = pplx::create_task(nowork); - defaultTask.wait(); - VERIFY_ARE_EQUAL(s_flag, 0); + // 2 continuations to be scheduled on the scheduler. + // Note that task "t" is not scheduled. + auto t1 = t.then(nowork).then(nowork); - pplx::task_completion_event tce; - auto t = pplx::create_task(tce, sched); + tce.set(); + t1.wait(); - // 2 continuations to be scheduled on the scheduler. - // Note that task "t" is not scheduled. - auto t1 = t.then(nowork).then(nowork); + VERIFY_ARE_EQUAL(s_flag, 2); + } - tce.set(); - t1.wait(); + TEST(task_throws_exception) + { + pplx::extensibility::event_t ev; + bool caught = false; + + // Ensure that exceptions thrown from user lambda + // are indeed propagated and do not escape out of + // the task. + auto t1 = pplx::create_task([&ev]() { + ev.set(); + throw std::logic_error("Should not escape"); + }); - VERIFY_ARE_EQUAL(s_flag, 2); -} + auto t2 = t1.then([]() { VERIFY_IS_TRUE(false); }); -TEST(task_throws_exception) -{ - pplx::extensibility::event_t ev; - bool caught = false; + // Ensure that we do not inline the work on this thread + ev.wait(); - // Ensure that exceptions thrown from user lambda - // are indeed propagated and do not escape out of - // the task. - auto t1 = pplx::create_task([&ev]() - { - ev.set(); - throw std::logic_error("Should not escape"); - }); + try + { + t2.wait(); + } + catch (std::exception&) + { + caught = true; + } - auto t2 = t1.then([]() - { - VERIFY_IS_TRUE(false); - }); + VERIFY_IS_TRUE(caught); + } - // Ensure that we do not inline the work on this thread - ev.wait(); - - try + pplx::task make_unwrapped_task() { - t2.wait(); + pplx::task t1([]() { return 10; }); + + return pplx::task([t1]() { return t1; }); } - catch(std::exception&) + + TEST(unwrap_task) { - caught = true; + pplx::task t = make_unwrapped_task(); + int n = t.get(); + VERIFY_ARE_EQUAL(n, 10); } - VERIFY_IS_TRUE(caught); -} - -pplx::task make_unwrapped_task() -{ - pplx::task t1([]() { - return 10; - }); - - return pplx::task([t1]() { - return t1; - }); -} - -TEST(unwrap_task) -{ - pplx::task t = make_unwrapped_task(); - int n = t.get(); - VERIFY_ARE_EQUAL(n,10); -} - -TEST(task_from_event_with_tb_continuation) -{ - volatile long flag = 0; + TEST(task_from_event_with_tb_continuation) + { + volatile long flag = 0; - pplx::task_completion_event tce; - auto val = pplx::create_task(tce).then( - [=,&flag](pplx::task op) -> short - { + pplx::task_completion_event tce; + auto val = pplx::create_task(tce).then([=, &flag](pplx::task op) -> short { flag = 1; return (short)op.get(); }); - tce.set(17); + tce.set(17); - VERIFY_ARE_EQUAL(val.get(), 17); - VERIFY_ARE_EQUAL(flag, 1); -} - -class fcc_370010 -{ -public: - fcc_370010(pplx::task_completion_event op) : m_op(op) { } + VERIFY_ARE_EQUAL(val.get(), 17); + VERIFY_ARE_EQUAL(flag, 1); + } - virtual void on_closed(bool result) + class fcc_370010 { - m_op.set(result); + public: + fcc_370010(pplx::task_completion_event op) : m_op(op) {} + + virtual void on_closed(bool result) + { + m_op.set(result); #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor" #endif - delete this; + delete this; #if defined(__clang__) #pragma clang diagnostic pop #endif - } + } -private: - pplx::task_completion_event m_op; -}; + private: + pplx::task_completion_event m_op; + }; -TEST(BugRepro370010) -{ - auto result_tce = pplx::task_completion_event(); + TEST(BugRepro370010) + { + auto result_tce = pplx::task_completion_event(); - auto f = new fcc_370010(result_tce); + auto f = new fcc_370010(result_tce); - pplx::task dummy([f]() - { - f->on_closed(true); - }); + pplx::task dummy([f]() { f->on_closed(true); }); - auto result = pplx::task(result_tce); + auto result = pplx::task(result_tce); - VERIFY_IS_TRUE(result.get()); -} + VERIFY_IS_TRUE(result.get()); + } -TEST(event_set_reset_timeout, "Ignore", "785846") -{ - pplx::extensibility::event_t ev; + TEST(event_set_reset_timeout, "Ignore", "785846") + { + pplx::extensibility::event_t ev; - ev.set(); + ev.set(); - // Wait should succeed as the event was set above - VERIFY_IS_TRUE(ev.wait(0) == 0); + // Wait should succeed as the event was set above + VERIFY_IS_TRUE(ev.wait(0) == 0); - // wait should succeed as this is manual reset - VERIFY_IS_TRUE(ev.wait(0) == 0); + // wait should succeed as this is manual reset + VERIFY_IS_TRUE(ev.wait(0) == 0); - ev.reset(); + ev.reset(); - // wait should fail as the event is reset (not set) - VERIFY_IS_TRUE(ev.wait(0) == pplx::extensibility::event_t::timeout_infinite); -} + // wait should fail as the event is reset (not set) + VERIFY_IS_TRUE(ev.wait(0) == pplx::extensibility::event_t::timeout_infinite); + } } // SUITE(pplx_op_tests) -}}} // namespaces +} // namespace pplx_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/pplx/pplx_test/pplx_task_options.cpp b/Release/tests/functional/pplx/pplx_test/pplx_task_options.cpp index 85f9cd4a2c..983e9cc06e 100644 --- a/Release/tests/functional/pplx/pplx_test/pplx_task_options.cpp +++ b/Release/tests/functional/pplx/pplx_test/pplx_task_options.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests for PPLX task options. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests for PPLX task options. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -18,16 +18,13 @@ class direct_executor : public pplx::scheduler_interface { public: - virtual void schedule( concurrency::TaskProc_t proc, _In_ void* param) - { - proc(param); - } + virtual void schedule(concurrency::TaskProc_t proc, _In_ void* param) { proc(param); } }; static std::shared_ptr g_executor; std::shared_ptr __cdecl get_scheduler() { - if ( !g_executor) + if (!g_executor) { g_executor = std::make_shared(); } @@ -35,18 +32,13 @@ std::shared_ptr __cdecl get_scheduler() return g_executor; } #else -std::shared_ptr __cdecl get_scheduler() -{ - return pplx::get_ambient_scheduler(); -} +std::shared_ptr __cdecl get_scheduler() { return pplx::get_ambient_scheduler(); } #endif class TaskOptionsTestScheduler : public pplx::scheduler_interface { public: - TaskOptionsTestScheduler() : m_numTasks(0), m_scheduler(get_scheduler()) - { - } + TaskOptionsTestScheduler() : m_numTasks(0), m_scheduler(get_scheduler()) {} virtual void schedule(pplx::TaskProc_t proc, void* param) { @@ -54,18 +46,14 @@ class TaskOptionsTestScheduler : public pplx::scheduler_interface m_scheduler->schedule(proc, param); } - long get_num_tasks() - { - return m_numTasks; - } + long get_num_tasks() { return m_numTasks; } private: - pplx::details::atomic_long m_numTasks; pplx::scheduler_ptr m_scheduler; - TaskOptionsTestScheduler(const TaskOptionsTestScheduler &); - TaskOptionsTestScheduler & operator=(const TaskOptionsTestScheduler &); + TaskOptionsTestScheduler(const TaskOptionsTestScheduler&); + TaskOptionsTestScheduler& operator=(const TaskOptionsTestScheduler&); }; #if defined(_MSC_VER) @@ -75,16 +63,9 @@ class TaskOptionsTestScheduler : public pplx::scheduler_interface class CheckLifetimeScheduler : public pplx::scheduler_interface { public: + CheckLifetimeScheduler(pplx::extensibility::event_t& ev) : m_event(ev), m_numTasks(0) {} - CheckLifetimeScheduler(pplx::extensibility::event_t& ev) - : m_event(ev), m_numTasks(0) - { - } - - ~CheckLifetimeScheduler() - { - m_event.set(); - } + ~CheckLifetimeScheduler() { m_event.set(); } virtual void schedule(pplx::TaskProc_t proc, void* param) { @@ -92,10 +73,7 @@ class CheckLifetimeScheduler : public pplx::scheduler_interface get_scheduler()->schedule(proc, param); } - long get_num_tasks() - { - return m_numTasks; - } + long get_num_tasks() { return m_numTasks; } pplx::extensibility::event_t& m_event; pplx::details::atomic_long m_numTasks; @@ -104,348 +82,366 @@ class CheckLifetimeScheduler : public pplx::scheduler_interface #pragma warning(pop) #endif -namespace tests { namespace functional { namespace PPLX { - +namespace tests +{ +namespace functional +{ +namespace PPLX +{ SUITE(pplx_task_options_tests) { + TEST(voidtask_schedoption_test) + { + TaskOptionsTestScheduler sched; + long n = 0; -TEST(voidtask_schedoption_test) -{ - TaskOptionsTestScheduler sched; - long n=0; + auto t1 = pplx::create_task([&n]() { n++; }, sched); // run on sched + t1.wait(); - auto t1 = pplx::create_task([&n]() {n++;}, sched); // run on sched - t1.wait(); + VERIFY_ARE_EQUAL(sched.get_num_tasks(), n); + } - VERIFY_ARE_EQUAL(sched.get_num_tasks(), n); -} + TEST(task_schedoption_test) + { + TaskOptionsTestScheduler sched; + long n = 0; + + auto t1 = pplx::create_task( + [&n]() -> int { + n++; + return 1; + }, + sched); // run on sched + t1.wait(); + + VERIFY_ARE_EQUAL(sched.get_num_tasks(), n); + } -TEST(task_schedoption_test) -{ - TaskOptionsTestScheduler sched; - long n=0; + TEST(then_nooptions_test) + { + TaskOptionsTestScheduler sched; + long n = 0; - auto t1 = pplx::create_task([&n]() -> int {n++; return 1;}, sched); // run on sched - t1.wait(); + auto t1 = pplx::create_task([&n]() { n++; }, sched); + t1.then([&n]() { n++; }) // inherit sched + .then([&n]() { n++; }) + .wait(); - VERIFY_ARE_EQUAL(sched.get_num_tasks(), n); -} + VERIFY_ARE_EQUAL(sched.get_num_tasks(), n); + } -TEST(then_nooptions_test) -{ - TaskOptionsTestScheduler sched; - long n=0; + TEST(then_multiple_schedulers_test1) + { + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; - auto t1 = pplx::create_task([&n]() {n++;}, sched); - t1.then([&n](){n++;}) // inherit sched - .then([&n](){n++;}) - .wait(); + auto emptyFunc = []() {}; - VERIFY_ARE_EQUAL(sched.get_num_tasks(), n); -} + auto t1 = pplx::create_task(emptyFunc, sched1); // sched1 + t1.then(emptyFunc, sched2).wait(); // sched2 -TEST(then_multiple_schedulers_test1) -{ - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; - - auto emptyFunc = [](){}; + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), 1); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); + } - auto t1 = pplx::create_task(emptyFunc, sched1); // sched1 - t1.then(emptyFunc, sched2).wait(); // sched2 + TEST(then_multiple_schedulers_test2) + { + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), 1); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); -} + auto emptyFunc = []() {}; -TEST(then_multiple_schedulers_test2) -{ - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; - - auto emptyFunc = [](){}; - - auto t1 = pplx::create_task(emptyFunc, sched1); - t1.then(emptyFunc, sched2) - .then(emptyFunc) // inherit sched2 - .wait(); - - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), 1); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 2); -} + auto t1 = pplx::create_task(emptyFunc, sched1); + t1.then(emptyFunc, sched2) + .then(emptyFunc) // inherit sched2 + .wait(); -TEST(opand_nooptions_test) -{ - TaskOptionsTestScheduler sched; + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), 1); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 2); + } - auto t1 = pplx::create_task([]() {}, sched); - auto t2 = pplx::create_task([]() {}, sched); + TEST(opand_nooptions_test) + { + TaskOptionsTestScheduler sched; - auto t3 = t1 && t2; // Does not run on the scheduler - it should run inline - t3.then([](){}, sched).wait(); // run on sched - - VERIFY_ARE_EQUAL(sched.get_num_tasks(), 3); -} + auto t1 = pplx::create_task([]() {}, sched); + auto t2 = pplx::create_task([]() {}, sched); -TEST(whenall_nooptions_test) -{ - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; + auto t3 = t1 && t2; // Does not run on the scheduler - it should run inline + t3.then([]() {}, sched).wait(); // run on sched - std::vector> taskVect; - const int n = 10; - for (int i = 0; i < n; i++) - { - taskVect.push_back(pplx::create_task([]() {}, sched1)); + VERIFY_ARE_EQUAL(sched.get_num_tasks(), 3); } - auto t3 = pplx::when_all(begin(taskVect), end(taskVect)); // Does not run on the scheduler - it should run inline - t3.then([](){}, sched2).wait(); // run on sched2 - - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); -} - -TEST(whenall_options_test1) -{ - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; - - std::vector> taskVect; - const int n = 10; - for (int i = 0; i < n; i++) + TEST(whenall_nooptions_test) { - taskVect.push_back(pplx::create_task([]() {}, sched1)); + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; + + std::vector> taskVect; + const int n = 10; + for (int i = 0; i < n; i++) + { + taskVect.push_back(pplx::create_task([]() {}, sched1)); + } + + auto t3 = + pplx::when_all(begin(taskVect), end(taskVect)); // Does not run on the scheduler - it should run inline + t3.then([]() {}, sched2).wait(); // run on sched2 + + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); } - auto t3 = pplx::when_all(begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline - t3.then([](){}).wait(); // run on sched2 (inherits from the when_all task - - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); -} - -TEST(whenall_options_test2) -{ - // Same as the above test but use task to instatinate those templates - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; - - std::vector> taskVect; - const int n = 10; - for (int i = 0; i < n; i++) + TEST(whenall_options_test1) { - taskVect.push_back(pplx::create_task([i]() ->int { return i;}, sched1)); + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; + + std::vector> taskVect; + const int n = 10; + for (int i = 0; i < n; i++) + { + taskVect.push_back(pplx::create_task([]() {}, sched1)); + } + + auto t3 = pplx::when_all( + begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline + t3.then([]() {}).wait(); // run on sched2 (inherits from the when_all task + + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); } - auto t3 = pplx::when_all(begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline - t3.then([](std::vector){}).wait(); // run on sched2 (inherits from the when_all task - - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); -} - -TEST(whenall_options_test3) -{ - // Same as the above test but use multiple when_all - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; - - std::vector> taskVect; - const int n = 10; - for (int i = 0; i < n; i++) + TEST(whenall_options_test2) { - taskVect.push_back(pplx::create_task([i]() ->int { return i;}, sched1)); + // Same as the above test but use task to instatinate those templates + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; + + std::vector> taskVect; + const int n = 10; + for (int i = 0; i < n; i++) + { + taskVect.push_back(pplx::create_task([i]() -> int { return i; }, sched1)); + } + + auto t3 = pplx::when_all( + begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline + t3.then([](std::vector) {}).wait(); // run on sched2 (inherits from the when_all task + + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); } - - auto t2 = pplx::create_task([]()->int { return 0;}, sched1); - auto t3 = pplx::when_all(begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline + TEST(whenall_options_test3) + { + // Same as the above test but use multiple when_all + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; - auto t4 = t2 && t3; - t4.then([](std::vector){}).wait(); // run on default scheduler as the operator && breaks the chain of inheritance - - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n+1); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 0); -} + std::vector> taskVect; + const int n = 10; + for (int i = 0; i < n; i++) + { + taskVect.push_back(pplx::create_task([i]() -> int { return i; }, sched1)); + } -TEST(opor_nooptions_test) -{ - TaskOptionsTestScheduler sched; + auto t2 = pplx::create_task([]() -> int { return 0; }, sched1); - auto t1 = pplx::create_task([]() {}, sched); - auto t2 = pplx::create_task([]() {}, sched); + auto t3 = pplx::when_all( + begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline - auto t3 = t1 || t2; // Runs inline - t3.then([](){}, sched).wait(); - - VERIFY_ARE_EQUAL(sched.get_num_tasks(), 3); -} + auto t4 = t2 && t3; + t4.then([](std::vector) {}) + .wait(); // run on default scheduler as the operator && breaks the chain of inheritance -TEST(whenany_nooptions_test) -{ - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n + 1); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 0); + } - std::vector> taskVect; - const int n = 10; - for (int i = 0; i < n; i++) + TEST(opor_nooptions_test) { - taskVect.push_back(pplx::create_task([]() {}, sched1)); - } + TaskOptionsTestScheduler sched; - auto t3 = pplx::when_any(begin(taskVect), end(taskVect)); // Does not run on the scheduler - it should run inline - t3.then([](size_t){}, sched2).wait(); // run on sched2 - - // Do a whenall to wait for all the tasks - pplx::when_all(begin(taskVect), end(taskVect)).wait(); + auto t1 = pplx::create_task([]() {}, sched); + auto t2 = pplx::create_task([]() {}, sched); - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); -} + auto t3 = t1 || t2; // Runs inline + t3.then([]() {}, sched).wait(); -TEST(whenany_options_test1) -{ - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; + VERIFY_ARE_EQUAL(sched.get_num_tasks(), 3); + } - std::vector> taskVect; - const int n = 10; - for (int i = 0; i < n; i++) + TEST(whenany_nooptions_test) { - taskVect.push_back(pplx::create_task([]() {}, sched1)); - } + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; - auto t3 = pplx::when_any(begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline - t3.then([](size_t){}).wait(); // run on sched2 (inherits from the when_all task - - // Do a whenall to wait for all the tasks - pplx::when_all(begin(taskVect), end(taskVect)).wait(); + std::vector> taskVect; + const int n = 10; + for (int i = 0; i < n; i++) + { + taskVect.push_back(pplx::create_task([]() {}, sched1)); + } - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); -} + auto t3 = + pplx::when_any(begin(taskVect), end(taskVect)); // Does not run on the scheduler - it should run inline + t3.then([](size_t) {}, sched2).wait(); // run on sched2 -TEST(whenany_options_test2) -{ - // Same as whenany_options_test1 except that we instantiate a different set of template functions - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; + // Do a whenall to wait for all the tasks + pplx::when_all(begin(taskVect), end(taskVect)).wait(); - std::vector> taskVect; - const int n = 10; - for (int i = 0; i < n; i++) - { - taskVect.push_back(pplx::create_task([]() -> int {return 0;}, sched1)); + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); } - auto t3 = pplx::when_any(begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline - t3.then([](std::pair){}).wait(); // run on sched2 (inherits from the when_all task - - // Do a whenall to wait for all the tasks - pplx::when_all(begin(taskVect), end(taskVect)).wait(); + TEST(whenany_options_test1) + { + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); -} + std::vector> taskVect; + const int n = 10; + for (int i = 0; i < n; i++) + { + taskVect.push_back(pplx::create_task([]() {}, sched1)); + } -TEST(tce_nooptions_test) -{ - TaskOptionsTestScheduler sched; - TaskOptionsTestScheduler sched1; - TaskOptionsTestScheduler sched2; + auto t3 = pplx::when_any( + begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline + t3.then([](size_t) {}).wait(); // run on sched2 (inherits from the when_all task + + // Do a whenall to wait for all the tasks + pplx::when_all(begin(taskVect), end(taskVect)).wait(); - pplx::task_completion_event tce; - auto t1 = pplx::create_task(tce, sched1); - auto t2 = pplx::create_task(tce, sched2); + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); + } - tce.set(); - t1.wait(); - t2.wait(); - - // There is nothing to execute - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), 0); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 0); + TEST(whenany_options_test2) + { + // Same as whenany_options_test1 except that we instantiate a different set of template functions + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; + + std::vector> taskVect; + const int n = 10; + for (int i = 0; i < n; i++) + { + taskVect.push_back(pplx::create_task([]() -> int { return 0; }, sched1)); + } + + auto t3 = pplx::when_any( + begin(taskVect), end(taskVect), sched2); // Does not run on the scheduler - it should run inline + t3.then([](std::pair) {}).wait(); // run on sched2 (inherits from the when_all task + + // Do a whenall to wait for all the tasks + pplx::when_all(begin(taskVect), end(taskVect)).wait(); + + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), n); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); + } - auto emptyFunc = [](){}; + TEST(tce_nooptions_test) + { + TaskOptionsTestScheduler sched; + TaskOptionsTestScheduler sched1; + TaskOptionsTestScheduler sched2; - auto t3 = t1.then(emptyFunc); - auto t4 = t2.then(emptyFunc); + pplx::task_completion_event tce; + auto t1 = pplx::create_task(tce, sched1); + auto t2 = pplx::create_task(tce, sched2); - t3.wait(); - t4.wait(); + tce.set(); + t1.wait(); + t2.wait(); - VERIFY_ARE_EQUAL(sched1.get_num_tasks(), 1); - VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); -} + // There is nothing to execute + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), 0); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 0); -TEST(fromresult_options_test) -{ - TaskOptionsTestScheduler sched; + auto emptyFunc = []() {}; - int value = 10; - auto t1 = pplx::task_from_result(value); - t1.wait(); - VERIFY_ARE_EQUAL(sched.get_num_tasks(), 0); + auto t3 = t1.then(emptyFunc); + auto t4 = t2.then(emptyFunc); - t1.then([](int i) -> int {return i;}, sched).wait(); - VERIFY_ARE_EQUAL(sched.get_num_tasks(), 1); + t3.wait(); + t4.wait(); -} + VERIFY_ARE_EQUAL(sched1.get_num_tasks(), 1); + VERIFY_ARE_EQUAL(sched2.get_num_tasks(), 1); + } -TEST(scheduler_lifetime) -{ - pplx::extensibility::event_t ev; + TEST(fromresult_options_test) { - auto sched = std::make_shared(ev); + TaskOptionsTestScheduler sched; - pplx::create_task([]() {}, sched) // runs on sched (1) - .then([](){}) // runs on sched (2) - .wait(); + int value = 10; + auto t1 = pplx::task_from_result(value); + t1.wait(); + VERIFY_ARE_EQUAL(sched.get_num_tasks(), 0); - VERIFY_ARE_EQUAL(sched->get_num_tasks(), 2); + t1.then([](int i) -> int { return i; }, sched).wait(); + VERIFY_ARE_EQUAL(sched.get_num_tasks(), 1); } - ev.wait(); -} - -TEST(scheduler_lifetime_mixed) -{ - pplx::extensibility::event_t ev; - auto t = pplx::create_task([](){}); // use default scheduler + TEST(scheduler_lifetime) { - auto sched = std::make_shared(ev); + pplx::extensibility::event_t ev; + { + auto sched = std::make_shared(ev); - t.then([]() {}, sched) // (1) - .then([](){}) // (2) - .wait(); + pplx::create_task([]() {}, sched) // runs on sched (1) + .then([]() {}) // runs on sched (2) + .wait(); - VERIFY_ARE_EQUAL(sched->get_num_tasks(), 2); - } + VERIFY_ARE_EQUAL(sched->get_num_tasks(), 2); + } - ev.wait(); -} + ev.wait(); + } -TEST(scheduler_lifetime_nested) -{ - pplx::extensibility::event_t ev; - auto t = pplx::create_task([](){}); // use default scheduler + TEST(scheduler_lifetime_mixed) { - auto sched = std::make_shared(ev); + pplx::extensibility::event_t ev; + auto t = pplx::create_task([]() {}); // use default scheduler + { + auto sched = std::make_shared(ev); + + t.then([]() {}, sched) // (1) + .then([]() {}) // (2) + .wait(); - t.then([]() {}, sched) // custom scheduler (1) - .then([sched]() - { - // We are on the default scheduler - pplx::create_task([](){}, sched); // run on custom scheduler (2) - }, t.scheduler()) - .wait(); + VERIFY_ARE_EQUAL(sched->get_num_tasks(), 2); + } - VERIFY_ARE_EQUAL(sched->get_num_tasks(), 2); + ev.wait(); } - ev.wait(); -} + TEST(scheduler_lifetime_nested) + { + pplx::extensibility::event_t ev; + auto t = pplx::create_task([]() {}); // use default scheduler + { + auto sched = std::make_shared(ev); + + t.then([]() {}, sched) // custom scheduler (1) + .then( + [sched]() { + // We are on the default scheduler + pplx::create_task([]() {}, sched); // run on custom scheduler (2) + }, + t.scheduler()) + .wait(); + + VERIFY_ARE_EQUAL(sched->get_num_tasks(), 2); + } + + ev.wait(); + } } // SUITE(pplx_task_options_tests) -}}} // namespaces +} // namespace PPLX +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp b/Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp index 7f4f247f1b..7c61982420 100644 --- a/Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp +++ b/Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp @@ -1,1959 +1,1898 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests for PPLX operations -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests for PPLX operations + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace ::pplx; using namespace ::tests::common::utilities; -namespace tests { namespace functional { namespace PPLX { +namespace tests +{ +namespace functional +{ +namespace PPLX +{ +static void IsTrue(bool condition, const wchar_t*, ...) { VERIFY_IS_TRUE(condition); } -static void IsTrue(bool condition, const wchar_t *, ...) +static void IsFalse(bool condition, ...) { VERIFY_IS_TRUE(condition == false); } + +static void LogFailure(const wchar_t* msg, ...) { - VERIFY_IS_TRUE(condition); + wprintf(L"%s", msg); + VERIFY_IS_TRUE(false); } -static void IsFalse(bool condition, ...) +namespace helpers +{ +static int FibSerial(int n) { - VERIFY_IS_TRUE(condition == false); + if (n < 2) return n; + + return FibSerial(n - 1) + FibSerial(n - 2); } -static void LogFailure(const wchar_t * msg, ...) +static void DoRandomParallelWork() { - wprintf(L"%s", msg); - VERIFY_IS_TRUE(false); + int param = (rand() % 8) + 20; + // Calculate fib in serial + volatile int val = FibSerial(param); + val; } -namespace helpers +template +bool VerifyException(task<_T>& task) { - static int FibSerial(int n) - { - if (n < 2) return n; + bool gotException = true; + bool wrongException = false; - return FibSerial(n - 1) + FibSerial(n - 2); + try + { + task.get(); + gotException = false; } - - static void DoRandomParallelWork() + catch (const _EX&) { - int param = (rand() % 8) + 20; - // Calculate fib in serial - volatile int val = FibSerial(param); - val; } - - template - bool VerifyException(task<_T> &task) + catch (...) { - bool gotException = true; - bool wrongException = false; + wrongException = true; + } - try - { - task.get(); - gotException = false; - } - catch(const _EX&) - { - } - catch(...) - { - wrongException = true; - } + return (gotException && !wrongException); +} - return (gotException && !wrongException); +template +bool VerifyNoException(task<_T>& task) +{ + try + { + task.get(); } + catch (...) + { + return false; + } + return true; +} - template - bool VerifyNoException(task<_T> &task) +template +bool VerifyCanceled(task<_T>& task) +{ + try + { + task.get(); + } + catch (task_canceled&) { - try - { - task.get(); - } - catch(...) - { - return false; - } return true; } - - template - bool VerifyCanceled(task<_T> &task) + catch (...) { - try - { - task.get(); - } - catch(task_canceled&) - { - return true; - } - catch(...) - { - return false; - } return false; } + return false; +} - template - void ObserveException(task<_T> &task) +template +void ObserveException(task<_T>& task) +{ + try + { + task.get(); + } + catch (...) { - try - { - task.get(); - } - catch(...) - { - } } +} - template - void ObserveAllExceptions(Iter begin, Iter end) +template +void ObserveAllExceptions(Iter begin, Iter end) +{ + typedef typename std::iterator_traits::value_type::result_type TaskType; + for (auto it = begin; it != end; ++it) { - typedef typename std::iterator_traits::value_type::result_type TaskType; - for(auto it = begin; it != end; ++it) - { - ObserveException(*it); - } + ObserveException(*it); } +} } // namespace helpers SUITE(pplxtask_tests) { - -TEST(TestCancellationTokenRegression) -{ - for (int i=0; i < 500; i++) + TEST(TestCancellationTokenRegression) { - task_completion_event tce; - task starter(tce); + for (int i = 0; i < 500; i++) + { + task_completion_event tce; + task starter(tce); - cancellation_token_source ct; + cancellation_token_source ct; - task t1 = starter.then([]() -> int { - return 47; - }, ct.get_token()); + task t1 = starter.then([]() -> int { return 47; }, ct.get_token()); - task t2 ([]() -> int { - return 82; - }); + task t2([]() -> int { return 82; }); - task t3 ([]() -> int { - return 147; - }); + task t3([]() -> int { return 147; }); - auto t4 = (t1 && t2 && t3).then([=](std::vector vec) -> int { - return vec[0] + vec[1] + vec[3]; - }); + auto t4 = (t1 && t2 && t3).then([=](std::vector vec) -> int { return vec[0] + vec[1] + vec[3]; }); - ct.cancel(); + ct.cancel(); - tce.set(); - // this should not hang - task_status t4Status = t4.wait(); - IsTrue(t4Status == canceled, L"operator && did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status); + tce.set(); + // this should not hang + task_status t4Status = t4.wait(); + IsTrue(t4Status == canceled, + L"operator && did not properly cancel. Expected: %d, Actual: %d", + canceled, + t4Status); + } } -} -TEST(TestTasks_basic) -{ + TEST(TestTasks_basic) { - task t1 ([]() -> int { - return 47; - }); + { + task t1([]() -> int { return 47; }); - auto t2 = t1.then([=](int i) -> float { - IsTrue(i == 47, L"Continuation did not recieve the correct value from ancestor. Expected: 47, Actual: %d", i); - return (float)i/2; - }); + auto t2 = t1.then([=](int i) -> float { + IsTrue(i == 47, + L"Continuation did not recieve the correct value from ancestor. Expected: 47, Actual: %d", + i); + return (float)i / 2; + }); - float t2Result = t2.get(); - IsTrue(t2Result == 23.5, L"Continuation task did not produce the correct result. Expected: 23.5, Actual: %f", t2Result); + float t2Result = t2.get(); + IsTrue(t2Result == 23.5, + L"Continuation task did not produce the correct result. Expected: 23.5, Actual: %f", + t2Result); - task_status t2Status = t2.wait(); - IsTrue(t2Status == completed, L"Continuation task was not in completed state. Expected: %d, Actual: %d", completed, t2Status); + task_status t2Status = t2.wait(); + IsTrue(t2Status == completed, + L"Continuation task was not in completed state. Expected: %d, Actual: %d", + completed, + t2Status); - task t3 ([]() -> int { - return 0; - }); + task t3([]() -> int { return 0; }); - IsTrue(t1 == t1, L"task operator== resulted false on equivalent tasks"); - IsFalse(t1 != t1, L"task operator!= resulted true on equivalent tasks"); - IsFalse(t1 == t3, L"task operator== resulted true on different tasks"); - IsTrue(t1 != t3, L"task operator!= resulted false on different tasks"); + IsTrue(t1 == t1, L"task operator== resulted false on equivalent tasks"); + IsFalse(t1 != t1, L"task operator!= resulted true on equivalent tasks"); + IsFalse(t1 == t3, L"task operator== resulted true on different tasks"); + IsTrue(t1 != t3, L"task operator!= resulted false on different tasks"); - t3.wait(); + t3.wait(); + } } -} -TEST(TestTasks_default_construction) -{ - // Test that default constructed task properly throw exceptions + TEST(TestTasks_default_construction) { - task t1; - - try - { - t1.wait(); - LogFailure(L"t1.wait() should have thrown an exception"); - } - catch (invalid_operation) + // Test that default constructed task properly throw exceptions { - } + task t1; - try - { - t1.get(); - LogFailure(L"t1.get() should have thrown an exception"); - } - catch (invalid_operation) - { - } + try + { + t1.wait(); + LogFailure(L"t1.wait() should have thrown an exception"); + } + catch (invalid_operation) + { + } - try - { - t1.then([] (int i) { - return i; - }); + try + { + t1.get(); + LogFailure(L"t1.get() should have thrown an exception"); + } + catch (invalid_operation) + { + } - LogFailure(L"t1.then() should have thrown an exception"); - } - catch (invalid_operation) - { + try + { + t1.then([](int i) { return i; }); + + LogFailure(L"t1.then() should have thrown an exception"); + } + catch (invalid_operation) + { + } } } -} -TEST(TestTasks_void_tasks) -{ - // Test void tasks + TEST(TestTasks_void_tasks) { - int value = 0; - task t1 ([&value]() { - value = 147; - }); + // Test void tasks + { + int value = 0; + task t1([&value]() { value = 147; }); - auto t2 = t1.then([&]() { - IsTrue(value == 147, L"void continuation did not recieve the correct value from ancestor. Expected: 147, Actual: %d", value); - value++; - }); + auto t2 = t1.then([&]() { + IsTrue(value == 147, + L"void continuation did not recieve the correct value from ancestor. Expected: 147, Actual: %d", + value); + value++; + }); - IsTrue(t2.wait() == completed, L"void task was not in completed state."); + IsTrue(t2.wait() == completed, L"void task was not in completed state."); - IsTrue(value == 148, L"void tasks did not properly execute. Expected: 148, Actual: %d", value); + IsTrue(value == 148, L"void tasks did not properly execute. Expected: 148, Actual: %d", value); - task t3 ([]() { }); + task t3([]() {}); - IsTrue(t1 == t1, L"task operator== resulted false on equivalent tasks"); - IsFalse(t1 != t1, L"task operator!= resulted true on equivalent tasks"); - IsFalse(t1 == t3, L"task operator== resulted true on different tasks"); - IsTrue(t1 != t3, L"task operator!= resulted false on different tasks"); + IsTrue(t1 == t1, L"task operator== resulted false on equivalent tasks"); + IsFalse(t1 != t1, L"task operator!= resulted true on equivalent tasks"); + IsFalse(t1 == t3, L"task operator== resulted true on different tasks"); + IsTrue(t1 != t3, L"task operator!= resulted false on different tasks"); + } } -} -TEST(TestTasks_void_tasks_default_construction) -{ - // Test that default constructed task properly throw exceptions + TEST(TestTasks_void_tasks_default_construction) { - task t1; - - try + // Test that default constructed task properly throw exceptions { - t1.wait(); - LogFailure(L"t1.wait() should have thrown an exception"); - } - catch (invalid_operation) - { - } + task t1; - try - { - t1.get(); - LogFailure(L"t1.get() should have thrown an exception"); - } - catch (invalid_operation) - { - } + try + { + t1.wait(); + LogFailure(L"t1.wait() should have thrown an exception"); + } + catch (invalid_operation) + { + } - try - { - t1.then([] () { }); - LogFailure(L"t1.contiue_with() should have thrown an exception"); - } - catch (invalid_operation) - { + try + { + t1.get(); + LogFailure(L"t1.get() should have thrown an exception"); + } + catch (invalid_operation) + { + } + + try + { + t1.then([]() {}); + LogFailure(L"t1.contiue_with() should have thrown an exception"); + } + catch (invalid_operation) + { + } } } -} -TEST(TestTasks_movable_then) -{ -#ifndef _MSC_VER - // create movable only type - struct A + TEST(TestTasks_movable_then) { - A() = default; - A(A&&) = default; - A& operator=(A&&) = default; +#ifndef _MSC_VER + // create movable only type + struct A + { + A() = default; + A(A&&) = default; + A& operator=(A&&) = default; - // explicitly delete copy functions - A(const A&) = delete; - A& operator=(const A&) = delete; + // explicitly delete copy functions + A(const A&) = delete; + A& operator=(const A&) = delete; - char operator()(int) - { - return 'c'; - } - } a; + char operator()(int) { return 'c'; } + } a; - task task = create_task([]{ return 2; }); - auto f = task.then(std::move(a)); + task task = create_task([] { return 2; }); + auto f = task.then(std::move(a)); - IsTrue(f.get() == 'c', L".then should be able to work with movable functors"); + IsTrue(f.get() == 'c', L".then should be able to work with movable functors"); #endif // _MSC_VER -} + } -TEST(TestTasks_constant_this) -{ + TEST(TestTasks_constant_this) + { #ifdef _MSC_VER #if _MSC_VER < 1700 - // Dev10 compiler gives an error => .then(func) where func = int! + // Dev10 compiler gives an error => .then(func) where func = int! #else - { - // Test constant 'this' pointer in member functions then(), wait() and get(), - // so that they can be used in Lambda. - task t1([]() -> int { - return 0; - }); - - auto func = [t1]() -> int { - t1.then([](int last) -> int { - return last; - }); - t1.wait(); - return t1.get(); - }; + // Test constant 'this' pointer in member functions then(), wait() and get(), + // so that they can be used in Lambda. + task t1([]() -> int { return 0; }); - IsTrue(func() == 0, L"Tasks should be able to used inside a Lambda."); - } + auto func = [t1]() -> int { + t1.then([](int last) -> int { return last; }); + t1.wait(); + return t1.get(); + }; + + IsTrue(func() == 0, L"Tasks should be able to used inside a Lambda."); + } #endif // _MSC_VER < 1700 #endif // _MSC_VER -} + } -TEST(TestTasks_fire_and_forget) -{ - // Test Fire-and-forget behavior - extensibility::event_t evt; - bool flag = false; + TEST(TestTasks_fire_and_forget) { - task t1([&flag, &evt]() -> int{ + // Test Fire-and-forget behavior + extensibility::event_t evt; + bool flag = false; + { + task t1([&flag, &evt]() -> int { flag = true; evt.set(); return 0; }); - } - - evt.wait(); - IsTrue(flag == true, L"Fire-and-forget task did not properly execute."); -} -TEST(TestTasks_create_task) -{ - // test create task - task t1 = create_task([]() -> int { - return 4; - }); - IsTrue(t1.get() == 4, L"create_task for simple task did not properly execute."); - IsTrue(create_task(t1).get() == 4, L"create_task from a task task did not properly execute."); - task t2 = create_task([](){}); - task t3 = create_task([]() -> task { - return create_task([]() -> int { - return 4; - }); - }); - IsTrue(t3.get() == 4, L"create_task for task unwrapping did not properly execute."); -} - -TEST(TestTaskCompletionEvents_basic) -{ - task_completion_event tce; - task completion(tce); - auto completion2 = create_task(tce); - - task setEvent([=]() { - tce.set(50); - }); - - int result = completion.get(); - IsTrue(result == 50, L"Task Completion Event did not get the right result. Expected: 50, Actual: %d", result); - IsTrue(completion2.get() == 50, L"create_task didn't construct correct task for task_completion_event, Expected: 50, Actual: %d", result); -} - -TEST(TestTaskCompletionEvents_basic2) -{ - task_completion_event tce; - task completion(tce); - auto completion2 = create_task(tce); - - task setEvent([=]() { - tce.set(); - }); - - // this should not hang, because of the set of tce - completion.wait(); - completion2.wait(); -} - -TEST(TestTaskCompletionEvents_set_exception_basic) -{ - task_completion_event tce; - task t(tce); - tce.set_exception(42); - - t.then([=](task p) { - try - { - p.get(); - IsTrue(false, L"Exception not propagated to task t when calling set_exception."); } - catch(int n) - { - IsTrue(n==42, L"%ws:%u:bad exception value", __FILE__, __LINE__); - } - }).wait(); -} - -TEST(TestTaskCompletionEvents_set_exception_multiple) -{ - task_completion_event tce; - task t(tce); - tce.set_exception(42); - - t.then([=](task p) { - try - { - p.get(); - IsTrue(false, L"Exception not propagated to task t's first continuation when calling set_exception."); - } - catch(int n) - { - IsTrue(n==42, L"%ws:%u:bad exception value", __FILE__, __LINE__); - } - }).wait(); - - t.then([=](task p) { - try - { - p.get(); - IsTrue(false, L"Exception not propagated to task t's second continuation when calling set_exception."); - } - catch(int n) - { - IsTrue(n==42, L"%ws:%u:bad exception value", __FILE__, __LINE__); - } - }).wait(); -} -TEST(TestTaskCompletionEvents_set_exception_struct) -{ -#if defined(_MSC_VER) && _MSC_VER < 1700 - // The Dev10 compiler hits an ICE with this code -#else - struct s + evt.wait(); + IsTrue(flag == true, L"Fire-and-forget task did not properly execute."); + } + TEST(TestTasks_create_task) { - }; - - task_completion_event tce; - task t(tce); - tce.set_exception(s()); - t.then([=](task p){ - try - { - p.get(); - IsTrue(false, L"Exception not caught."); - } - catch(s) - { - //Do nothing - } - catch(...) - { - IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__); - } - }).wait(); -#endif // _MSC_VER < 1700 -} - -TEST(TestTaskCompletionEvents_multiple_tasks) -{ - task_completion_event tce; - task t1(tce); - task t2(tce); - tce.set_exception(1); - - t1.then([=](task p) { - try - { - p.get(); - IsTrue(false, L"An exception was not thrown when calling t1.get(). An exception was expected."); - } - catch(int ex) - { - IsTrue(ex==1, L"%ws:%u:wrong exception value", __FILE__, __LINE__); - } - catch(...) - { - IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__); - } - }); - - t2.then([=](task p) { - try - { - p.get(); - IsTrue(false, L"An exception was not thrown when calling t2.get(). An exception was expected."); - } - catch(int ex) - { - IsTrue(ex==1, L"%ws:%u:wrong exception value", __FILE__, __LINE__); - } - catch(...) - { - IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__); - } - }); -} - -TEST(TestTaskCompletionEvents_set_exception_after_set) -{ - task_completion_event tce; - task t(tce); - tce.set(1); - auto result = tce.set_exception(std::current_exception()); - IsFalse(result, L"set_exception must return false, but did not"); - t.then([=](task p) { - try - { - int n=p.get(); - IsTrue(n==1, L"Value not properly propagated to continuation"); - } - catch(...) - { - IsTrue(false, L"An exception was unexpectedly thrown in the continuation task"); - } - }).wait(); -} - -TEST(TestTaskCompletionEvents_set_exception_after_set2) -{ - task_completion_event tce; - task t(tce); - tce.set_exception(1); - auto result = tce.set_exception(2); - IsFalse(result, L"set_exception must return false, but did not"); - t.then([=](task p) { - try - { - p.get(); - IsTrue(false, L"%ws:%u:expected exception not thrown", __FILE__, __LINE__); - } - catch(int n) - { - IsTrue(n==1, L"%ws:%u:unexpected exception payload", __FILE__, __LINE__); - } - }).wait(); -} - -TEST(TestTaskCompletionEvents_set_after_set_exception) -{ - task_completion_event tce; - task t(tce); - tce.set_exception(42); - tce.set(1); // should be no-op - t.then([=](task p) { - try - { - p.get(); - IsTrue(false, L"Exception should have been thrown here."); - } - catch(int e) - { - IsTrue(e==42, L"%ws:%u:not the right exception value", __FILE__, __LINE__); - } - catch(...) - { - IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__); - } - }).wait(); -} - -TEST(TestTaskOperators_and_or) -{ - task t1 ([]() -> int { - return 47; - }); - - task t2 ([]() -> int { - return 82; - }); - - auto t3 = (t1 && t2).then([=](std::vector vec) -> int { - IsTrue(vec.size() == 2, L"operator&& did not produce a correct vector size. Expected: 2, Actual: %d", vec.size()); - IsTrue(vec[0] == 47, L"operator&& did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]); - IsTrue(vec[1] == 82, L"operator&& did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]); - return vec[0] + vec[1]; - }); - - int t3Result = t3.get(); - IsTrue(t3Result == 129, L"operator&& task did not produce the correct result. Expected: 129, Actual: %d", t3Result); -} - -TEST(TestTaskOperators_and_or2) -{ - task t1 ([]() -> int { - return 47; - }); - - task t2 ([]() -> int { - return 82; - }); - - task t3 ([]() -> int { - return 147; - }); - - task t4 ([]() -> int { - return 192; - }); - - auto t5 = (t1 && t2 && t3 && t4).then([=](std::vector vec) -> int { - IsTrue(vec.size() == 4, L"operator&& did not produce a correct vector size. Expected: 4, Actual: %d", vec.size()); - IsTrue(vec[0] == 47, L"operator&& did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]); - IsTrue(vec[1] == 82, L"operator&& did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]); - IsTrue(vec[2] == 147, L"operator&& did not produce a correct vector[2]. Expected: 147, Actual: %d", vec[2]); - IsTrue(vec[3] == 192, L"operator&& did not produce a correct vector[3]. Expected: 192, Actual: %d", vec[3]); - int count = 0; - for(unsigned i = 0; i < vec.size(); i++) - count += vec[i]; - return count; - }); - - int t5Result = t5.get(); - IsTrue(t5Result == 468, L"operator&& task did not produce the correct result. Expected: 468, Actual: %d", t5Result); - -} - -TEST(TestTaskOperators_and_or3) -{ - task t1 ([]() -> int { - return 47; - }); - - task t2 ([]() -> int { - return 82; - }); - - task t3 ([]() -> int { - return 147; - }); - - task t4 ([]() -> int { - return 192; - }); - - auto t5 = ((t1 && t2) && (t3 && t4)).then([=](std::vector vec) -> int { - IsTrue(vec.size() == 4, L"operator&& did not produce a correct vector size. Expected: 4, Actual: %d", vec.size()); - IsTrue(vec[0] == 47, L"operator&& did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]); - IsTrue(vec[1] == 82, L"operator&& did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]); - IsTrue(vec[2] == 147, L"operator&& did not produce a correct vector[2]. Expected: 147, Actual: %d", vec[2]); - IsTrue(vec[3] == 192, L"operator&& did not produce a correct vector[3]. Expected: 192, Actual: %d", vec[3]); - int count = 0; - for(unsigned i = 0; i < vec.size(); i++) - count += vec[i]; - return count; - }); - - int t5Result = t5.get(); - IsTrue(t5Result == 468, L"operator&& task did not produce the correct result. Expected: 468, Actual: %d", t5Result); -} + // test create task + task t1 = create_task([]() -> int { return 4; }); + IsTrue(t1.get() == 4, L"create_task for simple task did not properly execute."); + IsTrue(create_task(t1).get() == 4, L"create_task from a task task did not properly execute."); + task t2 = create_task([]() {}); + task t3 = create_task([]() -> task { return create_task([]() -> int { return 4; }); }); + IsTrue(t3.get() == 4, L"create_task for task unwrapping did not properly execute."); + } -TEST(TestTaskOperators_and_or4) -{ - extensibility::event_t evt; + TEST(TestTaskCompletionEvents_basic) + { + task_completion_event tce; + task completion(tce); + auto completion2 = create_task(tce); - task t1 ([&evt]() -> int { - evt.wait(); - return 47; - }); + task setEvent([=]() { tce.set(50); }); - task t2 ([]() -> int { - return 82; - }); + int result = completion.get(); + IsTrue(result == 50, L"Task Completion Event did not get the right result. Expected: 50, Actual: %d", result); + IsTrue(completion2.get() == 50, + L"create_task didn't construct correct task for task_completion_event, Expected: 50, Actual: %d", + result); + } - auto t3 = (t1 || t2).then([=](int p) -> int { - IsTrue(p == 82, L"operator|| did not get the right result. Expected: 82, Actual: %d", p); - return p; - }); + TEST(TestTaskCompletionEvents_basic2) + { + task_completion_event tce; + task completion(tce); + auto completion2 = create_task(tce); - t3.wait(); + task setEvent([=]() { tce.set(); }); - evt.set(); - t1.wait(); -} + // this should not hang, because of the set of tce + completion.wait(); + completion2.wait(); + } -TEST(TestTaskOperators_and_or5) -{ - extensibility::event_t evt; + TEST(TestTaskCompletionEvents_set_exception_basic) + { + task_completion_event tce; + task t(tce); + tce.set_exception(42); + + t.then([=](task p) { + try + { + p.get(); + IsTrue(false, L"Exception not propagated to task t when calling set_exception."); + } + catch (int n) + { + IsTrue(n == 42, L"%ws:%u:bad exception value", __FILE__, __LINE__); + } + }) + .wait(); + } - task t1 ([&evt]() -> int { - evt.wait(); - return 47; - }); + TEST(TestTaskCompletionEvents_set_exception_multiple) + { + task_completion_event tce; + task t(tce); + tce.set_exception(42); + + t.then([=](task p) { + try + { + p.get(); + IsTrue(false, L"Exception not propagated to task t's first continuation when calling set_exception."); + } + catch (int n) + { + IsTrue(n == 42, L"%ws:%u:bad exception value", __FILE__, __LINE__); + } + }) + .wait(); + + t.then([=](task p) { + try + { + p.get(); + IsTrue(false, L"Exception not propagated to task t's second continuation when calling set_exception."); + } + catch (int n) + { + IsTrue(n == 42, L"%ws:%u:bad exception value", __FILE__, __LINE__); + } + }) + .wait(); + } - task t2 ([&evt]() -> int { - evt.wait(); - return 82; - }); + TEST(TestTaskCompletionEvents_set_exception_struct) + { +#if defined(_MSC_VER) && _MSC_VER < 1700 + // The Dev10 compiler hits an ICE with this code +#else + struct s + { + }; - task t3 ([]() -> int { - return 147; - }); + task_completion_event tce; + task t(tce); + tce.set_exception(s()); + t.then([=](task p) { + try + { + p.get(); + IsTrue(false, L"Exception not caught."); + } + catch (s) + { + // Do nothing + } + catch (...) + { + IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__); + } + }) + .wait(); +#endif // _MSC_VER < 1700 + } - task t4 ([&evt]() -> int { - evt.wait(); - return 192; - }); + TEST(TestTaskCompletionEvents_multiple_tasks) + { + task_completion_event tce; + task t1(tce); + task t2(tce); + tce.set_exception(1); - auto t5 = (t1 || t2 || t3 || t4).then([=](int result) -> int { - IsTrue(result == 147, L"operator|| did not produce a correct result. Expected: 147, Actual: %d", result); - return result; - }); + t1.then([=](task p) { + try + { + p.get(); + IsTrue(false, L"An exception was not thrown when calling t1.get(). An exception was expected."); + } + catch (int ex) + { + IsTrue(ex == 1, L"%ws:%u:wrong exception value", __FILE__, __LINE__); + } + catch (...) + { + IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__); + } + }); - t5.wait(); + t2.then([=](task p) { + try + { + p.get(); + IsTrue(false, L"An exception was not thrown when calling t2.get(). An exception was expected."); + } + catch (int ex) + { + IsTrue(ex == 1, L"%ws:%u:wrong exception value", __FILE__, __LINE__); + } + catch (...) + { + IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__); + } + }); + } - evt.set(); - t1.wait(); - t2.wait(); - t4.wait(); -} + TEST(TestTaskCompletionEvents_set_exception_after_set) + { + task_completion_event tce; + task t(tce); + tce.set(1); + auto result = tce.set_exception(std::current_exception()); + IsFalse(result, L"set_exception must return false, but did not"); + t.then([=](task p) { + try + { + int n = p.get(); + IsTrue(n == 1, L"Value not properly propagated to continuation"); + } + catch (...) + { + IsTrue(false, L"An exception was unexpectedly thrown in the continuation task"); + } + }) + .wait(); + } -TEST(TestTaskOperators_and_or_sequence) -{ - // testing ( t1 && t2 ) || t3, operator&& finishes first - extensibility::event_t evt; + TEST(TestTaskCompletionEvents_set_exception_after_set2) + { + task_completion_event tce; + task t(tce); + tce.set_exception(1); + auto result = tce.set_exception(2); + IsFalse(result, L"set_exception must return false, but did not"); + t.then([=](task p) { + try + { + p.get(); + IsTrue(false, L"%ws:%u:expected exception not thrown", __FILE__, __LINE__); + } + catch (int n) + { + IsTrue(n == 1, L"%ws:%u:unexpected exception payload", __FILE__, __LINE__); + } + }) + .wait(); + } - task t1 ([]() -> int { - return 47; - }); + TEST(TestTaskCompletionEvents_set_after_set_exception) + { + task_completion_event tce; + task t(tce); + tce.set_exception(42); + tce.set(1); // should be no-op + t.then([=](task p) { + try + { + p.get(); + IsTrue(false, L"Exception should have been thrown here."); + } + catch (int e) + { + IsTrue(e == 42, L"%ws:%u:not the right exception value", __FILE__, __LINE__); + } + catch (...) + { + IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__); + } + }) + .wait(); + } - task t2 ([]() -> int { - return 82; - }); + TEST(TestTaskOperators_and_or) + { + task t1([]() -> int { return 47; }); - task t3 ([&evt]() -> int { - evt.wait(); - return 147; - }); + task t2([]() -> int { return 82; }); - auto t4 = ((t1 && t2) || t3).then([=](std::vector vec) -> int { - IsTrue(vec.size() == 2, L"(t1 && t2) || t3 did not produce a correct vector size. Expected: 2, Actual: %d", vec.size()); - IsTrue(vec[0] == 47, L"(t1 && t2) || t3 did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]); - IsTrue(vec[1] == 82, L"(t1 && t2) || t3 did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]); + auto t3 = (t1 && t2).then([=](std::vector vec) -> int { + IsTrue(vec.size() == 2, + L"operator&& did not produce a correct vector size. Expected: 2, Actual: %d", + vec.size()); + IsTrue(vec[0] == 47, L"operator&& did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]); + IsTrue(vec[1] == 82, L"operator&& did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]); return vec[0] + vec[1]; - }); + }); - int t4Result = t4.get(); - IsTrue(t4.get() == 129, L"(t1 && t2) || t3 task did not produce the correct result. Expected: 129, Actual: %d", t4Result); + int t3Result = t3.get(); + IsTrue(t3Result == 129, + L"operator&& task did not produce the correct result. Expected: 129, Actual: %d", + t3Result); + } - evt.set(); - t3.wait(); -} + TEST(TestTaskOperators_and_or2) + { + task t1([]() -> int { return 47; }); + + task t2([]() -> int { return 82; }); + + task t3([]() -> int { return 147; }); + + task t4([]() -> int { return 192; }); + + auto t5 = (t1 && t2 && t3 && t4).then([=](std::vector vec) -> int { + IsTrue(vec.size() == 4, + L"operator&& did not produce a correct vector size. Expected: 4, Actual: %d", + vec.size()); + IsTrue(vec[0] == 47, L"operator&& did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]); + IsTrue(vec[1] == 82, L"operator&& did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]); + IsTrue(vec[2] == 147, L"operator&& did not produce a correct vector[2]. Expected: 147, Actual: %d", vec[2]); + IsTrue(vec[3] == 192, L"operator&& did not produce a correct vector[3]. Expected: 192, Actual: %d", vec[3]); + int count = 0; + for (unsigned i = 0; i < vec.size(); i++) + count += vec[i]; + return count; + }); -TEST(TestTaskOperators_and_or_sequence2) -{ - // testing ( t1 && t2 ) || t3, operator|| finishes first - extensibility::event_t evt; + int t5Result = t5.get(); + IsTrue(t5Result == 468, + L"operator&& task did not produce the correct result. Expected: 468, Actual: %d", + t5Result); + } - task t1 ([&evt]() -> int { - evt.wait(); - return 47; - }); + TEST(TestTaskOperators_and_or3) + { + task t1([]() -> int { return 47; }); + + task t2([]() -> int { return 82; }); + + task t3([]() -> int { return 147; }); + + task t4([]() -> int { return 192; }); + + auto t5 = ((t1 && t2) && (t3 && t4)).then([=](std::vector vec) -> int { + IsTrue(vec.size() == 4, + L"operator&& did not produce a correct vector size. Expected: 4, Actual: %d", + vec.size()); + IsTrue(vec[0] == 47, L"operator&& did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]); + IsTrue(vec[1] == 82, L"operator&& did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]); + IsTrue(vec[2] == 147, L"operator&& did not produce a correct vector[2]. Expected: 147, Actual: %d", vec[2]); + IsTrue(vec[3] == 192, L"operator&& did not produce a correct vector[3]. Expected: 192, Actual: %d", vec[3]); + int count = 0; + for (unsigned i = 0; i < vec.size(); i++) + count += vec[i]; + return count; + }); - task t2 ([&evt]() -> int { - evt.wait(); - return 82; - }); + int t5Result = t5.get(); + IsTrue(t5Result == 468, + L"operator&& task did not produce the correct result. Expected: 468, Actual: %d", + t5Result); + } - task t3 ([]() -> int { - return 147; - }); + TEST(TestTaskOperators_and_or4) + { + extensibility::event_t evt; - auto t4 = ((t1 && t2) || t3).then([=](std::vector vec) -> int { - IsTrue(vec.size() == 1, L"(t1 && t2) || t3 did not produce a correct vector size. Expected: 1, Actual: %d", vec.size()); - IsTrue(vec[0] == 147, L"(t1 && t2) || t3 did not produce a correct vector[0]. Expected: 147, Actual: %d", vec[0]); - return vec[0]; - }); + task t1([&evt]() -> int { + evt.wait(); + return 47; + }); - int t4Result = t4.get(); - IsTrue(t4.get() == 147, L"(t1 && t2) || t3 task did not produce the correct result. Expected: 147, Actual: %d", t4Result); + task t2([]() -> int { return 82; }); - evt.set(); - t1.wait(); - t2.wait(); -} + auto t3 = (t1 || t2).then([=](int p) -> int { + IsTrue(p == 82, L"operator|| did not get the right result. Expected: 82, Actual: %d", p); + return p; + }); -TEST(TestTaskOperators_and_or_sequence3) -{ - // testing t1 && (t2 || t3) - extensibility::event_t evt; + t3.wait(); - task t1 ([]() -> int { - return 47; - }); + evt.set(); + t1.wait(); + } - task t2 ([&evt]() -> int { - evt.wait(); - return 82; - }); + TEST(TestTaskOperators_and_or5) + { + extensibility::event_t evt; - task t3 ([]() -> int { - return 147; - }); + task t1([&evt]() -> int { + evt.wait(); + return 47; + }); - auto t4 = (t1 && (t2 || t3)).then([=](std::vector vec) -> int { - IsTrue(vec.size() == 2, L"t1 && (t2 || t3) did not produce a correct vector size. Expected: 2, Actual: %d", vec.size()); - IsTrue(vec[0] == 47, L"t1 && (t2 || t3) did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]); - IsTrue(vec[1] == 147, L"t1 && (t2 || t3) did not produce a correct vector[1]. Expected: 147, Actual: %d", vec[1]); - return vec[0] + vec[1]; - }); + task t2([&evt]() -> int { + evt.wait(); + return 82; + }); - int t4Result = t4.get(); - IsTrue(t4.get() == 194, L"t1 && (t2 || t3) task did not produce the correct result. Expected: 194 Actual: %d", t4Result); + task t3([]() -> int { return 147; }); - evt.set(); - t2.wait(); -} + task t4([&evt]() -> int { + evt.wait(); + return 192; + }); -TEST(TestTaskOperators_cancellation) -{ - task_completion_event tce; - task starter(tce); + auto t5 = (t1 || t2 || t3 || t4).then([=](int result) -> int { + IsTrue(result == 147, L"operator|| did not produce a correct result. Expected: 147, Actual: %d", result); + return result; + }); - cancellation_token_source ct; + t5.wait(); - task t1 = starter.then([]() -> int { - return 47; - }, ct.get_token()); + evt.set(); + t1.wait(); + t2.wait(); + t4.wait(); + } - task t2 ([]() -> int { - return 82; - }); + TEST(TestTaskOperators_and_or_sequence) + { + // testing ( t1 && t2 ) || t3, operator&& finishes first + extensibility::event_t evt; - task t3 ([]() -> int { - return 147; - }); + task t1([]() -> int { return 47; }); - auto t4 = (t1 && t2 && t3).then([=](std::vector vec) -> int { - return vec[0] + vec[1] + vec[3]; - }); + task t2([]() -> int { return 82; }); - ct.cancel(); + task t3([&evt]() -> int { + evt.wait(); + return 147; + }); - tce.set(); - // this should not hang - task_status t4Status = t4.wait(); - IsTrue(t4Status == canceled, L"operator && did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status); -} + auto t4 = ((t1 && t2) || t3).then([=](std::vector vec) -> int { + IsTrue(vec.size() == 2, + L"(t1 && t2) || t3 did not produce a correct vector size. Expected: 2, Actual: %d", + vec.size()); + IsTrue(vec[0] == 47, + L"(t1 && t2) || t3 did not produce a correct vector[0]. Expected: 47, Actual: %d", + vec[0]); + IsTrue(vec[1] == 82, + L"(t1 && t2) || t3 did not produce a correct vector[1]. Expected: 82, Actual: %d", + vec[1]); + return vec[0] + vec[1]; + }); -TEST(TestTaskOperators_cancellation_and) -{ - task_completion_event tce; - task starter(tce); + int t4Result = t4.get(); + IsTrue(t4.get() == 129, + L"(t1 && t2) || t3 task did not produce the correct result. Expected: 129, Actual: %d", + t4Result); - cancellation_token_source ct; + evt.set(); + t3.wait(); + } - task t1 = starter.then([]() -> void {}, ct.get_token()); + TEST(TestTaskOperators_and_or_sequence2) + { + // testing ( t1 && t2 ) || t3, operator|| finishes first + extensibility::event_t evt; - task t2 ([]() -> void {}); + task t1([&evt]() -> int { + evt.wait(); + return 47; + }); - task t3 ([]() -> void {}); + task t2([&evt]() -> int { + evt.wait(); + return 82; + }); - auto t4 = (t1 && t2 && t3).then([=]() {}); + task t3([]() -> int { return 147; }); - ct.cancel(); + auto t4 = ((t1 && t2) || t3).then([=](std::vector vec) -> int { + IsTrue(vec.size() == 1, + L"(t1 && t2) || t3 did not produce a correct vector size. Expected: 1, Actual: %d", + vec.size()); + IsTrue(vec[0] == 147, + L"(t1 && t2) || t3 did not produce a correct vector[0]. Expected: 147, Actual: %d", + vec[0]); + return vec[0]; + }); - tce.set(); - // this should not hang - task_status t4Status = t4.wait(); - IsTrue(t4Status == canceled, L"operator && did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status); -} + int t4Result = t4.get(); + IsTrue(t4.get() == 147, + L"(t1 && t2) || t3 task did not produce the correct result. Expected: 147, Actual: %d", + t4Result); -TEST(TestTaskOperators_cancellation_or) -{ - task_completion_event tce; - task starter(tce); + evt.set(); + t1.wait(); + t2.wait(); + } - cancellation_token_source ct1; - cancellation_token_source ct2; - cancellation_token_source ct3; + TEST(TestTaskOperators_and_or_sequence3) + { + // testing t1 && (t2 || t3) + extensibility::event_t evt; - task t1 = starter.then([]() -> int { - return 47; - }, ct1.get_token()); + task t1([]() -> int { return 47; }); - task t2 = starter.then([]() -> int { - return 82; - }, ct2.get_token()); + task t2([&evt]() -> int { + evt.wait(); + return 82; + }); - task t3 = starter.then([]() -> int { - return 147; - }, ct3.get_token()); + task t3([]() -> int { return 147; }); + + auto t4 = (t1 && (t2 || t3)).then([=](std::vector vec) -> int { + IsTrue(vec.size() == 2, + L"t1 && (t2 || t3) did not produce a correct vector size. Expected: 2, Actual: %d", + vec.size()); + IsTrue(vec[0] == 47, + L"t1 && (t2 || t3) did not produce a correct vector[0]. Expected: 47, Actual: %d", + vec[0]); + IsTrue(vec[1] == 147, + L"t1 && (t2 || t3) did not produce a correct vector[1]. Expected: 147, Actual: %d", + vec[1]); + return vec[0] + vec[1]; + }); - auto t4 = (t1 || t2 || t3).then([=](int result) -> int { - return result; - }); + int t4Result = t4.get(); + IsTrue(t4.get() == 194, + L"t1 && (t2 || t3) task did not produce the correct result. Expected: 194 Actual: %d", + t4Result); - ct1.cancel(); - ct2.cancel(); - ct3.cancel(); + evt.set(); + t2.wait(); + } - tce.set(); - // this should not hang - task_status t4Status = t4.wait(); - IsTrue(t4Status == canceled, L"operator || did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status); + TEST(TestTaskOperators_cancellation) + { + task_completion_event tce; + task starter(tce); -} -TEST(TestTaskOperators_cancellation_or2) -{ - task_completion_event tce; - task starter(tce); + cancellation_token_source ct; - cancellation_token_source ct1; - cancellation_token_source ct2; - cancellation_token_source ct3; + task t1 = starter.then([]() -> int { return 47; }, ct.get_token()); - task t1 = starter.then([]() -> void {}, ct1.get_token()); + task t2([]() -> int { return 82; }); - task t2 = starter.then([]() -> void {}, ct2.get_token()); + task t3([]() -> int { return 147; }); - task t3 = starter.then([]() -> void {}, ct3.get_token()); + auto t4 = (t1 && t2 && t3).then([=](std::vector vec) -> int { return vec[0] + vec[1] + vec[3]; }); - auto t4 = (t1 || t2 || t3).then([=]() {}); + ct.cancel(); - ct1.cancel(); - ct2.cancel(); - ct3.cancel(); + tce.set(); + // this should not hang + task_status t4Status = t4.wait(); + IsTrue( + t4Status == canceled, L"operator && did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status); + } - tce.set(); - // this should not hang - task_status t4Status = t4.wait(); - IsTrue(t4Status == canceled, L"operator || did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status); -} + TEST(TestTaskOperators_cancellation_and) + { + task_completion_event tce; + task starter(tce); -TEST(TestTaskOperators_cancellation_complex) -{ - extensibility::event_t evt1, evt2; - pplx::details::atomic_long n(0); + cancellation_token_source ct; - cancellation_token_source ct; + task t1 = starter.then([]() -> void {}, ct.get_token()); - task t1([&n, &evt1, &evt2](){ - pplx::details::atomic_add(n, 1L); // this should execute - evt2.set(); - evt1.wait(); - }, ct.get_token()); + task t2([]() -> void {}); - task t2 = t1.then([&n](){ - pplx::details::atomic_add(n, 10L); // this should NOT execute - }); + task t3([]() -> void {}); - task t3 = t1.then([&n](){ - pplx::details::atomic_add(n, 100L); // this should NOT execute - }); + auto t4 = (t1 && t2 && t3).then([=]() {}); - task t4 = t1.then([&n](task taskResult){ - pplx::details::atomic_add(n, 1000L); // this should execute - }); + ct.cancel(); - task t5 = t1.then([&n](task taskResult){ - try - { - taskResult.get(); - pplx::details::atomic_add(n, 10000L); // this should execute - } - catch(task_canceled&) - { - pplx::details::atomic_add(n, 100000L); // this should NOT execute - } - }); + tce.set(); + // this should not hang + task_status t4Status = t4.wait(); + IsTrue( + t4Status == canceled, L"operator && did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status); + } - evt2.wait(); - ct.cancel(); - evt1.set(); + TEST(TestTaskOperators_cancellation_or) + { + task_completion_event tce; + task starter(tce); - IsTrue((t2 && t3).wait() == canceled, L"(t1 && t2) was not canceled"); - IsTrue((t2 || t3 || t4 || t5).wait() == completed, L"(t2 || t3 || t4 || t5) did not complete"); - IsTrue((t4 && t5).wait() == completed, L"(t4 && t5) did not complete"); + cancellation_token_source ct1; + cancellation_token_source ct2; + cancellation_token_source ct3; - try - { - t1.get(); - } - catch (task_canceled&) - { - LogFailure(L"get() on canceled task t1 should not throw a task_canceled exception."); - } + task t1 = starter.then([]() -> int { return 47; }, ct1.get_token()); - try - { - t2.get(); - LogFailure(L"get() on canceled task t2 should throw a task_canceled exception."); - } - catch (task_canceled&){} + task t2 = starter.then([]() -> int { return 82; }, ct2.get_token()); - try - { - t3.get(); - LogFailure(L"get() on canceled task t3 should throw a task_canceled exception."); - } - catch (task_canceled&){} + task t3 = starter.then([]() -> int { return 147; }, ct3.get_token()); - try - { - t4.get(); - t5.get(); + auto t4 = (t1 || t2 || t3).then([=](int result) -> int { return result; }); + + ct1.cancel(); + ct2.cancel(); + ct3.cancel(); + + tce.set(); + // this should not hang + task_status t4Status = t4.wait(); + IsTrue( + t4Status == canceled, L"operator || did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status); } - catch(...) + TEST(TestTaskOperators_cancellation_or2) { - LogFailure(L"get() on completed tasks threw an exception."); - } - IsTrue(n == 11001L, L"The right result was not obtained from the sequence of tasks that executed. Expected: 11001, Actual: %d", static_cast(n)); -} + task_completion_event tce; + task starter(tce); -TEST(TestTaskOperators_cancellation_exception) -{ - extensibility::event_t evt1, evt2; - pplx::details::atomic_long n(0); + cancellation_token_source ct1; + cancellation_token_source ct2; + cancellation_token_source ct3; - cancellation_token_source ct; + task t1 = starter.then([]() -> void {}, ct1.get_token()); - task t1([&n, &evt1, &evt2](){ - evt2.set(); - evt1.wait(); - }, ct.get_token()); + task t2 = starter.then([]() -> void {}, ct2.get_token()); - task t2([&n](){ - throw 42; - }); + task t3 = starter.then([]() -> void {}, ct3.get_token()); - for (int i = 0; i < 5; ++i) - { - try - { - t2.get(); - LogFailure(L"Exception was not received from t2.get()"); - } - catch(int x) - { - IsTrue(x == 42, L"Incorrect integer was thrown from t2.get(). Expected: 42, Actual: %d", x); - } - catch(task_canceled&) - { - LogFailure(L"task_canceled was thrown from t2.get() when an integer was expected"); - } + auto t4 = (t1 || t2 || t3).then([=]() {}); + + ct1.cancel(); + ct2.cancel(); + ct3.cancel(); + + tce.set(); + // this should not hang + task_status t4Status = t4.wait(); + IsTrue( + t4Status == canceled, L"operator || did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status); } - for (int i = 0; i < 5; ++i) + TEST(TestTaskOperators_cancellation_complex) { - try - { - t2.wait(); - LogFailure(L"Exception was not received from t2.wait()"); - } - catch(int x) - { - IsTrue(x == 42, L"Incorrect integer was thrown from t2.wait(). Expected: 42, Actual: %d", x); - } - catch(task_canceled&) - { - LogFailure(L"task_canceled was thrown from t2.wait() when an integer was expected"); - } - } + extensibility::event_t evt1, evt2; + pplx::details::atomic_long n(0); + + cancellation_token_source ct; + + task t1( + [&n, &evt1, &evt2]() { + pplx::details::atomic_add(n, 1L); // this should execute + evt2.set(); + evt1.wait(); + }, + ct.get_token()); + + task t2 = t1.then([&n]() { + pplx::details::atomic_add(n, 10L); // this should NOT execute + }); + + task t3 = t1.then([&n]() { + pplx::details::atomic_add(n, 100L); // this should NOT execute + }); - task t3 = t1.then([&n](){ - pplx::details::atomic_add(n, 1L); // this should NOT execute, - }); + task t4 = t1.then([&n](task taskResult) { + pplx::details::atomic_add(n, 1000L); // this should execute + }); - task t4 = t1.then([&n](task taskResult){ - pplx::details::atomic_add(n, 10L); // this should execute - }); + task t5 = t1.then([&n](task taskResult) { + try + { + taskResult.get(); + pplx::details::atomic_add(n, 10000L); // this should execute + } + catch (task_canceled&) + { + pplx::details::atomic_add(n, 100000L); // this should NOT execute + } + }); - task t5 = t2.then([&n](){ - pplx::details::atomic_add(n, 100L); // this should NOT execute - }); + evt2.wait(); + ct.cancel(); + evt1.set(); - task t6 = t2.then([&n](task taskResult){ - pplx::details::atomic_add(n, 1000L); // this should execute - taskResult.get(); // should throw 42 - pplx::details::atomic_add(n, 10000L); // this should NOT execute - }); + IsTrue((t2 && t3).wait() == canceled, L"(t1 && t2) was not canceled"); + IsTrue((t2 || t3 || t4 || t5).wait() == completed, L"(t2 || t3 || t4 || t5) did not complete"); + IsTrue((t4 && t5).wait() == completed, L"(t4 && t5) did not complete"); - task t7 = t2.then([&n, this](task taskResult){ try { - taskResult.get(); - pplx::details::atomic_add(n, 100000L); // this should NOT execute + t1.get(); } - catch(int x) + catch (task_canceled&) { - IsTrue(x == 42, L"Incorrect integer exception was received in t7 from taskresult.get(). Expected: 42, Actual: %d", x); - pplx::details::atomic_add(n, 1000000L); // this should execute + LogFailure(L"get() on canceled task t1 should not throw a task_canceled exception."); } - catch(task_canceled) + + try { - LogFailure(L"task_canceled was thrown by taskResult.get() in t7"); + t2.get(); + LogFailure(L"get() on canceled task t2 should throw a task_canceled exception."); } - catch(...) + catch (task_canceled&) { - LogFailure(L"A random exception was thrown by taskResult.get() in t7"); } - throw 96; - }); - - task t8 = (t6 || t7).then([&n, this](task taskResult){ try { - taskResult.get(); - pplx::details::atomic_add(n, 1000000L); // this should NOT execute + t3.get(); + LogFailure(L"get() on canceled task t3 should throw a task_canceled exception."); } - catch(int x) + catch (task_canceled&) { - IsTrue((x == 42 || x ==96), L"Incorrect integer exception was received in t7 from taskresult.get(). Expected: 42 or 96, Actual: %d", x); - pplx::details::atomic_add(n, 100000000L); // this should execute } - catch(task_canceled) + + try { - LogFailure(L"(t6 || t7) was canceled without an exception"); + t4.get(); + t5.get(); } - catch(...) + catch (...) { - LogFailure(L"(t6 || t7) was canceled with an unexpected exception"); + LogFailure(L"get() on completed tasks threw an exception."); } - }); - - // Cancel t1 now that t2 is guaranteed canceled with an exception - evt2.wait(); - ct.cancel(); - evt1.set(); - - try - { - task_status status = (t1 && t2).wait(); - IsTrue((status == canceled), L"(t1 && t2).wait() did not return canceled. Expected: %d, Actual %d", canceled, status); - } - catch(int x) - { - IsTrue(x == 42, L"Incorrect integer exception was received from (t1 && t2).wait(). Expected: 42, Actual: %d", x); + IsTrue( + n == 11001L, + L"The right result was not obtained from the sequence of tasks that executed. Expected: 11001, Actual: %d", + static_cast(n)); } - try - { - task_status status = t3.wait(); - IsTrue((status == canceled), L"t3.wait() did not returned canceled. Expected: %d, Actual %d", canceled, status); - } - catch(task_canceled&) - { - LogFailure(L"t3.wait() threw task_canceled instead of returning canceled"); - } - catch(...) + TEST(TestTaskOperators_cancellation_exception) { - LogFailure(L"t3.wait() threw an unexpected exception"); - } + extensibility::event_t evt1, evt2; + pplx::details::atomic_long n(0); - try - { - task_status status = t4.wait(); - IsTrue((status == completed), L"t4.wait() did not returned completed. Expected: %d, Actual %d", completed, status); - } - catch(...) - { - LogFailure(L"t4.wait() threw an unexpected exception"); - } + cancellation_token_source ct; - try - { - t5.wait(); - LogFailure(L"t5.wait() did not throw an exception"); - } - catch(int x) - { - IsTrue(x == 42, L"Incorrect integer exception was received from t5.wait(). Expected: 42, Actual: %d", x); - } + task t1( + [&n, &evt1, &evt2]() { + evt2.set(); + evt1.wait(); + }, + ct.get_token()); - // Observe the exceptions from t5, t6 and t7 - helpers::ObserveException(t5); helpers::ObserveException(t6); helpers::ObserveException(t7); + task t2([&n]() { throw 42; }); - try - { - (t1 || t6).get(); - LogFailure(L"(t1 || t6).get() should throw an exception."); - } - catch (task_canceled&) - { - LogFailure(L"(t1 || t6).get() threw task_canceled when an int was expected."); - } - catch(int x) - { - IsTrue((x == 42 || x ==96), L"Incorrect integer exception was received from (t1 || t6 || t7).get(). Expected: 42 or 96, Actual: %d", x); - } + for (int i = 0; i < 5; ++i) + { + try + { + t2.get(); + LogFailure(L"Exception was not received from t2.get()"); + } + catch (int x) + { + IsTrue(x == 42, L"Incorrect integer was thrown from t2.get(). Expected: 42, Actual: %d", x); + } + catch (task_canceled&) + { + LogFailure(L"task_canceled was thrown from t2.get() when an integer was expected"); + } + } - t8.wait(); + for (int i = 0; i < 5; ++i) + { + try + { + t2.wait(); + LogFailure(L"Exception was not received from t2.wait()"); + } + catch (int x) + { + IsTrue(x == 42, L"Incorrect integer was thrown from t2.wait(). Expected: 42, Actual: %d", x); + } + catch (task_canceled&) + { + LogFailure(L"task_canceled was thrown from t2.wait() when an integer was expected"); + } + } - IsTrue(n == 101001010L, L"The right result was not obtained from the sequence of tasks that executed. Expected 101001010, actual %d", 101001010, static_cast(n)); -} + task t3 = t1.then([&n]() { + pplx::details::atomic_add(n, 1L); // this should NOT execute, + }); -TEST(TestTaskOperators_when_all_cancellation) -{ - // A task that participates in a 'when all' operation is canceled and then throws an exception. Verify that value and task based continuations of the when - // all task see the exception. - extensibility::event_t evt1, evt2; + task t4 = t1.then([&n](task taskResult) { + pplx::details::atomic_add(n, 10L); // this should execute + }); + + task t5 = t2.then([&n]() { + pplx::details::atomic_add(n, 100L); // this should NOT execute + }); - cancellation_token_source ct; + task t6 = t2.then([&n](task taskResult) { + pplx::details::atomic_add(n, 1000L); // this should execute + taskResult.get(); // should throw 42 + pplx::details::atomic_add(n, 10000L); // this should NOT execute + }); - task t1([&evt1, &evt2](){ - evt2.set(); - evt1.wait(); - os_utilities::sleep(100); - throw 42; - }, ct.get_token()); + task t7 = t2.then([&n, this](task taskResult) { + try + { + taskResult.get(); + pplx::details::atomic_add(n, 100000L); // this should NOT execute + } + catch (int x) + { + IsTrue( + x == 42, + L"Incorrect integer exception was received in t7 from taskresult.get(). Expected: 42, Actual: %d", + x); + pplx::details::atomic_add(n, 1000000L); // this should execute + } + catch (task_canceled) + { + LogFailure(L"task_canceled was thrown by taskResult.get() in t7"); + } + catch (...) + { + LogFailure(L"A random exception was thrown by taskResult.get() in t7"); + } - task t2([](){ - helpers::DoRandomParallelWork(); - }); + throw 96; + }); - task t3([](){ - helpers::DoRandomParallelWork(); - }); + task t8 = (t6 || t7).then([&n, this](task taskResult) { + try + { + taskResult.get(); + pplx::details::atomic_add(n, 1000000L); // this should NOT execute + } + catch (int x) + { + IsTrue((x == 42 || x == 96), + L"Incorrect integer exception was received in t7 from taskresult.get(). Expected: 42 or 96, " + L"Actual: %d", + x); + pplx::details::atomic_add(n, 100000000L); // this should execute + } + catch (task_canceled) + { + LogFailure(L"(t6 || t7) was canceled without an exception"); + } + catch (...) + { + LogFailure(L"(t6 || t7) was canceled with an unexpected exception"); + } + }); - task whenAllTask = t1 && t2 && t3; + // Cancel t1 now that t2 is guaranteed canceled with an exception + evt2.wait(); + ct.cancel(); + evt1.set(); - task t4 = whenAllTask.then([this](task t){ - IsFalse(helpers::VerifyCanceled(t), L"%ws:%u:t should be canceled by token", __FILE__, __LINE__); - IsTrue(helpers::VerifyException(t), L"%ws:%u:exception from t is unexpected", __FILE__, __LINE__); - }); + try + { + task_status status = (t1 && t2).wait(); + IsTrue((status == canceled), + L"(t1 && t2).wait() did not return canceled. Expected: %d, Actual %d", + canceled, + status); + } + catch (int x) + { + IsTrue(x == 42, + L"Incorrect integer exception was received from (t1 && t2).wait(). Expected: 42, Actual: %d", + x); + } - task t5 = whenAllTask.then([this]() { - LogFailure(L"%ws:%u:t5 was unexpectedly executed", __FILE__, __LINE__); - }); + try + { + task_status status = t3.wait(); + IsTrue((status == canceled), + L"t3.wait() did not returned canceled. Expected: %d, Actual %d", + canceled, + status); + } + catch (task_canceled&) + { + LogFailure(L"t3.wait() threw task_canceled instead of returning canceled"); + } + catch (...) + { + LogFailure(L"t3.wait() threw an unexpected exception"); + } - evt2.wait(); - ct.cancel(); - evt1.set(); + try + { + task_status status = t4.wait(); + IsTrue((status == completed), + L"t4.wait() did not returned completed. Expected: %d, Actual %d", + completed, + status); + } + catch (...) + { + LogFailure(L"t4.wait() threw an unexpected exception"); + } - IsFalse(helpers::VerifyCanceled(t5), L"%ws:%u:t5 should be canceled", __FILE__, __LINE__); -} + try + { + t5.wait(); + LogFailure(L"t5.wait() did not throw an exception"); + } + catch (int x) + { + IsTrue(x == 42, L"Incorrect integer exception was received from t5.wait(). Expected: 42, Actual: %d", x); + } + // Observe the exceptions from t5, t6 and t7 + helpers::ObserveException(t5); + helpers::ObserveException(t6); + helpers::ObserveException(t7); -TEST(TestTaskOperators_when_all_cancellation_sequence) -{ - // A task that participates in a 'when all' operation throws an exception, but a continuation of the when all task is canceled before this point. - // Ensure that continuation does not get the exception but others do. - extensibility::event_t evt1, evt2; + try + { + (t1 || t6).get(); + LogFailure(L"(t1 || t6).get() should throw an exception."); + } + catch (task_canceled&) + { + LogFailure(L"(t1 || t6).get() threw task_canceled when an int was expected."); + } + catch (int x) + { + IsTrue( + (x == 42 || x == 96), + L"Incorrect integer exception was received from (t1 || t6 || t7).get(). Expected: 42 or 96, Actual: %d", + x); + } - cancellation_token_source ct; + t8.wait(); - task t1([&evt1, &evt2](){ - evt2.set(); - evt1.wait(); - os_utilities::sleep(100); - throw 42; - }); + IsTrue(n == 101001010L, + L"The right result was not obtained from the sequence of tasks that executed. Expected 101001010, " + L"actual %d", + 101001010, + static_cast(n)); + } - task t2([](){ - helpers::DoRandomParallelWork(); - }); + TEST(TestTaskOperators_when_all_cancellation) + { + // A task that participates in a 'when all' operation is canceled and then throws an exception. Verify that + // value and task based continuations of the when all task see the exception. + extensibility::event_t evt1, evt2; - task t3([](){ - helpers::DoRandomParallelWork(); - }); + cancellation_token_source ct; - task whenAllTask = t1 && t2 && t3; + task t1( + [&evt1, &evt2]() { + evt2.set(); + evt1.wait(); + os_utilities::sleep(100); + throw 42; + }, + ct.get_token()); - task t4 = whenAllTask.then([this](task t){ - IsFalse(helpers::VerifyCanceled(t), L"%ws:%u:t was unexpectedly canceled", __FILE__, __LINE__); - IsTrue(helpers::VerifyException(t), L"%ws:%u:Did not receive the correct exception from t", __FILE__, __LINE__); - }); + task t2([]() { helpers::DoRandomParallelWork(); }); - task t5 = whenAllTask.then([this]() { - LogFailure(L"%ws:%u:t5 was unexpectedly executed", __FILE__, __LINE__); - }); + task t3([]() { helpers::DoRandomParallelWork(); }); - task t6 = whenAllTask.then([this](task t){ - IsTrue(helpers::VerifyCanceled(t), L"%ws:%u:t was not canceled as expected", __FILE__, __LINE__); - }, ct.get_token()); + task whenAllTask = t1 && t2 && t3; - evt2.wait(); - ct.cancel(); - evt1.set(); + task t4 = whenAllTask.then([this](task t) { + IsFalse(helpers::VerifyCanceled(t), L"%ws:%u:t should be canceled by token", __FILE__, __LINE__); + IsTrue(helpers::VerifyException(t), L"%ws:%u:exception from t is unexpected", __FILE__, __LINE__); + }); - IsTrue(helpers::VerifyException(t5), L"%ws:%u:Did not receive the correct exception from t5", __FILE__, __LINE__); -} + task t5 = + whenAllTask.then([this]() { LogFailure(L"%ws:%u:t5 was unexpectedly executed", __FILE__, __LINE__); }); -TEST(TestTaskOperators_and_cancellation_multiple_tokens) -// -// operator&& with differing tokens: -// -{ - cancellation_token_source ct1; - cancellation_token_source ct2; - cancellation_token_source ct3; - cancellation_token_source ct4; + evt2.wait(); + ct.cancel(); + evt1.set(); + IsFalse(helpers::VerifyCanceled(t5), L"%ws:%u:t5 should be canceled", __FILE__, __LINE__); + } - task t1( []() -> int { - return 42; - }, ct1.get_token()); + TEST(TestTaskOperators_when_all_cancellation_sequence) + { + // A task that participates in a 'when all' operation throws an exception, but a continuation of the when all + // task is canceled before this point. Ensure that continuation does not get the exception but others do. + extensibility::event_t evt1, evt2; - task t2( []() -> int { - return 77; - }, ct2.get_token()); + cancellation_token_source ct; - task t3( []() -> int { - return 92; - }, ct3.get_token()); + task t1([&evt1, &evt2]() { + evt2.set(); + evt1.wait(); + os_utilities::sleep(100); + throw 42; + }); - task t4( []() -> int { - return 147; - }, ct4.get_token()); + task t2([]() { helpers::DoRandomParallelWork(); }); - auto t5 = t1 && t2 && t3 && t4; + task t3([]() { helpers::DoRandomParallelWork(); }); - extensibility::event_t ev1, ev2; + task whenAllTask = t1 && t2 && t3; - auto t6 = t5.then( [&ev1, &ev2](std::vector iVec) -> int { - ev2.set(); - ev1.wait(); - return iVec[0] + iVec[1] + iVec[2] + iVec[3]; - }); + task t4 = whenAllTask.then([this](task t) { + IsFalse(helpers::VerifyCanceled(t), L"%ws:%u:t was unexpectedly canceled", __FILE__, __LINE__); + IsTrue(helpers::VerifyException(t), + L"%ws:%u:Did not receive the correct exception from t", + __FILE__, + __LINE__); + }); - auto t7 = t6.then( [](int val) -> int { - return val; - }); + task t5 = + whenAllTask.then([this]() { LogFailure(L"%ws:%u:t5 was unexpectedly executed", __FILE__, __LINE__); }); - ev2.wait(); - ct3.cancel(); - ev1.set(); - t6.wait(); - t7.wait(); + task t6 = whenAllTask.then( + [this](task t) { + IsTrue(helpers::VerifyCanceled(t), L"%ws:%u:t was not canceled as expected", __FILE__, __LINE__); + }, + ct.get_token()); - bool caughtCanceled = false; + evt2.wait(); + ct.cancel(); + evt1.set(); - try - { - t7.get(); - } - catch(task_canceled&) - { - caughtCanceled = true; + IsTrue(helpers::VerifyException(t5), + L"%ws:%u:Did not receive the correct exception from t5", + __FILE__, + __LINE__); } - IsTrue(caughtCanceled, L"Cancellation token was not joined/inherited on operator&&"); -} - -struct TestException1 -{ -}; - -struct TestException2 -{ -}; + TEST(TestTaskOperators_and_cancellation_multiple_tokens) + // + // operator&& with differing tokens: + // + { + cancellation_token_source ct1; + cancellation_token_source ct2; + cancellation_token_source ct3; + cancellation_token_source ct4; -// CodePlex 292 -static int ThrowFunc() -{ - throw 42; -} + task t1([]() -> int { return 42; }, ct1.get_token()); -TEST(TestContinuationsWithTask1) -{ - int n2 = 0; + task t2([]() -> int { return 77; }, ct2.get_token()); - task t([&]() -> int { - return 10; - }); + task t3([]() -> int { return 92; }, ct3.get_token()); - t.then([&] (task ti) { - n2 = ti.get(); - }).wait(); + task t4([]() -> int { return 147; }, ct4.get_token()); - VERIFY_IS_TRUE(n2 == 10); -} + auto t5 = t1 && t2 && t3 && t4; -TEST(TestContinuationsWithTask2) -{ - int n = 0; + extensibility::event_t ev1, ev2; - task tt1([](){}); - auto tt2 = tt1.then([&]()-> task { - task tt3([&](){ - n = 1; + auto t6 = t5.then([&ev1, &ev2](std::vector iVec) -> int { + ev2.set(); + ev1.wait(); + return iVec[0] + iVec[1] + iVec[2] + iVec[3]; }); - return tt3; - }); - tt2.get(); - VERIFY_IS_TRUE(n == 1); + auto t7 = t6.then([](int val) -> int { return val; }); - task tt4 = tt2.then([&]()-> task { - task tt5([&](){ - n = 2; - }); - return tt5; - }); - tt4.get(); - VERIFY_IS_TRUE(n == 2); -} + ev2.wait(); + ct3.cancel(); + ev1.set(); + t6.wait(); + t7.wait(); + + bool caughtCanceled = false; -TEST(TestContinuationsWithTask3) -{ - bool gotException = true; - int n2 = 0; - task t(ThrowFunc); - t.then([&] (task ti) { try { - ti.get(); - gotException = false; + t7.get(); } - catch (int) + catch (task_canceled&) { - n2 = 20; + caughtCanceled = true; } - }).wait(); - VERIFY_IS_TRUE(gotException); - VERIFY_IS_TRUE(n2 == 20); -} + IsTrue(caughtCanceled, L"Cancellation token was not joined/inherited on operator&&"); + } -TEST(TestContinuationsWithTask4) -{ - int n2 = 0; + struct TestException1 + { + }; - task t([&]() -> int { - return 10; - }); + struct TestException2 + { + }; - t.then([&] (int n) -> task { - task t2([n]() -> int { - return n+10; - }); - return t2; - }).then([&](int n) { - n2 = n; - }).wait(); + // CodePlex 292 + static int ThrowFunc() { throw 42; } - VERIFY_IS_TRUE(n2 == 20); -} + TEST(TestContinuationsWithTask1) + { + int n2 = 0; -TEST(TestContinuationsWithTask5) -{ - int n2 = 0; + task t([&]() -> int { return 10; }); - task t([&]() -> int { - return 10; - }); + t.then([&](task ti) { n2 = ti.get(); }).wait(); - t.then([&] (task tn) -> task { - int n = tn.get(); - task t2([n]() -> int { - return n+10; - }); - return t2; - }).then([&](task n) { - n2 = n.get(); - }).wait(); + VERIFY_IS_TRUE(n2 == 10); + } - VERIFY_IS_TRUE(n2 == 20); -} + TEST(TestContinuationsWithTask2) + { + int n = 0; -TEST(TestContinuationsWithTask6) -{ - pplx::details::atomic_long hit(0); - auto * hitptr = &hit; - task t([](){ - return 10; - }); - - auto ot = t.then([hitptr](int n) -> task { - auto hitptr1 = hitptr; - task it([n, hitptr1]() -> int { - os_utilities::sleep(100); - pplx::details::atomic_exchange(*hitptr1, 1L); - return n * 2; + task tt1([]() {}); + auto tt2 = tt1.then([&]() -> task { + task tt3([&]() { n = 1; }); + return tt3; }); - return it; - }); + tt2.get(); + VERIFY_IS_TRUE(n == 1); - int value = ot.get(); - VERIFY_IS_TRUE(value == 20 && hit != 0); -} + task tt4 = tt2.then([&]() -> task { + task tt5([&]() { n = 2; }); + return tt5; + }); + tt4.get(); + VERIFY_IS_TRUE(n == 2); + } -TEST(TestContinuationsWithTask7) -{ - volatile long hit = 0; - volatile long * hitptr = &hit; + TEST(TestContinuationsWithTask3) + { + bool gotException = true; + int n2 = 0; + task t(ThrowFunc); + t.then([&](task ti) { + try + { + ti.get(); + gotException = false; + } + catch (int) + { + n2 = 20; + } + }) + .wait(); + + VERIFY_IS_TRUE(gotException); + VERIFY_IS_TRUE(n2 == 20); + } - task t([](){ - return 10; - }); + TEST(TestContinuationsWithTask4) + { + int n2 = 0; - auto ot = t.then( [hitptr](int n) -> task { - task it([n, hitptr]() -> int { - throw TestException1(); - }); + task t([&]() -> int { return 10; }); - return it; - }); + t.then([&](int n) -> task { + task t2([n]() -> int { return n + 10; }); + return t2; + }) + .then([&](int n) { n2 = n; }) + .wait(); - VERIFY_IS_TRUE(helpers::VerifyException(ot)); -} + VERIFY_IS_TRUE(n2 == 20); + } -TEST(TestContinuationsWithTask8) -{ - volatile long hit = 0; - volatile long * hitptr = &hit; + TEST(TestContinuationsWithTask5) + { + int n2 = 0; - task t([](){ - return 10; - }); + task t([&]() -> int { return 10; }); - auto ot = t.then( [hitptr](int n) -> task { - volatile long * hitptr1 = hitptr; - task it([n, hitptr1]() -> int { - os_utilities::sleep(100); - os_utilities::interlocked_exchange(hitptr1, 1); + t.then([&](task tn) -> task { + int n = tn.get(); + task t2([n]() -> int { return n + 10; }); + return t2; + }) + .then([&](task n) { n2 = n.get(); }) + .wait(); - // This test is needed to disable an optimizer dead-code check that - // winds up generating errors in VS 2010. - if ( n == 10 ) - throw TestException2(); + VERIFY_IS_TRUE(n2 == 20); + } + + TEST(TestContinuationsWithTask6) + { + pplx::details::atomic_long hit(0); + auto* hitptr = &hit; + task t([]() { return 10; }); + + auto ot = t.then([hitptr](int n) -> task { + auto hitptr1 = hitptr; + task it([n, hitptr1]() -> int { + os_utilities::sleep(100); + pplx::details::atomic_exchange(*hitptr1, 1L); + return n * 2; + }); - return n * 3; + return it; }); - return it; - }); + int value = ot.get(); + VERIFY_IS_TRUE(value == 20 && hit != 0); + } - VERIFY_IS_TRUE(helpers::VerifyException(ot), "(7) Inner task exception not propagated out of outer .get()"); - VERIFY_IS_TRUE(hit != 0, "(7) Expected inner task hit marker to be set!"); -} + TEST(TestContinuationsWithTask7) + { + volatile long hit = 0; + volatile long* hitptr = &hit; -TEST(TestContinuationsWithTask9) -{ - volatile long hit = 0; - volatile long * hitptr = &hit; - extensibility::event_t e; - task it; - - task t([](){ - return 10; - }); - - auto ot = t.then( [hitptr, &it, &e](int n) -> task { - volatile long * hitptr1 = hitptr; - it = task([hitptr1, n]() -> int { - os_utilities::interlocked_exchange(hitptr1, 1); - // This test is needed to disable an optimizer dead-code check that - // winds up generating errors in VS 2010. - if ( n == 10 ) - throw TestException1(); - return n * 5; + task t([]() { return 10; }); + + auto ot = t.then([hitptr](int n) -> task { + task it([n, hitptr]() -> int { throw TestException1(); }); + + return it; }); - e.set(); - os_utilities::sleep(100); - // This test is needed to disable an optimizer dead-code check that - // winds up generating errors in VS 2010. - if ( n == 10 ) - throw TestException2(); - return it; - }); + VERIFY_IS_TRUE(helpers::VerifyException(ot)); + } + + TEST(TestContinuationsWithTask8) + { + volatile long hit = 0; + volatile long* hitptr = &hit; - e.wait(); + task t([]() { return 10; }); - VERIFY_IS_TRUE(helpers::VerifyException(ot), "(8) Outer task exception not propagated when inner task also throws"); - VERIFY_IS_TRUE(helpers::VerifyException(it), "(8) Inner task exception not explicitly propgated on pass out / get"); - VERIFY_IS_TRUE(hit != 0, "(8) Inner hit marker expected!"); -} + auto ot = t.then([hitptr](int n) -> task { + volatile long* hitptr1 = hitptr; + task it([n, hitptr1]() -> int { + os_utilities::sleep(100); + os_utilities::interlocked_exchange(hitptr1, 1); -TEST(TestContinuationsWithTask10) -{ - volatile long hit = 0; + // This test is needed to disable an optimizer dead-code check that + // winds up generating errors in VS 2010. + if (n == 10) throw TestException2(); - task t([](){ - return 10; - }); + return n * 3; + }); - auto ot = t.then( [&](int n) -> task { - task it([&, n]() -> int { - os_utilities::sleep(100); - // This test is needed to disable an optimizer dead-code check that - // winds up generating errors in VS 2010. - if ( n == 10 ) - throw TestException1(); - return n * 6; + return it; }); - return it; - }); - - auto otc = ot.then( [&](task itp){ - os_utilities::interlocked_exchange(&hit, 1); - VERIFY_IS_TRUE(helpers::VerifyException(itp), "(9) Outer task exception handling continuation did not get plumbed inner exception"); - }); - VERIFY_IS_TRUE(helpers::VerifyException(ot), "(9) Inner task exception not propagated correctly"); - helpers::ObserveException(otc); - VERIFY_IS_TRUE(hit != 0, "(9) Outer task exception handling continuation did not run!"); -} + VERIFY_IS_TRUE(helpers::VerifyException(ot), + "(7) Inner task exception not propagated out of outer .get()"); + VERIFY_IS_TRUE(hit != 0, "(7) Expected inner task hit marker to be set!"); + } -TEST(TestUnwrappingCtors) -{ - int res; + TEST(TestContinuationsWithTask9) { - // take task in the ctor + volatile long hit = 0; + volatile long* hitptr = &hit; + extensibility::event_t e; + task it; + + task t([]() { return 10; }); + + auto ot = t.then([hitptr, &it, &e](int n) -> task { + volatile long* hitptr1 = hitptr; + it = task([hitptr1, n]() -> int { + os_utilities::interlocked_exchange(hitptr1, 1); + // This test is needed to disable an optimizer dead-code check that + // winds up generating errors in VS 2010. + if (n == 10) throw TestException1(); + return n * 5; + }); - task ti([]() -> int { - return 1; + e.set(); + os_utilities::sleep(100); + // This test is needed to disable an optimizer dead-code check that + // winds up generating errors in VS 2010. + if (n == 10) throw TestException2(); + return it; }); - // Must unwrap: - task t1(ti); - res = t1.get(); - VERIFY_IS_TRUE(res==1, "unexpected value in TestUnwrappingCtors, location 1"); + e.wait(); + + VERIFY_IS_TRUE(helpers::VerifyException(ot), + "(8) Outer task exception not propagated when inner task also throws"); + VERIFY_IS_TRUE(helpers::VerifyException(it), + "(8) Inner task exception not explicitly propgated on pass out / get"); + VERIFY_IS_TRUE(hit != 0, "(8) Inner hit marker expected!"); } + TEST(TestContinuationsWithTask10) { - // take lambda returning task in the ctor + volatile long hit = 0; - // Must NOT unwrap: - task> t1([]() -> task { - task ti([]() -> int { - return 1; + task t([]() { return 10; }); + + auto ot = t.then([&](int n) -> task { + task it([&, n]() -> int { + os_utilities::sleep(100); + // This test is needed to disable an optimizer dead-code check that + // winds up generating errors in VS 2010. + if (n == 10) throw TestException1(); + return n * 6; }); - return ti; + return it; }); - res = t1.get().get(); - VERIFY_IS_TRUE(res==1, "unexpected value in TestUnwrappingCtors, location 2"); - // Must unwrap: - task t2([]() -> task { - task ti([]() -> int { - return 2; - }); - return ti; + auto otc = ot.then([&](task itp) { + os_utilities::interlocked_exchange(&hit, 1); + VERIFY_IS_TRUE(helpers::VerifyException(itp), + "(9) Outer task exception handling continuation did not get plumbed inner exception"); }); - res = t2.get(); - VERIFY_IS_TRUE(res==2, "unexpected value in TestUnwrappingCtors, location 3"); - res = t2.then([](int n) { return n+1; }).get(); - VERIFY_IS_TRUE(res==3, "unexpected value in TestUnwrappingCtors, location 4"); + VERIFY_IS_TRUE(helpers::VerifyException(ot), + "(9) Inner task exception not propagated correctly"); + helpers::ObserveException(otc); + VERIFY_IS_TRUE(hit != 0, "(9) Outer task exception handling continuation did not run!"); } + TEST(TestUnwrappingCtors) { - int executed = 0; - // take task in the ctor - task ti([&]() { - executed = 1; - }); + int res; + { + // take task in the ctor - // Must unwrap: - task t1(ti); - t1.wait(); - VERIFY_IS_TRUE(executed==1, "unexpected value in TestUnwrappingCtors, location 5"); - } + task ti([]() -> int { return 1; }); - { - // take lambda returning task in the ctor + // Must unwrap: + task t1(ti); + res = t1.get(); + VERIFY_IS_TRUE(res == 1, "unexpected value in TestUnwrappingCtors, location 1"); + } - int executed = 0; - int * executedPtr = &executed; + { + // take lambda returning task in the ctor - // Must NOT unwrap: - task> t1([executedPtr]() -> task { - auto executedPtr1 = executedPtr; - task ti([executedPtr1]() { - *executedPtr1 = 1; + // Must NOT unwrap: + task> t1([]() -> task { + task ti([]() -> int { return 1; }); + return ti; }); - return ti; - }); - t1.get().get(); - VERIFY_IS_TRUE(executed==1, "unexpected value in TestUnwrappingCtors, location 6"); - - task t2([](){}); - // Must unwrap: - taskt3 = t2.then([executedPtr]()-> task { - auto executedPtr1 = executedPtr; - task ti([executedPtr1](){ - *executedPtr1 = 2; + res = t1.get().get(); + VERIFY_IS_TRUE(res == 1, "unexpected value in TestUnwrappingCtors, location 2"); + + // Must unwrap: + task t2([]() -> task { + task ti([]() -> int { return 2; }); + return ti; }); - return ti; - }); + res = t2.get(); + VERIFY_IS_TRUE(res == 2, "unexpected value in TestUnwrappingCtors, location 3"); - t3.wait(); - VERIFY_IS_TRUE(executed==2, "unexpected value in TestUnwrappingCtors, location 7"); + res = t2.then([](int n) { return n + 1; }).get(); + VERIFY_IS_TRUE(res == 3, "unexpected value in TestUnwrappingCtors, location 4"); + } - // Must unwrap: - task t4([executedPtr]() -> task { - auto executedPtr1 = executedPtr; - task ti([executedPtr1]() { - *executedPtr1 = 3; - }); - return ti; - }); - t4.wait(); - VERIFY_IS_TRUE(executed==3, "unexpected value in TestUnwrappingCtors, location 8"); + { + int executed = 0; + // take task in the ctor + task ti([&]() { executed = 1; }); - t4.then([&]() { executed++; }).wait(); - VERIFY_IS_TRUE(executed==4, "unexpected value in TestUnwrappingCtors, location 9"); - } + // Must unwrap: + task t1(ti); + t1.wait(); + VERIFY_IS_TRUE(executed == 1, "unexpected value in TestUnwrappingCtors, location 5"); + } - { - res = create_task([]() -> task { - return create_task([]() -> int { - return 1; + { + // take lambda returning task in the ctor + + int executed = 0; + int* executedPtr = &executed; + + // Must NOT unwrap: + task> t1([executedPtr]() -> task { + auto executedPtr1 = executedPtr; + task ti([executedPtr1]() { *executedPtr1 = 1; }); + return ti; + }); + t1.get().get(); + VERIFY_IS_TRUE(executed == 1, "unexpected value in TestUnwrappingCtors, location 6"); + + task t2([]() {}); + // Must unwrap: + task t3 = t2.then([executedPtr]() -> task { + auto executedPtr1 = executedPtr; + task ti([executedPtr1]() { *executedPtr1 = 2; }); + return ti; }); - }).get(); - VERIFY_IS_TRUE(res==1, "unexpected value in TestUnwrappingCtors, create_task, location 1"); - create_task([]() -> task { - return create_task([]() { + t3.wait(); + VERIFY_IS_TRUE(executed == 2, "unexpected value in TestUnwrappingCtors, location 7"); + + // Must unwrap: + task t4([executedPtr]() -> task { + auto executedPtr1 = executedPtr; + task ti([executedPtr1]() { *executedPtr1 = 3; }); + return ti; }); - }).wait(); - } - - { - // BUG TFS: 344954 - cancellation_token_source cts, cts2; - cts.cancel(); // Commenting this line out makes the program work! - // Create a task that is always cancelled - auto falseTask = create_task([]() {}, cts.get_token()); - cancellation_token ct2 = cts2.get_token(); - create_task([falseTask]() { - // Task unwrapping! - // This should not crash - return falseTask; - }, ct2).then([this, falseTask, ct2](task t) -> task { - VERIFY_IS_TRUE(t.wait() == canceled, "unexpected value in TestUnwrappingCtors, cancellation token, location 1"); - VERIFY_IS_TRUE(!ct2.is_canceled(), "unexpected value in TestUnwrappingCtors, cancellation token, location 2"); - // again, unwrapping in continuation - // this should not crash - return falseTask; - }).then([this] { - VERIFY_IS_TRUE(false, "unexpected path in TestUnwrappingCtors, cancellation token, location 3"); - }); + t4.wait(); + VERIFY_IS_TRUE(executed == 3, "unexpected value in TestUnwrappingCtors, location 8"); + + t4.then([&]() { executed++; }).wait(); + VERIFY_IS_TRUE(executed == 4, "unexpected value in TestUnwrappingCtors, location 9"); + } + + { + res = create_task([]() -> task { return create_task([]() -> int { return 1; }); }).get(); + VERIFY_IS_TRUE(res == 1, "unexpected value in TestUnwrappingCtors, create_task, location 1"); + + create_task([]() -> task { return create_task([]() {}); }).wait(); + } + + { + // BUG TFS: 344954 + cancellation_token_source cts, cts2; + cts.cancel(); // Commenting this line out makes the program work! + // Create a task that is always cancelled + auto falseTask = create_task([]() {}, cts.get_token()); + cancellation_token ct2 = cts2.get_token(); + create_task( + [falseTask]() { + // Task unwrapping! + // This should not crash + return falseTask; + }, + ct2) + .then([this, falseTask, ct2](task t) -> task { + VERIFY_IS_TRUE(t.wait() == canceled, + "unexpected value in TestUnwrappingCtors, cancellation token, location 1"); + VERIFY_IS_TRUE(!ct2.is_canceled(), + "unexpected value in TestUnwrappingCtors, cancellation token, location 2"); + // again, unwrapping in continuation + // this should not crash + return falseTask; + }) + .then([this] { + VERIFY_IS_TRUE(false, "unexpected path in TestUnwrappingCtors, cancellation token, location 3"); + }); + } } -} - -TEST(TestNestedTasks) -{ + TEST(TestNestedTasks) { - task rootTask([]() -> int { return 234; }); + { + task rootTask([]() -> int { return 234; }); - task> resultTask = rootTask.then([](int value) -> task> { - return task>([=]() -> task { - auto val1 = value; - return task([=]() -> int { - return val1 + 22; + task> resultTask = rootTask.then([](int value) -> task> { + return task>([=]() -> task { + auto val1 = value; + return task([=]() -> int { return val1 + 22; }); }); }); - }); - int n = resultTask.get().get(); - VERIFY_IS_TRUE(n==256, "TestNestedTasks_1"); - } - - { - // Same for void task - int flag = 1; - int * flagptr = &flag; - task rootTask([&]() { flag++; }); + int n = resultTask.get().get(); + VERIFY_IS_TRUE(n == 256, "TestNestedTasks_1"); + } - task> resultTask = rootTask.then([flagptr]() -> task> { - auto flag1 = flagptr; - return task>([flag1]() -> task - { - auto flag2 = flag1; - return task([flag2]() - { - ++(flag2[0]); + // Same for void task + int flag = 1; + int* flagptr = &flag; + task rootTask([&]() { flag++; }); + + task> resultTask = rootTask.then([flagptr]() -> task> { + auto flag1 = flagptr; + return task>([flag1]() -> task { + auto flag2 = flag1; + return task([flag2]() { ++(flag2[0]); }); }); }); - }); - resultTask.get().wait(); - VERIFY_IS_TRUE(flag==3, "TestNestedTasks_2"); - } + resultTask.get().wait(); + VERIFY_IS_TRUE(flag == 3, "TestNestedTasks_2"); + } - { - task rootTask([]() -> int { return 234; }); + { + task rootTask([]() -> int { return 234; }); - task>> - resultTask = rootTask.then([](int value) -> task>> { - return task>>([=]() -> task> { - auto v1 = value; - return task>([=]() -> task { - auto v2 = v1; - return task([=]() -> int { - return v2 + 22; + task>> resultTask = rootTask.then([](int value) -> task>> { + return task>>([=]() -> task> { + auto v1 = value; + return task>([=]() -> task { + auto v2 = v1; + return task([=]() -> int { return v2 + 22; }); }); }); }); - }); - int n = resultTask.get().get().get(); - VERIFY_IS_TRUE(n==256, "TestNestedTasks_3"); - } + int n = resultTask.get().get().get(); + VERIFY_IS_TRUE(n == 256, "TestNestedTasks_3"); + } - { - task nestedTask; - task unwrap([&]() -> task { - nestedTask = task([]() { - cancel_current_task(); + { + task nestedTask; + task unwrap([&]() -> task { + nestedTask = task([]() { cancel_current_task(); }); + return nestedTask; }); - return nestedTask; - }); - task_status st = unwrap.wait(); - VERIFY_IS_TRUE(st==canceled, "TestNestedTasks_4"); - st = nestedTask.wait(); - VERIFY_IS_TRUE(st==canceled, "TestNestedTasks_5 "); + task_status st = unwrap.wait(); + VERIFY_IS_TRUE(st == canceled, "TestNestedTasks_4"); + st = nestedTask.wait(); + VERIFY_IS_TRUE(st == canceled, "TestNestedTasks_5 "); + } } -} -template -task async_for(int start, int step, int end, Function func) -{ - if (start < end) + template + task async_for(int start, int step, int end, Function func) { - return func(start).then([=] () -> task + if (start < end) { - return async_for(start + step, step, end, func); - }); - } - else - { - return task([]{}); + return func(start).then([=]() -> task { return async_for(start + step, step, end, func); }); + } + else + { + return task([] {}); + } } -} -TEST(TestInlineChunker) -{ - const int numiter = 1000; - volatile int sum = 0; - async_for(0, 1, numiter, [&](int) -> task + TEST(TestInlineChunker) { - sum++; - return create_task([]() {}); - }).wait(); - - VERIFY_IS_TRUE(sum == numiter, "TestInlineChunker: async_for did not return correct result."); -} + const int numiter = 1000; + volatile int sum = 0; + async_for(0, + 1, + numiter, + [&](int) -> task { + sum++; + return create_task([]() {}); + }) + .wait(); + + VERIFY_IS_TRUE(sum == numiter, "TestInlineChunker: async_for did not return correct result."); + } #if defined(_WIN32) && (_MSC_VER >= 1700) && (_MSC_VER < 1800) -TEST(PPL_Conversions_basic) -{ - pplx::task t1([]{ return 1;}); - concurrency::task t2 = pplx::pplx_task_to_concurrency_task(t1); - int n = t2.get(); - VERIFY_ARE_EQUAL(n,1); - - pplx::task t3 = pplx::concurrency_task_to_pplx_task(t2); - int n2 = t3.get(); - VERIFY_ARE_EQUAL(n2,1); -} - -TEST(PPL_Conversions_Nested) -{ - pplx::task t1([]{ return 12;}); - pplx::task t2 = pplx::concurrency_task_to_pplx_task(pplx::pplx_task_to_concurrency_task(pplx::concurrency_task_to_pplx_task(pplx::pplx_task_to_concurrency_task(t1)))); - int n = t2.get(); - VERIFY_ARE_EQUAL(n,12); -} - -TEST(PPL_Conversions_Exceptions) -{ - pplx::task t1(ThrowFunc); - concurrency::task t2 = pplx::pplx_task_to_concurrency_task(t1); - try + TEST(PPL_Conversions_basic) { - t2.get(); - VERIFY_IS_TRUE(false); - } - catch(int m) - { - VERIFY_ARE_EQUAL(m,42); + pplx::task t1([] { return 1; }); + concurrency::task t2 = pplx::pplx_task_to_concurrency_task(t1); + int n = t2.get(); + VERIFY_ARE_EQUAL(n, 1); + + pplx::task t3 = pplx::concurrency_task_to_pplx_task(t2); + int n2 = t3.get(); + VERIFY_ARE_EQUAL(n2, 1); } - pplx::task t3 = pplx::concurrency_task_to_pplx_task(t2); - try + TEST(PPL_Conversions_Nested) { - t3.get(); - VERIFY_IS_TRUE(false); - } - catch(int m) - { - VERIFY_ARE_EQUAL(m,42); + pplx::task t1([] { return 12; }); + pplx::task t2 = pplx::concurrency_task_to_pplx_task(pplx::pplx_task_to_concurrency_task( + pplx::concurrency_task_to_pplx_task(pplx::pplx_task_to_concurrency_task(t1)))); + int n = t2.get(); + VERIFY_ARE_EQUAL(n, 12); } -} -TEST(PPL_Conversions_Basic_void) -{ - pplx::task t1([]{}); - concurrency::task t2 = pplx::pplx_task_to_concurrency_task(t1); - t2.get(); + TEST(PPL_Conversions_Exceptions) + { + pplx::task t1(ThrowFunc); + concurrency::task t2 = pplx::pplx_task_to_concurrency_task(t1); + try + { + t2.get(); + VERIFY_IS_TRUE(false); + } + catch (int m) + { + VERIFY_ARE_EQUAL(m, 42); + } - pplx::task t3 = pplx::concurrency_task_to_pplx_task(t2); - t3.get(); -} + pplx::task t3 = pplx::concurrency_task_to_pplx_task(t2); + try + { + t3.get(); + VERIFY_IS_TRUE(false); + } + catch (int m) + { + VERIFY_ARE_EQUAL(m, 42); + } + } -TEST(PPL_Conversions_Exceptions_void) -{ - pplx::task t1([]() { throw 3;}); - concurrency::task t2 = pplx::pplx_task_to_concurrency_task(t1); - try + TEST(PPL_Conversions_Basic_void) { + pplx::task t1([] {}); + concurrency::task t2 = pplx::pplx_task_to_concurrency_task(t1); t2.get(); - VERIFY_IS_TRUE(false); - } - catch(int m) - { - VERIFY_ARE_EQUAL(m,3); - } - pplx::task t3 = pplx::concurrency_task_to_pplx_task(t2); - try - { + pplx::task t3 = pplx::concurrency_task_to_pplx_task(t2); t3.get(); - VERIFY_IS_TRUE(false); } - catch(int m) + + TEST(PPL_Conversions_Exceptions_void) { - VERIFY_ARE_EQUAL(m,3); + pplx::task t1([]() { throw 3; }); + concurrency::task t2 = pplx::pplx_task_to_concurrency_task(t1); + try + { + t2.get(); + VERIFY_IS_TRUE(false); + } + catch (int m) + { + VERIFY_ARE_EQUAL(m, 3); + } + + pplx::task t3 = pplx::concurrency_task_to_pplx_task(t2); + try + { + t3.get(); + VERIFY_IS_TRUE(false); + } + catch (int m) + { + VERIFY_ARE_EQUAL(m, 3); + } } -} #endif } // SUITE(pplxtask_tests) -}}} // namespaces +} // namespace PPLX +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/pplx/pplx_test/stdafx.cpp b/Release/tests/functional/pplx/pplx_test/stdafx.cpp index 5b0483c91b..155f888eae 100644 --- a/Release/tests/functional/pplx/pplx_test/stdafx.cpp +++ b/Release/tests/functional/pplx/pplx_test/stdafx.cpp @@ -1,10 +1,10 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ -// stdafx.cpp : + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ +// stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" diff --git a/Release/tests/functional/pplx/pplx_test/stdafx.h b/Release/tests/functional/pplx/pplx_test/stdafx.h index f73ecaec0d..7c2d53ab4f 100644 --- a/Release/tests/functional/pplx/pplx_test/stdafx.h +++ b/Release/tests/functional/pplx/pplx_test/stdafx.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -16,13 +16,12 @@ #include #endif -#include +#include "pplx/pplxtasks.h" #include #include #include #include - -#include "pplx/pplxtasks.h" +#include #if defined(_WIN32) #include "pplx/pplxconv.h" @@ -31,5 +30,5 @@ #endif #include "cpprest/asyncrt_utils.h" -#include "unittestpp.h" #include "os_utilities.h" +#include "unittestpp.h" diff --git a/Release/tests/functional/streams/CppSparseFile.cpp b/Release/tests/functional/streams/CppSparseFile.cpp index a14a5e3b37..a4afc6fd17 100644 --- a/Release/tests/functional/streams/CppSparseFile.cpp +++ b/Release/tests/functional/streams/CppSparseFile.cpp @@ -3,7 +3,7 @@ * Project: CppSparseFile * URL: http://code.msdn.microsoft.com/windowsapps/CppSparseFile-7f28156b * Copyright (c) Microsoft Corporation. -* +* * CppSparseFile demonstrates the common operations on sparse files. A sparse * file is a type of computer file that attempts to use file system space more * efficiently when blocks allocated to the file are mostly empty. This is @@ -12,11 +12,11 @@ * block, using less disk space. You can find in this example the creation of * sparse file, the detection of sparse attribute, the retrieval of sparse * file size, and the query of sparse file layout. -* +* * This source is subject to the Microsoft Public License. * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. * All other rights reserved. -* +* * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. @@ -24,39 +24,35 @@ #pragma region Includes #include "stdafx.h" + #include "CppSparseFile.h" #pragma endregion - /*! -* VolumeSupportsSparseFiles determines if the volume supports sparse streams. -* -* \param lpRootPathName -* Volume root path e.g. C:\ -*/ + * VolumeSupportsSparseFiles determines if the volume supports sparse streams. + * + * \param lpRootPathName + * Volume root path e.g. C:\ + */ BOOL VolumeSupportsSparseFiles(LPCTSTR lpRootPathName) { DWORD dwVolFlags; - GetVolumeInformation(lpRootPathName, NULL, MAX_PATH, NULL, NULL, - &dwVolFlags, NULL, MAX_PATH); + GetVolumeInformation(lpRootPathName, NULL, MAX_PATH, NULL, NULL, &dwVolFlags, NULL, MAX_PATH); return (dwVolFlags & FILE_SUPPORTS_SPARSE_FILES) ? TRUE : FALSE; } - /*! -* IsSparseFile determines if a file is sparse. -* -* \param lpFileName -* File name -*/ + * IsSparseFile determines if a file is sparse. + * + * \param lpFileName + * File name + */ BOOL IsSparseFile(LPCTSTR lpFileName) { // Open the file for read - HANDLE hFile = CreateFile(lpFileName, GENERIC_READ, 0, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; + HANDLE hFile = CreateFile(lpFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return FALSE; // Get file information BY_HANDLE_FILE_INFORMATION bhfi; @@ -66,89 +62,81 @@ BOOL IsSparseFile(LPCTSTR lpFileName) return (bhfi.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) ? TRUE : FALSE; } - /*! -* Get sparse file sizes. -* -* \param lpFileName -* File name -* -* \see -* http://msdn.microsoft.com/en-us/library/aa365276.aspx -*/ + * Get sparse file sizes. + * + * \param lpFileName + * File name + * + * \see + * http://msdn.microsoft.com/en-us/library/aa365276.aspx + */ BOOL GetSparseFileSize(LPCTSTR lpFileName) { // Retrieves the size of the specified file, in bytes. The size includes // both allocated ranges and sparse ranges. - HANDLE hFile = CreateFile(lpFileName, GENERIC_READ, 0, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; + HANDLE hFile = CreateFile(lpFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return FALSE; LARGE_INTEGER liSparseFileSize; GetFileSizeEx(hFile, &liSparseFileSize); // Retrieves the file's actual size on disk, in bytes. The size does not // include the sparse ranges. LARGE_INTEGER liSparseFileCompressedSize; - liSparseFileCompressedSize.LowPart = GetCompressedFileSize(lpFileName, - (LPDWORD)&liSparseFileCompressedSize.HighPart); + liSparseFileCompressedSize.LowPart = + GetCompressedFileSize(lpFileName, (LPDWORD)&liSparseFileCompressedSize.HighPart); // Print the result wprintf(L"\nFile total size: %I64uKB\nActual size on disk: %I64uKB\n", - liSparseFileSize.QuadPart / 1024, - liSparseFileCompressedSize.QuadPart / 1024); + liSparseFileSize.QuadPart / 1024, + liSparseFileCompressedSize.QuadPart / 1024); CloseHandle(hFile); return TRUE; } - /*! -* Create a sparse file. -* -* \param lpFileName -* The name of the sparse file -*/ + * Create a sparse file. + * + * \param lpFileName + * The name of the sparse file + */ HANDLE CreateSparseFile(LPCTSTR lpFileName) { // Create a normal file - HANDLE hSparseFile = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE hSparseFile = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (hSparseFile == INVALID_HANDLE_VALUE) - return hSparseFile; + if (hSparseFile == INVALID_HANDLE_VALUE) return hSparseFile; // Use the DeviceIoControl function with the FSCTL_SET_SPARSE control // code to mark the file as sparse. If you don't mark the file as sparse, // the FSCTL_SET_ZERO_DATA control code will actually write zero bytes to // the file instead of marking the region as sparse zero area. DWORD dwTemp; - DeviceIoControl(hSparseFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, - NULL); + DeviceIoControl(hSparseFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, NULL); return hSparseFile; } - /*! -* Converting a file region to A sparse zero area. -* -* \param hSparseFile -* Handle of the sparse file -* -* \param start -* Start address of the sparse zero area -* -* \param size -* Size of the sparse zero block. The minimum sparse size is 64KB. -* -* \remarks -* Note that SetSparseRange does not perform actual file I/O, and unlike the -* WriteFile function, it does not move the current file I/O pointer or sets -* the end-of-file pointer. That is, if you want to place a sparse zero block -* in the end of the file, you must move the file pointer accordingly using -* the FileStream.Seek function, otherwise DeviceIoControl will have no effect -*/ + * Converting a file region to A sparse zero area. + * + * \param hSparseFile + * Handle of the sparse file + * + * \param start + * Start address of the sparse zero area + * + * \param size + * Size of the sparse zero block. The minimum sparse size is 64KB. + * + * \remarks + * Note that SetSparseRange does not perform actual file I/O, and unlike the + * WriteFile function, it does not move the current file I/O pointer or sets + * the end-of-file pointer. That is, if you want to place a sparse zero block + * in the end of the file, you must move the file pointer accordingly using + * the FileStream.Seek function, otherwise DeviceIoControl will have no effect + */ void SetSparseRange(HANDLE hSparseFile, LONGLONG start, LONGLONG size) { // Specify the starting and the ending address (not the size) of the @@ -156,27 +144,23 @@ void SetSparseRange(HANDLE hSparseFile, LONGLONG start, LONGLONG size) FILE_ZERO_DATA_INFORMATION fzdi; fzdi.FileOffset.QuadPart = start; fzdi.BeyondFinalZero.QuadPart = start + size; - + // Mark the range as sparse zero block DWORD dwTemp; - DeviceIoControl(hSparseFile, FSCTL_SET_ZERO_DATA, &fzdi, sizeof(fzdi), - NULL, 0, &dwTemp, NULL); + DeviceIoControl(hSparseFile, FSCTL_SET_ZERO_DATA, &fzdi, sizeof(fzdi), NULL, 0, &dwTemp, NULL); } - /*! -* Query the sparse file layout. -* -* \param lpFileName -* File name -*/ + * Query the sparse file layout. + * + * \param lpFileName + * File name + */ BOOL GetSparseRanges(LPCTSTR lpFileName) { // Open the file for read - HANDLE hFile = CreateFile(lpFileName, GENERIC_READ, 0, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; + HANDLE hFile = CreateFile(lpFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return FALSE; LARGE_INTEGER liFileSize; GetFileSizeEx(hFile, &liFileSize); @@ -194,9 +178,14 @@ BOOL GetSparseRanges(LPCTSTR lpFileName) _putws(L"\nAllocated ranges in the file:"); do { - fFinished = DeviceIoControl(hFile, FSCTL_QUERY_ALLOCATED_RANGES, - &queryRange, sizeof(queryRange), allocRanges, - sizeof(allocRanges), &nbytes, NULL); + fFinished = DeviceIoControl(hFile, + FSCTL_QUERY_ALLOCATED_RANGES, + &queryRange, + sizeof(queryRange), + allocRanges, + sizeof(allocRanges), + &nbytes, + NULL); if (!fFinished) { @@ -212,26 +201,23 @@ BOOL GetSparseRanges(LPCTSTR lpFileName) } // Calculate the number of records returned - DWORD dwAllocRangeCount = nbytes / - sizeof(FILE_ALLOCATED_RANGE_BUFFER); + DWORD dwAllocRangeCount = nbytes / sizeof(FILE_ALLOCATED_RANGE_BUFFER); // Print each allocated range for (DWORD i = 0; i < dwAllocRangeCount; i++) { wprintf(L"allocated range: [%I64u] [%I64u]\n", - allocRanges[i].FileOffset.QuadPart, - allocRanges[i].Length.QuadPart); + allocRanges[i].FileOffset.QuadPart, + allocRanges[i].Length.QuadPart); } // Set starting address and size for the next query if (!fFinished && dwAllocRangeCount > 0) { - queryRange.FileOffset.QuadPart = - allocRanges[dwAllocRangeCount - 1].FileOffset.QuadPart + - allocRanges[dwAllocRangeCount - 1].Length.QuadPart; - - queryRange.Length.QuadPart = liFileSize.QuadPart - - queryRange.FileOffset.QuadPart; + queryRange.FileOffset.QuadPart = allocRanges[dwAllocRangeCount - 1].FileOffset.QuadPart + + allocRanges[dwAllocRangeCount - 1].Length.QuadPart; + + queryRange.Length.QuadPart = liFileSize.QuadPart - queryRange.FileOffset.QuadPart; } } while (!fFinished); diff --git a/Release/tests/functional/streams/CppSparseFile.h b/Release/tests/functional/streams/CppSparseFile.h index c563671443..306b44b250 100644 --- a/Release/tests/functional/streams/CppSparseFile.h +++ b/Release/tests/functional/streams/CppSparseFile.h @@ -1,84 +1,82 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* CppSparseFile.h : defines various apis for creation and access of sparse files under windows -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * CppSparseFile.h : defines various apis for creation and access of sparse files under windows + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma region Includes +#include #include #include + #include -#include #pragma endregion - /*! -* VolumeSupportsSparseFiles determines if the volume supports sparse streams. -* -* \param lpRootPathName -* Volume root path e.g. C:\ -*/ + * VolumeSupportsSparseFiles determines if the volume supports sparse streams. + * + * \param lpRootPathName + * Volume root path e.g. C:\ + */ BOOL VolumeSupportsSparseFiles(LPCTSTR lpRootPathName); - /*! -* IsSparseFile determines if a file is sparse. -* -* \param lpFileName -* File name -*/ + * IsSparseFile determines if a file is sparse. + * + * \param lpFileName + * File name + */ BOOL IsSparseFile(LPCTSTR lpFileName); /*! -* Get sparse file sizes. -* -* \param lpFileName -* File name -* -* \see -* http://msdn.microsoft.com/en-us/library/aa365276.aspx -*/ + * Get sparse file sizes. + * + * \param lpFileName + * File name + * + * \see + * http://msdn.microsoft.com/en-us/library/aa365276.aspx + */ BOOL GetSparseFileSize(LPCTSTR lpFileName); - /*! -* Create a sparse file. -* -* \param lpFileName -* The name of the sparse file -*/ + * Create a sparse file. + * + * \param lpFileName + * The name of the sparse file + */ HANDLE CreateSparseFile(LPCTSTR lpFileName); /*! -* Converting a file region to A sparse zero area. -* -* \param hSparseFile -* Handle of the sparse file -* -* \param start -* Start address of the sparse zero area -* -* \param size -* Size of the sparse zero block. The minimum sparse size is 64KB. -* -* \remarks -* Note that SetSparseRange does not perform actual file I/O, and unlike the -* WriteFile function, it does not move the current file I/O pointer or sets -* the end-of-file pointer. That is, if you want to place a sparse zero block -* in the end of the file, you must move the file pointer accordingly using -* the FileStream.Seek function, otherwise DeviceIoControl will have no effect -*/ + * Converting a file region to A sparse zero area. + * + * \param hSparseFile + * Handle of the sparse file + * + * \param start + * Start address of the sparse zero area + * + * \param size + * Size of the sparse zero block. The minimum sparse size is 64KB. + * + * \remarks + * Note that SetSparseRange does not perform actual file I/O, and unlike the + * WriteFile function, it does not move the current file I/O pointer or sets + * the end-of-file pointer. That is, if you want to place a sparse zero block + * in the end of the file, you must move the file pointer accordingly using + * the FileStream.Seek function, otherwise DeviceIoControl will have no effect + */ void SetSparseRange(HANDLE hSparseFile, LONGLONG start, LONGLONG size); /*! -* Query the sparse file layout. -* -* \param lpFileName -* File name -*/ + * Query the sparse file layout. + * + * \param lpFileName + * File name + */ BOOL GetSparseRanges(LPCTSTR lpFileName); diff --git a/Release/tests/functional/streams/fstreambuf_tests.cpp b/Release/tests/functional/streams/fstreambuf_tests.cpp index 06750213ca..190eb66b0c 100644 --- a/Release/tests/functional/streams/fstreambuf_tests.cpp +++ b/Release/tests/functional/streams/fstreambuf_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests for async file stream buffer operations. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests for async file stream buffer operations. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" #ifdef _WIN32 @@ -19,24 +19,28 @@ using namespace Windows::Storage; #endif #ifdef _WIN32 -# define DEFAULT_PROT (int)std::ios_base::_Openprot +#define DEFAULT_PROT (int)std::ios_base::_Openprot #else -# define DEFAULT_PROT 0 -# define _SH_DENYRW 0x20 +#define DEFAULT_PROT 0 +#define _SH_DENYRW 0x20 #endif -namespace tests { namespace functional { namespace streams { - +namespace tests +{ +namespace functional +{ +namespace streams +{ using namespace utility; using namespace ::pplx; // Used to prepare data for read tests -utility::string_t get_full_name(const utility::string_t &name); +utility::string_t get_full_name(const utility::string_t& name); -void fill_file(const utility::string_t &name, size_t repetitions = 1); +void fill_file(const utility::string_t& name, size_t repetitions = 1); #ifdef _WIN32 -void fill_file_w(const utility::string_t &name, size_t repetitions = 1); +void fill_file_w(const utility::string_t& name, size_t repetitions = 1); #endif // @@ -48,36 +52,40 @@ void fill_file_w(const utility::string_t &name, size_t repetitions = 1); // #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable : 4100) // Because of '_Prot' in WinRT builds. +#pragma warning(disable : 4100) // Because of '_Prot' in WinRT builds. #endif template -pplx::task> OPEN(const utility::string_t &name, std::ios::ios_base::openmode mode, int _Prot = DEFAULT_PROT) +pplx::task> OPEN(const utility::string_t& name, + std::ios::ios_base::openmode mode, + int _Prot = DEFAULT_PROT) { #if !defined(__cplusplus_winrt) return concurrency::streams::file_buffer<_CharType>::open(name, mode, _Prot); #else try { - if ( (mode & std::ios::out) ) + if ((mode & std::ios::out)) { - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->CreateFileAsync( - ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)).get(); + auto file = + pplx::create_task(KnownFolders::DocumentsLibrary->CreateFileAsync( + ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)) + .get(); return concurrency::streams::file_buffer<_CharType>::open(file, mode); } else { - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); + auto file = + pplx::create_task(KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))) + .get(); return concurrency::streams::file_buffer<_CharType>::open(file, mode); } } - catch(Platform::Exception^ exc) - { + catch (Platform::Exception ^ exc) + { // The create_system_error API expects a WIN32 error code NOT an HRESULT. - if(exc->HResult == 0x80070002) + if (exc->HResult == 0x80070002) { throw utility::details::create_system_error(ERROR_FILE_NOT_FOUND); } @@ -94,13 +102,13 @@ pplx::task> OPEN(const utility::strin } template -pplx::task> OPEN_W(const utility::string_t &name, int _Prot = DEFAULT_PROT) +pplx::task> OPEN_W(const utility::string_t& name, int _Prot = DEFAULT_PROT) { return OPEN<_CharType>(name, std::ios_base::out | std::ios_base::trunc, _Prot); } template -pplx::task> OPEN_R(const utility::string_t &name, int _Prot = DEFAULT_PROT) +pplx::task> OPEN_R(const utility::string_t& name, int _Prot = DEFAULT_PROT) { return OPEN<_CharType>(name, std::ios_base::in, _Prot); } @@ -111,980 +119,947 @@ pplx::task> OPEN_R(const utility::str SUITE(file_buffer_tests) { + TEST(OpenCloseTest1) + { + // Test using single-byte strings + auto open = OPEN_W(U("OpenCloseTest1.txt")); -TEST(OpenCloseTest1) -{ - // Test using single-byte strings - auto open = OPEN_W(U("OpenCloseTest1.txt")); - - auto stream = open.get(); - - VERIFY_IS_TRUE(open.is_done()); - VERIFY_IS_TRUE(stream.is_open()); - - auto close = stream.close(); - close.get(); + auto stream = open.get(); - VERIFY_IS_TRUE(close.is_done()); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_TRUE(open.is_done()); + VERIFY_IS_TRUE(stream.is_open()); -TEST(OpenForReadDoesntCreateFile1) -{ - utility::string_t fname = U("OpenForReadDoesntCreateFile1.txt"); + auto close = stream.close(); + close.get(); - VERIFY_THROWS_SYSTEM_ERROR(OPEN_R(fname).get(), std::errc::no_such_file_or_directory); + VERIFY_IS_TRUE(close.is_done()); + VERIFY_IS_FALSE(stream.is_open()); + } - std::ifstream is; - VERIFY_IS_NULL(is.rdbuf()->open(fname.c_str(), std::ios::in)); -} + TEST(OpenForReadDoesntCreateFile1) + { + utility::string_t fname = U("OpenForReadDoesntCreateFile1.txt"); -TEST(OpenForReadDoesntCreateFile2) -{ - utility::string_t fname = U("OpenForReadDoesntCreateFile2.txt"); + VERIFY_THROWS_SYSTEM_ERROR(OPEN_R(fname).get(), std::errc::no_such_file_or_directory); - VERIFY_THROWS_SYSTEM_ERROR(OPEN(fname, std::ios_base::in | std::ios_base::binary ).get(), std::errc::no_such_file_or_directory); + std::ifstream is; + VERIFY_IS_NULL(is.rdbuf()->open(fname.c_str(), std::ios::in)); + } - std::ifstream is; - VERIFY_IS_NULL(is.rdbuf()->open(fname.c_str(), std::ios::in | std::ios_base::binary)); -} + TEST(OpenForReadDoesntCreateFile2) + { + utility::string_t fname = U("OpenForReadDoesntCreateFile2.txt"); -TEST(WriteSingleCharTest1) -{ - auto open = OPEN_W(U("WriteSingleCharTest1.txt")); - auto stream = open.get(); + VERIFY_THROWS_SYSTEM_ERROR(OPEN(fname, std::ios_base::in | std::ios_base::binary).get(), + std::errc::no_such_file_or_directory); - VERIFY_IS_TRUE(open.is_done()); - VERIFY_IS_TRUE(stream.is_open()); + std::ifstream is; + VERIFY_IS_NULL(is.rdbuf()->open(fname.c_str(), std::ios::in | std::ios_base::binary)); + } - bool elements_equal = true; - for (uint8_t ch = 'a'; ch <= 'z'; ch++) + TEST(WriteSingleCharTest1) { - elements_equal = elements_equal && (ch == stream.putc(ch).get()); - } + auto open = OPEN_W(U("WriteSingleCharTest1.txt")); + auto stream = open.get(); - VERIFY_IS_TRUE(elements_equal); + VERIFY_IS_TRUE(open.is_done()); + VERIFY_IS_TRUE(stream.is_open()); - auto close = stream.close(); - close.get(); + bool elements_equal = true; + for (uint8_t ch = 'a'; ch <= 'z'; ch++) + { + elements_equal = elements_equal && (ch == stream.putc(ch).get()); + } - VERIFY_IS_TRUE(close.is_done()); - VERIFY_IS_FALSE(stream.is_open()); -} -#ifdef _WIN32 -TEST(WriteSingleCharTest1w) -{ - auto open = OPEN_W(U("WriteSingleCharTest1w.txt")); - auto stream = open.get(); + VERIFY_IS_TRUE(elements_equal); - VERIFY_IS_TRUE(open.is_done()); - VERIFY_IS_TRUE(stream.is_open()); + auto close = stream.close(); + close.get(); - bool elements_equal = true; - for (wchar_t ch = L'a'; ch <= L'z'; ch++) - { - elements_equal = elements_equal && (ch == stream.putc(ch).get()); + VERIFY_IS_TRUE(close.is_done()); + VERIFY_IS_FALSE(stream.is_open()); } +#ifdef _WIN32 + TEST(WriteSingleCharTest1w) + { + auto open = OPEN_W(U("WriteSingleCharTest1w.txt")); + auto stream = open.get(); - VERIFY_IS_TRUE(elements_equal); - - auto close = stream.close(); - close.get(); + VERIFY_IS_TRUE(open.is_done()); + VERIFY_IS_TRUE(stream.is_open()); - VERIFY_IS_TRUE(close.is_done()); - VERIFY_IS_FALSE(stream.is_open()); -} -#endif + bool elements_equal = true; + for (wchar_t ch = L'a'; ch <= L'z'; ch++) + { + elements_equal = elements_equal && (ch == stream.putc(ch).get()); + } -TEST(WriteBufferTest1) -{ - auto open = OPEN_W(U("WriteBufferTest1.txt")); - auto stream = open.get(); + VERIFY_IS_TRUE(elements_equal); - VERIFY_IS_TRUE(open.is_done()); - VERIFY_IS_TRUE(stream.is_open()); + auto close = stream.close(); + close.get(); - std::vector vect; + VERIFY_IS_TRUE(close.is_done()); + VERIFY_IS_FALSE(stream.is_open()); + } +#endif - for (uint8_t ch = 'a'; ch <= 'z'; ch++) + TEST(WriteBufferTest1) { - vect.push_back(ch); - } + auto open = OPEN_W(U("WriteBufferTest1.txt")); + auto stream = open.get(); - VERIFY_ARE_EQUAL(stream.putn_nocopy(&vect[0], vect.size()).get(), vect.size()); + VERIFY_IS_TRUE(open.is_done()); + VERIFY_IS_TRUE(stream.is_open()); - auto close = stream.close(); - close.get(); + std::vector vect; - VERIFY_IS_TRUE(close.is_done()); - VERIFY_IS_FALSE(stream.is_open()); -} -#ifdef _WIN32 -TEST(WriteBufferTest1w) -{ - auto open = OPEN_W(U("WriteBufferTest1w.txt")); - auto stream = open.get(); + for (uint8_t ch = 'a'; ch <= 'z'; ch++) + { + vect.push_back(ch); + } - VERIFY_IS_TRUE(open.is_done()); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_ARE_EQUAL(stream.putn_nocopy(&vect[0], vect.size()).get(), vect.size()); - std::vector vect; + auto close = stream.close(); + close.get(); - for (wchar_t ch = L'a'; ch <= L'z'; ch++) - { - vect.push_back(ch); + VERIFY_IS_TRUE(close.is_done()); + VERIFY_IS_FALSE(stream.is_open()); } +#ifdef _WIN32 + TEST(WriteBufferTest1w) + { + auto open = OPEN_W(U("WriteBufferTest1w.txt")); + auto stream = open.get(); - VERIFY_ARE_EQUAL(stream.putn_nocopy(&vect[0], vect.size()).get(), vect.size()); - - auto close = stream.close(); - close.get(); + VERIFY_IS_TRUE(open.is_done()); + VERIFY_IS_TRUE(stream.is_open()); - VERIFY_IS_TRUE(close.is_done()); - VERIFY_IS_FALSE(stream.is_open()); -} -#endif + std::vector vect; -TEST(WriteBufferAndSyncTest1) -{ - auto open = OPEN_W(U("WriteBufferAndSyncTest1.txt")); - auto stream = open.get(); + for (wchar_t ch = L'a'; ch <= L'z'; ch++) + { + vect.push_back(ch); + } - VERIFY_IS_TRUE(open.is_done()); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_ARE_EQUAL(stream.putn_nocopy(&vect[0], vect.size()).get(), vect.size()); - std::vector vect; + auto close = stream.close(); + close.get(); - for (uint8_t ch = 'a'; ch <= 'z'; ch++) - { - vect.push_back(ch); + VERIFY_IS_TRUE(close.is_done()); + VERIFY_IS_FALSE(stream.is_open()); } +#endif - auto write = stream.putn_nocopy(&vect[0], vect.size()); + TEST(WriteBufferAndSyncTest1) + { + auto open = OPEN_W(U("WriteBufferAndSyncTest1.txt")); + auto stream = open.get(); - stream.sync().get(); + VERIFY_IS_TRUE(open.is_done()); + VERIFY_IS_TRUE(stream.is_open()); - VERIFY_ARE_EQUAL(write.get(), vect.size()); - VERIFY_IS_TRUE(write.is_done()); + std::vector vect; - auto close = stream.close(); - close.get(); + for (uint8_t ch = 'a'; ch <= 'z'; ch++) + { + vect.push_back(ch); + } - VERIFY_IS_TRUE(close.is_done()); - VERIFY_IS_FALSE(stream.is_open()); -} + auto write = stream.putn_nocopy(&vect[0], vect.size()); -TEST(ReadSingleChar_bumpc1) -{ - utility::string_t fname = U("ReadSingleChar_bumpc1.txt"); - fill_file(fname); + stream.sync().get(); - auto stream = OPEN_R(fname).get(); + VERIFY_ARE_EQUAL(write.get(), vect.size()); + VERIFY_IS_TRUE(write.is_done()); - VERIFY_IS_TRUE(stream.is_open()); + auto close = stream.close(); + close.get(); - uint8_t buf[10]; - memset(buf, 0, sizeof(buf)); + VERIFY_IS_TRUE(close.is_done()); + VERIFY_IS_FALSE(stream.is_open()); + } - for (int i = 0; i < sizeof(buf); i++) + TEST(ReadSingleChar_bumpc1) { - buf[i] = (uint8_t)stream.bumpc().get(); - VERIFY_ARE_EQUAL(buf[i], 'a'+i); - } + utility::string_t fname = U("ReadSingleChar_bumpc1.txt"); + fill_file(fname); - stream.close().get(); + auto stream = OPEN_R(fname).get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_TRUE(stream.is_open()); -TEST(SequentialReadWrite) -{ - utility::string_t fname = U("SequentialReadWrite.txt"); + uint8_t buf[10]; + memset(buf, 0, sizeof(buf)); - auto ostreamBuf = OPEN_W(fname).get(); + for (int i = 0; i < sizeof(buf); i++) + { + buf[i] = (uint8_t)stream.bumpc().get(); + VERIFY_ARE_EQUAL(buf[i], 'a' + i); + } - VERIFY_IS_TRUE(ostreamBuf.is_open()); + stream.close().get(); - for (int i = 0; i < 1000; i++) - { - ostreamBuf.putc(i % 26 + 'a'); - ostreamBuf.putn_nocopy("ABCDEFGHIJ", 10); + VERIFY_IS_FALSE(stream.is_open()); } - ostreamBuf.close().wait(); - VERIFY_IS_FALSE(ostreamBuf.is_open()); - - auto istreamBuf = OPEN_R(fname).get(); - std::vector> t; - for (int k = 0; k < 2; k++) + TEST(SequentialReadWrite) { + utility::string_t fname = U("SequentialReadWrite.txt"); + + auto ostreamBuf = OPEN_W(fname).get(); + + VERIFY_IS_TRUE(ostreamBuf.is_open()); + for (int i = 0; i < 1000; i++) { - t.push_back(istreamBuf.getc().then([i, this](char c) { - VERIFY_ARE_EQUAL(i % 26 + 'a', c); - })); - t.push_back(istreamBuf.bumpc().then([i, this](char c) { - VERIFY_ARE_EQUAL(i % 26 + 'a', c); - })); - char *buffer = new char[11]; - t.push_back(istreamBuf.getn(buffer, 10).then([=](size_t n) { - VERIFY_ARE_EQUAL(10u, n); - VERIFY_ARE_EQUAL(std::string("ABCDEFGHIJ"), std::string(buffer, 10)); - delete[] buffer; - })); + ostreamBuf.putc(i % 26 + 'a'); + ostreamBuf.putn_nocopy("ABCDEFGHIJ", 10); } - istreamBuf.seekpos(0, std::ios::in); - } - istreamBuf.close().wait(); - VERIFY_IS_FALSE(istreamBuf.is_open()); - for (size_t i = 0; i < t.size(); i++) - t[i].wait(); -} + ostreamBuf.close().wait(); + VERIFY_IS_FALSE(ostreamBuf.is_open()); + auto istreamBuf = OPEN_R(fname).get(); + std::vector> t; + + for (int k = 0; k < 2; k++) + { + for (int i = 0; i < 1000; i++) + { + t.push_back(istreamBuf.getc().then([i, this](char c) { VERIFY_ARE_EQUAL(i % 26 + 'a', c); })); + t.push_back(istreamBuf.bumpc().then([i, this](char c) { VERIFY_ARE_EQUAL(i % 26 + 'a', c); })); + char* buffer = new char[11]; + t.push_back(istreamBuf.getn(buffer, 10).then([=](size_t n) { + VERIFY_ARE_EQUAL(10u, n); + VERIFY_ARE_EQUAL(std::string("ABCDEFGHIJ"), std::string(buffer, 10)); + delete[] buffer; + })); + } + istreamBuf.seekpos(0, std::ios::in); + } + istreamBuf.close().wait(); + VERIFY_IS_FALSE(istreamBuf.is_open()); + for (size_t i = 0; i < t.size(); i++) + t[i].wait(); + } #ifdef _WIN32 -TEST(ReadSingleChar_bumpcw) -{ - utility::string_t fname = U("ReadSingleChar_bumpcw.txt"); - fill_file_w(fname); + TEST(ReadSingleChar_bumpcw) + { + utility::string_t fname = U("ReadSingleChar_bumpcw.txt"); + fill_file_w(fname); - auto stream = OPEN_R(fname).get(); + auto stream = OPEN_R(fname).get(); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - wchar_t buf[10]; - memset(buf, 0, sizeof(buf)); + wchar_t buf[10]; + memset(buf, 0, sizeof(buf)); - for (int i = 0; i < 10; i++) - { - buf[i] = stream.bumpc().get(); - VERIFY_ARE_EQUAL(buf[i], L'a'+i); - } + for (int i = 0; i < 10; i++) + { + buf[i] = stream.bumpc().get(); + VERIFY_ARE_EQUAL(buf[i], L'a' + i); + } - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } #endif -TEST(ReadSingleChar_bumpc2) -{ - // Test that seeking works. - utility::string_t fname = U("ReadSingleChar_bumpc2.txt"); - fill_file(fname); + TEST(ReadSingleChar_bumpc2) + { + // Test that seeking works. + utility::string_t fname = U("ReadSingleChar_bumpc2.txt"); + fill_file(fname); - auto stream = OPEN_R(fname).get(); + auto stream = OPEN_R(fname).get(); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - stream.seekpos(3, std::ios_base::in); + stream.seekpos(3, std::ios_base::in); - uint8_t buf[10]; - memset(buf, 0, sizeof(buf)); + uint8_t buf[10]; + memset(buf, 0, sizeof(buf)); - for (int i = 0; i < sizeof(buf); i++) - { - buf[i] = (uint8_t)stream.bumpc().get(); - VERIFY_ARE_EQUAL(buf[i], 'd'+i); - } + for (int i = 0; i < sizeof(buf); i++) + { + buf[i] = (uint8_t)stream.bumpc().get(); + VERIFY_ARE_EQUAL(buf[i], 'd' + i); + } - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } -TEST(filestream_length) -{ - utility::string_t fname = U("ReadSingleChar_bumpc3.txt"); - fill_file(fname); + TEST(filestream_length) + { + utility::string_t fname = U("ReadSingleChar_bumpc3.txt"); + fill_file(fname); - auto stream = OPEN_R(fname, _SH_DENYRW).get(); - stream.set_buffer_size(512); + auto stream = OPEN_R(fname, _SH_DENYRW).get(); + stream.set_buffer_size(512); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - test_stream_length(stream.create_istream(), 26); + test_stream_length(stream.create_istream(), 26); - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } -TEST(ReadSingleChar_bumpc3) -{ - // Test that seeking works. - utility::string_t fname = U("ReadSingleChar_bumpc3.txt"); - fill_file(fname); + TEST(ReadSingleChar_bumpc3) + { + // Test that seeking works. + utility::string_t fname = U("ReadSingleChar_bumpc3.txt"); + fill_file(fname); - auto stream = OPEN_R(fname, _SH_DENYRW).get(); - stream.set_buffer_size(512); + auto stream = OPEN_R(fname, _SH_DENYRW).get(); + stream.set_buffer_size(512); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - stream.seekpos(2, std::ios_base::in); + stream.seekpos(2, std::ios_base::in); - // Read a character asynchronously to get the buffer primed. - stream.bumpc().get(); + // Read a character asynchronously to get the buffer primed. + stream.bumpc().get(); - auto ras = concurrency::streams::char_traits::requires_async(); + auto ras = concurrency::streams::char_traits::requires_async(); - for (int i = 3; i < 26; i++) - { - auto c = (uint8_t)stream.sbumpc(); - if ( c != ras ) + for (int i = 3; i < 26; i++) { - VERIFY_ARE_EQUAL(c, 'a'+i); + auto c = (uint8_t)stream.sbumpc(); + if (c != ras) + { + VERIFY_ARE_EQUAL(c, 'a' + i); + } } - } - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } -TEST(ReadSingleChar_nextc) -{ - utility::string_t fname = U("ReadSingleChar_nextc.txt"); - fill_file(fname); + TEST(ReadSingleChar_nextc) + { + utility::string_t fname = U("ReadSingleChar_nextc.txt"); + fill_file(fname); - auto stream = OPEN_R(fname).get(); + auto stream = OPEN_R(fname).get(); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - uint8_t buf[10]; - memset(buf, 0, sizeof(buf)); + uint8_t buf[10]; + memset(buf, 0, sizeof(buf)); - for (int i = 0; i < sizeof(buf); i++) - { - buf[i] = (uint8_t)stream.nextc().get(); - VERIFY_ARE_EQUAL(buf[i], 'b'+i); - } + for (int i = 0; i < sizeof(buf); i++) + { + buf[i] = (uint8_t)stream.nextc().get(); + VERIFY_ARE_EQUAL(buf[i], 'b' + i); + } - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } #ifdef _WIN32 -TEST(ReadSingleChar_nextcw) -{ - utility::string_t fname = U("ReadSingleChar_nextcw.txt"); - fill_file_w(fname); + TEST(ReadSingleChar_nextcw) + { + utility::string_t fname = U("ReadSingleChar_nextcw.txt"); + fill_file_w(fname); - auto stream = OPEN_R(fname).get(); + auto stream = OPEN_R(fname).get(); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - wchar_t buf[10]; - memset(buf, 0, sizeof(buf)); + wchar_t buf[10]; + memset(buf, 0, sizeof(buf)); - for (int i = 0; i < 10; i++) - { - buf[i] = stream.nextc().get(); - VERIFY_ARE_EQUAL(buf[i], L'b'+i); - } + for (int i = 0; i < 10; i++) + { + buf[i] = stream.nextc().get(); + VERIFY_ARE_EQUAL(buf[i], L'b' + i); + } - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } #endif -TEST(ReadSingleChar_ungetc) -{ - // Test that seeking works. - utility::string_t fname = U("ReadSingleChar_ungetc.txt"); - fill_file(fname); + TEST(ReadSingleChar_ungetc) + { + // Test that seeking works. + utility::string_t fname = U("ReadSingleChar_ungetc.txt"); + fill_file(fname); - auto stream = OPEN_R(fname).get(); + auto stream = OPEN_R(fname).get(); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - stream.seekpos(13, std::ios_base::in); + stream.seekpos(13, std::ios_base::in); - uint8_t buf[10]; - memset(buf, 0, sizeof(buf)); + uint8_t buf[10]; + memset(buf, 0, sizeof(buf)); - for (int i = 0; i < sizeof(buf); i++) - { - buf[i] = (uint8_t)stream.ungetc().get(); - VERIFY_ARE_EQUAL(buf[i], 'm'-i); - } + for (int i = 0; i < sizeof(buf); i++) + { + buf[i] = (uint8_t)stream.ungetc().get(); + VERIFY_ARE_EQUAL(buf[i], 'm' - i); + } - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } -TEST(ReadSingleChar_getc1) -{ - utility::string_t fname = U("ReadSingleChar_getc1.txt"); - fill_file(fname); + TEST(ReadSingleChar_getc1) + { + utility::string_t fname = U("ReadSingleChar_getc1.txt"); + fill_file(fname); - auto stream = OPEN_R(fname, _SH_DENYRW).get(); + auto stream = OPEN_R(fname, _SH_DENYRW).get(); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - uint8_t ch0 = (uint8_t)stream.getc().get(); - uint8_t ch1 = (uint8_t)stream.getc().get(); + uint8_t ch0 = (uint8_t)stream.getc().get(); + uint8_t ch1 = (uint8_t)stream.getc().get(); - VERIFY_ARE_EQUAL(ch0, ch1); + VERIFY_ARE_EQUAL(ch0, ch1); - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } -TEST(ReadSingleChar_getc2) -{ - utility::string_t fname = U("ReadSingleChar_getc2.txt"); - fill_file(fname); + TEST(ReadSingleChar_getc2) + { + utility::string_t fname = U("ReadSingleChar_getc2.txt"); + fill_file(fname); - auto stream = OPEN_R(fname, _SH_DENYRW).get(); + auto stream = OPEN_R(fname, _SH_DENYRW).get(); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - stream.seekpos(13, std::ios_base::in); + stream.seekpos(13, std::ios_base::in); - uint8_t ch0 = (uint8_t)stream.getc().get(); - uint8_t ch1 = (uint8_t)stream.sgetc(); + uint8_t ch0 = (uint8_t)stream.getc().get(); + uint8_t ch1 = (uint8_t)stream.sgetc(); - VERIFY_ARE_EQUAL(ch0, ch1); + VERIFY_ARE_EQUAL(ch0, ch1); - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } #ifdef _WIN32 -TEST(ReadSingleChar_getc1w) -{ - utility::string_t fname = U("ReadSingleChar_getc1w.txt"); - fill_file_w(fname); + TEST(ReadSingleChar_getc1w) + { + utility::string_t fname = U("ReadSingleChar_getc1w.txt"); + fill_file_w(fname); - auto stream = OPEN_R(fname, _SH_DENYRW).get(); + auto stream = OPEN_R(fname, _SH_DENYRW).get(); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - wchar_t ch0 = stream.getc().get(); - wchar_t ch1 = stream.getc().get(); + wchar_t ch0 = stream.getc().get(); + wchar_t ch1 = stream.getc().get(); - VERIFY_ARE_EQUAL(ch0, ch1); - VERIFY_ARE_EQUAL(ch0, L'a'); + VERIFY_ARE_EQUAL(ch0, ch1); + VERIFY_ARE_EQUAL(ch0, L'a'); - stream.seekpos(15, std::ios_base::in); + stream.seekpos(15, std::ios_base::in); - ch0 = stream.getc().get(); - ch1 = stream.getc().get(); + ch0 = stream.getc().get(); + ch1 = stream.getc().get(); - VERIFY_ARE_EQUAL(ch0, ch1); - VERIFY_ARE_EQUAL(ch0, L'p'); + VERIFY_ARE_EQUAL(ch0, ch1); + VERIFY_ARE_EQUAL(ch0, L'p'); - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } -TEST(ReadSingleChar_getc2w) -{ - utility::string_t fname = U("ReadSingleChar_getc2w.txt"); - fill_file_w(fname); + TEST(ReadSingleChar_getc2w) + { + utility::string_t fname = U("ReadSingleChar_getc2w.txt"); + fill_file_w(fname); - auto stream = OPEN_R(fname, _SH_DENYRW).get(); + auto stream = OPEN_R(fname, _SH_DENYRW).get(); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_IS_TRUE(stream.is_open()); - stream.seekpos(13, std::ios_base::in); + stream.seekpos(13, std::ios_base::in); - wchar_t ch0 = stream.getc().get(); - wchar_t ch1 = stream.getc().get(); + wchar_t ch0 = stream.getc().get(); + wchar_t ch1 = stream.getc().get(); - VERIFY_ARE_EQUAL(ch0, ch1); - VERIFY_ARE_EQUAL(ch0, L'n'); + VERIFY_ARE_EQUAL(ch0, ch1); + VERIFY_ARE_EQUAL(ch0, L'n'); - stream.seekpos(5, std::ios_base::in); + stream.seekpos(5, std::ios_base::in); - ch0 = stream.getc().get(); - ch1 = stream.getc().get(); + ch0 = stream.getc().get(); + ch1 = stream.getc().get(); - VERIFY_ARE_EQUAL(ch0, ch1); - VERIFY_ARE_EQUAL(ch0, L'f'); + VERIFY_ARE_EQUAL(ch0, ch1); + VERIFY_ARE_EQUAL(ch0, L'f'); - stream.close().get(); + stream.close().get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_FALSE(stream.is_open()); + } #endif -TEST(ReadBuffer1) -{ - // Test that seeking works. - utility::string_t fname = U("ReadBuffer1.txt"); - fill_file(fname); + TEST(ReadBuffer1) + { + // Test that seeking works. + utility::string_t fname = U("ReadBuffer1.txt"); + fill_file(fname); + + // In order to get the implementation to buffer reads, we have to open the file + // with protection against sharing. + auto stream = OPEN_R(fname, _SH_DENYRW).get(); + stream.set_buffer_size(512); - // In order to get the implementation to buffer reads, we have to open the file - // with protection against sharing. - auto stream = OPEN_R(fname, _SH_DENYRW).get(); - stream.set_buffer_size(512); + VERIFY_IS_TRUE(stream.is_open()); - VERIFY_IS_TRUE(stream.is_open()); + char buf[10]; + memset(buf, 0, sizeof(buf)); - char buf[10]; - memset(buf, 0, sizeof(buf)); + auto read = stream.getn(buf, sizeof(buf)).then([=](pplx::task op) -> size_t { return op.get(); }); - auto read = - stream.getn(buf, sizeof(buf)).then( - [=](pplx::task op) -> size_t + VERIFY_ARE_EQUAL(sizeof(buf), read.get()); + + bool elements_equal = true; + + for (int i = 0; i < sizeof(buf); i++) { - return op.get(); - }); + elements_equal = elements_equal && (buf[i] == 'a' + i); + } - VERIFY_ARE_EQUAL(sizeof(buf), read.get()); + VERIFY_IS_TRUE(elements_equal); - bool elements_equal = true; + stream.seekpos(3, std::ios_base::in); - for (int i = 0; i < sizeof(buf); i++) - { - elements_equal = elements_equal && (buf[i] == 'a'+i); - } + memset(buf, 0, sizeof(buf)); - VERIFY_IS_TRUE(elements_equal); + read = stream.getn(buf, sizeof(buf)).then([=](pplx::task op) -> size_t { return op.get(); }); - stream.seekpos(3, std::ios_base::in); + VERIFY_ARE_EQUAL(sizeof(buf), read.get()); - memset(buf, 0, sizeof(buf)); + elements_equal = true; - read = - stream.getn(buf, sizeof(buf)).then( - [=](pplx::task op) -> size_t + for (int i = 0; i < sizeof(buf); i++) { - return op.get(); - }); + elements_equal = elements_equal && (buf[i] == 'd' + i); + } - VERIFY_ARE_EQUAL(sizeof(buf), read.get()); + VERIFY_IS_TRUE(elements_equal); - elements_equal = true; + stream.close().get(); - for (int i = 0; i < sizeof(buf); i++) - { - elements_equal = elements_equal && (buf[i] == 'd'+i); + VERIFY_IS_FALSE(stream.is_open()); } - VERIFY_IS_TRUE(elements_equal); +#ifdef _WIN32 + TEST(ReadBuffer1w) + { + // Test that seeking works. + utility::string_t fname = U("ReadBuffer1w.txt"); + fill_file_w(fname); - stream.close().get(); + // In order to get the implementation to buffer reads, we have to open the file + // with protection against sharing. + auto stream = OPEN_R(fname, _SH_DENYRW).get(); - VERIFY_IS_FALSE(stream.is_open()); -} + VERIFY_IS_TRUE(stream.is_open()); -#ifdef _WIN32 -TEST(ReadBuffer1w) -{ - // Test that seeking works. - utility::string_t fname = U("ReadBuffer1w.txt"); - fill_file_w(fname); + wchar_t buf[10]; + memset(buf, 0, sizeof(buf)); - // In order to get the implementation to buffer reads, we have to open the file - // with protection against sharing. - auto stream = OPEN_R(fname, _SH_DENYRW).get(); + auto read = stream.getn(buf, 10).then([=](pplx::task op) -> size_t { return op.get(); }); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_ARE_EQUAL(10u, read.get()); - wchar_t buf[10]; - memset(buf, 0, sizeof(buf)); + bool elements_equal = true; - auto read = - stream.getn(buf, 10).then( - [=](pplx::task op) -> size_t + for (int i = 0; i < 10; i++) { - return op.get(); - }); + elements_equal = elements_equal && (buf[i] == L'a' + i); + } - VERIFY_ARE_EQUAL(10u, read.get()); + VERIFY_IS_TRUE(elements_equal); - bool elements_equal = true; + stream.seekpos(3, std::ios_base::in); - for (int i = 0; i < 10; i++) - { - elements_equal = elements_equal && (buf[i] == L'a'+i); - } + memset(buf, 0, sizeof(buf)); - VERIFY_IS_TRUE(elements_equal); + read = stream.getn(buf, 10).then([=](pplx::task op) -> size_t { return op.get(); }); - stream.seekpos(3, std::ios_base::in); + VERIFY_ARE_EQUAL(10u, read.get()); - memset(buf, 0, sizeof(buf)); + elements_equal = true; - read = - stream.getn(buf, 10).then( - [=](pplx::task op) -> size_t - { - return op.get(); - }); + for (int i = 0; i < 10; i++) + { + elements_equal = elements_equal && (buf[i] == L'd' + i); + } - VERIFY_ARE_EQUAL(10u, read.get()); + VERIFY_IS_TRUE(elements_equal); - elements_equal = true; + stream.close().get(); - for (int i = 0; i < 10; i++) - { - elements_equal = elements_equal && (buf[i] == L'd'+i); + VERIFY_IS_FALSE(stream.is_open()); } +#endif - VERIFY_IS_TRUE(elements_equal); + TEST(ReadBuffer2) + { + // Test that seeking works when the file is larger than the internal buffer size. + utility::string_t fname = U("ReadBuffer2.txt"); + fill_file(fname, 30); - stream.close().get(); + // In order to get the implementation to buffer reads, we have to open the file + // with protection against sharing. + auto stream = OPEN_R(fname, _SH_DENYRW).get(); - VERIFY_IS_FALSE(stream.is_open()); -} -#endif + VERIFY_IS_TRUE(stream.is_open()); -TEST(ReadBuffer2) -{ - // Test that seeking works when the file is larger than the internal buffer size. - utility::string_t fname = U("ReadBuffer2.txt"); - fill_file(fname,30); + char buf[10]; + memset(buf, 0, sizeof(buf)); - // In order to get the implementation to buffer reads, we have to open the file - // with protection against sharing. - auto stream = OPEN_R(fname, _SH_DENYRW).get(); + auto read = stream.getn(buf, sizeof(buf)).then([=](pplx::task op) -> size_t { return op.get(); }); - VERIFY_IS_TRUE(stream.is_open()); + VERIFY_ARE_EQUAL(sizeof(buf), read.get()); - char buf[10]; - memset(buf, 0, sizeof(buf)); + bool elements_equal = true; - auto read = - stream.getn(buf, sizeof(buf)).then( - [=](pplx::task op) -> size_t + for (int i = 0; i < sizeof(buf); i++) { - return op.get(); - }); + elements_equal = elements_equal && (buf[i] == 'a' + i); + } - VERIFY_ARE_EQUAL(sizeof(buf), read.get()); + VERIFY_IS_TRUE(elements_equal); - bool elements_equal = true; + // Test that we can seek to a position near the end of the initial buffer, + // read a chunk spanning the end of the buffer, and get a correct outcome. - for (int i = 0; i < sizeof(buf); i++) - { - elements_equal = elements_equal && (buf[i] == 'a'+i); - } + stream.seekpos(505, std::ios_base::in); - VERIFY_IS_TRUE(elements_equal); + memset(buf, 0, sizeof(buf)); - // Test that we can seek to a position near the end of the initial buffer, - // read a chunk spanning the end of the buffer, and get a correct outcome. + read = stream.getn(buf, sizeof(buf)).then([=](pplx::task op) -> size_t { return op.get(); }); - stream.seekpos(505, std::ios_base::in); + VERIFY_ARE_EQUAL(sizeof(buf), read.get()); - memset(buf, 0, sizeof(buf)); + elements_equal = true; - read = - stream.getn(buf, sizeof(buf)).then( - [=](pplx::task op) -> size_t + for (int i = 0; i < sizeof(buf); i++) { - return op.get(); - }); + elements_equal = elements_equal && (buf[i] == 'l' + i); + } - VERIFY_ARE_EQUAL(sizeof(buf), read.get()); + VERIFY_IS_TRUE(elements_equal); - elements_equal = true; + stream.close().get(); - for (int i = 0; i < sizeof(buf); i++) - { - elements_equal = elements_equal && (buf[i] == 'l'+i); + VERIFY_IS_FALSE(stream.is_open()); } - VERIFY_IS_TRUE(elements_equal); + TEST(SeekEnd1) + { + utility::string_t fname = U("SeekEnd1.txt"); + fill_file(fname, 30); - stream.close().get(); + // In order to get the implementation to buffer reads, we have to open the file + // with protection against sharing. + auto stream = OPEN_R(fname).get(); - VERIFY_IS_FALSE(stream.is_open()); -} + auto pos = stream.seekoff(0, std::ios_base::end, std::ios_base::in); -TEST(SeekEnd1) -{ - utility::string_t fname = U("SeekEnd1.txt"); - fill_file(fname,30); + VERIFY_ARE_EQUAL(30 * 26, pos); + } - // In order to get the implementation to buffer reads, we have to open the file - // with protection against sharing. - auto stream = OPEN_R(fname).get(); + TEST(IsEOFTest) + { + utility::string_t fname = U("IsEOFTest.txt"); + fill_file(fname, 30); + + auto stream = OPEN_R(fname).get(); + VERIFY_IS_FALSE(stream.is_eof()); + stream.getc().wait(); + VERIFY_IS_FALSE(stream.is_eof()); + stream.seekoff(0, std::ios_base::end, std::ios_base::in); + VERIFY_IS_FALSE(stream.is_eof()); + stream.getc().wait(); + VERIFY_IS_TRUE(stream.is_eof()); + stream.seekoff(0, std::ios_base::beg, std::ios_base::in); + VERIFY_IS_TRUE(stream.is_eof()); + stream.getc().wait(); + VERIFY_IS_FALSE(stream.is_eof()); + } - auto pos = stream.seekoff(0, std::ios_base::end, std::ios_base::in); + TEST(CloseWithException) + { + struct MyException + { + }; + auto streambuf = OPEN_W(U("CloseExceptionTest.txt")).get(); + streambuf.close(std::ios::out, std::make_exception_ptr(MyException())).wait(); + VERIFY_THROWS(streambuf.putn_nocopy("this is good", 10).get(), MyException); + VERIFY_THROWS(streambuf.putc('c').get(), MyException); + + streambuf = OPEN_R(U("CloseExceptionTest.txt")).get(); + streambuf.close(std::ios::in, std::make_exception_ptr(MyException())).wait(); + char buf[100]; + VERIFY_THROWS(streambuf.getn(buf, 100).get(), MyException); + VERIFY_THROWS(streambuf.getc().get(), MyException); + } - VERIFY_ARE_EQUAL(30*26, pos); -} + TEST(inout_regression_test) + { + std::string data = "abcdefghijklmn"; + concurrency::streams::streambuf file_buf = + OPEN(U("inout_regression_test.txt"), std::ios_base::in | std::ios_base::out).get(); + file_buf.putn_nocopy(&data[0], data.size()).get(); -TEST(IsEOFTest) -{ - utility::string_t fname = U("IsEOFTest.txt"); - fill_file(fname,30); - - auto stream = OPEN_R(fname).get(); - VERIFY_IS_FALSE(stream.is_eof()); - stream.getc().wait(); - VERIFY_IS_FALSE(stream.is_eof()); - stream.seekoff(0, std::ios_base::end, std::ios_base::in); - VERIFY_IS_FALSE(stream.is_eof()); - stream.getc().wait(); - VERIFY_IS_TRUE(stream.is_eof()); - stream.seekoff(0, std::ios_base::beg, std::ios_base::in); - VERIFY_IS_TRUE(stream.is_eof()); - stream.getc().wait(); - VERIFY_IS_FALSE(stream.is_eof()); -} + file_buf.bumpc().get(); // reads 'a' -TEST(CloseWithException) -{ - struct MyException {}; - auto streambuf = OPEN_W(U("CloseExceptionTest.txt")).get(); - streambuf.close(std::ios::out, std::make_exception_ptr(MyException())).wait(); - VERIFY_THROWS(streambuf.putn_nocopy("this is good", 10).get(), MyException); - VERIFY_THROWS(streambuf.putc('c').get(), MyException); - - streambuf = OPEN_R(U("CloseExceptionTest.txt")).get(); - streambuf.close(std::ios::in, std::make_exception_ptr(MyException())).wait(); - char buf[100]; - VERIFY_THROWS(streambuf.getn(buf, 100).get(), MyException); - VERIFY_THROWS(streambuf.getc().get(), MyException); -} + char readdata[256]; + memset(&readdata[0], '\0', 256); -TEST(inout_regression_test) -{ - std::string data = "abcdefghijklmn"; - concurrency::streams::streambuf file_buf = OPEN(U("inout_regression_test.txt"), std::ios_base::in|std::ios_base::out).get(); - file_buf.putn_nocopy(&data[0], data.size()).get(); + file_buf.seekoff(0, std::ios::beg, std::ios::in); + auto data_read = file_buf.getn(&readdata[0], 3).get(); // reads 'bcd'. File contains the org string though!!! - file_buf.bumpc().get(); // reads 'a' - - char readdata[256]; - memset(&readdata[0], '\0', 256); + memset(&readdata[0], '\0', 256); - file_buf.seekoff(0, std::ios::beg, std::ios::in); - auto data_read = file_buf.getn(&readdata[0], 3).get(); // reads 'bcd'. File contains the org string though!!! + file_buf.seekoff(0, std::ios::beg, std::ios::in); + data_read = file_buf.getn(&readdata[0], 3).get(); // reads 'efg'. File contains org string 'abcdef..'. - memset(&readdata[0], '\0', 256); - - file_buf.seekoff(0, std::ios::beg, std::ios::in); - data_read = file_buf.getn(&readdata[0], 3).get(); // reads 'efg'. File contains org string 'abcdef..'. + file_buf.close().wait(); + } - file_buf.close().wait(); -} + TEST(seek_read_regression_test) + { + utility::string_t fname = U("seek_read_regression_test.txt"); + fill_file(fname, 100); -TEST(seek_read_regression_test) -{ - utility::string_t fname = U("seek_read_regression_test.txt"); - fill_file(fname,100); + char readdata[256]; - char readdata[256]; + auto istream = OPEN_R(fname, _SH_DENYRW).get().create_istream(); + istream.streambuf().set_buffer_size(128); - auto istream = OPEN_R(fname, _SH_DENYRW).get().create_istream(); - istream.streambuf().set_buffer_size(128); + { + istream.seek(50, std::ios_base::beg); + concurrency::streams::rawptr_buffer block(readdata, sizeof(readdata)); + istream.read(block, 50).get(); + } - { - istream.seek(50, std::ios_base::beg); - concurrency::streams::rawptr_buffer block(readdata, sizeof(readdata)); - istream.read(block, 50).get(); + { + istream.seek(256, std::ios_base::beg); + concurrency::streams::rawptr_buffer block(readdata, sizeof(readdata)); + istream.read(block, 256).get(); + } + + istream.close().get(); } + TEST(file_size) { - istream.seek(256, std::ios_base::beg); - concurrency::streams::rawptr_buffer block(readdata, sizeof(readdata)); - istream.read(block, 256).get(); + utility::string_t fname = U("file_size.txt"); + fill_file(fname, 100); + auto istream = OPEN_R(fname).get(); + VERIFY_IS_TRUE(istream.has_size()); + VERIFY_ARE_EQUAL(istream.size(), 2600); } - istream.close().get(); -} - -TEST(file_size) -{ - utility::string_t fname = U("file_size.txt"); - fill_file(fname,100); - auto istream = OPEN_R(fname).get(); - VERIFY_IS_TRUE(istream.has_size()); - VERIFY_ARE_EQUAL(istream.size(), 2600); - -} - #ifdef _WIN32 -TEST(file_size_w) -{ - utility::string_t fname = U("file_size_w.txt"); - fill_file_w(fname,100); - auto istream = OPEN_R(fname).get(); - VERIFY_IS_TRUE(istream.has_size()); - VERIFY_ARE_EQUAL(istream.size(), 2600); - -} + TEST(file_size_w) + { + utility::string_t fname = U("file_size_w.txt"); + fill_file_w(fname, 100); + auto istream = OPEN_R(fname).get(); + VERIFY_IS_TRUE(istream.has_size()); + VERIFY_ARE_EQUAL(istream.size(), 2600); + } -TEST(file_with_one_byte_size) -{ - // Create a file with one byte. - concurrency::streams::streambuf file_buf = OPEN(U("one_byte_file.txt"), std::ios_base::out).get(); - file_buf.putc('a').wait(); - file_buf.close().wait(); - - // Try to read from file with a 2 byte character. - concurrency::streams::basic_istream inFile(OPEN(U("one_byte_file.txt"), std::ios::in).get()); - concurrency::streams::container_buffer buffer; - VERIFY_ARE_EQUAL(inFile.read(buffer, 1).get(), 0); - VERIFY_IS_TRUE(inFile.is_eof()); -} + TEST(file_with_one_byte_size) + { + // Create a file with one byte. + concurrency::streams::streambuf file_buf = OPEN(U("one_byte_file.txt"), std::ios_base::out).get(); + file_buf.putc('a').wait(); + file_buf.close().wait(); + + // Try to read from file with a 2 byte character. + concurrency::streams::basic_istream inFile(OPEN(U("one_byte_file.txt"), std::ios::in).get()); + concurrency::streams::container_buffer buffer; + VERIFY_ARE_EQUAL(inFile.read(buffer, 1).get(), 0); + VERIFY_IS_TRUE(inFile.is_eof()); + } #endif #if defined(_WIN32) && (!defined(__cplusplus_winrt)) && defined(_WIN64) -// since casablanca does not use sparse file apis we're not doing the reverse test (write one byte at 4Gb and verify with std apis) -// because the file created would be too big -TEST(read_one_byte_at_4G) -{ - // Create a file with one byte. - string_t filename = U("read_one_byte_at_4G.txt"); - // create a sparse file with sparse file apis - auto handle = CreateSparseFile(filename.c_str()); - VERIFY_ARE_NOT_EQUAL(handle, INVALID_HANDLE_VALUE); + // since casablanca does not use sparse file apis we're not doing the reverse test (write one byte at 4Gb and verify + // with std apis) because the file created would be too big + TEST(read_one_byte_at_4G) + { + // Create a file with one byte. + string_t filename = U("read_one_byte_at_4G.txt"); + // create a sparse file with sparse file apis + auto handle = CreateSparseFile(filename.c_str()); + VERIFY_ARE_NOT_EQUAL(handle, INVALID_HANDLE_VALUE); - // write 1 byte - auto data = 'a'; + // write 1 byte + auto data = 'a'; - DWORD dwBytesWritten; - LARGE_INTEGER i; - i.QuadPart = 0x100000000; + DWORD dwBytesWritten; + LARGE_INTEGER i; + i.QuadPart = 0x100000000; - SetFilePointerEx(handle, i /*4GB*/, NULL, FILE_END); - WriteFile(handle, &data, 1, &dwBytesWritten, NULL); + SetFilePointerEx(handle, i /*4GB*/, NULL, FILE_END); + WriteFile(handle, &data, 1, &dwBytesWritten, NULL); - CloseHandle(handle); + CloseHandle(handle); - // read the file with casablanca streams - concurrency::streams::streambuf file_buf = OPEN(filename, std::ios_base::in).get(); - file_buf.seekoff(4 * 1024 * 1024 * 1024ll, ::std::ios_base::beg, ::std::ios_base::in); + // read the file with casablanca streams + concurrency::streams::streambuf file_buf = OPEN(filename, std::ios_base::in).get(); + file_buf.seekoff(4 * 1024 * 1024 * 1024ll, ::std::ios_base::beg, ::std::ios_base::in); - int aCharacter = file_buf.getc().get(); - file_buf.close().wait(); + int aCharacter = file_buf.getc().get(); + file_buf.close().wait(); - VERIFY_ARE_EQUAL(aCharacter, data); -} + VERIFY_ARE_EQUAL(aCharacter, data); + } #endif #if !defined(_WIN32) && defined(__x86_64__) -struct TidyStream -{ - string_t _fileName; - concurrency::streams::streambuf _stream; + struct TidyStream + { + string_t _fileName; + concurrency::streams::streambuf _stream; - TidyStream(string_t filename) + TidyStream(string_t filename) + { + _fileName = filename; + _stream = OPEN(filename, std::ios_base::out | ::std::ios_base::in).get(); + } + + ~TidyStream() + { + _stream.close().wait(); + std::remove(_fileName.c_str()); + } + }; + + TEST(write_one_byte_at_4G) { - _fileName = filename; - _stream = OPEN(filename, std::ios_base::out | ::std::ios_base::in).get(); + // write using casablanca streams + concurrency::streams::streambuf::off_type pos = 4 * 1024 * 1024 * 1024ll; + + string_t filename = U("write_one_byte_at_4G.txt"); + TidyStream file_buf(filename); + file_buf._stream.seekoff(pos, ::std::ios_base::beg, ::std::ios_base::out); + file_buf._stream.putc('a').wait(); + file_buf._stream.sync().get(); + + // verify with std streams + std::fstream stream(get_full_name(filename), std::ios_base::in); + stream.seekg(pos); + char c; + stream >> c; + stream.close(); + VERIFY_ARE_EQUAL(c, 'a'); } - ~TidyStream() + TEST(read_one_byte_at_4G) { - _stream.close().wait(); - std::remove(_fileName.c_str()); + // write with std stream + concurrency::streams::streambuf::off_type pos = 4 * 1024 * 1024 * 1024ll; + // Create a file with one byte. + string_t filename = U("read_one_byte_at_4G.txt"); + + std::fstream stream(get_full_name(filename), std::ios_base::out); + stream.seekg(pos); + stream << 'a'; + stream.close(); + + // verify with casablanca streams + TidyStream file_buf(filename); + file_buf._stream.seekoff(pos, ::std::ios_base::beg, ::std::ios_base::in); + int aCharacter = file_buf._stream.getc().get(); + + VERIFY_ARE_EQUAL(aCharacter, 'a'); } -}; - -TEST(write_one_byte_at_4G) -{ - // write using casablanca streams - concurrency::streams::streambuf::off_type pos = 4 * 1024 * 1024 * 1024ll; - - string_t filename = U("write_one_byte_at_4G.txt"); - TidyStream file_buf(filename); - file_buf._stream.seekoff(pos, ::std::ios_base::beg, ::std::ios_base::out); - file_buf._stream.putc('a').wait(); - file_buf._stream.sync().get(); - - // verify with std streams - std::fstream stream(get_full_name(filename), std::ios_base::in); - stream.seekg(pos); - char c; - stream >> c; - stream.close(); - VERIFY_ARE_EQUAL(c, 'a'); -} - -TEST(read_one_byte_at_4G) -{ - // write with std stream - concurrency::streams::streambuf::off_type pos = 4 * 1024 * 1024 * 1024ll; - // Create a file with one byte. - string_t filename = U("read_one_byte_at_4G.txt"); - - std::fstream stream(get_full_name(filename), std::ios_base::out); - stream.seekg(pos); - stream << 'a'; - stream.close(); - - // verify with casablanca streams - TidyStream file_buf(filename); - file_buf._stream.seekoff(pos, ::std::ios_base::beg, ::std::ios_base::in); - int aCharacter = file_buf._stream.getc().get(); - - VERIFY_ARE_EQUAL(aCharacter, 'a'); -} #endif -TEST(alloc_acquire_not_supported) -{ - concurrency::streams::streambuf file_buf = OPEN(U("alloc_not_supported.txt"), std::ios::out | std::ios::in).get(); - VERIFY_IS_TRUE(file_buf.alloc(1) == nullptr); - char *temp; - size_t size; - VERIFY_IS_FALSE(file_buf.acquire(temp, size)); -} + TEST(alloc_acquire_not_supported) + { + concurrency::streams::streambuf file_buf = + OPEN(U("alloc_not_supported.txt"), std::ios::out | std::ios::in).get(); + VERIFY_IS_TRUE(file_buf.alloc(1) == nullptr); + char* temp; + size_t size; + VERIFY_IS_FALSE(file_buf.acquire(temp, size)); + } -TEST(read_alloc_acquire_not_supported) -{ - auto file_buf1 = OPEN(U("read_acquire_not_supported1.txt"), std::ios::out | std::ios::in).get(); - auto file_buf2 = OPEN(U("read_acquire_not_supported2.txt"), std::ios::out | std::ios::in).get(); - - concurrency::streams::stringstreambuf data_buf("A"); - file_buf1.create_ostream().write(data_buf, 1).wait(); - file_buf1.sync().wait(); - file_buf2.create_ostream().write(file_buf1, 1).wait(); - file_buf2.sync().wait(); - - file_buf2.create_istream().read(file_buf1, 1).wait(); - file_buf1.sync().wait(); - file_buf1.seekpos(0, std::ios::in); - data_buf = concurrency::streams::stringstreambuf(); - file_buf1.create_istream().read(data_buf, 2).wait(); - const auto &data = data_buf.collection(); - VERIFY_ARE_EQUAL(data[0], 'A'); - VERIFY_ARE_EQUAL(data[1], 'A'); - - file_buf1.close().wait(); - file_buf2.close().wait(); -} + TEST(read_alloc_acquire_not_supported) + { + auto file_buf1 = OPEN(U("read_acquire_not_supported1.txt"), std::ios::out | std::ios::in).get(); + auto file_buf2 = OPEN(U("read_acquire_not_supported2.txt"), std::ios::out | std::ios::in).get(); + + concurrency::streams::stringstreambuf data_buf("A"); + file_buf1.create_ostream().write(data_buf, 1).wait(); + file_buf1.sync().wait(); + file_buf2.create_ostream().write(file_buf1, 1).wait(); + file_buf2.sync().wait(); + + file_buf2.create_istream().read(file_buf1, 1).wait(); + file_buf1.sync().wait(); + file_buf1.seekpos(0, std::ios::in); + data_buf = concurrency::streams::stringstreambuf(); + file_buf1.create_istream().read(data_buf, 2).wait(); + const auto& data = data_buf.collection(); + VERIFY_ARE_EQUAL(data[0], 'A'); + VERIFY_ARE_EQUAL(data[1], 'A'); + + file_buf1.close().wait(); + file_buf2.close().wait(); + } -TEST(winrt_filestream_close) -{ - std::string str("test data"); - auto t = OPEN_W(U("file.txt")).then( - [this, str](concurrency::streams::ostream stream) + TEST(winrt_filestream_close) { - concurrency::streams::container_buffer rbuf(str); - concurrency::streams::istream is(rbuf); - size_t size = 0; - is.read(stream.streambuf(), 1).wait(); - while (!is.is_eof()) - { + std::string str("test data"); + auto t = OPEN_W(U("file.txt")).then([this, str](concurrency::streams::ostream stream) { + concurrency::streams::container_buffer rbuf(str); + concurrency::streams::istream is(rbuf); + size_t size = 0; is.read(stream.streambuf(), 1).wait(); - size += 1; - } - - return stream.flush().then([size, stream](){ - stream.close(); - return size; + while (!is.is_eof()) + { + is.read(stream.streambuf(), 1).wait(); + size += 1; + } + + return stream.flush().then([size, stream]() { + stream.close(); + return size; + }); }); - }); - VERIFY_ARE_EQUAL(t.get(), str.length()); -} + VERIFY_ARE_EQUAL(t.get(), str.length()); + } } // SUITE(file_buffer_tests) -}}} +} // namespace streams +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/streams/fuzz_tests.cpp b/Release/tests/functional/streams/fuzz_tests.cpp index 651d4f1c9d..7b10e1210b 100644 --- a/Release/tests/functional/streams/fuzz_tests.cpp +++ b/Release/tests/functional/streams/fuzz_tests.cpp @@ -1,113 +1,116 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Fuzzing tests for streams read operations that involve parsing of data. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Fuzzing tests for streams read operations that involve parsing of data. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace concurrency::streams; -namespace tests { namespace functional { namespace streams { - +namespace tests +{ +namespace functional +{ +namespace streams +{ using namespace utility; using namespace ::pplx; SUITE(streams_fuzz_tests) { -std::string get_fuzzed_file_path(std::string requires_str) -{ - std::string ipfile; - - if(UnitTest::GlobalSettings::Has(requires_str)) + std::string get_fuzzed_file_path(std::string requires_str) { - ipfile = UnitTest::GlobalSettings::Get(requires_str); - } + std::string ipfile; - return ipfile; -} + if (UnitTest::GlobalSettings::Has(requires_str)) + { + ipfile = UnitTest::GlobalSettings::Get(requires_str); + } -concurrency::streams::basic_istream get_input_stream(std::string requires_str) -{ - utility::string_t ipfile = utility::conversions::to_string_t(get_fuzzed_file_path(requires_str)); - concurrency::streams::basic_istream ifs; - - if (true == ipfile.empty()) - { - VERIFY_IS_TRUE(false, "Input file is empty"); - return ifs; + return ipfile; } - ifs = concurrency::streams::file_stream::open_istream(ipfile, std::ios::in).get(); - - // Look for UTF-8 BOM - if (ifs.read().get() != 0xEF || ifs.read().get() != 0xBB || ifs.read().get() != 0xBF) + concurrency::streams::basic_istream get_input_stream(std::string requires_str) { - VERIFY_IS_TRUE(false, "Input file encoding is not UTF-8. Test will not parse the file."); - ifs.close().get(); + utility::string_t ipfile = utility::conversions::to_string_t(get_fuzzed_file_path(requires_str)); + concurrency::streams::basic_istream ifs; + + if (true == ipfile.empty()) + { + VERIFY_IS_TRUE(false, "Input file is empty"); + return ifs; + } + + ifs = concurrency::streams::file_stream::open_istream(ipfile, std::ios::in).get(); + + // Look for UTF-8 BOM + if (ifs.read().get() != 0xEF || ifs.read().get() != 0xBB || ifs.read().get() != 0xBF) + { + VERIFY_IS_TRUE(false, "Input file encoding is not UTF-8. Test will not parse the file."); + ifs.close().get(); + } + return ifs; } - return ifs; -} -TEST(fuzz_read_line, "Requires", "fuzz_read_line_ipfile", "Timeout", "600000") -{ - auto ifs = get_input_stream("fuzz_read_line_ipfile"); - if(!ifs.is_valid() || !ifs.is_open()) - return; - - size_t num_lines = 0; - while(false == ifs.is_eof()) + TEST(fuzz_read_line, "Requires", "fuzz_read_line_ipfile", "Timeout", "600000") { - container_buffer> buf; - ifs.read_line(buf).get(); - num_lines++; + auto ifs = get_input_stream("fuzz_read_line_ipfile"); + if (!ifs.is_valid() || !ifs.is_open()) return; + + size_t num_lines = 0; + while (false == ifs.is_eof()) + { + container_buffer> buf; + ifs.read_line(buf).get(); + num_lines++; + } + ifs.close().get(); + std::wcout << U("Number of lines read:") << num_lines; } - ifs.close().get(); - std::wcout << U("Number of lines read:") << num_lines; -} -template -void extract(const basic_istream & ifs) -{ - try - { - ifs.extract().get(); - } - catch(std::exception) + template + void extract(const basic_istream& ifs) { - } - return; -} - -TEST(fuzz_extract, "Requires", "fuzz_extract_ipfile", "Timeout", "600000") -{ - auto ifs = get_input_stream("fuzz_extract_ipfile"); - if(!ifs.is_valid() || !ifs.is_open()) + try + { + ifs.extract().get(); + } + catch (std::exception) + { + } return; + } - int num_lines = 0; - while(false == ifs.is_eof()) + TEST(fuzz_extract, "Requires", "fuzz_extract_ipfile", "Timeout", "600000") { - extract(ifs); - extract(ifs); - extract(ifs); - extract(ifs); - extract(ifs); - extract(ifs); - extract(ifs); - container_buffer> buf; - ifs.read_line(buf).get(); - num_lines++; + auto ifs = get_input_stream("fuzz_extract_ipfile"); + if (!ifs.is_valid() || !ifs.is_open()) return; + + int num_lines = 0; + while (false == ifs.is_eof()) + { + extract(ifs); + extract(ifs); + extract(ifs); + extract(ifs); + extract(ifs); + extract(ifs); + extract(ifs); + container_buffer> buf; + ifs.read_line(buf).get(); + num_lines++; + } + ifs.close().get(); + std::wcout << L"Number of lines read:" << num_lines << std::endl; } - ifs.close().get(); - std::wcout << L"Number of lines read:" << num_lines << std::endl; -} } // SUITE(streams_fuzz_tests) -}}} - +} // namespace streams +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/streams/istream_tests.cpp b/Release/tests/functional/streams/istream_tests.cpp index db12390c57..d1018e3116 100644 --- a/Release/tests/functional/streams/istream_tests.cpp +++ b/Release/tests/functional/streams/istream_tests.cpp @@ -1,16 +1,16 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests for async input stream operations. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ -#include "unittestpp.h" + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests for async input stream operations. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" +#include "unittestpp.h" #include #ifdef max @@ -22,34 +22,38 @@ using namespace Windows::Storage; #endif #ifdef _WIN32 -# define DEFAULT_PROT (int)std::ios_base::_Openprot +#define DEFAULT_PROT (int)std::ios_base::_Openprot #else -# define DEFAULT_PROT 0 +#define DEFAULT_PROT 0 #endif -namespace tests { namespace functional { namespace streams { - +namespace tests +{ +namespace functional +{ +namespace streams +{ using namespace ::pplx; using namespace utility; using namespace concurrency::streams; // Used to prepare data for file-stream read tests -utility::string_t get_full_name(const utility::string_t &name) +utility::string_t get_full_name(const utility::string_t& name) { #if defined(__cplusplus_winrt) // On WinRT, we must compensate for the fact that we will be accessing files in the // Documents folder - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->CreateFileAsync( - ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)).get(); + auto file = pplx::create_task(KnownFolders::DocumentsLibrary->CreateFileAsync( + ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)) + .get(); return file->Path->Data(); #else return name; #endif } -void fill_file(const utility::string_t &name, size_t repetitions = 1) +void fill_file(const utility::string_t& name, size_t repetitions = 1) { std::fstream stream(get_full_name(name), std::ios_base::out | std::ios_base::trunc); @@ -57,7 +61,7 @@ void fill_file(const utility::string_t &name, size_t repetitions = 1) stream << "abcdefghijklmnopqrstuvwxyz"; } -void fill_file_with_lines(const utility::string_t &name, const std::string &end, size_t repetitions = 1) +void fill_file_with_lines(const utility::string_t& name, const std::string& end, size_t repetitions = 1) { std::fstream stream(get_full_name(name), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary); @@ -68,13 +72,13 @@ void fill_file_with_lines(const utility::string_t &name, const std::string &end, #ifdef _WIN32 // Disabling warning in test because we check for nullptr. -#pragma warning (push) -#pragma warning (disable : 6387) -void fill_file_w(const utility::string_t &name, size_t repetitions = 1) +#pragma warning(push) +#pragma warning(disable : 6387) +void fill_file_w(const utility::string_t& name, size_t repetitions = 1) { - FILE *stream = nullptr; + FILE* stream = nullptr; _wfopen_s(&stream, get_full_name(name).c_str(), L"w"); - if(stream == nullptr) + if (stream == nullptr) { VERIFY_IS_TRUE(false, "FILE pointer is null"); } @@ -85,7 +89,7 @@ void fill_file_w(const utility::string_t &name, size_t repetitions = 1) fclose(stream); } -#pragma warning (pop) +#pragma warning(pop) #endif @@ -98,16 +102,16 @@ void fill_file_w(const utility::string_t &name, size_t repetitions = 1) // #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable : 4100) // Because of '_Prot' in WinRT builds. +#pragma warning(disable : 4100) // Because of '_Prot' in WinRT builds. #endif template -pplx::task> OPEN_R(const utility::string_t &name, int _Prot = DEFAULT_PROT) +pplx::task> OPEN_R(const utility::string_t& name, int _Prot = DEFAULT_PROT) { #if !defined(__cplusplus_winrt) return streams::file_buffer<_CharType>::open(name, std::ios_base::in, _Prot); #else - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); + auto file = + pplx::create_task(KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); return streams::file_buffer<_CharType>::open(file, std::ios_base::in); #endif @@ -117,1461 +121,1454 @@ pplx::task> OPEN_R(const utility::string_t &name, #endif SUITE(istream_tests) { + // Tests using memory stream buffers. + TEST(stream_read_1) + { + producer_consumer_buffer rbuf; -// Tests using memory stream buffers. -TEST(stream_read_1) -{ - producer_consumer_buffer rbuf; + VERIFY_ARE_EQUAL(26u, rbuf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get()); + + istream stream(rbuf); - VERIFY_ARE_EQUAL(26u, rbuf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get()); + VERIFY_IS_FALSE(stream.can_seek()); - istream stream(rbuf); + for (char c = 'a'; c <= 'z'; c++) + { + char ch = (char)stream.read().get(); + VERIFY_ARE_EQUAL(c, ch); + } - VERIFY_IS_FALSE(stream.can_seek()); + stream.close().get(); + } - for (char c = 'a'; c <= 'z'; c++) + TEST(fstream_read_1) { - char ch = (char)stream.read().get(); - VERIFY_ARE_EQUAL(c, ch); - } + utility::string_t fname = U("fstream_read_1.txt"); + fill_file(fname); - stream.close().get(); -} + streams::basic_istream stream = OPEN_R(fname).get().create_istream(); -TEST(fstream_read_1) -{ - utility::string_t fname = U("fstream_read_1.txt"); - fill_file(fname); + VERIFY_IS_TRUE(stream.is_open()); - streams::basic_istream stream = OPEN_R(fname).get().create_istream(); + for (char c = 'a'; c <= 'z'; c++) + { + char ch = (char)stream.read().get(); + VERIFY_ARE_EQUAL(c, ch); + } - VERIFY_IS_TRUE(stream.is_open()); + stream.close().get(); + } - for (char c = 'a'; c <= 'z'; c++) + TEST(stream_read_1_fail) { - char ch = (char)stream.read().get(); - VERIFY_ARE_EQUAL(c, ch); - } + producer_consumer_buffer rbuf; - stream.close().get(); -} + VERIFY_ARE_EQUAL(26u, rbuf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get()); -TEST(stream_read_1_fail) -{ - producer_consumer_buffer rbuf; + istream stream(rbuf); + rbuf.close(std::ios_base::in).get(); + + VERIFY_THROWS(stream.read().get(), std::runtime_error); + // Closing again should not throw. + stream.close().wait(); + } - VERIFY_ARE_EQUAL(26u, rbuf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get()); + TEST(stream_read_2) + { + producer_consumer_buffer rbuf; - istream stream(rbuf); - rbuf.close(std::ios_base::in).get(); + VERIFY_ARE_EQUAL(26u, rbuf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get()); - VERIFY_THROWS(stream.read().get(), std::runtime_error); - // Closing again should not throw. - stream.close().wait(); -} + istream stream(rbuf); -TEST(stream_read_2) -{ - producer_consumer_buffer rbuf; + uint8_t buffer[128]; + streams::rawptr_buffer tbuf(buffer, 128); - VERIFY_ARE_EQUAL(26u, rbuf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get()); + VERIFY_ARE_EQUAL(26u, stream.read(tbuf, 26).get()); - istream stream(rbuf); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - uint8_t buffer[128]; - streams::rawptr_buffer tbuf(buffer, 128); + rbuf.close(std::ios_base::out).get(); - VERIFY_ARE_EQUAL(26u, stream.read(tbuf, 26).get()); + VERIFY_ARE_EQUAL(0u, stream.read(tbuf, 26).get()); - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); } - rbuf.close(std::ios_base::out).get(); - - VERIFY_ARE_EQUAL(0u, stream.read(tbuf, 26).get()); + TEST(fstream_read_2) + { + utility::string_t fname = U("fstream_read_2.txt"); + fill_file(fname); - stream.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + streams::basic_istream stream = OPEN_R(fname).get().create_istream(); -TEST(fstream_read_2) -{ - utility::string_t fname = U("fstream_read_2.txt"); - fill_file(fname); + char buffer[128]; + streams::rawptr_buffer tbuf(buffer, 128); - streams::basic_istream stream = OPEN_R(fname).get().create_istream(); + VERIFY_ARE_EQUAL(26u, stream.read(tbuf, 26).get()); - char buffer[128]; - streams::rawptr_buffer tbuf(buffer, 128); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - VERIFY_ARE_EQUAL(26u, stream.read(tbuf, 26).get()); + VERIFY_ARE_EQUAL(0u, stream.read(tbuf, 26).get()); - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); } - VERIFY_ARE_EQUAL(0u, stream.read(tbuf, 26).get()); - - stream.close().get(); -} + TEST(stream_read_3) + { + producer_consumer_buffer rbuf; -TEST(stream_read_3) -{ - producer_consumer_buffer rbuf; + // There's no newline int the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - // There's no newline int the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + rbuf.close(std::ios_base::out).get(); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - rbuf.close(std::ios_base::out).get(); + istream stream(rbuf); - istream stream(rbuf); + uint8_t buffer[128]; + streams::rawptr_buffer tbuf(buffer, 128); - uint8_t buffer[128]; - streams::rawptr_buffer tbuf(buffer, 128); + VERIFY_ARE_EQUAL(52u, stream.read(tbuf, sizeof(buffer)).get()); - VERIFY_ARE_EQUAL(52u, stream.read(tbuf,sizeof(buffer)).get()); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'A', buffer[i + 26]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); - } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'A', buffer[i+26]); + stream.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); } - stream.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + TEST(stream_read_3_fail) + { + producer_consumer_buffer rbuf; -TEST(stream_read_3_fail) -{ - producer_consumer_buffer rbuf; + // There's no newline int the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - // There's no newline int the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + rbuf.close(std::ios_base::out).get(); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - rbuf.close(std::ios_base::out).get(); + istream stream(rbuf); - istream stream(rbuf); + uint8_t buffer[128]; + streams::rawptr_buffer tbuf(buffer, 128); + tbuf.close(std::ios_base::out).get(); - uint8_t buffer[128]; - streams::rawptr_buffer tbuf(buffer, 128); - tbuf.close(std::ios_base::out).get(); + VERIFY_THROWS(stream.read(tbuf, sizeof(buffer)).get(), std::runtime_error); - VERIFY_THROWS(stream.read(tbuf,sizeof(buffer)).get(), std::runtime_error); + stream.close().get(); + } - stream.close().get(); -} + TEST(stream_read_4) + { + producer_consumer_buffer rbuf; + producer_consumer_buffer trg; -TEST(stream_read_4) -{ - producer_consumer_buffer rbuf; - producer_consumer_buffer trg; + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + rbuf.close(std::ios_base::out).get(); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - rbuf.close(std::ios_base::out).get(); + streams::basic_istream stream = rbuf; - streams::basic_istream stream = rbuf; + VERIFY_ARE_EQUAL(52u, stream.read_to_delim(trg, '\n').get()); - VERIFY_ARE_EQUAL(52u, stream.read_to_delim(trg, '\n').get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(52u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(52u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'A', buffer[i + 26]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); - } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'A', buffer[i+26]); + stream.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); } - stream.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + TEST(fstream_read_4) + { + producer_consumer_buffer trg; -TEST(fstream_read_4) -{ - producer_consumer_buffer trg; + utility::string_t fname = U("fstream_read_4.txt"); + fill_file(fname, 2); - utility::string_t fname = U("fstream_read_4.txt"); - fill_file(fname, 2); + streams::basic_istream stream = OPEN_R(fname).get().create_istream(); - streams::basic_istream stream = OPEN_R(fname).get().create_istream(); + VERIFY_ARE_EQUAL(52u, stream.read_to_delim(trg, '\n').get()); - VERIFY_ARE_EQUAL(52u, stream.read_to_delim(trg, '\n').get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(52u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(52u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i + 26]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); } - for (int i = 0; i < 26; i++) + + TEST(stream_read_4_fail) { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i+26]); - } + producer_consumer_buffer rbuf; + producer_consumer_buffer trg; - stream.close().get(); -} + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); -TEST(stream_read_4_fail) -{ - producer_consumer_buffer rbuf; - producer_consumer_buffer trg; + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + rbuf.close(std::ios_base::out).get(); - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + streams::basic_istream stream = rbuf; - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - rbuf.close(std::ios_base::out).get(); + trg.close(std::ios::out).get(); - streams::basic_istream stream = rbuf; + VERIFY_THROWS(stream.read_to_delim(trg, '\n').get(), std::runtime_error); - trg.close(std::ios::out).get(); + stream.close().get(); + } - VERIFY_THROWS(stream.read_to_delim(trg, '\n').get(), std::runtime_error); + TEST(stream_read_5) + { + producer_consumer_buffer rbuf; + producer_consumer_buffer trg; - stream.close().get(); -} + // There's one newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz\n\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); -TEST(stream_read_5) -{ - producer_consumer_buffer rbuf; - producer_consumer_buffer trg; - - // There's one newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz\n\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + istream stream(rbuf); - istream stream(rbuf); + VERIFY_IS_FALSE(stream.is_eof()); + VERIFY_ARE_EQUAL(26u, stream.read_to_delim(trg, '\n').get()); + VERIFY_IS_FALSE(stream.is_eof()); + VERIFY_ARE_EQUAL(0u, stream.read_to_delim(trg, '\n').get()); + VERIFY_IS_FALSE(stream.is_eof()); + VERIFY_ARE_EQUAL('A', (char)rbuf.getc().get()); - VERIFY_IS_FALSE(stream.is_eof()); - VERIFY_ARE_EQUAL(26u, stream.read_to_delim(trg, '\n').get()); - VERIFY_IS_FALSE(stream.is_eof()); - VERIFY_ARE_EQUAL(0u, stream.read_to_delim(trg, '\n').get()); - VERIFY_IS_FALSE(stream.is_eof()); - VERIFY_ARE_EQUAL('A', (char)rbuf.getc().get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(26u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(26u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); } - stream.close().get(); -} + TEST(fstream_read_5) + { + producer_consumer_buffer trg; -TEST(fstream_read_5) -{ - producer_consumer_buffer trg; + utility::string_t fname = U("fstream_read_5.txt"); + fill_file_with_lines(fname, "\n", 2); - utility::string_t fname = U("fstream_read_5.txt"); - fill_file_with_lines(fname, "\n", 2); + streams::basic_istream stream = OPEN_R(fname).get().create_istream(); - streams::basic_istream stream = OPEN_R(fname).get().create_istream(); + VERIFY_ARE_EQUAL(26u, stream.read_to_delim(trg, '\n').get()); + VERIFY_ARE_EQUAL('a', (char)stream.read().get()); - VERIFY_ARE_EQUAL(26u, stream.read_to_delim(trg, '\n').get()); - VERIFY_ARE_EQUAL('a', (char)stream.read().get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(26u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(26u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); } - stream.close().get(); -} + TEST(stream_readline_1) + { + producer_consumer_buffer rbuf; + producer_consumer_buffer trg; -TEST(stream_readline_1) -{ - producer_consumer_buffer rbuf; - producer_consumer_buffer trg; + // There's one newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - // There's one newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + istream stream(rbuf); - istream stream(rbuf); + VERIFY_ARE_EQUAL(26u, stream.read_line(trg).get()); + VERIFY_ARE_EQUAL('A', (char)rbuf.getc().get()); - VERIFY_ARE_EQUAL(26u, stream.read_line(trg).get()); - VERIFY_ARE_EQUAL('A', (char)rbuf.getc().get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(26u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(26u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); } - stream.close().get(); -} + TEST(stream_readline_1_fail) + { + producer_consumer_buffer rbuf; + producer_consumer_buffer trg; -TEST(stream_readline_1_fail) -{ - producer_consumer_buffer rbuf; - producer_consumer_buffer trg; + // There's one newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - // There's one newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + istream stream(rbuf); - istream stream(rbuf); + trg.close(std::ios_base::out).get(); - trg.close(std::ios_base::out).get(); + VERIFY_THROWS(stream.read_line(trg).get(), std::runtime_error); - VERIFY_THROWS(stream.read_line(trg).get(), std::runtime_error); + stream.close().get(); + } - stream.close().get(); -} + TEST(stream_readline_2) + { + producer_consumer_buffer rbuf; + producer_consumer_buffer trg; -TEST(stream_readline_2) -{ - producer_consumer_buffer rbuf; - producer_consumer_buffer trg; + // There's one newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz\r\n\r\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - // There's one newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz\r\n\r\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + istream stream(rbuf); - istream stream(rbuf); + VERIFY_IS_FALSE(stream.is_eof()); + VERIFY_ARE_EQUAL(26u, stream.read_line(trg).get()); + VERIFY_IS_FALSE(stream.is_eof()); + VERIFY_ARE_EQUAL(0u, stream.read_line(trg).get()); + VERIFY_IS_FALSE(stream.is_eof()); + VERIFY_ARE_EQUAL('A', (char)rbuf.getc().get()); - VERIFY_IS_FALSE(stream.is_eof()); - VERIFY_ARE_EQUAL(26u, stream.read_line(trg).get()); - VERIFY_IS_FALSE(stream.is_eof()); - VERIFY_ARE_EQUAL(0u, stream.read_line(trg).get()); - VERIFY_IS_FALSE(stream.is_eof()); - VERIFY_ARE_EQUAL('A', (char)rbuf.getc().get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(26u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(26u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); } - stream.close().get(); -} + TEST(fstream_readline_1) + { + producer_consumer_buffer trg; -TEST(fstream_readline_1) -{ - producer_consumer_buffer trg; + utility::string_t fname = U("fstream_readline_1.txt"); + fill_file_with_lines(fname, "\n", 2); - utility::string_t fname = U("fstream_readline_1.txt"); - fill_file_with_lines(fname, "\n", 2); + streams::basic_istream stream = OPEN_R(fname).get().create_istream(); - streams::basic_istream stream = OPEN_R(fname).get().create_istream(); + VERIFY_ARE_EQUAL(26u, stream.read_line(trg).get()); + VERIFY_ARE_EQUAL('a', (char)stream.read().get()); - VERIFY_ARE_EQUAL(26u, stream.read_line(trg).get()); - VERIFY_ARE_EQUAL('a', (char)stream.read().get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(26u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(26u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); } - stream.close().get(); -} + TEST(fstream_readline_2) + { + producer_consumer_buffer trg; -TEST(fstream_readline_2) -{ - producer_consumer_buffer trg; + utility::string_t fname = U("fstream_readline_2.txt"); + fill_file_with_lines(fname, "\r\n", 2); - utility::string_t fname = U("fstream_readline_2.txt"); - fill_file_with_lines(fname, "\r\n", 2); + streams::basic_istream stream = OPEN_R(fname).get().create_istream(); - streams::basic_istream stream = OPEN_R(fname).get().create_istream(); + VERIFY_ARE_EQUAL(26u, stream.read_line(trg).get()); + VERIFY_ARE_EQUAL('a', (char)stream.read().get()); - VERIFY_ARE_EQUAL(26u, stream.read_line(trg).get()); - VERIFY_ARE_EQUAL('a', (char)stream.read().get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(26u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(26u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); } - stream.close().get(); -} + TEST(stream_read_6) + { + producer_consumer_buffer rbuf; + producer_consumer_buffer trg; -TEST(stream_read_6) -{ - producer_consumer_buffer rbuf; - producer_consumer_buffer trg; + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + rbuf.close(std::ios_base::out).get(); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - rbuf.close(std::ios_base::out).get(); + istream stream(rbuf); - istream stream(rbuf); + VERIFY_ARE_EQUAL(52u, stream.read_to_delim(trg, '|').get()); - VERIFY_ARE_EQUAL(52u, stream.read_to_delim(trg, '|').get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(52u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(52u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'A', buffer[i + 26]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); - } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'A', buffer[i+26]); + stream.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); } - stream.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + TEST(stream_read_7) + { + producer_consumer_buffer rbuf; + producer_consumer_buffer trg; -TEST(stream_read_7) -{ - producer_consumer_buffer rbuf; - producer_consumer_buffer trg; + // There's one delimiter in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - // There's one delimiter in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + istream stream(rbuf); - istream stream(rbuf); + VERIFY_ARE_EQUAL(26u, stream.read_to_delim(trg, '|').get()); + VERIFY_ARE_EQUAL('A', (char)rbuf.getc().get()); - VERIFY_ARE_EQUAL(26u, stream.read_to_delim(trg, '|').get()); - VERIFY_ARE_EQUAL('A', (char)rbuf.getc().get()); + uint8_t buffer[128]; + VERIFY_ARE_EQUAL(26u, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - uint8_t buffer[128]; - VERIFY_ARE_EQUAL(26u, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + stream.close().get(); } - stream.close().get(); -} - -TEST(stream_read_to_end_1) -{ - // Create a really large (200KB) stream and read into a stream buffer. - // It should not take a long time to do this test. - - producer_consumer_buffer rbuf; - - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); - - for (int i = 0; i < 4096; ++i) + TEST(stream_read_to_end_1) { - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - } + // Create a really large (200KB) stream and read into a stream buffer. + // It should not take a long time to do this test. - rbuf.close(std::ios_base::out).get(); + producer_consumer_buffer rbuf; - streams::basic_istream stream = rbuf; + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - streams::stringstreambuf sbuf; - auto& target = sbuf.collection(); + for (int i = 0; i < 4096; ++i) + { + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + } - VERIFY_ARE_EQUAL(len*4096, stream.read_to_end(sbuf).get()); - VERIFY_ARE_EQUAL(len*4096, target.size()); + rbuf.close(std::ios_base::out).get(); - stream.close().get(); - sbuf.close().get(); -} + streams::basic_istream stream = rbuf; -TEST(stream_read_to_end_1_fail) -{ - producer_consumer_buffer rbuf; + streams::stringstreambuf sbuf; + auto& target = sbuf.collection(); - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + VERIFY_ARE_EQUAL(len * 4096, stream.read_to_end(sbuf).get()); + VERIFY_ARE_EQUAL(len * 4096, target.size()); - for (int i = 0; i < 4096; ++i) - { - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + stream.close().get(); + sbuf.close().get(); } - rbuf.close(std::ios_base::out).get(); + TEST(stream_read_to_end_1_fail) + { + producer_consumer_buffer rbuf; - streams::basic_istream stream = rbuf; + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - streams::stringstreambuf sbuf; - sbuf.close(std::ios_base::out).get(); + for (int i = 0; i < 4096; ++i) + { + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + } - VERIFY_THROWS(stream.read_to_end(sbuf).get(), std::runtime_error); + rbuf.close(std::ios_base::out).get(); - stream.close().get(); - // This should not throw - sbuf.close().wait(); -} + streams::basic_istream stream = rbuf; -TEST(fstream_read_to_end_1) -{ - // Create a really large (100KB) stream and read into a stream buffer. - // It should not take a long time to do this test. + streams::stringstreambuf sbuf; + sbuf.close(std::ios_base::out).get(); - utility::string_t fname = U("fstream_read_to_end_1.txt"); - fill_file(fname, 4096); + VERIFY_THROWS(stream.read_to_end(sbuf).get(), std::runtime_error); - streams::basic_istream stream = OPEN_R(fname).get().create_istream(); + stream.close().get(); + // This should not throw + sbuf.close().wait(); + } - streams::stringstreambuf sbuf; - VERIFY_IS_FALSE(stream.is_eof()); - auto& target = sbuf.collection(); + TEST(fstream_read_to_end_1) + { + // Create a really large (100KB) stream and read into a stream buffer. + // It should not take a long time to do this test. - VERIFY_ARE_EQUAL(26*4096, stream.read_to_end(sbuf).get()); - VERIFY_ARE_EQUAL(26*4096, target.size()); - VERIFY_IS_TRUE(stream.is_eof()); + utility::string_t fname = U("fstream_read_to_end_1.txt"); + fill_file(fname, 4096); - stream.close().get(); - sbuf.close().get(); -} + streams::basic_istream stream = OPEN_R(fname).get().create_istream(); -TEST(fstream_read_to_end_2) -{ - // Read a file to end with is_eof tests. - utility::string_t fname = U("fstream_read_to_end_2.txt"); - fill_file(fname); - - streams::basic_istream stream = OPEN_R(fname).get().create_istream(); - - streams::stringstreambuf sbuf; - int c; - while(c = stream.read().get(), !stream.is_eof()) - sbuf.putc(static_cast(c)).get(); - auto& target = sbuf.collection(); - VERIFY_ARE_EQUAL(26, target.size()); - VERIFY_IS_TRUE(stream.is_eof()); - - stream.close().get(); - sbuf.close().get(); -} + streams::stringstreambuf sbuf; + VERIFY_IS_FALSE(stream.is_eof()); + auto& target = sbuf.collection(); + VERIFY_ARE_EQUAL(26 * 4096, stream.read_to_end(sbuf).get()); + VERIFY_ARE_EQUAL(26 * 4096, target.size()); + VERIFY_IS_TRUE(stream.is_eof()); -TEST(fstream_read_to_end_3) -{ - // Async Read a file to end with is_eof tests. - utility::string_t fname = U("fstream_read_to_end_3.txt"); - fill_file(fname, 1); + stream.close().get(); + sbuf.close().get(); + } + + TEST(fstream_read_to_end_2) + { + // Read a file to end with is_eof tests. + utility::string_t fname = U("fstream_read_to_end_2.txt"); + fill_file(fname); + + streams::basic_istream stream = OPEN_R(fname).get().create_istream(); + + streams::stringstreambuf sbuf; + int c; + while (c = stream.read().get(), !stream.is_eof()) + sbuf.putc(static_cast(c)).get(); + auto& target = sbuf.collection(); + VERIFY_ARE_EQUAL(26, target.size()); + VERIFY_IS_TRUE(stream.is_eof()); + + stream.close().get(); + sbuf.close().get(); + } - streams::basic_istream stream = OPEN_R(fname).get().create_istream(); + TEST(fstream_read_to_end_3) + { + // Async Read a file to end with is_eof tests. + utility::string_t fname = U("fstream_read_to_end_3.txt"); + fill_file(fname, 1); + + streams::basic_istream stream = OPEN_R(fname).get().create_istream(); - streams::stringstreambuf sbuf; - // workaround VC10 's bug. - auto lambda2 = [](int) { return true; }; - auto lambda1 = [sbuf, stream, lambda2](int val) mutable -> pplx::task { + streams::stringstreambuf sbuf; + // workaround VC10 's bug. + auto lambda2 = [](int) { return true; }; + auto lambda1 = [sbuf, stream, lambda2](int val) mutable -> pplx::task { if (!stream.is_eof()) return sbuf.putc(static_cast(val)).then(lambda2); else return pplx::task_from_result(false); }; - pplx::details::_do_while([=]()-> pplx::task { - return stream.read().then(lambda1); - }).wait(); - - auto& target = sbuf.collection(); - VERIFY_ARE_EQUAL(26, target.size()); - VERIFY_IS_TRUE(stream.is_eof()); + pplx::details::_do_while([=]() -> pplx::task { return stream.read().then(lambda1); }).wait(); - stream.close().get(); - sbuf.close().get(); -} + auto& target = sbuf.collection(); + VERIFY_ARE_EQUAL(26, target.size()); + VERIFY_IS_TRUE(stream.is_eof()); + stream.close().get(); + sbuf.close().get(); + } -TEST(stream_read_to_delim_flush) -{ - producer_consumer_buffer rbuf; + TEST(stream_read_to_delim_flush) + { + producer_consumer_buffer rbuf; - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - rbuf.close(std::ios_base::out).get(); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + rbuf.close(std::ios_base::out).get(); - streams::basic_istream stream = rbuf; + streams::basic_istream stream = rbuf; - producer_consumer_buffer sbuf; + producer_consumer_buffer sbuf; - char chars[128]; + char chars[128]; - VERIFY_ARE_EQUAL(26u, stream.read_to_delim(sbuf, '|').get()); - // The read_to_delim() should have flushed, so we should be getting what's there, - // less than we asked for. - VERIFY_ARE_EQUAL(26u, sbuf.getn(chars, 100).get()); + VERIFY_ARE_EQUAL(26u, stream.read_to_delim(sbuf, '|').get()); + // The read_to_delim() should have flushed, so we should be getting what's there, + // less than we asked for. + VERIFY_ARE_EQUAL(26u, sbuf.getn(chars, 100).get()); - stream.close().get(); - sbuf.close().get(); -} + stream.close().get(); + sbuf.close().get(); + } -TEST(stream_read_line_flush) -{ - producer_consumer_buffer rbuf; + TEST(stream_read_line_flush) + { + producer_consumer_buffer rbuf; - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - rbuf.close(std::ios_base::out).get(); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + rbuf.close(std::ios_base::out).get(); - streams::basic_istream stream = rbuf; + streams::basic_istream stream = rbuf; - producer_consumer_buffer sbuf; + producer_consumer_buffer sbuf; - char chars[128]; + char chars[128]; - VERIFY_ARE_EQUAL(26u, stream.read_line(sbuf).get()); - // The read_line() should have flushed, so we should be getting what's there, - // less than we asked for. - VERIFY_ARE_EQUAL(26u, sbuf.getn(chars, 100).get()); + VERIFY_ARE_EQUAL(26u, stream.read_line(sbuf).get()); + // The read_line() should have flushed, so we should be getting what's there, + // less than we asked for. + VERIFY_ARE_EQUAL(26u, sbuf.getn(chars, 100).get()); - stream.close().get(); - sbuf.close().get(); -} + stream.close().get(); + sbuf.close().get(); + } -TEST(stream_read_to_end_flush) -{ - producer_consumer_buffer rbuf; - streams::basic_istream stream = rbuf; + TEST(stream_read_to_end_flush) + { + producer_consumer_buffer rbuf; + streams::basic_istream stream = rbuf; - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - size_t len = strlen(text); + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + size_t len = strlen(text); - VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); + VERIFY_ARE_EQUAL(len, rbuf.putn_nocopy(text, len).get()); - rbuf.close(std::ios_base::out).get(); + rbuf.close(std::ios_base::out).get(); - producer_consumer_buffer sbuf; + producer_consumer_buffer sbuf; - char chars[128]; + char chars[128]; - VERIFY_ARE_EQUAL(len, stream.read_to_end(sbuf).get()); - // The read_to_end() should have flushed, so we should be getting what's there, - // less than we asked for. - VERIFY_ARE_EQUAL(len, sbuf.getn(chars, len*2).get()); + VERIFY_ARE_EQUAL(len, stream.read_to_end(sbuf).get()); + // The read_to_end() should have flushed, so we should be getting what's there, + // less than we asked for. + VERIFY_ARE_EQUAL(len, sbuf.getn(chars, len * 2).get()); - stream.close().get(); - sbuf.close().get(); -} + stream.close().get(); + sbuf.close().get(); + } -TEST(istream_extract_string) -{ - producer_consumer_buffer rbuf; - const char *text = " abc defgsf "; + TEST(istream_extract_string) + { + producer_consumer_buffer rbuf; + const char* text = " abc defgsf "; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); - streams::basic_istream is = rbuf; - std::string str1 = is.extract().get(); - std::string str2 = is.extract().get(); + streams::basic_istream is = rbuf; + std::string str1 = is.extract().get(); + std::string str2 = is.extract().get(); - VERIFY_ARE_EQUAL(str1, "abc"); - VERIFY_ARE_EQUAL(str2, "defgsf"); -} + VERIFY_ARE_EQUAL(str1, "abc"); + VERIFY_ARE_EQUAL(str2, "defgsf"); + } #ifdef _WIN32 // On Linux, this becomes the exact copy of istream_extract_string1, hence disabled -TEST(istream_extract_wstring_1) -{ - producer_consumer_buffer rbuf; - const char *text = " abc defgsf "; + TEST(istream_extract_wstring_1) + { + producer_consumer_buffer rbuf; + const char* text = " abc defgsf "; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); - streams::basic_istream is = rbuf; - utility::string_t str1 = is.extract().get(); - utility::string_t str2 = is.extract().get(); + streams::basic_istream is = rbuf; + utility::string_t str1 = is.extract().get(); + utility::string_t str2 = is.extract().get(); - VERIFY_ARE_EQUAL(str1, L"abc"); - VERIFY_ARE_EQUAL(str2, L"defgsf"); -} + VERIFY_ARE_EQUAL(str1, L"abc"); + VERIFY_ARE_EQUAL(str2, L"defgsf"); + } -TEST(istream_extract_wstring_2) // On Linux, this becomes the exact copy of istream_extract_string2, hence disabled -{ - producer_consumer_buffer rbuf; - const char *text = " abc defgsf "; + TEST(istream_extract_wstring_2) // On Linux, this becomes the exact copy of istream_extract_string2, hence disabled + { + producer_consumer_buffer rbuf; + const char* text = " abc defgsf "; - size_t len = strlen(text); - rbuf.putn_nocopy((const signed char *)text, len).wait(); - rbuf.close(std::ios_base::out).get(); + size_t len = strlen(text); + rbuf.putn_nocopy((const signed char*)text, len).wait(); + rbuf.close(std::ios_base::out).get(); - streams::basic_istream is = rbuf; - utility::string_t str1 = is.extract().get(); - utility::string_t str2 = is.extract().get(); + streams::basic_istream is = rbuf; + utility::string_t str1 = is.extract().get(); + utility::string_t str2 = is.extract().get(); - VERIFY_ARE_EQUAL(str1, L"abc"); - VERIFY_ARE_EQUAL(str2, L"defgsf"); -} + VERIFY_ARE_EQUAL(str1, L"abc"); + VERIFY_ARE_EQUAL(str2, L"defgsf"); + } -TEST(istream_extract_wstring_3) -{ - producer_consumer_buffer rbuf; - const char *text = " abc defgsf "; + TEST(istream_extract_wstring_3) + { + producer_consumer_buffer rbuf; + const char* text = " abc defgsf "; - size_t len = strlen(text); - rbuf.putn_nocopy((const unsigned char *)text, len).wait(); - rbuf.close(std::ios_base::out).get(); + size_t len = strlen(text); + rbuf.putn_nocopy((const unsigned char*)text, len).wait(); + rbuf.close(std::ios_base::out).get(); - streams::basic_istream is = rbuf; - utility::string_t str1 = is.extract().get(); - utility::string_t str2 = is.extract().get(); + streams::basic_istream is = rbuf; + utility::string_t str1 = is.extract().get(); + utility::string_t str2 = is.extract().get(); - VERIFY_ARE_EQUAL(str1, L"abc"); - VERIFY_ARE_EQUAL(str2, L"defgsf"); -} + VERIFY_ARE_EQUAL(str1, L"abc"); + VERIFY_ARE_EQUAL(str2, L"defgsf"); + } #endif -TEST(istream_extract_int64) -{ - producer_consumer_buffer rbuf; - const char *text = "1024 -17134711"; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::basic_istream is = rbuf; - int64_t i1 = is.extract().get(); - int64_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, -17134711); -} + TEST(istream_extract_int64) + { + producer_consumer_buffer rbuf; + const char* text = "1024 -17134711"; + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::basic_istream is = rbuf; + int64_t i1 = is.extract().get(); + int64_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, -17134711); + } -TEST(istream_extract_uint64) -{ - producer_consumer_buffer rbuf; - const char *text = "1024 12000000000"; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::istream is(rbuf); - uint64_t i1 = is.extract().get(); - uint64_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, (uint64_t)12000000000); -} + TEST(istream_extract_uint64) + { + producer_consumer_buffer rbuf; + const char* text = "1024 12000000000"; + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::istream is(rbuf); + uint64_t i1 = is.extract().get(); + uint64_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, (uint64_t)12000000000); + } #ifdef _WIN32 -TEST(istream_extract_int64w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L"1024 -17134711"; - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - int64_t i1 = is.extract().get(); - int64_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, -17134711); -} + TEST(istream_extract_int64w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L"1024 -17134711"; + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + int64_t i1 = is.extract().get(); + int64_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, -17134711); + } -TEST(istream_extract_uint64w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L"1024 12000000000"; - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - uint64_t i1 = is.extract().get(); - uint64_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, (uint64_t)12000000000); -} + TEST(istream_extract_uint64w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L"1024 12000000000"; + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + uint64_t i1 = is.extract().get(); + uint64_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, (uint64_t)12000000000); + } #endif -TEST(istream_extract_int32) -{ - producer_consumer_buffer rbuf; - const char *text = "1024 -17134711 12000000000"; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::istream is(rbuf); - int32_t i1 = is.extract().get(); - int32_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, -17134711); - VERIFY_THROWS(is.extract().get(), std::range_error); -} + TEST(istream_extract_int32) + { + producer_consumer_buffer rbuf; + const char* text = "1024 -17134711 12000000000"; + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::istream is(rbuf); + int32_t i1 = is.extract().get(); + int32_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, -17134711); + VERIFY_THROWS(is.extract().get(), std::range_error); + } -TEST(istream_extract_uint32) -{ - producer_consumer_buffer rbuf; - const char *text = "1024 3000000000 12000000000"; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::istream is(rbuf); - uint32_t i1 = is.extract().get(); - uint32_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024u); - VERIFY_ARE_EQUAL(i2, (uint32_t)3000000000); - VERIFY_THROWS(is.extract().get(), std::range_error); -} + TEST(istream_extract_uint32) + { + producer_consumer_buffer rbuf; + const char* text = "1024 3000000000 12000000000"; + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::istream is(rbuf); + uint32_t i1 = is.extract().get(); + uint32_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024u); + VERIFY_ARE_EQUAL(i2, (uint32_t)3000000000); + VERIFY_THROWS(is.extract().get(), std::range_error); + } #ifdef _WIN32 -TEST(istream_extract_int32w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L"1024 -17134711 12000000000"; - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - int32_t i1 = is.extract().get(); - int32_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, -17134711); - VERIFY_THROWS(is.extract().get(), std::range_error); -} + TEST(istream_extract_int32w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L"1024 -17134711 12000000000"; + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + int32_t i1 = is.extract().get(); + int32_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, -17134711); + VERIFY_THROWS(is.extract().get(), std::range_error); + } -TEST(istream_extract_uint32w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L"1024 3000000000 12000000000"; - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - uint32_t i1 = is.extract().get(); - uint32_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024u); - VERIFY_ARE_EQUAL(i2, 3000000000u); - VERIFY_THROWS(is.extract().get(), std::range_error); -} + TEST(istream_extract_uint32w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L"1024 3000000000 12000000000"; + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + uint32_t i1 = is.extract().get(); + uint32_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024u); + VERIFY_ARE_EQUAL(i2, 3000000000u); + VERIFY_THROWS(is.extract().get(), std::range_error); + } #endif -TEST(istream_extract_int16) -{ - producer_consumer_buffer rbuf; - const char *text = "1024 -4711 100000"; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::istream is(rbuf); - int16_t i1 = is.extract().get(); - int16_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, -4711); - VERIFY_THROWS(is.extract().get(), std::range_error); -} + TEST(istream_extract_int16) + { + producer_consumer_buffer rbuf; + const char* text = "1024 -4711 100000"; + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::istream is(rbuf); + int16_t i1 = is.extract().get(); + int16_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, -4711); + VERIFY_THROWS(is.extract().get(), std::range_error); + } -TEST(istream_extract_uint16) -{ - producer_consumer_buffer rbuf; - const char *text = "1024 50000 100000"; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::istream is(rbuf); - uint16_t i1 = is.extract().get(); - uint16_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, 50000); - VERIFY_THROWS(is.extract().get(), std::range_error); -} + TEST(istream_extract_uint16) + { + producer_consumer_buffer rbuf; + const char* text = "1024 50000 100000"; + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::istream is(rbuf); + uint16_t i1 = is.extract().get(); + uint16_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, 50000); + VERIFY_THROWS(is.extract().get(), std::range_error); + } #ifdef _WIN32 -TEST(istream_extract_int16w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L"1024 -4711 100000"; - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - int16_t i1 = is.extract().get(); - int16_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, -4711); - VERIFY_THROWS(is.extract().get(), std::range_error); -} + TEST(istream_extract_int16w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L"1024 -4711 100000"; + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + int16_t i1 = is.extract().get(); + int16_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, -4711); + VERIFY_THROWS(is.extract().get(), std::range_error); + } -TEST(istream_extract_uint16w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L"1024 50000 100000"; - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - uint16_t i1 = is.extract().get(); - uint16_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, 1024); - VERIFY_ARE_EQUAL(i2, 50000); - VERIFY_THROWS(is.extract().get(), std::range_error); -} + TEST(istream_extract_uint16w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L"1024 50000 100000"; + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + uint16_t i1 = is.extract().get(); + uint16_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, 1024); + VERIFY_ARE_EQUAL(i2, 50000); + VERIFY_THROWS(is.extract().get(), std::range_error); + } #endif -TEST(istream_extract_int8) -{ - producer_consumer_buffer rbuf; - const char *text = "0 -125 512"; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::basic_istream is(rbuf); - int8_t i1 = is.extract().get(); - int8_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, '0'); - VERIFY_ARE_EQUAL(i2, '-'); -} + TEST(istream_extract_int8) + { + producer_consumer_buffer rbuf; + const char* text = "0 -125 512"; + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::basic_istream is(rbuf); + int8_t i1 = is.extract().get(); + int8_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, '0'); + VERIFY_ARE_EQUAL(i2, '-'); + } -TEST(istream_extract_uint8) -{ - producer_consumer_buffer rbuf; - const char *text = "0 150 512"; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::basic_istream is(rbuf); - uint8_t i1 = is.extract().get(); - uint8_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, '0'); - VERIFY_ARE_EQUAL(i2, '1'); -} + TEST(istream_extract_uint8) + { + producer_consumer_buffer rbuf; + const char* text = "0 150 512"; + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::basic_istream is(rbuf); + uint8_t i1 = is.extract().get(); + uint8_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, '0'); + VERIFY_ARE_EQUAL(i2, '1'); + } #ifdef _WIN32 -TEST(istream_extract_int8w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L"0 -125 512"; - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - int8_t i1 = is.extract().get(); - int8_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, '0'); - VERIFY_ARE_EQUAL(i2, '-'); -} + TEST(istream_extract_int8w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L"0 -125 512"; + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + int8_t i1 = is.extract().get(); + int8_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, '0'); + VERIFY_ARE_EQUAL(i2, '-'); + } -TEST(istream_extract_uint8w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L"0 150 512"; - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - uint8_t i1 = is.extract().get(); - uint8_t i2 = is.extract().get(); - - VERIFY_ARE_EQUAL(i1, '0'); - VERIFY_ARE_EQUAL(i2, '1'); -} + TEST(istream_extract_uint8w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L"0 150 512"; + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + uint8_t i1 = is.extract().get(); + uint8_t i2 = is.extract().get(); + + VERIFY_ARE_EQUAL(i1, '0'); + VERIFY_ARE_EQUAL(i2, '1'); + } #endif -TEST(istream_extract_bool) -{ - producer_consumer_buffer rbuf; - const char *text = " true false NOT_OK"; - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::istream is(rbuf); - bool i1 = is.extract().get(); - bool i2 = is.extract().get(); - - VERIFY_IS_TRUE(i1); - VERIFY_IS_FALSE(i2); - VERIFY_THROWS(is.extract().get(), std::runtime_error); -} + TEST(istream_extract_bool) + { + producer_consumer_buffer rbuf; + const char* text = " true false NOT_OK"; + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::istream is(rbuf); + bool i1 = is.extract().get(); + bool i2 = is.extract().get(); + + VERIFY_IS_TRUE(i1); + VERIFY_IS_FALSE(i2); + VERIFY_THROWS(is.extract().get(), std::runtime_error); + } -TEST(istream_extract_bool_from_number) -{ - producer_consumer_buffer rbuf; - const char *text = " 1 0 NOT_OK"; - - size_t len = strlen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::istream is(rbuf); - bool i1 = is.extract().get(); - bool i2 = is.extract().get(); - - VERIFY_IS_TRUE(i1); - VERIFY_IS_FALSE(i2); - // Make sure parsing consumes just the right amount of characters. - VERIFY_ARE_EQUAL(7u, rbuf.in_avail()); - VERIFY_THROWS(is.extract().get(), std::runtime_error); -} + TEST(istream_extract_bool_from_number) + { + producer_consumer_buffer rbuf; + const char* text = " 1 0 NOT_OK"; + + size_t len = strlen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::istream is(rbuf); + bool i1 = is.extract().get(); + bool i2 = is.extract().get(); + + VERIFY_IS_TRUE(i1); + VERIFY_IS_FALSE(i2); + // Make sure parsing consumes just the right amount of characters. + VERIFY_ARE_EQUAL(7u, rbuf.in_avail()); + VERIFY_THROWS(is.extract().get(), std::runtime_error); + } #ifdef _WIN32 -TEST(istream_extract_bool_w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L" true false NOT_OK"; - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - bool i1 = is.extract().get(); - bool i2 = is.extract().get(); - - VERIFY_IS_TRUE(i1); - VERIFY_IS_FALSE(i2); - VERIFY_THROWS(is.extract().get(), std::runtime_error); -} + TEST(istream_extract_bool_w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L" true false NOT_OK"; + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + bool i1 = is.extract().get(); + bool i2 = is.extract().get(); + + VERIFY_IS_TRUE(i1); + VERIFY_IS_FALSE(i2); + VERIFY_THROWS(is.extract().get(), std::runtime_error); + } -TEST(istream_extract_bool_from_number_w) -{ - producer_consumer_buffer rbuf; - const wchar_t *text = L" 1 0 NOT_OK"; - - size_t len = wcslen(text); - rbuf.putn_nocopy(text, len).wait(); - rbuf.close(std::ios_base::out).get(); - - streams::wistream is(rbuf); - bool i1 = is.extract().get(); - bool i2 = is.extract().get(); - - VERIFY_IS_TRUE(i1); - VERIFY_IS_FALSE(i2); - // Make sure parsing consumes just the right amount of characters. - VERIFY_ARE_EQUAL(7u, rbuf.in_avail()); - VERIFY_THROWS(is.extract().get(), std::runtime_error); -} + TEST(istream_extract_bool_from_number_w) + { + producer_consumer_buffer rbuf; + const wchar_t* text = L" 1 0 NOT_OK"; + + size_t len = wcslen(text); + rbuf.putn_nocopy(text, len).wait(); + rbuf.close(std::ios_base::out).get(); + + streams::wistream is(rbuf); + bool i1 = is.extract().get(); + bool i2 = is.extract().get(); + + VERIFY_IS_TRUE(i1); + VERIFY_IS_FALSE(i2); + // Make sure parsing consumes just the right amount of characters. + VERIFY_ARE_EQUAL(7u, rbuf.in_avail()); + VERIFY_THROWS(is.extract().get(), std::runtime_error); + } #endif -template -void istream_extract_long_impl(streambuf<_CharType> buf) -{ - basic_istream<_CharType> is(buf); - const _LongType v1 = is.template extract<_LongType>().get(); - const _LongType v2 = is.template extract<_LongType>().get(); + template + void istream_extract_long_impl(streambuf<_CharType> buf) + { + basic_istream<_CharType> is(buf); + const _LongType v1 = is.template extract<_LongType>().get(); + const _LongType v2 = is.template extract<_LongType>().get(); - VERIFY_ARE_EQUAL(123, v1); - VERIFY_ARE_EQUAL(-567, v2); - VERIFY_THROWS(is.template extract<_LongType>().get(), std::runtime_error); -} + VERIFY_ARE_EQUAL(123, v1); + VERIFY_ARE_EQUAL(-567, v2); + VERIFY_THROWS(is.template extract<_LongType>().get(), std::runtime_error); + } -TEST(istream_extract_long) -{ - istream_extract_long_impl(container_buffer("123 -567 120000000000000000000000000000000000000000000000")); + TEST(istream_extract_long) + { + istream_extract_long_impl( + container_buffer("123 -567 120000000000000000000000000000000000000000000000")); #ifdef _WIN32 - istream_extract_long_impl(container_buffer(L"123 -567 12000000000")); + istream_extract_long_impl(container_buffer(L"123 -567 12000000000")); #endif -} + } -template -void istream_extract_unsigned_long_impl(streambuf<_CharType> buf) -{ - basic_istream<_CharType> is(buf); - const _LongType v1 = is.template extract<_LongType>().get(); - const _LongType v2 = is.template extract<_LongType>().get(); + template + void istream_extract_unsigned_long_impl(streambuf<_CharType> buf) + { + basic_istream<_CharType> is(buf); + const _LongType v1 = is.template extract<_LongType>().get(); + const _LongType v2 = is.template extract<_LongType>().get(); - VERIFY_ARE_EQUAL(876, v1); - VERIFY_ARE_EQUAL(3, v2); - VERIFY_THROWS(is.template extract<_LongType>().get(), std::runtime_error); -} + VERIFY_ARE_EQUAL(876, v1); + VERIFY_ARE_EQUAL(3, v2); + VERIFY_THROWS(is.template extract<_LongType>().get(), std::runtime_error); + } -TEST(istream_extract_unsigned_long) -{ - istream_extract_unsigned_long_impl(container_buffer("876 3 -44")); + TEST(istream_extract_unsigned_long) + { + istream_extract_unsigned_long_impl(container_buffer("876 3 -44")); #ifdef _WIN32 - istream_extract_unsigned_long_impl(container_buffer(L"876 3 -44")); + istream_extract_unsigned_long_impl(container_buffer(L"876 3 -44")); #endif -} + } -TEST(istream_extract_long_long) -{ - istream_extract_long_impl(container_buffer("123 -567 92233720368547758078")); + TEST(istream_extract_long_long) + { + istream_extract_long_impl(container_buffer("123 -567 92233720368547758078")); #ifdef _WIN32 - istream_extract_long_impl(container_buffer(L"123 -567 92233720368547758078")); + istream_extract_long_impl(container_buffer(L"123 -567 92233720368547758078")); #endif -} + } -TEST(istream_extract_unsigned_long_long) -{ - istream_extract_unsigned_long_impl(container_buffer("876 3 -44")); + TEST(istream_extract_unsigned_long_long) + { + istream_extract_unsigned_long_impl(container_buffer("876 3 -44")); #ifdef _WIN32 - istream_extract_unsigned_long_impl(container_buffer(L"876 3 -44")); + istream_extract_unsigned_long_impl(container_buffer(L"876 3 -44")); #endif -} + } -template -void compare_floating(T expected, T actual, T relativeDiff) -{ - // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ - if (expected != actual) - { - const auto diff = fabs(expected - actual); - const auto absExpected = fabs(expected); - const auto absActual = fabs(actual); - const auto largest = absExpected > absActual ? absExpected : absActual; - if (diff > largest * relativeDiff) + template + void compare_floating(T expected, T actual, T relativeDiff) + { + // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + if (expected != actual) { - VERIFY_IS_TRUE(false); + const auto diff = fabs(expected - actual); + const auto absExpected = fabs(expected); + const auto absActual = fabs(actual); + const auto largest = absExpected > absActual ? absExpected : absActual; + if (diff > largest * relativeDiff) + { + VERIFY_IS_TRUE(false); + } } } -} -void compare_double(double expected, double actual) -{ - compare_floating(expected, actual, DBL_EPSILON); -} -void compare_float(float expected, float actual) -{ - compare_floating(expected, actual, FLT_EPSILON); -} + void compare_double(double expected, double actual) { compare_floating(expected, actual, DBL_EPSILON); } + void compare_float(float expected, float actual) { compare_floating(expected, actual, FLT_EPSILON); } -TEST(extract_floating_point) -{ - std::string test_string; - test_string.append(" 9.81E05 3.14"); - test_string.append(" 2.71.5"); // two numbers merged after comma - test_string.append(" 6E+4.5"); // two numbers merged in exponent - test_string.append(" 6E-4.5"); // two numbers merged in exponent - test_string.append(" 3.14 -10 +42.0 -1234.567 .01 +0 -0"); + TEST(extract_floating_point) + { + std::string test_string; + test_string.append(" 9.81E05 3.14"); + test_string.append(" 2.71.5"); // two numbers merged after comma + test_string.append(" 6E+4.5"); // two numbers merged in exponent + test_string.append(" 6E-4.5"); // two numbers merged in exponent + test_string.append(" 3.14 -10 +42.0 -1234.567 .01 +0 -0"); #ifndef __APPLE__ - test_string.append(" 12345678901234567890123456789012345678901234567890"); // a big number + test_string.append(" 12345678901234567890123456789012345678901234567890"); // a big number #endif - test_string.append(" 9.81E05 6.0221413e+23 1.6e-14"); // numbers with exponent - test_string.append(" 6."); // a number ending with a dot + test_string.append(" 9.81E05 6.0221413e+23 1.6e-14"); // numbers with exponent + test_string.append(" 6."); // a number ending with a dot - std::stringstream std_istream; - std_istream << test_string; + std::stringstream std_istream; + std_istream << test_string; - producer_consumer_buffer buff, bufd; - auto ostream_float = buff.create_ostream(); - auto istream_float = buff.create_istream(); - auto ostream_double = bufd.create_ostream(); - auto istream_double = bufd.create_istream(); + producer_consumer_buffer buff, bufd; + auto ostream_float = buff.create_ostream(); + auto istream_float = buff.create_istream(); + auto ostream_double = bufd.create_ostream(); + auto istream_double = bufd.create_istream(); - ostream_float.print(test_string); - ostream_double.print(test_string); - ostream_float.close().wait(); - ostream_double.close().wait(); + ostream_float.print(test_string); + ostream_double.print(test_string); + ostream_float.close().wait(); + ostream_double.close().wait(); - do - { - double expected = 0; - std_istream >> expected; + do + { + double expected = 0; + std_istream >> expected; - const auto actual = istream_double.extract().get(); - compare_double(expected, actual); + const auto actual = istream_double.extract().get(); + compare_double(expected, actual); - if (actual <= std::numeric_limits::max()) - compare_float(float(expected), istream_float.extract().get()); - else - VERIFY_THROWS(istream_float.extract().get(), std::exception); + if (actual <= std::numeric_limits::max()) + compare_float(float(expected), istream_float.extract().get()); + else + VERIFY_THROWS(istream_float.extract().get(), std::exception); - // Checking positive and negative zero's by dividing 1 with it. They should result in positive and negative infinity. - if (expected == 0) - VERIFY_ARE_EQUAL(1 / expected, 1 / actual); - } while (!std_istream.eof()); -} + // Checking positive and negative zero's by dividing 1 with it. They should result in positive and negative + // infinity. + if (expected == 0) VERIFY_ARE_EQUAL(1 / expected, 1 / actual); + } while (!std_istream.eof()); + } -TEST(extract_floating_point_with_exceptions) -{ - std::vector> tests; - tests.push_back(std::pair("a", "Invalid character 'a'")); - tests.push_back(std::pair("x", "Invalid character 'x'")); - tests.push_back(std::pair("e", "Invalid character 'e'")); - tests.push_back(std::pair("E", "Invalid character 'E'")); - tests.push_back(std::pair("6.022e+t", "Invalid character 't' in exponent")); - tests.push_back(std::pair("9.81e-.", "Invalid character '.' in exponent")); - tests.push_back(std::pair("9.81e-", "Incomplete exponent")); - tests.push_back(std::pair("1.2e+", "Incomplete exponent")); - tests.push_back(std::pair("10E+-23", "The exponent sign already set")); - tests.push_back(std::pair("15E-+45", "The exponent sign already set")); - tests.push_back(std::pair("5.34e", "Incomplete exponent")); - tests.push_back(std::pair("2E+308", "The value is too big")); - tests.push_back(std::pair("-2E+308", "The value is too big")); - tests.push_back(std::pair("1E-324", "The value is too small")); - tests.push_back(std::pair("-1E-324", "The value is too small")); - - for (auto iter = tests.begin(); iter != tests.end(); iter++) + TEST(extract_floating_point_with_exceptions) { - std::stringstream std_istream; - std_istream << iter->first; - VERIFY_IS_TRUE(std_istream.good()); - double x; - std_istream >> x; - VERIFY_IS_FALSE(std_istream.good()); - - producer_consumer_buffer buf; - auto stream = buf.create_ostream(); - auto istream_double = buf.create_istream(); - - stream.print(iter->first); - stream.close().wait(); - - try - { - istream_double.extract().get(); - VERIFY_IS_TRUE(false, "No exception has been thrown"); - } - catch (const std::exception& exc) + std::vector> tests; + tests.push_back(std::pair("a", "Invalid character 'a'")); + tests.push_back(std::pair("x", "Invalid character 'x'")); + tests.push_back(std::pair("e", "Invalid character 'e'")); + tests.push_back(std::pair("E", "Invalid character 'E'")); + tests.push_back(std::pair("6.022e+t", "Invalid character 't' in exponent")); + tests.push_back(std::pair("9.81e-.", "Invalid character '.' in exponent")); + tests.push_back(std::pair("9.81e-", "Incomplete exponent")); + tests.push_back(std::pair("1.2e+", "Incomplete exponent")); + tests.push_back(std::pair("10E+-23", "The exponent sign already set")); + tests.push_back(std::pair("15E-+45", "The exponent sign already set")); + tests.push_back(std::pair("5.34e", "Incomplete exponent")); + tests.push_back(std::pair("2E+308", "The value is too big")); + tests.push_back(std::pair("-2E+308", "The value is too big")); + tests.push_back(std::pair("1E-324", "The value is too small")); + tests.push_back(std::pair("-1E-324", "The value is too small")); + + for (auto iter = tests.begin(); iter != tests.end(); iter++) { - VERIFY_ARE_EQUAL(std::string(exc.what()), iter->second); - } - catch (...) - { - VERIFY_IS_TRUE(false, "A wrong exception has been thrown"); + std::stringstream std_istream; + std_istream << iter->first; + VERIFY_IS_TRUE(std_istream.good()); + double x; + std_istream >> x; + VERIFY_IS_FALSE(std_istream.good()); + + producer_consumer_buffer buf; + auto stream = buf.create_ostream(); + auto istream_double = buf.create_istream(); + + stream.print(iter->first); + stream.close().wait(); + + try + { + istream_double.extract().get(); + VERIFY_IS_TRUE(false, "No exception has been thrown"); + } + catch (const std::exception& exc) + { + VERIFY_ARE_EQUAL(std::string(exc.what()), iter->second); + } + catch (...) + { + VERIFY_IS_TRUE(false, "A wrong exception has been thrown"); + } } } -} -TEST(streambuf_read_delim) -{ - producer_consumer_buffer rbuf; - std::string s("Hello World"); // there are 2 spaces here - - streams::stringstreambuf data; - - streams::istream is(rbuf); - - auto t = is.read_to_delim(data, ' ').then([&data, is](size_t size) -> pplx::task - { - std::string r("Hello"); - VERIFY_ARE_EQUAL(size, r.size()); - VERIFY_IS_FALSE(is.is_eof()); - - auto& s2 = data.collection(); - VERIFY_ARE_EQUAL(s2, r); - return is.read_to_delim(data, ' '); - }).then([&data, is](size_t size) -> pplx::task { - VERIFY_ARE_EQUAL(size, 0); - VERIFY_IS_FALSE(is.is_eof()); - return is.read_to_delim(data, ' '); - }).then([&data, is](size_t size) -> void { - VERIFY_ARE_EQUAL(size, 5); - VERIFY_IS_TRUE(is.is_eof()); - }); - rbuf.putn_nocopy((uint8_t *)s.data(), s.size()).wait(); - rbuf.close(std::ios_base::out).get(); - t.wait(); -} + TEST(streambuf_read_delim) + { + producer_consumer_buffer rbuf; + std::string s("Hello World"); // there are 2 spaces here + + streams::stringstreambuf data; + + streams::istream is(rbuf); + + auto t = is.read_to_delim(data, ' ') + .then([&data, is](size_t size) -> pplx::task { + std::string r("Hello"); + VERIFY_ARE_EQUAL(size, r.size()); + VERIFY_IS_FALSE(is.is_eof()); + + auto& s2 = data.collection(); + VERIFY_ARE_EQUAL(s2, r); + return is.read_to_delim(data, ' '); + }) + .then([&data, is](size_t size) -> pplx::task { + VERIFY_ARE_EQUAL(size, 0); + VERIFY_IS_FALSE(is.is_eof()); + return is.read_to_delim(data, ' '); + }) + .then([&data, is](size_t size) -> void { + VERIFY_ARE_EQUAL(size, 5); + VERIFY_IS_TRUE(is.is_eof()); + }); + rbuf.putn_nocopy((uint8_t*)s.data(), s.size()).wait(); + rbuf.close(std::ios_base::out).get(); + t.wait(); + } -TEST(uninitialized_stream) -{ - streams::basic_ostream test_ostream; - streams::basic_istream test_istream; + TEST(uninitialized_stream) + { + streams::basic_ostream test_ostream; + streams::basic_istream test_istream; - VERIFY_IS_FALSE(test_ostream.is_valid()); - VERIFY_IS_FALSE(test_istream.is_valid()); + VERIFY_IS_FALSE(test_ostream.is_valid()); + VERIFY_IS_FALSE(test_istream.is_valid()); - VERIFY_THROWS(test_istream.read(), std::logic_error); - VERIFY_THROWS(test_ostream.flush(), std::logic_error); + VERIFY_THROWS(test_istream.read(), std::logic_error); + VERIFY_THROWS(test_ostream.flush(), std::logic_error); - test_istream.close().wait(); - test_ostream.close().wait(); -} + test_istream.close().wait(); + test_ostream.close().wait(); + } -TEST(uninitialized_streambuf) -{ - streams::streambuf strbuf; + TEST(uninitialized_streambuf) + { + streams::streambuf strbuf; - // The bool operator shall not throw - VERIFY_IS_TRUE(!strbuf); + // The bool operator shall not throw + VERIFY_IS_TRUE(!strbuf); - // All operations should throw - uint8_t * ptr = nullptr; - size_t count = 0; + // All operations should throw + uint8_t* ptr = nullptr; + size_t count = 0; - VERIFY_THROWS(strbuf.acquire(ptr, count), std::invalid_argument); - VERIFY_THROWS(strbuf.release(ptr, count), std::invalid_argument); + VERIFY_THROWS(strbuf.acquire(ptr, count), std::invalid_argument); + VERIFY_THROWS(strbuf.release(ptr, count), std::invalid_argument); - VERIFY_THROWS(strbuf.alloc(count), std::invalid_argument); - VERIFY_THROWS(strbuf.commit(count), std::invalid_argument); + VERIFY_THROWS(strbuf.alloc(count), std::invalid_argument); + VERIFY_THROWS(strbuf.commit(count), std::invalid_argument); - VERIFY_THROWS(strbuf.can_read(), std::invalid_argument); - VERIFY_THROWS(strbuf.can_write(), std::invalid_argument); - VERIFY_THROWS(strbuf.can_seek(), std::invalid_argument); + VERIFY_THROWS(strbuf.can_read(), std::invalid_argument); + VERIFY_THROWS(strbuf.can_write(), std::invalid_argument); + VERIFY_THROWS(strbuf.can_seek(), std::invalid_argument); - VERIFY_THROWS(strbuf.is_eof(), std::invalid_argument); - VERIFY_THROWS(strbuf.is_open(), std::invalid_argument); + VERIFY_THROWS(strbuf.is_eof(), std::invalid_argument); + VERIFY_THROWS(strbuf.is_open(), std::invalid_argument); - VERIFY_THROWS(strbuf.in_avail(), std::invalid_argument); - VERIFY_THROWS(strbuf.get_base(), std::invalid_argument); + VERIFY_THROWS(strbuf.in_avail(), std::invalid_argument); + VERIFY_THROWS(strbuf.get_base(), std::invalid_argument); - VERIFY_THROWS(strbuf.putc('a').get(), std::invalid_argument); - VERIFY_THROWS(strbuf.putn_nocopy(ptr, count).get(), std::invalid_argument); - VERIFY_THROWS(strbuf.sync().get(), std::invalid_argument); + VERIFY_THROWS(strbuf.putc('a').get(), std::invalid_argument); + VERIFY_THROWS(strbuf.putn_nocopy(ptr, count).get(), std::invalid_argument); + VERIFY_THROWS(strbuf.sync().get(), std::invalid_argument); - VERIFY_THROWS(strbuf.getc().get(), std::invalid_argument); - VERIFY_THROWS(strbuf.ungetc().get(), std::invalid_argument); - VERIFY_THROWS(strbuf.bumpc().get(), std::invalid_argument); - VERIFY_THROWS(strbuf.nextc().get(), std::invalid_argument); - VERIFY_THROWS(strbuf.getn(ptr, count).get(), std::invalid_argument); + VERIFY_THROWS(strbuf.getc().get(), std::invalid_argument); + VERIFY_THROWS(strbuf.ungetc().get(), std::invalid_argument); + VERIFY_THROWS(strbuf.bumpc().get(), std::invalid_argument); + VERIFY_THROWS(strbuf.nextc().get(), std::invalid_argument); + VERIFY_THROWS(strbuf.getn(ptr, count).get(), std::invalid_argument); - VERIFY_THROWS(strbuf.close().get(), std::invalid_argument); + VERIFY_THROWS(strbuf.close().get(), std::invalid_argument); - // The destructor shall not throw -} + // The destructor shall not throw + } -TEST(create_istream_from_output_only) -{ - container_buffer sourceBuf; - VERIFY_THROWS(sourceBuf.create_istream(), std::runtime_error); -} + TEST(create_istream_from_output_only) + { + container_buffer sourceBuf; + VERIFY_THROWS(sourceBuf.create_istream(), std::runtime_error); + } -TEST(extract_close_with_exception) -{ - container_buffer sourceBuf(std::ios::in); - auto inStream = sourceBuf.create_istream(); - inStream.close(std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); - auto extractTask = inStream.extract(); - VERIFY_THROWS(extractTask.get(), std::invalid_argument); -} + TEST(extract_close_with_exception) + { + container_buffer sourceBuf(std::ios::in); + auto inStream = sourceBuf.create_istream(); + inStream.close(std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); + auto extractTask = inStream.extract(); + VERIFY_THROWS(extractTask.get(), std::invalid_argument); + } -TEST(streambuf_close_with_exception_read) -{ - container_buffer sourceBuf("test data string"); - sourceBuf.close(std::ios::in, std::make_exception_ptr(std::invalid_argument("custom exception"))); + TEST(streambuf_close_with_exception_read) + { + container_buffer sourceBuf("test data string"); + sourceBuf.close(std::ios::in, std::make_exception_ptr(std::invalid_argument("custom exception"))); - const size_t size = 4; - char targetBuf[size]; - auto t = sourceBuf.getn(targetBuf, size); - VERIFY_THROWS(t.get(), std::invalid_argument); -} + const size_t size = 4; + char targetBuf[size]; + auto t = sourceBuf.getn(targetBuf, size); + VERIFY_THROWS(t.get(), std::invalid_argument); + } -TEST(stream_close_with_exception_read) -{ - container_buffer sourceBuf("test data string"); - auto inStream = sourceBuf.create_istream(); - inStream.close(std::make_exception_ptr(std::invalid_argument("custom exception"))); - - container_buffer targetBuf; - auto t1 = inStream.read(targetBuf, 4); - VERIFY_THROWS(t1.get(), std::invalid_argument); - VERIFY_THROWS(inStream.streambuf().sbumpc(), std::invalid_argument); - VERIFY_THROWS(inStream.streambuf().sgetc(), std::invalid_argument); -} + TEST(stream_close_with_exception_read) + { + container_buffer sourceBuf("test data string"); + auto inStream = sourceBuf.create_istream(); + inStream.close(std::make_exception_ptr(std::invalid_argument("custom exception"))); + + container_buffer targetBuf; + auto t1 = inStream.read(targetBuf, 4); + VERIFY_THROWS(t1.get(), std::invalid_argument); + VERIFY_THROWS(inStream.streambuf().sbumpc(), std::invalid_argument); + VERIFY_THROWS(inStream.streambuf().sgetc(), std::invalid_argument); + } -TEST(istream_input_after_close) -{ - container_buffer sourceBuf("test data"); - auto inStream = sourceBuf.create_istream(); - inStream.close().wait(); - - container_buffer targetBuf; - VERIFY_THROWS(inStream.peek().get(), std::runtime_error); - VERIFY_THROWS(inStream.read(targetBuf, 1).get(), std::runtime_error); - VERIFY_THROWS(inStream.read_line(targetBuf).get(), std::runtime_error); - VERIFY_THROWS(inStream.read_to_delim(targetBuf, '-').get(), std::runtime_error); - VERIFY_THROWS(inStream.read_to_end(targetBuf).get(), std::runtime_error); - VERIFY_THROWS(inStream.seek(0), std::runtime_error); - VERIFY_THROWS(inStream.seek(1, std::ios::beg), std::runtime_error); - VERIFY_THROWS(inStream.tell(), std::runtime_error); - VERIFY_THROWS(inStream.extract().get(), std::runtime_error); -} + TEST(istream_input_after_close) + { + container_buffer sourceBuf("test data"); + auto inStream = sourceBuf.create_istream(); + inStream.close().wait(); + + container_buffer targetBuf; + VERIFY_THROWS(inStream.peek().get(), std::runtime_error); + VERIFY_THROWS(inStream.read(targetBuf, 1).get(), std::runtime_error); + VERIFY_THROWS(inStream.read_line(targetBuf).get(), std::runtime_error); + VERIFY_THROWS(inStream.read_to_delim(targetBuf, '-').get(), std::runtime_error); + VERIFY_THROWS(inStream.read_to_end(targetBuf).get(), std::runtime_error); + VERIFY_THROWS(inStream.seek(0), std::runtime_error); + VERIFY_THROWS(inStream.seek(1, std::ios::beg), std::runtime_error); + VERIFY_THROWS(inStream.tell(), std::runtime_error); + VERIFY_THROWS(inStream.extract().get(), std::runtime_error); + } -TEST(extract_from_empty_stream) -{ - container_buffer sourceBuf(std::ios::in); - auto inStream = sourceBuf.create_istream(); + TEST(extract_from_empty_stream) + { + container_buffer sourceBuf(std::ios::in); + auto inStream = sourceBuf.create_istream(); - VERIFY_THROWS(inStream.extract().get(), std::range_error); - VERIFY_THROWS(inStream.extract().get(), std::runtime_error); - VERIFY_THROWS(inStream.extract().get(), std::runtime_error); - VERIFY_THROWS(inStream.extract().get(), std::runtime_error); - VERIFY_THROWS(inStream.extract().get(), std::runtime_error); + VERIFY_THROWS(inStream.extract().get(), std::range_error); + VERIFY_THROWS(inStream.extract().get(), std::runtime_error); + VERIFY_THROWS(inStream.extract().get(), std::runtime_error); + VERIFY_THROWS(inStream.extract().get(), std::runtime_error); + VERIFY_THROWS(inStream.extract().get(), std::runtime_error); - const std::string strValue = inStream.extract().get(); - VERIFY_ARE_EQUAL("", strValue); + const std::string strValue = inStream.extract().get(); + VERIFY_ARE_EQUAL("", strValue); #ifdef _WIN32 - const std::wstring wstrValue = inStream.extract().get(); - VERIFY_ARE_EQUAL(L"", wstrValue); + const std::wstring wstrValue = inStream.extract().get(); + VERIFY_ARE_EQUAL(L"", wstrValue); #endif -} - + } -TEST(seek_after_eof) -{ - container_buffer sourceBuf(std::ios::in); - VERIFY_ARE_EQUAL(basic_istream::traits::eof(), sourceBuf.seekoff(1, std::ios::cur, std::ios::in)); -} + TEST(seek_after_eof) + { + container_buffer sourceBuf(std::ios::in); + VERIFY_ARE_EQUAL(basic_istream::traits::eof(), sourceBuf.seekoff(1, std::ios::cur, std::ios::in)); + } } // SUITE(istream_tests) -}}} +} // namespace streams +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/streams/memstream_tests.cpp b/Release/tests/functional/streams/memstream_tests.cpp index 5395cf2cf7..6442883327 100644 --- a/Release/tests/functional/streams/memstream_tests.cpp +++ b/Release/tests/functional/streams/memstream_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests for async memory stream buffer operations. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests for async memory stream buffer operations. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" #if defined(__cplusplus_winrt) #include @@ -18,8 +18,12 @@ #include #endif -namespace tests { namespace functional { namespace streams { - +namespace tests +{ +namespace functional +{ +namespace streams +{ using namespace ::pplx; using namespace utility; using namespace concurrency::streams; @@ -35,7 +39,6 @@ void streambuf_putc(StreamBufferType& wbuf) s.push_back((typename StreamBufferType::char_type)2); s.push_back((typename StreamBufferType::char_type)3); - // Verify putc synchronously VERIFY_ARE_EQUAL((typename StreamBufferType::int_type)s[0], wbuf.putc(s[0]).get()); VERIFY_ARE_EQUAL((typename StreamBufferType::int_type)s[1], wbuf.putc(s[1]).get()); @@ -46,8 +49,8 @@ void streambuf_putc(StreamBufferType& wbuf) // Verify putc async size_t count = 10; - auto seg2 = [&count](typename StreamBufferType::int_type ) { return (--count > 0); }; - auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; + auto seg2 = [&count](typename StreamBufferType::int_type) { return (--count > 0); }; + auto seg1 = [&s, &wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; pplx::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() + 10, wbuf.in_avail()); @@ -81,8 +84,8 @@ void streambuf_putc(concurrency::streams::rawptr_buffer& wbuf) // Verify putc async size_t count = 10; - auto seg2 = [&count](typename StreamBufferType::int_type ) { return (--count > 0); }; - auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; + auto seg2 = [&count](typename StreamBufferType::int_type) { return (--count > 0); }; + auto seg1 = [&s, &wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; pplx::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() + 10, wbuf.block().size()); @@ -117,8 +120,8 @@ void streambuf_putc(concurrency::streams::container_buffer& wbuf // Verify putc async size_t count = 10; - auto seg2 = [&count](typename StreamBufferType::int_type ) { return (--count > 0); }; - auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; + auto seg2 = [&count](typename StreamBufferType::int_type) { return (--count > 0); }; + auto seg1 = [&s, &wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; pplx::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() + 10, wbuf.collection().size()); @@ -148,8 +151,8 @@ void streambuf_putn(StreamBufferType& wbuf) VERIFY_ARE_EQUAL(s.size() * 2, wbuf.in_avail()); int count = 10; - auto seg2 = [&count](size_t ) { return (--count > 0); }; - auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; + auto seg2 = [&count](size_t) { return (--count > 0); }; + auto seg1 = [&s, &wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; pplx::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() * 12, wbuf.in_avail()); @@ -178,8 +181,8 @@ void streambuf_putn(concurrency::streams::rawptr_buffer& wbuf) VERIFY_ARE_EQUAL(s.size(), wbuf.putn_nocopy(s.data(), s.size()).get()); int count = 10; - auto seg2 = [&count](size_t ) { return (--count > 0); }; - auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; + auto seg2 = [&count](size_t) { return (--count > 0); }; + auto seg1 = [&s, &wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; pplx::details::_do_while(seg1).wait(); wbuf.close().get(); @@ -207,8 +210,8 @@ void streambuf_putn(concurrency::streams::container_buffer& wbuf VERIFY_ARE_EQUAL(s.size(), wbuf.putn_nocopy(s.data(), s.size()).get()); int count = 10; - auto seg2 = [&count](size_t ) { return (--count > 0); }; - auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; + auto seg2 = [&count](size_t) { return (--count > 0); }; + auto seg1 = [&s, &wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; pplx::details::_do_while(seg1).wait(); wbuf.close().get(); @@ -228,7 +231,7 @@ void streambuf_alloc_commit(StreamBufferType& wbuf) size_t allocSize = 10; size_t commitSize = 2; - for (size_t i = 0; i < allocSize/commitSize; i++) + for (size_t i = 0; i < allocSize / commitSize; i++) { // Allocate space for 10 chars auto data = wbuf.alloc(allocSize); @@ -238,7 +241,7 @@ void streambuf_alloc_commit(StreamBufferType& wbuf) // commit 2 wbuf.commit(commitSize); - VERIFY_ARE_EQUAL((i+1)*commitSize, wbuf.in_avail()); + VERIFY_ARE_EQUAL((i + 1) * commitSize, wbuf.in_avail()); } VERIFY_ARE_EQUAL(allocSize, wbuf.in_avail()); @@ -257,7 +260,7 @@ void streambuf_alloc_commit(concurrency::streams::container_buffer& wbuf) size_t allocSize = 10; size_t commitSize = 2; - for (size_t i = 0; i < allocSize/commitSize; i++) + for (size_t i = 0; i < allocSize / commitSize; i++) { // Allocate space for 10 chars auto data = wbuf.alloc(allocSize); @@ -296,7 +299,7 @@ void streambuf_alloc_commit(concurrency::streams::rawptr_buffer& wbuf) // commit 2 wbuf.commit(commitSize); - VERIFY_IS_TRUE((i+1)*commitSize <= wbuf.block().size()); + VERIFY_IS_TRUE((i + 1) * commitSize <= wbuf.block().size()); } VERIFY_IS_TRUE(allocSize <= wbuf.block().size()); @@ -338,7 +341,7 @@ void streambuf_getc(StreamBufferType& rbuf, typename StreamBufferType::char_type rbuf.close().get(); VERIFY_IS_FALSE(rbuf.can_read()); - + // getc should return eof after close VERIFY_ARE_EQUAL(StreamBufferType::traits::eof(), rbuf.getc().get()); } @@ -357,7 +360,7 @@ void streambuf_sgetc(StreamBufferType& rbuf, typename StreamBufferType::char_typ rbuf.close().get(); VERIFY_IS_FALSE(rbuf.can_read()); - + // sgetc should return eof after close VERIFY_ARE_EQUAL(StreamBufferType::traits::eof(), rbuf.sgetc()); } @@ -386,7 +389,7 @@ void streambuf_bumpc(StreamBufferType& rbuf, const std::vector -void streambuf_acquire_release(StreamBufferType& rbuf, const std::vector& ) +void streambuf_acquire_release(StreamBufferType& rbuf, const std::vector&) { VERIFY_IS_TRUE(rbuf.can_read()); - typename StreamBufferType::char_type * ptr = nullptr; + typename StreamBufferType::char_type* ptr = nullptr; size_t size = 0; rbuf.acquire(ptr, size); @@ -559,11 +562,9 @@ void streambuf_putn_getn(StreamBufferType& rwbuf) typename StreamBufferType::char_type ptr[4]; - auto readTask = pplx::create_task([&s, &ptr, &rwbuf]() - { - + auto readTask = pplx::create_task([&s, &ptr, &rwbuf]() { VERIFY_ARE_EQUAL(rwbuf.getn(ptr, 4).get(), 4); - + for (size_t i = 0; i < 4; i++) { VERIFY_ARE_EQUAL(s[i], ptr[i]); @@ -573,8 +574,7 @@ void streambuf_putn_getn(StreamBufferType& rwbuf) VERIFY_IS_TRUE(rwbuf.is_eof()); }); - auto writeTask = pplx::create_task([&s, &rwbuf]() - { + auto writeTask = pplx::create_task([&s, &rwbuf]() { VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(s.data(), s.size()).get(), s.size()); rwbuf.close(std::ios_base::out); }); @@ -594,24 +594,21 @@ void streambuf_acquire_alloc(StreamBufferType& rwbuf) { // There should be nothing to read - typename StreamBufferType::char_type * ptr = nullptr; + typename StreamBufferType::char_type* ptr = nullptr; size_t count = 0; rwbuf.acquire(ptr, count); VERIFY_ARE_EQUAL(count, 0); rwbuf.release(ptr, count); } - auto writeTask = pplx::create_task([&rwbuf]() - { + auto writeTask = pplx::create_task([&rwbuf]() { auto ptr = rwbuf.alloc(8); VERIFY_IS_TRUE(ptr != nullptr); rwbuf.commit(4); }); - typename StreamBufferType::char_type * ptr = nullptr; - auto readTask = pplx::create_task([&rwbuf, &ptr, writeTask]() - { - + typename StreamBufferType::char_type* ptr = nullptr; + auto readTask = pplx::create_task([&rwbuf, &ptr, writeTask]() { size_t count = 0; int repeat = 10; @@ -644,13 +641,13 @@ void streambuf_close(StreamBufferType& rwbuf) bool can_rd = rwbuf.can_read(); bool can_wr = rwbuf.can_write(); - if ( can_wr ) + if (can_wr) { // Close the write head rwbuf.close(std::ios_base::out).get(); VERIFY_IS_FALSE(rwbuf.can_write()); - if ( can_rd ) + if (can_rd) { VERIFY_IS_FALSE(rwbuf.can_write()); VERIFY_IS_TRUE(rwbuf.can_read()); @@ -665,8 +662,8 @@ void streambuf_close(StreamBufferType& rwbuf) VERIFY_IS_TRUE(rwbuf.can_read()); } } - - if ( can_rd ) + + if (can_rd) { // Close the read head rwbuf.close(std::ios_base::in).get(); @@ -769,8 +766,7 @@ void streambuf_close_parallel(StreamBufferType& rwbuf) VERIFY_IS_TRUE(rwbuf.can_write()); // Close the read and write head in parallel - auto closeReadTask = pplx::create_task([&rwbuf]() - { + auto closeReadTask = pplx::create_task([&rwbuf]() { VERIFY_IS_TRUE(rwbuf.can_read()); // Close the read head @@ -781,8 +777,7 @@ void streambuf_close_parallel(StreamBufferType& rwbuf) rwbuf.close(std::ios_base::in).wait(); }); - auto closeWriteTask = pplx::create_task([&rwbuf]() - { + auto closeWriteTask = pplx::create_task([&rwbuf]() { VERIFY_IS_TRUE(rwbuf.can_write()); // Close the write head @@ -793,7 +788,6 @@ void streambuf_close_parallel(StreamBufferType& rwbuf) rwbuf.close(std::ios_base::out).wait(); }); - closeReadTask.wait(); closeWriteTask.wait(); @@ -801,7 +795,7 @@ void streambuf_close_parallel(StreamBufferType& rwbuf) VERIFY_IS_FALSE(rwbuf.is_open()); } -streams::producer_consumer_buffer create_producer_consumer_buffer_with_data(const std::vector & s) +streams::producer_consumer_buffer create_producer_consumer_buffer_with_data(const std::vector& s) { streams::producer_consumer_buffer buf; VERIFY_ARE_EQUAL(buf.putn_nocopy(s.data(), s.size()).get(), s.size()); @@ -811,1770 +805,1732 @@ streams::producer_consumer_buffer create_producer_consumer_buffer_with_ SUITE(memstream_tests) { - -TEST(string_buffer_putc) -{ - stringstreambuf buf; - streambuf_putc(buf); -} - -TEST(charptr_buffer_putc_fail) -{ - char chars[26]; - rawptr_buffer buf(chars, 26); - VERIFY_ARE_EQUAL(buf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get(), 26); - VERIFY_ARE_EQUAL(buf.putc('a').get(), std::char_traits::eof()); -} - -TEST(wstring_buffer_putc) -{ - wstringstreambuf buf; - streambuf_putc(buf); -} - -TEST(string_buffer_putn) -{ - stringstreambuf buf; - streambuf_putn(buf); -} -TEST(wstring_buffer_putn) -{ - wstringstreambuf buf; - streambuf_putn(buf); -} -TEST(charptr_buffer_putn) -{ - { - char chars[128]; - rawptr_buffer buf(chars, sizeof(chars)); - streambuf_putn(buf); - } + TEST(string_buffer_putc) { - uint8_t chars[128]; - rawptr_buffer buf(chars, sizeof(chars)); - streambuf_putn(buf); + stringstreambuf buf; + streambuf_putc(buf); } + + TEST(charptr_buffer_putc_fail) { - utf16char chars[128]; - rawptr_buffer buf(chars, sizeof(chars)/sizeof(utf16char)); - streambuf_putn(buf); + char chars[26]; + rawptr_buffer buf(chars, 26); + VERIFY_ARE_EQUAL(buf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get(), 26); + VERIFY_ARE_EQUAL(buf.putc('a').get(), std::char_traits::eof()); } -} -TEST(charptr_buffer_putn_fail) -{ + + TEST(wstring_buffer_putc) { - char chars[128]; - rawptr_buffer buf(chars, 12); - VERIFY_THROWS(buf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get(), std::runtime_error); + wstringstreambuf buf; + streambuf_putc(buf); } -} -TEST(bytevec_buffer_putn) -{ + TEST(string_buffer_putn) { - container_buffer> buf; + stringstreambuf buf; streambuf_putn(buf); } + TEST(wstring_buffer_putn) { - container_buffer> buf; + wstringstreambuf buf; streambuf_putn(buf); } + TEST(charptr_buffer_putn) { - container_buffer> buf; - streambuf_putn(buf); + { + char chars[128]; + rawptr_buffer buf(chars, sizeof(chars)); + streambuf_putn(buf); + } + { + uint8_t chars[128]; + rawptr_buffer buf(chars, sizeof(chars)); + streambuf_putn(buf); + } + { + utf16char chars[128]; + rawptr_buffer buf(chars, sizeof(chars) / sizeof(utf16char)); + streambuf_putn(buf); + } } -} -TEST(mem_buffer_putn) -{ + TEST(charptr_buffer_putn_fail) { - streams::producer_consumer_buffer buf; - streambuf_putn(buf); + { + char chars[128]; + rawptr_buffer buf(chars, 12); + VERIFY_THROWS(buf.putn_nocopy("abcdefghijklmnopqrstuvwxyz", 26).get(), std::runtime_error); + } } + TEST(bytevec_buffer_putn) { - streams::producer_consumer_buffer buf; - streambuf_putn(buf); + { + container_buffer> buf; + streambuf_putn(buf); + } + { + container_buffer> buf; + streambuf_putn(buf); + } + { + container_buffer> buf; + streambuf_putn(buf); + } } - + TEST(mem_buffer_putn) { - streams::producer_consumer_buffer buf; - streambuf_putn(buf); - } -} + { + streams::producer_consumer_buffer buf; + streambuf_putn(buf); + } -TEST(string_buffer_alloc_commit) -{ - stringstreambuf buf; - streambuf_alloc_commit(buf); -} + { + streams::producer_consumer_buffer buf; + streambuf_putn(buf); + } -TEST(wstring_buffer_alloc_commit) -{ - wstringstreambuf buf; - streambuf_alloc_commit(buf); -} + { + streams::producer_consumer_buffer buf; + streambuf_putn(buf); + } + } -TEST(mem_buffer_alloc_commit) -{ + TEST(string_buffer_alloc_commit) { - streams::producer_consumer_buffer buf; + stringstreambuf buf; streambuf_alloc_commit(buf); } + TEST(wstring_buffer_alloc_commit) { - streams::producer_consumer_buffer buf; + wstringstreambuf buf; streambuf_alloc_commit(buf); } + TEST(mem_buffer_alloc_commit) { - streams::producer_consumer_buffer buf; - streambuf_alloc_commit(buf); + { + streams::producer_consumer_buffer buf; + streambuf_alloc_commit(buf); + } + + { + streams::producer_consumer_buffer buf; + streambuf_alloc_commit(buf); + } + + { + streams::producer_consumer_buffer buf; + streambuf_alloc_commit(buf); + } } -} -TEST(string_buffer_seek_write) -{ - stringstreambuf buf; - streambuf_seek_write(buf); -} -TEST(wstring_buffer_seek_write) -{ - wstringstreambuf buf; - streambuf_seek_write(buf); -} -TEST(charptr_buffer_seek_write) -{ + TEST(string_buffer_seek_write) { - char chars[128]; - rawptr_buffer buf(chars, sizeof(chars)); + stringstreambuf buf; streambuf_seek_write(buf); } + TEST(wstring_buffer_seek_write) { - uint8_t chars[128]; - rawptr_buffer buf(chars, sizeof(chars)); + wstringstreambuf buf; streambuf_seek_write(buf); } + TEST(charptr_buffer_seek_write) { - utf16char chars[128]; - rawptr_buffer buf(chars, sizeof(chars)/sizeof(utf16char)); - streambuf_seek_write(buf); + { + char chars[128]; + rawptr_buffer buf(chars, sizeof(chars)); + streambuf_seek_write(buf); + } + { + uint8_t chars[128]; + rawptr_buffer buf(chars, sizeof(chars)); + streambuf_seek_write(buf); + } + { + utf16char chars[128]; + rawptr_buffer buf(chars, sizeof(chars) / sizeof(utf16char)); + streambuf_seek_write(buf); + } } -} -TEST(bytevec_buffer_seek_write) -{ + TEST(bytevec_buffer_seek_write) { - container_buffer> buf; - streambuf_seek_write(buf); + { + container_buffer> buf; + streambuf_seek_write(buf); + } + { + container_buffer> buf; + streambuf_seek_write(buf); + } + { + container_buffer> buf; + streambuf_seek_write(buf); + } } + TEST(mem_buffer_seek_write) { - container_buffer> buf; - streambuf_seek_write(buf); + streams::producer_consumer_buffer buf; + VERIFY_IS_FALSE(buf.can_seek()); } + + TEST(string_buffer_getc) { - container_buffer> buf; - streambuf_seek_write(buf); + std::string s("Hello World"); + std::vector v(std::begin(s), std::end(s)); + streams::stringstreambuf buf(s); + streambuf_getc(buf, v[0]); + } + TEST(wstring_buffer_getc) + { + utility::string_t s(U("Hello World")); + std::vector v(std::begin(s), std::end(s)); + streams::wstringstreambuf buf(s); + streambuf_getc(buf, v[0]); + } + TEST(charptr_buffer_getc) + { + { + char chars[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + rawptr_buffer buf(chars, sizeof(chars), std::ios::in); + streambuf_getc(buf, chars[0]); + } + { + uint8_t chars[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + rawptr_buffer buf(chars, sizeof(chars), std::ios::in); + streambuf_getc(buf, chars[0]); + } + { + utf16char chars[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + rawptr_buffer buf(chars, sizeof(chars) / sizeof(utf16char), std::ios::in); + streambuf_getc(buf, chars[0]); + } + } + TEST(bytevec_buffer_getc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + container_buffer> buf(s); + streambuf_getc(buf, s[0]); + } + TEST(mem_buffer_getc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); + streambuf_getc(buf, s[0]); } -} -TEST(mem_buffer_seek_write) -{ - streams::producer_consumer_buffer buf; - VERIFY_IS_FALSE(buf.can_seek()); -} -TEST(string_buffer_getc) -{ - std::string s("Hello World"); - std::vector v(std::begin(s), std::end(s)); - streams::stringstreambuf buf(s); - streambuf_getc(buf, v[0]); -} -TEST(wstring_buffer_getc) -{ - utility::string_t s(U("Hello World")); - std::vector v(std::begin(s), std::end(s)); - streams::wstringstreambuf buf(s); - streambuf_getc(buf, v[0]); -} -TEST(charptr_buffer_getc) -{ + TEST(string_buffer_sgetc) + { + std::string s("Hello World"); + std::vector v(std::begin(s), std::end(s)); + streams::stringstreambuf buf(s); + streambuf_sgetc(buf, v[0]); + } + TEST(wstring_buffer_sgetc) + { + utility::string_t s(U("Hello World")); + std::vector v(std::begin(s), std::end(s)); + streams::wstringstreambuf buf(s); + streambuf_sgetc(buf, v[0]); + } + TEST(charptr_buffer_sgetc) { char chars[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; rawptr_buffer buf(chars, sizeof(chars), std::ios::in); - streambuf_getc(buf, chars[0]); + streambuf_sgetc(buf, chars[0]); + } + TEST(bytevec_buffer_sgetc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + container_buffer> buf(s); + streambuf_sgetc(buf, s[0]); + } + TEST(mem_buffer_sgetc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); + streambuf_sgetc(buf, s[0]); + } + + TEST(string_buffer_bumpc) + { + std::string s("Hello World"); + std::vector v(std::begin(s), std::end(s)); + streams::stringstreambuf buf(s); + streambuf_bumpc(buf, v); + } + TEST(wstring_buffer_bumpc) + { + utility::string_t s(U("Hello World")); + std::vector v(std::begin(s), std::end(s)); + streams::wstringstreambuf buf(s); + streambuf_bumpc(buf, v); } + TEST(charptr_buffer_bumpc) { uint8_t chars[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(chars), std::end(chars)); rawptr_buffer buf(chars, sizeof(chars), std::ios::in); - streambuf_getc(buf, chars[0]); + streambuf_bumpc(buf, s); } + TEST(bytevec_buffer_bumpc) { - utf16char chars[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - rawptr_buffer buf(chars, sizeof(chars)/sizeof(utf16char), std::ios::in); - streambuf_getc(buf, chars[0]); + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + container_buffer> buf(s); + streambuf_bumpc(buf, s); } -} -TEST(bytevec_buffer_getc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - container_buffer> buf(s); - streambuf_getc(buf, s[0]); -} -TEST(mem_buffer_getc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); - streambuf_getc(buf, s[0]); -} - -TEST(string_buffer_sgetc) -{ - std::string s("Hello World"); - std::vector v(std::begin(s), std::end(s)); - streams::stringstreambuf buf(s); - streambuf_sgetc(buf, v[0]); -} -TEST(wstring_buffer_sgetc) -{ - utility::string_t s(U("Hello World")); - std::vector v(std::begin(s), std::end(s)); - streams::wstringstreambuf buf(s); - streambuf_sgetc(buf, v[0]); -} -TEST(charptr_buffer_sgetc) -{ - char chars[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - rawptr_buffer buf(chars, sizeof(chars), std::ios::in); - streambuf_sgetc(buf, chars[0]); -} -TEST(bytevec_buffer_sgetc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - container_buffer> buf(s); - streambuf_sgetc(buf, s[0]); -} -TEST(mem_buffer_sgetc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); - streambuf_sgetc(buf, s[0]); -} -TEST(string_buffer_bumpc) -{ - std::string s("Hello World"); - std::vector v(std::begin(s), std::end(s)); - streams::stringstreambuf buf(s); - streambuf_bumpc(buf, v); -} -TEST(wstring_buffer_bumpc) -{ - utility::string_t s(U("Hello World")); - std::vector v(std::begin(s), std::end(s)); - streams::wstringstreambuf buf(s); - streambuf_bumpc(buf, v); -} -TEST(charptr_buffer_bumpc) -{ - uint8_t chars[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(chars), std::end(chars)); - rawptr_buffer buf(chars, sizeof(chars), std::ios::in); - streambuf_bumpc(buf, s); -} -TEST(bytevec_buffer_bumpc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - container_buffer> buf(s); - streambuf_bumpc(buf, s); -} + TEST(mem_buffer_bumpc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); + streambuf_bumpc(buf, s); + } -TEST(mem_buffer_bumpc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); - streambuf_bumpc(buf, s); -} + TEST(string_buffer_sbumpc) + { + std::string s("Hello World"); + std::vector v(std::begin(s), std::end(s)); + streams::stringstreambuf buf(s); + streambuf_sbumpc(buf, v); + } + TEST(wstring_buffer_sbumpc) + { + utility::string_t s(U("Hello World")); + std::vector v(std::begin(s), std::end(s)); + streams::wstringstreambuf buf(s); + streambuf_sbumpc(buf, v); + } + TEST(charptr_buffer_sbumpc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + rawptr_buffer buf(data, sizeof(data), std::ios::in); + streambuf_sbumpc(buf, s); + } + TEST(bytevec_buffer_sbumpc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + container_buffer> buf(s); + streambuf_sbumpc(buf, s); + } -TEST(string_buffer_sbumpc) -{ - std::string s("Hello World"); - std::vector v(std::begin(s), std::end(s)); - streams::stringstreambuf buf(s); - streambuf_sbumpc(buf, v); -} -TEST(wstring_buffer_sbumpc) -{ - utility::string_t s(U("Hello World")); - std::vector v(std::begin(s), std::end(s)); - streams::wstringstreambuf buf(s); - streambuf_sbumpc(buf, v); -} -TEST(charptr_buffer_sbumpc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - rawptr_buffer buf(data, sizeof(data), std::ios::in); - streambuf_sbumpc(buf, s); -} -TEST(bytevec_buffer_sbumpc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - container_buffer> buf(s); - streambuf_sbumpc(buf, s); -} + TEST(mem_buffer_sbumpc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); + streambuf_sbumpc(buf, s); + } + TEST(string_buffer_nextc) + { + std::string s("Hello World"); + std::vector v(std::begin(s), std::end(s)); + streams::stringstreambuf buf(s); + streambuf_nextc(buf, v); + } + TEST(wstring_buffer_nextc) + { + utility::string_t s(U("Hello World")); + std::vector v(std::begin(s), std::end(s)); + streams::wstringstreambuf buf(s); + streambuf_nextc(buf, v); + } + TEST(charptr_buffer_nextc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + rawptr_buffer buf(data, sizeof(data), std::ios::in); + streambuf_nextc(buf, s); + } + TEST(bytevec_buffer_nextc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + container_buffer> buf(s); + streambuf_nextc(buf, s); + } + TEST(mem_buffer_nextc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); + streambuf_nextc(buf, s); + } -TEST(mem_buffer_sbumpc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); - streambuf_sbumpc(buf, s); -} -TEST(string_buffer_nextc) -{ - std::string s("Hello World"); - std::vector v(std::begin(s), std::end(s)); - streams::stringstreambuf buf(s); - streambuf_nextc(buf, v); -} -TEST(wstring_buffer_nextc) -{ - utility::string_t s(U("Hello World")); - std::vector v(std::begin(s), std::end(s)); - streams::wstringstreambuf buf(s); - streambuf_nextc(buf, v); -} -TEST(charptr_buffer_nextc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - rawptr_buffer buf(data, sizeof(data), std::ios::in); - streambuf_nextc(buf, s); -} -TEST(bytevec_buffer_nextc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - container_buffer> buf(s); - streambuf_nextc(buf, s); -} -TEST(mem_buffer_nextc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); - streambuf_nextc(buf, s); -} + TEST(string_buffer_ungetc) + { + std::string s("Hello World"); + std::vector v(std::begin(s), std::end(s)); + streams::stringstreambuf buf(s); + streambuf_ungetc(buf, v); + } + TEST(wstring_buffer_ungetc) + { + utility::string_t s(U("Hello World")); + std::vector v(std::begin(s), std::end(s)); + streams::wstringstreambuf buf(s); + streambuf_ungetc(buf, v); + } + TEST(charptr_buffer_ungetc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + rawptr_buffer buf(data, sizeof(data), std::ios::in); + streambuf_ungetc(buf, s); + } + TEST(bytevec_buffer_ungetc) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + container_buffer> buf(s); + streambuf_ungetc(buf, s); + } -TEST(string_buffer_ungetc) -{ - std::string s("Hello World"); - std::vector v(std::begin(s), std::end(s)); - streams::stringstreambuf buf(s); - streambuf_ungetc(buf, v); -} -TEST(wstring_buffer_ungetc) -{ - utility::string_t s(U("Hello World")); - std::vector v(std::begin(s), std::end(s)); - streams::wstringstreambuf buf(s); - streambuf_ungetc(buf, v); -} -TEST(charptr_buffer_ungetc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - rawptr_buffer buf(data, sizeof(data), std::ios::in); - streambuf_ungetc(buf, s); -} -TEST(bytevec_buffer_ungetc) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - container_buffer> buf(s); - streambuf_ungetc(buf, s); -} + TEST(string_buffer_getn) + { + std::string s("Hello World"); + std::vector v(std::begin(s), std::end(s)); + streams::stringstreambuf buf(s); + streambuf_getn(buf, v); + } + TEST(wstring_buffer_getn) + { + utility::string_t s(U("Hello World")); + std::vector v(std::begin(s), std::end(s)); + streams::wstringstreambuf buf(s); + streambuf_getn(buf, v); + } + TEST(charptr_buffer_getn) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + rawptr_buffer buf(data, sizeof(data), std::ios::in); + streambuf_getn(buf, s); + } + TEST(bytevec_buffer_getn) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + container_buffer> buf(s); + streambuf_getn(buf, s); + } + TEST(mem_buffer_getn) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); + streambuf_getn(buf, s); + } -TEST(string_buffer_getn) -{ - std::string s("Hello World"); - std::vector v(std::begin(s), std::end(s)); - streams::stringstreambuf buf(s); - streambuf_getn(buf, v); -} -TEST(wstring_buffer_getn) -{ - utility::string_t s(U("Hello World")); - std::vector v(std::begin(s), std::end(s)); - streams::wstringstreambuf buf(s); - streambuf_getn(buf, v); -} -TEST(charptr_buffer_getn) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - rawptr_buffer buf(data, sizeof(data), std::ios::in); - streambuf_getn(buf, s); -} -TEST(bytevec_buffer_getn) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - container_buffer> buf(s); - streambuf_getn(buf, s); -} -TEST(mem_buffer_getn) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); - streambuf_getn(buf, s); -} - -TEST(string_buffer_acquire_release) -{ - std::string s("Hello World"); - std::vector v(std::begin(s), std::end(s)); - streams::stringstreambuf buf(s); - streambuf_acquire_release(buf, v); -} -TEST(wstring_buffer_acquire_release) -{ - utility::string_t s(U("Hello World")); - std::vector v(std::begin(s), std::end(s)); - streams::wstringstreambuf buf(s); - streambuf_acquire_release(buf, v); -} -TEST(charptr_buffer_acquire_release) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - rawptr_buffer buf(data, sizeof(data), std::ios::in); - streambuf_acquire_release(buf, s); -} -TEST(bytevec_buffer_acquire_release) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - container_buffer> buf(s); - streambuf_acquire_release(buf, s); -} -TEST(mem_buffer_acquire_release) -{ - uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; - std::vector s(std::begin(data), std::end(data)); - streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); - streambuf_acquire_release(buf, s); -} -TEST(string_buffer_seek_read) -{ - std::string s("Hello World"); - std::vector v(std::begin(s), std::end(s)); - streams::stringstreambuf buf(s); - streambuf_seek_read(buf); -} - -TEST(mem_buffer_putn_getn) -{ - streams::producer_consumer_buffer buf; - streambuf_putn_getn(buf); -} - -TEST(mem_buffer_acquire_alloc) -{ - streams::producer_consumer_buffer buf; - streambuf_acquire_alloc(buf); -} + TEST(string_buffer_acquire_release) + { + std::string s("Hello World"); + std::vector v(std::begin(s), std::end(s)); + streams::stringstreambuf buf(s); + streambuf_acquire_release(buf, v); + } + TEST(wstring_buffer_acquire_release) + { + utility::string_t s(U("Hello World")); + std::vector v(std::begin(s), std::end(s)); + streams::wstringstreambuf buf(s); + streambuf_acquire_release(buf, v); + } + TEST(charptr_buffer_acquire_release) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + rawptr_buffer buf(data, sizeof(data), std::ios::in); + streambuf_acquire_release(buf, s); + } + TEST(bytevec_buffer_acquire_release) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + container_buffer> buf(s); + streambuf_acquire_release(buf, s); + } + TEST(mem_buffer_acquire_release) + { + uint8_t data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; + std::vector s(std::begin(data), std::end(data)); + streams::producer_consumer_buffer buf = create_producer_consumer_buffer_with_data(s); + streambuf_acquire_release(buf, s); + } + TEST(string_buffer_seek_read) + { + std::string s("Hello World"); + std::vector v(std::begin(s), std::end(s)); + streams::stringstreambuf buf(s); + streambuf_seek_read(buf); + } -TEST(string_buffer_close) -{ - streams::stringstreambuf buf; - streambuf_close(buf); -} -TEST(wstring_buffer_close) -{ - streams::wstringstreambuf buf; - streambuf_close(buf); -} -TEST(bytevec_buffer_close) -{ - container_buffer> buf; - streambuf_close(buf); -} -TEST(mem_buffer_close) -{ - streams::producer_consumer_buffer buf; - streambuf_close(buf); -} + TEST(mem_buffer_putn_getn) + { + streams::producer_consumer_buffer buf; + streambuf_putn_getn(buf); + } -TEST(mem_buffer_close_read_with_pending_read) -{ - streams::producer_consumer_buffer buf; - streambuf_close_read_with_pending_read(buf); -} + TEST(mem_buffer_acquire_alloc) + { + streams::producer_consumer_buffer buf; + streambuf_acquire_alloc(buf); + } -TEST(mem_buffer_close_write_with_pending_read) -{ - streams::producer_consumer_buffer buf; - streambuf_close_write_with_pending_read(buf); -} + TEST(string_buffer_close) + { + streams::stringstreambuf buf; + streambuf_close(buf); + } + TEST(wstring_buffer_close) + { + streams::wstringstreambuf buf; + streambuf_close(buf); + } + TEST(bytevec_buffer_close) + { + container_buffer> buf; + streambuf_close(buf); + } + TEST(mem_buffer_close) + { + streams::producer_consumer_buffer buf; + streambuf_close(buf); + } -TEST(mem_buffer_close_parallel) -{ - streams::producer_consumer_buffer buf; - streambuf_close_parallel(buf); -} + TEST(mem_buffer_close_read_with_pending_read) + { + streams::producer_consumer_buffer buf; + streambuf_close_read_with_pending_read(buf); + } -TEST(mem_buffer_close_destroy) -{ - std::vector> taskVector; + TEST(mem_buffer_close_write_with_pending_read) + { + streams::producer_consumer_buffer buf; + streambuf_close_write_with_pending_read(buf); + } - for (int i = 0; i < 1000; i++) + TEST(mem_buffer_close_parallel) { streams::producer_consumer_buffer buf; - taskVector.push_back(buf.close()); + streambuf_close_parallel(buf); } - pplx::when_all(std::begin(taskVector), std::end(taskVector)).wait(); -} + TEST(mem_buffer_close_destroy) + { + std::vector> taskVector; -TEST(string_buffer_ctor) -{ - std::string src("abcdef ghij"); - auto instream = streams::stringstream::open_istream(src); + for (int i = 0; i < 1000; i++) + { + streams::producer_consumer_buffer buf; + taskVector.push_back(buf.close()); + } - streams::stringstreambuf sbuf; - auto outstream = sbuf.create_ostream(); + pplx::when_all(std::begin(taskVector), std::end(taskVector)).wait(); + } - for(;;) + TEST(string_buffer_ctor) { - const int count = 4; - char temp[count]; - streams::rawptr_buffer buf1(temp, count); - streams::rawptr_buffer buf2(temp, count, std::ios::in); - auto size = instream.read(buf1, count).get(); - VERIFY_IS_TRUE(size <= count); - VERIFY_ARE_EQUAL(size, outstream.write(buf2, size).get()); + std::string src("abcdef ghij"); + auto instream = streams::stringstream::open_istream(src); + + streams::stringstreambuf sbuf; + auto outstream = sbuf.create_ostream(); - if (size != count) break; + for (;;) + { + const int count = 4; + char temp[count]; + streams::rawptr_buffer buf1(temp, count); + streams::rawptr_buffer buf2(temp, count, std::ios::in); + auto size = instream.read(buf1, count).get(); + VERIFY_IS_TRUE(size <= count); + VERIFY_ARE_EQUAL(size, outstream.write(buf2, size).get()); + + if (size != count) break; + } + + auto& dest = sbuf.collection(); + VERIFY_ARE_EQUAL(src, dest); } - auto& dest = sbuf.collection(); - VERIFY_ARE_EQUAL(src, dest); -} + TEST(vec_buffer_ctor) + { + std::string srcstr("abcdef ghij"); + std::vector src(begin(srcstr), end(srcstr)); + auto instream = streams::bytestream::open_istream(src); -TEST(vec_buffer_ctor) -{ - std::string srcstr("abcdef ghij"); - std::vector src(begin(srcstr), end(srcstr)); - auto instream = streams::bytestream::open_istream(src); + container_buffer> sbuf; + auto outstream = sbuf.create_ostream(); - container_buffer> sbuf; - auto outstream = sbuf.create_ostream(); + for (;;) + { + const int count = 4; + uint8_t temp[count]; + streams::rawptr_buffer buf1(temp, count); + streams::rawptr_buffer buf2(temp, count, std::ios::in); + auto size = instream.read(buf1, count).get(); + VERIFY_IS_TRUE(size <= count); + VERIFY_ARE_EQUAL(size, outstream.write(buf2, size).get()); + + if (size != count) break; + } - for(;;) + auto& dest = sbuf.collection(); + VERIFY_ARE_EQUAL(src, dest); + } + + TEST(charptr_buffer_ctor_1) { - const int count = 4; - uint8_t temp[count]; - streams::rawptr_buffer buf1(temp, count); - streams::rawptr_buffer buf2(temp, count, std::ios::in); - auto size = instream.read(buf1, count).get(); - VERIFY_IS_TRUE(size <= count); - VERIFY_ARE_EQUAL(size, outstream.write(buf2, size).get()); + char chars[] = {'a', 'b', 'c', 'd', 'e', 'f', ' ', 'g', 'h', 'i', 'j'}; + auto instream = streams::rawptr_stream::open_istream(chars, sizeof(chars)); - if (size != count) break; + stringstreambuf sbuf; + auto outstream = sbuf.create_ostream(); + + for (;;) + { + const int count = 4; + char temp[count]; + streams::rawptr_buffer buf1(temp, count); + streams::rawptr_buffer buf2(temp, count, std::ios::in); + auto size = instream.read(buf1, count).get(); + VERIFY_IS_TRUE(size <= count); + VERIFY_ARE_EQUAL(size, outstream.write(buf2, size).get()); + + if (size != count) break; + } + + auto& dest = sbuf.collection(); + VERIFY_ARE_EQUAL(memcmp(chars, &(dest)[0], sizeof(chars)), 0); } - auto& dest = sbuf.collection(); - VERIFY_ARE_EQUAL(src, dest); -} + TEST(charptr_buffer_ctor_2) + { + char chars[] = {'a', 'b', 'c', 'd', 'e', 'f', ' ', 'g', 'h', 'i', 'j'}; + auto instream = streams::rawptr_stream::open_istream(chars, sizeof(chars)); -TEST(charptr_buffer_ctor_1) -{ - char chars[] = {'a', 'b', 'c', 'd', 'e', 'f', ' ', 'g', 'h', 'i', 'j'}; - auto instream = streams::rawptr_stream::open_istream(chars, sizeof(chars)); + stringstreambuf sbuf; + auto outstream = sbuf.create_ostream(); - stringstreambuf sbuf; - auto outstream = sbuf.create_ostream(); + for (;;) + { + const int count = 4; + char temp[count]; + streams::rawptr_buffer buf1(temp, count); + streams::rawptr_buffer buf2(temp, count, std::ios::in); + auto size = instream.read(buf1, count).get(); + VERIFY_IS_TRUE(size <= count); + VERIFY_ARE_EQUAL(size, outstream.write(buf2, size).get()); + + if (size != count) break; + } - for(;;) + auto& dest = sbuf.collection(); + VERIFY_ARE_EQUAL(memcmp(chars, &(dest)[0], sizeof(chars)), 0); + } + + TEST(charptr_buffer_ctor_3) { - const int count = 4; - char temp[count]; - streams::rawptr_buffer buf1(temp, count); - streams::rawptr_buffer buf2(temp, count, std::ios::in); - auto size = instream.read(buf1, count).get(); - VERIFY_IS_TRUE(size <= count); - VERIFY_ARE_EQUAL(size, outstream.write(buf2, size).get()); + char chars[128]; + memset(chars, 0, sizeof(chars)); - if (size != count) break; - } + rawptr_buffer buf(chars, sizeof(chars)); - auto& dest = sbuf.collection(); - VERIFY_ARE_EQUAL(memcmp(chars, &(dest)[0], sizeof(chars)), 0); -} + auto outstream = buf.create_ostream(); -TEST(charptr_buffer_ctor_2) -{ - char chars[] = {'a', 'b', 'c', 'd', 'e', 'f', ' ', 'g', 'h', 'i', 'j'}; - auto instream = streams::rawptr_stream::open_istream(chars, sizeof(chars)); + auto t1 = outstream.print("Hello "); + auto t2 = outstream.print(10); + auto t3 = outstream.print(" Again!"); + (t1 && t2 && t3).wait(); - stringstreambuf sbuf; - auto outstream = sbuf.create_ostream(); + std::string result(chars); - for(;;) - { - const int count = 4; - char temp[count]; - streams::rawptr_buffer buf1(temp, count); - streams::rawptr_buffer buf2(temp, count, std::ios::in); - auto size = instream.read(buf1, count).get(); - VERIFY_IS_TRUE(size <= count); - VERIFY_ARE_EQUAL(size, outstream.write(buf2, size).get()); + VERIFY_ARE_EQUAL(result, "Hello 10 Again!"); + } - if (size != count) break; + TEST(validate_stream_mode) + { + VERIFY_THROWS(concurrency::streams::container_buffer>(std::ios::in | std::ios::out), + std::invalid_argument); + std::vector vc; + VERIFY_THROWS(concurrency::streams::container_buffer>(vc, std::ios::in | std::ios::out), + std::invalid_argument); } - auto& dest = sbuf.collection(); - VERIFY_ARE_EQUAL(memcmp(chars, &(dest)[0], sizeof(chars)), 0); -} + TEST(write_stream_test_1) + { + char chars[128]; + memset(chars, 0, sizeof(chars)); -TEST(charptr_buffer_ctor_3) -{ - char chars[128]; - memset(chars, 0, sizeof(chars)); + auto stream = streams::rawptr_stream::open_ostream(chars, sizeof(chars)); - rawptr_buffer buf(chars, sizeof(chars)); + std::vector vect; - auto outstream = buf.create_ostream(); + for (char ch = 'a'; ch <= 'z'; ch++) + { + vect.push_back(ch); + } - auto t1 = outstream.print("Hello "); - auto t2 = outstream.print(10); - auto t3 = outstream.print(" Again!"); - (t1 && t2 && t3).wait(); + size_t vsz = vect.size(); - std::string result(chars); + concurrency::streams::container_stream>::buffer_type txtbuf(std::move(vect), + std::ios_base::in); - VERIFY_ARE_EQUAL(result, "Hello 10 Again!"); -} + VERIFY_ARE_EQUAL(stream.write(txtbuf, vsz).get(), vsz); + VERIFY_ARE_EQUAL(strcmp(chars, "abcdefghijklmnopqrstuvwxyz"), 0); -TEST(validate_stream_mode) -{ - VERIFY_THROWS(concurrency::streams::container_buffer>(std::ios::in | std::ios::out), std::invalid_argument); - std::vector vc; - VERIFY_THROWS(concurrency::streams::container_buffer>(vc, std::ios::in | std::ios::out), std::invalid_argument); -} + auto close = stream.close(); -TEST(write_stream_test_1) -{ + VERIFY_IS_TRUE(close.is_done()); + } - char chars[128]; - memset(chars, 0, sizeof(chars)); + TEST(mem_buffer_large_data) + { + // stream large amounts of data + // If the stream stores all the data then we will run out of VA space! + streams::producer_consumer_buffer membuf; - auto stream = streams::rawptr_stream::open_ostream(chars, sizeof(chars)); + const size_t size = 4 * 1024 * 1024; // 4 MB + char* ptr = new char[size]; - std::vector vect; + // stream 4 GB + for (size_t i = 0; i < 1024; i++) + { + // Fill some random positions in the buffer + ptr[i + 0] = 'a'; + ptr[i + 100] = 'b'; - for (char ch = 'a'; ch <= 'z'; ch++) - { - vect.push_back(ch); - } + VERIFY_ARE_EQUAL(size, membuf.putn_nocopy(ptr, size).get()); + + // overwrite the values in ptr + ptr[i + 0] = 'c'; + ptr[i + 100] = 'd'; - size_t vsz = vect.size(); + VERIFY_ARE_EQUAL(size, membuf.getn(ptr, size).get()); - concurrency::streams::container_stream>::buffer_type txtbuf(std::move(vect), std::ios_base::in); + VERIFY_ARE_EQUAL(ptr[i + 0], 'a'); + VERIFY_ARE_EQUAL(ptr[i + 100], 'b'); + } - VERIFY_ARE_EQUAL(stream.write(txtbuf, vsz).get(), vsz); - VERIFY_ARE_EQUAL(strcmp(chars, "abcdefghijklmnopqrstuvwxyz"), 0); + delete[] ptr; + } - auto close = stream.close(); +#ifdef _WIN32 - VERIFY_IS_TRUE(close.is_done()); -} + class ISequentialStream_bridge +#if defined(__cplusplus_winrt) + : public Microsoft::WRL::RuntimeClass, + ISequentialStream> +#endif + { + public: + ISequentialStream_bridge(streambuf buf) : m_buffer(buf) {} -TEST(mem_buffer_large_data) -{ - // stream large amounts of data - // If the stream stores all the data then we will run out of VA space! - streams::producer_consumer_buffer membuf; + // ISequentialStream implementation + virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead) + { + size_t count = m_buffer.getn((char*)pv, (size_t)cb).get(); + if (pcbRead != nullptr) *pcbRead = (ULONG)count; + return S_OK; + } - const size_t size = 4 * 1024 * 1024; // 4 MB - char * ptr = new char[size]; + virtual HRESULT STDMETHODCALLTYPE Write(const void* pv, ULONG cb, ULONG* pcbWritten) + { + size_t count = m_buffer.putn_nocopy((const char*)pv, (size_t)cb).get(); + if (pcbWritten != nullptr) *pcbWritten = (ULONG)count; + return S_OK; + } - // stream 4 GB - for (size_t i = 0; i < 1024; i++) + private: + streambuf m_buffer; + }; + + template + void IStreamTest1() { - // Fill some random positions in the buffer - ptr[i + 0] = 'a'; - ptr[i + 100] = 'b'; + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); - VERIFY_ARE_EQUAL(size, membuf.putn_nocopy(ptr, size).get()); + std::string text = "This is a test"; + size_t len = text.size(); - // overwrite the values in ptr - ptr[i + 0] = 'c'; - ptr[i + 100] = 'd'; + ULONG pcbWritten = 0; - VERIFY_ARE_EQUAL(size, membuf.getn(ptr, size).get()); + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text[0], (ULONG)text.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(text.size(), pcbWritten); - VERIFY_ARE_EQUAL(ptr[i + 0], 'a'); - VERIFY_ARE_EQUAL(ptr[i + 100], 'b'); - } + text = " - but this is not"; + len += text.size(); + pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text[0], (ULONG)text.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(text.size(), pcbWritten); - delete [] ptr; -} + char buf[128]; + memset(buf, 0, sizeof(buf)); -#ifdef _WIN32 + rbuf.getn((char*)buf, len).wait(); -class ISequentialStream_bridge -#if defined(__cplusplus_winrt) - : public Microsoft::WRL::RuntimeClass, ISequentialStream> -#endif -{ -public: - ISequentialStream_bridge(streambuf buf) : m_buffer(buf) - { - } + VERIFY_ARE_EQUAL(0, strcmp("This is a test - but this is not", buf)); - // ISequentialStream implementation - virtual HRESULT STDMETHODCALLTYPE Read( void *pv, ULONG cb, ULONG *pcbRead) - { - size_t count = m_buffer.getn((char *)pv, (size_t)cb).get(); - if ( pcbRead != nullptr ) - *pcbRead = (ULONG)count; - return S_OK; + rbuf.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); } - - virtual HRESULT STDMETHODCALLTYPE Write( const void *pv, ULONG cb, ULONG *pcbWritten ) + + TEST(membuf_IStreamTest1) { IStreamTest1>(); } + + template + void IStreamTest2() { - size_t count = m_buffer.putn_nocopy((const char *)pv, (size_t)cb).get(); - if ( pcbWritten != nullptr ) - *pcbWritten = (ULONG)count; - return S_OK; - } + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); -private: - streambuf m_buffer; -}; + std::string text = "This is a test"; + size_t len = text.size(); -template -void IStreamTest1() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + ULONG pcbWritten = 0; - std::string text = "This is a test"; - size_t len = text.size(); + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text[0], (ULONG)text.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(text.size(), pcbWritten); - ULONG pcbWritten = 0; + text = " - but this is not"; + len += text.size(); + pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text[0], (ULONG)text.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(text.size(), pcbWritten); - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text[0], (ULONG)text.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(text.size(), pcbWritten); + char buf[128]; + memset(buf, 0, sizeof(buf)); - text = " - but this is not"; - len += text.size(); - pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text[0], (ULONG)text.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(text.size(), pcbWritten); + rbuf.getn((char*)buf, len).wait(); - char buf[128]; - memset(buf, 0, sizeof(buf)); + VERIFY_ARE_EQUAL(0, strcmp("This is a test - but this is not", buf)); - rbuf.getn((char *)buf, len).wait(); - - VERIFY_ARE_EQUAL(0, strcmp("This is a test - but this is not", buf)); + rbuf.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); + } - rbuf.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + TEST(membuf_IStreamTest2) { IStreamTest2>(); } -TEST(membuf_IStreamTest1) -{ - IStreamTest1>(); -} + template + void IStreamTest3() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); -template -void IStreamTest2() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + std::string text1 = "This is a test"; + size_t len1 = text1.size(); + std::string text2 = " - but this is not"; + size_t len2 = text2.size(); - std::string text = "This is a test"; - size_t len = text.size(); + char buf[128]; + memset(buf, 0, sizeof(buf)); - ULONG pcbWritten = 0; + // The read happens before the write. - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text[0], (ULONG)text.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(text.size(), pcbWritten); + auto read = rbuf.getn((char*)buf, len1 + len2); - text = " - but this is not"; - len += text.size(); - pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text[0], (ULONG)text.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(text.size(), pcbWritten); + ULONG pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text1[0], (ULONG)text1.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(len1, pcbWritten); + pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text2[0], (ULONG)text2.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(len2, pcbWritten); - char buf[128]; - memset(buf, 0, sizeof(buf)); + read.wait(); - rbuf.getn((char *)buf, len).wait(); - - VERIFY_ARE_EQUAL(0, strcmp("This is a test - but this is not", buf)); + // We may or may not read data from both writes here. It depends on the + // stream in use. Both are correct behaviors. + if (read.get() == len1 + len2) + VERIFY_ARE_EQUAL(0, strcmp("This is a test - but this is not", (char*)buf)); + else + VERIFY_ARE_EQUAL(0, strcmp("This is a test", (char*)buf)); - rbuf.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + rbuf.close().get(); + } -TEST(membuf_IStreamTest2) -{ - IStreamTest2>(); -} + TEST(membuf_IStreamTest3) { IStreamTest3>(); } -template -void IStreamTest3() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); - - std::string text1 = "This is a test"; - size_t len1 = text1.size(); - std::string text2 = " - but this is not"; - size_t len2 = text2.size(); - - char buf[128]; - memset(buf, 0, sizeof(buf)); - - // The read happens before the write. - - auto read = rbuf.getn((char *)buf, len1+len2); - - ULONG pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text1[0], (ULONG)text1.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(len1, pcbWritten); - pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text2[0], (ULONG)text2.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(len2, pcbWritten); - - read.wait(); - - // We may or may not read data from both writes here. It depends on the - // stream in use. Both are correct behaviors. - if ( read.get() == len1+len2 ) - VERIFY_ARE_EQUAL(0, strcmp("This is a test - but this is not", (char*)buf)); - else - VERIFY_ARE_EQUAL(0, strcmp("This is a test", (char*)buf)); + template + void IStreamTest4() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); + std::string text1 = "This is a test"; + size_t len1 = text1.size(); + std::string text2 = " - but this is not"; + size_t len2 = text2.size(); - rbuf.close().get(); -} + char buf1[128]; + memset(buf1, 0, sizeof(buf1)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); -TEST(membuf_IStreamTest3) -{ - IStreamTest3>(); -} + // The read happens before the write. -template -void IStreamTest4() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); - - std::string text1 = "This is a test"; - size_t len1 = text1.size(); - std::string text2 = " - but this is not"; - size_t len2 = text2.size(); - - char buf1[128]; - memset(buf1, 0, sizeof(buf1)); - char buf2[128]; - memset(buf2, 0, sizeof(buf2)); - - // The read happens before the write. - - auto read1 = rbuf.getn(buf1, 8); - auto read2 = rbuf.getn(buf2, 12); - - ULONG pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text1[0], (ULONG)text1.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(len1, pcbWritten); - pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text2[0], (ULONG)text2.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(len2, pcbWritten); - - VERIFY_ARE_EQUAL(8u, read1.get()); - // Different results depending on stream implementation. Both correct. - VERIFY_IS_TRUE(read2.get() == 12u || read2.get() == 6u); - - VERIFY_ARE_EQUAL(0, strcmp("This is ", (char*)buf1)); - if ( read2.get() == 12u ) - VERIFY_ARE_EQUAL(0, strcmp("a test - but", (char*)buf2)); - else - VERIFY_ARE_EQUAL(0, strcmp("a test", (char*)buf2)); + auto read1 = rbuf.getn(buf1, 8); + auto read2 = rbuf.getn(buf2, 12); - rbuf.close().get(); -} + ULONG pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text1[0], (ULONG)text1.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(len1, pcbWritten); + pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text2[0], (ULONG)text2.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(len2, pcbWritten); -TEST(membuf_IStreamTest4) -{ - IStreamTest4>(); -} + VERIFY_ARE_EQUAL(8u, read1.get()); + // Different results depending on stream implementation. Both correct. + VERIFY_IS_TRUE(read2.get() == 12u || read2.get() == 6u); -template -void IStreamTest5() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + VERIFY_ARE_EQUAL(0, strcmp("This is ", (char*)buf1)); + if (read2.get() == 12u) + VERIFY_ARE_EQUAL(0, strcmp("a test - but", (char*)buf2)); + else + VERIFY_ARE_EQUAL(0, strcmp("a test", (char*)buf2)); - std::string text1 = "This is a test"; - size_t len1 = text1.size(); + rbuf.close().get(); + } - char buf1[128]; - memset(buf1, 0, sizeof(buf1)); - - // The read happens before the write. + TEST(membuf_IStreamTest4) { IStreamTest4>(); } - auto read1 = rbuf.getn(buf1, 28); - - ULONG pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text1[0], (ULONG)text1.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(len1, pcbWritten); + template + void IStreamTest5() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); - // We close the stream buffer before enough bytes have been written. + std::string text1 = "This is a test"; + size_t len1 = text1.size(); - rbuf.close().get(); + char buf1[128]; + memset(buf1, 0, sizeof(buf1)); - VERIFY_ARE_EQUAL(len1, read1.get()); - VERIFY_ARE_EQUAL(len1, strlen((char*)buf1)); - VERIFY_ARE_EQUAL(0, strcmp("This is a test", (char*)buf1)); -} + // The read happens before the write. -TEST(membuf_IStreamTest5) -{ - IStreamTest5>(); -} + auto read1 = rbuf.getn(buf1, 28); -template -void IStreamTest6() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + ULONG pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text1[0], (ULONG)text1.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(len1, pcbWritten); - std::string text1 = "abcdefghijklmnopqrstuvwxyz"; - size_t len1 = text1.size(); + // We close the stream buffer before enough bytes have been written. - ULONG pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text1[0], (ULONG)text1.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(len1, pcbWritten); + rbuf.close().get(); - bool validated = true; - for ( int expected = 'a'; expected <= 'z'; expected++) - { - validated = validated && (expected == rbuf.bumpc().get()); + VERIFY_ARE_EQUAL(len1, read1.get()); + VERIFY_ARE_EQUAL(len1, strlen((char*)buf1)); + VERIFY_ARE_EQUAL(0, strcmp("This is a test", (char*)buf1)); } - VERIFY_IS_TRUE(validated); - rbuf.close().get(); -} + TEST(membuf_IStreamTest5) { IStreamTest5>(); } -TEST(membuf_IStreamTest6) -{ - IStreamTest6>(); -} + template + void IStreamTest6() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); -template -void IStreamTest7() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + std::string text1 = "abcdefghijklmnopqrstuvwxyz"; + size_t len1 = text1.size(); - std::vector> reads; + ULONG pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text1[0], (ULONG)text1.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(len1, pcbWritten); - for ( int i = 0; i < 26; i++ ) - { - reads.push_back(rbuf.bumpc()); - } + bool validated = true; + for (int expected = 'a'; expected <= 'z'; expected++) + { + validated = validated && (expected == rbuf.bumpc().get()); + } - std::string text1 = "abcdefghijklmnopqrstuvwxyz"; - size_t len1 = text1.size(); + VERIFY_IS_TRUE(validated); + rbuf.close().get(); + } - ULONG pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text1[0], (ULONG)text1.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(len1, pcbWritten); + TEST(membuf_IStreamTest6) { IStreamTest6>(); } - bool validated = true; - for ( int i = 0; i < 26; i++ ) + template + void IStreamTest7() { - int expected = 'a'+i; - validated = validated && (expected == reads[i].get()); + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); + + std::vector> reads; + + for (int i = 0; i < 26; i++) + { + reads.push_back(rbuf.bumpc()); + } + + std::string text1 = "abcdefghijklmnopqrstuvwxyz"; + size_t len1 = text1.size(); + + ULONG pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text1[0], (ULONG)text1.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(len1, pcbWritten); + + bool validated = true; + for (int i = 0; i < 26; i++) + { + int expected = 'a' + i; + validated = validated && (expected == reads[i].get()); + } + + VERIFY_IS_TRUE(validated); + rbuf.close().get(); } - - VERIFY_IS_TRUE(validated); - rbuf.close().get(); -} -TEST(membuf_IStreamTest7) -{ - IStreamTest7>(); -} + TEST(membuf_IStreamTest7) { IStreamTest7>(); } -template -void IStreamTest8() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + template + void IStreamTest8() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); - std::string text1 = "This is a test"; - size_t len1 = text1.size(); + std::string text1 = "This is a test"; + size_t len1 = text1.size(); - char buf1[128]; - memset(buf1, 0, sizeof(buf1)); - - // The read happens before the write. + char buf1[128]; + memset(buf1, 0, sizeof(buf1)); - auto read1 = rbuf.getn(buf1, 28); - auto read2 = rbuf.getn(buf1, 8); + // The read happens before the write. - ULONG pcbWritten = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Write((const void *)&text1[0], (ULONG)text1.size(), &pcbWritten)); - VERIFY_ARE_EQUAL(len1, pcbWritten); + auto read1 = rbuf.getn(buf1, 28); + auto read2 = rbuf.getn(buf1, 8); - // We close the stream buffer before enough bytes have been written. - // Make sure that the first read results in fewer bytes than requested - // and that the second read returns -1. + ULONG pcbWritten = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Write((const void*)&text1[0], (ULONG)text1.size(), &pcbWritten)); + VERIFY_ARE_EQUAL(len1, pcbWritten); - rbuf.close(std::ios_base::out).get(); + // We close the stream buffer before enough bytes have been written. + // Make sure that the first read results in fewer bytes than requested + // and that the second read returns -1. - VERIFY_ARE_EQUAL(len1, read1.get()); - VERIFY_ARE_EQUAL(-0, (int)read2.get()); - VERIFY_ARE_EQUAL(len1, strlen((char*)buf1)); - VERIFY_ARE_EQUAL(0, strcmp("This is a test", (char*)buf1)); -} + rbuf.close(std::ios_base::out).get(); -TEST(membuf_IStreamTest8) -{ - IStreamTest8>(); -} + VERIFY_ARE_EQUAL(len1, read1.get()); + VERIFY_ARE_EQUAL(-0, (int)read2.get()); + VERIFY_ARE_EQUAL(len1, strlen((char*)buf1)); + VERIFY_ARE_EQUAL(0, strcmp("This is a test", (char*)buf1)); + } -template -void IStreamTest9() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + TEST(membuf_IStreamTest8) { IStreamTest8>(); } - VERIFY_ARE_EQUAL((int)'a', rbuf.putc('a').get()); - VERIFY_ARE_EQUAL((int)'n', rbuf.putc('n').get()); - VERIFY_ARE_EQUAL((int)'q', rbuf.putc('q').get()); - VERIFY_ARE_EQUAL((int)'s', rbuf.putc('s').get()); + template + void IStreamTest9() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); - VERIFY_ARE_EQUAL(4u, rbuf.in_avail()); + VERIFY_ARE_EQUAL((int)'a', rbuf.putc('a').get()); + VERIFY_ARE_EQUAL((int)'n', rbuf.putc('n').get()); + VERIFY_ARE_EQUAL((int)'q', rbuf.putc('q').get()); + VERIFY_ARE_EQUAL((int)'s', rbuf.putc('s').get()); - std::string chars(32, '\0'); - ULONG pcbRead = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], 4, &pcbRead)); - VERIFY_ARE_EQUAL(4u, pcbRead); + VERIFY_ARE_EQUAL(4u, rbuf.in_avail()); - VERIFY_ARE_EQUAL("anqs", chars.c_str()); + std::string chars(32, '\0'); + ULONG pcbRead = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], 4, &pcbRead)); + VERIFY_ARE_EQUAL(4u, pcbRead); - rbuf.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + VERIFY_ARE_EQUAL("anqs", chars.c_str()); -TEST(membuf_IStreamTest9) -{ - IStreamTest9>(); -} + rbuf.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); + } -template -void IStreamTest10() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + TEST(membuf_IStreamTest9) { IStreamTest9>(); } - std::string text(128, '\0'); - strcpy_s(&text[0], 128, "This is a test"); - size_t len1 = strlen(&text[0]); + template + void IStreamTest10() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); - VERIFY_ARE_EQUAL(len1, rbuf.putn_nocopy(&text[0], len1).get()); + std::string text(128, '\0'); + strcpy_s(&text[0], 128, "This is a test"); + size_t len1 = strlen(&text[0]); - strcpy_s(&text[0], 128, " - but this is not"); - size_t len2 = strlen(&text[0]); + VERIFY_ARE_EQUAL(len1, rbuf.putn_nocopy(&text[0], len1).get()); - VERIFY_ARE_EQUAL(len2, rbuf.putn_nocopy(&text[0], len2).get()); + strcpy_s(&text[0], 128, " - but this is not"); + size_t len2 = strlen(&text[0]); - VERIFY_ARE_EQUAL(len1+len2, rbuf.in_avail()); + VERIFY_ARE_EQUAL(len2, rbuf.putn_nocopy(&text[0], len2).get()); - std::string chars(128, '\0'); - size_t was_available = rbuf.in_avail(); - ULONG pcbRead = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], (ULONG)was_available, &pcbRead)); - VERIFY_ARE_EQUAL(was_available, pcbRead); + VERIFY_ARE_EQUAL(len1 + len2, rbuf.in_avail()); - VERIFY_ARE_EQUAL("This is a test - but this is not", chars.c_str()); + std::string chars(128, '\0'); + size_t was_available = rbuf.in_avail(); + ULONG pcbRead = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], (ULONG)was_available, &pcbRead)); + VERIFY_ARE_EQUAL(was_available, pcbRead); - rbuf.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + VERIFY_ARE_EQUAL("This is a test - but this is not", chars.c_str()); -TEST(membuf_IStreamTest10) -{ - IStreamTest10>(); -} + rbuf.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); + } -template -void IStreamTest11() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + TEST(membuf_IStreamTest10) { IStreamTest10>(); } - char ch = 'a'; + template + void IStreamTest11() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); - auto seg2 = [&ch](int val) { return (val != -1) && (++ch <= 'z'); }; - auto seg1 = [=,&ch,&rbuf]() { return rbuf.putc(ch).then(seg2); }; + char ch = 'a'; - pplx::details::_do_while(seg1).wait(); + auto seg2 = [&ch](int val) { return (val != -1) && (++ch <= 'z'); }; + auto seg1 = [=, &ch, &rbuf]() { return rbuf.putc(ch).then(seg2); }; - VERIFY_ARE_EQUAL(26u, rbuf.in_avail()); + pplx::details::_do_while(seg1).wait(); - std::string chars(128, '\0'); - size_t was_available = rbuf.in_avail(); - ULONG pcbRead = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], (ULONG)was_available, &pcbRead)); - VERIFY_ARE_EQUAL(was_available, pcbRead); + VERIFY_ARE_EQUAL(26u, rbuf.in_avail()); - VERIFY_ARE_EQUAL("abcdefghijklmnopqrstuvwxyz", chars.c_str()); + std::string chars(128, '\0'); + size_t was_available = rbuf.in_avail(); + ULONG pcbRead = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], (ULONG)was_available, &pcbRead)); + VERIFY_ARE_EQUAL(was_available, pcbRead); - rbuf.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + VERIFY_ARE_EQUAL("abcdefghijklmnopqrstuvwxyz", chars.c_str()); -TEST(membuf_IStreamTest11) -{ - IStreamTest11>(); -} + rbuf.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); + } -template -void IStreamTest12() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + TEST(membuf_IStreamTest11) { IStreamTest11>(); } - std::string text(128, '\0'); - strcpy_s(&text[0], 128, "This is a test"); - size_t len1 = strlen(&text[0]); + template + void IStreamTest12() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); - VERIFY_ARE_EQUAL(len1, rbuf.putn_nocopy(&text[0], len1).get()); + std::string text(128, '\0'); + strcpy_s(&text[0], 128, "This is a test"); + size_t len1 = strlen(&text[0]); - strcpy_s(&text[0], 128, " - but this is not"); - size_t len2 = strlen(&text[0]); + VERIFY_ARE_EQUAL(len1, rbuf.putn_nocopy(&text[0], len1).get()); - VERIFY_ARE_EQUAL(len2, rbuf.putn_nocopy(&text[0], len2).get()); + strcpy_s(&text[0], 128, " - but this is not"); + size_t len2 = strlen(&text[0]); - VERIFY_ARE_EQUAL(len1+len2, rbuf.in_avail()); + VERIFY_ARE_EQUAL(len2, rbuf.putn_nocopy(&text[0], len2).get()); - std::string chars(128, '\0'); - size_t was_available = rbuf.in_avail(); - ULONG pcbRead = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], (ULONG)was_available, &pcbRead)); - VERIFY_ARE_EQUAL(was_available, pcbRead); + VERIFY_ARE_EQUAL(len1 + len2, rbuf.in_avail()); - VERIFY_ARE_EQUAL("This is a test - but this is not", chars.c_str()); + std::string chars(128, '\0'); + size_t was_available = rbuf.in_avail(); + ULONG pcbRead = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], (ULONG)was_available, &pcbRead)); + VERIFY_ARE_EQUAL(was_available, pcbRead); - rbuf.close().get(); - VERIFY_IS_FALSE(rbuf.is_open()); -} + VERIFY_ARE_EQUAL("This is a test - but this is not", chars.c_str()); -TEST(membuf_IStreamTest12) -{ - IStreamTest12>(); -} + rbuf.close().get(); + VERIFY_IS_FALSE(rbuf.is_open()); + } -template -void IStreamTest13() -{ - _StreamBufferType rbuf; - ISequentialStream_bridge stream(rbuf); + TEST(membuf_IStreamTest12) { IStreamTest12>(); } - streams::basic_ostream os(rbuf); + template + void IStreamTest13() + { + _StreamBufferType rbuf; + ISequentialStream_bridge stream(rbuf); - auto a = os.print("This is a test"); - auto b = os.print(" "); - auto c = os.print("- but this is not"); - (a && b && c).wait(); + streams::basic_ostream os(rbuf); - VERIFY_ARE_EQUAL(32u, rbuf.in_avail()); + auto a = os.print("This is a test"); + auto b = os.print(" "); + auto c = os.print("- but this is not"); + (a && b && c).wait(); - std::string chars(128, '\0'); - size_t was_available = rbuf.in_avail(); - ULONG pcbRead = 0; - VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], (ULONG)was_available, &pcbRead)); - VERIFY_ARE_EQUAL(was_available, pcbRead); + VERIFY_ARE_EQUAL(32u, rbuf.in_avail()); - VERIFY_ARE_EQUAL("This is a test - but this is not", chars.c_str()); + std::string chars(128, '\0'); + size_t was_available = rbuf.in_avail(); + ULONG pcbRead = 0; + VERIFY_ARE_EQUAL(S_OK, stream.Read(&chars[0], (ULONG)was_available, &pcbRead)); + VERIFY_ARE_EQUAL(was_available, pcbRead); - os.close().get(); + VERIFY_ARE_EQUAL("This is a test - but this is not", chars.c_str()); - // The read end should still be open - VERIFY_IS_TRUE(rbuf.is_open()); + os.close().get(); - // close the read end - rbuf.close(std::ios_base::in).get(); + // The read end should still be open + VERIFY_IS_TRUE(rbuf.is_open()); - // Now the buffer should no longer be open - VERIFY_IS_FALSE(rbuf.is_open()); -} + // close the read end + rbuf.close(std::ios_base::in).get(); -TEST(membuf_IStreamTest13) -{ - IStreamTest13>(); -} + // Now the buffer should no longer be open + VERIFY_IS_FALSE(rbuf.is_open()); + } + + TEST(membuf_IStreamTest13) { IStreamTest13>(); } #endif -TEST(producer_consumer_buffer_flush_1) -{ - streams::producer_consumer_buffer rwbuf; + TEST(producer_consumer_buffer_flush_1) + { + streams::producer_consumer_buffer rwbuf; - VERIFY_IS_TRUE(rwbuf.is_open()); - VERIFY_IS_TRUE(rwbuf.can_read()); - VERIFY_IS_TRUE(rwbuf.can_write()); + VERIFY_IS_TRUE(rwbuf.is_open()); + VERIFY_IS_TRUE(rwbuf.can_read()); + VERIFY_IS_TRUE(rwbuf.can_write()); - char buf1[128], buf2[128]; - memset(buf1, 0, sizeof(buf1)); - memset(buf2, 0, sizeof(buf2)); - - // The read happens before the write. + char buf1[128], buf2[128]; + memset(buf1, 0, sizeof(buf1)); + memset(buf2, 0, sizeof(buf2)); - auto read1 = rwbuf.getn(buf1, 128); - auto read2 = rwbuf.getn(buf2, 128); + // The read happens before the write. - std::string text1 = "This is a test"; - size_t len1 = text1.size(); - VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text1[0], len1).get(), len1); - rwbuf.sync().wait(); + auto read1 = rwbuf.getn(buf1, 128); + auto read2 = rwbuf.getn(buf2, 128); - std::string text2 = "- but this is not"; - size_t len2 = text2.size(); - VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text2[0], len2).get(), len2); - rwbuf.sync().wait(); + std::string text1 = "This is a test"; + size_t len1 = text1.size(); + VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text1[0], len1).get(), len1); + rwbuf.sync().wait(); - VERIFY_ARE_EQUAL(read1.get(), len1); - VERIFY_ARE_EQUAL(read2.get(), len2); + std::string text2 = "- but this is not"; + size_t len2 = text2.size(); + VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text2[0], len2).get(), len2); + rwbuf.sync().wait(); - rwbuf.close().get(); -} + VERIFY_ARE_EQUAL(read1.get(), len1); + VERIFY_ARE_EQUAL(read2.get(), len2); -TEST(producer_consumer_buffer_flush_2) -{ - streams::producer_consumer_buffer rwbuf; + rwbuf.close().get(); + } - VERIFY_IS_TRUE(rwbuf.is_open()); - VERIFY_IS_TRUE(rwbuf.can_read()); - VERIFY_IS_TRUE(rwbuf.can_write()); + TEST(producer_consumer_buffer_flush_2) + { + streams::producer_consumer_buffer rwbuf; - // The read happens after the write. + VERIFY_IS_TRUE(rwbuf.is_open()); + VERIFY_IS_TRUE(rwbuf.can_read()); + VERIFY_IS_TRUE(rwbuf.can_write()); - std::string text1 = "This is a test"; - std::string text2 = "- but this is not"; - size_t len1 = text1.size(); - size_t len2 = text2.size(); - VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text1[0], len1).get(), len1); - VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text2[0], len2).get(), len2); - rwbuf.sync().wait(); + // The read happens after the write. - char buf1[128], buf2[128]; - memset(buf1, 0, sizeof(buf1)); - memset(buf2, 0, sizeof(buf2)); - - auto read1 = rwbuf.getn(buf1, 128); + std::string text1 = "This is a test"; + std::string text2 = "- but this is not"; + size_t len1 = text1.size(); + size_t len2 = text2.size(); + VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text1[0], len1).get(), len1); + VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text2[0], len2).get(), len2); + rwbuf.sync().wait(); - VERIFY_ARE_EQUAL(read1.get(), len1+len2); + char buf1[128], buf2[128]; + memset(buf1, 0, sizeof(buf1)); + memset(buf2, 0, sizeof(buf2)); - rwbuf.close().get(); -} + auto read1 = rwbuf.getn(buf1, 128); -TEST(producer_consumer_buffer_flush_3) -{ - streams::producer_consumer_buffer rwbuf; + VERIFY_ARE_EQUAL(read1.get(), len1 + len2); - VERIFY_IS_TRUE(rwbuf.is_open()); - VERIFY_IS_TRUE(rwbuf.can_read()); - VERIFY_IS_TRUE(rwbuf.can_write()); + rwbuf.close().get(); + } - // The read happens before the write. + TEST(producer_consumer_buffer_flush_3) + { + streams::producer_consumer_buffer rwbuf; - char buf1[128], buf2[128]; - memset(buf1, 0, sizeof(buf1)); - memset(buf2, 0, sizeof(buf2)); - - auto read1 = rwbuf.getn(buf1, 128); - auto read2 = rwbuf.getn(buf2, 128); + VERIFY_IS_TRUE(rwbuf.is_open()); + VERIFY_IS_TRUE(rwbuf.can_read()); + VERIFY_IS_TRUE(rwbuf.can_write()); - for (char c = 'a'; c <= 'z'; ++c) - rwbuf.putc(c); - rwbuf.sync().wait(); - for (char c = 'a'; c <= 'z'; ++c) - rwbuf.putc(c); + // The read happens before the write. - VERIFY_ARE_EQUAL(read1.get(), 26); + char buf1[128], buf2[128]; + memset(buf1, 0, sizeof(buf1)); + memset(buf2, 0, sizeof(buf2)); - rwbuf.close().get(); + auto read1 = rwbuf.getn(buf1, 128); + auto read2 = rwbuf.getn(buf2, 128); - VERIFY_ARE_EQUAL(read2.get(), 26); -} + for (char c = 'a'; c <= 'z'; ++c) + rwbuf.putc(c); + rwbuf.sync().wait(); + for (char c = 'a'; c <= 'z'; ++c) + rwbuf.putc(c); -TEST(producer_consumer_buffer_flush_4) -{ - streams::producer_consumer_buffer rwbuf; + VERIFY_ARE_EQUAL(read1.get(), 26); - VERIFY_IS_TRUE(rwbuf.is_open()); - VERIFY_IS_TRUE(rwbuf.can_read()); - VERIFY_IS_TRUE(rwbuf.can_write()); + rwbuf.close().get(); - // The read happens after the write. + VERIFY_ARE_EQUAL(read2.get(), 26); + } - for (char c = 'a'; c <= 'z'; ++c) - rwbuf.putc(c); - rwbuf.sync().wait(); + TEST(producer_consumer_buffer_flush_4) + { + streams::producer_consumer_buffer rwbuf; - char buf1[128], buf2[128]; - memset(buf1, 0, sizeof(buf1)); - memset(buf2, 0, sizeof(buf2)); - - auto read1 = rwbuf.getn(buf1, 20); - auto read2 = rwbuf.getn(buf1, 128); + VERIFY_IS_TRUE(rwbuf.is_open()); + VERIFY_IS_TRUE(rwbuf.can_read()); + VERIFY_IS_TRUE(rwbuf.can_write()); - VERIFY_ARE_EQUAL(read1.get(), 20); - VERIFY_ARE_EQUAL(read2.get(), 6); + // The read happens after the write. - rwbuf.close().get(); -} + for (char c = 'a'; c <= 'z'; ++c) + rwbuf.putc(c); + rwbuf.sync().wait(); -TEST(producer_consumer_buffer_flush_5) -{ - streams::producer_consumer_buffer rwbuf; + char buf1[128], buf2[128]; + memset(buf1, 0, sizeof(buf1)); + memset(buf2, 0, sizeof(buf2)); - VERIFY_IS_TRUE(rwbuf.is_open()); - VERIFY_IS_TRUE(rwbuf.can_read()); - VERIFY_IS_TRUE(rwbuf.can_write()); + auto read1 = rwbuf.getn(buf1, 20); + auto read2 = rwbuf.getn(buf1, 128); - // The read happens before the write. + VERIFY_ARE_EQUAL(read1.get(), 20); + VERIFY_ARE_EQUAL(read2.get(), 6); - pplx::task buf1[128]; + rwbuf.close().get(); + } - for (int i = 0; i < 128; ++i) + TEST(producer_consumer_buffer_flush_5) { - buf1[i] = rwbuf.bumpc(); - } + streams::producer_consumer_buffer rwbuf; + + VERIFY_IS_TRUE(rwbuf.is_open()); + VERIFY_IS_TRUE(rwbuf.can_read()); + VERIFY_IS_TRUE(rwbuf.can_write()); - for (char c = 'a'; c <= 'z'; ++c) - rwbuf.putc(c); - rwbuf.sync().wait(); + // The read happens before the write. - for (int i = 0; i < 26; ++i) - { - VERIFY_ARE_EQUAL('a'+i,buf1[i].get()); + pplx::task buf1[128]; + + for (int i = 0; i < 128; ++i) + { + buf1[i] = rwbuf.bumpc(); + } + + for (char c = 'a'; c <= 'z'; ++c) + rwbuf.putc(c); + rwbuf.sync().wait(); + + for (int i = 0; i < 26; ++i) + { + VERIFY_ARE_EQUAL('a' + i, buf1[i].get()); + } + for (int i = 26; i < 128; ++i) + { + VERIFY_IS_FALSE(buf1[i].is_done()); + } + rwbuf.close().get(); } - for (int i = 26; i < 128; ++i) + + TEST(producer_consumer_buffer_flush_6) { - VERIFY_IS_FALSE(buf1[i].is_done()); - } - rwbuf.close().get(); -} + streams::producer_consumer_buffer rwbuf; -TEST(producer_consumer_buffer_flush_6) -{ - streams::producer_consumer_buffer rwbuf; + VERIFY_IS_TRUE(rwbuf.is_open()); + VERIFY_IS_TRUE(rwbuf.can_read()); + VERIFY_IS_TRUE(rwbuf.can_write()); - VERIFY_IS_TRUE(rwbuf.is_open()); - VERIFY_IS_TRUE(rwbuf.can_read()); - VERIFY_IS_TRUE(rwbuf.can_write()); + // The read happens after the write. - // The read happens after the write. + for (char c = 'a'; c <= 'z'; ++c) + rwbuf.putc(c); + rwbuf.sync().wait(); - for (char c = 'a'; c <= 'z'; ++c) - rwbuf.putc(c); - rwbuf.sync().wait(); + pplx::task buf1[128]; - pplx::task buf1[128]; + for (int i = 0; i < 128; ++i) + { + buf1[i] = rwbuf.bumpc(); + } - for (int i = 0; i < 128; ++i) - { - buf1[i] = rwbuf.bumpc(); + for (int i = 0; i < 26; ++i) + { + VERIFY_IS_TRUE(buf1[i].is_done()); + } + for (int i = 26; i < 128; ++i) + { + VERIFY_IS_FALSE(buf1[i].is_done()); + } + rwbuf.close().get(); } - for (int i = 0; i < 26; ++i) + TEST(producer_consumer_buffer_close_reader_early) { - VERIFY_IS_TRUE(buf1[i].is_done()); - } - for (int i = 26; i < 128; ++i) - { - VERIFY_IS_FALSE(buf1[i].is_done()); - } - rwbuf.close().get(); -} + streams::producer_consumer_buffer rwbuf; -TEST(producer_consumer_buffer_close_reader_early) -{ - streams::producer_consumer_buffer rwbuf; + VERIFY_IS_TRUE(rwbuf.is_open()); + VERIFY_IS_TRUE(rwbuf.can_read()); + VERIFY_IS_TRUE(rwbuf.can_write()); - VERIFY_IS_TRUE(rwbuf.is_open()); - VERIFY_IS_TRUE(rwbuf.can_read()); - VERIFY_IS_TRUE(rwbuf.can_write()); + rwbuf.close(std::ios::in).wait(); - rwbuf.close(std::ios::in).wait(); + // Even though we have closed for read, we should + // still be able to write. - // Even though we have closed for read, we should - // still be able to write. + auto size = rwbuf.in_avail(); - auto size = rwbuf.in_avail(); + for (char c = 'a'; c <= 'z'; ++c) + VERIFY_ARE_EQUAL((int)c, rwbuf.putc(c).get()); - for (char c = 'a'; c <= 'z'; ++c) - VERIFY_ARE_EQUAL((int)c, rwbuf.putc(c).get()); + VERIFY_ARE_EQUAL(size, rwbuf.in_avail()); - VERIFY_ARE_EQUAL(size, rwbuf.in_avail()); + std::string text1 = "This is a test"; + size_t len1 = text1.size(); + VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text1[0], len1).get(), len1); - std::string text1 = "This is a test"; - size_t len1 = text1.size(); - VERIFY_ARE_EQUAL(rwbuf.putn_nocopy(&text1[0], len1).get(), len1); + VERIFY_ARE_EQUAL(size, rwbuf.in_avail()); - VERIFY_ARE_EQUAL(size, rwbuf.in_avail()); + rwbuf.close().get(); + } - rwbuf.close().get(); -} + TEST(container_buffer_exception_propagation) + { + struct MyException + { + }; + { + streams::stringstreambuf rwbuf(std::string("this is the test")); + rwbuf.close(std::ios::out, std::make_exception_ptr(MyException())).wait(); + char buffer[100]; + VERIFY_ARE_EQUAL(rwbuf.getn(buffer, 100).get(), 16); + VERIFY_THROWS(rwbuf.getn(buffer, 100).get(), MyException); + VERIFY_THROWS(rwbuf.getc().get(), MyException); + VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + } + { + streams::stringstreambuf rwbuf(std::string("this is the test")); + rwbuf.close(std::ios::in, std::make_exception_ptr(MyException())); + char buffer[100]; + VERIFY_THROWS(rwbuf.getn(buffer, 100).get(), MyException); + VERIFY_THROWS(rwbuf.getc().get(), MyException); + VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + } + { + streams::stringstreambuf rwbuf; + rwbuf.putn_nocopy("this is the test", 16); + rwbuf.close(std::ios::out, std::make_exception_ptr(MyException())); + VERIFY_THROWS(rwbuf.putn_nocopy("this is the test", 16).get(), MyException); + VERIFY_THROWS(rwbuf.putc('c').get(), MyException); + VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + } + } -TEST(container_buffer_exception_propagation) -{ - struct MyException {}; + TEST(producer_consumer_buffer_exception_propagation) { - streams::stringstreambuf rwbuf(std::string("this is the test")); - rwbuf.close(std::ios::out, std::make_exception_ptr(MyException())).wait(); - char buffer[100]; - VERIFY_ARE_EQUAL(rwbuf.getn(buffer, 100).get(), 16); - VERIFY_THROWS(rwbuf.getn(buffer, 100).get(), MyException); - VERIFY_THROWS(rwbuf.getc().get(), MyException); - VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + struct MyException + { + }; + { + streams::producer_consumer_buffer rwbuf; + rwbuf.putn_nocopy("this is the test", 16); + rwbuf.close(std::ios::out, std::make_exception_ptr(MyException())); + char buffer[100]; + VERIFY_ARE_EQUAL(rwbuf.getn(buffer, 100).get(), 16); + VERIFY_THROWS(rwbuf.getn(buffer, 100).get(), MyException); + VERIFY_THROWS(rwbuf.getc().get(), MyException); + VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + } + { + streams::producer_consumer_buffer rwbuf; + rwbuf.putn_nocopy("this is the test", 16); + rwbuf.close(std::ios::in, std::make_exception_ptr(MyException())); + char buffer[100]; + VERIFY_THROWS(rwbuf.getn(buffer, 100).get(), MyException); + VERIFY_THROWS(rwbuf.getc().get(), MyException); + VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + } + + { + streams::producer_consumer_buffer rwbuf; + rwbuf.putn_nocopy("this is the test", 16); + rwbuf.close(std::ios::out, std::make_exception_ptr(MyException())); + VERIFY_THROWS(rwbuf.putn_nocopy("this is the test", 16).get(), MyException); + VERIFY_THROWS(rwbuf.putc('c').get(), MyException); + VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + } } + + TEST(producer_consumer_alloc_after_close) { - streams::stringstreambuf rwbuf(std::string("this is the test")); - rwbuf.close(std::ios::in, std::make_exception_ptr(MyException())); - char buffer[100]; - VERIFY_THROWS(rwbuf.getn(buffer, 100).get(), MyException); - VERIFY_THROWS(rwbuf.getc().get(), MyException); - VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + producer_consumer_buffer buffer; + buffer.close().wait(); + VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); + + buffer = producer_consumer_buffer(); + buffer.close(std::ios::out); + VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); } + TEST(producer_consumer_acquire_after_close) { - streams::stringstreambuf rwbuf; - rwbuf.putn_nocopy("this is the test", 16); - rwbuf.close(std::ios::out, std::make_exception_ptr(MyException())); - VERIFY_THROWS(rwbuf.putn_nocopy("this is the test", 16).get(), MyException); - VERIFY_THROWS(rwbuf.putc('c').get(), MyException); - VERIFY_IS_FALSE(rwbuf.exception() == nullptr); - } + char* temp = nullptr; + size_t size = 0; + producer_consumer_buffer buffer; + buffer.close().wait(); + VERIFY_IS_FALSE(buffer.acquire(temp, size)); + VERIFY_IS_TRUE(nullptr == temp); + VERIFY_ARE_EQUAL(0, size); + buffer.release(temp, size); -} + buffer = producer_consumer_buffer(); + buffer.close(std::ios::out); + temp = (char*)1; + size = 1; + VERIFY_IS_TRUE(buffer.acquire(temp, size)); + VERIFY_IS_TRUE(nullptr == temp); + VERIFY_ARE_EQUAL(0, size); + buffer.release(temp, size); + } -TEST(producer_consumer_buffer_exception_propagation) -{ - struct MyException {}; + TEST(create_buffers_inout_error) { - streams::producer_consumer_buffer rwbuf; - rwbuf.putn_nocopy("this is the test", 16); - rwbuf.close(std::ios::out, std::make_exception_ptr(MyException())); - char buffer[100]; - VERIFY_ARE_EQUAL(rwbuf.getn(buffer, 100).get(), 16); - VERIFY_THROWS(rwbuf.getn(buffer, 100).get(), MyException); - VERIFY_THROWS(rwbuf.getc().get(), MyException); - VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + VERIFY_THROWS(container_buffer(std::ios::in | std::ios::out), std::invalid_argument); + VERIFY_THROWS(container_buffer("test data", std::ios::in | std::ios::out), std::invalid_argument); + char* data = nullptr; + VERIFY_THROWS(rawptr_buffer(data, 2, std::ios::in | std::ios::out), std::invalid_argument); } + + TEST(memstream_length) { - streams::producer_consumer_buffer rwbuf; - rwbuf.putn_nocopy("this is the test", 16); - rwbuf.close(std::ios::in, std::make_exception_ptr(MyException())); - char buffer[100]; - VERIFY_THROWS(rwbuf.getn(buffer, 100).get(), MyException); - VERIFY_THROWS(rwbuf.getc().get(), MyException); - VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + producer_consumer_buffer rbuf; + auto istr = rbuf.create_istream(); + + auto curr = istr.tell(); + VERIFY_ARE_EQUAL((long long)curr, 0); } + TEST(buffer_size) { - streams::producer_consumer_buffer rwbuf; - rwbuf.putn_nocopy("this is the test", 16); - rwbuf.close(std::ios::out, std::make_exception_ptr(MyException())); - VERIFY_THROWS(rwbuf.putn_nocopy("this is the test", 16).get(), MyException); - VERIFY_THROWS(rwbuf.putc('c').get(), MyException); - VERIFY_IS_FALSE(rwbuf.exception() == nullptr); + { + container_buffer buf("test data"); + VERIFY_IS_TRUE(buf.has_size()); + VERIFY_ARE_EQUAL(buf.size(), 9); + buf.seekoff(1024, std::ios::beg, std::ios::in); + VERIFY_ARE_EQUAL(buf.size(), 9); + } + { + container_buffer buf; + VERIFY_IS_TRUE(buf.has_size()); + VERIFY_ARE_EQUAL(buf.size(), 0); + buf.seekoff(1024, std::ios::beg, std::ios::out); + VERIFY_ARE_EQUAL(buf.size(), 1024); + VERIFY_ARE_EQUAL(buf.collection().size(), 1024); + } + { + producer_consumer_buffer buf; + VERIFY_IS_FALSE(buf.has_size()); + VERIFY_ARE_EQUAL(buf.size(), 0); + } } -} - -TEST(producer_consumer_alloc_after_close) -{ - producer_consumer_buffer buffer; - buffer.close().wait(); - VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); - - buffer = producer_consumer_buffer(); - buffer.close(std::ios::out); - VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); -} - -TEST(producer_consumer_acquire_after_close) -{ - char *temp = nullptr; - size_t size = 0; - producer_consumer_buffer buffer; - buffer.close().wait(); - VERIFY_IS_FALSE(buffer.acquire(temp, size)); - VERIFY_IS_TRUE(nullptr == temp); - VERIFY_ARE_EQUAL(0, size); - buffer.release(temp, size); - - buffer = producer_consumer_buffer(); - buffer.close(std::ios::out); - temp = (char *)1; - size = 1; - VERIFY_IS_TRUE(buffer.acquire(temp, size)); - VERIFY_IS_TRUE(nullptr == temp); - VERIFY_ARE_EQUAL(0, size); - buffer.release(temp, size); -} -TEST(create_buffers_inout_error) -{ - VERIFY_THROWS(container_buffer(std::ios::in | std::ios::out), std::invalid_argument); - VERIFY_THROWS(container_buffer("test data", std::ios::in | std::ios::out), std::invalid_argument); - char *data = nullptr; - VERIFY_THROWS(rawptr_buffer(data, 2, std::ios::in | std::ios::out), std::invalid_argument); -} - -TEST(memstream_length) -{ - producer_consumer_buffer rbuf; - auto istr = rbuf.create_istream(); - - auto curr = istr.tell(); - VERIFY_ARE_EQUAL((long long)curr, 0); -} - -TEST(buffer_size) -{ + TEST(rawptr_alloc_after_close) { - container_buffer buf("test data"); - VERIFY_IS_TRUE(buf.has_size()); - VERIFY_ARE_EQUAL(buf.size(), 9); - buf.seekoff(1024, std::ios::beg, std::ios::in); - VERIFY_ARE_EQUAL(buf.size(), 9); + char data[2]; + rawptr_buffer buffer(&data[0], sizeof(data), std::ios::out); + buffer.close().wait(); + VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); + + buffer = rawptr_buffer(&data[0], sizeof(data), std::ios::out); + buffer.close(std::ios::out); + VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); } + + TEST(rawptr_alloc_too_large) { - container_buffer buf; - VERIFY_IS_TRUE(buf.has_size()); - VERIFY_ARE_EQUAL(buf.size(), 0); - buf.seekoff(1024, std::ios::beg, std::ios::out); - VERIFY_ARE_EQUAL(buf.size(), 1024); - VERIFY_ARE_EQUAL(buf.collection().size(), 1024); + char data[4]; + rawptr_buffer buffer(&data[0], sizeof(data), std::ios::out); + VERIFY_IS_TRUE(buffer.alloc(10) == nullptr); } + + TEST(rawptr_buffer_acquire_after_close) { - producer_consumer_buffer buf; - VERIFY_IS_FALSE(buf.has_size()); - VERIFY_ARE_EQUAL(buf.size(), 0); + char* temp = nullptr; + size_t size = 0; + char data[2]; + rawptr_buffer buffer(&data[0], sizeof(data), std::ios::in); + buffer.close().wait(); + VERIFY_IS_FALSE(buffer.acquire(temp, size)); + VERIFY_IS_TRUE(nullptr == temp); + VERIFY_ARE_EQUAL(0, size); + buffer.release(temp, size); + + buffer = rawptr_buffer(nullptr, 0, std::ios::in); + temp = (char*)1; + size = 1; + VERIFY_IS_TRUE(buffer.acquire(temp, size)); + VERIFY_IS_TRUE(nullptr == temp); + VERIFY_ARE_EQUAL(0, size); + buffer.release(temp, size); } -} -TEST(rawptr_alloc_after_close) -{ - char data[2]; - rawptr_buffer buffer(&data[0], sizeof(data), std::ios::out); - buffer.close().wait(); - VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); - - buffer = rawptr_buffer(&data[0], sizeof(data), std::ios::out); - buffer.close(std::ios::out); - VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); -} + TEST(container_buffer_alloc_after_close) + { + container_buffer buffer; + buffer.close().wait(); + VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); -TEST(rawptr_alloc_too_large) -{ - char data[4]; - rawptr_buffer buffer(&data[0], sizeof(data), std::ios::out); - VERIFY_IS_TRUE(buffer.alloc(10) == nullptr); -} + buffer = container_buffer(); + buffer.close(std::ios::out); + VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); + } -TEST(rawptr_buffer_acquire_after_close) -{ - char *temp = nullptr; - size_t size = 0; - char data[2]; - rawptr_buffer buffer(&data[0], sizeof(data), std::ios::in); - buffer.close().wait(); - VERIFY_IS_FALSE(buffer.acquire(temp, size)); - VERIFY_IS_TRUE(nullptr == temp); - VERIFY_ARE_EQUAL(0, size); - buffer.release(temp, size); - - buffer = rawptr_buffer(nullptr, 0, std::ios::in); - temp = (char *)1; - size = 1; - VERIFY_IS_TRUE(buffer.acquire(temp, size)); - VERIFY_IS_TRUE(nullptr == temp); - VERIFY_ARE_EQUAL(0, size); - buffer.release(temp, size); -} + TEST(container_buffer_acquire_after_close) + { + char* temp = nullptr; + size_t size = 0; + container_buffer buffer("test data"); + buffer.close().wait(); + VERIFY_IS_FALSE(buffer.acquire(temp, size)); + VERIFY_IS_TRUE(nullptr == temp); + VERIFY_ARE_EQUAL(0, size); + buffer.release(temp, size); -TEST(container_buffer_alloc_after_close) -{ - container_buffer buffer; - buffer.close().wait(); - VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); + buffer = container_buffer(std::ios::in); + temp = (char*)1; + size = 1; + VERIFY_IS_TRUE(buffer.acquire(temp, size)); + VERIFY_IS_TRUE(nullptr == temp); + VERIFY_ARE_EQUAL(0, size); + buffer.release(temp, size); + } - buffer = container_buffer(); - buffer.close(std::ios::out); - VERIFY_IS_TRUE(buffer.alloc(2) == nullptr); -} + TEST(bytestream_length) + { + // test byte stream + std::string s("12345"); + auto istr = bytestream::open_istream(s); + test_stream_length(istr, s.size()); + } -TEST(container_buffer_acquire_after_close) -{ - char *temp = nullptr; - size_t size = 0; - container_buffer buffer("test data"); - buffer.close().wait(); - VERIFY_IS_FALSE(buffer.acquire(temp, size)); - VERIFY_IS_TRUE(nullptr == temp); - VERIFY_ARE_EQUAL(0, size); - buffer.release(temp, size); - - buffer = container_buffer(std::ios::in); - temp = (char *)1; - size = 1; - VERIFY_IS_TRUE(buffer.acquire(temp, size)); - VERIFY_IS_TRUE(nullptr == temp); - VERIFY_ARE_EQUAL(0, size); - buffer.release(temp, size); -} + TEST(read_pending_close_with_exception) + { + producer_consumer_buffer sourceBuf; -TEST(bytestream_length) -{ - // test byte stream - std::string s("12345"); - auto istr = bytestream::open_istream(s); - test_stream_length(istr, s.size()); -} + const size_t size = 4; + char buf[size]; + memset(&buf[0], '0', size); + auto firstRead = sourceBuf.getn(buf, size); + sourceBuf.putc('a').wait(); -TEST(read_pending_close_with_exception) -{ - producer_consumer_buffer sourceBuf; - - const size_t size = 4; - char buf[size]; - memset(&buf[0], '0', size); - auto firstRead = sourceBuf.getn(buf, size); - sourceBuf.putc('a').wait(); - - sourceBuf.close(std::ios::in | std::ios::out, std::make_exception_ptr(std::runtime_error("test exception"))).wait(); - VERIFY_ARE_EQUAL(firstRead.get(), 1); - VERIFY_ARE_EQUAL(buf[0], 'a'); - VERIFY_ARE_EQUAL(buf[1], '0'); - VERIFY_ARE_EQUAL(buf[2], '0'); - VERIFY_ARE_EQUAL(buf[3], '0'); - - VERIFY_THROWS(sourceBuf.getn(buf, size).get(), std::runtime_error); - VERIFY_ARE_EQUAL(buf[0], 'a'); - VERIFY_ARE_EQUAL(buf[1], '0'); - VERIFY_ARE_EQUAL(buf[2], '0'); - VERIFY_ARE_EQUAL(buf[3], '0'); -} + sourceBuf.close(std::ios::in | std::ios::out, std::make_exception_ptr(std::runtime_error("test exception"))) + .wait(); + VERIFY_ARE_EQUAL(firstRead.get(), 1); + VERIFY_ARE_EQUAL(buf[0], 'a'); + VERIFY_ARE_EQUAL(buf[1], '0'); + VERIFY_ARE_EQUAL(buf[2], '0'); + VERIFY_ARE_EQUAL(buf[3], '0'); -TEST(close_on_one_head_write) -{ - producer_consumer_buffer sourceBuf; - sourceBuf.putc('a').wait(); + VERIFY_THROWS(sourceBuf.getn(buf, size).get(), std::runtime_error); + VERIFY_ARE_EQUAL(buf[0], 'a'); + VERIFY_ARE_EQUAL(buf[1], '0'); + VERIFY_ARE_EQUAL(buf[2], '0'); + VERIFY_ARE_EQUAL(buf[3], '0'); + } - auto ostream = sourceBuf.create_ostream(); + TEST(close_on_one_head_write) + { + producer_consumer_buffer sourceBuf; + sourceBuf.putc('a').wait(); - ostream.close().wait(); + auto ostream = sourceBuf.create_ostream(); - // Check that the exception is generated by the 'get(),' not the operation. - auto t1 = sourceBuf.putc('b'); - auto t2 = ostream.write('b'); - VERIFY_ARE_EQUAL(t1.get(), streams::streambuf::traits::eof()); - VERIFY_THROWS(t2.get(), std::runtime_error); - VERIFY_ARE_EQUAL(sourceBuf.getc().get(), 'a'); -} + ostream.close().wait(); -TEST(close_on_one_head_read) -{ - producer_consumer_buffer sourceBuf; - sourceBuf.putc('a').wait(); + // Check that the exception is generated by the 'get(),' not the operation. + auto t1 = sourceBuf.putc('b'); + auto t2 = ostream.write('b'); + VERIFY_ARE_EQUAL(t1.get(), streams::streambuf::traits::eof()); + VERIFY_THROWS(t2.get(), std::runtime_error); + VERIFY_ARE_EQUAL(sourceBuf.getc().get(), 'a'); + } - auto istream = sourceBuf.create_istream(); + TEST(close_on_one_head_read) + { + producer_consumer_buffer sourceBuf; + sourceBuf.putc('a').wait(); - istream.close().wait(); + auto istream = sourceBuf.create_istream(); - // Check that the exception is generated by the 'get(),' not the operation. - auto t1 = sourceBuf.bumpc(); - auto t2 = istream.read(); - VERIFY_ARE_EQUAL(t1.get(), streams::streambuf::traits::eof()); - VERIFY_THROWS(t2.get(), std::runtime_error); - VERIFY_ARE_EQUAL(sourceBuf.putc('a').get(), 'a'); -} + istream.close().wait(); -TEST(close_with_exception_on_one_head_write) -{ - producer_consumer_buffer sourceBuf; - sourceBuf.putc('a').wait(); + // Check that the exception is generated by the 'get(),' not the operation. + auto t1 = sourceBuf.bumpc(); + auto t2 = istream.read(); + VERIFY_ARE_EQUAL(t1.get(), streams::streambuf::traits::eof()); + VERIFY_THROWS(t2.get(), std::runtime_error); + VERIFY_ARE_EQUAL(sourceBuf.putc('a').get(), 'a'); + } - auto ostream = sourceBuf.create_ostream(); + TEST(close_with_exception_on_one_head_write) + { + producer_consumer_buffer sourceBuf; + sourceBuf.putc('a').wait(); - ostream.close(std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); + auto ostream = sourceBuf.create_ostream(); - // Check that the exception is generated by the 'get(),' not the operation. - auto t1 = sourceBuf.putc('b'); - auto t2 = ostream.write('b'); - VERIFY_THROWS(t1.get(), std::invalid_argument); - VERIFY_THROWS(t2.get(), std::invalid_argument); - VERIFY_ARE_EQUAL(sourceBuf.getc().get(), 'a'); -} + ostream.close(std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); -TEST(close_with_exception_on_one_head_read) -{ - producer_consumer_buffer sourceBuf; - sourceBuf.putc('a').wait(); + // Check that the exception is generated by the 'get(),' not the operation. + auto t1 = sourceBuf.putc('b'); + auto t2 = ostream.write('b'); + VERIFY_THROWS(t1.get(), std::invalid_argument); + VERIFY_THROWS(t2.get(), std::invalid_argument); + VERIFY_ARE_EQUAL(sourceBuf.getc().get(), 'a'); + } - auto istream = sourceBuf.create_istream(); + TEST(close_with_exception_on_one_head_read) + { + producer_consumer_buffer sourceBuf; + sourceBuf.putc('a').wait(); - istream.close(std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); + auto istream = sourceBuf.create_istream(); - // Check that the exception is generated by the 'get(),' not the operation. - auto t1 = sourceBuf.bumpc(); - auto t2 = istream.read(); - VERIFY_THROWS(t1.get(), std::invalid_argument); - VERIFY_THROWS(t2.get(), std::invalid_argument); - VERIFY_ARE_EQUAL(sourceBuf.putc('a').get(), 'a'); -} + istream.close(std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); -TEST(close_twice) -{ - // This test passes if it does not generate an exception. - { - producer_consumer_buffer sourceBuf; - sourceBuf.close(std::ios::in).wait(); - sourceBuf.close(std::ios::in).wait(); - } - { - producer_consumer_buffer sourceBuf; - sourceBuf.close(std::ios::out).wait(); - sourceBuf.close(std::ios::out).wait(); + // Check that the exception is generated by the 'get(),' not the operation. + auto t1 = sourceBuf.bumpc(); + auto t2 = istream.read(); + VERIFY_THROWS(t1.get(), std::invalid_argument); + VERIFY_THROWS(t2.get(), std::invalid_argument); + VERIFY_ARE_EQUAL(sourceBuf.putc('a').get(), 'a'); } + + TEST(close_twice) { - producer_consumer_buffer sourceBuf; - sourceBuf.close().wait(); - sourceBuf.close().wait(); + // This test passes if it does not generate an exception. + { + producer_consumer_buffer sourceBuf; + sourceBuf.close(std::ios::in).wait(); + sourceBuf.close(std::ios::in).wait(); + } + { + producer_consumer_buffer sourceBuf; + sourceBuf.close(std::ios::out).wait(); + sourceBuf.close(std::ios::out).wait(); + } + { + producer_consumer_buffer sourceBuf; + sourceBuf.close().wait(); + sourceBuf.close().wait(); + } } } -} - -}}} +} // namespace streams +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/streams/ostream_tests.cpp b/Release/tests/functional/streams/ostream_tests.cpp index ac7a7d44d8..078337dec5 100644 --- a/Release/tests/functional/streams/ostream_tests.cpp +++ b/Release/tests/functional/streams/ostream_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests for async output stream operations. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests for async output stream operations. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace concurrency::streams; @@ -16,8 +16,12 @@ using namespace concurrency::streams; using namespace Windows::Storage; #endif -namespace tests { namespace functional { namespace streams { - +namespace tests +{ +namespace functional +{ +namespace streams +{ using namespace utility; using namespace ::pplx; @@ -29,14 +33,15 @@ using namespace ::pplx; // used in testing in the Documents folder. // template -pplx::task> OPENSTR_W(const utility::string_t &name, std::ios_base::openmode mode = std::ios_base::out) +pplx::task> OPENSTR_W(const utility::string_t& name, + std::ios_base::openmode mode = std::ios_base::out) { #if !defined(__cplusplus_winrt) return concurrency::streams::file_stream<_CharType>::open_ostream(name, mode); #else - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->CreateFileAsync( - ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)).get(); + auto file = pplx::create_task(KnownFolders::DocumentsLibrary->CreateFileAsync( + ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)) + .get(); return concurrency::streams::file_stream<_CharType>::open_ostream(file, mode); #endif @@ -44,17 +49,17 @@ pplx::task> OPENSTR_W(const utili #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable : 4100) // Because of '_Prot' in WinRT builds. +#pragma warning(disable : 4100) // Because of '_Prot' in WinRT builds. #endif template -pplx::task> OPENSTR_R(const utility::string_t &name, std::ios_base::openmode mode = std::ios_base::in) +pplx::task> OPENSTR_R(const utility::string_t& name, + std::ios_base::openmode mode = std::ios_base::in) { #if !defined(__cplusplus_winrt) return concurrency::streams::file_stream<_CharType>::open_istream(name, mode); #else - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->GetFileAsync( - ref new Platform::String(name.c_str()))).get(); + auto file = + pplx::create_task(KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); return concurrency::streams::file_stream<_CharType>::open_istream(file, mode); #endif @@ -65,28 +70,24 @@ pplx::task> OPENSTR_R(const utili SUITE(ostream_tests) { + TEST(BasicTest1) + { + auto open = OPENSTR_W(U("BasicTest1.txt")); + auto basic_stream = open.get(); + VERIFY_IS_TRUE(basic_stream.can_seek()); + auto a = basic_stream.print(10); + auto b = basic_stream.print("-suffix"); + (a && b).wait(); + auto cls = basic_stream.close(); + cls.get(); + VERIFY_IS_TRUE(cls.is_done()); + } -TEST(BasicTest1) -{ - auto open = OPENSTR_W(U("BasicTest1.txt")); - auto basic_stream = open.get(); - VERIFY_IS_TRUE(basic_stream.can_seek()); - auto a = basic_stream.print(10); - auto b = basic_stream.print("-suffix"); - (a && b).wait(); - auto cls = basic_stream.close(); - cls.get(); - VERIFY_IS_TRUE(cls.is_done()); -} - -TEST(BasicTest2) -{ - auto open = OPENSTR_W(U("BasicTest2.txt")); + TEST(BasicTest2) + { + auto open = OPENSTR_W(U("BasicTest2.txt")); - auto cls = - open.then( - [](pplx::task op) -> pplx::task - { + auto cls = open.then([](pplx::task op) -> pplx::task { auto basic_stream = op.get(); auto a = basic_stream.print(10); auto b = basic_stream.print("-suffix"); @@ -94,301 +95,304 @@ TEST(BasicTest2) return basic_stream.close(); }); - cls.get(); + cls.get(); - VERIFY_IS_TRUE(cls.is_done()); -} - - -TEST(WriteSingleCharTest2) -{ - auto open = OPENSTR_W(U("WriteSingleCharStrTest1.txt")); - auto stream = open.get(); - - VERIFY_IS_TRUE(open.is_done()); - - bool elements_equal = true; - - for (uint8_t ch = 'a'; ch <= 'z'; ch++) - { - elements_equal = elements_equal && (ch == stream.write(ch).get()); + VERIFY_IS_TRUE(cls.is_done()); } - VERIFY_IS_TRUE(elements_equal); + TEST(WriteSingleCharTest2) + { + auto open = OPENSTR_W(U("WriteSingleCharStrTest1.txt")); + auto stream = open.get(); - auto close = stream.close(); - close.get(); + VERIFY_IS_TRUE(open.is_done()); - VERIFY_IS_TRUE(close.is_done()); -} + bool elements_equal = true; -TEST(WriteBufferTest1) -{ - auto open = OPENSTR_W(U("WriteBufferStrTest1.txt")); - auto stream = open.get(); + for (uint8_t ch = 'a'; ch <= 'z'; ch++) + { + elements_equal = elements_equal && (ch == stream.write(ch).get()); + } - VERIFY_IS_TRUE(open.is_done()); + VERIFY_IS_TRUE(elements_equal); - std::vector vect; + auto close = stream.close(); + close.get(); - for (char ch = 'a'; ch <= 'z'; ch++) - { - vect.push_back(ch); + VERIFY_IS_TRUE(close.is_done()); } - size_t vsz = vect.size(); + TEST(WriteBufferTest1) + { + auto open = OPENSTR_W(U("WriteBufferStrTest1.txt")); + auto stream = open.get(); - concurrency::streams::container_stream>::buffer_type txtbuf(std::move(vect), std::ios_base::in); + VERIFY_IS_TRUE(open.is_done()); - VERIFY_ARE_EQUAL(stream.write(txtbuf, vsz).get(), vsz); + std::vector vect; - auto close = stream.close(); - close.get(); + for (char ch = 'a'; ch <= 'z'; ch++) + { + vect.push_back(ch); + } - VERIFY_IS_TRUE(close.is_done()); -} + size_t vsz = vect.size(); -TEST(WriteBufferAndSyncTest1) -{ - auto open = OPENSTR_W(U("WriteBufferAndSyncStrTest1.txt")); - auto stream = open.get(); + concurrency::streams::container_stream>::buffer_type txtbuf(std::move(vect), + std::ios_base::in); - VERIFY_IS_TRUE(open.is_done()); + VERIFY_ARE_EQUAL(stream.write(txtbuf, vsz).get(), vsz); - std::vector vect; + auto close = stream.close(); + close.get(); - for (char ch = 'a'; ch <= 'z'; ch++) - { - vect.push_back(ch); + VERIFY_IS_TRUE(close.is_done()); } - size_t vsz = vect.size(); - concurrency::streams::rawptr_buffer txtbuf(reinterpret_cast(&vect[0]), vsz); + TEST(WriteBufferAndSyncTest1) + { + auto open = OPENSTR_W(U("WriteBufferAndSyncStrTest1.txt")); + auto stream = open.get(); - auto write = stream.write(txtbuf, vsz); - stream.flush().get(); + VERIFY_IS_TRUE(open.is_done()); - VERIFY_ARE_EQUAL(write.get(), vect.size()); - VERIFY_IS_TRUE(write.is_done()); + std::vector vect; - auto close = stream.close(); - close.get(); + for (char ch = 'a'; ch <= 'z'; ch++) + { + vect.push_back(ch); + } - VERIFY_IS_TRUE(close.is_done()); -} + size_t vsz = vect.size(); + concurrency::streams::rawptr_buffer txtbuf(reinterpret_cast(&vect[0]), vsz); -TEST(tell_bug) -{ - auto count = - OPENSTR_W(U("tell_bug.txt"), std::ios_base::out | std::ios_base::trunc). - then([=](concurrency::streams::ostream os) -> std::streamoff { - os.print("A"); - auto val = os.tell(); - os.close().get(); - return val; - }).get(); - - VERIFY_ARE_EQUAL(std::streamoff(1), count); -} + auto write = stream.write(txtbuf, vsz); + stream.flush().get(); -TEST(iostream_container_buffer1) -{ - concurrency::streams::container_buffer> buf; + VERIFY_ARE_EQUAL(write.get(), vect.size()); + VERIFY_IS_TRUE(write.is_done()); - auto os = buf.create_ostream(); - os.write('a'); - os.write('b'); - os.close(); + auto close = stream.close(); + close.get(); - auto is = concurrency::streams::container_stream>::open_istream(std::move(buf.collection())); - VERIFY_ARE_EQUAL(is.read().get(), 'a'); - VERIFY_ARE_EQUAL(is.read().get(), 'b'); -} + VERIFY_IS_TRUE(close.is_done()); + } -TEST(iostream_container_buffer2) -{ - concurrency::streams::container_buffer> buf; + TEST(tell_bug) + { + auto count = OPENSTR_W(U("tell_bug.txt"), std::ios_base::out | std::ios_base::trunc) + .then([=](concurrency::streams::ostream os) -> std::streamoff { + os.print("A"); + auto val = os.tell(); + os.close().get(); + return val; + }) + .get(); + + VERIFY_ARE_EQUAL(std::streamoff(1), count); + } + TEST(iostream_container_buffer1) { + concurrency::streams::container_buffer> buf; + auto os = buf.create_ostream(); os.write('a'); os.write('b'); os.close(); + + auto is = concurrency::streams::container_stream>::open_istream(std::move(buf.collection())); + VERIFY_ARE_EQUAL(is.read().get(), 'a'); + VERIFY_ARE_EQUAL(is.read().get(), 'b'); } + TEST(iostream_container_buffer2) { - auto is = concurrency::streams::container_stream>::open_istream(std::move(buf.collection())); + concurrency::streams::container_buffer> buf; - is.read().then([&is](concurrency::streams::basic_ostream::int_type c) { - VERIFY_ARE_EQUAL(c, 'a'); - return is.read(); - }).then([&is](concurrency::streams::basic_ostream::int_type c) -> pplx::task + auto os = buf.create_ostream(); + os.write('a'); + os.write('b'); + os.close(); + } + { - VERIFY_ARE_EQUAL(c, 'b'); - return is.close(); - }).wait(); + auto is = + concurrency::streams::container_stream>::open_istream(std::move(buf.collection())); + + is.read() + .then([&is](concurrency::streams::basic_ostream::int_type c) { + VERIFY_ARE_EQUAL(c, 'a'); + return is.read(); + }) + .then([&is](concurrency::streams::basic_ostream::int_type c) -> pplx::task { + VERIFY_ARE_EQUAL(c, 'b'); + return is.close(); + }) + .wait(); + } } -} - -TEST(extract_on_space) -{ - const int number1 = 42; - const int number2 = 123; - - auto open = OPENSTR_W(U("SpaceWithNumber.txt"), std::ios::trunc); - auto stream = open.get(); - VERIFY_IS_TRUE(open.is_done()); - stream.print(" \r").wait(); - stream.print(number1).wait(); - stream.print("\n \t").wait(); - stream.print(number2).wait(); - stream.print(" \f \v ").wait(); - stream.close().wait(); - - auto istream = OPENSTR_R(U("SpaceWithNumber.txt")).get(); - VERIFY_IS_TRUE(istream.can_seek()); - VERIFY_ARE_EQUAL(number1, istream.extract().get()); - VERIFY_ARE_EQUAL(number2, istream.extract().get()); -} - -TEST(file_sequential_write) -{ - auto open = OPENSTR_W(U("WriteFileSequential.txt"), std::ios::trunc); - auto stream = open.get(); - VERIFY_IS_TRUE(open.is_done()); - - std::vector> v; - for (int i = 0; i < 100; i++) + TEST(extract_on_space) { - v.push_back(stream.print(i)); - v.push_back(stream.print(' ')); + const int number1 = 42; + const int number2 = 123; + + auto open = OPENSTR_W(U("SpaceWithNumber.txt"), std::ios::trunc); + auto stream = open.get(); + VERIFY_IS_TRUE(open.is_done()); + stream.print(" \r").wait(); + stream.print(number1).wait(); + stream.print("\n \t").wait(); + stream.print(number2).wait(); + stream.print(" \f \v ").wait(); + stream.close().wait(); + + auto istream = OPENSTR_R(U("SpaceWithNumber.txt")).get(); + VERIFY_IS_TRUE(istream.can_seek()); + VERIFY_ARE_EQUAL(number1, istream.extract().get()); + VERIFY_ARE_EQUAL(number2, istream.extract().get()); } - pplx::when_all(v.begin(), v.end()).wait(); - stream.close().wait(); - auto istream = OPENSTR_R(U("WriteFileSequential.txt")).get(); - for (int i = 0; i < 100; i++) + + TEST(file_sequential_write) { - int int_read = istream.extract().get(); - if (int_read != i) - { - // This will fail - VERIFY_ARE_EQUAL(int_read, i); + auto open = OPENSTR_W(U("WriteFileSequential.txt"), std::ios::trunc); + auto stream = open.get(); - // This return statment will prevent the test from hanging, - // cause if the numbers are merged there will be less than 100 numbers, - // and reading from the file will block - return; + VERIFY_IS_TRUE(open.is_done()); + + std::vector> v; + for (int i = 0; i < 100; i++) + { + v.push_back(stream.print(i)); + v.push_back(stream.print(' ')); + } + pplx::when_all(v.begin(), v.end()).wait(); + stream.close().wait(); + auto istream = OPENSTR_R(U("WriteFileSequential.txt")).get(); + for (int i = 0; i < 100; i++) + { + int int_read = istream.extract().get(); + if (int_read != i) + { + // This will fail + VERIFY_ARE_EQUAL(int_read, i); + + // This return statment will prevent the test from hanging, + // cause if the numbers are merged there will be less than 100 numbers, + // and reading from the file will block + return; + } + istream.read().get(); } - istream.read().get(); } -} -TEST(implied_out_mode) -{ - auto ostr = OPENSTR_W(U("implied_out_mode.txt"), std::ios::ios_base::app).get(); + TEST(implied_out_mode) + { + auto ostr = OPENSTR_W(U("implied_out_mode.txt"), std::ios::ios_base::app).get(); - std::string str = "abcd"; - concurrency::streams::stringstreambuf block(str); + std::string str = "abcd"; + concurrency::streams::stringstreambuf block(str); - size_t s = ostr.write(block, str.size()).get(); + size_t s = ostr.write(block, str.size()).get(); - VERIFY_ARE_EQUAL(s, str.size()); + VERIFY_ARE_EQUAL(s, str.size()); - auto cls = ostr.close(); + auto cls = ostr.close(); - cls.get(); - VERIFY_IS_TRUE(cls.is_done()); -} + cls.get(); + VERIFY_IS_TRUE(cls.is_done()); + } -TEST(create_ostream_from_input_only) -{ - container_buffer sourceBuf("test data"); - VERIFY_THROWS(sourceBuf.create_ostream(), std::runtime_error); -} + TEST(create_ostream_from_input_only) + { + container_buffer sourceBuf("test data"); + VERIFY_THROWS(sourceBuf.create_ostream(), std::runtime_error); + } -TEST(streambuf_close_with_exception_write) -{ - container_buffer sourceBuf; - sourceBuf.close(std::ios::out, std::make_exception_ptr(std::invalid_argument("custom exception"))).wait(); + TEST(streambuf_close_with_exception_write) + { + container_buffer sourceBuf; + sourceBuf.close(std::ios::out, std::make_exception_ptr(std::invalid_argument("custom exception"))).wait(); - const size_t size = 4; - char targetBuf[size]; - auto t1 = sourceBuf.putn_nocopy(targetBuf, size); - VERIFY_THROWS(t1.get(), std::invalid_argument); -} + const size_t size = 4; + char targetBuf[size]; + auto t1 = sourceBuf.putn_nocopy(targetBuf, size); + VERIFY_THROWS(t1.get(), std::invalid_argument); + } -TEST(stream_close_with_exception_write) -{ - container_buffer sourceBuf; - auto outStream = sourceBuf.create_ostream(); - outStream.close(std::make_exception_ptr(std::invalid_argument("custom exception"))).wait(); + TEST(stream_close_with_exception_write) + { + container_buffer sourceBuf; + auto outStream = sourceBuf.create_ostream(); + outStream.close(std::make_exception_ptr(std::invalid_argument("custom exception"))).wait(); - container_buffer targetBuf("test data"); - auto t1 = outStream.write(targetBuf, 4); - VERIFY_THROWS(t1.get(), std::invalid_argument); -} + container_buffer targetBuf("test data"); + auto t1 = outStream.write(targetBuf, 4); + VERIFY_THROWS(t1.get(), std::invalid_argument); + } -TEST(input_after_close) -{ - container_buffer sourceBuf; - auto outStream = sourceBuf.create_ostream(); - outStream.close().wait(); - - container_buffer targetBuf; - - auto t1 = outStream.flush(); - auto t2 = outStream.print('a'); - auto t3 = outStream.print(std::string("abc")); - - VERIFY_THROWS(t1.get(), std::runtime_error); - VERIFY_THROWS(t2.get(), std::runtime_error); - VERIFY_THROWS(t3.get(), std::runtime_error); - VERIFY_THROWS(outStream.seek(0), std::runtime_error); - VERIFY_THROWS(outStream.seek(0, std::ios::beg), std::runtime_error); - VERIFY_THROWS(outStream.tell(), std::runtime_error); - - auto t4 = outStream.write('a'); - auto t5 = outStream.write(targetBuf, 1); - VERIFY_THROWS(t4.get(), std::runtime_error); - VERIFY_THROWS(t5.get(), std::runtime_error); -} + TEST(input_after_close) + { + container_buffer sourceBuf; + auto outStream = sourceBuf.create_ostream(); + outStream.close().wait(); + + container_buffer targetBuf; + + auto t1 = outStream.flush(); + auto t2 = outStream.print('a'); + auto t3 = outStream.print(std::string("abc")); + + VERIFY_THROWS(t1.get(), std::runtime_error); + VERIFY_THROWS(t2.get(), std::runtime_error); + VERIFY_THROWS(t3.get(), std::runtime_error); + VERIFY_THROWS(outStream.seek(0), std::runtime_error); + VERIFY_THROWS(outStream.seek(0, std::ios::beg), std::runtime_error); + VERIFY_THROWS(outStream.tell(), std::runtime_error); + + auto t4 = outStream.write('a'); + auto t5 = outStream.write(targetBuf, 1); + VERIFY_THROWS(t4.get(), std::runtime_error); + VERIFY_THROWS(t5.get(), std::runtime_error); + } -TEST(write_emptybuffer_to_ostream) -{ - auto ofs = OPENSTR_W(U("file.txt")).get(); - auto sbuf = concurrency::streams::producer_consumer_buffer(); - auto result = ofs.write(sbuf,0); - VERIFY_ARE_EQUAL(result.get(), 0); -} + TEST(write_emptybuffer_to_ostream) + { + auto ofs = OPENSTR_W(U("file.txt")).get(); + auto sbuf = concurrency::streams::producer_consumer_buffer(); + auto result = ofs.write(sbuf, 0); + VERIFY_ARE_EQUAL(result.get(), 0); + } -TEST(write_stream_twice) -{ - producer_consumer_buffer buf1; - auto t1 = pplx::create_task([&]{ - buf1.alloc(8); - buf1.alloc(9); - }); - VERIFY_THROWS(t1.get(), std::logic_error); - - std::string strData("test string to write\n"); - container_buffer buf2(std::move(strData)); - auto t2 = pplx::create_task([&]{ - buf2.commit(8); - buf2.alloc(9); - }); - VERIFY_THROWS(t2.get(), std::logic_error); - - rawptr_buffer buf3; - auto t3 = pplx::create_task([&]{ - buf3.commit(8); - buf3.commit(9); - }); - VERIFY_THROWS(t3.get(), std::logic_error); -} + TEST(write_stream_twice) + { + producer_consumer_buffer buf1; + auto t1 = pplx::create_task([&] { + buf1.alloc(8); + buf1.alloc(9); + }); + VERIFY_THROWS(t1.get(), std::logic_error); -} // SUITE(ostream_tests) + std::string strData("test string to write\n"); + container_buffer buf2(std::move(strData)); + auto t2 = pplx::create_task([&] { + buf2.commit(8); + buf2.alloc(9); + }); + VERIFY_THROWS(t2.get(), std::logic_error); -}}} + rawptr_buffer buf3; + auto t3 = pplx::create_task([&] { + buf3.commit(8); + buf3.commit(9); + }); + VERIFY_THROWS(t3.get(), std::logic_error); + } + +} // SUITE(ostream_tests) +} // namespace streams +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/streams/prefix.h b/Release/tests/functional/streams/prefix.h index 64fc8923f2..1fd757597e 100644 --- a/Release/tests/functional/streams/prefix.h +++ b/Release/tests/functional/streams/prefix.h @@ -1,43 +1,41 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.h + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #ifndef __PREFIX_H #define __PREFIX_H -#include #include #include #include #include +#include #if defined(_MSC_VER) && (_MSC_VER >= 1800) #include namespace pplx = Concurrency; -#else +#else #include "pplx/pplxtasks.h" #endif #include "cpprest/asyncrt_utils.h" - -#include "cpprest/producerconsumerstream.h" -#include "cpprest/rawptrstream.h" #include "cpprest/containerstream.h" +#include "cpprest/filestream.h" #include "cpprest/interopstream.h" +#include "cpprest/producerconsumerstream.h" +#include "cpprest/rawptrstream.h" #include "cpprest/streams.h" -#include "cpprest/filestream.h" - -#include "unittestpp.h" #include "streams_tests.h" +#include "unittestpp.h" template class concurrency::streams::file_buffer; template class concurrency::streams::file_buffer; @@ -60,5 +58,4 @@ template class concurrency::streams::producer_consumer_buffer; template class concurrency::streams::container_stream>; template class concurrency::streams::container_stream>; - -#endif \ No newline at end of file +#endif diff --git a/Release/tests/functional/streams/stdafx.cpp b/Release/tests/functional/streams/stdafx.cpp index 027a0ecba7..5f1ad19216 100644 --- a/Release/tests/functional/streams/stdafx.cpp +++ b/Release/tests/functional/streams/stdafx.cpp @@ -1,15 +1,14 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ -// stdafx.cpp : + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ +// stdafx.cpp : // Include the standard header and generate the precompiled header. - #include "stdafx.h" #if WIN32 __declspec(dllexport) int streams_test_generate_lib = 0; -#endif \ No newline at end of file +#endif diff --git a/Release/tests/functional/streams/stdafx.h b/Release/tests/functional/streams/stdafx.h index a278f3145e..ac54b8c4ae 100644 --- a/Release/tests/functional/streams/stdafx.h +++ b/Release/tests/functional/streams/stdafx.h @@ -1,42 +1,38 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.h + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include #include #include #include #include +#include #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX #include namespace pplx = Concurrency; -#else +#else #include "pplx/pplxtasks.h" #endif #include "cpprest/asyncrt_utils.h" - -#include "cpprest/producerconsumerstream.h" -#include "cpprest/rawptrstream.h" #include "cpprest/containerstream.h" +#include "cpprest/filestream.h" #include "cpprest/interopstream.h" +#include "cpprest/producerconsumerstream.h" +#include "cpprest/rawptrstream.h" #include "cpprest/streams.h" -#include "cpprest/filestream.h" - #include "os_utilities.h" - - -#include "unittestpp.h" #include "streams_tests.h" +#include "unittestpp.h" diff --git a/Release/tests/functional/streams/stdstream_tests.cpp b/Release/tests/functional/streams/stdstream_tests.cpp index a8fde13499..34b9b3af12 100644 --- a/Release/tests/functional/streams/stdstream_tests.cpp +++ b/Release/tests/functional/streams/stdstream_tests.cpp @@ -1,18 +1,18 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests for integration of async streams with std streams. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests for integration of async streams with std streams. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include "cpprest/rawptrstream.h" #include "cpprest/filestream.h" #include "cpprest/producerconsumerstream.h" +#include "cpprest/rawptrstream.h" #if (!defined(_WIN32) || !defined(CPPREST_EXCLUDE_WEBSOCKETS)) && !defined(__cplusplus_winrt) #include @@ -23,17 +23,21 @@ using namespace Windows::Storage; #endif #ifdef _WIN32 -# define DEFAULT_PROT (int)std::ios_base::_Openprot +#define DEFAULT_PROT (int)std::ios_base::_Openprot #else -# define DEFAULT_PROT 0 +#define DEFAULT_PROT 0 #endif -namespace tests { namespace functional { namespace streams { - +namespace tests +{ +namespace functional +{ +namespace streams +{ using namespace ::pplx; using namespace utility; -utility::string_t get_full_name(const utility::string_t &name); +utility::string_t get_full_name(const utility::string_t& name); template void extract_test(std::basic_istream& stream, std::basic_string expected) @@ -45,7 +49,7 @@ void extract_test(std::basic_istream& stream, std::basic_string -pplx::task> OPEN_R(const utility::string_t &name) +pplx::task> OPEN_R(const utility::string_t& name) { #if !defined(__cplusplus_winrt) return Concurrency::streams::file_buffer<_CharType>::open(name, std::ios_base::in); #else - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); + auto file = + pplx::create_task(KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); return Concurrency::streams::file_buffer<_CharType>::open(file, std::ios_base::in); #endif @@ -75,234 +79,233 @@ pplx::task> OPEN_R(const utility::str SUITE(stdstreambuf_tests) { + TEST(sync_on_async_write) + { + Concurrency::streams::stringstreambuf strbuf; + auto ss = strbuf.create_ostream(); + Concurrency::streams::async_ostream bios(ss); -TEST(sync_on_async_write) -{ - Concurrency::streams::stringstreambuf strbuf; - auto ss = strbuf.create_ostream(); - Concurrency::streams::async_ostream bios(ss); + auto text = "hello!"; - auto text = "hello!"; + bios.write(text, strlen(text)); - bios.write(text, strlen(text)); + auto buf = ss.streambuf(); - auto buf = ss.streambuf(); + VERIFY_ARE_EQUAL(strbuf.collection(), "hello!"); + } - VERIFY_ARE_EQUAL(strbuf.collection(), "hello!"); -} + TEST(sync_on_async_put) + { + Concurrency::streams::stringstreambuf strbuf; + auto ss = strbuf.create_ostream(); + Concurrency::streams::async_ostream bios(ss); -TEST(sync_on_async_put) -{ - Concurrency::streams::stringstreambuf strbuf; - auto ss = strbuf.create_ostream(); - Concurrency::streams::async_ostream bios(ss); + bios.put('h').put('e').put('l').put('l').put('o').put('!'); - bios.put('h').put('e').put('l').put('l').put('o').put('!'); + VERIFY_ARE_EQUAL(strbuf.collection(), "hello!"); + } - VERIFY_ARE_EQUAL(strbuf.collection(), "hello!"); -} + TEST(sync_on_async_insert) + { + Concurrency::streams::stringstreambuf strbuf; + auto ss = strbuf.create_ostream(); + Concurrency::streams::async_ostream bios(ss); -TEST(sync_on_async_insert) -{ - Concurrency::streams::stringstreambuf strbuf; - auto ss = strbuf.create_ostream(); - Concurrency::streams::async_ostream bios(ss); + bios << "hello" + << ", there, this is " << 4711; - bios << "hello" << ", there, this is " << 4711; + VERIFY_ARE_EQUAL(strbuf.collection(), "hello, there, this is 4711"); + ss.close().wait(); + } - VERIFY_ARE_EQUAL(strbuf.collection(), "hello, there, this is 4711"); - ss.close().wait(); -} + TEST(sync_on_async_seekp) + { + Concurrency::streams::stringstreambuf strbuf; + auto ss = strbuf.create_ostream(); + Concurrency::streams::async_ostream bios(ss); -TEST(sync_on_async_seekp) -{ - Concurrency::streams::stringstreambuf strbuf; - auto ss = strbuf.create_ostream(); - Concurrency::streams::async_ostream bios(ss); + bios << "hello" + << ", there, this is " << 4711; - bios << "hello" << ", there, this is " << 4711; + bios.seekp(10); + bios << 'X'; - bios.seekp(10); - bios << 'X'; + VERIFY_ARE_EQUAL(strbuf.collection(), "hello, theXe, this is 4711"); + ss.close().wait(); + } - VERIFY_ARE_EQUAL(strbuf.collection(), "hello, theXe, this is 4711"); - ss.close().wait(); -} + TEST(sync_on_async_getline_1) + { + std::string s("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + auto ss = Concurrency::streams::stringstream::open_istream(s); -TEST(sync_on_async_getline_1) -{ - std::string s("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); - auto ss = Concurrency::streams::stringstream::open_istream(s); + Concurrency::streams::async_iostream bios(ss.streambuf()); - Concurrency::streams::async_iostream bios(ss.streambuf()); - - char chars[128]; - bios.getline(chars, sizeof(chars)); + char chars[128]; + bios.getline(chars, sizeof(chars)); - VERIFY_ARE_EQUAL(strcmp(chars,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0); -} + VERIFY_ARE_EQUAL(strcmp(chars, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0); + } -TEST(sync_on_async_getline_2) -{ - std::string s("abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"); - auto ss = Concurrency::streams::stringstream::open_istream(s); + TEST(sync_on_async_getline_2) + { + std::string s("abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"); + auto ss = Concurrency::streams::stringstream::open_istream(s); - Concurrency::streams::async_iostream bios(ss.streambuf()); - - char chars[128]; + Concurrency::streams::async_iostream bios(ss.streambuf()); - bios.getline(chars,sizeof(chars)); + char chars[128]; - VERIFY_ARE_EQUAL(strcmp(chars,"abcdefghijklmnopqrstuvwxyz"), 0); + bios.getline(chars, sizeof(chars)); - VERIFY_ARE_EQUAL(bios.get(), 'A'); -} + VERIFY_ARE_EQUAL(strcmp(chars, "abcdefghijklmnopqrstuvwxyz"), 0); -TEST(sync_on_async_getline_3) -{ - std::string s("abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - auto ss = Concurrency::streams::stringstream::open_istream(s); + VERIFY_ARE_EQUAL(bios.get(), 'A'); + } - Concurrency::streams::async_iostream bios(ss.streambuf()); - - char chars[128]; + TEST(sync_on_async_getline_3) + { + std::string s("abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + auto ss = Concurrency::streams::stringstream::open_istream(s); - bios.getline(chars,sizeof(chars), '|'); + Concurrency::streams::async_iostream bios(ss.streambuf()); - VERIFY_ARE_EQUAL(strcmp(chars,"abcdefghijklmnopqrstuvwxyz"), 0); + char chars[128]; - VERIFY_ARE_EQUAL(bios.get(), 'A'); -} + bios.getline(chars, sizeof(chars), '|'); -TEST(sync_on_async_get_1) -{ - std::string s("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); - auto ss = Concurrency::streams::stringstream::open_istream(s); + VERIFY_ARE_EQUAL(strcmp(chars, "abcdefghijklmnopqrstuvwxyz"), 0); - Concurrency::streams::async_iostream bios(ss.streambuf()); - - char chars[128]; + VERIFY_ARE_EQUAL(bios.get(), 'A'); + } - bios.get(chars, sizeof(chars)); + TEST(sync_on_async_get_1) + { + std::string s("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + auto ss = Concurrency::streams::stringstream::open_istream(s); - VERIFY_ARE_EQUAL(strcmp(chars,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0); -} + Concurrency::streams::async_iostream bios(ss.streambuf()); -TEST(sync_on_async_fget_1) -{ - utility::string_t fname = U("sync_on_async_fget_1.txt"); - fill_file(fname, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + char chars[128]; - auto ofs = OPEN_R(fname).get(); - Concurrency::streams::async_istream bios(ofs); - - char chars[128]; + bios.get(chars, sizeof(chars)); - bios.get(chars, sizeof(chars)); + VERIFY_ARE_EQUAL(strcmp(chars, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0); + } - VERIFY_ARE_EQUAL(strcmp(chars,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0); - ofs.close().wait(); -} + TEST(sync_on_async_fget_1) + { + utility::string_t fname = U("sync_on_async_fget_1.txt"); + fill_file(fname, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); -TEST(sync_on_async_get_2) -{ - std::string s("abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"); - auto ss = Concurrency::streams::stringstream::open_istream(s); + auto ofs = OPEN_R(fname).get(); + Concurrency::streams::async_istream bios(ofs); - Concurrency::streams::async_iostream bios(ss.streambuf()); - - char chars[128]; + char chars[128]; - bios.get(chars,sizeof(chars)); + bios.get(chars, sizeof(chars)); - VERIFY_ARE_EQUAL(strcmp(chars,"abcdefghijklmnopqrstuvwxyz"), 0); + VERIFY_ARE_EQUAL(strcmp(chars, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0); + ofs.close().wait(); + } - VERIFY_ARE_EQUAL(bios.get(), '\n'); -} + TEST(sync_on_async_get_2) + { + std::string s("abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"); + auto ss = Concurrency::streams::stringstream::open_istream(s); -TEST(sync_on_async_get_3) -{ - std::string s("abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - auto ss = Concurrency::streams::stringstream::open_istream(s); + Concurrency::streams::async_iostream bios(ss.streambuf()); - Concurrency::streams::async_iostream bios(ss.streambuf()); - - char chars[128]; + char chars[128]; - bios.get(chars,sizeof(chars), '|'); + bios.get(chars, sizeof(chars)); - VERIFY_ARE_EQUAL(strcmp(chars,"abcdefghijklmnopqrstuvwxyz"), 0); + VERIFY_ARE_EQUAL(strcmp(chars, "abcdefghijklmnopqrstuvwxyz"), 0); - VERIFY_ARE_EQUAL(bios.get(), '|'); -} + VERIFY_ARE_EQUAL(bios.get(), '\n'); + } -TEST(sync_on_async_extract_1) -{ - auto ss = Concurrency::streams::stringstream::open_istream(std::string("abcdefg 10 1 9.4711")); + TEST(sync_on_async_get_3) + { + std::string s("abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + auto ss = Concurrency::streams::stringstream::open_istream(s); - Concurrency::streams::async_iostream bios(ss.streambuf()); + Concurrency::streams::async_iostream bios(ss.streambuf()); - std::string s; - int i; - bool b; - double d; + char chars[128]; - bios >> s >> i >> b >> d; + bios.get(chars, sizeof(chars), '|'); - VERIFY_ARE_EQUAL(s, "abcdefg"); - VERIFY_ARE_EQUAL(i, 10); - VERIFY_IS_TRUE(b); - VERIFY_ARE_EQUAL(d, 9.4711); -} + VERIFY_ARE_EQUAL(strcmp(chars, "abcdefghijklmnopqrstuvwxyz"), 0); -TEST(sync_on_async_fextract_1) -{ - utility::string_t fname = U("sync_on_async_fextract_1.txt"); - fill_file(fname, "abcdefg 10 1 9.4711"); + VERIFY_ARE_EQUAL(bios.get(), '|'); + } - auto ofs = OPEN_R(fname).get(); - Concurrency::streams::async_istream bios(ofs); - - std::string s; - int i; - bool b; - double d; + TEST(sync_on_async_extract_1) + { + auto ss = Concurrency::streams::stringstream::open_istream(std::string("abcdefg 10 1 9.4711")); - bios >> s >> i >> b >> d; + Concurrency::streams::async_iostream bios(ss.streambuf()); - VERIFY_ARE_EQUAL(s, "abcdefg"); - VERIFY_ARE_EQUAL(i, 10); - VERIFY_IS_TRUE(b); - VERIFY_ARE_EQUAL(d, 9.4711); + std::string s; + int i; + bool b; + double d; - ofs.close().wait(); -} + bios >> s >> i >> b >> d; -TEST(sync_on_async_extract_2) -{ - std::string s("abcdefg 10 1 9.4711"); - auto is = Concurrency::streams::stringstream::open_istream(s); + VERIFY_ARE_EQUAL(s, "abcdefg"); + VERIFY_ARE_EQUAL(i, 10); + VERIFY_IS_TRUE(b); + VERIFY_ARE_EQUAL(d, 9.4711); + } - Concurrency::streams::async_istream ss(is.streambuf()); - extract_test(ss, "abcdefg"); + TEST(sync_on_async_fextract_1) + { + utility::string_t fname = U("sync_on_async_fextract_1.txt"); + fill_file(fname, "abcdefg 10 1 9.4711"); - is.close().wait(); -} + auto ofs = OPEN_R(fname).get(); + Concurrency::streams::async_istream bios(ofs); -TEST(sync_on_async_prodcons) -{ - Concurrency::streams::producer_consumer_buffer pcbuf; + std::string s; + int i; + bool b; + double d; + + bios >> s >> i >> b >> d; + + VERIFY_ARE_EQUAL(s, "abcdefg"); + VERIFY_ARE_EQUAL(i, 10); + VERIFY_IS_TRUE(b); + VERIFY_ARE_EQUAL(d, 9.4711); + + ofs.close().wait(); + } + + TEST(sync_on_async_extract_2) + { + std::string s("abcdefg 10 1 9.4711"); + auto is = Concurrency::streams::stringstream::open_istream(s); + + Concurrency::streams::async_istream ss(is.streambuf()); + extract_test(ss, "abcdefg"); + + is.close().wait(); + } - auto ostream = pcbuf.create_ostream(); - auto istream = pcbuf.create_istream(); + TEST(sync_on_async_prodcons) + { + Concurrency::streams::producer_consumer_buffer pcbuf; + + auto ostream = pcbuf.create_ostream(); + auto istream = pcbuf.create_istream(); - const std::streamsize iterations = 100; + const std::streamsize iterations = 100; - const std::string the_alphabet("abcdefghijklmnopqrstuvwxyz"); + const std::string the_alphabet("abcdefghijklmnopqrstuvwxyz"); - auto writer = pplx::create_task( - [ostream,iterations,the_alphabet]() - { + auto writer = pplx::create_task([ostream, iterations, the_alphabet]() { auto os = ostream; for (std::streamsize i = 0; i < iterations; i++) { @@ -312,493 +315,490 @@ TEST(sync_on_async_prodcons) os.close(); }); - Concurrency::streams::async_istream ss(istream.streambuf()); + Concurrency::streams::async_istream ss(istream.streambuf()); - char chars[1024]; - std::streamsize count = 0; + char chars[1024]; + std::streamsize count = 0; - while(!ss.eof()) - { - memset(chars, 0, sizeof(chars)); - ss.read(chars, sizeof(chars)-1); - count += strlen(chars); - } + while (!ss.eof()) + { + memset(chars, 0, sizeof(chars)); + ss.read(chars, sizeof(chars) - 1); + count += strlen(chars); + } - VERIFY_ARE_EQUAL(the_alphabet.size()*iterations, count); + VERIFY_ARE_EQUAL(the_alphabet.size() * iterations, count); - writer.wait(); -} + writer.wait(); + } -TEST(sync_on_async_tellg) -{ - Concurrency::streams::producer_consumer_buffer pcbuf; + TEST(sync_on_async_tellg) + { + Concurrency::streams::producer_consumer_buffer pcbuf; - auto ostream = pcbuf.create_ostream(); - auto istream = pcbuf.create_istream(); + auto ostream = pcbuf.create_ostream(); + auto istream = pcbuf.create_istream(); - const std::streamsize iterations = 100; + const std::streamsize iterations = 100; - const std::string the_alphabet("abcdefghijklmnopqrstuvwxyz"); + const std::string the_alphabet("abcdefghijklmnopqrstuvwxyz"); - auto writer = pplx::create_task( - [ostream,iterations,the_alphabet]() - { + auto writer = pplx::create_task([ostream, iterations, the_alphabet]() { auto os = ostream; for (std::streamsize i = 0; i < iterations; i++) { os.print(the_alphabet).wait(); os.flush().wait(); - VERIFY_ARE_EQUAL((i+1)*the_alphabet.size(), os.tell()); + VERIFY_ARE_EQUAL((i + 1) * the_alphabet.size(), os.tell()); } os.close(); }); - Concurrency::streams::async_istream ss(istream.streambuf()); + Concurrency::streams::async_istream ss(istream.streambuf()); - char chars[1024]; - std::streamsize count = 0; + char chars[1024]; + std::streamsize count = 0; - while(!ss.eof()) - { - VERIFY_ARE_EQUAL(count, ss.tellg()); - memset(chars, 0, sizeof(chars)); - ss.read(chars, sizeof(chars)-1); - count += strlen(chars); + while (!ss.eof()) + { + VERIFY_ARE_EQUAL(count, ss.tellg()); + memset(chars, 0, sizeof(chars)); + ss.read(chars, sizeof(chars) - 1); + count += strlen(chars); + } + + VERIFY_ARE_EQUAL(the_alphabet.size() * iterations, count); + + writer.wait(); } - VERIFY_ARE_EQUAL(the_alphabet.size()*iterations, count); + TEST(async_on_sync_read_1) + { + std::stringstream stream; + Concurrency::streams::stdio_istream astream(stream); - writer.wait(); -} + stream << "abcdefghijklmnopqrstuvwxyz"; -TEST(async_on_sync_read_1) -{ - std::stringstream stream; - Concurrency::streams::stdio_istream astream(stream); + for (char c = 'a'; c <= 'z'; c++) + { + char ch = (char)astream.read().get(); + VERIFY_ARE_EQUAL(c, ch); + } - stream << "abcdefghijklmnopqrstuvwxyz"; + astream.close().get(); + } - for (char c = 'a'; c <= 'z'; c++) + TEST(async_on_sync_read_2) { - char ch = (char)astream.read().get(); - VERIFY_ARE_EQUAL(c, ch); - } + std::stringstream stream; + Concurrency::streams::stdio_istream astream(stream); - astream.close().get(); -} + stream << "abcdefghijklmnopqrstuvwxyz"; -TEST(async_on_sync_read_2) -{ - std::stringstream stream; - Concurrency::streams::stdio_istream astream(stream); + char buffer[128]; + Concurrency::streams::rawptr_buffer txtbuf(buffer, 128); - stream << "abcdefghijklmnopqrstuvwxyz"; + VERIFY_ARE_EQUAL(26, astream.read(txtbuf, 26).get()); - char buffer[128]; - Concurrency::streams::rawptr_buffer txtbuf(buffer, 128); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - VERIFY_ARE_EQUAL(26, astream.read(txtbuf, 26).get()); + VERIFY_ARE_EQUAL(0, astream.read(txtbuf, 26).get()); - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + astream.close().get(); } - VERIFY_ARE_EQUAL(0, astream.read(txtbuf, 26).get()); - - astream.close().get(); -} + TEST(async_on_sync_read_3) + { + Concurrency::streams::producer_consumer_buffer trg; -TEST(async_on_sync_read_3) -{ - Concurrency::streams::producer_consumer_buffer trg; + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + std::stringstream stream; + Concurrency::streams::stdio_istream astream(stream); - std::stringstream stream; - Concurrency::streams::stdio_istream astream(stream); + stream << text; - stream << text; + VERIFY_ARE_EQUAL(52, astream.read_to_delim(trg, '\n').get()); - VERIFY_ARE_EQUAL(52, astream.read_to_delim(trg, '\n').get()); + char buffer[128]; + VERIFY_ARE_EQUAL(52, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - char buffer[128]; - VERIFY_ARE_EQUAL(52, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'A', buffer[i + 26]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); - } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'A', buffer[i+26]); + astream.close().get(); } - astream.close().get(); -} + TEST(async_on_sync_read_4) + { + Concurrency::streams::producer_consumer_buffer trg; -TEST(async_on_sync_read_4) -{ - Concurrency::streams::producer_consumer_buffer trg; + // There's one newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; - // There's one newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; + std::stringstream stream; + Concurrency::streams::stdio_istream astream(stream); - std::stringstream stream; - Concurrency::streams::stdio_istream astream(stream); + stream << text; - stream << text; + VERIFY_ARE_EQUAL(26, astream.read_to_delim(trg, '\n').get()); + VERIFY_ARE_EQUAL('A', (char)astream.read().get()); - VERIFY_ARE_EQUAL(26, astream.read_to_delim(trg, '\n').get()); - VERIFY_ARE_EQUAL('A', (char)astream.read().get()); + char buffer[128]; + VERIFY_ARE_EQUAL(26, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - char buffer[128]; - VERIFY_ARE_EQUAL(26, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + astream.close().get(); } - astream.close().get(); -} + TEST(async_on_sync_read_5) + { + Concurrency::streams::producer_consumer_buffer trg; -TEST(async_on_sync_read_5) -{ - Concurrency::streams::producer_consumer_buffer trg; + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + std::stringstream stream; + Concurrency::streams::stdio_istream astream(stream); - std::stringstream stream; - Concurrency::streams::stdio_istream astream(stream); + stream << text; - stream << text; + VERIFY_ARE_EQUAL(52, astream.read_to_delim(trg, '|').get()); - VERIFY_ARE_EQUAL(52, astream.read_to_delim(trg, '|').get()); + char buffer[128]; + VERIFY_ARE_EQUAL(52, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - char buffer[128]; - VERIFY_ARE_EQUAL(52, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'A', buffer[i + 26]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); + astream.close().get(); } - for (int i = 0; i < 26; i++) + + TEST(async_on_sync_read_6) { - VERIFY_ARE_EQUAL((char)i+'A', buffer[i+26]); - } + Concurrency::streams::producer_consumer_buffer trg; - astream.close().get(); -} + // There's one delimiter in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"; -TEST(async_on_sync_read_6) -{ - Concurrency::streams::producer_consumer_buffer trg; + std::stringstream stream; + Concurrency::streams::stdio_istream astream(stream); - // There's one delimiter in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + stream << text; - std::stringstream stream; - Concurrency::streams::stdio_istream astream(stream); + VERIFY_ARE_EQUAL(26, astream.read_to_delim(trg, '|').get()); + VERIFY_ARE_EQUAL('A', (char)astream.read().get()); - stream << text; + char buffer[128]; + VERIFY_ARE_EQUAL(26, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - VERIFY_ARE_EQUAL(26, astream.read_to_delim(trg, '|').get()); - VERIFY_ARE_EQUAL('A', (char)astream.read().get()); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - char buffer[128]; - VERIFY_ARE_EQUAL(26, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + astream.close().get(); + } - for (int i = 0; i < 26; i++) + TEST(async_on_sync_read_line_1) { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); - } + Concurrency::streams::producer_consumer_buffer trg; - astream.close().get(); -} + // There's no newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; -TEST(async_on_sync_read_line_1) -{ - Concurrency::streams::producer_consumer_buffer trg; + std::stringstream stream; + Concurrency::streams::stdio_istream astream(stream); - // There's no newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; + stream << text; - std::stringstream stream; - Concurrency::streams::stdio_istream astream(stream); + VERIFY_ARE_EQUAL(26, astream.read_line(trg).get()); + VERIFY_ARE_EQUAL('A', (char)astream.read().get()); - stream << text; + char buffer[128]; + VERIFY_ARE_EQUAL(26, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - VERIFY_ARE_EQUAL(26, astream.read_line(trg).get()); - VERIFY_ARE_EQUAL('A', (char)astream.read().get()); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - char buffer[128]; - VERIFY_ARE_EQUAL(26, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + astream.close().get(); + } - for (int i = 0; i < 26; i++) + TEST(async_on_sync_read_to_end_1) { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); - } + Concurrency::streams::producer_consumer_buffer trg; - astream.close().get(); -} + // There's one newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; -TEST(async_on_sync_read_to_end_1) -{ - Concurrency::streams::producer_consumer_buffer trg; + std::stringstream stream; + Concurrency::streams::stdio_istream astream(stream); - // There's one newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; + stream << text; - std::stringstream stream; - Concurrency::streams::stdio_istream astream(stream); + VERIFY_ARE_EQUAL(53, astream.read_to_end(trg).get()); - stream << text; + char buffer[128]; + VERIFY_ARE_EQUAL(53, trg.in_avail()); + trg.getn(buffer, trg.in_avail()).get(); - VERIFY_ARE_EQUAL(53, astream.read_to_end(trg).get()); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'a', buffer[i]); + } - char buffer[128]; - VERIFY_ARE_EQUAL(53, trg.in_avail()); - trg.getn(buffer, trg.in_avail()).get(); + for (int i = 0; i < 26; i++) + { + VERIFY_ARE_EQUAL((char)i + 'A', buffer[i + 27]); + } - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'a', buffer[i]); - } - - for (int i = 0; i < 26; i++) - { - VERIFY_ARE_EQUAL((char)i+'A', buffer[i+27]); + astream.close().get(); } - astream.close().get(); -} - -TEST(ostream_write_single_char) -{ - std::stringstream stream; - - Concurrency::streams::stdio_ostream os(stream); - - bool elements_equal = true; - - for (char ch = 'a'; ch <= 'z'; ch++) + TEST(ostream_write_single_char) { - elements_equal = elements_equal && (ch == os.write(ch).get()); - } + std::stringstream stream; - VERIFY_IS_TRUE(elements_equal); + Concurrency::streams::stdio_ostream os(stream); - VERIFY_ARE_EQUAL(stream.str(), "abcdefghijklmnopqrstuvwxyz"); + bool elements_equal = true; - os.close().get(); -} + for (char ch = 'a'; ch <= 'z'; ch++) + { + elements_equal = elements_equal && (ch == os.write(ch).get()); + } -TEST(ostream_write_buffer) -{ - std::stringstream stream; + VERIFY_IS_TRUE(elements_equal); - Concurrency::streams::stdio_ostream os(stream); + VERIFY_ARE_EQUAL(stream.str(), "abcdefghijklmnopqrstuvwxyz"); - const char *text = "abcdefghijklmnopqrstuvwxyz"; - size_t len = strlen(text); + os.close().get(); + } - Concurrency::streams::rawptr_buffer txtbuf(text, len); + TEST(ostream_write_buffer) + { + std::stringstream stream; - VERIFY_ARE_EQUAL(os.write(txtbuf, len).get(), len); + Concurrency::streams::stdio_ostream os(stream); - VERIFY_ARE_EQUAL(stream.str(), "abcdefghijklmnopqrstuvwxyz"); + const char* text = "abcdefghijklmnopqrstuvwxyz"; + size_t len = strlen(text); - os.close().get(); -} + Concurrency::streams::rawptr_buffer txtbuf(text, len); -TEST(ostream_output_print_string) -{ - std::stringstream stream; + VERIFY_ARE_EQUAL(os.write(txtbuf, len).get(), len); + + VERIFY_ARE_EQUAL(stream.str(), "abcdefghijklmnopqrstuvwxyz"); - Concurrency::streams::stdio_ostream os(stream); + os.close().get(); + } - os.print("abcdefghijklmnopqrstuvwxyz").wait(); + TEST(ostream_output_print_string) + { + std::stringstream stream; - VERIFY_ARE_EQUAL(stream.str(), "abcdefghijklmnopqrstuvwxyz"); + Concurrency::streams::stdio_ostream os(stream); - os.close().get(); -} + os.print("abcdefghijklmnopqrstuvwxyz").wait(); -TEST(ostream_output_print_types) -{ - std::stringstream stream; + VERIFY_ARE_EQUAL(stream.str(), "abcdefghijklmnopqrstuvwxyz"); - Concurrency::streams::stdio_ostream os(stream); + os.close().get(); + } - auto a = os.print("data: "); - auto b = os.print(10); - auto c = os.print(","); - auto d = os.print(true); - (a && b && c && d).wait(); + TEST(ostream_output_print_types) + { + std::stringstream stream; - VERIFY_ARE_EQUAL(stream.str(), "data: 10,1"); + Concurrency::streams::stdio_ostream os(stream); - os.close().get(); -} + auto a = os.print("data: "); + auto b = os.print(10); + auto c = os.print(","); + auto d = os.print(true); + (a && b && c && d).wait(); -TEST(ostream_output_print_line_string) -{ - std::stringstream stream; + VERIFY_ARE_EQUAL(stream.str(), "data: 10,1"); - Concurrency::streams::stdio_ostream os(stream); + os.close().get(); + } - os.print_line("abcdefghijklmnopqrstuvwxyz").wait(); + TEST(ostream_output_print_line_string) + { + std::stringstream stream; - VERIFY_ARE_EQUAL(stream.str(), "abcdefghijklmnopqrstuvwxyz\n"); + Concurrency::streams::stdio_ostream os(stream); - os.close().get(); -} + os.print_line("abcdefghijklmnopqrstuvwxyz").wait(); -TEST(ostream_output_print_line_types) -{ - std::stringstream stream; + VERIFY_ARE_EQUAL(stream.str(), "abcdefghijklmnopqrstuvwxyz\n"); - Concurrency::streams::stdio_ostream os(stream); + os.close().get(); + } - auto a = os.print_line("data: "); - auto b = os.print_line(10); - auto c = os.print_line(","); - auto d = os.print_line(true); - (a && b && c && d).wait(); + TEST(ostream_output_print_line_types) + { + std::stringstream stream; - VERIFY_ARE_EQUAL(stream.str(), "data: \n10\n,\n1\n"); + Concurrency::streams::stdio_ostream os(stream); - os.close().get(); -} + auto a = os.print_line("data: "); + auto b = os.print_line(10); + auto c = os.print_line(","); + auto d = os.print_line(true); + (a && b && c && d).wait(); -TEST(istream_extract_string) -{ - const char *text = " abc defgsf "; + VERIFY_ARE_EQUAL(stream.str(), "data: \n10\n,\n1\n"); - std::stringstream stream; - stream << text; + os.close().get(); + } - Concurrency::streams::stdio_istream is(stream); + TEST(istream_extract_string) + { + const char* text = " abc defgsf "; - std::string str1 = is.extract().get(); - std::string str2 = is.extract().get(); + std::stringstream stream; + stream << text; - VERIFY_ARE_EQUAL(str1, "abc"); - VERIFY_ARE_EQUAL(str2, "defgsf"); + Concurrency::streams::stdio_istream is(stream); - is.close().get(); -} + std::string str1 = is.extract().get(); + std::string str2 = is.extract().get(); -TEST(stdio_istream_error) -{ - std::ifstream inFile; - inFile.open("stdio_istream_error.txt"); - concurrency::streams::stdio_istream is(inFile); + VERIFY_ARE_EQUAL(str1, "abc"); + VERIFY_ARE_EQUAL(str2, "defgsf"); - concurrency::streams::container_buffer buffer; - VERIFY_ARE_EQUAL(0, is.read_to_end(buffer).get()); - VERIFY_IS_TRUE(is.is_eof()); - VERIFY_IS_TRUE(is.is_open()); + is.close().get(); + } - is.close().wait(); -} + TEST(stdio_istream_error) + { + std::ifstream inFile; + inFile.open("stdio_istream_error.txt"); + concurrency::streams::stdio_istream is(inFile); -TEST(stdio_istream_setstate) -{ - std::ifstream inFile; - inFile.open("stdio_istream_setstate.txt"); - concurrency::streams::stdio_istream is(inFile); - inFile.setstate(std::ios::failbit); + concurrency::streams::container_buffer buffer; + VERIFY_ARE_EQUAL(0, is.read_to_end(buffer).get()); + VERIFY_IS_TRUE(is.is_eof()); + VERIFY_IS_TRUE(is.is_open()); - concurrency::streams::container_buffer buffer; - VERIFY_ARE_EQUAL(0, is.read_to_end(buffer).get()); - VERIFY_IS_TRUE(is.is_eof()); - VERIFY_IS_TRUE(is.is_open()); + is.close().wait(); + } - is.close().wait(); -} + TEST(stdio_istream_setstate) + { + std::ifstream inFile; + inFile.open("stdio_istream_setstate.txt"); + concurrency::streams::stdio_istream is(inFile); + inFile.setstate(std::ios::failbit); -TEST(stdio_istream_close) -{ - std::ifstream inFile; - inFile.open("stdio_istream_close.txt"); - concurrency::streams::stdio_istream is(inFile); - inFile.close(); - - concurrency::streams::container_buffer buffer; - VERIFY_ARE_EQUAL(0, is.read_to_end(buffer).get()); - // Won't fix bug TFS 639208 - // VERIFY_IS_FALSE(is.is_open()); - VERIFY_IS_TRUE(is.is_eof()); -} + concurrency::streams::container_buffer buffer; + VERIFY_ARE_EQUAL(0, is.read_to_end(buffer).get()); + VERIFY_IS_TRUE(is.is_eof()); + VERIFY_IS_TRUE(is.is_open()); -TEST(sync_on_async_close_early) -{ - concurrency::streams::container_buffer buffer; - concurrency::streams::async_ostream os(buffer); - buffer.close(); + is.close().wait(); + } - os << 10 << std::endl; - VERIFY_IS_TRUE((std::ios::badbit & os.rdstate()) == std::ios::badbit); -} + TEST(stdio_istream_close) + { + std::ifstream inFile; + inFile.open("stdio_istream_close.txt"); + concurrency::streams::stdio_istream is(inFile); + inFile.close(); + + concurrency::streams::container_buffer buffer; + VERIFY_ARE_EQUAL(0, is.read_to_end(buffer).get()); + // Won't fix bug TFS 639208 + // VERIFY_IS_FALSE(is.is_open()); + VERIFY_IS_TRUE(is.is_eof()); + } -TEST(sync_on_async_close_with_exception) -{ - const std::string &data("abc123"); - - // Try with a read. + TEST(sync_on_async_close_early) { - concurrency::streams::container_buffer buffer(data); - concurrency::streams::async_istream inputStream(buffer); - buffer.close(std::ios::in, std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); - const size_t tempBufSize = 4; - char tempBuf[tempBufSize]; - inputStream.read(&tempBuf[0], tempBufSize); - VERIFY_ARE_EQUAL(std::ios::failbit | std::ios::eofbit, inputStream.rdstate()); + concurrency::streams::container_buffer buffer; + concurrency::streams::async_ostream os(buffer); + buffer.close(); + + os << 10 << std::endl; + VERIFY_IS_TRUE((std::ios::badbit & os.rdstate()) == std::ios::badbit); } - // Try with a write. + TEST(sync_on_async_close_with_exception) { - concurrency::streams::container_buffer buffer(data); - concurrency::streams::async_ostream outputStream(buffer); - buffer.close(std::ios::in, std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); - const size_t tempBufSize = 4; - char tempBuf[tempBufSize]; - outputStream.write(&tempBuf[0], tempBufSize); - VERIFY_ARE_EQUAL(std::ios::badbit, outputStream.rdstate()); + const std::string& data("abc123"); + + // Try with a read. + { + concurrency::streams::container_buffer buffer(data); + concurrency::streams::async_istream inputStream(buffer); + buffer.close(std::ios::in, std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); + const size_t tempBufSize = 4; + char tempBuf[tempBufSize]; + inputStream.read(&tempBuf[0], tempBufSize); + VERIFY_ARE_EQUAL(std::ios::failbit | std::ios::eofbit, inputStream.rdstate()); + } + + // Try with a write. + { + concurrency::streams::container_buffer buffer(data); + concurrency::streams::async_ostream outputStream(buffer); + buffer.close(std::ios::in, std::make_exception_ptr(std::invalid_argument("test exception"))).wait(); + const size_t tempBufSize = 4; + char tempBuf[tempBufSize]; + outputStream.write(&tempBuf[0], tempBufSize); + VERIFY_ARE_EQUAL(std::ios::badbit, outputStream.rdstate()); + } } -} #if (!defined(_WIN32) || !defined(CPPREST_EXCLUDE_WEBSOCKETS)) && !defined(__cplusplus_winrt) -TEST(ostream_full_throw_exception) -{ - char tgt_buffer[5]; - boost::interprocess::bufferstream limited_stream(tgt_buffer, sizeof(tgt_buffer), - ::std::ios_base::out | std::ios_base::binary); - concurrency::streams::stdio_ostream os_wrapper(limited_stream); - concurrency::streams::streambuf os_streambuf = os_wrapper.streambuf(); - + TEST(ostream_full_throw_exception) + { + char tgt_buffer[5]; + boost::interprocess::bufferstream limited_stream( + tgt_buffer, sizeof(tgt_buffer), ::std::ios_base::out | std::ios_base::binary); + concurrency::streams::stdio_ostream os_wrapper(limited_stream); + concurrency::streams::streambuf os_streambuf = os_wrapper.streambuf(); - // There's one newline in the input. - const char *text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; + // There's one newline in the input. + const char* text = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ"; - std::stringstream stream; - Concurrency::streams::stdio_istream astream(stream); + std::stringstream stream; + Concurrency::streams::stdio_istream astream(stream); - stream << text; + stream << text; - VERIFY_THROWS(astream.read_to_end(os_streambuf).get(), std::exception); -} + VERIFY_THROWS(astream.read_to_end(os_streambuf).get(), std::exception); + } #endif - } -}}} - +} // namespace streams +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/streams/streams_tests.h b/Release/tests/functional/streams/streams_tests.h index 96b3f67a2f..a7f02f76e4 100644 --- a/Release/tests/functional/streams/streams_tests.h +++ b/Release/tests/functional/streams/streams_tests.h @@ -1,33 +1,39 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* streams_tests.h -* -* Common routines for streams tests. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * streams_tests.h + * + * Common routines for streams tests. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include +#include -namespace tests { namespace functional { namespace streams { - +namespace tests +{ +namespace functional +{ +namespace streams +{ template void test_stream_length(concurrency::streams::basic_istream istr, size_t length) { using namespace concurrency::streams; - + auto curr = istr.tell(); auto t1 = (curr != static_cast::pos_type>(basic_istream::traits::eof())); VERIFY_IS_TRUE(t1); auto end = istr.seek(0, std::ios_base::end); - VERIFY_IS_TRUE(end != static_cast::pos_type>(basic_istream::traits::eof())); + VERIFY_IS_TRUE(end != + static_cast::pos_type>(basic_istream::traits::eof())); auto len = end - curr; @@ -35,10 +41,12 @@ void test_stream_length(concurrency::streams::basic_istream istr, size { auto curr2 = istr.tell(); - VERIFY_IS_TRUE(curr != static_cast::pos_type>(basic_istream::traits::eof())); + VERIFY_IS_TRUE(curr != + static_cast::pos_type>(basic_istream::traits::eof())); auto end2 = istr.seek(0, std::ios_base::end); - VERIFY_IS_TRUE(end != static_cast::pos_type>(basic_istream::traits::eof())); + VERIFY_IS_TRUE(end != + static_cast::pos_type>(basic_istream::traits::eof())); auto len2 = end2 - curr2; @@ -46,32 +54,35 @@ void test_stream_length(concurrency::streams::basic_istream istr, size } auto newpos = istr.seek(curr); - VERIFY_IS_TRUE(newpos != static_cast::pos_type>(basic_istream::traits::eof())); + VERIFY_IS_TRUE(newpos != + static_cast::pos_type>(basic_istream::traits::eof())); VERIFY_ARE_EQUAL(curr, newpos); } // Helper function to verify std::system_error is thrown with correct error code -#define VERIFY_THROWS_SYSTEM_ERROR(__expression, __code) \ - UNITTEST_MULTILINE_MACRO_BEGIN \ - try \ - { \ - __expression; \ - VERIFY_IS_TRUE(false, "Expected std::system_error not thrown"); \ - } \ - catch (const std::system_error &_exc) \ - { \ - VERIFY_IS_TRUE(std::string(_exc.what()).size() > 0); \ - /* The reason we can't directly compare with the given std::errc code is because*/ \ - /* on Windows the STL implementation of error categories are NOT unique across*/ \ - /* dll boundaries.*/ \ - const std::error_condition _condFound = _exc.code().default_error_condition(); \ - VERIFY_ARE_EQUAL(static_cast(__code), _condFound.value()); \ - } \ - catch(...) \ - { \ - VERIFY_IS_TRUE(false, "Exception other than std::system_error thrown"); \ - } \ +#define VERIFY_THROWS_SYSTEM_ERROR(__expression, __code) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + try \ + { \ + __expression; \ + VERIFY_IS_TRUE(false, "Expected std::system_error not thrown"); \ + } \ + catch (const std::system_error& _exc) \ + { \ + VERIFY_IS_TRUE(std::string(_exc.what()).size() > 0); \ + /* The reason we can't directly compare with the given std::errc code is because*/ \ + /* on Windows the STL implementation of error categories are NOT unique across*/ \ + /* dll boundaries.*/ \ + const std::error_condition _condFound = _exc.code().default_error_condition(); \ + VERIFY_ARE_EQUAL(static_cast(__code), _condFound.value()); \ + } \ + catch (...) \ + { \ + VERIFY_IS_TRUE(false, "Exception other than std::system_error thrown"); \ + } \ UNITTEST_MULTILINE_MACRO_END -}}} +} // namespace streams +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/streams/winrt_interop_tests.cpp b/Release/tests/functional/streams/winrt_interop_tests.cpp index a3a97e7e73..8781c0511d 100644 --- a/Release/tests/functional/streams/winrt_interop_tests.cpp +++ b/Release/tests/functional/streams/winrt_interop_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Basic tests for winrt interop streams. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Basic tests for winrt interop streams. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace concurrency::streams; @@ -18,235 +18,241 @@ using namespace ::pplx; using namespace Windows::Storage; #endif -namespace tests { namespace functional { namespace streams { - -SUITE(winrt_interop_tests) +namespace tests { - -TEST(read_in) +namespace functional { - producer_consumer_buffer buf; - auto ostream = buf.create_ostream(); - std::string strData("abcdefghij"); - buf.putn_nocopy((char *)&strData[0], strData.size() * sizeof(char)).wait(); - - auto dr = ref new Windows::Storage::Streams::DataReader(winrt_stream::create_input_stream(buf)); - dr->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; - - { - VERIFY_ARE_EQUAL(10, pplx::create_task(dr->LoadAsync(10)).get()); - - auto value = dr->ReadString(5); - VERIFY_ARE_EQUAL(utility::string_t(value->Data()), U("abcde")); - value = dr->ReadString(5); - VERIFY_ARE_EQUAL(utility::string_t(value->Data()), U("fghij")); - } +namespace streams +{ +SUITE(winrt_interop_tests) +{ + TEST(read_in) { - ostream.write(char(11)).wait(); - ostream.write(char(17)).wait(); + producer_consumer_buffer buf; + auto ostream = buf.create_ostream(); + std::string strData("abcdefghij"); + buf.putn_nocopy((char*)&strData[0], strData.size() * sizeof(char)).wait(); - VERIFY_ARE_EQUAL(2, pplx::create_task(dr->LoadAsync(2)).get()); + auto dr = ref new Windows::Storage::Streams::DataReader(winrt_stream::create_input_stream(buf)); + dr->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; - auto ival = dr->ReadByte(); - VERIFY_ARE_EQUAL(ival, 11); - ival = dr->ReadByte(); - VERIFY_ARE_EQUAL(ival, 17); - } - { - for (int i = 0; i < 100; i++) { - ostream.write(char(i)).wait(); - } + VERIFY_ARE_EQUAL(10, pplx::create_task(dr->LoadAsync(10)).get()); - VERIFY_ARE_EQUAL(100, pplx::create_task(dr->LoadAsync(100)).get()); + auto value = dr->ReadString(5); + VERIFY_ARE_EQUAL(utility::string_t(value->Data()), U("abcde")); + value = dr->ReadString(5); + VERIFY_ARE_EQUAL(utility::string_t(value->Data()), U("fghij")); + } + { + ostream.write(char(11)).wait(); + ostream.write(char(17)).wait(); - auto arr = ref new Platform::Array(100); - dr->ReadBytes(arr); + VERIFY_ARE_EQUAL(2, pplx::create_task(dr->LoadAsync(2)).get()); - for (int i = 0; i < 100; i++) - { - VERIFY_ARE_EQUAL(arr[i], i); + auto ival = dr->ReadByte(); + VERIFY_ARE_EQUAL(ival, 11); + ival = dr->ReadByte(); + VERIFY_ARE_EQUAL(ival, 17); } - } - buf.close(std::ios_base::out); -} + { + for (int i = 0; i < 100; i++) + { + ostream.write(char(i)).wait(); + } -TEST(read_rand) -{ - producer_consumer_buffer buf; - auto ostream = buf.create_ostream(); - std::string strData("abcdefghij"); - buf.putn_nocopy((char *)&strData[0], strData.size() * sizeof(char)).wait(); + VERIFY_ARE_EQUAL(100, pplx::create_task(dr->LoadAsync(100)).get()); - auto dr = ref new Windows::Storage::Streams::DataReader(winrt_stream::create_random_access_stream(buf)); - dr->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; + auto arr = ref new Platform::Array(100); + dr->ReadBytes(arr); - { - VERIFY_ARE_EQUAL(10, pplx::create_task(dr->LoadAsync(10)).get()); - - auto value = dr->ReadString(5); - VERIFY_ARE_EQUAL(utility::string_t(value->Data()), U("abcde")); - value = dr->ReadString(5); - VERIFY_ARE_EQUAL(utility::string_t(value->Data()), U("fghij")); + for (int i = 0; i < 100; i++) + { + VERIFY_ARE_EQUAL(arr[i], i); + } + } + buf.close(std::ios_base::out); } + + TEST(read_rand) { - ostream.write(char(11)).wait(); - ostream.write(char(17)).wait(); + producer_consumer_buffer buf; + auto ostream = buf.create_ostream(); + std::string strData("abcdefghij"); + buf.putn_nocopy((char*)&strData[0], strData.size() * sizeof(char)).wait(); - VERIFY_ARE_EQUAL(2, pplx::create_task(dr->LoadAsync(2)).get()); + auto dr = ref new Windows::Storage::Streams::DataReader(winrt_stream::create_random_access_stream(buf)); + dr->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; - auto ival = dr->ReadByte(); - VERIFY_ARE_EQUAL(ival, 11); - ival = dr->ReadByte(); - VERIFY_ARE_EQUAL(ival, 17); - } - { - for (int i = 0; i < 100; i++) { - ostream.write(char(i)).wait(); + VERIFY_ARE_EQUAL(10, pplx::create_task(dr->LoadAsync(10)).get()); + + auto value = dr->ReadString(5); + VERIFY_ARE_EQUAL(utility::string_t(value->Data()), U("abcde")); + value = dr->ReadString(5); + VERIFY_ARE_EQUAL(utility::string_t(value->Data()), U("fghij")); } + { + ostream.write(char(11)).wait(); + ostream.write(char(17)).wait(); - VERIFY_ARE_EQUAL(100, pplx::create_task(dr->LoadAsync(100)).get()); - auto arr = ref new Platform::Array(100); - dr->ReadBytes(arr); + VERIFY_ARE_EQUAL(2, pplx::create_task(dr->LoadAsync(2)).get()); - for (int i = 0; i < 100; i++) + auto ival = dr->ReadByte(); + VERIFY_ARE_EQUAL(ival, 11); + ival = dr->ReadByte(); + VERIFY_ARE_EQUAL(ival, 17); + } { - VERIFY_ARE_EQUAL(arr[i], i); + for (int i = 0; i < 100; i++) + { + ostream.write(char(i)).wait(); + } + + VERIFY_ARE_EQUAL(100, pplx::create_task(dr->LoadAsync(100)).get()); + auto arr = ref new Platform::Array(100); + dr->ReadBytes(arr); + + for (int i = 0; i < 100; i++) + { + VERIFY_ARE_EQUAL(arr[i], i); + } } + buf.close(std::ios_base::out); } - buf.close(std::ios_base::out); -} -pplx::task StoreAndFlush(Windows::Storage::Streams::DataWriter^ dw) -{ - return pplx::create_task(dw->StoreAsync()). - then([dw](unsigned int) { return pplx::create_task(dw->FlushAsync()); }); -} + pplx::task StoreAndFlush(Windows::Storage::Streams::DataWriter ^ dw) + { + return pplx::create_task(dw->StoreAsync()).then([dw](unsigned int) { + return pplx::create_task(dw->FlushAsync()); + }); + } -TEST(write_out) -{ - producer_consumer_buffer buf; - - auto dw = ref new Windows::Storage::Streams::DataWriter(winrt_stream::create_output_stream(buf)); - dw->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; - - auto value = ref new ::Platform::String(U("10 4711 -10.0 hello!")); - dw->WriteString(value); - dw->WriteByte(11); // Take care to make this a non-character! - dw->WriteUInt16(17); - dw->WriteUInt32(4711); - VERIFY_IS_TRUE(StoreAndFlush(dw).get()); - buf.close(std::ios_base::out); - - auto istream = buf.create_istream(); - VERIFY_ARE_EQUAL(10, istream.extract().get()); - VERIFY_ARE_EQUAL(4711, istream.extract().get()); - VERIFY_ARE_EQUAL(-10.0, istream.extract().get()); - VERIFY_ARE_EQUAL(utility::string_t(U("hello!")), istream.extract().get()); - VERIFY_ARE_EQUAL(11, istream.read().get()); - uint16_t int16; - buf.getn((char *)&int16, sizeof(int16)).wait(); - VERIFY_ARE_EQUAL(17, int16); - uint32_t int32; - buf.getn((char *)&int32, sizeof(int32)).wait(); - VERIFY_ARE_EQUAL(4711, int32); -} - -TEST(write_rand) -{ - producer_consumer_buffer buf; - - auto dw = ref new Windows::Storage::Streams::DataWriter(winrt_stream::create_random_access_stream(buf)); - dw->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; - - auto value = ref new ::Platform::String(U("10 4711 -10.0 hello!")); - dw->WriteString(value); - dw->WriteByte(11); // Take care to make this a non-character! - dw->WriteUInt16(17); - dw->WriteUInt32(4711); - VERIFY_IS_TRUE(StoreAndFlush(dw).get()); - buf.close(std::ios_base::out); - - auto istream = buf.create_istream(); - VERIFY_ARE_EQUAL(10, istream.extract().get()); - VERIFY_ARE_EQUAL(4711, istream.extract().get()); - VERIFY_ARE_EQUAL(-10.0, istream.extract().get()); - VERIFY_ARE_EQUAL(utility::string_t(U("hello!")), istream.extract().get()); - VERIFY_ARE_EQUAL(11, istream.read().get()); - uint16_t int16; - buf.getn((char *)&int16, sizeof(int16)).wait(); - VERIFY_ARE_EQUAL(17, int16); - uint32_t int32; - buf.getn((char *)&int32, sizeof(int32)).wait(); - VERIFY_ARE_EQUAL(4711, int32); -} - -TEST(read_write_attributes) -{ + TEST(write_out) { - container_buffer buf("test data"); - auto rastr = winrt_stream::create_random_access_stream(buf); - VERIFY_IS_TRUE(rastr->CanRead); - VERIFY_IS_FALSE(rastr->CanWrite); - VERIFY_ARE_EQUAL(rastr->Position, 0); - - VERIFY_ARE_EQUAL(rastr->Size, 9); - rastr->Size = 1024U; - VERIFY_ARE_EQUAL(rastr->Size, 9); + producer_consumer_buffer buf; + + auto dw = ref new Windows::Storage::Streams::DataWriter(winrt_stream::create_output_stream(buf)); + dw->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; + + auto value = ref new ::Platform::String(U("10 4711 -10.0 hello!")); + dw->WriteString(value); + dw->WriteByte(11); // Take care to make this a non-character! + dw->WriteUInt16(17); + dw->WriteUInt32(4711); + VERIFY_IS_TRUE(StoreAndFlush(dw).get()); + buf.close(std::ios_base::out); + + auto istream = buf.create_istream(); + VERIFY_ARE_EQUAL(10, istream.extract().get()); + VERIFY_ARE_EQUAL(4711, istream.extract().get()); + VERIFY_ARE_EQUAL(-10.0, istream.extract().get()); + VERIFY_ARE_EQUAL(utility::string_t(U("hello!")), istream.extract().get()); + VERIFY_ARE_EQUAL(11, istream.read().get()); + uint16_t int16; + buf.getn((char*)&int16, sizeof(int16)).wait(); + VERIFY_ARE_EQUAL(17, int16); + uint32_t int32; + buf.getn((char*)&int32, sizeof(int32)).wait(); + VERIFY_ARE_EQUAL(4711, int32); } + + TEST(write_rand) { - container_buffer buf; - auto rastr = winrt_stream::create_random_access_stream(buf); - VERIFY_IS_FALSE(rastr->CanRead); - VERIFY_IS_TRUE(rastr->CanWrite); - VERIFY_ARE_EQUAL(rastr->Position, 0); - - VERIFY_ARE_EQUAL(rastr->Size, 0); - rastr->Size = 1024U; - VERIFY_ARE_EQUAL(rastr->Size, 1024U); - VERIFY_ARE_EQUAL(buf.collection().size(), 1024U); + producer_consumer_buffer buf; + + auto dw = ref new Windows::Storage::Streams::DataWriter(winrt_stream::create_random_access_stream(buf)); + dw->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; + + auto value = ref new ::Platform::String(U("10 4711 -10.0 hello!")); + dw->WriteString(value); + dw->WriteByte(11); // Take care to make this a non-character! + dw->WriteUInt16(17); + dw->WriteUInt32(4711); + VERIFY_IS_TRUE(StoreAndFlush(dw).get()); + buf.close(std::ios_base::out); + + auto istream = buf.create_istream(); + VERIFY_ARE_EQUAL(10, istream.extract().get()); + VERIFY_ARE_EQUAL(4711, istream.extract().get()); + VERIFY_ARE_EQUAL(-10.0, istream.extract().get()); + VERIFY_ARE_EQUAL(utility::string_t(U("hello!")), istream.extract().get()); + VERIFY_ARE_EQUAL(11, istream.read().get()); + uint16_t int16; + buf.getn((char*)&int16, sizeof(int16)).wait(); + VERIFY_ARE_EQUAL(17, int16); + uint32_t int32; + buf.getn((char*)&int32, sizeof(int32)).wait(); + VERIFY_ARE_EQUAL(4711, int32); } + + TEST(read_write_attributes) { - producer_consumer_buffer buf; - auto rastr = winrt_stream::create_random_access_stream(buf); - VERIFY_IS_TRUE(rastr->CanRead); - VERIFY_IS_TRUE(rastr->CanWrite); - VERIFY_ARE_EQUAL(rastr->Position, 0); - - VERIFY_ARE_EQUAL(rastr->Size, 0); - rastr->Size = 1024U; - VERIFY_ARE_EQUAL(rastr->Size, 1024U); + { + container_buffer buf("test data"); + auto rastr = winrt_stream::create_random_access_stream(buf); + VERIFY_IS_TRUE(rastr->CanRead); + VERIFY_IS_FALSE(rastr->CanWrite); + VERIFY_ARE_EQUAL(rastr->Position, 0); + + VERIFY_ARE_EQUAL(rastr->Size, 9); + rastr->Size = 1024U; + VERIFY_ARE_EQUAL(rastr->Size, 9); + } + { + container_buffer buf; + auto rastr = winrt_stream::create_random_access_stream(buf); + VERIFY_IS_FALSE(rastr->CanRead); + VERIFY_IS_TRUE(rastr->CanWrite); + VERIFY_ARE_EQUAL(rastr->Position, 0); + + VERIFY_ARE_EQUAL(rastr->Size, 0); + rastr->Size = 1024U; + VERIFY_ARE_EQUAL(rastr->Size, 1024U); + VERIFY_ARE_EQUAL(buf.collection().size(), 1024U); + } + { + producer_consumer_buffer buf; + auto rastr = winrt_stream::create_random_access_stream(buf); + VERIFY_IS_TRUE(rastr->CanRead); + VERIFY_IS_TRUE(rastr->CanWrite); + VERIFY_ARE_EQUAL(rastr->Position, 0); + + VERIFY_ARE_EQUAL(rastr->Size, 0); + rastr->Size = 1024U; + VERIFY_ARE_EQUAL(rastr->Size, 1024U); + } } -} -TEST(cant_write) -{ - container_buffer buf("test data"); + TEST(cant_write) + { + container_buffer buf("test data"); - auto ostr = winrt_stream::create_output_stream(buf); - auto dw = ref new Windows::Storage::Streams::DataWriter(ostr); - dw->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; + auto ostr = winrt_stream::create_output_stream(buf); + auto dw = ref new Windows::Storage::Streams::DataWriter(ostr); + dw->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; - auto value = ref new ::Platform::String(U("10 4711 -10.0 hello!")); - dw->WriteString(value); + auto value = ref new ::Platform::String(U("10 4711 -10.0 hello!")); + dw->WriteString(value); - VERIFY_IS_FALSE(StoreAndFlush(dw).get()); -} + VERIFY_IS_FALSE(StoreAndFlush(dw).get()); + } -TEST(cant_read) -{ - container_buffer buf; - auto ostream = buf.create_ostream(); - ostream.print(10); + TEST(cant_read) + { + container_buffer buf; + auto ostream = buf.create_ostream(); + ostream.print(10); - auto istr = winrt_stream::create_input_stream(buf); - auto dr = ref new Windows::Storage::Streams::DataReader(istr); - dr->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; + auto istr = winrt_stream::create_input_stream(buf); + auto dr = ref new Windows::Storage::Streams::DataReader(istr); + dr->ByteOrder = Windows::Storage::Streams::ByteOrder::LittleEndian; - VERIFY_ARE_EQUAL(0, pplx::create_task(dr->LoadAsync(2)).get()); -} + VERIFY_ARE_EQUAL(0, pplx::create_task(dr->LoadAsync(2)).get()); + } } // SUITE -}}} // namespaces \ No newline at end of file +} // namespace streams +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/accessor_tests.cpp b/Release/tests/functional/uri/accessor_tests.cpp index f6012a5a91..e540fb3278 100644 --- a/Release/tests/functional/uri/accessor_tests.cpp +++ b/Release/tests/functional/uri/accessor_tests.cpp @@ -1,50 +1,55 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* constructor_string_tests.cpp -* -* Tests for constructors of the uri class -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * constructor_string_tests.cpp + * + * Tests for constructors of the uri class + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; using namespace utility; -namespace tests { namespace functional { namespace uri_tests { - -SUITE(accessor_tests) +namespace tests { - -TEST(authority_string) +namespace functional { - uri u(U("http://testname.com:81/path?baz")); - uri a = u.authority(); - - VERIFY_ARE_EQUAL(U("/path"), u.path()); - VERIFY_ARE_EQUAL(U("http"), a.scheme()); - VERIFY_ARE_EQUAL(U("testname.com"), a.host()); - VERIFY_ARE_EQUAL(81, a.port()); - VERIFY_ARE_EQUAL(uri(U("http://testname.com:81")), a); -} - -TEST(authority_wstring) +namespace uri_tests { - uri u(U("http://testname.com:81/path?baz")); - uri a = u.authority(); - - VERIFY_ARE_EQUAL(U("/path"), u.path()); - VERIFY_ARE_EQUAL(U("http"), a.scheme()); - VERIFY_ARE_EQUAL(U("testname.com"), a.host()); - VERIFY_ARE_EQUAL(81, a.port()); - VERIFY_ARE_EQUAL(uri(U("http://testname.com:81")), a); -} +SUITE(accessor_tests) +{ + TEST(authority_string) + { + uri u(U("http://testname.com:81/path?baz")); + uri a = u.authority(); + + VERIFY_ARE_EQUAL(U("/path"), u.path()); + VERIFY_ARE_EQUAL(U("http"), a.scheme()); + VERIFY_ARE_EQUAL(U("testname.com"), a.host()); + VERIFY_ARE_EQUAL(81, a.port()); + VERIFY_ARE_EQUAL(uri(U("http://testname.com:81")), a); + } + + TEST(authority_wstring) + { + uri u(U("http://testname.com:81/path?baz")); + uri a = u.authority(); + + VERIFY_ARE_EQUAL(U("/path"), u.path()); + VERIFY_ARE_EQUAL(U("http"), a.scheme()); + VERIFY_ARE_EQUAL(U("testname.com"), a.host()); + VERIFY_ARE_EQUAL(81, a.port()); + VERIFY_ARE_EQUAL(uri(U("http://testname.com:81")), a); + } } // SUITE(accessor_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/combining_tests.cpp b/Release/tests/functional/uri/combining_tests.cpp index 0afa381375..0860052526 100644 --- a/Release/tests/functional/uri/combining_tests.cpp +++ b/Release/tests/functional/uri/combining_tests.cpp @@ -1,84 +1,89 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* combining_tests.cpp -* -* Tests for appending/combining features of the http::uri class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * combining_tests.cpp + * + * Tests for appending/combining features of the http::uri class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; using namespace utility; -namespace tests { namespace functional { namespace uri_tests { - -SUITE(combining_tests) -{ - -TEST(append_path) -{ - utility::string_t uri_str = U("http://testname.com/path?baz"); - uri_builder ub(uri_str); - uri combined = ub.append_path(U("/baz")).to_uri(); - - VERIFY_ARE_EQUAL(uri(U("http://testname.com/path/baz?baz")), combined); -} - -TEST(append_empty_path) +namespace tests { - utility::string_t uri_str(U("http://fakeuri.net")); - uri u = uri_str; - uri_builder ub(u); - uri combined = ub.append_path(U("")).to_uri(); - - VERIFY_ARE_EQUAL(u, combined); -} - -TEST(append_query) +namespace functional { - utility::string_t uri_str(U("http://testname.com/path1?key1=value2")); - uri_builder ub(uri_str); - uri combined = ub.append_query(uri(U("http://testname2.com/path2?key2=value3")).query()).to_uri(); - - VERIFY_ARE_EQUAL(U("http://testname.com/path1?key1=value2&key2=value3"), combined.to_string()); -} - -TEST(append_empty_query) +namespace uri_tests { - utility::string_t uri_str(U("http://fakeuri.org/?key=value")); - uri u(uri_str); - uri_builder ub(u); - uri combined = ub.append_query(U("")).to_uri(); - - VERIFY_ARE_EQUAL(u, combined); -} - -TEST(append) -{ - utility::string_t uri_str(U("http://testname.com/path1?key1=value2")); - uri_builder ub(uri_str); - uri combined = ub.append(U("http://testname2.com/path2?key2=value3")).to_uri(); - - VERIFY_ARE_EQUAL(U("http://testname.com/path1/path2?key1=value2&key2=value3"), combined.to_string()); - VERIFY_ARE_EQUAL(U("/path1/path2?key1=value2&key2=value3"), combined.resource().to_string()); -} - -TEST(append_empty) +SUITE(combining_tests) { - utility::string_t uri_str(U("http://myhost.com")); - uri u(uri_str); - uri_builder ub(u); - uri combined = ub.append(U("")).to_uri(); - - VERIFY_ARE_EQUAL(u, combined); -} + TEST(append_path) + { + utility::string_t uri_str = U("http://testname.com/path?baz"); + uri_builder ub(uri_str); + uri combined = ub.append_path(U("/baz")).to_uri(); + + VERIFY_ARE_EQUAL(uri(U("http://testname.com/path/baz?baz")), combined); + } + + TEST(append_empty_path) + { + utility::string_t uri_str(U("http://fakeuri.net")); + uri u = uri_str; + uri_builder ub(u); + uri combined = ub.append_path(U("")).to_uri(); + + VERIFY_ARE_EQUAL(u, combined); + } + + TEST(append_query) + { + utility::string_t uri_str(U("http://testname.com/path1?key1=value2")); + uri_builder ub(uri_str); + uri combined = ub.append_query(uri(U("http://testname2.com/path2?key2=value3")).query()).to_uri(); + + VERIFY_ARE_EQUAL(U("http://testname.com/path1?key1=value2&key2=value3"), combined.to_string()); + } + + TEST(append_empty_query) + { + utility::string_t uri_str(U("http://fakeuri.org/?key=value")); + uri u(uri_str); + uri_builder ub(u); + uri combined = ub.append_query(U("")).to_uri(); + + VERIFY_ARE_EQUAL(u, combined); + } + + TEST(append) + { + utility::string_t uri_str(U("http://testname.com/path1?key1=value2")); + uri_builder ub(uri_str); + uri combined = ub.append(U("http://testname2.com/path2?key2=value3")).to_uri(); + + VERIFY_ARE_EQUAL(U("http://testname.com/path1/path2?key1=value2&key2=value3"), combined.to_string()); + VERIFY_ARE_EQUAL(U("/path1/path2?key1=value2&key2=value3"), combined.resource().to_string()); + } + + TEST(append_empty) + { + utility::string_t uri_str(U("http://myhost.com")); + uri u(uri_str); + uri_builder ub(u); + uri combined = ub.append(U("")).to_uri(); + + VERIFY_ARE_EQUAL(u, combined); + } } // SUITE(combining_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/constructor_tests.cpp b/Release/tests/functional/uri/constructor_tests.cpp index a300c68f80..ea6041c26a 100644 --- a/Release/tests/functional/uri/constructor_tests.cpp +++ b/Release/tests/functional/uri/constructor_tests.cpp @@ -1,260 +1,262 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* constructor_tests.cpp -* -* Tests for constructors of the uri class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * constructor_tests.cpp + * + * Tests for constructors of the uri class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; using namespace utility; -namespace tests { namespace functional { namespace uri_tests { - -SUITE(constructor_tests) -{ - -TEST(parsing_constructor_char) -{ - uri u(uri::encode_uri(U("net.tcp://steve:@testname.com:81/bleh%?qstring#goo"))); - - VERIFY_ARE_EQUAL(U("net.tcp"), u.scheme()); - VERIFY_ARE_EQUAL(U("steve:"), u.user_info()); - VERIFY_ARE_EQUAL(U("testname.com"), u.host()); - VERIFY_ARE_EQUAL(81, u.port()); - VERIFY_ARE_EQUAL(U("/bleh%25"), u.path()); - VERIFY_ARE_EQUAL(U("qstring"), u.query()); - VERIFY_ARE_EQUAL(U("goo"), u.fragment()); -} - -TEST(parsing_constructor_encoded_string) -{ - uri u(uri::encode_uri(U("net.tcp://testname.com:81/bleh%?qstring#goo"))); - - VERIFY_ARE_EQUAL(U("net.tcp"), u.scheme()); - VERIFY_ARE_EQUAL(U("testname.com"), u.host()); - VERIFY_ARE_EQUAL(81, u.port()); - VERIFY_ARE_EQUAL(U("/bleh%25"), u.path()); - VERIFY_ARE_EQUAL(U("qstring"), u.query()); - VERIFY_ARE_EQUAL(U("goo"), u.fragment()); -} - -TEST(parsing_constructor_string_string) -{ - uri u(uri::encode_uri(U("net.tcp://testname.com:81/bleh%?qstring#goo"))); - - VERIFY_ARE_EQUAL(U("net.tcp"), u.scheme()); - VERIFY_ARE_EQUAL(U("testname.com"), u.host()); - VERIFY_ARE_EQUAL(81, u.port()); - VERIFY_ARE_EQUAL(U("/bleh%25"), u.path()); - VERIFY_ARE_EQUAL(U("qstring"), u.query()); - VERIFY_ARE_EQUAL(U("goo"), u.fragment()); -} - -TEST(empty_strings) -{ - VERIFY_IS_TRUE(uri(U("")).is_empty()); - VERIFY_IS_TRUE(uri(U("")).is_empty()); - VERIFY_IS_TRUE(uri(uri::encode_uri(U(""))).is_empty()); -} - -TEST(default_constructor) -{ - VERIFY_IS_TRUE(uri().is_empty()); -} - -TEST(relative_ref_string) -{ - uri u(uri::encode_uri(U("first/second#boff"))); - - VERIFY_ARE_EQUAL(U(""), u.scheme()); - VERIFY_ARE_EQUAL(U(""), u.host()); - VERIFY_ARE_EQUAL(0, u.port()); - VERIFY_ARE_EQUAL(U("first/second"), u.path()); - VERIFY_ARE_EQUAL(U(""), u.query()); - VERIFY_ARE_EQUAL(U("boff"), u.fragment()); -} - -TEST(absolute_ref_string) -{ - uri u(uri::encode_uri(U("/first/second#boff"))); - - VERIFY_ARE_EQUAL(U(""), u.scheme()); - VERIFY_ARE_EQUAL(U(""), u.host()); - VERIFY_ARE_EQUAL(0, u.port()); - VERIFY_ARE_EQUAL(U("/first/second"), u.path()); - VERIFY_ARE_EQUAL(U(""), u.query()); - VERIFY_ARE_EQUAL(U("boff"), u.fragment()); -} - -TEST(copy_constructor) -{ - uri original(U("http://st:pass@localhost:456/path1?qstring#goo")); - uri new_uri(original); - - VERIFY_ARE_EQUAL(original, new_uri); -} - -TEST(move_constructor) +namespace tests { - const utility::string_t uri_str(U("http://localhost:456/path1?qstring#goo")); - uri original(uri_str); - uri new_uri = std::move(original); - - VERIFY_ARE_EQUAL(uri_str, new_uri.to_string()); - VERIFY_ARE_EQUAL(uri(uri_str), new_uri); -} - -TEST(assignment_operator) -{ - uri original(U("http://localhost:456/path?qstring#goo")); - uri new_uri = original; - - VERIFY_ARE_EQUAL(original, new_uri); -} - -// Tests invalid URI being passed in constructor. -TEST(parsing_constructor_invalid) -{ - VERIFY_THROWS(uri(U("123http://localhost:345/")), uri_exception); - VERIFY_THROWS(uri(U("h*ttp://localhost:345/")), uri_exception); - VERIFY_THROWS(uri(U("http://localhost:345/\"")), uri_exception); - VERIFY_THROWS(uri(U("http://localhost:345/path?\"")), uri_exception); - VERIFY_THROWS(uri(U("http://local\"host:345/")), uri_exception); -} - -// Tests a variety of different URIs using the examples in RFC 2732 -TEST(RFC_2732_examples_string) +namespace functional { - // The URI parser will make characters lower case - uri http1(U("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html")); - VERIFY_ARE_EQUAL(U("http"), http1.scheme()); - VERIFY_ARE_EQUAL(U("[fedc:ba98:7654:3210:fedc:ba98:7654:3210]"), http1.host()); - VERIFY_ARE_EQUAL(80, http1.port()); - VERIFY_ARE_EQUAL(U("/index.html"), http1.path()); - VERIFY_ARE_EQUAL(U(""), http1.query()); - - uri http2(U("http://[1080:0:0:0:8:800:200C:417A]/index.html")); - VERIFY_ARE_EQUAL(U("http"), http2.scheme()); - VERIFY_ARE_EQUAL(U("[1080:0:0:0:8:800:200c:417a]"), http2.host()); - VERIFY_ARE_EQUAL(0, http2.port()); - VERIFY_ARE_EQUAL(U("/index.html"), http2.path()); - VERIFY_ARE_EQUAL(U(""), http2.query()); - - uri http3(U("https://[3ffe:2a00:100:7031::1]")); - VERIFY_ARE_EQUAL(U("https"), http3.scheme()); - VERIFY_ARE_EQUAL(U("[3ffe:2a00:100:7031::1]"), http3.host()); - VERIFY_ARE_EQUAL(0, http3.port()); - VERIFY_ARE_EQUAL(U("/"), http3.path()); - VERIFY_ARE_EQUAL(U(""), http3.query()); - - uri http4(U("http://[::192.9.5.5]/ipng")); - VERIFY_ARE_EQUAL(U("http"), http4.scheme()); - VERIFY_ARE_EQUAL(U("[::192.9.5.5]"), http4.host()); - VERIFY_ARE_EQUAL(0, http4.port()); - VERIFY_ARE_EQUAL(U("/ipng"), http4.path()); - VERIFY_ARE_EQUAL(U(""), http4.query()); - - uri http5(U("http://[1080::8:800:200C:417A]/foo")); - VERIFY_ARE_EQUAL(U("http"), http5.scheme()); - VERIFY_ARE_EQUAL(U("[1080::8:800:200c:417a]"), http5.host()); - VERIFY_ARE_EQUAL(0, http5.port()); - VERIFY_ARE_EQUAL(U("/foo"), http5.path()); - VERIFY_ARE_EQUAL(U(""), http5.query()); - - uri http6(U("http://[::FFFF:129.144.52.38]:80/index.html")); - VERIFY_ARE_EQUAL(U("http"), http6.scheme()); - VERIFY_ARE_EQUAL(U("[::ffff:129.144.52.38]"), http6.host()); - VERIFY_ARE_EQUAL(80, http6.port()); - VERIFY_ARE_EQUAL(U("/index.html"), http6.path()); - VERIFY_ARE_EQUAL(U(""), http6.query()); - - uri http7(U("http://[2010:836B:4179::836B:4179]")); - VERIFY_ARE_EQUAL(U("http"), http7.scheme()); - VERIFY_ARE_EQUAL(U("[2010:836b:4179::836b:4179]"), http7.host()); - VERIFY_ARE_EQUAL(0, http7.port()); - VERIFY_ARE_EQUAL(U("/"), http7.path()); - VERIFY_ARE_EQUAL(U(""), http7.query()); -} - -// Tests a variety of different URIs using the examples in RFC 3986. -TEST(RFC_3968_examples_string) +namespace uri_tests { - uri ftp(U("ftp://ftp.is.co.za/rfc/rfc1808.txt")); - VERIFY_ARE_EQUAL(U("ftp"), ftp.scheme()); - VERIFY_ARE_EQUAL(U(""), ftp.user_info()); - VERIFY_ARE_EQUAL(U("ftp.is.co.za"), ftp.host()); - VERIFY_ARE_EQUAL(0, ftp.port()); - VERIFY_ARE_EQUAL(U("/rfc/rfc1808.txt"), ftp.path()); - VERIFY_ARE_EQUAL(U(""), ftp.query()); - VERIFY_ARE_EQUAL(U(""), ftp.fragment()); - - // TFS #371892 - //uri ldap(U("ldap://[2001:db8::7]/?c=GB#objectClass?one")); - //VERIFY_ARE_EQUAL(U("ldap"), ldap.scheme()); - //VERIFY_ARE_EQUAL(U(""), ldap.user_info()); - //VERIFY_ARE_EQUAL(U("2001:db8::7"), ldap.host()); - //VERIFY_ARE_EQUAL(0, ldap.port()); - //VERIFY_ARE_EQUAL(U("/"), ldap.path()); - //VERIFY_ARE_EQUAL(U("c=GB"), ldap.query()); - //VERIFY_ARE_EQUAL(U("objectClass?one"), ldap.fragment()); - - // We don't support anything scheme specific like in C# so - // these common ones don't have a great experience yet. - uri mailto(U("mailto:John.Doe@example.com")); - VERIFY_ARE_EQUAL(U("mailto"), mailto.scheme()); - VERIFY_ARE_EQUAL(U(""), mailto.user_info()); - VERIFY_ARE_EQUAL(U(""), mailto.host()); - VERIFY_ARE_EQUAL(0, mailto.port()); - VERIFY_ARE_EQUAL(U("John.Doe@example.com"), mailto.path()); - VERIFY_ARE_EQUAL(U(""), mailto.query()); - VERIFY_ARE_EQUAL(U(""), mailto.fragment()); - - uri tel(U("tel:+1-816-555-1212")); - VERIFY_ARE_EQUAL(U("tel"), tel.scheme()); - VERIFY_ARE_EQUAL(U(""), tel.user_info()); - VERIFY_ARE_EQUAL(U(""), tel.host()); - VERIFY_ARE_EQUAL(0, tel.port()); - VERIFY_ARE_EQUAL(U("+1-816-555-1212"), tel.path()); - VERIFY_ARE_EQUAL(U(""), tel.query()); - VERIFY_ARE_EQUAL(U(""), tel.fragment()); - - uri telnet(U("telnet://192.0.2.16:80/")); - VERIFY_ARE_EQUAL(U("telnet"), telnet.scheme()); - VERIFY_ARE_EQUAL(U(""), telnet.user_info()); - VERIFY_ARE_EQUAL(U("192.0.2.16"), telnet.host()); - VERIFY_ARE_EQUAL(80, telnet.port()); - VERIFY_ARE_EQUAL(U("/"), telnet.path()); - VERIFY_ARE_EQUAL(U(""), telnet.query()); - VERIFY_ARE_EQUAL(U(""), telnet.fragment()); -} - -TEST(user_info_string) -{ - uri ftp(U("ftp://johndoe:testname@ftp.is.co.za/rfc/rfc1808.txt")); - VERIFY_ARE_EQUAL(U("ftp"), ftp.scheme()); - VERIFY_ARE_EQUAL(U("johndoe:testname"), ftp.user_info()); - VERIFY_ARE_EQUAL(U("ftp.is.co.za"), ftp.host()); - VERIFY_ARE_EQUAL(0, ftp.port()); - VERIFY_ARE_EQUAL(U("/rfc/rfc1808.txt"), ftp.path()); - VERIFY_ARE_EQUAL(U(""), ftp.query()); - VERIFY_ARE_EQUAL(U(""), ftp.fragment()); -} - -// Test query component can be separated with '&' or ';'. -TEST(query_seperated_with_semi_colon) +SUITE(constructor_tests) { - uri u(U("http://localhost/path1?key1=val1;key2=val2")); - VERIFY_ARE_EQUAL(U("key1=val1;key2=val2"), u.query()); -} + TEST(parsing_constructor_char) + { + uri u(uri::encode_uri(U("net.tcp://steve:@testname.com:81/bleh%?qstring#goo"))); + + VERIFY_ARE_EQUAL(U("net.tcp"), u.scheme()); + VERIFY_ARE_EQUAL(U("steve:"), u.user_info()); + VERIFY_ARE_EQUAL(U("testname.com"), u.host()); + VERIFY_ARE_EQUAL(81, u.port()); + VERIFY_ARE_EQUAL(U("/bleh%25"), u.path()); + VERIFY_ARE_EQUAL(U("qstring"), u.query()); + VERIFY_ARE_EQUAL(U("goo"), u.fragment()); + } + + TEST(parsing_constructor_encoded_string) + { + uri u(uri::encode_uri(U("net.tcp://testname.com:81/bleh%?qstring#goo"))); + + VERIFY_ARE_EQUAL(U("net.tcp"), u.scheme()); + VERIFY_ARE_EQUAL(U("testname.com"), u.host()); + VERIFY_ARE_EQUAL(81, u.port()); + VERIFY_ARE_EQUAL(U("/bleh%25"), u.path()); + VERIFY_ARE_EQUAL(U("qstring"), u.query()); + VERIFY_ARE_EQUAL(U("goo"), u.fragment()); + } + + TEST(parsing_constructor_string_string) + { + uri u(uri::encode_uri(U("net.tcp://testname.com:81/bleh%?qstring#goo"))); + + VERIFY_ARE_EQUAL(U("net.tcp"), u.scheme()); + VERIFY_ARE_EQUAL(U("testname.com"), u.host()); + VERIFY_ARE_EQUAL(81, u.port()); + VERIFY_ARE_EQUAL(U("/bleh%25"), u.path()); + VERIFY_ARE_EQUAL(U("qstring"), u.query()); + VERIFY_ARE_EQUAL(U("goo"), u.fragment()); + } + + TEST(empty_strings) + { + VERIFY_IS_TRUE(uri(U("")).is_empty()); + VERIFY_IS_TRUE(uri(U("")).is_empty()); + VERIFY_IS_TRUE(uri(uri::encode_uri(U(""))).is_empty()); + } + + TEST(default_constructor) { VERIFY_IS_TRUE(uri().is_empty()); } + + TEST(relative_ref_string) + { + uri u(uri::encode_uri(U("first/second#boff"))); + + VERIFY_ARE_EQUAL(U(""), u.scheme()); + VERIFY_ARE_EQUAL(U(""), u.host()); + VERIFY_ARE_EQUAL(0, u.port()); + VERIFY_ARE_EQUAL(U("first/second"), u.path()); + VERIFY_ARE_EQUAL(U(""), u.query()); + VERIFY_ARE_EQUAL(U("boff"), u.fragment()); + } + + TEST(absolute_ref_string) + { + uri u(uri::encode_uri(U("/first/second#boff"))); + + VERIFY_ARE_EQUAL(U(""), u.scheme()); + VERIFY_ARE_EQUAL(U(""), u.host()); + VERIFY_ARE_EQUAL(0, u.port()); + VERIFY_ARE_EQUAL(U("/first/second"), u.path()); + VERIFY_ARE_EQUAL(U(""), u.query()); + VERIFY_ARE_EQUAL(U("boff"), u.fragment()); + } + + TEST(copy_constructor) + { + uri original(U("http://st:pass@localhost:456/path1?qstring#goo")); + uri new_uri(original); + + VERIFY_ARE_EQUAL(original, new_uri); + } + + TEST(move_constructor) + { + const utility::string_t uri_str(U("http://localhost:456/path1?qstring#goo")); + uri original(uri_str); + uri new_uri = std::move(original); + + VERIFY_ARE_EQUAL(uri_str, new_uri.to_string()); + VERIFY_ARE_EQUAL(uri(uri_str), new_uri); + } + + TEST(assignment_operator) + { + uri original(U("http://localhost:456/path?qstring#goo")); + uri new_uri = original; + + VERIFY_ARE_EQUAL(original, new_uri); + } + + // Tests invalid URI being passed in constructor. + TEST(parsing_constructor_invalid) + { + VERIFY_THROWS(uri(U("123http://localhost:345/")), uri_exception); + VERIFY_THROWS(uri(U("h*ttp://localhost:345/")), uri_exception); + VERIFY_THROWS(uri(U("http://localhost:345/\"")), uri_exception); + VERIFY_THROWS(uri(U("http://localhost:345/path?\"")), uri_exception); + VERIFY_THROWS(uri(U("http://local\"host:345/")), uri_exception); + } + + // Tests a variety of different URIs using the examples in RFC 2732 + TEST(RFC_2732_examples_string) + { + // The URI parser will make characters lower case + uri http1(U("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html")); + VERIFY_ARE_EQUAL(U("http"), http1.scheme()); + VERIFY_ARE_EQUAL(U("[fedc:ba98:7654:3210:fedc:ba98:7654:3210]"), http1.host()); + VERIFY_ARE_EQUAL(80, http1.port()); + VERIFY_ARE_EQUAL(U("/index.html"), http1.path()); + VERIFY_ARE_EQUAL(U(""), http1.query()); + + uri http2(U("http://[1080:0:0:0:8:800:200C:417A]/index.html")); + VERIFY_ARE_EQUAL(U("http"), http2.scheme()); + VERIFY_ARE_EQUAL(U("[1080:0:0:0:8:800:200c:417a]"), http2.host()); + VERIFY_ARE_EQUAL(0, http2.port()); + VERIFY_ARE_EQUAL(U("/index.html"), http2.path()); + VERIFY_ARE_EQUAL(U(""), http2.query()); + + uri http3(U("https://[3ffe:2a00:100:7031::1]")); + VERIFY_ARE_EQUAL(U("https"), http3.scheme()); + VERIFY_ARE_EQUAL(U("[3ffe:2a00:100:7031::1]"), http3.host()); + VERIFY_ARE_EQUAL(0, http3.port()); + VERIFY_ARE_EQUAL(U("/"), http3.path()); + VERIFY_ARE_EQUAL(U(""), http3.query()); + + uri http4(U("http://[::192.9.5.5]/ipng")); + VERIFY_ARE_EQUAL(U("http"), http4.scheme()); + VERIFY_ARE_EQUAL(U("[::192.9.5.5]"), http4.host()); + VERIFY_ARE_EQUAL(0, http4.port()); + VERIFY_ARE_EQUAL(U("/ipng"), http4.path()); + VERIFY_ARE_EQUAL(U(""), http4.query()); + + uri http5(U("http://[1080::8:800:200C:417A]/foo")); + VERIFY_ARE_EQUAL(U("http"), http5.scheme()); + VERIFY_ARE_EQUAL(U("[1080::8:800:200c:417a]"), http5.host()); + VERIFY_ARE_EQUAL(0, http5.port()); + VERIFY_ARE_EQUAL(U("/foo"), http5.path()); + VERIFY_ARE_EQUAL(U(""), http5.query()); + + uri http6(U("http://[::FFFF:129.144.52.38]:80/index.html")); + VERIFY_ARE_EQUAL(U("http"), http6.scheme()); + VERIFY_ARE_EQUAL(U("[::ffff:129.144.52.38]"), http6.host()); + VERIFY_ARE_EQUAL(80, http6.port()); + VERIFY_ARE_EQUAL(U("/index.html"), http6.path()); + VERIFY_ARE_EQUAL(U(""), http6.query()); + + uri http7(U("http://[2010:836B:4179::836B:4179]")); + VERIFY_ARE_EQUAL(U("http"), http7.scheme()); + VERIFY_ARE_EQUAL(U("[2010:836b:4179::836b:4179]"), http7.host()); + VERIFY_ARE_EQUAL(0, http7.port()); + VERIFY_ARE_EQUAL(U("/"), http7.path()); + VERIFY_ARE_EQUAL(U(""), http7.query()); + } + + // Tests a variety of different URIs using the examples in RFC 3986. + TEST(RFC_3968_examples_string) + { + uri ftp(U("ftp://ftp.is.co.za/rfc/rfc1808.txt")); + VERIFY_ARE_EQUAL(U("ftp"), ftp.scheme()); + VERIFY_ARE_EQUAL(U(""), ftp.user_info()); + VERIFY_ARE_EQUAL(U("ftp.is.co.za"), ftp.host()); + VERIFY_ARE_EQUAL(0, ftp.port()); + VERIFY_ARE_EQUAL(U("/rfc/rfc1808.txt"), ftp.path()); + VERIFY_ARE_EQUAL(U(""), ftp.query()); + VERIFY_ARE_EQUAL(U(""), ftp.fragment()); + + // TFS #371892 + // uri ldap(U("ldap://[2001:db8::7]/?c=GB#objectClass?one")); + // VERIFY_ARE_EQUAL(U("ldap"), ldap.scheme()); + // VERIFY_ARE_EQUAL(U(""), ldap.user_info()); + // VERIFY_ARE_EQUAL(U("2001:db8::7"), ldap.host()); + // VERIFY_ARE_EQUAL(0, ldap.port()); + // VERIFY_ARE_EQUAL(U("/"), ldap.path()); + // VERIFY_ARE_EQUAL(U("c=GB"), ldap.query()); + // VERIFY_ARE_EQUAL(U("objectClass?one"), ldap.fragment()); + + // We don't support anything scheme specific like in C# so + // these common ones don't have a great experience yet. + uri mailto(U("mailto:John.Doe@example.com")); + VERIFY_ARE_EQUAL(U("mailto"), mailto.scheme()); + VERIFY_ARE_EQUAL(U(""), mailto.user_info()); + VERIFY_ARE_EQUAL(U(""), mailto.host()); + VERIFY_ARE_EQUAL(0, mailto.port()); + VERIFY_ARE_EQUAL(U("John.Doe@example.com"), mailto.path()); + VERIFY_ARE_EQUAL(U(""), mailto.query()); + VERIFY_ARE_EQUAL(U(""), mailto.fragment()); + + uri tel(U("tel:+1-816-555-1212")); + VERIFY_ARE_EQUAL(U("tel"), tel.scheme()); + VERIFY_ARE_EQUAL(U(""), tel.user_info()); + VERIFY_ARE_EQUAL(U(""), tel.host()); + VERIFY_ARE_EQUAL(0, tel.port()); + VERIFY_ARE_EQUAL(U("+1-816-555-1212"), tel.path()); + VERIFY_ARE_EQUAL(U(""), tel.query()); + VERIFY_ARE_EQUAL(U(""), tel.fragment()); + + uri telnet(U("telnet://192.0.2.16:80/")); + VERIFY_ARE_EQUAL(U("telnet"), telnet.scheme()); + VERIFY_ARE_EQUAL(U(""), telnet.user_info()); + VERIFY_ARE_EQUAL(U("192.0.2.16"), telnet.host()); + VERIFY_ARE_EQUAL(80, telnet.port()); + VERIFY_ARE_EQUAL(U("/"), telnet.path()); + VERIFY_ARE_EQUAL(U(""), telnet.query()); + VERIFY_ARE_EQUAL(U(""), telnet.fragment()); + } + + TEST(user_info_string) + { + uri ftp(U("ftp://johndoe:testname@ftp.is.co.za/rfc/rfc1808.txt")); + VERIFY_ARE_EQUAL(U("ftp"), ftp.scheme()); + VERIFY_ARE_EQUAL(U("johndoe:testname"), ftp.user_info()); + VERIFY_ARE_EQUAL(U("ftp.is.co.za"), ftp.host()); + VERIFY_ARE_EQUAL(0, ftp.port()); + VERIFY_ARE_EQUAL(U("/rfc/rfc1808.txt"), ftp.path()); + VERIFY_ARE_EQUAL(U(""), ftp.query()); + VERIFY_ARE_EQUAL(U(""), ftp.fragment()); + } + + // Test query component can be separated with '&' or ';'. + TEST(query_seperated_with_semi_colon) + { + uri u(U("http://localhost/path1?key1=val1;key2=val2")); + VERIFY_ARE_EQUAL(U("key1=val1;key2=val2"), u.query()); + } } // SUITE(constructor_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/conversions_tests.cpp b/Release/tests/functional/uri/conversions_tests.cpp index dfcee7690d..ba99c749ba 100644 --- a/Release/tests/functional/uri/conversions_tests.cpp +++ b/Release/tests/functional/uri/conversions_tests.cpp @@ -1,48 +1,53 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* conversion_tests.cpp -* -* Tests to string functions and implicit conversions of the http::uri class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * conversion_tests.cpp + * + * Tests to string functions and implicit conversions of the http::uri class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; using namespace utility; -namespace tests { namespace functional { namespace uri_tests { - +namespace tests +{ +namespace functional +{ +namespace uri_tests +{ SUITE(conversions_tests) { + TEST(to_string_conversion) + { + utility::string_t encoded = uri::encode_uri(U("http://testname.com/%%?qstring")); + uri u1(U("http://testname.com/%25%25?qstring")); -TEST(to_string_conversion) -{ - utility::string_t encoded = uri::encode_uri(U("http://testname.com/%%?qstring")); - uri u1(U("http://testname.com/%25%25?qstring")); - - VERIFY_ARE_EQUAL(uri::decode(encoded), uri::decode(u1.to_string())); -} + VERIFY_ARE_EQUAL(uri::decode(encoded), uri::decode(u1.to_string())); + } -TEST(to_encoded_string) -{ - utility::string_t encoded = uri::encode_uri(U("http://testname.com/%%?qstring")); - uri u(U("http://testname.com/%25%25?qstring")); + TEST(to_encoded_string) + { + utility::string_t encoded = uri::encode_uri(U("http://testname.com/%%?qstring")); + uri u(U("http://testname.com/%25%25?qstring")); - VERIFY_ARE_EQUAL(encoded, u.to_string()); -} + VERIFY_ARE_EQUAL(encoded, u.to_string()); + } -TEST(empty_to_string) -{ - uri u; - VERIFY_ARE_EQUAL(U("/"), u.to_string()); -} + TEST(empty_to_string) + { + uri u; + VERIFY_ARE_EQUAL(U("/"), u.to_string()); + } } // SUITE(conversions_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/diagnostic_tests.cpp b/Release/tests/functional/uri/diagnostic_tests.cpp index 738dd52e40..d8fb45d91c 100644 --- a/Release/tests/functional/uri/diagnostic_tests.cpp +++ b/Release/tests/functional/uri/diagnostic_tests.cpp @@ -1,112 +1,117 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* diagnostic_tests.cpp -* -* Tests for diagnostic functions like is_host_loopback of the uri class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * diagnostic_tests.cpp + * + * Tests for diagnostic functions like is_host_loopback of the uri class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; using namespace utility; -namespace tests { namespace functional { namespace uri_tests { - -SUITE(diagnostic_tests) -{ - -TEST(empty_components) -{ - VERIFY_IS_TRUE(uri().is_empty()); - - VERIFY_IS_FALSE(uri().is_authority()); - - VERIFY_IS_FALSE(uri().is_host_loopback()); - VERIFY_IS_FALSE(uri().is_host_wildcard()); - VERIFY_IS_FALSE(uri().is_host_portable()); - - VERIFY_IS_FALSE(uri().is_port_default()); -} - -TEST(is_authority) -{ - VERIFY_IS_TRUE(uri(U("http://first.second/")).is_authority()); - VERIFY_IS_TRUE(uri(U("http://first.second")).is_authority()); - - VERIFY_IS_FALSE(uri(U("http://first.second/b")).is_authority()); - VERIFY_IS_FALSE(uri(U("http://first.second?qstring")).is_authority()); - VERIFY_IS_FALSE(uri(U("http://first.second#third")).is_authority()); -} - -TEST(has_same_authority) -{ - VERIFY_IS_TRUE(uri(U("http://first.second/")).has_same_authority(uri(U("http://first.second/path")))); - VERIFY_IS_TRUE(uri(U("http://first.second:83/")).has_same_authority(uri(U("http://first.second:83/path:83")))); - - VERIFY_IS_FALSE(uri(U("http://first.second:82/")).has_same_authority(uri(U("http://first.second/path")))); - VERIFY_IS_FALSE(uri(U("tcp://first.second:82/")).has_same_authority(uri(U("http://first.second/path")))); - VERIFY_IS_FALSE(uri(U("http://path.:82/")).has_same_authority(uri(U("http://first.second/path")))); -} - -TEST(has_same_authority_empty) +namespace tests { - VERIFY_IS_FALSE(uri().has_same_authority(uri())); - VERIFY_IS_FALSE(uri(U("http://first.second/")).has_same_authority(uri())); - VERIFY_IS_FALSE(uri().has_same_authority(uri(U("http://first.second/")))); -} - -TEST(is_host_wildcard) +namespace functional { - VERIFY_IS_TRUE(uri(U("http://*/")).is_host_wildcard()); - VERIFY_IS_TRUE(uri(U("http://+/?qstring")).is_host_wildcard()); - - VERIFY_IS_FALSE(uri(U("http://bleh/?qstring")).is_host_wildcard()); - VERIFY_IS_FALSE(uri(U("http://+*/?qstring")).is_host_wildcard()); -} - -TEST(is_host_loopback) -{ - VERIFY_IS_TRUE(uri(U("http://localhost/")).is_host_loopback()); - VERIFY_IS_TRUE(uri(U("http://LoCALHoST/")).is_host_loopback()); - - VERIFY_IS_FALSE(uri(U("http://127")).is_host_loopback()); - VERIFY_IS_FALSE(uri(U("http://bleh/?qstring")).is_host_loopback()); - VERIFY_IS_FALSE(uri(U("http://+*/?qstring")).is_host_loopback()); - VERIFY_IS_TRUE(uri(U("http://127.0.0.1/")).is_host_loopback()); - VERIFY_IS_TRUE(uri(U("http://127.155.0.1/")).is_host_loopback()); - VERIFY_IS_FALSE(uri(U("http://128.0.0.1/")).is_host_loopback()); -} - -TEST(is_host_portable) +namespace uri_tests { - VERIFY_IS_TRUE(uri(U("http://bleh/?qstring")).is_host_portable()); - - VERIFY_IS_FALSE(uri(U("http://localhost/")).is_host_portable()); - VERIFY_IS_FALSE(uri(U("http://+/?qstring")).is_host_portable()); -} - -TEST(is_port_default) -{ - VERIFY_IS_TRUE(uri(U("http://bleh/?qstring")).is_port_default()); - VERIFY_IS_TRUE(uri(U("http://localhost:0/")).is_port_default()); - - VERIFY_IS_FALSE(uri(U("http://+:85/?qstring")).is_port_default()); -} - -TEST(is_path_empty) +SUITE(diagnostic_tests) { - VERIFY_IS_TRUE(uri(U("http://bleh/?qstring")).is_path_empty()); - VERIFY_IS_TRUE(uri(U("http://localhost:0")).is_path_empty()); - - VERIFY_IS_FALSE(uri(U("http://+:85/path/?qstring")).is_path_empty()); -} + TEST(empty_components) + { + VERIFY_IS_TRUE(uri().is_empty()); + + VERIFY_IS_FALSE(uri().is_authority()); + + VERIFY_IS_FALSE(uri().is_host_loopback()); + VERIFY_IS_FALSE(uri().is_host_wildcard()); + VERIFY_IS_FALSE(uri().is_host_portable()); + + VERIFY_IS_FALSE(uri().is_port_default()); + } + + TEST(is_authority) + { + VERIFY_IS_TRUE(uri(U("http://first.second/")).is_authority()); + VERIFY_IS_TRUE(uri(U("http://first.second")).is_authority()); + + VERIFY_IS_FALSE(uri(U("http://first.second/b")).is_authority()); + VERIFY_IS_FALSE(uri(U("http://first.second?qstring")).is_authority()); + VERIFY_IS_FALSE(uri(U("http://first.second#third")).is_authority()); + } + + TEST(has_same_authority) + { + VERIFY_IS_TRUE(uri(U("http://first.second/")).has_same_authority(uri(U("http://first.second/path")))); + VERIFY_IS_TRUE(uri(U("http://first.second:83/")).has_same_authority(uri(U("http://first.second:83/path:83")))); + + VERIFY_IS_FALSE(uri(U("http://first.second:82/")).has_same_authority(uri(U("http://first.second/path")))); + VERIFY_IS_FALSE(uri(U("tcp://first.second:82/")).has_same_authority(uri(U("http://first.second/path")))); + VERIFY_IS_FALSE(uri(U("http://path.:82/")).has_same_authority(uri(U("http://first.second/path")))); + } + + TEST(has_same_authority_empty) + { + VERIFY_IS_FALSE(uri().has_same_authority(uri())); + VERIFY_IS_FALSE(uri(U("http://first.second/")).has_same_authority(uri())); + VERIFY_IS_FALSE(uri().has_same_authority(uri(U("http://first.second/")))); + } + + TEST(is_host_wildcard) + { + VERIFY_IS_TRUE(uri(U("http://*/")).is_host_wildcard()); + VERIFY_IS_TRUE(uri(U("http://+/?qstring")).is_host_wildcard()); + + VERIFY_IS_FALSE(uri(U("http://bleh/?qstring")).is_host_wildcard()); + VERIFY_IS_FALSE(uri(U("http://+*/?qstring")).is_host_wildcard()); + } + + TEST(is_host_loopback) + { + VERIFY_IS_TRUE(uri(U("http://localhost/")).is_host_loopback()); + VERIFY_IS_TRUE(uri(U("http://LoCALHoST/")).is_host_loopback()); + + VERIFY_IS_FALSE(uri(U("http://127")).is_host_loopback()); + VERIFY_IS_FALSE(uri(U("http://bleh/?qstring")).is_host_loopback()); + VERIFY_IS_FALSE(uri(U("http://+*/?qstring")).is_host_loopback()); + VERIFY_IS_TRUE(uri(U("http://127.0.0.1/")).is_host_loopback()); + VERIFY_IS_TRUE(uri(U("http://127.155.0.1/")).is_host_loopback()); + VERIFY_IS_FALSE(uri(U("http://128.0.0.1/")).is_host_loopback()); + } + + TEST(is_host_portable) + { + VERIFY_IS_TRUE(uri(U("http://bleh/?qstring")).is_host_portable()); + + VERIFY_IS_FALSE(uri(U("http://localhost/")).is_host_portable()); + VERIFY_IS_FALSE(uri(U("http://+/?qstring")).is_host_portable()); + } + + TEST(is_port_default) + { + VERIFY_IS_TRUE(uri(U("http://bleh/?qstring")).is_port_default()); + VERIFY_IS_TRUE(uri(U("http://localhost:0/")).is_port_default()); + + VERIFY_IS_FALSE(uri(U("http://+:85/?qstring")).is_port_default()); + } + + TEST(is_path_empty) + { + VERIFY_IS_TRUE(uri(U("http://bleh/?qstring")).is_path_empty()); + VERIFY_IS_TRUE(uri(U("http://localhost:0")).is_path_empty()); + + VERIFY_IS_FALSE(uri(U("http://+:85/path/?qstring")).is_path_empty()); + } } // SUITE(diagnostic_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/encoding_tests.cpp b/Release/tests/functional/uri/encoding_tests.cpp index 3daff234f8..535bc2aec2 100644 --- a/Release/tests/functional/uri/encoding_tests.cpp +++ b/Release/tests/functional/uri/encoding_tests.cpp @@ -1,129 +1,134 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests for encoding features of the uri class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests for encoding features of the uri class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; using namespace utility; -namespace tests { namespace functional { namespace uri_tests { - -SUITE(encoding_tests) -{ - -#ifdef _WIN32 -#pragma warning (push) -#pragma warning (disable : 4428) -TEST(encode_string) -{ - utility::string_t result = uri::encode_uri(L"first%second\u4e2d\u56fd"); - VERIFY_ARE_EQUAL(U("first%25second%E4%B8%AD%E5%9B%BD"), result); - - result = uri::encode_uri(U("first%second")); - VERIFY_ARE_EQUAL(U("first%25second"), result); -} - -TEST(decode_string) -{ - utility::string_t result = uri::decode(U("first%25second%E4%B8%AD%E5%9B%BD")); - VERIFY_ARE_EQUAL(L"first%second\u4e2d\u56fd", result); - - result = uri::decode(U("first%25second")); - VERIFY_ARE_EQUAL(U("first%second"), result); -} -#pragma warning (pop) -#endif - -TEST(encode_characters_in_resource) -{ - utility::string_t result = uri::encode_uri(U("http://path%name/%#!%")); - VERIFY_ARE_EQUAL(U("http://path%25name/%25#!%25"), result); -} - -// Tests trying to encode empty strings. -TEST(encode_decode_empty_strings) -{ - // utility::string_t - utility::string_t result = uri::encode_uri(U("")); - VERIFY_ARE_EQUAL(U(""), result); - utility::string_t str = uri::decode(result); - VERIFY_ARE_EQUAL(U(""), str); - - // std::wstring - result = uri::encode_uri(U("")); - VERIFY_ARE_EQUAL(U(""), result); - auto wstr = uri::decode(result); - VERIFY_ARE_EQUAL(U(""), wstr); -} - -// Tests encoding in various components of the URI. -TEST(encode_uri_multiple_components) +namespace tests { - // only encodes characters that aren't in the unreserved and reserved set. - - // utility::string_t - utility::string_t str(U("htt p://^localhost:80/path ?^one=two# frag")); - utility::string_t result = uri::encode_uri(str); - VERIFY_ARE_EQUAL(U("htt%20p://%5Elocalhost:80/path%20?%5Eone=two#%20frag"), result); - VERIFY_ARE_EQUAL(str, uri::decode(result)); -} - -// Tests encoding individual components of a URI. -TEST(encode_uri_component) -{ - // encodes all characters not in the unreserved set. - - // utility::string_t - utility::string_t str(U("path with^spaced")); - utility::string_t result = uri::encode_uri(str); - VERIFY_ARE_EQUAL(U("path%20with%5Espaced"), result); - VERIFY_ARE_EQUAL(str, uri::decode(result)); -} - -// Tests trying to decode a string that doesn't have 2 hex digits after % -TEST(decode_invalid_hex) +namespace functional { - VERIFY_THROWS(uri::decode(U("hehe%")), uri_exception); - VERIFY_THROWS(uri::decode(U("hehe%2")), uri_exception); - VERIFY_THROWS(uri::decode(U("hehe%4H")), uri_exception); - VERIFY_THROWS(uri::decode(U("he%kkhe")), uri_exception); -} - -// Tests making sure '+' is encoded even though nonstandard, so it doesn't -// get mistaken later by some implementations as a space. -TEST(encode_plus_char) +namespace uri_tests { - const utility::string_t encodedPlus(U("%2B")); - - uri_builder builder; - builder.set_user_info(U("+"), true); - builder.set_path(U("+"), true); - builder.set_query(U("+"), true); - builder.set_fragment(U("+"), true); - - VERIFY_ARE_EQUAL(builder.user_info(), encodedPlus); - VERIFY_ARE_EQUAL(builder.path(), encodedPlus); - VERIFY_ARE_EQUAL(builder.query(), encodedPlus); - VERIFY_ARE_EQUAL(builder.fragment(), encodedPlus); -} - -TEST(bug_417601) +SUITE(encoding_tests) { - utility::ostringstream_t ss1; - auto enc1 = uri::encode_data_string(U("!")); - ss1 << enc1; +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable : 4428) + TEST(encode_string) + { + utility::string_t result = uri::encode_uri(L"first%second\u4e2d\u56fd"); + VERIFY_ARE_EQUAL(U("first%25second%E4%B8%AD%E5%9B%BD"), result); + + result = uri::encode_uri(U("first%second")); + VERIFY_ARE_EQUAL(U("first%25second"), result); + } + + TEST(decode_string) + { + utility::string_t result = uri::decode(U("first%25second%E4%B8%AD%E5%9B%BD")); + VERIFY_ARE_EQUAL(L"first%second\u4e2d\u56fd", result); + + result = uri::decode(U("first%25second")); + VERIFY_ARE_EQUAL(U("first%second"), result); + } +#pragma warning(pop) +#endif - VERIFY_ARE_EQUAL(U("%21"), ss1.str()); -} + TEST(encode_characters_in_resource) + { + utility::string_t result = uri::encode_uri(U("http://path%name/%#!%")); + VERIFY_ARE_EQUAL(U("http://path%25name/%25#!%25"), result); + } + + // Tests trying to encode empty strings. + TEST(encode_decode_empty_strings) + { + // utility::string_t + utility::string_t result = uri::encode_uri(U("")); + VERIFY_ARE_EQUAL(U(""), result); + utility::string_t str = uri::decode(result); + VERIFY_ARE_EQUAL(U(""), str); + + // std::wstring + result = uri::encode_uri(U("")); + VERIFY_ARE_EQUAL(U(""), result); + auto wstr = uri::decode(result); + VERIFY_ARE_EQUAL(U(""), wstr); + } + + // Tests encoding in various components of the URI. + TEST(encode_uri_multiple_components) + { + // only encodes characters that aren't in the unreserved and reserved set. + + // utility::string_t + utility::string_t str(U("htt p://^localhost:80/path ?^one=two# frag")); + utility::string_t result = uri::encode_uri(str); + VERIFY_ARE_EQUAL(U("htt%20p://%5Elocalhost:80/path%20?%5Eone=two#%20frag"), result); + VERIFY_ARE_EQUAL(str, uri::decode(result)); + } + + // Tests encoding individual components of a URI. + TEST(encode_uri_component) + { + // encodes all characters not in the unreserved set. + + // utility::string_t + utility::string_t str(U("path with^spaced")); + utility::string_t result = uri::encode_uri(str); + VERIFY_ARE_EQUAL(U("path%20with%5Espaced"), result); + VERIFY_ARE_EQUAL(str, uri::decode(result)); + } + + // Tests trying to decode a string that doesn't have 2 hex digits after % + TEST(decode_invalid_hex) + { + VERIFY_THROWS(uri::decode(U("hehe%")), uri_exception); + VERIFY_THROWS(uri::decode(U("hehe%2")), uri_exception); + VERIFY_THROWS(uri::decode(U("hehe%4H")), uri_exception); + VERIFY_THROWS(uri::decode(U("he%kkhe")), uri_exception); + } + + // Tests making sure '+' is encoded even though nonstandard, so it doesn't + // get mistaken later by some implementations as a space. + TEST(encode_plus_char) + { + const utility::string_t encodedPlus(U("%2B")); + + uri_builder builder; + builder.set_user_info(U("+"), true); + builder.set_path(U("+"), true); + builder.set_query(U("+"), true); + builder.set_fragment(U("+"), true); + + VERIFY_ARE_EQUAL(builder.user_info(), encodedPlus); + VERIFY_ARE_EQUAL(builder.path(), encodedPlus); + VERIFY_ARE_EQUAL(builder.query(), encodedPlus); + VERIFY_ARE_EQUAL(builder.fragment(), encodedPlus); + } + + TEST(bug_417601) + { + utility::ostringstream_t ss1; + auto enc1 = uri::encode_data_string(U("!")); + ss1 << enc1; + + VERIFY_ARE_EQUAL(U("%21"), ss1.str()); + } } // SUITE(encoding_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/operator_tests.cpp b/Release/tests/functional/uri/operator_tests.cpp index 171b8ea0ee..b76475e408 100644 --- a/Release/tests/functional/uri/operator_tests.cpp +++ b/Release/tests/functional/uri/operator_tests.cpp @@ -1,73 +1,80 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* operator_tests.cpp -* -* Tests for operators of the uri class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * operator_tests.cpp + * + * Tests for operators of the uri class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace web; using namespace utility; -namespace tests { namespace functional { namespace uri_tests { - +namespace tests +{ +namespace functional +{ +namespace uri_tests +{ SUITE(operator_tests) { + TEST(uri_basic_equality) + { + VERIFY_ARE_EQUAL(uri(U("")), uri(U(""))); -TEST(uri_basic_equality) -{ - VERIFY_ARE_EQUAL(uri(U("")), uri(U(""))); + uri u1(U("http://localhost:80/path1")); + uri u2(U("http://localhost:80/path1")); + VERIFY_ARE_EQUAL(u1, u2); + } - uri u1(U("http://localhost:80/path1")); - uri u2(U("http://localhost:80/path1")); - VERIFY_ARE_EQUAL(u1, u2); -} + TEST(uri_decoded_equality) + { + uri_builder u3b(U("http://localhost:80")); + u3b.set_path(U("path 1"), true); -TEST(uri_decoded_equality) -{ - uri_builder u3b(U("http://localhost:80")); - u3b.set_path(U("path 1"), true); - - uri u3 = u3b.to_uri(); - uri u4(U("http://localhost:80/path%201")); - VERIFY_ARE_EQUAL(u3, u4); + uri u3 = u3b.to_uri(); + uri u4(U("http://localhost:80/path%201")); + VERIFY_ARE_EQUAL(u3, u4); - uri u5(U("http://localhost:80/pat%68a1")); - uri u6(U("http://localhost:80/patha1")); - VERIFY_ARE_EQUAL(u5, u6); + uri u5(U("http://localhost:80/pat%68a1")); + uri u6(U("http://localhost:80/patha1")); + VERIFY_ARE_EQUAL(u5, u6); - uri u9(U("http://localhost:80/patha1?name=first#t%65st")); - uri u10(U("http://localhost:80/patha1?name=first#test")); - VERIFY_ARE_EQUAL(u9, u10); -} + uri u9(U("http://localhost:80/patha1?name=first#t%65st")); + uri u10(U("http://localhost:80/patha1?name=first#test")); + VERIFY_ARE_EQUAL(u9, u10); + } -TEST(uri_basic_inequality) -{ - VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1")), uri(U("https://localhost:80/path1"))); - VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1")), uri(U("http://localhost2:80/path1"))); - VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1")), uri(U("http://localhost:81/path1"))); - VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1")), uri(U("http://localhost:80/path2"))); - VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1?key=value")), uri(U("http://localhost:80/path1?key=value2"))); - VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1?key=value#nose")), uri(U("http://localhost:80/path1?key=value#nose1"))); -} + TEST(uri_basic_inequality) + { + VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1")), uri(U("https://localhost:80/path1"))); + VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1")), uri(U("http://localhost2:80/path1"))); + VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1")), uri(U("http://localhost:81/path1"))); + VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1")), uri(U("http://localhost:80/path2"))); + VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1?key=value")), + uri(U("http://localhost:80/path1?key=value2"))); + VERIFY_ARE_NOT_EQUAL(uri(U("http://localhost:80/path1?key=value#nose")), + uri(U("http://localhost:80/path1?key=value#nose1"))); + } -TEST(test_empty) -{ - VERIFY_ARE_EQUAL(uri(), uri()); - VERIFY_ARE_EQUAL(uri(U("htTp://Path")), uri(U("hTtp://pAth"))); + TEST(test_empty) + { + VERIFY_ARE_EQUAL(uri(), uri()); + VERIFY_ARE_EQUAL(uri(U("htTp://Path")), uri(U("hTtp://pAth"))); - VERIFY_ARE_NOT_EQUAL(uri(U("http://path")), uri()); - VERIFY_ARE_NOT_EQUAL(uri(), uri(U("http://path"))); - VERIFY_ARE_NOT_EQUAL(uri(U("http://path1")), uri(U("http://path2"))); -} + VERIFY_ARE_NOT_EQUAL(uri(U("http://path")), uri()); + VERIFY_ARE_NOT_EQUAL(uri(), uri(U("http://path"))); + VERIFY_ARE_NOT_EQUAL(uri(U("http://path1")), uri(U("http://path2"))); + } } // SUITE(operator_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/resolve_uri_tests.cpp b/Release/tests/functional/uri/resolve_uri_tests.cpp index 963be8656f..537b5a4773 100644 --- a/Release/tests/functional/uri/resolve_uri_tests.cpp +++ b/Release/tests/functional/uri/resolve_uri_tests.cpp @@ -3,66 +3,72 @@ using namespace web; using namespace utility; -namespace tests { namespace functional { namespace uri_tests { - -//testing resolution against examples from Section 5.4 https://tools.ietf.org/html/rfc3986#section-5.4 -SUITE(resolve_uri_tests) +namespace tests { -//5.4.1. Normal Examples https://tools.ietf.org/html/rfc3986#section-5.4.1 -TEST(resolve_uri_normal) +namespace functional { - const uri baseUri = U("http://a/b/c/d;p?q"); - - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g:h")), U("g:h")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g")), U("http://a/b/c/g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./g")), U("http://a/b/c/g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g/")), U("http://a/b/c/g/")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("/g")), U("http://a/g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("//g")), U("http://g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("?y")), U("http://a/b/c/d;p?y")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y")), U("http://a/b/c/g?y")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("#s")), U("http://a/b/c/d;p?q#s")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g#s")), U("http://a/b/c/g#s")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y#s")), U("http://a/b/c/g?y#s")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U(";x")), U("http://a/b/c/;x")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x")), U("http://a/b/c/g;x")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x?y#s")), U("http://a/b/c/g;x?y#s")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("")), U("http://a/b/c/d;p?q")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U(".")), U("http://a/b/c/")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./")), U("http://a/b/c/")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("..")), U("http://a/b/")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../")), U("http://a/b/")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../g")), U("http://a/b/g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../..")), U("http://a/")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../")), U("http://a/")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../g")), U("http://a/g")); -} -//5.4.2. Abnormal Examples https://tools.ietf.org/html/rfc3986#section-5.4.2 -TEST(resolve_uri_abnormal) +namespace uri_tests { - const uri baseUri = U("http://a/b/c/d;p?q"); +// testing resolution against examples from Section 5.4 https://tools.ietf.org/html/rfc3986#section-5.4 +SUITE(resolve_uri_tests) +{ + // 5.4.1. Normal Examples https://tools.ietf.org/html/rfc3986#section-5.4.1 + TEST(resolve_uri_normal) + { + const uri baseUri = U("http://a/b/c/d;p?q"); + + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g:h")), U("g:h")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g")), U("http://a/b/c/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./g")), U("http://a/b/c/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g/")), U("http://a/b/c/g/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("/g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("//g")), U("http://g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("?y")), U("http://a/b/c/d;p?y")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y")), U("http://a/b/c/g?y")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("#s")), U("http://a/b/c/d;p?q#s")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g#s")), U("http://a/b/c/g#s")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y#s")), U("http://a/b/c/g?y#s")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U(";x")), U("http://a/b/c/;x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x")), U("http://a/b/c/g;x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x?y#s")), U("http://a/b/c/g;x?y#s")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("")), U("http://a/b/c/d;p?q")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U(".")), U("http://a/b/c/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./")), U("http://a/b/c/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("..")), U("http://a/b/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../")), U("http://a/b/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../g")), U("http://a/b/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../..")), U("http://a/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../")), U("http://a/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../g")), U("http://a/g")); + } + // 5.4.2. Abnormal Examples https://tools.ietf.org/html/rfc3986#section-5.4.2 + TEST(resolve_uri_abnormal) + { + const uri baseUri = U("http://a/b/c/d;p?q"); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../../g")), U("http://a/g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../../../g")), U("http://a/g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("/./g")), U("http://a/g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("/../g")), U("http://a/g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g.")), U("http://a/b/c/g.")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U(".g")), U("http://a/b/c/.g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g..")), U("http://a/b/c/g..")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("..g")), U("http://a/b/c/..g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./../g")), U("http://a/b/g")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./g/.")), U("http://a/b/c/g/")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g/./h")), U("http://a/b/c/g/h")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g/../h")), U("http://a/b/c/h")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x=1/./y")), U("http://a/b/c/g;x=1/y")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x=1/../y")), U("http://a/b/c/y")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y/./x")), U("http://a/b/c/g?y/./x")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y/../x")), U("http://a/b/c/g?y/../x")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g#s/./x")), U("http://a/b/c/g#s/./x")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g#s/../x")), U("http://a/b/c/g#s/../x")); - VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("http:g")), U("http:g")); -} + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../../g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../../../g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("/./g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("/../g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g.")), U("http://a/b/c/g.")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U(".g")), U("http://a/b/c/.g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g..")), U("http://a/b/c/g..")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("..g")), U("http://a/b/c/..g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./../g")), U("http://a/b/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./g/.")), U("http://a/b/c/g/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g/./h")), U("http://a/b/c/g/h")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g/../h")), U("http://a/b/c/h")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x=1/./y")), U("http://a/b/c/g;x=1/y")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x=1/../y")), U("http://a/b/c/y")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y/./x")), U("http://a/b/c/g?y/./x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y/../x")), U("http://a/b/c/g?y/../x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g#s/./x")), U("http://a/b/c/g#s/./x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g#s/../x")), U("http://a/b/c/g#s/../x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("http:g")), U("http:g")); + } } // SUITE(resolve_uri_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/splitting_tests.cpp b/Release/tests/functional/uri/splitting_tests.cpp index 76825cd68d..918e9666e8 100644 --- a/Release/tests/functional/uri/splitting_tests.cpp +++ b/Release/tests/functional/uri/splitting_tests.cpp @@ -1,172 +1,181 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* splitting_tests.cpp -* -* Tests for path and query splitting features of the uri class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * splitting_tests.cpp + * + * Tests for path and query splitting features of the uri class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -namespace tests { namespace functional { namespace uri_tests { - -using namespace web; -using namespace utility; - -SUITE(splitting_tests) -{ - -TEST(split_string) +namespace tests { - std::vector s = uri::split_path(U("/first/second/third")); - VERIFY_ARE_EQUAL(3u, s.size()); - VERIFY_ARE_EQUAL(U("first"), s[0]); - VERIFY_ARE_EQUAL(U("second"), s[1]); - VERIFY_ARE_EQUAL(U("third"), s[2]); -} - -TEST(split_encoded_string) +namespace functional { - std::vector s = uri::split_path(utility::string_t(U("heh%2Ffirst/second/third"))); - VERIFY_ARE_EQUAL(3u, s.size()); - VERIFY_ARE_EQUAL(U("heh%2Ffirst"), s[0]); - VERIFY_ARE_EQUAL(U("second"), s[1]); - VERIFY_ARE_EQUAL(U("third"), s[2]); -} - -TEST(split_no_slash) +namespace uri_tests { - std::vector s = uri::split_path(utility::string_t(U("noslash"))); - VERIFY_ARE_EQUAL(1u, s.size()); - VERIFY_ARE_EQUAL(U("noslash"), s[0]); -} +using namespace web; +using namespace utility; -TEST(split_query_basic) +SUITE(splitting_tests) { + TEST(split_string) { - // Separating with '&' - std::map keyMap = uri::split_query(U("key1=value1&key2=value2&key3=value3")); - VERIFY_ARE_EQUAL(3u, keyMap.size()); - auto iter = keyMap.begin(); - VERIFY_ARE_EQUAL(U("key1"), iter->first); - VERIFY_ARE_EQUAL(U("value1"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("key2"), iter->first); - VERIFY_ARE_EQUAL(U("value2"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("key3"), iter->first); - VERIFY_ARE_EQUAL(U("value3"), iter->second); + std::vector s = uri::split_path(U("/first/second/third")); + VERIFY_ARE_EQUAL(3u, s.size()); + VERIFY_ARE_EQUAL(U("first"), s[0]); + VERIFY_ARE_EQUAL(U("second"), s[1]); + VERIFY_ARE_EQUAL(U("third"), s[2]); } + + TEST(split_encoded_string) { - // Separating with ';' - std::map keyMap = uri::split_query(U("key1=value1;key2=value2;key3=value3")); - VERIFY_ARE_EQUAL(3u, keyMap.size()); - auto iter = keyMap.begin(); - VERIFY_ARE_EQUAL(U("key1"), iter->first); - VERIFY_ARE_EQUAL(U("value1"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("key2"), iter->first); - VERIFY_ARE_EQUAL(U("value2"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("key3"), iter->first); - VERIFY_ARE_EQUAL(U("value3"), iter->second); + std::vector s = uri::split_path(utility::string_t(U("heh%2Ffirst/second/third"))); + VERIFY_ARE_EQUAL(3u, s.size()); + VERIFY_ARE_EQUAL(U("heh%2Ffirst"), s[0]); + VERIFY_ARE_EQUAL(U("second"), s[1]); + VERIFY_ARE_EQUAL(U("third"), s[2]); } -} -TEST(split_encoded_query) -{ + TEST(split_no_slash) { - // Separating with '&' - std::map keyMap = uri::split_query(utility::string_t(U("key=value%26key1%20=value1&key2=%5Evalue2&key3=value3%20"))); - VERIFY_ARE_EQUAL(3u, keyMap.size()); - auto iter = keyMap.begin(); - VERIFY_ARE_EQUAL(U("key"), iter->first); - VERIFY_ARE_EQUAL(U("value%26key1%20=value1"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("key2"), iter->first); - VERIFY_ARE_EQUAL(U("%5Evalue2"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("key3"), iter->first); - VERIFY_ARE_EQUAL(U("value3%20"), iter->second); + std::vector s = uri::split_path(utility::string_t(U("noslash"))); + VERIFY_ARE_EQUAL(1u, s.size()); + VERIFY_ARE_EQUAL(U("noslash"), s[0]); } + + TEST(split_query_basic) { - // Separating with ';' - std::map keyMap = uri::split_query(utility::string_t(U("key=value%26key1%20=value1;key2=%5Evalue2;key3=value3%20"))); - VERIFY_ARE_EQUAL(3u, keyMap.size()); - auto iter = keyMap.begin(); - VERIFY_ARE_EQUAL(U("key"), iter->first); - VERIFY_ARE_EQUAL(U("value%26key1%20=value1"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("key2"), iter->first); - VERIFY_ARE_EQUAL(U("%5Evalue2"), iter->second); - ++iter; - VERIFY_ARE_EQUAL(U("key3"), iter->first); - VERIFY_ARE_EQUAL(U("value3%20"), iter->second); + { + // Separating with '&' + std::map keyMap = + uri::split_query(U("key1=value1&key2=value2&key3=value3")); + VERIFY_ARE_EQUAL(3u, keyMap.size()); + auto iter = keyMap.begin(); + VERIFY_ARE_EQUAL(U("key1"), iter->first); + VERIFY_ARE_EQUAL(U("value1"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("key2"), iter->first); + VERIFY_ARE_EQUAL(U("value2"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("key3"), iter->first); + VERIFY_ARE_EQUAL(U("value3"), iter->second); + } + { + // Separating with ';' + std::map keyMap = + uri::split_query(U("key1=value1;key2=value2;key3=value3")); + VERIFY_ARE_EQUAL(3u, keyMap.size()); + auto iter = keyMap.begin(); + VERIFY_ARE_EQUAL(U("key1"), iter->first); + VERIFY_ARE_EQUAL(U("value1"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("key2"), iter->first); + VERIFY_ARE_EQUAL(U("value2"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("key3"), iter->first); + VERIFY_ARE_EQUAL(U("value3"), iter->second); + } } -} -TEST(split_query_empty) -{ - std::map keyMap = uri::split_query(U("")); - VERIFY_ARE_EQUAL(0u, keyMap.size()); -} - -TEST(split_query_single) -{ - std::map keyMap = uri::split_query(U("key1=44")); - VERIFY_ARE_EQUAL(1u, keyMap.size()); - auto iter = keyMap.begin(); - VERIFY_ARE_EQUAL(U("key1"), iter->first); - VERIFY_ARE_EQUAL(U("44"), iter->second); -} - -TEST(split_query_no_value) -{ - std::map keyMap = uri::split_query(U("key1")); - VERIFY_ARE_EQUAL(0u, keyMap.size()); - keyMap = uri::split_query(U("key1=")); - VERIFY_ARE_EQUAL(1u, keyMap.size()); - auto iter = keyMap.begin(); - VERIFY_ARE_EQUAL(U("key1"), iter->first); - VERIFY_ARE_EQUAL(U(""), iter->second); - keyMap = uri::split_query(U("key1&")); - VERIFY_ARE_EQUAL(0u, keyMap.size()); -} + TEST(split_encoded_query) + { + { + // Separating with '&' + std::map keyMap = + uri::split_query(utility::string_t(U("key=value%26key1%20=value1&key2=%5Evalue2&key3=value3%20"))); + VERIFY_ARE_EQUAL(3u, keyMap.size()); + auto iter = keyMap.begin(); + VERIFY_ARE_EQUAL(U("key"), iter->first); + VERIFY_ARE_EQUAL(U("value%26key1%20=value1"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("key2"), iter->first); + VERIFY_ARE_EQUAL(U("%5Evalue2"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("key3"), iter->first); + VERIFY_ARE_EQUAL(U("value3%20"), iter->second); + } + { + // Separating with ';' + std::map keyMap = + uri::split_query(utility::string_t(U("key=value%26key1%20=value1;key2=%5Evalue2;key3=value3%20"))); + VERIFY_ARE_EQUAL(3u, keyMap.size()); + auto iter = keyMap.begin(); + VERIFY_ARE_EQUAL(U("key"), iter->first); + VERIFY_ARE_EQUAL(U("value%26key1%20=value1"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("key2"), iter->first); + VERIFY_ARE_EQUAL(U("%5Evalue2"), iter->second); + ++iter; + VERIFY_ARE_EQUAL(U("key3"), iter->first); + VERIFY_ARE_EQUAL(U("value3%20"), iter->second); + } + } -TEST(split_query_no_key) -{ - std::map keyMap = uri::split_query(U("=value1")); - VERIFY_ARE_EQUAL(1u, keyMap.size()); - auto iter = keyMap.begin(); - VERIFY_ARE_EQUAL(U(""), iter->first); - VERIFY_ARE_EQUAL(U("value1"), iter->second); -} + TEST(split_query_empty) + { + std::map keyMap = uri::split_query(U("")); + VERIFY_ARE_EQUAL(0u, keyMap.size()); + } -TEST(split_query_end_with_amp) -{ + TEST(split_query_single) { - // Separating with '&' - std::map keyMap = uri::split_query(U("key1=44&")); + std::map keyMap = uri::split_query(U("key1=44")); VERIFY_ARE_EQUAL(1u, keyMap.size()); auto iter = keyMap.begin(); VERIFY_ARE_EQUAL(U("key1"), iter->first); VERIFY_ARE_EQUAL(U("44"), iter->second); } + + TEST(split_query_no_value) { - // Separating with ';' - std::map keyMap = uri::split_query(U("key1=44;")); + std::map keyMap = uri::split_query(U("key1")); + VERIFY_ARE_EQUAL(0u, keyMap.size()); + keyMap = uri::split_query(U("key1=")); VERIFY_ARE_EQUAL(1u, keyMap.size()); auto iter = keyMap.begin(); VERIFY_ARE_EQUAL(U("key1"), iter->first); - VERIFY_ARE_EQUAL(U("44"), iter->second); + VERIFY_ARE_EQUAL(U(""), iter->second); + keyMap = uri::split_query(U("key1&")); + VERIFY_ARE_EQUAL(0u, keyMap.size()); + } + + TEST(split_query_no_key) + { + std::map keyMap = uri::split_query(U("=value1")); + VERIFY_ARE_EQUAL(1u, keyMap.size()); + auto iter = keyMap.begin(); + VERIFY_ARE_EQUAL(U(""), iter->first); + VERIFY_ARE_EQUAL(U("value1"), iter->second); + } + + TEST(split_query_end_with_amp) + { + { + // Separating with '&' + std::map keyMap = uri::split_query(U("key1=44&")); + VERIFY_ARE_EQUAL(1u, keyMap.size()); + auto iter = keyMap.begin(); + VERIFY_ARE_EQUAL(U("key1"), iter->first); + VERIFY_ARE_EQUAL(U("44"), iter->second); + } + { + // Separating with ';' + std::map keyMap = uri::split_query(U("key1=44;")); + VERIFY_ARE_EQUAL(1u, keyMap.size()); + auto iter = keyMap.begin(); + VERIFY_ARE_EQUAL(U("key1"), iter->first); + VERIFY_ARE_EQUAL(U("44"), iter->second); + } } -} } // SUITE(splitting_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/stdafx.cpp b/Release/tests/functional/uri/stdafx.cpp index 84ac9e6db3..3ca0605cb3 100644 --- a/Release/tests/functional/uri/stdafx.cpp +++ b/Release/tests/functional/uri/stdafx.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ -// stdafx.cpp : +// stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" #if WIN32 __declspec(dllexport) int uri_test_generate_lib = 0; -#endif \ No newline at end of file +#endif diff --git a/Release/tests/functional/uri/stdafx.h b/Release/tests/functional/uri/stdafx.h index b91b05c16f..4086ad42e9 100644 --- a/Release/tests/functional/uri/stdafx.h +++ b/Release/tests/functional/uri/stdafx.h @@ -1,20 +1,19 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.h + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include "cpprest/uri.h" #include "cpprest/asyncrt_utils.h" - +#include "cpprest/uri.h" #include "unittestpp.h" -#include "uri_tests.h" \ No newline at end of file +#include "uri_tests.h" diff --git a/Release/tests/functional/uri/uri_builder_tests.cpp b/Release/tests/functional/uri/uri_builder_tests.cpp index df15143d73..5a869a01ba 100644 --- a/Release/tests/functional/uri/uri_builder_tests.cpp +++ b/Release/tests/functional/uri/uri_builder_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests for the URI builder class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests for the URI builder class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -16,18 +16,21 @@ using namespace web; using namespace utility; -namespace tests { namespace functional { namespace uri_tests { - +namespace tests +{ +namespace functional +{ +namespace uri_tests +{ // Helper functions to verify components of a builder. -static void VERIFY_URI_BUILDER( - uri_builder &builder, - const utility::string_t &scheme, - const utility::string_t &user_info, - const utility::string_t &host, - const int port, - const utility::string_t &path, - const utility::string_t &query, - const utility::string_t &fragment) +static void VERIFY_URI_BUILDER(uri_builder& builder, + const utility::string_t& scheme, + const utility::string_t& user_info, + const utility::string_t& host, + const int port, + const utility::string_t& path, + const utility::string_t& query, + const utility::string_t& fragment) { VERIFY_ARE_EQUAL(scheme, builder.scheme()); VERIFY_ARE_EQUAL(host, builder.host()); @@ -37,546 +40,571 @@ static void VERIFY_URI_BUILDER( VERIFY_ARE_EQUAL(query, builder.query()); VERIFY_ARE_EQUAL(fragment, builder.fragment()); } -static void VERIFY_URI_BUILDER( - uri_builder &builder, - const utility::string_t &scheme, - const utility::string_t &host, - const int port) +static void VERIFY_URI_BUILDER(uri_builder& builder, + const utility::string_t& scheme, + const utility::string_t& host, + const int port) { - VERIFY_URI_BUILDER(builder, scheme, utility::string_t(), host, port, utility::string_t(U("/")), utility::string_t(), utility::string_t()); + VERIFY_URI_BUILDER(builder, + scheme, + utility::string_t(), + host, + port, + utility::string_t(U("/")), + utility::string_t(), + utility::string_t()); } -static void VERIFY_URI_BUILDER_IS_EMPTY(uri_builder &builder) +static void VERIFY_URI_BUILDER_IS_EMPTY(uri_builder& builder) { - VERIFY_URI_BUILDER(builder, utility::string_t(), utility::string_t(), utility::string_t(), -1, utility::string_t(U("/")), utility::string_t(), utility::string_t()); + VERIFY_URI_BUILDER(builder, + utility::string_t(), + utility::string_t(), + utility::string_t(), + -1, + utility::string_t(U("/")), + utility::string_t(), + utility::string_t()); } SUITE(uri_builder_tests) { + TEST(constructor_tests) + { + // Default constructor + uri_builder builder; + VERIFY_URI_BUILDER_IS_EMPTY(builder); + // scheme, user_info, host, port + utility::string_t scheme(U("ftp")); + utility::string_t user_info(U("steve:pass")); + utility::string_t host(U("localhost")); + int port = 44; + utility::string_t path(U("/Yeshere888")); + utility::string_t uri_str(U("ftp://steve:pass@localhost:44/Yeshere888")); + + // utility::string_t + utility::string_t uri_wstr(U("ftp://steve:pass@localhost:44/Yeshere888?abc:123&abc2:456#nose")); + builder = uri_builder(uri_wstr); + VERIFY_URI_BUILDER(builder, + scheme, + user_info, + host, + port, + path, + utility::string_t(U("abc:123&abc2:456")), + utility::string_t(U("nose"))); + + // copy constructor + uri_builder other(builder); + builder = uri_builder(uri_str); + VERIFY_URI_BUILDER(other, + scheme, + user_info, + host, + port, + path, + utility::string_t(U("abc:123&abc2:456")), + utility::string_t(U("nose"))); + VERIFY_URI_BUILDER(builder, scheme, user_info, host, port, path, U(""), U("")); + + // move constructor + uri_builder move_other = std::move(builder); + VERIFY_URI_BUILDER(move_other, scheme, user_info, host, port, path, U(""), U("")); + } -TEST(constructor_tests) -{ - // Default constructor - uri_builder builder; - VERIFY_URI_BUILDER_IS_EMPTY(builder); - // scheme, user_info, host, port - utility::string_t scheme(U("ftp")); - utility::string_t user_info(U("steve:pass")); - utility::string_t host(U("localhost")); - int port = 44; - utility::string_t path(U("/Yeshere888")); - utility::string_t uri_str(U("ftp://steve:pass@localhost:44/Yeshere888")); - - // utility::string_t - utility::string_t uri_wstr(U("ftp://steve:pass@localhost:44/Yeshere888?abc:123&abc2:456#nose")); - builder = uri_builder(uri_wstr); - VERIFY_URI_BUILDER(builder, scheme, user_info, host, port, path, utility::string_t(U("abc:123&abc2:456")), utility::string_t(U("nose"))); - - // copy constructor - uri_builder other(builder); - builder = uri_builder(uri_str); - VERIFY_URI_BUILDER(other, scheme, user_info, host, port, path, utility::string_t(U("abc:123&abc2:456")), utility::string_t(U("nose"))); - VERIFY_URI_BUILDER(builder, scheme, user_info, host, port, path, U(""), U("")); - - // move constructor - uri_builder move_other = std::move(builder); - VERIFY_URI_BUILDER(move_other, scheme, user_info, host, port, path, U(""), U("")); -} - -TEST(assignment_operators) -{ - // assignment operator - const utility::string_t scheme = U("http"), host = U("localhost"); - const int port = 44; - uri_builder original; - original.set_scheme(scheme).set_host(host).set_port(port); - uri_builder assign; - assign = original; - VERIFY_URI_BUILDER(assign, scheme, utility::string_t(host), port); - - // move assignment operator - uri_builder move_assign; - move_assign = std::move(original); - VERIFY_URI_BUILDER(assign, scheme, utility::string_t(host), port); -} - -TEST(set_port_as_string) -{ - uri_builder builder; + TEST(assignment_operators) + { + // assignment operator + const utility::string_t scheme = U("http"), host = U("localhost"); + const int port = 44; + uri_builder original; + original.set_scheme(scheme).set_host(host).set_port(port); + uri_builder assign; + assign = original; + VERIFY_URI_BUILDER(assign, scheme, utility::string_t(host), port); + + // move assignment operator + uri_builder move_assign; + move_assign = std::move(original); + VERIFY_URI_BUILDER(assign, scheme, utility::string_t(host), port); + } - VERIFY_THROWS(builder.set_port(U("")), std::invalid_argument); - VERIFY_ARE_EQUAL(-1, builder.port()); + TEST(set_port_as_string) + { + uri_builder builder; - builder.set_port(U("987")); - VERIFY_ARE_EQUAL(987, builder.port()); + VERIFY_THROWS(builder.set_port(U("")), std::invalid_argument); + VERIFY_ARE_EQUAL(-1, builder.port()); - VERIFY_THROWS(builder.set_port(U("abc")), std::invalid_argument); - VERIFY_ARE_EQUAL(987, builder.port()); + builder.set_port(U("987")); + VERIFY_ARE_EQUAL(987, builder.port()); - builder.set_port(U(" 44 ")); - VERIFY_ARE_EQUAL(44, builder.port()); + VERIFY_THROWS(builder.set_port(U("abc")), std::invalid_argument); + VERIFY_ARE_EQUAL(987, builder.port()); - builder.set_port(U("99")); - VERIFY_ARE_EQUAL(99, builder.port()); -} + builder.set_port(U(" 44 ")); + VERIFY_ARE_EQUAL(44, builder.port()); -TEST(component_assignment) -{ - uri_builder builder; - const utility::string_t scheme(U("myscheme")); - const utility::string_t uinfo(U("johndoe:test")); - const utility::string_t host(U("localhost")); - const int port = 88; - const utility::string_t path(U("jklajsd")); - const utility::string_t query(U("key1=val1")); - const utility::string_t fragment(U("last")); - - builder.set_scheme(scheme); - builder.set_user_info(uinfo); - builder.set_host(host); - builder.set_port(port); - builder.set_path(path); - builder.set_query(query); - builder.set_fragment(fragment); - - VERIFY_URI_BUILDER(builder, scheme, uinfo, host, port, path, query, fragment); -} + builder.set_port(U("99")); + VERIFY_ARE_EQUAL(99, builder.port()); + } -TEST(component_assignment_encode) -{ + TEST(component_assignment) { uri_builder builder; const utility::string_t scheme(U("myscheme")); const utility::string_t uinfo(U("johndoe:test")); const utility::string_t host(U("localhost")); const int port = 88; - const utility::string_t path(U("jklajsd/yes no")); - const utility::string_t query(U("key1=va%l1")); - const utility::string_t fragment(U("las t")); + const utility::string_t path(U("jklajsd")); + const utility::string_t query(U("key1=val1")); + const utility::string_t fragment(U("last")); builder.set_scheme(scheme); - builder.set_user_info(uinfo, true); - builder.set_host(host, true); + builder.set_user_info(uinfo); + builder.set_host(host); builder.set_port(port); - builder.set_path(path, true); - builder.set_query(query, true); - builder.set_fragment(fragment, true); - - VERIFY_URI_BUILDER( - builder, - scheme, - utility::string_t(U("johndoe:test")), - utility::string_t(U("localhost")), - port, - utility::string_t(U("jklajsd/yes%20no")), - utility::string_t(U("key1=va%25l1")), - utility::string_t(U("las%20t"))); - } - { - uri_builder builder; - const utility::string_t scheme(U("myscheme")); - const utility::string_t uinfo(U("johndoe:test")); - const utility::string_t host(U("localhost")); - const int port = 88; - const utility::string_t path(U("jklajsd/yes no")); - const utility::string_t query(U("key1=va%l1")); - const utility::string_t fragment(U("las t")); + builder.set_path(path); + builder.set_query(query); + builder.set_fragment(fragment); - builder.set_scheme(scheme); - builder.set_user_info(uinfo, true); - builder.set_host(host, true); - builder.set_port(port); - builder.set_path(path, true); - builder.set_query(query, true); - builder.set_fragment(fragment, true); - - VERIFY_URI_BUILDER( - builder, - scheme, - utility::string_t(U("johndoe:test")), - utility::string_t(U("localhost")), - port, - utility::string_t(U("jklajsd/yes%20no")), - utility::string_t(U("key1=va%25l1")), - utility::string_t(U("las%20t"))); + VERIFY_URI_BUILDER(builder, scheme, uinfo, host, port, path, query, fragment); } -} -TEST(validation) -{ + TEST(component_assignment_encode) { - // true - uri_builder builder(U("http://localhost:4567/")); - VERIFY_IS_TRUE(builder.is_valid()); - - // false - builder = uri_builder(); - builder.set_scheme(U("123")); - VERIFY_IS_FALSE(builder.is_valid()); + { + uri_builder builder; + const utility::string_t scheme(U("myscheme")); + const utility::string_t uinfo(U("johndoe:test")); + const utility::string_t host(U("localhost")); + const int port = 88; + const utility::string_t path(U("jklajsd/yes no")); + const utility::string_t query(U("key1=va%l1")); + const utility::string_t fragment(U("las t")); + + builder.set_scheme(scheme); + builder.set_user_info(uinfo, true); + builder.set_host(host, true); + builder.set_port(port); + builder.set_path(path, true); + builder.set_query(query, true); + builder.set_fragment(fragment, true); + + VERIFY_URI_BUILDER(builder, + scheme, + utility::string_t(U("johndoe:test")), + utility::string_t(U("localhost")), + port, + utility::string_t(U("jklajsd/yes%20no")), + utility::string_t(U("key1=va%25l1")), + utility::string_t(U("las%20t"))); + } + { + uri_builder builder; + const utility::string_t scheme(U("myscheme")); + const utility::string_t uinfo(U("johndoe:test")); + const utility::string_t host(U("localhost")); + const int port = 88; + const utility::string_t path(U("jklajsd/yes no")); + const utility::string_t query(U("key1=va%l1")); + const utility::string_t fragment(U("las t")); + + builder.set_scheme(scheme); + builder.set_user_info(uinfo, true); + builder.set_host(host, true); + builder.set_port(port); + builder.set_path(path, true); + builder.set_query(query, true); + builder.set_fragment(fragment, true); + + VERIFY_URI_BUILDER(builder, + scheme, + utility::string_t(U("johndoe:test")), + utility::string_t(U("localhost")), + port, + utility::string_t(U("jklajsd/yes%20no")), + utility::string_t(U("key1=va%25l1")), + utility::string_t(U("las%20t"))); + } } - { - // true - uri_builder builder(U("http://localhost:4567/")); - VERIFY_IS_TRUE(builder.is_valid()); - // false - builder = uri_builder(); - builder.set_scheme(U("123")); - VERIFY_IS_FALSE(builder.is_valid()); + TEST(validation) + { + { + // true + uri_builder builder(U("http://localhost:4567/")); + VERIFY_IS_TRUE(builder.is_valid()); + + // false + builder = uri_builder(); + builder.set_scheme(U("123")); + VERIFY_IS_FALSE(builder.is_valid()); + } + { + // true + uri_builder builder(U("http://localhost:4567/")); + VERIFY_IS_TRUE(builder.is_valid()); + + // false + builder = uri_builder(); + builder.set_scheme(U("123")); + VERIFY_IS_FALSE(builder.is_valid()); + } } -} -TEST(uri_creation_string) -{ - utility::string_t uri_str(U("http://steve:temp@localhost:4556/")); + TEST(uri_creation_string) + { + utility::string_t uri_str(U("http://steve:temp@localhost:4556/")); - // to_string - uri_builder builder(uri_str); - VERIFY_ARE_EQUAL(uri_str, builder.to_string()); + // to_string + uri_builder builder(uri_str); + VERIFY_ARE_EQUAL(uri_str, builder.to_string()); - // to_string - VERIFY_ARE_EQUAL(uri_str, builder.to_string()); + // to_string + VERIFY_ARE_EQUAL(uri_str, builder.to_string()); - // to uri - VERIFY_ARE_EQUAL(uri_str, builder.to_uri().to_string()); + // to uri + VERIFY_ARE_EQUAL(uri_str, builder.to_uri().to_string()); - // to encoded string - uri_builder with_space(builder); - with_space.set_path(utility::string_t(U("path%20with%20space"))); - VERIFY_ARE_EQUAL(U("http://steve:temp@localhost:4556/path%20with%20space"), with_space.to_string()); -} + // to encoded string + uri_builder with_space(builder); + with_space.set_path(utility::string_t(U("path%20with%20space"))); + VERIFY_ARE_EQUAL(U("http://steve:temp@localhost:4556/path%20with%20space"), with_space.to_string()); + } -TEST(append_path_string) -{ - // empty uri builder path - uri_builder builder; - builder.append_path(U("/path1")); - VERIFY_ARE_EQUAL(U("/path1"), builder.path()); - - // empty append path - builder.append_path(U("")); - VERIFY_ARE_EQUAL(U("/path1"), builder.path()); - - // uri builder with slash - builder.append_path(U("/")); - builder.append_path(U("path2")); - VERIFY_ARE_EQUAL(U("/path1/path2"), builder.path()); - - // both with slash - builder.append_path(U("/")); - builder.append_path(U("/path3")); - VERIFY_ARE_EQUAL(U("/path1/path2/path3"), builder.path()); - - // both without slash - builder.append_path(U("path4")); - VERIFY_ARE_EQUAL(U("/path1/path2/path3/path4"), builder.path()); - - // encoding - builder.clear(); - builder.append_path(U("encode%things")); - VERIFY_ARE_EQUAL(U("/encode%things"), builder.path()); - - builder.clear(); - builder.append_path(U("encode%things"), false); - VERIFY_ARE_EQUAL(U("/encode%things"), builder.path()); - - builder.clear(); - builder.append_path(U("encode%things"), true); - VERIFY_ARE_EQUAL(U("/encode%25things"), builder.path()); - - // self references - builder.set_path(U("example")); - builder.append_path(builder.path()); - VERIFY_ARE_EQUAL(U("example/example"), builder.path()); - - builder.set_path(U("/example")); - builder.append_path(builder.path()); - VERIFY_ARE_EQUAL(U("/example/example"), builder.path()); - - builder.set_path(U("/example/")); - builder.append_path(builder.path()); - VERIFY_ARE_EQUAL(U("/example/example/"), builder.path()); -} + TEST(append_path_string) + { + // empty uri builder path + uri_builder builder; + builder.append_path(U("/path1")); + VERIFY_ARE_EQUAL(U("/path1"), builder.path()); + + // empty append path + builder.append_path(U("")); + VERIFY_ARE_EQUAL(U("/path1"), builder.path()); + + // uri builder with slash + builder.append_path(U("/")); + builder.append_path(U("path2")); + VERIFY_ARE_EQUAL(U("/path1/path2"), builder.path()); + + // both with slash + builder.append_path(U("/")); + builder.append_path(U("/path3")); + VERIFY_ARE_EQUAL(U("/path1/path2/path3"), builder.path()); + + // both without slash + builder.append_path(U("path4")); + VERIFY_ARE_EQUAL(U("/path1/path2/path3/path4"), builder.path()); + + // encoding + builder.clear(); + builder.append_path(U("encode%things")); + VERIFY_ARE_EQUAL(U("/encode%things"), builder.path()); + + builder.clear(); + builder.append_path(U("encode%things"), false); + VERIFY_ARE_EQUAL(U("/encode%things"), builder.path()); + + builder.clear(); + builder.append_path(U("encode%things"), true); + VERIFY_ARE_EQUAL(U("/encode%25things"), builder.path()); + + // self references + builder.set_path(U("example")); + builder.append_path(builder.path()); + VERIFY_ARE_EQUAL(U("example/example"), builder.path()); + + builder.set_path(U("/example")); + builder.append_path(builder.path()); + VERIFY_ARE_EQUAL(U("/example/example"), builder.path()); + + builder.set_path(U("/example/")); + builder.append_path(builder.path()); + VERIFY_ARE_EQUAL(U("/example/example/"), builder.path()); + } -TEST(append_path_raw_string) -{ - // empty uri builder path - uri_builder builder; - builder.append_path_raw(U("path1")); - VERIFY_ARE_EQUAL(U("/path1"), builder.path()); - - // empty append path - builder.append_path_raw(U("")); - VERIFY_ARE_EQUAL(U("/path1"), builder.path()); - - // uri builder with slash - builder.append_path_raw(U("/")); - builder.append_path_raw(U("path2")); - VERIFY_ARE_EQUAL(U("/path1///path2"), builder.path()); - - // leading slash (should result in "//") - builder.append_path_raw(U("/path3")); - VERIFY_ARE_EQUAL(U("/path1///path2//path3"), builder.path()); - - // trailing slash - builder.append_path_raw(U("path4/")); - builder.append_path_raw(U("path5")); - VERIFY_ARE_EQUAL(U("/path1///path2//path3/path4//path5"), builder.path()); - - // encoding - builder.clear(); - builder.append_path_raw(U("encode%things")); - VERIFY_ARE_EQUAL(U("/encode%things"), builder.path()); - - builder.clear(); - builder.append_path_raw(U("encode%things"), false); - VERIFY_ARE_EQUAL(U("/encode%things"), builder.path()); - - builder.clear(); - builder.append_path_raw(U("encode%things"), true); - VERIFY_ARE_EQUAL(U("/encode%25things"), builder.path()); - - // self references - builder.set_path(U("example")); - builder.append_path_raw(builder.path()); - VERIFY_ARE_EQUAL(U("example/example"), builder.path()); - - builder.set_path(U("/example")); - builder.append_path_raw(builder.path()); - VERIFY_ARE_EQUAL(U("/example//example"), builder.path()); - - builder.set_path(U("/example/")); - builder.append_path_raw(builder.path()); - VERIFY_ARE_EQUAL(U("/example///example/"), builder.path()); -} + TEST(append_path_raw_string) + { + // empty uri builder path + uri_builder builder; + builder.append_path_raw(U("path1")); + VERIFY_ARE_EQUAL(U("/path1"), builder.path()); + + // empty append path + builder.append_path_raw(U("")); + VERIFY_ARE_EQUAL(U("/path1"), builder.path()); + + // uri builder with slash + builder.append_path_raw(U("/")); + builder.append_path_raw(U("path2")); + VERIFY_ARE_EQUAL(U("/path1///path2"), builder.path()); + + // leading slash (should result in "//") + builder.append_path_raw(U("/path3")); + VERIFY_ARE_EQUAL(U("/path1///path2//path3"), builder.path()); + + // trailing slash + builder.append_path_raw(U("path4/")); + builder.append_path_raw(U("path5")); + VERIFY_ARE_EQUAL(U("/path1///path2//path3/path4//path5"), builder.path()); + + // encoding + builder.clear(); + builder.append_path_raw(U("encode%things")); + VERIFY_ARE_EQUAL(U("/encode%things"), builder.path()); + + builder.clear(); + builder.append_path_raw(U("encode%things"), false); + VERIFY_ARE_EQUAL(U("/encode%things"), builder.path()); + + builder.clear(); + builder.append_path_raw(U("encode%things"), true); + VERIFY_ARE_EQUAL(U("/encode%25things"), builder.path()); + + // self references + builder.set_path(U("example")); + builder.append_path_raw(builder.path()); + VERIFY_ARE_EQUAL(U("example/example"), builder.path()); + + builder.set_path(U("/example")); + builder.append_path_raw(builder.path()); + VERIFY_ARE_EQUAL(U("/example//example"), builder.path()); + + builder.set_path(U("/example/")); + builder.append_path_raw(builder.path()); + VERIFY_ARE_EQUAL(U("/example///example/"), builder.path()); + } -TEST(append_query_string) -{ - // empty uri builder query - uri_builder builder; - builder.append_query(U("key1=value1")); - VERIFY_ARE_EQUAL(U("key1=value1"), builder.query()); - - // empty append query - builder.append_query(U("")); - VERIFY_ARE_EQUAL(U("key1=value1"), builder.query()); - - // uri builder with ampersand - builder.append_query(U("&")); - builder.append_query(U("key2=value2")); - VERIFY_ARE_EQUAL(U("key1=value1&key2=value2"), builder.query()); - - // both with ampersand - builder.append_query(U("&")); - builder.append_query(U("&key3=value3")); - VERIFY_ARE_EQUAL(U("key1=value1&key2=value2&key3=value3"), builder.query()); - - // both without ampersand - builder.append_query(U("key4=value4")); - VERIFY_ARE_EQUAL(U("key1=value1&key2=value2&key3=value3&key4=value4"), builder.query()); - - // number query - builder.append_query(U("key5"), 1); - VERIFY_ARE_EQUAL(U("key1=value1&key2=value2&key3=value3&key4=value4&key5=1"), builder.query()); - - // string query - builder.append_query(U("key6"), U("val6")); - VERIFY_ARE_EQUAL(U("key1=value1&key2=value2&key3=value3&key4=value4&key5=1&key6=val6"), builder.query()); - - // key and value separate with '=', '&', and ';' - builder.append_query(U("key=&;"), U("=&;value")); - VERIFY_ARE_EQUAL(U("key1=value1&key2=value2&key3=value3&key4=value4&key5=1&key6=val6&key%3D%26%3B=%3D%26%3Bvalue"), builder.query()); - - // self references - builder.set_query(U("example")); - builder.append_query(builder.query()); - VERIFY_ARE_EQUAL(U("example&example"), builder.query()); - - builder.set_query(U("&example")); - builder.append_query(builder.query()); - VERIFY_ARE_EQUAL(U("&example&example"), builder.query()); - - builder.set_query(U("&example&")); - builder.append_query(builder.query()); - VERIFY_ARE_EQUAL(U("&example&example&"), builder.query()); -} + TEST(append_query_string) + { + // empty uri builder query + uri_builder builder; + builder.append_query(U("key1=value1")); + VERIFY_ARE_EQUAL(U("key1=value1"), builder.query()); + + // empty append query + builder.append_query(U("")); + VERIFY_ARE_EQUAL(U("key1=value1"), builder.query()); + + // uri builder with ampersand + builder.append_query(U("&")); + builder.append_query(U("key2=value2")); + VERIFY_ARE_EQUAL(U("key1=value1&key2=value2"), builder.query()); + + // both with ampersand + builder.append_query(U("&")); + builder.append_query(U("&key3=value3")); + VERIFY_ARE_EQUAL(U("key1=value1&key2=value2&key3=value3"), builder.query()); + + // both without ampersand + builder.append_query(U("key4=value4")); + VERIFY_ARE_EQUAL(U("key1=value1&key2=value2&key3=value3&key4=value4"), builder.query()); + + // number query + builder.append_query(U("key5"), 1); + VERIFY_ARE_EQUAL(U("key1=value1&key2=value2&key3=value3&key4=value4&key5=1"), builder.query()); + + // string query + builder.append_query(U("key6"), U("val6")); + VERIFY_ARE_EQUAL(U("key1=value1&key2=value2&key3=value3&key4=value4&key5=1&key6=val6"), builder.query()); + + // key and value separate with '=', '&', and ';' + builder.append_query(U("key=&;"), U("=&;value")); + VERIFY_ARE_EQUAL( + U("key1=value1&key2=value2&key3=value3&key4=value4&key5=1&key6=val6&key%3D%26%3B=%3D%26%3Bvalue"), + builder.query()); + + // self references + builder.set_query(U("example")); + builder.append_query(builder.query()); + VERIFY_ARE_EQUAL(U("example&example"), builder.query()); + + builder.set_query(U("&example")); + builder.append_query(builder.query()); + VERIFY_ARE_EQUAL(U("&example&example"), builder.query()); + + builder.set_query(U("&example&")); + builder.append_query(builder.query()); + VERIFY_ARE_EQUAL(U("&example&example&"), builder.query()); + } -TEST(append_query_string_no_encode) -{ - uri_builder builder; - builder.append_query(U("key=&;"), U("=&;value"), false); - VERIFY_ARE_EQUAL(U("key=&;==&;value"), builder.query()); -} + TEST(append_query_string_no_encode) + { + uri_builder builder; + builder.append_query(U("key=&;"), U("=&;value"), false); + VERIFY_ARE_EQUAL(U("key=&;==&;value"), builder.query()); + } -TEST(append_string) -{ - // with just path - uri_builder builder; - builder.append(U("/path1")); - VERIFY_ARE_EQUAL(U("/path1"), builder.path()); - - // with just query - builder.append(U("?key1=value1")); - VERIFY_ARE_EQUAL(U("/path1"), builder.path()); - VERIFY_ARE_EQUAL(U("key1=value1"), builder.query()); - VERIFY_ARE_EQUAL(U("/path1?key1=value1"), builder.to_string()); - - // with just fragment - builder.append(U("#fragment")); - VERIFY_ARE_EQUAL(U("/path1"), builder.path()); - VERIFY_ARE_EQUAL(U("key1=value1"), builder.query()); - VERIFY_ARE_EQUAL(U("fragment"), builder.fragment()); - VERIFY_ARE_EQUAL(U("/path1?key1=value1#fragment"), builder.to_string()); - - // with all - builder.append(U("/path2?key2=value2#frag2")); - VERIFY_ARE_EQUAL(U("/path1/path2"), builder.path()); - VERIFY_ARE_EQUAL(U("key1=value1&key2=value2"), builder.query()); - VERIFY_ARE_EQUAL(U("fragmentfrag2"), builder.fragment()); - VERIFY_ARE_EQUAL(U("/path1/path2?key1=value1&key2=value2#fragmentfrag2"), builder.to_string()); -} + TEST(append_string) + { + // with just path + uri_builder builder; + builder.append(U("/path1")); + VERIFY_ARE_EQUAL(U("/path1"), builder.path()); + + // with just query + builder.append(U("?key1=value1")); + VERIFY_ARE_EQUAL(U("/path1"), builder.path()); + VERIFY_ARE_EQUAL(U("key1=value1"), builder.query()); + VERIFY_ARE_EQUAL(U("/path1?key1=value1"), builder.to_string()); + + // with just fragment + builder.append(U("#fragment")); + VERIFY_ARE_EQUAL(U("/path1"), builder.path()); + VERIFY_ARE_EQUAL(U("key1=value1"), builder.query()); + VERIFY_ARE_EQUAL(U("fragment"), builder.fragment()); + VERIFY_ARE_EQUAL(U("/path1?key1=value1#fragment"), builder.to_string()); + + // with all + builder.append(U("/path2?key2=value2#frag2")); + VERIFY_ARE_EQUAL(U("/path1/path2"), builder.path()); + VERIFY_ARE_EQUAL(U("key1=value1&key2=value2"), builder.query()); + VERIFY_ARE_EQUAL(U("fragmentfrag2"), builder.fragment()); + VERIFY_ARE_EQUAL(U("/path1/path2?key1=value1&key2=value2#fragmentfrag2"), builder.to_string()); + } -TEST(append_empty_string) -{ - utility::string_t uri_str(U("http://uribuilder.com/")); - uri_builder builder(uri_str); - builder.append(U("")); + TEST(append_empty_string) + { + utility::string_t uri_str(U("http://uribuilder.com/")); + uri_builder builder(uri_str); + builder.append(U("")); - VERIFY_ARE_EQUAL(builder.to_string(), uri_str); -} + VERIFY_ARE_EQUAL(builder.to_string(), uri_str); + } -TEST(append_path_encoding) -{ - uri_builder builder; - builder.append_path(U("/path space"), true); - VERIFY_ARE_EQUAL(U("/path%20space"), builder.path()); + TEST(append_path_encoding) + { + uri_builder builder; + builder.append_path(U("/path space"), true); + VERIFY_ARE_EQUAL(U("/path%20space"), builder.path()); - builder.append_path(U("path2")); - VERIFY_ARE_EQUAL(U("/path%20space/path2"), builder.path()); -} + builder.append_path(U("path2")); + VERIFY_ARE_EQUAL(U("/path%20space/path2"), builder.path()); + } -TEST(append_query_encoding) -{ - uri_builder builder; - builder.append_query(U("key1 =value2"), true); - VERIFY_ARE_EQUAL(U("key1%20=value2"), builder.query()); + TEST(append_query_encoding) + { + uri_builder builder; + builder.append_query(U("key1 =value2"), true); + VERIFY_ARE_EQUAL(U("key1%20=value2"), builder.query()); - builder.append_query(U("key2=value3")); - VERIFY_ARE_EQUAL(U("key1%20=value2&key2=value3"), builder.query()); -} + builder.append_query(U("key2=value3")); + VERIFY_ARE_EQUAL(U("key1%20=value2&key2=value3"), builder.query()); + } -TEST(append_encoding) -{ - uri_builder builder; - builder.append(uri::encode_uri(U("path space?key =space#frag space"))); - VERIFY_ARE_EQUAL(U("/path%20space"), builder.path()); - VERIFY_ARE_EQUAL(U("key%20=space"), builder.query()); - VERIFY_ARE_EQUAL(U("frag%20space"), builder.fragment()); - VERIFY_ARE_EQUAL(U("/path%20space?key%20=space#frag%20space"), builder.to_string()); - - // try with encoded_string - builder = uri_builder(); - builder.append(U("/path2?key2=value2#frag2")); - VERIFY_ARE_EQUAL(U("/path2"), builder.path()); - VERIFY_ARE_EQUAL(U("key2=value2"), builder.query()); - VERIFY_ARE_EQUAL(U("frag2"), builder.fragment()); - VERIFY_ARE_EQUAL(U("/path2?key2=value2#frag2"), builder.to_string()); -} + TEST(append_encoding) + { + uri_builder builder; + builder.append(uri::encode_uri(U("path space?key =space#frag space"))); + VERIFY_ARE_EQUAL(U("/path%20space"), builder.path()); + VERIFY_ARE_EQUAL(U("key%20=space"), builder.query()); + VERIFY_ARE_EQUAL(U("frag%20space"), builder.fragment()); + VERIFY_ARE_EQUAL(U("/path%20space?key%20=space#frag%20space"), builder.to_string()); -TEST(host_encoding) -{ - // Check that ASCII characters that are invalid in a host name - // do not get percent-encoded. + // try with encoded_string + builder = uri_builder(); + builder.append(U("/path2?key2=value2#frag2")); + VERIFY_ARE_EQUAL(U("/path2"), builder.path()); + VERIFY_ARE_EQUAL(U("key2=value2"), builder.query()); + VERIFY_ARE_EQUAL(U("frag2"), builder.fragment()); + VERIFY_ARE_EQUAL(U("/path2?key2=value2#frag2"), builder.to_string()); + } - uri_builder ub1; - ub1.set_scheme(U("http")).set_host(U("????dfasddsf!@#$%^&*()_+")).set_port(80); + TEST(host_encoding) + { + // Check that ASCII characters that are invalid in a host name + // do not get percent-encoded. - VERIFY_IS_FALSE(ub1.is_valid()); -} + uri_builder ub1; + ub1.set_scheme(U("http")).set_host(U("????dfasddsf!@#$%^&*()_+")).set_port(80); -TEST(clear) -{ - uri_builder ub; - ub.clear(); - CHECK(ub.scheme() == U("")); - CHECK(ub.user_info() == U("")); - CHECK(ub.host() == U("")); - CHECK(ub.port() == -1); - CHECK(ub.path() == U("/")); - CHECK(ub.query() == U("")); - CHECK(ub.fragment() == U("")); - - ub = uri_builder(U("http://myhost.com/path1")); - ub.append_path(U("path2")); - uri u = ub.to_uri(); - ub.clear(); - CHECK(ub.scheme() == U("")); - CHECK(ub.user_info() == U("")); - CHECK(ub.host() == U("")); - CHECK(ub.port() == -1); - CHECK(ub.path() == U("/")); - CHECK(ub.query() == U("")); - CHECK(ub.fragment() == U("")); - CHECK(u.to_string() == U("http://myhost.com/path1/path2")); - - ub.append_path(U("path3")); - ub.set_host(U("hahah")); - ub.set_fragment(U("No")); - ub.clear(); - CHECK(ub.scheme() == U("")); - CHECK(ub.user_info() == U("")); - CHECK(ub.host() == U("")); - CHECK(ub.port() == -1); - CHECK(ub.path() == U("/")); - CHECK(ub.query() == U("")); - CHECK(ub.fragment() == U("")); -} + VERIFY_IS_FALSE(ub1.is_valid()); + } -TEST(to_string_invalid_uri) -{ - uri_builder builder(U("http://invaliduri.com")); - builder.set_scheme(U("1http")); - VERIFY_THROWS(builder.to_string(), uri_exception); - VERIFY_THROWS(builder.to_uri(), uri_exception); + TEST(clear) + { + uri_builder ub; + ub.clear(); + CHECK(ub.scheme() == U("")); + CHECK(ub.user_info() == U("")); + CHECK(ub.host() == U("")); + CHECK(ub.port() == -1); + CHECK(ub.path() == U("/")); + CHECK(ub.query() == U("")); + CHECK(ub.fragment() == U("")); + + ub = uri_builder(U("http://myhost.com/path1")); + ub.append_path(U("path2")); + uri u = ub.to_uri(); + ub.clear(); + CHECK(ub.scheme() == U("")); + CHECK(ub.user_info() == U("")); + CHECK(ub.host() == U("")); + CHECK(ub.port() == -1); + CHECK(ub.path() == U("/")); + CHECK(ub.query() == U("")); + CHECK(ub.fragment() == U("")); + CHECK(u.to_string() == U("http://myhost.com/path1/path2")); + + ub.append_path(U("path3")); + ub.set_host(U("hahah")); + ub.set_fragment(U("No")); + ub.clear(); + CHECK(ub.scheme() == U("")); + CHECK(ub.user_info() == U("")); + CHECK(ub.host() == U("")); + CHECK(ub.port() == -1); + CHECK(ub.path() == U("/")); + CHECK(ub.query() == U("")); + CHECK(ub.fragment() == U("")); + } - builder.set_scheme(U("ht*ip")); - VERIFY_THROWS(builder.to_string(), uri_exception); + TEST(to_string_invalid_uri) + { + uri_builder builder(U("http://invaliduri.com")); + builder.set_scheme(U("1http")); + VERIFY_THROWS(builder.to_string(), uri_exception); + VERIFY_THROWS(builder.to_uri(), uri_exception); - builder.set_scheme(U("htt%20p")); - VERIFY_THROWS(builder.to_string(), uri_exception); -} + builder.set_scheme(U("ht*ip")); + VERIFY_THROWS(builder.to_string(), uri_exception); -TEST(append_query_locale, "Ignore:Android", "Locale unsupported on Android") -{ - std::locale changedLocale; - try + builder.set_scheme(U("htt%20p")); + VERIFY_THROWS(builder.to_string(), uri_exception); + } + + TEST(append_query_locale, "Ignore:Android", "Locale unsupported on Android") { + std::locale changedLocale; + try + { #ifdef _WIN32 - changedLocale = std::locale("fr-FR"); + changedLocale = std::locale("fr-FR"); #else - changedLocale = std::locale("fr_FR.UTF-8"); + changedLocale = std::locale("fr_FR.UTF-8"); #endif - } - catch (const std::exception &) - { - // Silently pass if locale isn't installed on machine. - return; - } + } + catch (const std::exception&) + { + // Silently pass if locale isn't installed on machine. + return; + } - tests::common::utilities::locale_guard loc(changedLocale); + tests::common::utilities::locale_guard loc(changedLocale); - uri_builder builder; - auto const &key = U("key1000"); - builder.append_query(key, 1000); - ::utility::string_t expected(key); - expected.append(U("=1000")); - VERIFY_ARE_EQUAL(expected, builder.query()); -} + uri_builder builder; + auto const& key = U("key1000"); + builder.append_query(key, 1000); + ::utility::string_t expected(key); + expected.append(U("=1000")); + VERIFY_ARE_EQUAL(expected, builder.query()); + } -TEST(github_crash_994) -{ - web::uri uri(U("http://127.0.0.1:34568/")); -} + TEST(github_crash_994) { web::uri uri(U("http://127.0.0.1:34568/")); } } // SUITE(uri_builder_tests) -}}} +} // namespace uri_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/uri/uri_tests.h b/Release/tests/functional/uri/uri_tests.h index 8e2e82faa0..72271db8b6 100644 --- a/Release/tests/functional/uri/uri_tests.h +++ b/Release/tests/functional/uri/uri_tests.h @@ -1,20 +1,25 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* uri_tests.h -* -* Common utilities and helper functions for URI tests. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * uri_tests.h + * + * Common utilities and helper functions for URI tests. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "cpprest/uri.h" - #include "unittestpp.h" -namespace tests { namespace functional { namespace uri_tests { - -}}} \ No newline at end of file +namespace tests +{ +namespace functional +{ +namespace uri_tests +{ +} +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/utils/base64.cpp b/Release/tests/functional/utils/base64.cpp index ce7d0d5474..30ec199ef2 100644 --- a/Release/tests/functional/utils/base64.cpp +++ b/Release/tests/functional/utils/base64.cpp @@ -1,252 +1,260 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* base64.cpp -* -* Tests for base64-related utility functions and classes. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * base64.cpp + * + * Tests for base64-related utility functions and classes. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace utility; -namespace tests { namespace functional { namespace utils_tests { - -SUITE(base64) +namespace tests { - -// Note: base64 works by encoding any 3 bytes as a four-byte string. Each triple is encoded independently of -// previous and subsequent triples. If, for a given set of input bytes, the number is not an even multiple of 3, -// the remaining 1 or two bytes are encoded and padded using '=' characters at the end. The encoding format is -// defined by IETF RFC 4648. Such padding is only allowed at the end of a encoded string, which makes it impossible -// to generally concatenate encoded strings and wind up with a string that is a valid base64 encoding. -// -// Since each triple of bytes is independent of others, we don't have to test particularly large sets if input data, -// validating that the algorithm can process at least two triples should be sufficient. -// -TEST(rfc_4648_tests_encode) +namespace functional { - // These tests are what base64 RFC 4648 proposes. - { - std::vector str1; - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("")), utility::conversions::to_base64(str1)); - } - { - std::vector str1; - str1.push_back('f'); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zg==")), utility::conversions::to_base64(str1)); - } - { - std::vector str1; - str1.push_back('f'); - str1.push_back('o'); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm8=")), utility::conversions::to_base64(str1)); - } - { - std::vector str1; - str1.push_back('f'); - str1.push_back('o'); - str1.push_back('o'); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm9v")), utility::conversions::to_base64(str1)); - } - { - std::vector str1; - str1.push_back('f'); - str1.push_back('o'); - str1.push_back('o'); - str1.push_back('b'); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm9vYg==")), utility::conversions::to_base64(str1)); - } - { - std::vector str1; - str1.push_back('f'); - str1.push_back('o'); - str1.push_back('o'); - str1.push_back('b'); - str1.push_back('a'); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm9vYmE=")), utility::conversions::to_base64(str1)); - } - { - std::vector str1; - str1.push_back('f'); - str1.push_back('o'); - str1.push_back('o'); - str1.push_back('b'); - str1.push_back('a'); - str1.push_back('r'); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm9vYmFy")), utility::conversions::to_base64(str1)); - } -} - -TEST(rfc_4648_tests_decode) +namespace utils_tests { - // These tests are what base64 RFC 4648 proposes. - { - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("")); - VERIFY_ARE_EQUAL(0u, str1.size()); - } - { - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zg==")); - VERIFY_ARE_EQUAL(1u, str1.size()); - VERIFY_ARE_EQUAL('f', str1[0]); - } - { - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm8=")); - VERIFY_ARE_EQUAL(2u, str1.size()); - VERIFY_ARE_EQUAL('f', str1[0]); - VERIFY_ARE_EQUAL('o', str1[1]); - } - { - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm9v")); - VERIFY_ARE_EQUAL(3u, str1.size()); - VERIFY_ARE_EQUAL('f', str1[0]); - VERIFY_ARE_EQUAL('o', str1[1]); - VERIFY_ARE_EQUAL('o', str1[2]); - } - { - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm9vYg==")); - VERIFY_ARE_EQUAL(4u, str1.size()); - VERIFY_ARE_EQUAL('f', str1[0]); - VERIFY_ARE_EQUAL('o', str1[1]); - VERIFY_ARE_EQUAL('o', str1[2]); - VERIFY_ARE_EQUAL('b', str1[3]); - } - { - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm9vYmE=")); - VERIFY_ARE_EQUAL(5u, str1.size()); - VERIFY_ARE_EQUAL('f', str1[0]); - VERIFY_ARE_EQUAL('o', str1[1]); - VERIFY_ARE_EQUAL('o', str1[2]); - VERIFY_ARE_EQUAL('b', str1[3]); - VERIFY_ARE_EQUAL('a', str1[4]); - } - { - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm9vYmFy")); - VERIFY_ARE_EQUAL(6u, str1.size()); - VERIFY_ARE_EQUAL('f', str1[0]); - VERIFY_ARE_EQUAL('o', str1[1]); - VERIFY_ARE_EQUAL('o', str1[2]); - VERIFY_ARE_EQUAL('b', str1[3]); - VERIFY_ARE_EQUAL('a', str1[4]); - VERIFY_ARE_EQUAL('r', str1[5]); - } -} - -TEST(additional_encode) +SUITE(base64) { + // Note: base64 works by encoding any 3 bytes as a four-byte string. Each triple is encoded independently of + // previous and subsequent triples. If, for a given set of input bytes, the number is not an even multiple of 3, + // the remaining 1 or two bytes are encoded and padded using '=' characters at the end. The encoding format is + // defined by IETF RFC 4648. Such padding is only allowed at the end of a encoded string, which makes it impossible + // to generally concatenate encoded strings and wind up with a string that is a valid base64 encoding. + // + // Since each triple of bytes is independent of others, we don't have to test particularly large sets if input data, + // validating that the algorithm can process at least two triples should be sufficient. + // + TEST(rfc_4648_tests_encode) { - // Check '/' encoding - std::vector str1; - str1.push_back(254); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("/g==")), utility::conversions::to_base64(str1)); - } - { - // Check '+' encoding - std::vector str1; - str1.push_back(250); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("+g==")), utility::conversions::to_base64(str1)); - } - { - std::vector str1; - str1.push_back('f'); - str1.push_back('o'); - str1.push_back(239); - str1.push_back('b'); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm/vYg==")), utility::conversions::to_base64(str1)); + // These tests are what base64 RFC 4648 proposes. + { + std::vector str1; + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("")), utility::conversions::to_base64(str1)); + } + { + std::vector str1; + str1.push_back('f'); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zg==")), utility::conversions::to_base64(str1)); + } + { + std::vector str1; + str1.push_back('f'); + str1.push_back('o'); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm8=")), utility::conversions::to_base64(str1)); + } + { + std::vector str1; + str1.push_back('f'); + str1.push_back('o'); + str1.push_back('o'); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm9v")), utility::conversions::to_base64(str1)); + } + { + std::vector str1; + str1.push_back('f'); + str1.push_back('o'); + str1.push_back('o'); + str1.push_back('b'); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm9vYg==")), utility::conversions::to_base64(str1)); + } + { + std::vector str1; + str1.push_back('f'); + str1.push_back('o'); + str1.push_back('o'); + str1.push_back('b'); + str1.push_back('a'); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm9vYmE=")), utility::conversions::to_base64(str1)); + } + { + std::vector str1; + str1.push_back('f'); + str1.push_back('o'); + str1.push_back('o'); + str1.push_back('b'); + str1.push_back('a'); + str1.push_back('r'); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm9vYmFy")), utility::conversions::to_base64(str1)); + } } - { - std::vector str1; - str1.push_back('g'); - str1.push_back(239); - str1.push_back('o'); - str1.push_back('b'); - VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Z+9vYg==")), utility::conversions::to_base64(str1)); - } -} -TEST(additional_decode) -{ - // Tests beyond what the RFC recommends. + TEST(rfc_4648_tests_decode) { - // Check '/' decoding - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("/g==")); - VERIFY_ARE_EQUAL(1u, str1.size()); - VERIFY_ARE_EQUAL(254u, str1[0]); - } - { - // Check '+' decoding - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("+g==")); - VERIFY_ARE_EQUAL(1u, str1.size()); - VERIFY_ARE_EQUAL(250u, str1[0]); + // These tests are what base64 RFC 4648 proposes. + { + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("")); + VERIFY_ARE_EQUAL(0u, str1.size()); + } + { + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zg==")); + VERIFY_ARE_EQUAL(1u, str1.size()); + VERIFY_ARE_EQUAL('f', str1[0]); + } + { + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm8=")); + VERIFY_ARE_EQUAL(2u, str1.size()); + VERIFY_ARE_EQUAL('f', str1[0]); + VERIFY_ARE_EQUAL('o', str1[1]); + } + { + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm9v")); + VERIFY_ARE_EQUAL(3u, str1.size()); + VERIFY_ARE_EQUAL('f', str1[0]); + VERIFY_ARE_EQUAL('o', str1[1]); + VERIFY_ARE_EQUAL('o', str1[2]); + } + { + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm9vYg==")); + VERIFY_ARE_EQUAL(4u, str1.size()); + VERIFY_ARE_EQUAL('f', str1[0]); + VERIFY_ARE_EQUAL('o', str1[1]); + VERIFY_ARE_EQUAL('o', str1[2]); + VERIFY_ARE_EQUAL('b', str1[3]); + } + { + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm9vYmE=")); + VERIFY_ARE_EQUAL(5u, str1.size()); + VERIFY_ARE_EQUAL('f', str1[0]); + VERIFY_ARE_EQUAL('o', str1[1]); + VERIFY_ARE_EQUAL('o', str1[2]); + VERIFY_ARE_EQUAL('b', str1[3]); + VERIFY_ARE_EQUAL('a', str1[4]); + } + { + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm9vYmFy")); + VERIFY_ARE_EQUAL(6u, str1.size()); + VERIFY_ARE_EQUAL('f', str1[0]); + VERIFY_ARE_EQUAL('o', str1[1]); + VERIFY_ARE_EQUAL('o', str1[2]); + VERIFY_ARE_EQUAL('b', str1[3]); + VERIFY_ARE_EQUAL('a', str1[4]); + VERIFY_ARE_EQUAL('r', str1[5]); + } } + + TEST(additional_encode) { - // Check '/' decoding - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm/vYg==")); - VERIFY_ARE_EQUAL(4u, str1.size()); - VERIFY_ARE_EQUAL('f', str1[0]); - VERIFY_ARE_EQUAL('o', str1[1]); - VERIFY_ARE_EQUAL(239, str1[2]); - VERIFY_ARE_EQUAL('b', str1[3]); + { + // Check '/' encoding + std::vector str1; + str1.push_back(254); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("/g==")), utility::conversions::to_base64(str1)); + } + { + // Check '+' encoding + std::vector str1; + str1.push_back(250); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("+g==")), utility::conversions::to_base64(str1)); + } + { + std::vector str1; + str1.push_back('f'); + str1.push_back('o'); + str1.push_back(239); + str1.push_back('b'); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Zm/vYg==")), utility::conversions::to_base64(str1)); + } + { + std::vector str1; + str1.push_back('g'); + str1.push_back(239); + str1.push_back('o'); + str1.push_back('b'); + VERIFY_ARE_EQUAL(string_t(_XPLATSTR("Z+9vYg==")), utility::conversions::to_base64(str1)); + } } + + TEST(additional_decode) { - // Check '+' decoding - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Z+9vYg==")); - VERIFY_ARE_EQUAL(4u, str1.size()); - VERIFY_ARE_EQUAL('g', str1[0]); - VERIFY_ARE_EQUAL(239, str1[1]); - VERIFY_ARE_EQUAL('o', str1[2]); - VERIFY_ARE_EQUAL('b', str1[3]); + // Tests beyond what the RFC recommends. + { + // Check '/' decoding + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("/g==")); + VERIFY_ARE_EQUAL(1u, str1.size()); + VERIFY_ARE_EQUAL(254u, str1[0]); + } + { + // Check '+' decoding + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("+g==")); + VERIFY_ARE_EQUAL(1u, str1.size()); + VERIFY_ARE_EQUAL(250u, str1[0]); + } + { + // Check '/' decoding + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Zm/vYg==")); + VERIFY_ARE_EQUAL(4u, str1.size()); + VERIFY_ARE_EQUAL('f', str1[0]); + VERIFY_ARE_EQUAL('o', str1[1]); + VERIFY_ARE_EQUAL(239, str1[2]); + VERIFY_ARE_EQUAL('b', str1[3]); + } + { + // Check '+' decoding + std::vector str1 = utility::conversions::from_base64(_XPLATSTR("Z+9vYg==")); + VERIFY_ARE_EQUAL(4u, str1.size()); + VERIFY_ARE_EQUAL('g', str1[0]); + VERIFY_ARE_EQUAL(239, str1[1]); + VERIFY_ARE_EQUAL('o', str1[2]); + VERIFY_ARE_EQUAL('b', str1[3]); + } + { + // Check the whole base64 alphabet + std::vector str1 = utility::conversions::from_base64( + _XPLATSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")); + VERIFY_ARE_EQUAL(48u, str1.size()); + } } + + TEST(bad_decode) { - // Check the whole base64 alphabet - std::vector str1 = utility::conversions::from_base64(_XPLATSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")); - VERIFY_ARE_EQUAL(48u, str1.size()); - } -} + // These tests are for input that should be disallowed by a very strict decoder, but + // the available APIs on Windows accept them, as does glib, which is used on Linux. -TEST(bad_decode) -{ - // These tests are for input that should be disallowed by a very strict decoder, but - // the available APIs on Windows accept them, as does glib, which is used on Linux. - - // Invalid character before padding, unused ones. - VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("/q==")), std::runtime_error); - VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("Zm9vYmD=")), std::runtime_error); - - // CRLF in the middle. - VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\nabcdefghijklmnopqrstuvwxyz\r\n0123456789+/")), std::runtime_error); - - // Not the right length. - VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("/q")), std::runtime_error); - // Characters not in the alphabet - VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("$%#@")), std::runtime_error); - // Too much padding at the end. - VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("/q=========")), std::runtime_error); - // Valid strings, concatenated - VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("Z+9vYg==Z+9vYg==")), std::runtime_error); -} - -TEST(large_string) -{ - const size_t size = 64*1024; + // Invalid character before padding, unused ones. + VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("/q==")), std::runtime_error); + VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("Zm9vYmD=")), std::runtime_error); - std::vector data(size); - for (auto i = 0u; i < size; ++i) - { - data[i] = (unsigned char)(rand() & 0xFF); + // CRLF in the middle. + VERIFY_THROWS(utility::conversions::from_base64( + _XPLATSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\nabcdefghijklmnopqrstuvwxyz\r\n0123456789+/")), + std::runtime_error); + + // Not the right length. + VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("/q")), std::runtime_error); + // Characters not in the alphabet + VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("$%#@")), std::runtime_error); + // Too much padding at the end. + VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("/q=========")), std::runtime_error); + // Valid strings, concatenated + VERIFY_THROWS(utility::conversions::from_base64(_XPLATSTR("Z+9vYg==Z+9vYg==")), std::runtime_error); } - auto string = utility::conversions::to_base64(data); - auto data2 = utility::conversions::from_base64(string); + TEST(large_string) + { + const size_t size = 64 * 1024; + + std::vector data(size); + for (auto i = 0u; i < size; ++i) + { + data[i] = (unsigned char)(rand() & 0xFF); + } + + auto string = utility::conversions::to_base64(data); + auto data2 = utility::conversions::from_base64(string); - VERIFY_ARE_EQUAL(data, data2); -} + VERIFY_ARE_EQUAL(data, data2); + } } // SUITE(base64) -}}} +} // namespace utils_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/utils/datetime.cpp b/Release/tests/functional/utils/datetime.cpp index 4c1885b811..a55d6326d4 100644 --- a/Release/tests/functional/utils/datetime.cpp +++ b/Release/tests/functional/utils/datetime.cpp @@ -1,175 +1,183 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests for datetime-related utility functions and classes. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests for datetime-related utility functions and classes. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace utility; -namespace tests { namespace functional { namespace utils_tests { - +namespace tests +{ +namespace functional +{ +namespace utils_tests +{ SUITE(datetime) { + // This is by no means a comprehensive test suite for the datetime functionality. + // It's a response to a particular bug and should be amended over time. -// This is by no means a comprehensive test suite for the datetime functionality. -// It's a response to a particular bug and should be amended over time. - -TEST(parsing_dateandtime_basic) -{ - // ISO 8601 - // RFC 1123 + TEST(parsing_dateandtime_basic) + { + // ISO 8601 + // RFC 1123 - auto dt1 = utility::datetime::from_string(_XPLATSTR("20130517T00:00:00Z"), utility::datetime::ISO_8601); - VERIFY_ARE_NOT_EQUAL(0u, dt1.to_interval()); + auto dt1 = utility::datetime::from_string(_XPLATSTR("20130517T00:00:00Z"), utility::datetime::ISO_8601); + VERIFY_ARE_NOT_EQUAL(0u, dt1.to_interval()); - auto dt2 = utility::datetime::from_string(_XPLATSTR("Fri, 17 May 2013 00:00:00 GMT"), utility::datetime::RFC_1123); - VERIFY_ARE_NOT_EQUAL(0u, dt2.to_interval()); + auto dt2 = + utility::datetime::from_string(_XPLATSTR("Fri, 17 May 2013 00:00:00 GMT"), utility::datetime::RFC_1123); + VERIFY_ARE_NOT_EQUAL(0u, dt2.to_interval()); - VERIFY_ARE_EQUAL(dt1.to_interval(), dt2.to_interval()); -} + VERIFY_ARE_EQUAL(dt1.to_interval(), dt2.to_interval()); + } -TEST(parsing_dateandtime_extended) -{ - // ISO 8601 - // RFC 1123 + TEST(parsing_dateandtime_extended) + { + // ISO 8601 + // RFC 1123 - auto dt1 = utility::datetime::from_string(_XPLATSTR("2013-05-17T00:00:00Z"), utility::datetime::ISO_8601); - VERIFY_ARE_NOT_EQUAL(0u, dt1.to_interval()); + auto dt1 = utility::datetime::from_string(_XPLATSTR("2013-05-17T00:00:00Z"), utility::datetime::ISO_8601); + VERIFY_ARE_NOT_EQUAL(0u, dt1.to_interval()); - auto dt2 = utility::datetime::from_string(_XPLATSTR("Fri, 17 May 2013 00:00:00 GMT"), utility::datetime::RFC_1123); - VERIFY_ARE_NOT_EQUAL(0u, dt2.to_interval()); + auto dt2 = + utility::datetime::from_string(_XPLATSTR("Fri, 17 May 2013 00:00:00 GMT"), utility::datetime::RFC_1123); + VERIFY_ARE_NOT_EQUAL(0u, dt2.to_interval()); - VERIFY_ARE_EQUAL(dt1.to_interval(), dt2.to_interval()); -} + VERIFY_ARE_EQUAL(dt1.to_interval(), dt2.to_interval()); + } -TEST(parsing_date_basic) -{ - // ISO 8601 + TEST(parsing_date_basic) { - auto dt = utility::datetime::from_string(_XPLATSTR("20130517"), utility::datetime::ISO_8601); + // ISO 8601 + { + auto dt = utility::datetime::from_string(_XPLATSTR("20130517"), utility::datetime::ISO_8601); - VERIFY_ARE_NOT_EQUAL(0u, dt.to_interval()); + VERIFY_ARE_NOT_EQUAL(0u, dt.to_interval()); + } } -} -TEST(parsing_date_extended) -{ - // ISO 8601 + TEST(parsing_date_extended) { - auto dt = utility::datetime::from_string(_XPLATSTR("2013-05-17"), utility::datetime::ISO_8601); + // ISO 8601 + { + auto dt = utility::datetime::from_string(_XPLATSTR("2013-05-17"), utility::datetime::ISO_8601); - VERIFY_ARE_NOT_EQUAL(0u, dt.to_interval()); + VERIFY_ARE_NOT_EQUAL(0u, dt.to_interval()); + } } -} -TEST(parsing_time_extended) -{ - // ISO 8601 + TEST(parsing_time_extended) { - auto dt = utility::datetime::from_string(_XPLATSTR("14:30:01Z"), utility::datetime::ISO_8601); + // ISO 8601 + { + auto dt = utility::datetime::from_string(_XPLATSTR("14:30:01Z"), utility::datetime::ISO_8601); - VERIFY_ARE_NOT_EQUAL(0u, dt.to_interval()); + VERIFY_ARE_NOT_EQUAL(0u, dt.to_interval()); + } } -} -void TestDateTimeRoundtrip(utility::string_t str, utility::string_t strExpected) -{ - auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601); - utility::string_t str2 = dt.to_string(utility::datetime::ISO_8601); - VERIFY_ARE_EQUAL(str2, strExpected); -} + void TestDateTimeRoundtrip(utility::string_t str, utility::string_t strExpected) + { + auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601); + utility::string_t str2 = dt.to_string(utility::datetime::ISO_8601); + VERIFY_ARE_EQUAL(str2, strExpected); + } -void TestDateTimeRoundtrip(utility::string_t str) -{ - TestDateTimeRoundtrip(str, str); -} + void TestDateTimeRoundtrip(utility::string_t str) { TestDateTimeRoundtrip(str, str); } -TEST(parsing_time_roundtrip_datetime1) -{ - // Preserve all 7 digits after the comma: - TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.1234567Z")); -} + TEST(parsing_time_roundtrip_datetime1) + { + // Preserve all 7 digits after the comma: + TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.1234567Z")); + } -TEST(parsing_time_roundtrip_datetime2) -{ - // lose the last '999' without rounding up - TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.1234567999Z"), _XPLATSTR("2013-11-19T14:30:59.1234567Z")); -} + TEST(parsing_time_roundtrip_datetime2) + { + // lose the last '999' without rounding up + TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.1234567999Z"), _XPLATSTR("2013-11-19T14:30:59.1234567Z")); + } -TEST(parsing_time_roundtrip_datetime3) -{ - // leading 0-s after the comma, tricky to parse correctly - TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.00123Z")); -} + TEST(parsing_time_roundtrip_datetime3) + { + // leading 0-s after the comma, tricky to parse correctly + TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.00123Z")); + } -TEST(parsing_time_roundtrip_datetime4) -{ - // another leading 0 test - TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.0000001Z")); -} + TEST(parsing_time_roundtrip_datetime4) + { + // another leading 0 test + TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.0000001Z")); + } -TEST(parsing_time_roundtrip_datetime5) -{ - // this is going to be truncated - TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.00000001Z"), _XPLATSTR("2013-11-19T14:30:59Z")); -} + TEST(parsing_time_roundtrip_datetime5) + { + // this is going to be truncated + TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.00000001Z"), _XPLATSTR("2013-11-19T14:30:59Z")); + } -TEST(parsing_time_roundtrip_datetime6) -{ - // Only one digit after the dot - TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.5Z")); -} + TEST(parsing_time_roundtrip_datetime6) + { + // Only one digit after the dot + TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.5Z")); + } -TEST(parsing_time_roundtrip_datetime_invalid1, "Ignore:Linux", "Codeplex issue #115", "Ignore:Apple", "Codeplex issue #115") -{ - // No digits after the dot, or non-digits. This is not a valid input, but we should not choke on it, - // Simply ignore the bad fraction - const utility::string_t bad_strings[] = { _XPLATSTR("2013-11-19T14:30:59.Z"), - _XPLATSTR("2013-11-19T14:30:59.1a2Z") - }; - utility::string_t str_corrected = _XPLATSTR("2013-11-19T14:30:59Z"); - - for (const auto& str : bad_strings) + TEST(parsing_time_roundtrip_datetime_invalid1, + "Ignore:Linux", + "Codeplex issue #115", + "Ignore:Apple", + "Codeplex issue #115") { - auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601); - utility::string_t str2 = dt.to_string(utility::datetime::ISO_8601); - VERIFY_ARE_EQUAL(str2, str_corrected); + // No digits after the dot, or non-digits. This is not a valid input, but we should not choke on it, + // Simply ignore the bad fraction + const utility::string_t bad_strings[] = {_XPLATSTR("2013-11-19T14:30:59.Z"), + _XPLATSTR("2013-11-19T14:30:59.1a2Z")}; + utility::string_t str_corrected = _XPLATSTR("2013-11-19T14:30:59Z"); + + for (const auto& str : bad_strings) + { + auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601); + utility::string_t str2 = dt.to_string(utility::datetime::ISO_8601); + VERIFY_ARE_EQUAL(str2, str_corrected); + } } -} -TEST(parsing_time_roundtrip_datetime_invalid2) -{ - // Variouls unsupported cases. In all cases, we have produce an empty date time - const utility::string_t bad_strings[] = { _XPLATSTR(""), // empty - _XPLATSTR(".Z"), // too short - _XPLATSTR(".Zx"), // no trailing Z - _XPLATSTR("3.14Z") // not a valid date - }; - - for (const auto& str : bad_strings) + TEST(parsing_time_roundtrip_datetime_invalid2) { - auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601); - VERIFY_ARE_EQUAL(dt.to_interval(), 0); + // Variouls unsupported cases. In all cases, we have produce an empty date time + const utility::string_t bad_strings[] = { + _XPLATSTR(""), // empty + _XPLATSTR(".Z"), // too short + _XPLATSTR(".Zx"), // no trailing Z + _XPLATSTR("3.14Z") // not a valid date + }; + + for (const auto& str : bad_strings) + { + auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601); + VERIFY_ARE_EQUAL(dt.to_interval(), 0); + } } -} -TEST(parsing_time_roundtrip_time) -{ - // time only without date - utility::string_t str = _XPLATSTR("14:30:59.1234567Z"); - auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601); - utility::string_t str2 = dt.to_string(utility::datetime::ISO_8601); - // Must look for a substring now, since the date part is filled with today's date - VERIFY_IS_TRUE(str2.find(str) != std::string::npos); -} + TEST(parsing_time_roundtrip_time) + { + // time only without date + utility::string_t str = _XPLATSTR("14:30:59.1234567Z"); + auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601); + utility::string_t str2 = dt.to_string(utility::datetime::ISO_8601); + // Must look for a substring now, since the date part is filled with today's date + VERIFY_IS_TRUE(str2.find(str) != std::string::npos); + } } // SUITE(datetime) -}}} +} // namespace utils_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/utils/macro_test.cpp b/Release/tests/functional/utils/macro_test.cpp index 08794d4d24..f45bc9f237 100644 --- a/Release/tests/functional/utils/macro_test.cpp +++ b/Release/tests/functional/utils/macro_test.cpp @@ -1,34 +1,38 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* macro_test.cpp -* -* Tests cases for macro name conflicts. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * macro_test.cpp + * + * Tests cases for macro name conflicts. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" + #include "cpprest/http_client.h" #include "cpprest/http_msg.h" #include "cpprest/json.h" #include "cpprest/uri_builder.h" -namespace tests { namespace functional { namespace utils_tests { - - template - void macro_U_Test() - { - (void)U(); - } +namespace tests +{ +namespace functional +{ +namespace utils_tests +{ +template +void macro_U_Test() +{ + (void)U(); +} - SUITE(macro_test) - { - TEST(U_test) - { - macro_U_Test(); - } - } -}}} +SUITE(macro_test) +{ + TEST(U_test) { macro_U_Test(); } +} +} // namespace utils_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/utils/nonce_generator_tests.cpp b/Release/tests/functional/utils/nonce_generator_tests.cpp index 625808ea81..92c4ea0f6c 100644 --- a/Release/tests/functional/utils/nonce_generator_tests.cpp +++ b/Release/tests/functional/utils/nonce_generator_tests.cpp @@ -1,55 +1,60 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* nonce_generator_tests.cpp -* -* Tests for nonce_generator class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * nonce_generator_tests.cpp + * + * Tests for nonce_generator class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace utility; -namespace tests { namespace functional { namespace utils_tests { - -SUITE(nonce_generator_tests) +namespace tests { - -TEST(nonce_generator_set_length) +namespace functional { - utility::nonce_generator gen; - VERIFY_ARE_EQUAL(utility::nonce_generator::default_length, gen.generate().length()); - - gen.set_length(1); - VERIFY_ARE_EQUAL(1, gen.generate().length()); +namespace utils_tests +{ +SUITE(nonce_generator_tests) +{ + TEST(nonce_generator_set_length) + { + utility::nonce_generator gen; + VERIFY_ARE_EQUAL(utility::nonce_generator::default_length, gen.generate().length()); - gen.set_length(0); - VERIFY_ARE_EQUAL(0, gen.generate().length()); + gen.set_length(1); + VERIFY_ARE_EQUAL(1, gen.generate().length()); - gen.set_length(500); - VERIFY_ARE_EQUAL(500, gen.generate().length()); -} + gen.set_length(0); + VERIFY_ARE_EQUAL(0, gen.generate().length()); -TEST(nonce_generator_unique_strings) -{ - // Generate 100 nonces and check each is unique. - std::vector nonces(100); - utility::nonce_generator gen; - for (auto&& v : nonces) - { - v = gen.generate(); + gen.set_length(500); + VERIFY_ARE_EQUAL(500, gen.generate().length()); } - for (auto v : nonces) + + TEST(nonce_generator_unique_strings) { - VERIFY_ARE_EQUAL(1, std::count(nonces.begin(), nonces.end(), v)); + // Generate 100 nonces and check each is unique. + std::vector nonces(100); + utility::nonce_generator gen; + for (auto&& v : nonces) + { + v = gen.generate(); + } + for (auto v : nonces) + { + VERIFY_ARE_EQUAL(1, std::count(nonces.begin(), nonces.end(), v)); + } } -} } // SUITE(nonce_generator_tests) -}}} +} // namespace utils_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/utils/stdafx.cpp b/Release/tests/functional/utils/stdafx.cpp index b27e91b093..c9db6a62de 100644 --- a/Release/tests/functional/utils/stdafx.cpp +++ b/Release/tests/functional/utils/stdafx.cpp @@ -1,11 +1,11 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ -// stdafx.cpp : +// stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" diff --git a/Release/tests/functional/utils/stdafx.h b/Release/tests/functional/utils/stdafx.h index 8188bec2e5..40eb75f5a0 100644 --- a/Release/tests/functional/utils/stdafx.h +++ b/Release/tests/functional/utils/stdafx.h @@ -1,22 +1,21 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * stdafx.h + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #define _TURN_OFF_PLATFORM_STRING -#include "cpprest/uri.h" #include "cpprest/asyncrt_utils.h" #include "cpprest/details/web_utilities.h" - +#include "cpprest/uri.h" #include "unittestpp.h" #include "utils_tests.h" diff --git a/Release/tests/functional/utils/strings.cpp b/Release/tests/functional/utils/strings.cpp index 8f6957f61a..1879e1966c 100644 --- a/Release/tests/functional/utils/strings.cpp +++ b/Release/tests/functional/utils/strings.cpp @@ -1,14 +1,14 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* - * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * base64.cpp * * Tests for base64-related utility functions and classes. * - * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" @@ -21,294 +21,296 @@ using namespace utility; -namespace tests { namespace functional { namespace utils_tests { - -SUITE(strings) +namespace tests { - -TEST(usascii_to_utf16) +namespace functional +{ +namespace utils_tests { - std::string str_ascii("This is a test"); - utf16string str_utf16 = utility::conversions::usascii_to_utf16(str_ascii); - - for (size_t i = 0; i < str_ascii.size(); ++i) +SUITE(strings) +{ + TEST(usascii_to_utf16) { - VERIFY_ARE_EQUAL((utf16char)str_ascii[i], str_utf16[i]); + std::string str_ascii("This is a test"); + utf16string str_utf16 = utility::conversions::usascii_to_utf16(str_ascii); + + for (size_t i = 0; i < str_ascii.size(); ++i) + { + VERIFY_ARE_EQUAL((utf16char)str_ascii[i], str_utf16[i]); + } } -} #ifdef _WIN32 -#define UTF16(x) L ## x +#define UTF16(x) L##x #else -#define UTF16(x) u ## x +#define UTF16(x) u##x #endif -TEST(utf16_to_utf8) -{ + TEST(utf16_to_utf8) + { #if !defined(__GLIBCXX__) - std::wstring_convert, utf16char> conversion; + std::wstring_convert, utf16char> conversion; #endif - // encodes to single byte character - VERIFY_ARE_EQUAL("ABC987", utility::conversions::utf16_to_utf8(UTF16("ABC987"))); - utf16string input; - input.push_back(0x7F); // last ASCII character - auto result = utility::conversions::utf16_to_utf8(input); - VERIFY_ARE_EQUAL(0x7F, result[0]); - - // encodes to 2 byte character - input.clear(); - input.push_back(0x80); - input.push_back(0x14D); - input.push_back(0x7FF); - result = utility::conversions::utf16_to_utf8(input); + // encodes to single byte character + VERIFY_ARE_EQUAL("ABC987", utility::conversions::utf16_to_utf8(UTF16("ABC987"))); + utf16string input; + input.push_back(0x7F); // last ASCII character + auto result = utility::conversions::utf16_to_utf8(input); + VERIFY_ARE_EQUAL(0x7F, result[0]); + + // encodes to 2 byte character + input.clear(); + input.push_back(0x80); + input.push_back(0x14D); + input.push_back(0x7FF); + result = utility::conversions::utf16_to_utf8(input); #if defined(__GLIBCXX__) - VERIFY_ARE_EQUAL(194u, static_cast(result[0])); - VERIFY_ARE_EQUAL(128u, static_cast(result[1])); - VERIFY_ARE_EQUAL(197u, static_cast(result[2])); - VERIFY_ARE_EQUAL(141u, static_cast(result[3])); - VERIFY_ARE_EQUAL(223u, static_cast(result[4])); - VERIFY_ARE_EQUAL(191u, static_cast(result[5])); + VERIFY_ARE_EQUAL(194u, static_cast(result[0])); + VERIFY_ARE_EQUAL(128u, static_cast(result[1])); + VERIFY_ARE_EQUAL(197u, static_cast(result[2])); + VERIFY_ARE_EQUAL(141u, static_cast(result[3])); + VERIFY_ARE_EQUAL(223u, static_cast(result[4])); + VERIFY_ARE_EQUAL(191u, static_cast(result[5])); #else - VERIFY_ARE_EQUAL(conversion.to_bytes(input), result); + VERIFY_ARE_EQUAL(conversion.to_bytes(input), result); #endif - // encodes to 3 byte character - input.clear(); - input.push_back(0x800); - input.push_back(0x14AB); - input.push_back(0xFFFF); - result = utility::conversions::utf16_to_utf8(input); + // encodes to 3 byte character + input.clear(); + input.push_back(0x800); + input.push_back(0x14AB); + input.push_back(0xFFFF); + result = utility::conversions::utf16_to_utf8(input); #if defined(__GLIBCXX__) - VERIFY_ARE_EQUAL(224u, static_cast(result[0])); - VERIFY_ARE_EQUAL(160u, static_cast(result[1])); - VERIFY_ARE_EQUAL(128u, static_cast(result[2])); - VERIFY_ARE_EQUAL(225u, static_cast(result[3])); - VERIFY_ARE_EQUAL(146u, static_cast(result[4])); - VERIFY_ARE_EQUAL(171u, static_cast(result[5])); - VERIFY_ARE_EQUAL(239u, static_cast(result[6])); - VERIFY_ARE_EQUAL(191u, static_cast(result[7])); - VERIFY_ARE_EQUAL(191u, static_cast(result[8])); + VERIFY_ARE_EQUAL(224u, static_cast(result[0])); + VERIFY_ARE_EQUAL(160u, static_cast(result[1])); + VERIFY_ARE_EQUAL(128u, static_cast(result[2])); + VERIFY_ARE_EQUAL(225u, static_cast(result[3])); + VERIFY_ARE_EQUAL(146u, static_cast(result[4])); + VERIFY_ARE_EQUAL(171u, static_cast(result[5])); + VERIFY_ARE_EQUAL(239u, static_cast(result[6])); + VERIFY_ARE_EQUAL(191u, static_cast(result[7])); + VERIFY_ARE_EQUAL(191u, static_cast(result[8])); #else - VERIFY_ARE_EQUAL(conversion.to_bytes(input), result); + VERIFY_ARE_EQUAL(conversion.to_bytes(input), result); #endif - // surrogate pair - encodes to 4 byte character - input.clear(); - // U+10000 - input.push_back(0xD800); - input.push_back(0xDC00); - // U+12345 - input.push_back(0xD802); - input.push_back(0xDD29); - // U+10FFFF - input.push_back(0xDA3F); - input.push_back(0xDFFF); - result = utility::conversions::utf16_to_utf8(input); + // surrogate pair - encodes to 4 byte character + input.clear(); + // U+10000 + input.push_back(0xD800); + input.push_back(0xDC00); + // U+12345 + input.push_back(0xD802); + input.push_back(0xDD29); + // U+10FFFF + input.push_back(0xDA3F); + input.push_back(0xDFFF); + result = utility::conversions::utf16_to_utf8(input); #if defined(__GLIBCXX__) - VERIFY_ARE_EQUAL(240u, static_cast(result[0])); - VERIFY_ARE_EQUAL(144u, static_cast(result[1])); - VERIFY_ARE_EQUAL(128u, static_cast(result[2])); - VERIFY_ARE_EQUAL(128u, static_cast(result[3])); - VERIFY_ARE_EQUAL(240u, static_cast(result[4])); - VERIFY_ARE_EQUAL(144u, static_cast(result[5])); - VERIFY_ARE_EQUAL(164u, static_cast(result[6])); - VERIFY_ARE_EQUAL(169u, static_cast(result[7])); - VERIFY_ARE_EQUAL(242u, static_cast(result[8])); - VERIFY_ARE_EQUAL(159u, static_cast(result[9])); - VERIFY_ARE_EQUAL(191u, static_cast(result[10])); - VERIFY_ARE_EQUAL(191u, static_cast(result[11])); + VERIFY_ARE_EQUAL(240u, static_cast(result[0])); + VERIFY_ARE_EQUAL(144u, static_cast(result[1])); + VERIFY_ARE_EQUAL(128u, static_cast(result[2])); + VERIFY_ARE_EQUAL(128u, static_cast(result[3])); + VERIFY_ARE_EQUAL(240u, static_cast(result[4])); + VERIFY_ARE_EQUAL(144u, static_cast(result[5])); + VERIFY_ARE_EQUAL(164u, static_cast(result[6])); + VERIFY_ARE_EQUAL(169u, static_cast(result[7])); + VERIFY_ARE_EQUAL(242u, static_cast(result[8])); + VERIFY_ARE_EQUAL(159u, static_cast(result[9])); + VERIFY_ARE_EQUAL(191u, static_cast(result[10])); + VERIFY_ARE_EQUAL(191u, static_cast(result[11])); #else - VERIFY_ARE_EQUAL(conversion.to_bytes(input), result); + VERIFY_ARE_EQUAL(conversion.to_bytes(input), result); #endif - // surrogate pair - covering regression bug where 0x10000 was accidentally bitwise OR'ed instead of added. - input.clear(); - input.push_back(0xD840); - input.push_back(0xDC00); - result = utility::conversions::utf16_to_utf8(input); + // surrogate pair - covering regression bug where 0x10000 was accidentally bitwise OR'ed instead of added. + input.clear(); + input.push_back(0xD840); + input.push_back(0xDC00); + result = utility::conversions::utf16_to_utf8(input); #if defined(__GLIBCXX__) - VERIFY_ARE_EQUAL(240u, static_cast(result[0])); - VERIFY_ARE_EQUAL(160u, static_cast(result[1])); - VERIFY_ARE_EQUAL(128u, static_cast(result[2])); - VERIFY_ARE_EQUAL(128u, static_cast(result[3])); + VERIFY_ARE_EQUAL(240u, static_cast(result[0])); + VERIFY_ARE_EQUAL(160u, static_cast(result[1])); + VERIFY_ARE_EQUAL(128u, static_cast(result[2])); + VERIFY_ARE_EQUAL(128u, static_cast(result[3])); #else - VERIFY_ARE_EQUAL(conversion.to_bytes(input), result); + VERIFY_ARE_EQUAL(conversion.to_bytes(input), result); #endif -} + } -TEST(utf8_to_utf16) -{ + TEST(utf8_to_utf16) + { #if !defined(__GLIBCXX__) - std::wstring_convert, utf16char> conversion; + std::wstring_convert, utf16char> conversion; #endif - // single byte character - VERIFY_ARE_EQUAL(UTF16("ABC123"), utility::conversions::utf8_to_utf16("ABC123")); - std::string input; - input.push_back(0x7F); // last ASCII character - auto result = utility::conversions::utf8_to_utf16(input); - VERIFY_ARE_EQUAL(0x7F, result[0]); - - // 2 byte character - input.clear(); - // U+80 - input.push_back(208u); // 11010000 - input.push_back(128u); // 10000000 - // U+7FF - input.push_back(223u); // 11011111 - input.push_back(191u); // 10111111 - result = utility::conversions::utf8_to_utf16(input); + // single byte character + VERIFY_ARE_EQUAL(UTF16("ABC123"), utility::conversions::utf8_to_utf16("ABC123")); + std::string input; + input.push_back(0x7F); // last ASCII character + auto result = utility::conversions::utf8_to_utf16(input); + VERIFY_ARE_EQUAL(0x7F, result[0]); + + // 2 byte character + input.clear(); + // U+80 + input.push_back(208u); // 11010000 + input.push_back(128u); // 10000000 + // U+7FF + input.push_back(223u); // 11011111 + input.push_back(191u); // 10111111 + result = utility::conversions::utf8_to_utf16(input); #if defined(__GLIBCXX__) - VERIFY_ARE_EQUAL(1024, result[0]); - VERIFY_ARE_EQUAL(2047, result[1]); + VERIFY_ARE_EQUAL(1024, result[0]); + VERIFY_ARE_EQUAL(2047, result[1]); #else - VERIFY_ARE_EQUAL(conversion.from_bytes(input), result); + VERIFY_ARE_EQUAL(conversion.from_bytes(input), result); #endif - // 3 byte character - input.clear(); - // U+800 - input.push_back(232u); // 11101000 - input.push_back(128u); // 10000000 - input.push_back(128u); // 10000000 - // U+FFFF - input.push_back(239u); // 11101111 - input.push_back(191u); // 10111111 - input.push_back(191u); // 10111111 - result = utility::conversions::utf8_to_utf16(input); + // 3 byte character + input.clear(); + // U+800 + input.push_back(232u); // 11101000 + input.push_back(128u); // 10000000 + input.push_back(128u); // 10000000 + // U+FFFF + input.push_back(239u); // 11101111 + input.push_back(191u); // 10111111 + input.push_back(191u); // 10111111 + result = utility::conversions::utf8_to_utf16(input); #if defined(__GLIBCXX__) - VERIFY_ARE_EQUAL(32768, result[0]); - VERIFY_ARE_EQUAL(65535, result[1]); + VERIFY_ARE_EQUAL(32768, result[0]); + VERIFY_ARE_EQUAL(65535, result[1]); #else - VERIFY_ARE_EQUAL(conversion.from_bytes(input), result); + VERIFY_ARE_EQUAL(conversion.from_bytes(input), result); #endif - // 4 byte character - input.clear(); - // U+10000 - input.push_back(244u); // 11110100 - input.push_back(128u); // 10000000 - input.push_back(128u); // 10000000 - input.push_back(128u); // 10000000 - // U+10FFFF - input.push_back(244u); // 11110100 - input.push_back(143u); // 10001111 - input.push_back(191u); // 10111111 - input.push_back(191u); // 10111111 - result = utility::conversions::utf8_to_utf16(input); + // 4 byte character + input.clear(); + // U+10000 + input.push_back(244u); // 11110100 + input.push_back(128u); // 10000000 + input.push_back(128u); // 10000000 + input.push_back(128u); // 10000000 + // U+10FFFF + input.push_back(244u); // 11110100 + input.push_back(143u); // 10001111 + input.push_back(191u); // 10111111 + input.push_back(191u); // 10111111 + result = utility::conversions::utf8_to_utf16(input); #if defined(__GLIBCXX__) - VERIFY_ARE_EQUAL(56256, result[0]); - VERIFY_ARE_EQUAL(56320, result[1]); - VERIFY_ARE_EQUAL(56319, result[2]); - VERIFY_ARE_EQUAL(57343, result[3]); + VERIFY_ARE_EQUAL(56256, result[0]); + VERIFY_ARE_EQUAL(56320, result[1]); + VERIFY_ARE_EQUAL(56319, result[2]); + VERIFY_ARE_EQUAL(57343, result[3]); #else - VERIFY_ARE_EQUAL(conversion.from_bytes(input), result); + VERIFY_ARE_EQUAL(conversion.from_bytes(input), result); #endif - - // 1 byte character followed by 4 byte character - input.clear(); - input.push_back( 51u); // 00110011 - // U+10000 - input.push_back(244u); // 11110100 - input.push_back(128u); // 10000000 - input.push_back(128u); // 10000000 - input.push_back(128u); // 10000000 - // U+10FFFF - input.push_back(244u); // 11110100 - input.push_back(143u); // 10001111 - input.push_back(191u); // 10111111 - input.push_back(191u); // 10111111 - result = utility::conversions::utf8_to_utf16(input); + // 1 byte character followed by 4 byte character + input.clear(); + input.push_back(51u); // 00110011 + // U+10000 + input.push_back(244u); // 11110100 + input.push_back(128u); // 10000000 + input.push_back(128u); // 10000000 + input.push_back(128u); // 10000000 + // U+10FFFF + input.push_back(244u); // 11110100 + input.push_back(143u); // 10001111 + input.push_back(191u); // 10111111 + input.push_back(191u); // 10111111 + result = utility::conversions::utf8_to_utf16(input); #if defined(__GLIBCXX__) - VERIFY_ARE_EQUAL(51, result[0]); - VERIFY_ARE_EQUAL(56256, result[1]); - VERIFY_ARE_EQUAL(56320, result[2]); - VERIFY_ARE_EQUAL(56319, result[3]); - VERIFY_ARE_EQUAL(57343, result[4]); + VERIFY_ARE_EQUAL(51, result[0]); + VERIFY_ARE_EQUAL(56256, result[1]); + VERIFY_ARE_EQUAL(56320, result[2]); + VERIFY_ARE_EQUAL(56319, result[3]); + VERIFY_ARE_EQUAL(57343, result[4]); #else - VERIFY_ARE_EQUAL(conversion.from_bytes(input), result); + VERIFY_ARE_EQUAL(conversion.from_bytes(input), result); #endif -} - -TEST(utf16_to_utf8_errors) -{ - VERIFY_ARE_EQUAL("ABC987", utility::conversions::utf16_to_utf8(UTF16("ABC987"))); - utf16string input; - - // high surrogate with missing low surrogate. - input.push_back(0xD800); - input.push_back(0x0); - VERIFY_THROWS(utility::conversions::utf16_to_utf8(input), std::range_error); - - // high surrogate with no more characters - input.clear(); - input.push_back(0xD800); - VERIFY_THROWS(utility::conversions::utf16_to_utf8(input), std::range_error); -} - -TEST(utf8_to_utf16_errors) -{ - // missing second continuation byte - std::string input; - input.push_back(207u); // 11001111 - VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); - - // missing third continuation byte - input.clear(); - input.push_back(230u); // 11100110 - input.push_back(141u); // 10001101 - VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); - - // missing fourth continuation byte - input.clear(); - input.push_back(240u); // 11110000 - input.push_back(173u); // 10101101 - input.push_back(157u); // 10011101 - VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); - - // continuation byte missing leading 10xxxxxx - input.clear(); - input.push_back(230u); // 11100110 - input.push_back(141u); // 00001101 - VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); - input.clear(); - input.push_back(230u); // 11100110 - input.push_back(141u); // 11001101 - VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); - - // invalid for a first character to start with 1xxxxxxx - input.clear(); - input.push_back(128u); // 10000000 - input.push_back(128u); // 10000000 - VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); - input.clear(); - input.push_back(191u); // 10111111 - input.push_back(128u); // 10000000 - VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); -} + } -TEST(latin1_to_utf16) -{ - char in[256] = { 0 }; - char16_t expectedResult[256] = { 0 }; - for (size_t i = 0; i < 256; ++i) + TEST(utf16_to_utf8_errors) { - in[i] = static_cast(i); - expectedResult[i] = static_cast(i); + VERIFY_ARE_EQUAL("ABC987", utility::conversions::utf16_to_utf8(UTF16("ABC987"))); + utf16string input; + + // high surrogate with missing low surrogate. + input.push_back(0xD800); + input.push_back(0x0); + VERIFY_THROWS(utility::conversions::utf16_to_utf8(input), std::range_error); + + // high surrogate with no more characters + input.clear(); + input.push_back(0xD800); + VERIFY_THROWS(utility::conversions::utf16_to_utf8(input), std::range_error); } - std::string str_latin1(in, 256); - - auto actualResult = utility::conversions::latin1_to_utf16(str_latin1); + TEST(utf8_to_utf16_errors) + { + // missing second continuation byte + std::string input; + input.push_back(207u); // 11001111 + VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); + + // missing third continuation byte + input.clear(); + input.push_back(230u); // 11100110 + input.push_back(141u); // 10001101 + VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); + + // missing fourth continuation byte + input.clear(); + input.push_back(240u); // 11110000 + input.push_back(173u); // 10101101 + input.push_back(157u); // 10011101 + VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); + + // continuation byte missing leading 10xxxxxx + input.clear(); + input.push_back(230u); // 11100110 + input.push_back(141u); // 00001101 + VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); + input.clear(); + input.push_back(230u); // 11100110 + input.push_back(141u); // 11001101 + VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); + + // invalid for a first character to start with 1xxxxxxx + input.clear(); + input.push_back(128u); // 10000000 + input.push_back(128u); // 10000000 + VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); + input.clear(); + input.push_back(191u); // 10111111 + input.push_back(128u); // 10000000 + VERIFY_THROWS(utility::conversions::utf8_to_utf16(input), std::range_error); + } - VERIFY_ARE_EQUAL(str_latin1.size(), actualResult.size()); - for (size_t i = 0; i < actualResult.size(); ++i) + TEST(latin1_to_utf16) { - VERIFY_ARE_EQUAL(expectedResult[i], actualResult[i]); + char in[256] = {0}; + char16_t expectedResult[256] = {0}; + for (size_t i = 0; i < 256; ++i) + { + in[i] = static_cast(i); + expectedResult[i] = static_cast(i); + } + + std::string str_latin1(in, 256); + + auto actualResult = utility::conversions::latin1_to_utf16(str_latin1); + + VERIFY_ARE_EQUAL(str_latin1.size(), actualResult.size()); + for (size_t i = 0; i < actualResult.size(); ++i) + { + VERIFY_ARE_EQUAL(expectedResult[i], actualResult[i]); + } } -} #if defined(_MSC_VER) #pragma warning(disable : 4996) @@ -318,72 +320,82 @@ TEST(latin1_to_utf16) #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif -TEST(print_string_locale, "Ignore:Android", "Locale unsupported on Android") -{ - std::locale changedLocale; - try + TEST(print_string_locale, "Ignore:Android", "Locale unsupported on Android") { + std::locale changedLocale; + try + { #ifdef _WIN32 - changedLocale = std::locale("fr-FR"); + changedLocale = std::locale("fr-FR"); #else - changedLocale = std::locale("fr_FR.UTF-8"); + changedLocale = std::locale("fr_FR.UTF-8"); #endif - } - catch (const std::exception &) - { - // Silently pass if locale isn't installed on machine. - return; - } + } + catch (const std::exception&) + { + // Silently pass if locale isn't installed on machine. + return; + } - tests::common::utilities::locale_guard loc(changedLocale); + tests::common::utilities::locale_guard loc(changedLocale); - utility::ostringstream_t oss; - oss << 1000; - VERIFY_ARE_EQUAL(oss.str(), utility::conversions::print_string(1000)); - VERIFY_ARE_EQUAL(_XPLATSTR("1000"), utility::conversions::print_string(1000, std::locale::classic())); -} + utility::ostringstream_t oss; + oss << 1000; + VERIFY_ARE_EQUAL(oss.str(), utility::conversions::print_string(1000)); + VERIFY_ARE_EQUAL(_XPLATSTR("1000"), utility::conversions::print_string(1000, std::locale::classic())); + } -TEST(scan_string_locale, "Ignore:Android", "Locale unsupported on Android") -{ - std::locale changedLocale; - try + TEST(scan_string_locale, "Ignore:Android", "Locale unsupported on Android") { + std::locale changedLocale; + try + { #ifdef _WIN32 - changedLocale = std::locale("fr-FR"); + changedLocale = std::locale("fr-FR"); #else - changedLocale = std::locale("fr_FR.UTF-8"); + changedLocale = std::locale("fr_FR.UTF-8"); #endif - } - catch (const std::exception &) - { - // Silently pass if locale isn't installed on machine. - return; + } + catch (const std::exception&) + { + // Silently pass if locale isn't installed on machine. + return; + } + + VERIFY_ARE_EQUAL(_XPLATSTR("1000"), + utility::conversions::scan_string(utility::string_t(_XPLATSTR("1000")))); + VERIFY_ARE_EQUAL(_XPLATSTR("1,000"), + utility::conversions::scan_string(utility::string_t(_XPLATSTR("1,000")))); + + VERIFY_ARE_EQUAL( + _XPLATSTR("1000"), + utility::conversions::scan_string(utility::string_t(_XPLATSTR("1000")), changedLocale)); + VERIFY_ARE_EQUAL( + _XPLATSTR("1,000"), + utility::conversions::scan_string(utility::string_t(_XPLATSTR("1,000")), changedLocale)); + + { + tests::common::utilities::locale_guard loc(changedLocale); + VERIFY_ARE_EQUAL(_XPLATSTR("1000"), + utility::conversions::scan_string(utility::string_t(_XPLATSTR("1000")), + std::locale::classic())); + VERIFY_ARE_EQUAL(_XPLATSTR("1,000"), + utility::conversions::scan_string(utility::string_t(_XPLATSTR("1,000")), + std::locale::classic())); + } } - VERIFY_ARE_EQUAL(_XPLATSTR("1000"), utility::conversions::scan_string(utility::string_t(_XPLATSTR("1000")))); - VERIFY_ARE_EQUAL(_XPLATSTR("1,000"), utility::conversions::scan_string(utility::string_t(_XPLATSTR("1,000")))); - - VERIFY_ARE_EQUAL(_XPLATSTR("1000"), utility::conversions::scan_string(utility::string_t(_XPLATSTR("1000")), changedLocale)); - VERIFY_ARE_EQUAL(_XPLATSTR("1,000"), utility::conversions::scan_string(utility::string_t(_XPLATSTR("1,000")), changedLocale)); - +#ifdef _WIN32 + TEST(windows_category_message) { - tests::common::utilities::locale_guard loc(changedLocale); - VERIFY_ARE_EQUAL(_XPLATSTR("1000"), utility::conversions::scan_string(utility::string_t(_XPLATSTR("1000")), std::locale::classic())); - VERIFY_ARE_EQUAL(_XPLATSTR("1,000"), utility::conversions::scan_string(utility::string_t(_XPLATSTR("1,000")), std::locale::classic())); + // Ensure the error message string returned by windows_category doesn't contain trailing zeros. + std::string error_message = utility::details::windows_category().message(0); + std::string zero_terminated_copy = error_message.c_str(); + VERIFY_ARE_EQUAL(zero_terminated_copy, error_message); } -} - - -#ifdef _WIN32 -TEST(windows_category_message) -{ - // Ensure the error message string returned by windows_category doesn't contain trailing zeros. - std::string error_message = utility::details::windows_category().message( 0 ); - std::string zero_terminated_copy = error_message.c_str(); - VERIFY_ARE_EQUAL( zero_terminated_copy, error_message ); -} #endif // _WIN32 - } - -}}} //namespaces + +} // namespace utils_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/utils/utils_tests.h b/Release/tests/functional/utils/utils_tests.h index 99dbca7e3c..827664f102 100644 --- a/Release/tests/functional/utils/utils_tests.h +++ b/Release/tests/functional/utils/utils_tests.h @@ -1,18 +1,24 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* utils_tests.h -* -* Common utilities and helper functions for utility tests -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * utils_tests.h + * + * Common utilities and helper functions for utility tests + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "unittestpp.h" -namespace tests { namespace functional { namespace utils_tests { - -}}} \ No newline at end of file +namespace tests +{ +namespace functional +{ +namespace utils_tests +{ +} +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/utils/win32_encryption_tests.cpp b/Release/tests/functional/utils/win32_encryption_tests.cpp index 2ec4b21a68..32e6ab2ecb 100644 --- a/Release/tests/functional/utils/win32_encryption_tests.cpp +++ b/Release/tests/functional/utils/win32_encryption_tests.cpp @@ -1,44 +1,49 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* win32_encryption_tests.cpp -* -* Tests for win32_encryption class. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * win32_encryption_tests.cpp + * + * Tests for win32_encryption class. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" using namespace utility; -namespace tests { namespace functional { namespace utils_tests { - +namespace tests +{ +namespace functional +{ +namespace utils_tests +{ #if defined(_WIN32) && !defined(CPPREST_TARGET_XP) && !defined(__cplusplus_winrt) SUITE(win32_encryption) { + TEST(win32_encryption_random_string) + { + utility::string_t rndStr = utility::conversions::to_string_t("random string"); + web::details::win32_encryption enc(rndStr); -TEST(win32_encryption_random_string) -{ - utility::string_t rndStr = utility::conversions::to_string_t("random string"); - web::details::win32_encryption enc(rndStr); - - VERIFY_ARE_EQUAL(*enc.decrypt(), rndStr); -} + VERIFY_ARE_EQUAL(*enc.decrypt(), rndStr); + } -TEST(win32_encryption_empty_string) -{ - utility::string_t emptyStr = utility::conversions::to_string_t(""); - web::details::win32_encryption enc(emptyStr); + TEST(win32_encryption_empty_string) + { + utility::string_t emptyStr = utility::conversions::to_string_t(""); + web::details::win32_encryption enc(emptyStr); - VERIFY_ARE_EQUAL(*enc.decrypt(), emptyStr); -} + VERIFY_ARE_EQUAL(*enc.decrypt(), emptyStr); + } } // SUITE(win32_encryption) #endif -}}} +} // namespace utils_tests +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/websockets/client/authentication_tests.cpp b/Release/tests/functional/websockets/client/authentication_tests.cpp index 00a498cb67..2953686042 100644 --- a/Release/tests/functional/websockets/client/authentication_tests.cpp +++ b/Release/tests/functional/websockets/client/authentication_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* authentication_tests.cpp -* -* Tests cases for covering authentication using websocket_client -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * authentication_tests.cpp + * + * Tests cases for covering authentication using websocket_client + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,226 +20,224 @@ using namespace web::websockets::client; using namespace tests::functional::websocket::utilities; -namespace tests { namespace functional { namespace websocket { namespace client { - +namespace tests +{ +namespace functional +{ +namespace websocket +{ +namespace client +{ SUITE(authentication_tests) { - // Authorization not implemented in non WinRT websocket_client yet - CodePlex 254 #if defined(__cplusplus_winrt) -void auth_helper(test_websocket_server& server, const utility::string_t &username = U(""), const utility::string_t &password = U("")) -{ - server.set_http_handler([username, password](test_http_request request) + void auth_helper(test_websocket_server & server, + const utility::string_t& username = U(""), + const utility::string_t& password = U("")) { - test_http_response resp; - if (request->username().empty()) // No credentials -> challenge the request - { - resp.set_status_code(401); // Unauthorized. - resp.set_realm("My Realm"); - } - else if (request->username().compare(utility::conversions::to_utf8string(username)) - || request->password().compare(utility::conversions::to_utf8string(password))) - { - resp.set_status_code(403); // User name/password did not match: Forbidden - auth failure. - } - else - { - resp.set_status_code(200); // User name and passwords match. Successful auth. - } - return resp; - }); -} + server.set_http_handler([username, password](test_http_request request) { + test_http_response resp; + if (request->username().empty()) // No credentials -> challenge the request + { + resp.set_status_code(401); // Unauthorized. + resp.set_realm("My Realm"); + } + else if (request->username().compare(utility::conversions::to_utf8string(username)) || + request->password().compare(utility::conversions::to_utf8string(password))) + { + resp.set_status_code(403); // User name/password did not match: Forbidden - auth failure. + } + else + { + resp.set_status_code(200); // User name and passwords match. Successful auth. + } + return resp; + }); + } -// connect without credentials, when the server expects credentials -TEST_FIXTURE(uri_address, auth_no_credentials, "Ignore", "245") -{ - test_websocket_server server; - websocket_client client; - auth_helper(server); - VERIFY_THROWS(client.connect(m_uri).wait(), websocket_exception); -} - -// Connect with credentials -TEST_FIXTURE(uri_address, auth_with_credentials, "Ignore", "245") -{ - test_websocket_server server; - websocket_client_config config; - web::credentials cred(U("user"), U("password")); - config.set_credentials(cred); - websocket_client client(config); - - auth_helper(server, cred.username(), U("password")); - client.connect(m_uri).wait(); - client.close().wait(); -} + // connect without credentials, when the server expects credentials + TEST_FIXTURE(uri_address, auth_no_credentials, "Ignore", "245") + { + test_websocket_server server; + websocket_client client; + auth_helper(server); + VERIFY_THROWS(client.connect(m_uri).wait(), websocket_exception); + } + + // Connect with credentials + TEST_FIXTURE(uri_address, auth_with_credentials, "Ignore", "245") + { + test_websocket_server server; + websocket_client_config config; + web::credentials cred(U("user"), U("password")); + config.set_credentials(cred); + websocket_client client(config); + + auth_helper(server, cred.username(), U("password")); + client.connect(m_uri).wait(); + client.close().wait(); + } #endif -// helper function to check if failure is due to timeout. -bool is_timeout(const std::string &msg) -{ - if (msg.find("set_fail_handler") != std::string::npos) + // helper function to check if failure is due to timeout. + bool is_timeout(const std::string& msg) { - if (msg.find("handshake timed out") != std::string::npos || msg.find("Timer Expired") != std::string::npos) + if (msg.find("set_fail_handler") != std::string::npos) { - return true; + if (msg.find("handshake timed out") != std::string::npos || msg.find("Timer Expired") != std::string::npos) + { + return true; + } } + return false; } - return false; -} -TEST(ssl_test) -{ - websocket_client client; - std::string body_str("hello"); - - try + TEST(ssl_test) { - client.connect(U("wss://echo.websocket.org/")).wait(); - auto receive_task = client.receive().then([body_str](websocket_incoming_message ret_msg) + websocket_client client; + std::string body_str("hello"); + + try { - VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length()); - auto ret_str = ret_msg.extract_string().get(); + client.connect(U("wss://echo.websocket.org/")).wait(); + auto receive_task = client.receive().then([body_str](websocket_incoming_message ret_msg) { + VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length()); + auto ret_str = ret_msg.extract_string().get(); - VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); - }); + VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); + }); - websocket_outgoing_message msg; - msg.set_utf8_message(body_str); - client.send(msg).wait(); + websocket_outgoing_message msg; + msg.set_utf8_message(body_str); + client.send(msg).wait(); - receive_task.wait(); - client.close().wait(); - } - catch (const websocket_exception &e) - { - if (is_timeout(e.what())) + receive_task.wait(); + client.close().wait(); + } + catch (const websocket_exception& e) { - // Since this test depends on an outside server sometimes it sporadically can fail due to timeouts - // especially on our build machines. - return; + if (is_timeout(e.what())) + { + // Since this test depends on an outside server sometimes it sporadically can fail due to timeouts + // especially on our build machines. + return; + } + throw; } - throw; } -} // These tests are specific to our websocketpp based implementation. #if !defined(__cplusplus_winrt) -void sni_test_impl(websocket_client &client) -{ - try - { - client.connect(U("wss://swordsoftruth.com")).wait(); - - // Should never be reached. - VERIFY_IS_TRUE(false); - } - catch (const websocket_exception &e) + void sni_test_impl(websocket_client & client) { - if (is_timeout(e.what())) + try { - // Since this test depends on an outside server sometimes it sporadically can fail due to timeouts - // especially on our build machines. - return; - } + client.connect(U("wss://swordsoftruth.com")).wait(); - // This test just covers establishing the TLS connection and verifying - // the server certificate, expect it to return an unexpected HTTP status code. - if (e.error_code().value() == 20) + // Should never be reached. + VERIFY_IS_TRUE(false); + } + catch (const websocket_exception& e) { - return; + if (is_timeout(e.what())) + { + // Since this test depends on an outside server sometimes it sporadically can fail due to timeouts + // especially on our build machines. + return; + } + + // This test just covers establishing the TLS connection and verifying + // the server certificate, expect it to return an unexpected HTTP status code. + if (e.error_code().value() == 20) + { + return; + } + throw; } - throw; } -} -// Test specifically for server SignalR team hit interesting cases with. -TEST(sni_with_older_server_test) -{ - websocket_client client; - sni_test_impl(client); -} - -// WinRT doesn't expose option for disabling. -// No stable server is available to reliably test this. -// The configuration below relies on a timeout in the success case. -TEST(disable_sni, "Ignore", "Manual") -{ - websocket_client_config config; - config.set_server_name("expired.badssl.com"); - config.disable_sni(); - websocket_client client(config); - - try + // Test specifically for server SignalR team hit interesting cases with. + TEST(sni_with_older_server_test) { - client.connect(U("wss://badssl.com")).wait(); - - // Should never be reached. - VERIFY_IS_TRUE(false); + websocket_client client; + sni_test_impl(client); } - catch (const websocket_exception &e) + + // WinRT doesn't expose option for disabling. + // No stable server is available to reliably test this. + // The configuration below relies on a timeout in the success case. + TEST(disable_sni, "Ignore", "Manual") { - // Should fail for a reason different than invalid HTTP status. - if (e.error_code().value() != 20) + websocket_client_config config; + config.set_server_name("expired.badssl.com"); + config.disable_sni(); + websocket_client client(config); + + try { - return; + client.connect(U("wss://badssl.com")).wait(); + + // Should never be reached. + VERIFY_IS_TRUE(false); + } + catch (const websocket_exception& e) + { + // Should fail for a reason different than invalid HTTP status. + if (e.error_code().value() != 20) + { + return; + } + throw; } - throw; } -} -// Winrt doesn't allow explicitly setting server host for SNI. -TEST(sni_explicit_hostname) -{ - websocket_client_config config; - const auto &name = utf8string("swordsoftruth.com"); - config.set_server_name(name); - VERIFY_ARE_EQUAL(name, config.server_name()); - websocket_client client(config); - sni_test_impl(client); -} - -void handshake_error_test_impl(const ::utility::string_t &host) -{ - websocket_client client; - try + // Winrt doesn't allow explicitly setting server host for SNI. + TEST(sni_explicit_hostname) { - client.connect(host).wait(); - VERIFY_IS_TRUE(false); + websocket_client_config config; + const auto& name = utf8string("swordsoftruth.com"); + config.set_server_name(name); + VERIFY_ARE_EQUAL(name, config.server_name()); + websocket_client client(config); + sni_test_impl(client); } - catch (const websocket_exception &e) + + void handshake_error_test_impl(const ::utility::string_t& host) { - if (is_timeout(e.what())) + websocket_client client; + try + { + client.connect(host).wait(); + VERIFY_IS_TRUE(false); + } + catch (const websocket_exception& e) { - // Since this test depends on an outside server sometimes it sporadically can fail due to timeouts - // especially on our build machines. - return; + if (is_timeout(e.what())) + { + // Since this test depends on an outside server sometimes it sporadically can fail due to timeouts + // especially on our build machines. + return; + } + VERIFY_ARE_EQUAL("TLS handshake failed", e.error_code().message()); } - VERIFY_ARE_EQUAL("TLS handshake failed", e.error_code().message()); } -} -TEST(self_signed_cert) -{ - handshake_error_test_impl(U("wss://self-signed.badssl.com/")); -} + TEST(self_signed_cert) { handshake_error_test_impl(U("wss://self-signed.badssl.com/")); } -TEST(hostname_mismatch) -{ - handshake_error_test_impl(U("wss://wrong.host.badssl.com/")); -} + TEST(hostname_mismatch) { handshake_error_test_impl(U("wss://wrong.host.badssl.com/")); } -TEST(cert_expired) -{ - handshake_error_test_impl(U("wss://expired.badssl.com/")); -} + TEST(cert_expired) { handshake_error_test_impl(U("wss://expired.badssl.com/")); } #endif } // SUITE(authentication_tests) -}}}} +} // namespace client +} // namespace websocket +} // namespace functional +} // namespace tests #endif - diff --git a/Release/tests/functional/websockets/client/client_construction.cpp b/Release/tests/functional/websockets/client/client_construction.cpp index 766fa9685f..cffe647b05 100644 --- a/Release/tests/functional/websockets/client/client_construction.cpp +++ b/Release/tests/functional/websockets/client/client_construction.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* client_construction.cpp -* -* Tests cases for covering creating websocket_clients. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * client_construction.cpp + * + * Tests cases for covering creating websocket_clients. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -23,221 +23,233 @@ using namespace web::websockets::client; using namespace tests::functional::websocket::utilities; -namespace tests { namespace functional { namespace websocket { namespace client { - -SUITE(client_construction) +namespace tests { - -// Helper function verifies that when constructing a websocket_client with invalid -// URI std::invalid_argument is thrown. -static void verify_client_invalid_argument(const uri &address) +namespace functional { - try - { - websocket_client client; - client.connect(address).wait(); - VERIFY_IS_TRUE(false); - } catch(std::invalid_argument &) - { - // expected - } -} - -TEST_FIXTURE(uri_address, client_construction_error_cases) +namespace websocket { - uri address(U("notws://localhost:34567/")); - - // Invalid scheme. - verify_client_invalid_argument(address); - - // empty host. - address = uri(U("ws://:34567/")); - verify_client_invalid_argument(address); -} - -// Verify that we can read the config from the websocket_client -TEST_FIXTURE(uri_address, get_client_config) +namespace client { - websocket_client_config config; - - web::credentials cred(U("username"), U("password")); - config.set_credentials(cred); - websocket_client client(config); +SUITE(client_construction) +{ + // Helper function verifies that when constructing a websocket_client with invalid + // URI std::invalid_argument is thrown. + static void verify_client_invalid_argument(const uri& address) + { + try + { + websocket_client client; + client.connect(address).wait(); + VERIFY_IS_TRUE(false); + } + catch (std::invalid_argument&) + { + // expected + } + } - const websocket_client_config& config2 = client.config(); - VERIFY_ARE_EQUAL(config2.credentials().username(), cred.username()); -} + TEST_FIXTURE(uri_address, client_construction_error_cases) + { + uri address(U("notws://localhost:34567/")); -// Verify that we can read the config from the websocket_callback_client -TEST_FIXTURE(uri_address, get_client_config_callback_client) -{ - websocket_client_config config; + // Invalid scheme. + verify_client_invalid_argument(address); - web::credentials cred(U("username"), U("password")); - config.set_credentials(cred); - websocket_callback_client client(config); + // empty host. + address = uri(U("ws://:34567/")); + verify_client_invalid_argument(address); + } - const websocket_client_config& config2 = client.config(); - VERIFY_ARE_EQUAL(config2.credentials().username(), cred.username()); -} + // Verify that we can read the config from the websocket_client + TEST_FIXTURE(uri_address, get_client_config) + { + websocket_client_config config; + web::credentials cred(U("username"), U("password")); + config.set_credentials(cred); + websocket_client client(config); -// Verify that we can get the baseuri from websocket_client connect. -TEST_FIXTURE(uri_address, uri_test) -{ - websocket_client client1; - VERIFY_ARE_EQUAL(client1.uri(), U("/")); + const websocket_client_config& config2 = client.config(); + VERIFY_ARE_EQUAL(config2.credentials().username(), cred.username()); + } - test_websocket_server server; - client1.connect(m_uri).wait(); - VERIFY_ARE_EQUAL(client1.uri(), m_uri); - client1.close().wait(); + // Verify that we can read the config from the websocket_callback_client + TEST_FIXTURE(uri_address, get_client_config_callback_client) + { + websocket_client_config config; - websocket_client_config config; - websocket_client client2(config); - VERIFY_ARE_EQUAL(client2.uri(), U("/")); + web::credentials cred(U("username"), U("password")); + config.set_credentials(cred); + websocket_callback_client client(config); - client2.connect(m_uri).wait(); - VERIFY_ARE_EQUAL(client2.uri(), m_uri); - client2.close().wait(); -} + const websocket_client_config& config2 = client.config(); + VERIFY_ARE_EQUAL(config2.credentials().username(), cred.username()); + } -TEST_FIXTURE(uri_address, move_operations) -{ - std::string body("hello"); - std::vector body_vec(body.begin(), body.end()); + // Verify that we can get the baseuri from websocket_client connect. + TEST_FIXTURE(uri_address, uri_test) + { + websocket_client client1; + VERIFY_ARE_EQUAL(client1.uri(), U("/")); - test_websocket_server server; - websocket_client client; + test_websocket_server server; + client1.connect(m_uri).wait(); + VERIFY_ARE_EQUAL(client1.uri(), m_uri); + client1.close().wait(); - client.connect(m_uri).wait(); + websocket_client_config config; + websocket_client client2(config); + VERIFY_ARE_EQUAL(client2.uri(), U("/")); - // Move constructor - websocket_client client2 = std::move(client); + client2.connect(m_uri).wait(); + VERIFY_ARE_EQUAL(client2.uri(), m_uri); + client2.close().wait(); + } - server.next_message([&](test_websocket_msg msg) // Handler to verify the message sent by the client. + TEST_FIXTURE(uri_address, move_operations) { - websocket_asserts::assert_message_equals(msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - }); + std::string body("hello"); + std::vector body_vec(body.begin(), body.end()); - websocket_outgoing_message msg; - msg.set_utf8_message(body); - client2.send(std::move(msg)).wait(); + test_websocket_server server; + websocket_client client; - auto t = client2.receive().then([&](websocket_incoming_message ret_msg) - { - VERIFY_ARE_EQUAL(ret_msg.length(), body.length()); - auto ret_str = ret_msg.extract_string().get(); - - VERIFY_ARE_EQUAL(body.compare(ret_str), 0); - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); - }); - - test_websocket_msg rmsg; - rmsg.set_data(body_vec); - rmsg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - server.send_msg(rmsg); - t.wait(); - - // Move assignment - client = std::move(client2); - server.next_message([&](test_websocket_msg msg) // Handler to verify the message sent by the client. - { - websocket_asserts::assert_message_equals(msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - }); - - websocket_outgoing_message msg1; - msg1.set_utf8_message(body); - client.send(std::move(msg1)).wait(); - - test_websocket_msg rmsg1; - rmsg1.set_data(body_vec); - rmsg1.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - server.send_msg(rmsg1); - auto t1 = client.receive().then([&](websocket_incoming_message ret_msg) - { - VERIFY_ARE_EQUAL(ret_msg.length(), body.length()); - auto ret_str = ret_msg.extract_string().get(); + client.connect(m_uri).wait(); + + // Move constructor + websocket_client client2 = std::move(client); + + server.next_message([&](test_websocket_msg msg) // Handler to verify the message sent by the client. + { + websocket_asserts::assert_message_equals( + msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + }); + + websocket_outgoing_message msg; + msg.set_utf8_message(body); + client2.send(std::move(msg)).wait(); + + auto t = client2.receive().then([&](websocket_incoming_message ret_msg) { + VERIFY_ARE_EQUAL(ret_msg.length(), body.length()); + auto ret_str = ret_msg.extract_string().get(); + + VERIFY_ARE_EQUAL(body.compare(ret_str), 0); + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); + }); + + test_websocket_msg rmsg; + rmsg.set_data(body_vec); + rmsg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + server.send_msg(rmsg); + t.wait(); + + // Move assignment + client = std::move(client2); + server.next_message([&](test_websocket_msg msg) // Handler to verify the message sent by the client. + { + websocket_asserts::assert_message_equals( + msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + }); + + websocket_outgoing_message msg1; + msg1.set_utf8_message(body); + client.send(std::move(msg1)).wait(); + + test_websocket_msg rmsg1; + rmsg1.set_data(body_vec); + rmsg1.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + server.send_msg(rmsg1); + auto t1 = client.receive().then([&](websocket_incoming_message ret_msg) { + VERIFY_ARE_EQUAL(ret_msg.length(), body.length()); + auto ret_str = ret_msg.extract_string().get(); + + VERIFY_ARE_EQUAL(body.compare(ret_str), 0); + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); + }); + t1.wait(); + client.close().wait(); + } - VERIFY_ARE_EQUAL(body.compare(ret_str), 0); - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); - }); - t1.wait(); - client.close().wait(); -} + void header_test_impl(const uri& address, + const utility::string_t& headerName, + const utility::string_t& headerValue, + const utility::string_t& expectedHeaderValue = U("")) + { + test_websocket_server server; + websocket_client_config config; + utility::string_t expectedValue = headerValue; + if (!expectedHeaderValue.empty()) + { + expectedValue = expectedHeaderValue; + } + config.headers().add(headerName, headerValue); + websocket_client client(config); + + server.set_http_handler([&](test_http_request request) { + test_http_response resp; + if (request->get_header_val(utility::conversions::to_utf8string(headerName)) + .compare(utility::conversions::to_utf8string(expectedValue)) == 0) + resp.set_status_code(200); // Handshake request will be completed only if header match succeeds. + else + resp.set_status_code(400); // Else fail the handshake, websocket client connect will fail in this case. + return resp; + }); + client.connect(address).wait(); + client.close().wait(); + } -void header_test_impl(const uri &address, const utility::string_t &headerName, const utility::string_t &headerValue, const utility::string_t &expectedHeaderValue = U("")) -{ - test_websocket_server server; - websocket_client_config config; - utility::string_t expectedValue = headerValue; - if (!expectedHeaderValue.empty()) + TEST_FIXTURE(uri_address, connect_with_headers) { - expectedValue = expectedHeaderValue; + header_test_impl(m_uri, U("HeaderTest"), U("ConnectSuccessfully")); } - config.headers().add(headerName, headerValue); - websocket_client client(config); - server.set_http_handler([&](test_http_request request) + TEST_FIXTURE(uri_address, manually_set_protocol_header) { - test_http_response resp; - if (request->get_header_val(utility::conversions::to_utf8string(headerName)).compare(utility::conversions::to_utf8string(expectedValue)) == 0) - resp.set_status_code(200); // Handshake request will be completed only if header match succeeds. - else - resp.set_status_code(400); // Else fail the handshake, websocket client connect will fail in this case. - return resp; - }); - client.connect(address).wait(); - client.close().wait(); -} - -TEST_FIXTURE(uri_address, connect_with_headers) -{ - header_test_impl(m_uri, U("HeaderTest"), U("ConnectSuccessfully")); -} + utility::string_t headerName(U("Sec-WebSocket-Protocol")); + header_test_impl(m_uri, headerName, U("myprotocol")); + header_test_impl(m_uri, headerName, U("myprotocol2,"), U("myprotocol2")); + header_test_impl(m_uri, headerName, U("myprotocol2,protocol3"), U("myprotocol2, protocol3")); + header_test_impl( + m_uri, headerName, U("myprotocol2, protocol3, protocol6,,"), U("myprotocol2, protocol3, protocol6")); + } -TEST_FIXTURE(uri_address, manually_set_protocol_header) -{ - utility::string_t headerName(U("Sec-WebSocket-Protocol")); - header_test_impl(m_uri, headerName, U("myprotocol")); - header_test_impl(m_uri, headerName, U("myprotocol2,"), U("myprotocol2")); - header_test_impl(m_uri, headerName, U("myprotocol2,protocol3"), U("myprotocol2, protocol3")); - header_test_impl(m_uri, headerName, U("myprotocol2, protocol3, protocol6,,"), U("myprotocol2, protocol3, protocol6")); -} - -TEST_FIXTURE(uri_address, set_subprotocol) -{ - test_websocket_server server; - websocket_client_config config; - - utility::string_t expected1(U("pro1")); - config.add_subprotocol(expected1); - VERIFY_ARE_EQUAL(1, config.subprotocols().size()); - VERIFY_ARE_EQUAL(expected1, config.subprotocols()[0]); - - utility::string_t expected2(U("second")); - config.add_subprotocol(expected2); - VERIFY_ARE_EQUAL(2, config.subprotocols().size()); - VERIFY_ARE_EQUAL(expected1, config.subprotocols()[0]); - VERIFY_ARE_EQUAL(expected2, config.subprotocols()[1]); - - websocket_client client(config); - server.set_http_handler([&](test_http_request request) + TEST_FIXTURE(uri_address, set_subprotocol) { - test_http_response resp; - if (request->get_header_val(utility::conversions::to_utf8string(U("Sec-WebSocket-Protocol"))).compare(utility::conversions::to_utf8string(expected1 + U(", ") + expected2)) == 0) - resp.set_status_code(200); // Handshake request will be completed only if header match succeeds. - else - resp.set_status_code(400); // Else fail the handshake, websocket client connect will fail in this case. - return resp; - }); - - client.connect(m_uri).wait(); - client.close().wait(); -} + test_websocket_server server; + websocket_client_config config; + + utility::string_t expected1(U("pro1")); + config.add_subprotocol(expected1); + VERIFY_ARE_EQUAL(1, config.subprotocols().size()); + VERIFY_ARE_EQUAL(expected1, config.subprotocols()[0]); + + utility::string_t expected2(U("second")); + config.add_subprotocol(expected2); + VERIFY_ARE_EQUAL(2, config.subprotocols().size()); + VERIFY_ARE_EQUAL(expected1, config.subprotocols()[0]); + VERIFY_ARE_EQUAL(expected2, config.subprotocols()[1]); + + websocket_client client(config); + server.set_http_handler([&](test_http_request request) { + test_http_response resp; + if (request->get_header_val(utility::conversions::to_utf8string(U("Sec-WebSocket-Protocol"))) + .compare(utility::conversions::to_utf8string(expected1 + U(", ") + expected2)) == 0) + resp.set_status_code(200); // Handshake request will be completed only if header match succeeds. + else + resp.set_status_code(400); // Else fail the handshake, websocket client connect will fail in this case. + return resp; + }); + + client.connect(m_uri).wait(); + client.close().wait(); + } } // SUITE(client_construction) -}}}} +} // namespace client +} // namespace websocket +} // namespace functional +} // namespace tests #endif diff --git a/Release/tests/functional/websockets/client/close_tests.cpp b/Release/tests/functional/websockets/client/close_tests.cpp index 5912408cf1..58a6e7c9a6 100644 --- a/Release/tests/functional/websockets/client/close_tests.cpp +++ b/Release/tests/functional/websockets/client/close_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* close_tests.cpp -* -* Tests cases for closing websocket_client objects. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * close_tests.cpp + * + * Tests cases for closing websocket_client objects. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -22,135 +22,146 @@ using namespace web::websockets::client; using namespace tests::functional::websocket::utilities; -namespace tests { namespace functional { namespace websocket { namespace client { - -SUITE(close_tests) +namespace tests { - -// Test close websocket connection: client sends an empty close and server responds with close frame -TEST_FIXTURE(uri_address, close_client_websocket) +namespace functional +{ +namespace websocket +{ +namespace client { - test_websocket_server server; - - websocket_client client; +SUITE(close_tests) +{ + // Test close websocket connection: client sends an empty close and server responds with close frame + TEST_FIXTURE(uri_address, close_client_websocket) + { + test_websocket_server server; - client.connect(m_uri).wait(); + websocket_client client; - client.close().wait(); -} + client.connect(m_uri).wait(); -// Test close websocket connection: client sends a close with reason and server responds with close frame -TEST_FIXTURE(uri_address, close_with_reason) -{ - test_websocket_server server; - - websocket_client client; + client.close().wait(); + } - client.connect(m_uri).wait(); + // Test close websocket connection: client sends a close with reason and server responds with close frame + TEST_FIXTURE(uri_address, close_with_reason) + { + test_websocket_server server; - client.close(websocket_close_status::going_away, U("Client disconnecting")).wait(); -} + websocket_client client; -// Server sends a close frame (server initiated close) -TEST_FIXTURE(uri_address, close_from_server) -{ - std::string body("hello"); - test_websocket_server server; + client.connect(m_uri).wait(); - websocket_client client; + client.close(websocket_close_status::going_away, U("Client disconnecting")).wait(); + } - client.connect(m_uri).wait(); + // Server sends a close frame (server initiated close) + TEST_FIXTURE(uri_address, close_from_server) + { + std::string body("hello"); + test_websocket_server server; - // Send close frame from server - test_websocket_msg msg; - msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE); - server.send_msg(msg); + websocket_client client; - client.close().wait(); -} + client.connect(m_uri).wait(); -// Test close websocket connection with callback client: client sends an empty close and server responds with close frame -TEST_FIXTURE(uri_address, close_callback_client_websocket, "Ignore", "319") -{ - test_websocket_server server; - const utility::string_t close_reason = U("Too large"); + // Send close frame from server + test_websocket_msg msg; + msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE); + server.send_msg(msg); - // verify it is ok not to set close handler - websocket_callback_client client; + client.close().wait(); + } - client.connect(m_uri).wait(); + // Test close websocket connection with callback client: client sends an empty close and server responds with close + // frame + TEST_FIXTURE(uri_address, close_callback_client_websocket, "Ignore", "319") + { + test_websocket_server server; + const utility::string_t close_reason = U("Too large"); - client.close().wait(); + // verify it is ok not to set close handler + websocket_callback_client client; - websocket_callback_client client1; + client.connect(m_uri).wait(); - client1.set_close_handler([&close_reason](websocket_close_status status, const utility::string_t& reason, const std::error_code& code) - { - VERIFY_ARE_EQUAL(status, websocket_close_status::too_large); - VERIFY_ARE_EQUAL(reason, close_reason); - VERIFY_ARE_EQUAL(code.value(), 0); - }); + client.close().wait(); - client1.connect(m_uri).wait(); + websocket_callback_client client1; - client1.close(websocket_close_status::too_large, close_reason).wait(); -} + client1.set_close_handler([&close_reason](websocket_close_status status, + const utility::string_t& reason, + const std::error_code& code) { + VERIFY_ARE_EQUAL(status, websocket_close_status::too_large); + VERIFY_ARE_EQUAL(reason, close_reason); + VERIFY_ARE_EQUAL(code.value(), 0); + }); -// Test close websocket connection: client sends a close with reason and server responds with close frame -TEST_FIXTURE(uri_address, close_callback_client_with_reason, "Ignore", "319") -{ - const utility::string_t close_reason = U("Client disconnecting"); - test_websocket_server server; + client1.connect(m_uri).wait(); - websocket_callback_client client; + client1.close(websocket_close_status::too_large, close_reason).wait(); + } - client.set_close_handler([close_reason](websocket_close_status status, const utility::string_t& reason, const std::error_code& code) + // Test close websocket connection: client sends a close with reason and server responds with close frame + TEST_FIXTURE(uri_address, close_callback_client_with_reason, "Ignore", "319") { - VERIFY_ARE_EQUAL(status, websocket_close_status::normal); - VERIFY_ARE_EQUAL(reason, close_reason); - VERIFY_ARE_EQUAL(code.value(), 0); - }); + const utility::string_t close_reason = U("Client disconnecting"); + test_websocket_server server; - client.connect(m_uri).wait(); + websocket_callback_client client; - client.close(websocket_close_status::normal, close_reason).wait(); -} + client.set_close_handler([close_reason](websocket_close_status status, + const utility::string_t& reason, + const std::error_code& code) { + VERIFY_ARE_EQUAL(status, websocket_close_status::normal); + VERIFY_ARE_EQUAL(reason, close_reason); + VERIFY_ARE_EQUAL(code.value(), 0); + }); -// Server sends a close frame (server initiated close) -TEST_FIXTURE(uri_address, close_callback_client_from_server, "Ignore", "319") -{ - std::string body("hello"); - test_websocket_server server; + client.connect(m_uri).wait(); - websocket_callback_client client; + client.close(websocket_close_status::normal, close_reason).wait(); + } - int hitCount = 0; - pplx::task_completion_event closeEvent; - client.set_close_handler([&hitCount, closeEvent](websocket_close_status status, const utility::string_t& reason, const std::error_code& code) + // Server sends a close frame (server initiated close) + TEST_FIXTURE(uri_address, close_callback_client_from_server, "Ignore", "319") { - VERIFY_ARE_EQUAL(status, websocket_close_status::going_away); - VERIFY_ARE_EQUAL(reason, U("")); - VERIFY_ARE_EQUAL(code.value(), 0); + std::string body("hello"); + test_websocket_server server; + + websocket_callback_client client; - hitCount++; - closeEvent.set(); - }); + int hitCount = 0; + pplx::task_completion_event closeEvent; + client.set_close_handler([&hitCount, closeEvent](websocket_close_status status, + const utility::string_t& reason, + const std::error_code& code) { + VERIFY_ARE_EQUAL(status, websocket_close_status::going_away); + VERIFY_ARE_EQUAL(reason, U("")); + VERIFY_ARE_EQUAL(code.value(), 0); - client.connect(m_uri).wait(); + hitCount++; + closeEvent.set(); + }); - // Send close frame from server - test_websocket_msg msg; - msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE); - server.send_msg(msg); + client.connect(m_uri).wait(); - // make sure it only called once. - pplx::create_task(closeEvent).wait(); - VERIFY_ARE_EQUAL(hitCount, 1); -} + // Send close frame from server + test_websocket_msg msg; + msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE); + server.send_msg(msg); + + // make sure it only called once. + pplx::create_task(closeEvent).wait(); + VERIFY_ARE_EQUAL(hitCount, 1); + } } // SUITE(close_tests) -}}}} +} // namespace client +} // namespace websocket +} // namespace functional +} // namespace tests #endif - diff --git a/Release/tests/functional/websockets/client/error_tests.cpp b/Release/tests/functional/websockets/client/error_tests.cpp index 0e292d9386..7e24ec50bb 100644 --- a/Release/tests/functional/websockets/client/error_tests.cpp +++ b/Release/tests/functional/websockets/client/error_tests.cpp @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Tests cases error connection cases with websocket_client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Tests cases error connection cases with websocket_client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,145 +20,153 @@ using namespace web::websockets::client; using namespace tests::functional::websocket::utilities; -namespace tests { namespace functional { namespace websocket { namespace client { - -SUITE(error_tests) +namespace tests { - -// Send before connecting -TEST_FIXTURE(uri_address, send_before_connect) +namespace functional +{ +namespace websocket { - websocket_client client; +namespace client +{ +SUITE(error_tests) +{ + // Send before connecting + TEST_FIXTURE(uri_address, send_before_connect) + { + websocket_client client; - websocket_outgoing_message msg; - msg.set_utf8_message("xyz"); + websocket_outgoing_message msg; + msg.set_utf8_message("xyz"); - VERIFY_THROWS(client.send(msg).wait(), websocket_exception); -} + VERIFY_THROWS(client.send(msg).wait(), websocket_exception); + } -// Server does not exist -TEST_FIXTURE(uri_address, server_doesnt_exist) -{ - websocket_client client; - VERIFY_THROWS(client.connect(m_uri).get(), websocket_exception); -} + // Server does not exist + TEST_FIXTURE(uri_address, server_doesnt_exist) + { + websocket_client client; + VERIFY_THROWS(client.connect(m_uri).get(), websocket_exception); + } // Send after close // CodePlex 319 fails on VS2013. #if !defined(_MSC_VER) || _MSC_VER >= 1900 -TEST_FIXTURE(uri_address, send_after_close) -{ - std::string body("hello"); - test_websocket_server server; - - server.next_message([&](test_websocket_msg msg) + TEST_FIXTURE(uri_address, send_after_close) { - websocket_asserts::assert_message_equals(msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - }); - websocket_client client; - - client.connect(m_uri).wait(); - client.close().wait(); - - websocket_outgoing_message msg; - msg.set_utf8_message(body); - VERIFY_THROWS(client.send(msg).wait(), websocket_exception); -} + std::string body("hello"); + test_websocket_server server; + + server.next_message([&](test_websocket_msg msg) { + websocket_asserts::assert_message_equals( + msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + }); + websocket_client client; + + client.connect(m_uri).wait(); + client.close().wait(); + + websocket_outgoing_message msg; + msg.set_utf8_message(body); + VERIFY_THROWS(client.send(msg).wait(), websocket_exception); + } #endif -// Send after close for callback client -TEST_FIXTURE(uri_address, send_after_close_callback_client, "Ignore", "319") -{ - std::string body("hello"); - test_websocket_server server; - - server.next_message([&](test_websocket_msg msg) + // Send after close for callback client + TEST_FIXTURE(uri_address, send_after_close_callback_client, "Ignore", "319") { - websocket_asserts::assert_message_equals(msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - }); - websocket_callback_client client; + std::string body("hello"); + test_websocket_server server; - client.connect(m_uri).wait(); - client.close().wait(); + server.next_message([&](test_websocket_msg msg) { + websocket_asserts::assert_message_equals( + msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + }); + websocket_callback_client client; - websocket_outgoing_message msg; - msg.set_utf8_message(body); - VERIFY_THROWS(client.send(msg).wait(), websocket_exception); -} + client.connect(m_uri).wait(); + client.close().wait(); -// Receive after close -TEST_FIXTURE(uri_address, receive_after_close) -{ - test_websocket_server server; - websocket_client client; - client.connect(m_uri).wait(); - auto t = client.receive(); - client.close().wait(); - VERIFY_THROWS(t.wait(), websocket_exception); -} - -// Start receive task after client has closed -TEST_FIXTURE(uri_address, try_receive_after_close) -{ - test_websocket_server server; - websocket_client client; - client.connect(m_uri).wait(); - client.close().wait(); - auto t = client.receive(); - VERIFY_THROWS(t.wait(), websocket_exception); -} - -// Start the receive task after server has sent a close frame -TEST_FIXTURE(uri_address, try_receive_after_server_initiated_close) -{ - test_websocket_server server; - websocket_client client; - client.connect(m_uri).wait(); + websocket_outgoing_message msg; + msg.set_utf8_message(body); + VERIFY_THROWS(client.send(msg).wait(), websocket_exception); + } + + // Receive after close + TEST_FIXTURE(uri_address, receive_after_close) + { + test_websocket_server server; + websocket_client client; + client.connect(m_uri).wait(); + auto t = client.receive(); + client.close().wait(); + VERIFY_THROWS(t.wait(), websocket_exception); + } + + // Start receive task after client has closed + TEST_FIXTURE(uri_address, try_receive_after_close) + { + test_websocket_server server; + websocket_client client; + client.connect(m_uri).wait(); + client.close().wait(); + auto t = client.receive(); + VERIFY_THROWS(t.wait(), websocket_exception); + } + + // Start the receive task after server has sent a close frame + TEST_FIXTURE(uri_address, try_receive_after_server_initiated_close) + { + test_websocket_server server; + websocket_client client; + client.connect(m_uri).wait(); - // Send close frame from server - test_websocket_msg msg; - msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE); - server.send_msg(msg); + // Send close frame from server + test_websocket_msg msg; + msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE); + server.send_msg(msg); - // 100 ms should be plenty for local loopback - std::chrono::milliseconds dura(100); - std::this_thread::sleep_for(dura); + // 100 ms should be plenty for local loopback + std::chrono::milliseconds dura(100); + std::this_thread::sleep_for(dura); - auto t = client.receive(); - VERIFY_THROWS(t.wait(), websocket_exception); + auto t = client.receive(); + VERIFY_THROWS(t.wait(), websocket_exception); - client.close().wait(); -} + client.close().wait(); + } -// Destroy the client without closing it explicitly -TEST_FIXTURE(uri_address, destroy_without_close) -{ - test_websocket_server server; - websocket_client client; - client.connect(m_uri).wait(); -} + // Destroy the client without closing it explicitly + TEST_FIXTURE(uri_address, destroy_without_close) + { + test_websocket_server server; + websocket_client client; + client.connect(m_uri).wait(); + } -// Destroy the callback client without closing it explicitly -TEST_FIXTURE(uri_address, destroy_without_close_callback_client) -{ - // test won't finish if we can't release client properly - test_websocket_server server; - websocket_callback_client client; - client.connect(m_uri).wait(); -} - -// connect fails while user is waiting on receive -TEST_FIXTURE(uri_address, connect_fail_with_receive) -{ - websocket_client client; - auto t = client.receive(); + // Destroy the callback client without closing it explicitly + TEST_FIXTURE(uri_address, destroy_without_close_callback_client) + { + // test won't finish if we can't release client properly + test_websocket_server server; + websocket_callback_client client; + client.connect(m_uri).wait(); + } + + // connect fails while user is waiting on receive + TEST_FIXTURE(uri_address, connect_fail_with_receive) + { + websocket_client client; + auto t = client.receive(); - VERIFY_THROWS(client.connect(U("ws://localhost:9981/ws")).get(), websocket_exception); - VERIFY_THROWS(t.get(), websocket_exception); -} + VERIFY_THROWS(client.connect(U("ws://localhost:9981/ws")).get(), websocket_exception); + VERIFY_THROWS(t.get(), websocket_exception); + } } // SUITE(error_tests) -}}}} +} // namespace client +} // namespace websocket +} // namespace functional +} // namespace tests #endif diff --git a/Release/tests/functional/websockets/client/proxy_tests.cpp b/Release/tests/functional/websockets/client/proxy_tests.cpp index 1754949ca6..16df878f63 100644 --- a/Release/tests/functional/websockets/client/proxy_tests.cpp +++ b/Release/tests/functional/websockets/client/proxy_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* proxy_tests.cpp -* -* Tests cases for covering proxies using websocket_client -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * proxy_tests.cpp + * + * Tests cases for covering proxies using websocket_client + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -20,65 +20,73 @@ using namespace web::websockets::client; using namespace tests::functional::websocket::utilities; -namespace tests { namespace functional { namespace websocket { namespace client { - +namespace tests +{ +namespace functional +{ +namespace websocket +{ +namespace client +{ SUITE(proxy_tests) { - #ifdef __cplusplus_winrt -TEST_FIXTURE(uri_address, no_proxy_options_on_winrt) -{ - websocket_client_config config; - config.set_proxy(web::web_proxy::use_auto_discovery); - websocket_client client(config); - VERIFY_THROWS(client.connect(m_uri).wait(), websocket_exception); -} + TEST_FIXTURE(uri_address, no_proxy_options_on_winrt) + { + websocket_client_config config; + config.set_proxy(web::web_proxy::use_auto_discovery); + websocket_client client(config); + VERIFY_THROWS(client.connect(m_uri).wait(), websocket_exception); + } #endif #ifndef __cplusplus_winrt -// Can't specify a proxy with WinRT implementation. -TEST_FIXTURE(uri_address, proxy_with_credentials, "Ignore:Android", "390") -{ - web::web_proxy proxy(U("http://netproxy.redmond.corp.microsoft.com")); - web::credentials cred(U("artur"), U("fred")); // relax, this is not my real password - proxy.set_credentials(cred); - websocket_client_config config; - config.set_proxy(proxy); + // Can't specify a proxy with WinRT implementation. + TEST_FIXTURE(uri_address, proxy_with_credentials, "Ignore:Android", "390") + { + web::web_proxy proxy(U("http://netproxy.redmond.corp.microsoft.com")); + web::credentials cred(U("artur"), U("fred")); // relax, this is not my real password + proxy.set_credentials(cred); + websocket_client_config config; + config.set_proxy(proxy); - websocket_client client(config); + websocket_client client(config); - try - { - client.connect(U("wss://echo.websocket.org/")).wait(); - const auto text = std::string("hello"); - websocket_outgoing_message msg; - msg.set_utf8_message(text); - client.send(msg).wait(); - auto response = client.receive().get(); - VERIFY_ARE_EQUAL(text, response.extract_string().get()); - client.close().wait(); - } - catch (websocket_exception const& e) - { - if (e.error_code().value() == 12007) + try { - // The above "netproxy.redmond.corp.microsoft.com" is an internal site not generally accessible. - // This will cause a failure to resolve the URL. - // This is ok. - return; + client.connect(U("wss://echo.websocket.org/")).wait(); + const auto text = std::string("hello"); + websocket_outgoing_message msg; + msg.set_utf8_message(text); + client.send(msg).wait(); + auto response = client.receive().get(); + VERIFY_ARE_EQUAL(text, response.extract_string().get()); + client.close().wait(); } - else if (e.error_code().value() == 9 || e.error_code().value() == 5) + catch (websocket_exception const& e) { - // Timer expired case, since this is an outside test don't fail due to timing out. - return; + if (e.error_code().value() == 12007) + { + // The above "netproxy.redmond.corp.microsoft.com" is an internal site not generally accessible. + // This will cause a failure to resolve the URL. + // This is ok. + return; + } + else if (e.error_code().value() == 9 || e.error_code().value() == 5) + { + // Timer expired case, since this is an outside test don't fail due to timing out. + return; + } + throw; } - throw; } -} #endif } // SUITE(proxy_tests) -}}}} +} // namespace client +} // namespace websocket +} // namespace functional +} // namespace tests #endif diff --git a/Release/tests/functional/websockets/client/receive_msg_tests.cpp b/Release/tests/functional/websockets/client/receive_msg_tests.cpp index feca6a09a2..8100d51747 100644 --- a/Release/tests/functional/websockets/client/receive_msg_tests.cpp +++ b/Release/tests/functional/websockets/client/receive_msg_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* receive_msg_tests.cpp -* -* Test cases covering receiving messages from websocket server. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * receive_msg_tests.cpp + * + * Test cases covering receiving messages from websocket server. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -23,279 +23,285 @@ using namespace web::websockets::client; using namespace tests::functional::websocket::utilities; -namespace tests { namespace functional { namespace websocket { namespace client { - +namespace tests +{ +namespace functional +{ +namespace websocket +{ +namespace client +{ SUITE(receive_msg_tests) { + pplx::task receive_text_msg_helper(websocket_client & client, + test_websocket_server & server, + web::uri uri, + const std::string& body_str, + bool connect_client = true) + { + std::vector body(body_str.begin(), body_str.end()); -pplx::task receive_text_msg_helper(websocket_client& client, - test_websocket_server& server, - web::uri uri, - const std::string& body_str, - bool connect_client = true) -{ - std::vector body(body_str.begin(), body_str.end()); + if (connect_client) client.connect(uri).wait(); - if (connect_client) - client.connect(uri).wait(); + auto t = client.receive().then([body_str](websocket_incoming_message ret_msg) { + VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length()); + auto ret_str = ret_msg.extract_string().get(); - auto t = client.receive().then([body_str](websocket_incoming_message ret_msg) + VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); + }); + + test_websocket_msg msg; + msg.set_data(std::move(body)); + msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + server.send_msg(msg); + + return t; + } + + pplx::task receive_msg_stream_helper(websocket_client & client, + test_websocket_server & server, + web::uri uri, + const std::vector& body, + test_websocket_message_type type, + bool connect_client = true) { - VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length()); - auto ret_str = ret_msg.extract_string().get(); - - VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); - }); - - test_websocket_msg msg; - msg.set_data(std::move(body)); - msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - server.send_msg(msg); - - return t; -} - -pplx::task receive_msg_stream_helper(websocket_client& client, - test_websocket_server& server, - web::uri uri, - const std::vector& body, - test_websocket_message_type type, - bool connect_client = true) -{ - if (connect_client) - client.connect(uri).wait(); - - auto t = client.receive().then([body, type](websocket_incoming_message ret_msg) + if (connect_client) client.connect(uri).wait(); + + auto t = client.receive().then([body, type](websocket_incoming_message ret_msg) { + auto is = ret_msg.body(); + streams::container_buffer> ret_data; + is.read_to_end(ret_data).wait(); + + VERIFY_ARE_EQUAL(ret_msg.length(), body.size()); + VERIFY_ARE_EQUAL(body, ret_data.collection()); + if (type == test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE) + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::binary_message); + else if (type == test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE) + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); + }); + + test_websocket_msg msg; + msg.set_data(std::move(body)); + msg.set_msg_type(type); + server.send_msg(msg); + + return t; + } + + // Receive text message (no fragmentation) + TEST_FIXTURE(uri_address, receive_text_msg) { - auto is = ret_msg.body(); - streams::container_buffer> ret_data; - is.read_to_end(ret_data).wait(); - - VERIFY_ARE_EQUAL(ret_msg.length(), body.size()); - VERIFY_ARE_EQUAL(body, ret_data.collection()); - if (type == test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE) - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::binary_message); - else if (type == test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE) - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); - }); + test_websocket_server server; + websocket_client client; - test_websocket_msg msg; - msg.set_data(std::move(body)); - msg.set_msg_type(type); - server.send_msg(msg); + receive_text_msg_helper(client, server, m_uri, "hello").wait(); + client.close().wait(); + } - return t; -} + // Receive text message (no fragmentation) + // Test the stream interface to read data + TEST_FIXTURE(uri_address, receive_text_msg_stream) + { + std::string body_str("hello"); + std::vector body(body_str.begin(), body_str.end()); + test_websocket_server server; + websocket_client client; + + receive_msg_stream_helper( + client, server, m_uri, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE) + .wait(); + client.close().wait(); + } + + // Receive binary message (no fragmentation) + TEST_FIXTURE(uri_address, receive_binary_msg) + { + std::vector body; + body.resize(6); + memcpy(&body[0], "a\0b\0c\0", 6); -// Receive text message (no fragmentation) -TEST_FIXTURE(uri_address, receive_text_msg) -{ - test_websocket_server server; - websocket_client client; + test_websocket_server server; - receive_text_msg_helper(client, server, m_uri, "hello").wait(); - client.close().wait(); -} + websocket_client client; -// Receive text message (no fragmentation) -// Test the stream interface to read data -TEST_FIXTURE(uri_address, receive_text_msg_stream) -{ - std::string body_str("hello"); - std::vector body(body_str.begin(), body_str.end()); - test_websocket_server server; - websocket_client client; + receive_msg_stream_helper( + client, server, m_uri, body, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE) + .wait(); + client.close().wait(); + } - receive_msg_stream_helper(client, server, m_uri, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE).wait(); - client.close().wait(); -} + // Server sends text message fragmented in 2 fragments + TEST_FIXTURE(uri_address, receive_text_msg_fragments, "Ignore", "898451") + { + std::string body_str("hello"); + std::vector body(body_str.begin(), body_str.end()); + test_websocket_server server; -// Receive binary message (no fragmentation) -TEST_FIXTURE(uri_address, receive_binary_msg) -{ - std::vector body; - body.resize(6); - memcpy(&body[0], "a\0b\0c\0", 6); + websocket_client client; - test_websocket_server server; + client.connect(m_uri).wait(); - websocket_client client; + auto t = client.receive().then([&](websocket_incoming_message ret_msg) { + auto ret_str = ret_msg.extract_string().get(); - receive_msg_stream_helper(client, server, m_uri, body, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE).wait(); - client.close().wait(); -} + VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); + }); -// Server sends text message fragmented in 2 fragments -TEST_FIXTURE(uri_address, receive_text_msg_fragments, "Ignore", "898451") -{ - std::string body_str("hello"); - std::vector body(body_str.begin(), body_str.end()); - test_websocket_server server; + test_websocket_msg msg1; + msg1.set_data(std::move(body)); + msg1.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_FRAGMENT_TYPE); + server.send_msg(msg1); - websocket_client client; + test_websocket_msg msg2; + msg2.set_data(std::move(body)); + msg2.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_FRAGMENT_TYPE); + server.send_msg(msg2); - client.connect(m_uri).wait(); + t.wait(); + client.close().wait(); + } - auto t = client.receive().then([&](websocket_incoming_message ret_msg) + // Server sends message of length 0 + TEST_FIXTURE(uri_address, receive_zero_length_msg) { - auto ret_str = ret_msg.extract_string().get(); + test_websocket_server server; + websocket_client client; - VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); - }); + receive_text_msg_helper(client, server, m_uri, "").wait(); - test_websocket_msg msg1; - msg1.set_data(std::move(body)); - msg1.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_FRAGMENT_TYPE); - server.send_msg(msg1); + client.close().wait(); + } - test_websocket_msg msg2; - msg2.set_data(std::move(body)); - msg2.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_FRAGMENT_TYPE); - server.send_msg(msg2); - - t.wait(); - client.close().wait(); -} - -// Server sends message of length 0 -TEST_FIXTURE(uri_address, receive_zero_length_msg) -{ - test_websocket_server server; - websocket_client client; + // Receive UTF-8 string with special characters + TEST_FIXTURE(uri_address, receive_multi_byte_utf8_msg) + { + std::string body_str = "\xC3\xA0\xC3\xB8"; + test_websocket_server server; + websocket_client client; - receive_text_msg_helper(client, server, m_uri, "").wait(); + receive_text_msg_helper(client, server, m_uri, body_str).wait(); - client.close().wait(); -} + client.close().wait(); + } -// Receive UTF-8 string with special characters -TEST_FIXTURE(uri_address, receive_multi_byte_utf8_msg) -{ - std::string body_str = "\xC3\xA0\xC3\xB8"; - test_websocket_server server; - websocket_client client; - - receive_text_msg_helper(client, server, m_uri, body_str).wait(); + // Receive multiple messages + TEST_FIXTURE(uri_address, receive_multiple_msges) + { + test_websocket_server server; + websocket_client client; - client.close().wait(); -} + auto t1 = receive_text_msg_helper(client, server, m_uri, "hello1"); + auto t2 = receive_text_msg_helper(client, server, m_uri, "hello2", false); -// Receive multiple messages -TEST_FIXTURE(uri_address, receive_multiple_msges) -{ - test_websocket_server server; - websocket_client client; + t1.wait(); + t2.wait(); - auto t1 = receive_text_msg_helper(client, server, m_uri, "hello1"); - auto t2 = receive_text_msg_helper(client, server, m_uri, "hello2", false); + client.close().wait(); + } - t1.wait(); - t2.wait(); + // Start the receive task after the server has sent a message + TEST_FIXTURE(uri_address, receive_after_server_send) + { + std::string body_str("hello"); + std::vector body(body_str.begin(), body_str.end()); - client.close().wait(); -} + test_websocket_server server; -// Start the receive task after the server has sent a message -TEST_FIXTURE(uri_address, receive_after_server_send) -{ - std::string body_str("hello"); - std::vector body(body_str.begin(), body_str.end()); + websocket_client client; - test_websocket_server server; + client.connect(m_uri).wait(); - websocket_client client; + test_websocket_msg msg; + msg.set_data(std::move(body)); + msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + server.send_msg(msg); - client.connect(m_uri).wait(); + // We dont have a way of knowing if the message has been received by our client. + // Hence Sleep for 100 msecs and then initiate the receive + std::chrono::milliseconds dura(100); + std::this_thread::sleep_for(dura); - test_websocket_msg msg; - msg.set_data(std::move(body)); - msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - server.send_msg(msg); + client.receive() + .then([&](websocket_incoming_message ret_msg) { + auto ret_str = ret_msg.extract_string().get(); + VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); + }) + .wait(); - // We dont have a way of knowing if the message has been received by our client. - // Hence Sleep for 100 msecs and then initiate the receive - std::chrono::milliseconds dura(100); - std::this_thread::sleep_for(dura); + client.close().wait(); + } - client.receive().then([&](websocket_incoming_message ret_msg) + // Start task to receive text message before connecting. + TEST_FIXTURE(uri_address, receive_before_connect) { - auto ret_str = ret_msg.extract_string().get(); - VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); - }).wait(); - - client.close().wait(); -} + test_websocket_server server; + websocket_client client; -// Start task to receive text message before connecting. -TEST_FIXTURE(uri_address, receive_before_connect) -{ - test_websocket_server server; - websocket_client client; + std::string body_str("hello"); + std::vector body(body_str.begin(), body_str.end()); - std::string body_str("hello"); - std::vector body(body_str.begin(), body_str.end()); - - auto t = client.receive().then([body_str](websocket_incoming_message ret_msg) - { - VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length()); - auto ret_str = ret_msg.extract_string().get(); + auto t = client.receive().then([body_str](websocket_incoming_message ret_msg) { + VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length()); + auto ret_str = ret_msg.extract_string().get(); - VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); - }); + VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); + }); - // Connect after the client is waiting on a receive task. - client.connect(m_uri).wait(); + // Connect after the client is waiting on a receive task. + client.connect(m_uri).wait(); - // Now send the message from the server - test_websocket_msg msg; - msg.set_data(std::move(body)); - msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - server.send_msg(msg); + // Now send the message from the server + test_websocket_msg msg; + msg.set_data(std::move(body)); + msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + server.send_msg(msg); - t.wait(); - client.close().wait(); -} + t.wait(); + client.close().wait(); + } -// Receive message using callback APIs -TEST_FIXTURE(uri_address, receive_text_msg_callback_client) -{ - test_websocket_server server; - websocket_callback_client client; - - client.connect(m_uri).wait(); - std::string body_str("hello"); - std::vector body(body_str.begin(), body_str.end()); - - pplx::task_completion_event receiveEvent; - // make sure client works fine without setting receive handler - test_websocket_msg msg; - msg.set_data(std::move(body)); - msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - server.send_msg(msg); - - // set receive handler - client.set_message_handler([body_str, &receiveEvent](websocket_incoming_message ret_msg) + // Receive message using callback APIs + TEST_FIXTURE(uri_address, receive_text_msg_callback_client) { - VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length()); - auto ret_str = ret_msg.extract_string().get(); - - VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); - VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); + test_websocket_server server; + websocket_callback_client client; + + client.connect(m_uri).wait(); + std::string body_str("hello"); + std::vector body(body_str.begin(), body_str.end()); + + pplx::task_completion_event receiveEvent; + // make sure client works fine without setting receive handler + test_websocket_msg msg; + msg.set_data(std::move(body)); + msg.set_msg_type(test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + server.send_msg(msg); + + // set receive handler + client.set_message_handler([body_str, &receiveEvent](websocket_incoming_message ret_msg) { + VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length()); + auto ret_str = ret_msg.extract_string().get(); + + VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0); + VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message); - receiveEvent.set(); - }); + receiveEvent.set(); + }); - server.send_msg(msg); + server.send_msg(msg); - pplx::create_task(receiveEvent).wait(); - client.close().wait(); -} + pplx::create_task(receiveEvent).wait(); + client.close().wait(); + } } // SUITE(receive_msg_tests) -}}}} +} // namespace client +} // namespace websocket +} // namespace functional +} // namespace tests #endif diff --git a/Release/tests/functional/websockets/client/send_msg_tests.cpp b/Release/tests/functional/websockets/client/send_msg_tests.cpp index 63683ae2d1..e99bccd03c 100644 --- a/Release/tests/functional/websockets/client/send_msg_tests.cpp +++ b/Release/tests/functional/websockets/client/send_msg_tests.cpp @@ -1,15 +1,15 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* send_msg_tests.cpp -* -* Tests cases for covering sending messages from websocket client. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * send_msg_tests.cpp + * + * Tests cases for covering sending messages from websocket client. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" @@ -27,460 +27,496 @@ using namespace tests::functional::websocket::utilities; using namespace Windows::Storage; #endif -namespace tests { namespace functional { namespace websocket { namespace client { - -SUITE(send_msg_tests) +namespace tests +{ +namespace functional +{ +namespace websocket { -utility::string_t get_full_name(const utility::string_t &name) +namespace client { +SUITE(send_msg_tests) +{ + utility::string_t get_full_name(const utility::string_t& name) + { #if defined(__cplusplus_winrt) - // On WinRT, we must compensate for the fact that we will be accessing files in the - // Documents folder - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->CreateFileAsync( - ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)).get(); - return file->Path->Data(); + // On WinRT, we must compensate for the fact that we will be accessing files in the + // Documents folder + auto file = + pplx::create_task(KnownFolders::DocumentsLibrary->CreateFileAsync(ref new Platform::String(name.c_str()), + CreationCollisionOption::ReplaceExisting)) + .get(); + return file->Path->Data(); #else - return name; + return name; #endif -} + } -template -pplx::task> OPEN_R(const utility::string_t &name) -{ + template + pplx::task> OPEN_R(const utility::string_t& name) + { #if !defined(__cplusplus_winrt) - return streams::file_buffer<_CharType>::open(name, std::ios_base::in); + return streams::file_buffer<_CharType>::open(name, std::ios_base::in); #else - auto file = pplx::create_task( - KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))).get(); + auto file = + pplx::create_task(KnownFolders::DocumentsLibrary->GetFileAsync(ref new Platform::String(name.c_str()))) + .get(); - return streams::file_buffer<_CharType>::open(file, std::ios_base::in); + return streams::file_buffer<_CharType>::open(file, std::ios_base::in); #endif -} + } -// Used to prepare data for stream tests -void fill_file(const utility::string_t &name, const std::vector& body, size_t repetitions = 1) -{ - std::fstream stream(get_full_name(name), std::ios_base::out | std::ios_base::trunc); + // Used to prepare data for stream tests + void fill_file(const utility::string_t& name, const std::vector& body, size_t repetitions = 1) + { + std::fstream stream(get_full_name(name), std::ios_base::out | std::ios_base::trunc); - for (size_t i = 0; i < repetitions; i++) - stream.write((char *)&body[0], body.size()); - stream.close(); -} + for (size_t i = 0; i < repetitions; i++) + stream.write((char*)&body[0], body.size()); + stream.close(); + } -void fill_buffer(streams::streambuf rbuf, const std::vector& body, size_t repetitions = 1) -{ - size_t len = body.size(); - for (size_t i = 0; i < repetitions; i++) - rbuf.putn_nocopy((const uint8_t *)&body[0], len).wait(); -} + void fill_buffer(streams::streambuf rbuf, const std::vector& body, size_t repetitions = 1) + { + size_t len = body.size(); + for (size_t i = 0; i < repetitions; i++) + rbuf.putn_nocopy((const uint8_t*)&body[0], len).wait(); + } -template -pplx::task send_text_msg_helper(SocketClientClass& client, web::uri uri, test_websocket_server& server, const std::string& body, bool connect_client = true) -{ - server.next_message([body](test_websocket_msg msg) // Handler to verify the message sent by the client. + template + pplx::task send_text_msg_helper(SocketClientClass & client, + web::uri uri, + test_websocket_server & server, + const std::string& body, + bool connect_client = true) { - websocket_asserts::assert_message_equals(msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - }); + server.next_message([body](test_websocket_msg msg) // Handler to verify the message sent by the client. + { + websocket_asserts::assert_message_equals( + msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + }); - if (connect_client) - client.connect(uri).wait(); + if (connect_client) client.connect(uri).wait(); - websocket_outgoing_message msg; - msg.set_utf8_message(body); - return client.send(msg); -} + websocket_outgoing_message msg; + msg.set_utf8_message(body); + return client.send(msg); + } -template -pplx::task send_pong_msg_helper(SocketClientClass& client, web::uri uri, test_websocket_server& server) -{ - server.next_message([](test_websocket_msg msg) // Handler to verify the message sent by the client. - { - websocket_asserts::assert_message_equals(msg, "", test_websocket_message_type::WEB_SOCKET_PONG_TYPE); - }); - - client.connect(uri).wait(); - - websocket_outgoing_message msg; - msg.set_pong_message(); - return client.send(msg); -} - -pplx::task send_msg_from_stream(websocket_client& client, - test_websocket_server& server, - web::uri uri, - const std::vector& body, - streams::streambuf buf, - test_websocket_message_type type, - bool fill_data, - bool connect_client = true) -{ - server.next_message([body, type](test_websocket_msg msg) + template + pplx::task send_pong_msg_helper(SocketClientClass & client, web::uri uri, test_websocket_server & server) { - websocket_asserts::assert_message_equals(msg, body, type); - }); + server.next_message( + [](test_websocket_msg msg) // Handler to verify the message sent by the client. + { websocket_asserts::assert_message_equals(msg, "", test_websocket_message_type::WEB_SOCKET_PONG_TYPE); }); - if (connect_client) client.connect(uri).wait(); - if (fill_data) - fill_buffer(buf, body); - - websocket_outgoing_message msg; - if (type == test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE) - msg.set_utf8_message(streams::istream(buf), body.size()); - else if (type == test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE) - msg.set_binary_message(streams::istream(buf), body.size()); - - return client.send(msg); -} - -// Send message from input stream -> data is already populated in the stream buffer -pplx::task send_msg_from_istream_helper(websocket_client& client, - test_websocket_server& server, - web::uri uri, - const std::vector& body, - streams::streambuf rbuf, - test_websocket_message_type type, - bool connect_client = true) -{ - return send_msg_from_stream(client, server, uri, body, rbuf, type, false, connect_client); -} - -pplx::task send_msg_from_stream_helper(websocket_client& client, - test_websocket_server& server, - web::uri uri, - const std::vector& body, - streams::streambuf rbuf, - test_websocket_message_type type, - bool connect_client = true) -{ - return send_msg_from_stream(client, server, uri, body, rbuf, type, true, connect_client); -} -// Send text message (no fragmentation) -TEST_FIXTURE(uri_address, send_text_msg) -{ - test_websocket_server server; - websocket_client client; - send_text_msg_helper(client, m_uri, server, "hello").wait(); - client.close().wait(); -} - -// Send text message with websocket_callback_client -TEST_FIXTURE(uri_address, send_text_msg_callback_client) -{ - test_websocket_server server; - websocket_callback_client client; - send_text_msg_helper(client, m_uri, server, "hello").wait(); - client.close().wait(); -} - -// Send text message (no fragmentation) -// Test the stream interface to send data -TEST_FIXTURE(uri_address, send_text_msg_stream) -{ - test_websocket_server server; - streams::producer_consumer_buffer rbuf; - std::vector body(26); - memcpy(&body[0], "abcdefghijklmnopqrstuvwxyz", 26); + websocket_outgoing_message msg; + msg.set_pong_message(); + return client.send(msg); + } - websocket_client client; - send_msg_from_stream_helper(client, server, m_uri, body, rbuf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE).wait(); + pplx::task send_msg_from_stream(websocket_client & client, + test_websocket_server & server, + web::uri uri, + const std::vector& body, + streams::streambuf buf, + test_websocket_message_type type, + bool fill_data, + bool connect_client = true) + { + server.next_message( + [body, type](test_websocket_msg msg) { websocket_asserts::assert_message_equals(msg, body, type); }); - rbuf.close(std::ios::out).wait(); - client.close().wait(); -} + if (connect_client) client.connect(uri).wait(); + if (fill_data) fill_buffer(buf, body); -// Send Binary message (no fragmentation) -TEST_FIXTURE(uri_address, send_binary_msg) -{ - test_websocket_server server; - streams::producer_consumer_buffer rbuf; - std::vector body(6); - memcpy(&body[0], "a\0b\0c\0", 6); + websocket_outgoing_message msg; + if (type == test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE) + msg.set_utf8_message(streams::istream(buf), body.size()); + else if (type == test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE) + msg.set_binary_message(streams::istream(buf), body.size()); - websocket_client client; + return client.send(msg); + } - send_msg_from_stream_helper(client, server, m_uri, body, rbuf, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE).wait(); - rbuf.close(std::ios::out); - client.close().wait(); -} + // Send message from input stream -> data is already populated in the stream buffer + pplx::task send_msg_from_istream_helper(websocket_client & client, + test_websocket_server & server, + web::uri uri, + const std::vector& body, + streams::streambuf rbuf, + test_websocket_message_type type, + bool connect_client = true) + { + return send_msg_from_stream(client, server, uri, body, rbuf, type, false, connect_client); + } -// Send empty text message -// WinRT client does not handle empty messages. Verify websocket_exception is thrown. -TEST_FIXTURE(uri_address, send_empty_text_msg) -{ - test_websocket_server server; - websocket_client client; + pplx::task send_msg_from_stream_helper(websocket_client & client, + test_websocket_server & server, + web::uri uri, + const std::vector& body, + streams::streambuf rbuf, + test_websocket_message_type type, + bool connect_client = true) + { + return send_msg_from_stream(client, server, uri, body, rbuf, type, true, connect_client); + } - client.connect(m_uri).wait(); + // Send text message (no fragmentation) + TEST_FIXTURE(uri_address, send_text_msg) + { + test_websocket_server server; + websocket_client client; + send_text_msg_helper(client, m_uri, server, "hello").wait(); + client.close().wait(); + } - websocket_outgoing_message msg; - msg.set_utf8_message(""); - VERIFY_THROWS(client.send(msg).wait(), websocket_exception); + // Send text message with websocket_callback_client + TEST_FIXTURE(uri_address, send_text_msg_callback_client) + { + test_websocket_server server; + websocket_callback_client client; + send_text_msg_helper(client, m_uri, server, "hello").wait(); + client.close().wait(); + } - client.close().wait(); -} + // Send text message (no fragmentation) + // Test the stream interface to send data + TEST_FIXTURE(uri_address, send_text_msg_stream) + { + test_websocket_server server; + streams::producer_consumer_buffer rbuf; + std::vector body(26); + memcpy(&body[0], "abcdefghijklmnopqrstuvwxyz", 26); + + websocket_client client; + send_msg_from_stream_helper( + client, server, m_uri, body, rbuf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE) + .wait(); + + rbuf.close(std::ios::out).wait(); + client.close().wait(); + } -// Send multiple text messages -TEST_FIXTURE(uri_address, send_multiple_text_msges) -{ - test_websocket_server server; - websocket_client client; + // Send Binary message (no fragmentation) + TEST_FIXTURE(uri_address, send_binary_msg) + { + test_websocket_server server; + streams::producer_consumer_buffer rbuf; + std::vector body(6); + memcpy(&body[0], "a\0b\0c\0", 6); + + websocket_client client; + + send_msg_from_stream_helper( + client, server, m_uri, body, rbuf, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE) + .wait(); + rbuf.close(std::ios::out); + client.close().wait(); + } - send_text_msg_helper(client, m_uri, server, "hello1").wait(); - send_text_msg_helper(client, m_uri, server, "hello2", false).wait(); + // Send empty text message + // WinRT client does not handle empty messages. Verify websocket_exception is thrown. + TEST_FIXTURE(uri_address, send_empty_text_msg) + { + test_websocket_server server; + websocket_client client; - client.close().wait(); -} + client.connect(m_uri).wait(); -// Send multiple text messages -TEST_FIXTURE(uri_address, send_multiple_text_msges_async) -{ - test_websocket_server server; - websocket_client client; + websocket_outgoing_message msg; + msg.set_utf8_message(""); + VERIFY_THROWS(client.send(msg).wait(), websocket_exception); - auto t1 = send_text_msg_helper(client, m_uri, server, "hello1"); - auto t2 = send_text_msg_helper(client, m_uri, server, "hello2", false); + client.close().wait(); + } - t2.wait(); - t1.wait(); - client.close().wait(); -} + // Send multiple text messages + TEST_FIXTURE(uri_address, send_multiple_text_msges) + { + test_websocket_server server; + websocket_client client; -// Send multiple text messages from a stream -TEST_FIXTURE(uri_address, send_multiple_text_msges_stream) -{ - test_websocket_server server; - streams::producer_consumer_buffer rbuf; - std::vector body1(26); - memcpy(&body1[0], "abcdefghijklmnopqrstuvwxyz", 26); - std::vector body2(26); - memcpy(&body2[0], "zyxwvutsrqponmlkjihgfedcba", 26); - - websocket_client client; - - auto t1 = send_msg_from_stream_helper(client, server, m_uri, body1, rbuf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - auto t2 = send_msg_from_stream_helper(client, server, m_uri, body2, rbuf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE, false); - - t1.wait(); - t2.wait(); - client.close().wait(); -} - -// Send multiple text messages from a file stream -// send uses stream::acquire API, acquire will fail for file streams. -TEST_FIXTURE(uri_address, send_text_msges_fstream) -{ - test_websocket_server server; - utility::string_t fname = U("send_multiple_text_msges_fstream.txt"); - std::vector body1(26); - memcpy(&body1[0], "abcdefghijklmnopqrstuvwxyz", 26); - fill_file(fname, body1, 2); - auto file_buf = OPEN_R(fname).get(); - websocket_client client; - - auto t1 = send_msg_from_istream_helper(client, server, m_uri, body1, file_buf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - auto t2 = send_msg_from_istream_helper(client, server, m_uri, body1, file_buf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE, false); - - t1.wait(); - t2.wait(); - client.close().wait(); -} - -// Send multiple text messages from a container stream, where container stream has more data than what we want to send in a single message -TEST_FIXTURE(uri_address, send_text_msges_cstream) -{ - test_websocket_server server; - std::vector body(26); - memcpy(&body[0], "abcdefghijklmnopqrstuvwxyz", 26); - auto cbuf = streams::container_stream>::open_istream(body).streambuf(); + send_text_msg_helper(client, m_uri, server, "hello1").wait(); + send_text_msg_helper(client, m_uri, server, "hello2", false).wait(); - websocket_client client; + client.close().wait(); + } - auto t1 = send_msg_from_istream_helper(client, server, m_uri, std::vector(body.begin(), body.begin() + body.size() / 2), cbuf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - auto t2 = send_msg_from_istream_helper(client, server, m_uri, std::vector(body.begin() + body.size() / 2, body.end()), cbuf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE, false); + // Send multiple text messages + TEST_FIXTURE(uri_address, send_multiple_text_msges_async) + { + test_websocket_server server; + websocket_client client; - t1.wait(); - t2.wait(); - client.close().wait(); -} + auto t1 = send_text_msg_helper(client, m_uri, server, "hello1"); + auto t2 = send_text_msg_helper(client, m_uri, server, "hello2", false); -// Send multiple text messages from a producer consumer stream, where stream initially has less data than what we want to send in a single message -// Write data to the buffer after initiating the send, send should succeed. -TEST_FIXTURE(uri_address, send_text_msges_pcstream_lessdata) -{ - test_websocket_server server; - streams::producer_consumer_buffer rbuf; - std::vector body(26); - memcpy(&body[0], "abcdefghijklmnopqrstuvwxyz", 26); - fill_buffer(rbuf, body); + t2.wait(); + t1.wait(); + client.close().wait(); + } - server.next_message([](test_websocket_msg msg) + // Send multiple text messages from a stream + TEST_FIXTURE(uri_address, send_multiple_text_msges_stream) { - websocket_asserts::assert_message_equals(msg, "abcdefghijklmnopqrstuvwxyzabcd", test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - }); - - websocket_client client; - client.connect(m_uri).wait(); - websocket_outgoing_message msg; - msg.set_utf8_message(rbuf.create_istream(), 30); - auto t1 = client.send(msg); - - fill_buffer(rbuf, body); - t1.wait(); - client.close().wait(); -} - -// Send multiple text messages from a container stream, where stream has less data than what we want to send in a single message -// Since container stream does not support in | out simultaneously, websocket send_msg will fail to read the required number of bytes -// and throws an exception. -TEST_FIXTURE(uri_address, send_text_msges_cstream_lessdata) -{ - test_websocket_server server; - std::vector body(26); - memcpy(&body[0], "abcdefghijklmnopqrstuvwxyz", 26); - auto cbuf = streams::container_stream>::open_istream(body).streambuf(); + test_websocket_server server; + streams::producer_consumer_buffer rbuf; + std::vector body1(26); + memcpy(&body1[0], "abcdefghijklmnopqrstuvwxyz", 26); + std::vector body2(26); + memcpy(&body2[0], "zyxwvutsrqponmlkjihgfedcba", 26); + + websocket_client client; + + auto t1 = send_msg_from_stream_helper( + client, server, m_uri, body1, rbuf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + auto t2 = send_msg_from_stream_helper( + client, server, m_uri, body2, rbuf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE, false); + + t1.wait(); + t2.wait(); + client.close().wait(); + } - server.next_message([](test_websocket_msg msg) + // Send multiple text messages from a file stream + // send uses stream::acquire API, acquire will fail for file streams. + TEST_FIXTURE(uri_address, send_text_msges_fstream) { - websocket_asserts::assert_message_equals(msg, "abcdefghijklmnopqrstuvwxyzabcd", test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - }); + test_websocket_server server; + utility::string_t fname = U("send_multiple_text_msges_fstream.txt"); + std::vector body1(26); + memcpy(&body1[0], "abcdefghijklmnopqrstuvwxyz", 26); + fill_file(fname, body1, 2); + auto file_buf = OPEN_R(fname).get(); + websocket_client client; + + auto t1 = send_msg_from_istream_helper( + client, server, m_uri, body1, file_buf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + auto t2 = send_msg_from_istream_helper( + client, server, m_uri, body1, file_buf, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE, false); + + t1.wait(); + t2.wait(); + client.close().wait(); + } - websocket_client client; - client.connect(m_uri).wait(); - websocket_outgoing_message msg; - msg.set_utf8_message(cbuf.create_istream(), 30); + // Send multiple text messages from a container stream, where container stream has more data than what we want to + // send in a single message + TEST_FIXTURE(uri_address, send_text_msges_cstream) + { + test_websocket_server server; + std::vector body(26); + memcpy(&body[0], "abcdefghijklmnopqrstuvwxyz", 26); + auto cbuf = streams::container_stream>::open_istream(body).streambuf(); + + websocket_client client; + + auto t1 = send_msg_from_istream_helper(client, + server, + m_uri, + std::vector(body.begin(), body.begin() + body.size() / 2), + cbuf, + test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + auto t2 = send_msg_from_istream_helper(client, + server, + m_uri, + std::vector(body.begin() + body.size() / 2, body.end()), + cbuf, + test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE, + false); + + t1.wait(); + t2.wait(); + client.close().wait(); + } - VERIFY_THROWS(client.send(msg).wait(), websocket_exception); - client.close().wait(); -} + // Send multiple text messages from a producer consumer stream, where stream initially has less data than what we + // want to send in a single message Write data to the buffer after initiating the send, send should succeed. + TEST_FIXTURE(uri_address, send_text_msges_pcstream_lessdata) + { + test_websocket_server server; + streams::producer_consumer_buffer rbuf; + std::vector body(26); + memcpy(&body[0], "abcdefghijklmnopqrstuvwxyz", 26); + fill_buffer(rbuf, body); + + server.next_message([](test_websocket_msg msg) { + websocket_asserts::assert_message_equals( + msg, "abcdefghijklmnopqrstuvwxyzabcd", test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + }); -// Send multiple binary messages from the same stream -TEST_FIXTURE(uri_address, send_multiple_binary_msg_same_stream) -{ - test_websocket_server server; - streams::producer_consumer_buffer rbuf; - std::vector body1(6); - memcpy(&body1[0], "a\0b\0c\0", 6); - std::vector body2(6); - memcpy(&body2[0], "a\0b\0c\0", 6); - - websocket_client client; - - auto t1 = send_msg_from_stream_helper(client, server, m_uri, body1, rbuf, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE); - auto t2 = send_msg_from_stream_helper(client, server, m_uri, body2, rbuf, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE, false); - - t1.wait(); - t2.wait(); - rbuf.close(std::ios_base::out); - client.close().wait(); -} - -// Send text message followed by binary message -TEST_FIXTURE(uri_address, send_text_and_binary) -{ - test_websocket_server server; - streams::producer_consumer_buffer rbuf; - std::vector body2(6); - memcpy(&body2[0], "a\0b\0c\0", 6); + websocket_client client; + client.connect(m_uri).wait(); + websocket_outgoing_message msg; + msg.set_utf8_message(rbuf.create_istream(), 30); + auto t1 = client.send(msg); - websocket_client client; + fill_buffer(rbuf, body); + t1.wait(); + client.close().wait(); + } - send_text_msg_helper(client, m_uri, server, "hello1").wait(); - send_msg_from_stream_helper(client, server, m_uri, body2, rbuf, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE, false).wait(); + // Send multiple text messages from a container stream, where stream has less data than what we want to send in a + // single message Since container stream does not support in | out simultaneously, websocket send_msg will fail to + // read the required number of bytes and throws an exception. + TEST_FIXTURE(uri_address, send_text_msges_cstream_lessdata) + { + test_websocket_server server; + std::vector body(26); + memcpy(&body[0], "abcdefghijklmnopqrstuvwxyz", 26); + auto cbuf = streams::container_stream>::open_istream(body).streambuf(); + + server.next_message([](test_websocket_msg msg) { + websocket_asserts::assert_message_equals( + msg, "abcdefghijklmnopqrstuvwxyzabcd", test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + }); - rbuf.close(std::ios::out).wait(); - client.close().wait(); -} + websocket_client client; + client.connect(m_uri).wait(); + websocket_outgoing_message msg; + msg.set_utf8_message(cbuf.create_istream(), 30); -// Send a multi byte UTF-8 text message -TEST_FIXTURE(uri_address, send_multi_byte_utf8_msg) -{ - test_websocket_server server; - std::string body = "\xC3\xA0\xC3\xB8"; - websocket_client client; + VERIFY_THROWS(client.send(msg).wait(), websocket_exception); + client.close().wait(); + } - send_text_msg_helper(client, m_uri, server, body).wait(); - client.close().wait(); -} + // Send multiple binary messages from the same stream + TEST_FIXTURE(uri_address, send_multiple_binary_msg_same_stream) + { + test_websocket_server server; + streams::producer_consumer_buffer rbuf; + std::vector body1(6); + memcpy(&body1[0], "a\0b\0c\0", 6); + std::vector body2(6); + memcpy(&body2[0], "a\0b\0c\0", 6); + + websocket_client client; + + auto t1 = send_msg_from_stream_helper( + client, server, m_uri, body1, rbuf, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE); + auto t2 = send_msg_from_stream_helper( + client, server, m_uri, body2, rbuf, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE, false); + + t1.wait(); + t2.wait(); + rbuf.close(std::ios_base::out); + client.close().wait(); + } -// Send a streamed text message without specifying length -TEST_FIXTURE(uri_address, send_stream_utf8_msg_no_length) -{ - test_websocket_server server; + // Send text message followed by binary message + TEST_FIXTURE(uri_address, send_text_and_binary) + { + test_websocket_server server; + streams::producer_consumer_buffer rbuf; + std::vector body2(6); + memcpy(&body2[0], "a\0b\0c\0", 6); - std::string body = "\xC3\xA0\xC3\xB8"; - std::vector msgbuf(body.begin(), body.end()); + websocket_client client; - auto is = streams::container_stream>::open_istream(std::move(msgbuf)); + send_text_msg_helper(client, m_uri, server, "hello1").wait(); + send_msg_from_stream_helper( + client, server, m_uri, body2, rbuf, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE, false) + .wait(); - websocket_client client; - { - server.next_message([body](test_websocket_msg msg) // Handler to verify the message sent by the client. - { - websocket_asserts::assert_message_equals(msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); - }); + rbuf.close(std::ios::out).wait(); + client.close().wait(); + } - client.connect(m_uri).wait(); + // Send a multi byte UTF-8 text message + TEST_FIXTURE(uri_address, send_multi_byte_utf8_msg) + { + test_websocket_server server; + std::string body = "\xC3\xA0\xC3\xB8"; + websocket_client client; - websocket_outgoing_message msg; - msg.set_utf8_message(is); - client.send(msg).wait(); + send_text_msg_helper(client, m_uri, server, body).wait(); + client.close().wait(); } - client.close().wait(); -} + // Send a streamed text message without specifying length + TEST_FIXTURE(uri_address, send_stream_utf8_msg_no_length) + { + test_websocket_server server; -// Send a streamed binary message without specifying length -TEST_FIXTURE(uri_address, send_stream_binary_msg_no_length) -{ - test_websocket_server server; + std::string body = "\xC3\xA0\xC3\xB8"; + std::vector msgbuf(body.begin(), body.end()); - std::string body = "\x00\x01\x02\x00"; - std::vector msgbuf(body.begin(), body.end()); + auto is = streams::container_stream>::open_istream(std::move(msgbuf)); - auto is = streams::container_stream>::open_istream(std::move(msgbuf)); + websocket_client client; + { + server.next_message([body](test_websocket_msg msg) // Handler to verify the message sent by the client. + { + websocket_asserts::assert_message_equals( + msg, body, test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE); + }); + + client.connect(m_uri).wait(); - websocket_client client; + websocket_outgoing_message msg; + msg.set_utf8_message(is); + client.send(msg).wait(); + } + + client.close().wait(); + } + + // Send a streamed binary message without specifying length + TEST_FIXTURE(uri_address, send_stream_binary_msg_no_length) { - server.next_message([body](test_websocket_msg msg) // Handler to verify the message sent by the client. + test_websocket_server server; + + std::string body = "\x00\x01\x02\x00"; + std::vector msgbuf(body.begin(), body.end()); + + auto is = streams::container_stream>::open_istream(std::move(msgbuf)); + + websocket_client client; { - websocket_asserts::assert_message_equals(msg, body, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE); - }); + server.next_message([body](test_websocket_msg msg) // Handler to verify the message sent by the client. + { + websocket_asserts::assert_message_equals( + msg, body, test_websocket_message_type::WEB_SOCKET_BINARY_MESSAGE_TYPE); + }); - client.connect(m_uri).wait(); + client.connect(m_uri).wait(); - websocket_outgoing_message msg; - msg.set_binary_message(is); - client.send(msg).wait(); - } + websocket_outgoing_message msg; + msg.set_binary_message(is); + client.send(msg).wait(); + } - client.close().wait(); -} + client.close().wait(); + } #if !defined(__cplusplus_winrt) -// Send an unsolicited pong message to the server -TEST_FIXTURE(uri_address, send_pong_msg) -{ - test_websocket_server server; - websocket_client client; - send_pong_msg_helper(client, m_uri, server).wait(); - client.close().wait(); -} - -// Send an unsolicited pong message to the server with websocket_callback_client -TEST_FIXTURE(uri_address, send_pong_msg_callback_client) -{ - test_websocket_server server; - websocket_callback_client client; - send_pong_msg_helper(client, m_uri, server).wait(); - client.close().wait(); -} + // Send an unsolicited pong message to the server + TEST_FIXTURE(uri_address, send_pong_msg) + { + test_websocket_server server; + websocket_client client; + send_pong_msg_helper(client, m_uri, server).wait(); + client.close().wait(); + } + + // Send an unsolicited pong message to the server with websocket_callback_client + TEST_FIXTURE(uri_address, send_pong_msg_callback_client) + { + test_websocket_server server; + websocket_callback_client client; + send_pong_msg_helper(client, m_uri, server).wait(); + client.close().wait(); + } #endif } // SUITE(send_msg_tests) -}}}} +} // namespace client +} // namespace websocket +} // namespace functional +} // namespace tests #endif diff --git a/Release/tests/functional/websockets/client/stdafx.cpp b/Release/tests/functional/websockets/client/stdafx.cpp index d1bea25da0..2e322eaa32 100644 --- a/Release/tests/functional/websockets/client/stdafx.cpp +++ b/Release/tests/functional/websockets/client/stdafx.cpp @@ -1,14 +1,14 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ -// stdafx.cpp : + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ +// stdafx.cpp : // Include the standard header and generate the precompiled header. #include "stdafx.h" #if WIN32 __declspec(dllexport) int websocket_client_test_generate_lib = 0; -#endif \ No newline at end of file +#endif diff --git a/Release/tests/functional/websockets/client/stdafx.h b/Release/tests/functional/websockets/client/stdafx.h index 2fe1a6e277..6e22e86470 100644 --- a/Release/tests/functional/websockets/client/stdafx.h +++ b/Release/tests/functional/websockets/client/stdafx.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -15,19 +15,16 @@ #include #endif -#include -#include - #include "cpprest/asyncrt_utils.h" -#include "cpprest/rawptrstream.h" #include "cpprest/containerstream.h" -#include "cpprest/producerconsumerstream.h" #include "cpprest/filestream.h" +#include "cpprest/producerconsumerstream.h" +#include "cpprest/rawptrstream.h" #include "cpprest/ws_client.h" #include "cpprest/ws_msg.h" - -#include "unittestpp.h" #include "os_utilities.h" - -#include "websocket_client_tests.h" #include "test_websocket_server.h" +#include "unittestpp.h" +#include "websocket_client_tests.h" +#include +#include diff --git a/Release/tests/functional/websockets/client/websocket_client_tests.h b/Release/tests/functional/websockets/client/websocket_client_tests.h index e363cdf497..a7a7272571 100644 --- a/Release/tests/functional/websockets/client/websocket_client_tests.h +++ b/Release/tests/functional/websockets/client/websocket_client_tests.h @@ -1,23 +1,29 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* websocket_client_tests.h -* -* Common declarations and helper functions for http_client test cases. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * websocket_client_tests.h + * + * Common declarations and helper functions for http_client test cases. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #include "cpprest/uri.h" #include "unittestpp.h" -namespace tests { namespace functional { namespace websocket { namespace client { - +namespace tests +{ +namespace functional +{ +namespace websocket +{ +namespace client +{ class uri_address { public: @@ -25,4 +31,7 @@ class uri_address web::uri m_uri; }; -}}}} \ No newline at end of file +} // namespace client +} // namespace websocket +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/websockets/utilities/stdafx.cpp b/Release/tests/functional/websockets/utilities/stdafx.cpp index bc2dfe733c..c8f4d74525 100644 --- a/Release/tests/functional/websockets/utilities/stdafx.cpp +++ b/Release/tests/functional/websockets/utilities/stdafx.cpp @@ -1,10 +1,10 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -**/ -// stdafx.cpp : + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + **/ +// stdafx.cpp : // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" diff --git a/Release/tests/functional/websockets/utilities/stdafx.h b/Release/tests/functional/websockets/utilities/stdafx.h index 044c32650b..e8adb749c9 100644 --- a/Release/tests/functional/websockets/utilities/stdafx.h +++ b/Release/tests/functional/websockets/utilities/stdafx.h @@ -1,13 +1,13 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Pre-compiled headers + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once @@ -27,10 +27,8 @@ #endif #endif -#include "cpprest/uri.h" #include "cpprest/asyncrt_utils.h" -#include "cpprest/streams.h" #include "cpprest/containerstream.h" - +#include "cpprest/streams.h" +#include "cpprest/uri.h" #include "unittestpp.h" - diff --git a/Release/tests/functional/websockets/utilities/test_websocket_server.cpp b/Release/tests/functional/websockets/utilities/test_websocket_server.cpp index b4cfd806c4..151d03bca0 100644 --- a/Release/tests/functional/websockets/utilities/test_websocket_server.cpp +++ b/Release/tests/functional/websockets/utilities/test_websocket_server.cpp @@ -1,25 +1,24 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Defines a test server to handle websocket messages. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Defines a test server to handle websocket messages. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include -#include +#include "test_websocket_server.h" +#include #include - -#include "test_websocket_server.h" +#include #ifdef _WIN32 #pragma warning(disable : 4503) // generated too late for disable to be effective inside push/pop -#pragma warning( push ) +#pragma warning(push) #pragma warning(disable : 4100 4127 4996 4512 4701 4267 4067 4005) #define _WEBSOCKETPP_CPP11_STL_ #define _WEBSOCKETPP_CONSTEXPR_TOKEN_ @@ -41,7 +40,7 @@ #endif #ifdef _WIN32 -#pragma warning( pop ) +#pragma warning(pop) #endif using namespace web; @@ -54,216 +53,194 @@ using namespace utility::conversions; // Websocketpp typedefs typedef websocketpp::server server; -namespace tests { -namespace functional { -namespace websocket { -namespace utilities { - - /// - /// Implementation of http request from websocket handshake to avoid leaking - /// details about websocketpp into test utilities. - /// - class test_http_request_impl : public test_http_request_interface +namespace tests +{ +namespace functional +{ +namespace websocket +{ +namespace utilities +{ +/// +/// Implementation of http request from websocket handshake to avoid leaking +/// details about websocketpp into test utilities. +/// +class test_http_request_impl : public test_http_request_interface +{ +public: + test_http_request_impl(server::connection_ptr connection) : m_connection(std::move(connection)) {} + + const std::string& username() override { throw std::runtime_error("NYI"); } + const std::string& password() override { throw std::runtime_error("NYI"); } + + const std::string& get_header_val(const std::string& header_name) override { - public: - test_http_request_impl(server::connection_ptr connection) - : m_connection(std::move(connection)) - {} - - const std::string& username() override - { - throw std::runtime_error("NYI"); - } - const std::string& password() override - { - throw std::runtime_error("NYI"); - } - - const std::string& get_header_val(const std::string& header_name) override - { - return m_connection->get_request_header(header_name); - } + return m_connection->get_request_header(header_name); + } - private: - server::connection_ptr m_connection; - }; +private: + server::connection_ptr m_connection; +}; - class _test_websocket_server +class _test_websocket_server +{ +public: + _test_websocket_server(test_websocket_server* test_srv) : m_test_srv(test_srv) { - public: - _test_websocket_server(test_websocket_server* test_srv) - : m_test_srv(test_srv) - { - m_srv.clear_access_channels(websocketpp::log::alevel::all); - m_srv.clear_error_channels(websocketpp::log::elevel::all); - connect(); - } + m_srv.clear_access_channels(websocketpp::log::alevel::all); + m_srv.clear_error_channels(websocketpp::log::elevel::all); + connect(); + } - void connect() - { - m_srv.set_validate_handler([this](websocketpp::connection_hdl hdl) + void connect() + { + m_srv.set_validate_handler([this](websocketpp::connection_hdl hdl) { + auto handler = m_test_srv->get_http_handler(); + if (handler) { - auto handler = m_test_srv->get_http_handler(); - if (handler) + server::connection_ptr connection = m_srv.get_con_from_hdl(hdl); + test_http_request request(new test_http_request_impl(connection)); + test_http_response response = handler(std::move(request)); + + // Also need to indicate the connection is rejected if non 200 status code. + connection->set_status(static_cast(response.status_code())); + if (response.status_code() != 200) { - server::connection_ptr connection = m_srv.get_con_from_hdl(hdl); - test_http_request request(new test_http_request_impl(connection)); - test_http_response response = handler(std::move(request)); - - // Also need to indicate the connection is rejected if non 200 status code. - connection->set_status(static_cast(response.status_code())); - if (response.status_code() != 200) - { - return false; - } + return false; } - return true; - }); + } + return true; + }); - m_srv.set_open_handler([this](websocketpp::connection_hdl hdl) - { - m_con = hdl; - m_server_connected.set(); - }); + m_srv.set_open_handler([this](websocketpp::connection_hdl hdl) { + m_con = hdl; + m_server_connected.set(); + }); - m_srv.set_fail_handler([this](websocketpp::connection_hdl hdl) - { - m_con = hdl; - m_server_connected.set_exception(std::runtime_error("Connection attempt failed.")); - }); + m_srv.set_fail_handler([this](websocketpp::connection_hdl hdl) { + m_con = hdl; + m_server_connected.set_exception(std::runtime_error("Connection attempt failed.")); + }); - m_srv.set_pong_handler([this](websocketpp::connection_hdl hdl, std::string input) - { - auto fn = m_test_srv->get_next_message_handler(); - assert(fn); + m_srv.set_pong_handler([this](websocketpp::connection_hdl hdl, std::string input) { + auto fn = m_test_srv->get_next_message_handler(); + assert(fn); - test_websocket_msg wsmsg; + test_websocket_msg wsmsg; - wsmsg.set_data(std::vector(input.begin(), input.end())); + wsmsg.set_data(std::vector(input.begin(), input.end())); - wsmsg.set_msg_type(WEB_SOCKET_PONG_TYPE); - fn(wsmsg); - }); + wsmsg.set_msg_type(WEB_SOCKET_PONG_TYPE); + fn(wsmsg); + }); - m_srv.set_message_handler([this](websocketpp::connection_hdl hdl, server::message_ptr msg) - { - auto pay = msg->get_payload(); + m_srv.set_message_handler([this](websocketpp::connection_hdl hdl, server::message_ptr msg) { + auto pay = msg->get_payload(); - auto fn = m_test_srv->get_next_message_handler(); - assert(fn); + auto fn = m_test_srv->get_next_message_handler(); + assert(fn); - test_websocket_msg wsmsg; + test_websocket_msg wsmsg; - wsmsg.set_data(std::vector(pay.begin(), pay.end())); + wsmsg.set_data(std::vector(pay.begin(), pay.end())); - switch (msg->get_opcode()) - { + switch (msg->get_opcode()) + { case websocketpp::frame::opcode::binary: wsmsg.set_msg_type(utilities::WEB_SOCKET_BINARY_MESSAGE_TYPE); break; case websocketpp::frame::opcode::text: - wsmsg.set_msg_type(utilities::WEB_SOCKET_UTF8_MESSAGE_TYPE); + wsmsg.set_msg_type(utilities::WEB_SOCKET_UTF8_MESSAGE_TYPE); break; - case websocketpp::frame::opcode::close: - wsmsg.set_msg_type(utilities::WEB_SOCKET_CLOSE_TYPE); - break; - default: + case websocketpp::frame::opcode::close: wsmsg.set_msg_type(utilities::WEB_SOCKET_CLOSE_TYPE); break; + default: // Websocketspp does not currently support explicit fragmentation. We should not get here. std::abort(); - } - - fn(wsmsg); - }); - - m_srv.init_asio(); - m_srv.start_perpetual(); - - m_srv.set_reuse_addr(true); - - websocketpp::lib::error_code ec; - m_srv.listen(WEBSOCKETS_TEST_SERVER_PORT, ec); - if (ec) - { - throw std::runtime_error(ec.message()); } - m_srv.start_accept(); - m_thread = std::thread(&server::run, &m_srv); - } + fn(wsmsg); + }); - ~_test_websocket_server() - { - close("destructor"); - m_srv.stop_listening(); - m_srv.stop_perpetual(); - _ASSERTE(m_thread.joinable()); - m_thread.join(); - } + m_srv.init_asio(); + m_srv.start_perpetual(); - void send_msg(const test_websocket_msg& msg); + m_srv.set_reuse_addr(true); - void close(const std::string& reasoning) + websocketpp::lib::error_code ec; + m_srv.listen(WEBSOCKETS_TEST_SERVER_PORT, ec); + if (ec) { - websocketpp::lib::error_code ec; - m_srv.close(m_con, websocketpp::close::status::going_away, reasoning, ec); - // Ignore the error code. + throw std::runtime_error(ec.message()); } - private: - - test_websocket_server* m_test_srv; - - std::thread m_thread; - - server m_srv; - websocketpp::connection_hdl m_con; - // Once the WebSocket object has been initialized, - // the below event wil be used to signal that the server has been initialized. - // The server can now send messages to the client. - pplx::task_completion_event m_server_connected; - }; - - test_websocket_server::test_websocket_server() - : m_p_impl(std::make_shared<_test_websocket_server>(this)) - { } - - void test_websocket_server::next_message(std::function handler) - { - std::lock_guard lg(m_handler_queue_lock); - assert(handler); - m_handler_queue.push(handler); - assert(m_handler_queue.front()); + m_srv.start_accept(); + m_thread = std::thread(&server::run, &m_srv); } - std::function test_websocket_server::get_next_message_handler() + ~_test_websocket_server() { - std::lock_guard lg(m_handler_queue_lock); - assert(m_handler_queue.size() > 0); - auto handler = m_handler_queue.front(); - assert(handler); - m_handler_queue.pop(); - assert(handler); - return handler; + close("destructor"); + m_srv.stop_listening(); + m_srv.stop_perpetual(); + _ASSERTE(m_thread.joinable()); + m_thread.join(); } - void test_websocket_server::send_msg(const test_websocket_msg& msg) - { - m_p_impl->send_msg(msg); - } + void send_msg(const test_websocket_msg& msg); - std::shared_ptr<_test_websocket_server> test_websocket_server::get_impl() + void close(const std::string& reasoning) { - return m_p_impl; + websocketpp::lib::error_code ec; + m_srv.close(m_con, websocketpp::close::status::going_away, reasoning, ec); + // Ignore the error code. } - void _test_websocket_server::send_msg(const test_websocket_msg& msg) +private: + test_websocket_server* m_test_srv; + + std::thread m_thread; + + server m_srv; + websocketpp::connection_hdl m_con; + // Once the WebSocket object has been initialized, + // the below event wil be used to signal that the server has been initialized. + // The server can now send messages to the client. + pplx::task_completion_event m_server_connected; +}; + +test_websocket_server::test_websocket_server() : m_p_impl(std::make_shared<_test_websocket_server>(this)) {} + +void test_websocket_server::next_message(std::function handler) +{ + std::lock_guard lg(m_handler_queue_lock); + assert(handler); + m_handler_queue.push(handler); + assert(m_handler_queue.front()); +} + +std::function test_websocket_server::get_next_message_handler() +{ + std::lock_guard lg(m_handler_queue_lock); + assert(m_handler_queue.size() > 0); + auto handler = m_handler_queue.front(); + assert(handler); + m_handler_queue.pop(); + assert(handler); + return handler; +} + +void test_websocket_server::send_msg(const test_websocket_msg& msg) { m_p_impl->send_msg(msg); } + +std::shared_ptr<_test_websocket_server> test_websocket_server::get_impl() { return m_p_impl; } + +void _test_websocket_server::send_msg(const test_websocket_msg& msg) +{ + // Wait for the websocket server to be initialized. + pplx::task(m_server_connected).wait(); + const auto& data = msg.data(); + auto flags = websocketpp::frame::opcode::close; + switch (msg.msg_type()) { - // Wait for the websocket server to be initialized. - pplx::task(m_server_connected).wait(); - const auto& data = msg.data(); - auto flags = websocketpp::frame::opcode::close; - switch (msg.msg_type()) - { case test_websocket_message_type::WEB_SOCKET_UTF8_MESSAGE_TYPE: flags = websocketpp::frame::opcode::text; // WebSocket::FRAME_FLAG_FIN | WebSocket::FRAME_OP_TEXT; break; @@ -273,24 +250,25 @@ namespace utilities { case test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE: flags = websocketpp::frame::opcode::close; // WebSocket::FRAME_OP_CLOSE; break; - case test_websocket_message_type::WEB_SOCKET_UTF8_FRAGMENT_TYPE: + case test_websocket_message_type::WEB_SOCKET_UTF8_FRAGMENT_TYPE: case test_websocket_message_type::WEB_SOCKET_BINARY_FRAGMENT_TYPE: - default: - throw std::runtime_error("invalid message type"); - } + default: throw std::runtime_error("invalid message type"); + } - std::string strmsg(data.begin(), data.end()); + std::string strmsg(data.begin(), data.end()); - if (msg.msg_type() == test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE) - { - close(strmsg); - } - else - { - // std::cerr << "Sending message from server: " << strmsg << std::endl; - m_srv.send(m_con, strmsg, flags); - } + if (msg.msg_type() == test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE) + { + close(strmsg); } + else + { + // std::cerr << "Sending message from server: " << strmsg << std::endl; + m_srv.send(m_con, strmsg, flags); + } +} -}}}} - +} // namespace utilities +} // namespace websocket +} // namespace functional +} // namespace tests diff --git a/Release/tests/functional/websockets/utilities/test_websocket_server.h b/Release/tests/functional/websockets/utilities/test_websocket_server.h index dce960a479..50489e1a9d 100644 --- a/Release/tests/functional/websockets/utilities/test_websocket_server.h +++ b/Release/tests/functional/websockets/utilities/test_websocket_server.h @@ -1,21 +1,22 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* test_websocket_server.h -- Defines a test server to handle incoming and outgoing messages. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * test_websocket_server.h -- Defines a test server to handle incoming and outgoing messages. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once -#include -#include +#include #include +#include #include -#include +#include +#include #ifndef WEBSOCKET_UTILITY_API #ifdef WEBSOCKETTESTUTILITY_EXPORTS @@ -27,19 +28,25 @@ #if !defined(_M_ARM) || defined(__cplusplus_winrt) -namespace tests { namespace functional { namespace websocket { namespace utilities { - +namespace tests +{ +namespace functional +{ +namespace websocket +{ +namespace utilities +{ class _test_websocket_server; // The different types of a websocket message. enum test_websocket_message_type { - WEB_SOCKET_BINARY_MESSAGE_TYPE, - WEB_SOCKET_BINARY_FRAGMENT_TYPE, - WEB_SOCKET_UTF8_MESSAGE_TYPE, - WEB_SOCKET_UTF8_FRAGMENT_TYPE, - WEB_SOCKET_CLOSE_TYPE, - WEB_SOCKET_PONG_TYPE + WEB_SOCKET_BINARY_MESSAGE_TYPE, + WEB_SOCKET_BINARY_FRAGMENT_TYPE, + WEB_SOCKET_UTF8_MESSAGE_TYPE, + WEB_SOCKET_UTF8_FRAGMENT_TYPE, + WEB_SOCKET_CLOSE_TYPE, + WEB_SOCKET_PONG_TYPE }; // Interface containing details about the HTTP handshake request received by the test server. @@ -61,13 +68,14 @@ class test_http_response void set_status_code(unsigned short code) { m_status_code = code; } const std::string& realm() const { return m_realm; } unsigned short status_code() const { return m_status_code; } + private: std::string m_realm; unsigned short m_status_code; }; // Represents a websocket message at the test server. -// Contains a vector that can contain text/binary data +// Contains a vector that can contain text/binary data // and a type variable to denote the message type. class test_websocket_msg { @@ -86,13 +94,17 @@ class test_websocket_msg class websocket_asserts { public: - static void assert_message_equals(test_websocket_msg& msg, const std::string& expected_data, test_websocket_message_type expected_flag) + static void assert_message_equals(test_websocket_msg& msg, + const std::string& expected_data, + test_websocket_message_type expected_flag) { std::vector temp_vec(expected_data.begin(), expected_data.end()); assert_message_equals(msg, temp_vec, expected_flag); } - static void assert_message_equals(test_websocket_msg& msg, const std::vector& expected_data, test_websocket_message_type expected_flag) + static void assert_message_equals(test_websocket_msg& msg, + const std::vector& expected_data, + test_websocket_message_type expected_flag) { VERIFY_ARE_EQUAL(msg.msg_type(), expected_flag); auto& data = msg.data(); @@ -105,8 +117,8 @@ class websocket_asserts ~websocket_asserts() CPPREST_NOEXCEPT {} }; -// Test websocket server. -class test_websocket_server +// Test websocket server. +class test_websocket_server { public: WEBSOCKET_UTILITY_API test_websocket_server(); @@ -114,11 +126,11 @@ class test_websocket_server // Tests can add a handler to handle (verify) the next message received by the server. // If the test plans to send n messages, n handlers must be registered. // The server will call the handler in order, for each incoming message. - WEBSOCKET_UTILITY_API void next_message(std::function msg_handler); + WEBSOCKET_UTILITY_API void next_message(std::function msg_handler); WEBSOCKET_UTILITY_API std::function get_next_message_handler(); // Handler for initial HTTP request. - typedef std::function http_handler; + typedef std::function http_handler; WEBSOCKET_UTILITY_API void set_http_handler(http_handler handler) { m_http_handler = handler; } WEBSOCKET_UTILITY_API http_handler get_http_handler() { return m_http_handler; } @@ -127,7 +139,6 @@ class test_websocket_server WEBSOCKET_UTILITY_API std::shared_ptr<_test_websocket_server> get_impl(); private: - #if !defined(_MSC_VER) || _MSC_VER >= 1800 test_websocket_server(const test_websocket_server&) = delete; test_websocket_server& operator=(const test_websocket_server&) = delete; @@ -139,11 +150,14 @@ class test_websocket_server // Note: This queue is not thread-safe. Use m_handler_queue_lock to synchronize. std::mutex m_handler_queue_lock; std::queue> m_handler_queue; - // Handler to address the HTTP handshake request. To be used in scenarios where tests may wish to fail the HTTP request - // and not proceed with the websocket connection. + // Handler to address the HTTP handshake request. To be used in scenarios where tests may wish to fail the HTTP + // request and not proceed with the websocket connection. http_handler m_http_handler; std::shared_ptr<_test_websocket_server> m_p_impl; }; -}}}} +} // namespace utilities +} // namespace websocket +} // namespace functional +} // namespace tests #endif