Commit 86ef2a43 authored by Jacob Bogdanov's avatar Jacob Bogdanov

Upgrade to C++17 and use std::optional

Fixes #858

Replace `Pistache::Optional` with `std::optional`
parent 5b5e374d
...@@ -2,8 +2,8 @@ cmake_minimum_required (VERSION 3.11) ...@@ -2,8 +2,8 @@ cmake_minimum_required (VERSION 3.11)
set(CMAKE_BUILD_TYPE_INIT Release) set(CMAKE_BUILD_TYPE_INIT Release)
# CMAKE Pin cxx compiler to CXX14 until update to CXX17 # CMAKE Pin cxx compiler to CXX17
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
[![Build Status](https://travis-ci.org/pistacheio/pistache.svg?branch=master)](https://travis-ci.org/pistacheio/pistache) [![Build Status](https://travis-ci.org/pistacheio/pistache.svg?branch=master)](https://travis-ci.org/pistacheio/pistache)
Pistache is a modern and elegant HTTP and REST framework for C++. It is entirely written in pure-C++14 and provides a clear and pleasant API. Pistache is a modern and elegant HTTP and REST framework for C++. It is entirely written in pure-C++17 and provides a clear and pleasant API.
## Documentation ## Documentation
...@@ -214,13 +214,13 @@ Be patient, async_test can take some time before completing. And that's it, now ...@@ -214,13 +214,13 @@ Be patient, async_test can take some time before completing. And that's it, now
Some other Meson options: Some other Meson options:
| Option | Default | Description | | Option | Default | Description |
|-------------------------------|-------------|------------------------------------------------| | ----------------------------- | ------- | ---------------------------------------------- |
| PISTACHE_USE_SSL | False | Build server with SSL support | | PISTACHE_USE_SSL | False | Build server with SSL support |
| PISTACHE_BUILD_TESTS | False | Build all of the unit tests | | PISTACHE_BUILD_TESTS | False | Build all of the unit tests |
| PISTACHE_ENABLE_NETWORK_TESTS | True | Run unit tests requiring remote network access | | PISTACHE_ENABLE_NETWORK_TESTS | True | Run unit tests requiring remote network access |
| PISTACHE_BUILD_EXAMPLES | False | Build all of the example apps | | PISTACHE_BUILD_EXAMPLES | False | Build all of the example apps |
| PISTACHE_BUILD_DOCS | False | Build Doxygen docs | | PISTACHE_BUILD_DOCS | False | Build Doxygen docs |
## Continuous Integration Testing ## Continuous Integration Testing
......
...@@ -32,7 +32,7 @@ Depends: ...@@ -32,7 +32,7 @@ Depends:
rapidjson-dev (>= 1.1.0) rapidjson-dev (>= 1.1.0)
Description: elegant C++ REST framework Description: elegant C++ REST framework
Pistache is a C++ REST framework originally written by Mathieu Stefani at Pistache is a C++ REST framework originally written by Mathieu Stefani at
Datacratic, since maintained by other volunteers. It is written in pure C++14 Datacratic, since maintained by other volunteers. It is written in pure C++17
with no external dependency and provides a low-level HTTP abstraction. with no external dependency and provides a low-level HTTP abstraction.
. .
Pistache provides both an HTTP client and server that can be used to create and Pistache provides both an HTTP client and server that can be used to create and
...@@ -51,7 +51,7 @@ Depends: ...@@ -51,7 +51,7 @@ Depends:
${shlibs:Depends} ${shlibs:Depends}
Description: elegant C++ REST framework Description: elegant C++ REST framework
Pistache is a C++ REST framework originally written by Mathieu Stefani at Pistache is a C++ REST framework originally written by Mathieu Stefani at
Datacratic, since maintained by other volunteers. It is written in pure C++14 Datacratic, since maintained by other volunteers. It is written in pure C++17
with no external dependency and provides a low-level HTTP abstraction. with no external dependency and provides a low-level HTTP abstraction.
. .
Pistache provides both an HTTP client and server that can be used to create and Pistache provides both an HTTP client and server that can be used to create and
......
...@@ -9,12 +9,12 @@ ...@@ -9,12 +9,12 @@
#include <ctime> #include <ctime>
#include <list> #include <list>
#include <map> #include <map>
#include <optional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <pistache/http_defs.h> #include <pistache/http_defs.h>
#include <pistache/optional.h>
namespace Pistache namespace Pistache
{ {
...@@ -30,11 +30,11 @@ namespace Pistache ...@@ -30,11 +30,11 @@ namespace Pistache
std::string name; std::string name;
std::string value; std::string value;
Optional<std::string> path; std::optional<std::string> path;
Optional<std::string> domain; std::optional<std::string> domain;
Optional<FullDate> expires; std::optional<FullDate> expires;
Optional<int> maxAge; std::optional<int> maxAge;
bool secure; bool secure;
bool httpOnly; bool httpOnly;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <algorithm> #include <algorithm>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <optional>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
...@@ -16,7 +17,6 @@ ...@@ -16,7 +17,6 @@
#include <pistache/http_defs.h> #include <pistache/http_defs.h>
#include <pistache/iterator_adapter.h> #include <pistache/iterator_adapter.h>
#include <pistache/mime.h> #include <pistache/mime.h>
#include <pistache/optional.h>
#include <pistache/router.h> #include <pistache/router.h>
namespace Pistache namespace Pistache
...@@ -154,8 +154,8 @@ namespace Pistache ...@@ -154,8 +154,8 @@ namespace Pistache
std::string description; std::string description;
std::string termsOfService; std::string termsOfService;
Optional<Contact> contact; std::optional<Contact> contact;
Optional<License> license; std::optional<License> license;
}; };
struct InfoBuilder struct InfoBuilder
...@@ -305,7 +305,7 @@ namespace Pistache ...@@ -305,7 +305,7 @@ namespace Pistache
{ } { }
Group paths(const std::string& name) const; Group paths(const std::string& name) const;
Optional<Path> path(const std::string& name, Http::Method method) const; std::optional<Path> path(const std::string& name, Http::Method method) const;
group_iterator add(Path path); group_iterator add(Path path);
......
...@@ -125,7 +125,7 @@ namespace Pistache ...@@ -125,7 +125,7 @@ namespace Pistache
std::initializer_list<std::pair<const std::string, std::string>> params); std::initializer_list<std::pair<const std::string, std::string>> params);
void add(std::string name, std::string value); void add(std::string name, std::string value);
Optional<std::string> get(const std::string& name) const; std::optional<std::string> get(const std::string& name) const;
bool has(const std::string& name) const; bool has(const std::string& name) const;
// Return empty string or "?key1=value1&key2=value2" if query exist // Return empty string or "?key1=value1&key2=value2" if query exist
std::string as_str() const; std::string as_str() const;
......
...@@ -101,7 +101,7 @@ namespace Pistache ...@@ -101,7 +101,7 @@ namespace Pistache
std::shared_ptr<const Header> tryGet(const std::string& name) const; std::shared_ptr<const Header> tryGet(const std::string& name) const;
std::shared_ptr<Header> tryGet(const std::string& name); std::shared_ptr<Header> tryGet(const std::string& name);
Optional<Raw> tryGetRaw(const std::string& name) const; std::optional<Raw> tryGetRaw(const std::string& name) const;
template <typename H> template <typename H>
typename std::enable_if<IsHeader<H>::value, bool>::type has() const typename std::enable_if<IsHeader<H>::value, bool>::type has() const
......
...@@ -8,12 +8,11 @@ ...@@ -8,12 +8,11 @@
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <optional>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <pistache/optional.h>
namespace Pistache namespace Pistache
{ {
namespace Http namespace Http
...@@ -197,10 +196,10 @@ namespace Pistache ...@@ -197,10 +196,10 @@ namespace Pistache
std::string raw() const { return raw_; } std::string raw() const { return raw_; }
const Optional<Q>& q() const { return q_; } const std::optional<Q>& q() const { return q_; }
void setQuality(Q quality); void setQuality(Q quality);
Optional<std::string> getParam(const std::string& name) const; std::optional<std::string> getParam(const std::string& name) const;
void setParam(const std::string& name, std::string value); void setParam(const std::string& name, std::string value);
std::string toString() const; std::string toString() const;
...@@ -234,7 +233,7 @@ namespace Pistache ...@@ -234,7 +233,7 @@ namespace Pistache
std::unordered_map<std::string, std::string> params; std::unordered_map<std::string, std::string> params;
Optional<Q> q_; std::optional<Q> q_;
}; };
inline bool operator==(const MediaType& lhs, const MediaType& rhs) inline bool operator==(const MediaType& lhs, const MediaType& rhs)
......
/* optional.h
Mathieu Stefani, 27 August 2015
An algebraic data type that can either represent Some Value or None.
This type is the equivalent of the Haskell's Maybe type
*/
#pragma once
#include <array>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
namespace Pistache
{
template <typename T>
class Optional;
namespace types
{
template <typename T>
class Some
{
public:
template <typename U>
friend class Pistache::Optional;
explicit Some(const T& val)
: val_(val)
{ }
explicit Some(T&& val)
: val_(std::move(val))
{ }
private:
T val_;
};
class None
{ };
namespace impl
{
template <typename Func>
struct callable_trait : public callable_trait<decltype(&Func::operator())>
{ };
template <typename Class, typename Ret, typename... Args>
struct callable_trait<Ret (Class::*)(Args...) const>
{
static constexpr size_t Arity = sizeof...(Args);
typedef std::tuple<Args...> ArgsType;
typedef Ret ReturnType;
template <size_t Index>
struct Arg
{
static_assert(Index < Arity, "Invalid index");
typedef typename std::tuple_element<Index, ArgsType>::type Type;
};
};
} // namespace impl
template <typename Func, bool IsBindExp = std::is_bind_expression<Func>::value>
struct callable_trait;
/* std::bind returns an unspecified type which contains several overloads
* of operator(). Thus, decltype(&operator()) does not compile since operator()
* is overloaded. To bypass that, we only define the ReturnType for bind
* expressions
*/
template <typename Func>
struct callable_trait<Func, true>
{
typedef typename Func::result_type ReturnType;
};
template <typename Func>
struct callable_trait<Func, false> : public impl::callable_trait<Func>
{ };
template <typename T>
struct is_nothrow_move_constructible
: std::is_nothrow_constructible<
T, typename std::add_rvalue_reference<T>::type>
{ };
template <class T>
struct is_move_constructible
: std::is_constructible<T, typename std::add_rvalue_reference<T>::type>
{ };
// Workaround for C++14 defect (CWG 1558)
template <typename... Ts>
struct make_void
{
typedef void type;
};
template <typename... Ts>
using void_t = typename make_void<Ts...>::type;
// cppcheck 1.88 (and earlier?) are unable to handle the following template.
// cppcheck reports:
// (error) Syntax Error: AST broken, binary operator '>' doesn't have two
// operands.
// In order to run cppcheck on the rest of this file, we need to cause cppcheck
// to skip the next few lines of code (the code is valid and compiles just
// fine).
#ifndef CPPCHECK
template <typename, typename = void_t<>>
struct has_equalto_operator : std::false_type
{ };
#endif
template <typename T>
struct has_equalto_operator<
T, void_t<decltype(std::declval<T>() == std::declval<T>())>>
: std::true_type
{ };
} // namespace types
inline types::None None() { return types::None(); }
template <typename T, typename CleanT = typename std::remove_reference<T>::type>
inline types::Some<CleanT> Some(T&& value)
{
return types::Some<CleanT>(std::forward<T>(value));
}
template <typename T>
class Optional
{
public:
Optional() { none_flag = NoneMarker; }
// TODO: SFINAE-out if T is not trivially_copyable
Optional(const Optional<T>& other)
{
if (!other.isEmpty())
{
::new (data()) T(*other.data());
none_flag = ValueMarker;
}
else
{
none_flag = NoneMarker;
}
}
Optional(Optional<T>&& other) noexcept(
types::is_nothrow_move_constructible<T>::value)
{
*this = std::move(other);
}
template <typename U>
Optional(types::Some<U> some)
: none_flag(NoneMarker)
{
static_assert(std::is_same<T, U>::value || std::is_convertible<U, T>::value,
"Types mismatch");
from_some_helper(std::move(some), types::is_move_constructible<U>());
}
Optional(types::None) { none_flag = NoneMarker; }
template <typename U>
Optional<T>& operator=(types::Some<U> some)
{
static_assert(std::is_same<T, U>::value || std::is_convertible<U, T>::value,
"Types mismatch");
if (none_flag != NoneMarker)
{
data()->~T();
}
from_some_helper(std::move(some), types::is_move_constructible<U>());
return *this;
}
Optional<T>& operator=(types::None)
{
if (none_flag != NoneMarker)
{
data()->~T();
}
none_flag = NoneMarker;
return *this;
}
// TODO: SFINAE-out if T is not trivially_copyable
Optional<T>& operator=(const Optional<T>& other)
{
if (!other.isEmpty())
{
if (none_flag != NoneMarker)
{
data()->~T();
}
::new (data()) T(*other.data());
none_flag = ValueMarker;
}
else
{
if (none_flag != NoneMarker)
{
data()->~T();
}
none_flag = NoneMarker;
}
return *this;
}
Optional<T>& operator=(Optional<T>&& other) noexcept(
types::is_nothrow_move_constructible<T>::value)
{
if (!other.isEmpty())
{
move_helper(std::move(other), types::is_move_constructible<T>());
other.none_flag = NoneMarker;
}
else
{
none_flag = NoneMarker;
}
return *this;
}
bool isEmpty() const { return none_flag == NoneMarker; }
T getOrElse(const T& defaultValue)
{
if (none_flag != NoneMarker)
{
return *constData();
}
return defaultValue;
}
const T& getOrElse(const T& defaultValue) const
{
if (none_flag != NoneMarker)
{
return *constData();
}
return defaultValue;
}
template <typename Func>
void orElse(Func func) const
{
if (isEmpty())
{
func();
}
}
T get() { return *constData(); }
const T& get() const { return *constData(); }
T& unsafeGet() const { return *data(); }
~Optional()
{
if (!isEmpty())
{
data()->~T();
}
}
bool operator==(const Optional<T>& other) const
{
static_assert(
types::has_equalto_operator<T>::value,
"optional<T> requires T to be comparable by equal to operator");
return (isEmpty() && other.isEmpty()) || (!isEmpty() && !other.isEmpty() && get() == other.get());
}
bool operator!=(const Optional<T>& other) const
{
static_assert(
types::has_equalto_operator<T>::value,
"optional<T> requires T to be comparable by equal to operator");
return !(*this == other);
}
private:
T* constData() const
{
return const_cast<T* const>(reinterpret_cast<const T* const>(bytes.data()));
}
T* data() const
{
return const_cast<T*>(reinterpret_cast<const T*>(bytes.data()));
}
void move_helper(Optional<T>&& other, std::true_type)
{
::new (data()) T(std::move(*other.data()));
none_flag = ValueMarker;
}
void move_helper(Optional<T>&& other, std::false_type)
{
::new (data()) T(*other.data());
none_flag = ValueMarker;
}
template <typename U>
void from_some_helper(types::Some<U> some, std::true_type)
{
::new (data()) T(std::move(some.val_));
none_flag = ValueMarker;
}
template <typename U>
void from_some_helper(types::Some<U> some, std::false_type)
{
::new (data()) T(some.val_);
none_flag = ValueMarker;
}
typedef uint8_t none_flag_t;
static constexpr none_flag_t NoneMarker = 1;
static constexpr none_flag_t ValueMarker = 0;
alignas(T) std::array<uint8_t, sizeof(T)> bytes;
none_flag_t none_flag;
};
#define PistacheCheckSize(Type) \
static_assert(sizeof(Optional<Type>) == sizeof(Type) + alignof(Type), \
"Size differs")
PistacheCheckSize(uint8_t);
PistacheCheckSize(uint16_t);
PistacheCheckSize(int);
PistacheCheckSize(void*);
PistacheCheckSize(std::string);
namespace details
{
template <typename T>
struct RemoveOptional
{
typedef T Type;
};
template <typename T>
struct RemoveOptional<Optional<T>>
{
typedef T Type;
};
template <typename T, typename Func>
void do_static_checks(std::false_type)
{
static_assert(types::callable_trait<Func>::Arity == 1,
"The function must take exactly 1 argument");
typedef typename types::callable_trait<Func>::template Arg<0>::Type ArgType;
typedef typename std::remove_cv<
typename std::remove_reference<ArgType>::type>::type CleanArgType;
static_assert(std::is_same<CleanArgType, T>::value || std::is_convertible<CleanArgType, T>::value,
"Function parameter type mismatch");
}
template <typename T, typename Func>
void do_static_checks(std::true_type) { }
template <typename T, typename Func>
void static_checks()
{
do_static_checks<T, Func>(std::is_bind_expression<Func>());
}
template <typename Func>
struct IsArgMovable : public IsArgMovable<decltype(&Func::operator())>
{ };
template <typename R, typename Class, typename Arg>
struct IsArgMovable<R (Class::*)(Arg) const>
: public std::is_rvalue_reference<Arg>
{ };
template <typename Func, typename Arg>
typename std::conditional<IsArgMovable<Func>::value, Arg&&, const Arg&>::type
tryMove(Arg& arg)
{
return std::move(arg);
}
} // namespace details
template <typename T, typename Func>
const Optional<T>& optionally_do(const Optional<T>& option, Func func)
{
details::static_checks<T, Func>();
static_assert(std::is_same<typename types::callable_trait<Func>::ReturnType,
void>::value,
"Use optionally_map if you want to return a value");
if (!option.isEmpty())
{
func(details::tryMove<Func>(option.unsafeGet()));
}
return option;
}
template <typename T, typename Func>
auto optionally_map(const Optional<T>& option, Func func)
-> Optional<typename types::callable_trait<Func>::ReturnType>
{
details::static_checks<T, Func>();
if (!option.isEmpty())
{
return Some(func(details::tryMove<Func>(option.unsafeGet())));
}
return None();
}
template <typename T, typename Func>
auto optionally_fmap(const Optional<T>& option, Func func)
-> Optional<typename details::RemoveOptional<
typename types::callable_trait<Func>::ReturnType>::Type>
{
details::static_checks<T, Func>();
if (!option.isEmpty())
{
const auto& ret = func(details::tryMove<Func>(option.unsafeGet()));
if (!ret.isEmpty())
{
return Some(ret.get());
}
}
return None();
}
template <typename T, typename Func>
Optional<T> optionally_filter(const Optional<T>& option, Func func)
{
details::static_checks<T, Func>();
typedef typename types::callable_trait<Func>::ReturnType ReturnType;
static_assert(std::is_same<ReturnType, bool>::value || std::is_convertible<ReturnType, bool>::value,
"The predicate must return a boolean value");
if (!option.isEmpty() && func(option.get()))
{
return Some(option.get());
}
return None();
}
} // namespace Pistache
...@@ -3323,13 +3323,13 @@ namespace date ...@@ -3323,13 +3323,13 @@ namespace date
static CONSTDATA classify value = std::is_convertible<Duration, std::chrono::hours>::value static CONSTDATA classify value = std::is_convertible<Duration, std::chrono::hours>::value
? classify::hour ? classify::hour
: std::is_convertible<Duration, std::chrono::minutes>::value : std::is_convertible<Duration, std::chrono::minutes>::value
? classify::minute ? classify::minute
: std::is_convertible<Duration, std::chrono::seconds>::value : std::is_convertible<Duration, std::chrono::seconds>::value
? classify::second ? classify::second
: std::chrono::treat_as_floating_point< : std::chrono::treat_as_floating_point<
typename Duration::rep>::value typename Duration::rep>::value
? classify::not_valid ? classify::not_valid
: classify::subsecond; : classify::subsecond;
}; };
template <class Rep, class Period> template <class Rep, class Period>
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <pistache/async.h> #include <pistache/async.h>
#include <pistache/mailbox.h> #include <pistache/mailbox.h>
#include <pistache/optional.h>
#include <pistache/reactor.h> #include <pistache/reactor.h>
#include <pistache/stream.h> #include <pistache/stream.h>
...@@ -16,6 +15,7 @@ ...@@ -16,6 +15,7 @@
#include <deque> #include <deque>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <optional>
#include <unordered_map> #include <unordered_map>
namespace Pistache namespace Pistache
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <pistache/stream.h> #include <pistache/stream.h>
#include <iterator> #include <iterator>
#include <optional>
#include <unordered_map> #include <unordered_map>
namespace Pistache namespace Pistache
...@@ -38,21 +39,21 @@ namespace Pistache ...@@ -38,21 +39,21 @@ namespace Pistache
struct AttributeMatcher; struct AttributeMatcher;
template <> template <>
struct AttributeMatcher<Optional<std::string>> struct AttributeMatcher<std::optional<std::string>>
{ {
static void match(StreamCursor& cursor, Cookie* obj, static void match(StreamCursor& cursor, Cookie* obj,
Optional<std::string> Cookie::*attr) std::optional<std::string> Cookie::*attr)
{ {
auto token = matchValue(cursor); auto token = matchValue(cursor);
obj->*attr = Some(token.text()); obj->*attr = token.text();
} }
}; };
template <> template <>
struct AttributeMatcher<Optional<int>> struct AttributeMatcher<std::optional<int>>
{ {
static void match(StreamCursor& cursor, Cookie* obj, static void match(StreamCursor& cursor, Cookie* obj,
Optional<int> Cookie::*attr) std::optional<int> Cookie::*attr)
{ {
auto token = matchValue(cursor); auto token = matchValue(cursor);
...@@ -70,7 +71,7 @@ namespace Pistache ...@@ -70,7 +71,7 @@ namespace Pistache
return ret; return ret;
}; };
obj->*attr = Some(strntol(token.rawText(), token.size())); obj->*attr = strntol(token.rawText(), token.size());
} }
}; };
...@@ -85,13 +86,13 @@ namespace Pistache ...@@ -85,13 +86,13 @@ namespace Pistache
}; };
template <> template <>
struct AttributeMatcher<Optional<FullDate>> struct AttributeMatcher<std::optional<FullDate>>
{ {
static void match(StreamCursor& cursor, Cookie* obj, static void match(StreamCursor& cursor, Cookie* obj,
Optional<FullDate> Cookie::*attr) std::optional<FullDate> Cookie::*attr)
{ {
auto token = matchValue(cursor); auto token = matchValue(cursor);
obj->*attr = Some(FullDate::fromString(token.text())); obj->*attr = FullDate::fromString(token.text());
} }
}; };
...@@ -202,23 +203,31 @@ namespace Pistache ...@@ -202,23 +203,31 @@ namespace Pistache
void Cookie::write(std::ostream& os) const void Cookie::write(std::ostream& os) const
{ {
os << name << "=" << value; os << name << "=" << value;
optionally_do(path, [&](const std::string& value) { if (path.has_value())
{
const std::string& value = *path;
os << "; "; os << "; ";
os << "Path=" << value; os << "Path=" << value;
}); }
optionally_do(domain, [&](const std::string& value) { if (domain.has_value())
{
const std::string& value = *domain;
os << "; "; os << "; ";
os << "Domain=" << value; os << "Domain=" << value;
}); }
optionally_do(maxAge, [&](int value) { if (maxAge.has_value())
{
int value = *maxAge;
os << "; "; os << "; ";
os << "Max-Age=" << value; os << "Max-Age=" << value;
}); }
optionally_do(expires, [&](const FullDate& value) { if (expires.has_value())
{
const FullDate& value = *expires;
os << "; "; os << "; ";
os << "Expires="; os << "Expires=";
value.write(os); value.write(os);
}); }
if (secure) if (secure)
os << "; Secure"; os << "; Secure";
if (httpOnly) if (httpOnly)
......
...@@ -158,8 +158,8 @@ namespace Pistache ...@@ -158,8 +158,8 @@ namespace Pistache
return it->second; return it->second;
} }
Optional<Path> PathGroup::path(const std::string& name, std::optional<Path> PathGroup::path(const std::string& name,
Http::Method method) const Http::Method method) const
{ {
auto group = paths(name); auto group = paths(name);
auto it = std::find_if(std::begin(group), std::end(group), auto it = std::find_if(std::begin(group), std::end(group),
...@@ -167,9 +167,9 @@ namespace Pistache ...@@ -167,9 +167,9 @@ namespace Pistache
if (it != std::end(group)) if (it != std::end(group))
{ {
return Optional<Path>(Some(*it)); return std::optional<Path>(*it);
} }
return Optional<Path>(None()); return std::nullopt;
} }
PathGroup::group_iterator PathGroup::add(Path path) PathGroup::group_iterator PathGroup::add(Path path)
...@@ -258,13 +258,13 @@ namespace Pistache ...@@ -258,13 +258,13 @@ namespace Pistache
InfoBuilder& InfoBuilder::contact(std::string name, std::string url, InfoBuilder& InfoBuilder::contact(std::string name, std::string url,
std::string email) std::string email)
{ {
info_->contact = Some(Contact(std::move(name), std::move(url), std::move(email))); info_->contact = Contact(std::move(name), std::move(url), std::move(email));
return *this; return *this;
} }
InfoBuilder& InfoBuilder::license(std::string name, std::string url) InfoBuilder& InfoBuilder::license(std::string name, std::string url)
{ {
info_->license = Some(License(std::move(name), std::move(url))); info_->license = License(std::move(name), std::move(url));
return *this; return *this;
} }
......
...@@ -586,13 +586,13 @@ namespace Pistache ...@@ -586,13 +586,13 @@ namespace Pistache
params.insert(std::make_pair(std::move(name), std::move(value))); params.insert(std::make_pair(std::move(name), std::move(value)));
} }
Optional<std::string> Query::get(const std::string& name) const std::optional<std::string> Query::get(const std::string& name) const
{ {
auto it = params.find(name); auto it = params.find(name);
if (it == std::end(params)) if (it == std::end(params))
return Optional<std::string>(None()); return std::nullopt;
return Optional<std::string>(Some(it->second)); return std::optional<std::string>(it->second);
} }
std::string Query::as_str() const std::string Query::as_str() const
......
...@@ -170,15 +170,15 @@ namespace Pistache ...@@ -170,15 +170,15 @@ namespace Pistache
return header.second; return header.second;
} }
Optional<Raw> Collection::tryGetRaw(const std::string& name) const std::optional<Raw> Collection::tryGetRaw(const std::string& name) const
{ {
auto it = rawHeaders.find(name); auto it = rawHeaders.find(name);
if (it == std::end(rawHeaders)) if (it == std::end(rawHeaders))
{ {
return Optional<Raw>(None()); return std::nullopt;
} }
return Optional<Raw>(Some(it->second)); return std::optional<Raw>(it->second);
} }
bool Collection::has(const std::string& name) const bool Collection::has(const std::string& name) const
......
...@@ -240,7 +240,7 @@ namespace Pistache ...@@ -240,7 +240,7 @@ namespace Pistache
double val; double val;
if (!match_double(&val, cursor)) if (!match_double(&val, cursor))
raise("Invalid quality factor"); raise("Invalid quality factor");
q_ = Some(Q::fromFloat(val)); q_ = Q::fromFloat(val);
} }
else else
{ {
...@@ -266,17 +266,17 @@ namespace Pistache ...@@ -266,17 +266,17 @@ namespace Pistache
} }
} }
void MediaType::setQuality(Q quality) { q_ = Some(quality); } void MediaType::setQuality(Q quality) { q_ = quality; }
Optional<std::string> MediaType::getParam(const std::string& name) const std::optional<std::string> MediaType::getParam(const std::string& name) const
{ {
auto it = params.find(name); auto it = params.find(name);
if (it == std::end(params)) if (it == std::end(params))
{ {
return Optional<std::string>(None()); return std::nullopt;
} }
return Optional<std::string>(Some(it->second)); return std::optional<std::string>(it->second);
} }
void MediaType::setParam(const std::string& name, std::string value) void MediaType::setParam(const std::string& name, std::string value)
...@@ -339,10 +339,12 @@ namespace Pistache ...@@ -339,10 +339,12 @@ namespace Pistache
res += suffixString(suffix_); res += suffixString(suffix_);
} }
optionally_do(q_, [&res](Q quality) { if (q_.has_value())
{
Q quality = *q_;
res += "; "; res += "; ";
res += quality.toString(); res += quality.toString();
}); }
for (const auto& param : params) for (const auto& param : params)
{ {
......
...@@ -36,7 +36,6 @@ pistache_test(mailbox_test) ...@@ -36,7 +36,6 @@ pistache_test(mailbox_test)
pistache_test(stream_test) pistache_test(stream_test)
pistache_test(reactor_test) pistache_test(reactor_test)
pistache_test(threadname_test) pistache_test(threadname_test)
pistache_test(optional_test)
pistache_test(log_api_test) pistache_test(log_api_test)
pistache_test(string_logger_test) pistache_test(string_logger_test)
......
...@@ -28,29 +28,29 @@ TEST(cookie_test, attributes_test) ...@@ -28,29 +28,29 @@ TEST(cookie_test, attributes_test)
parse("SID=31d4d96e407aad42; Path=/", [](const Cookie& c) { parse("SID=31d4d96e407aad42; Path=/", [](const Cookie& c) {
ASSERT_EQ(c.name, "SID"); ASSERT_EQ(c.name, "SID");
ASSERT_EQ(c.value, "31d4d96e407aad42"); ASSERT_EQ(c.value, "31d4d96e407aad42");
ASSERT_EQ(c.path.getOrElse(""), "/"); ASSERT_EQ(c.path.value_or(""), "/");
}); });
parse("SID=31d4d96e407aad42; Path=/; Domain=example.com", parse("SID=31d4d96e407aad42; Path=/; Domain=example.com",
[](const Cookie& c) { [](const Cookie& c) {
ASSERT_EQ(c.path.getOrElse(""), "/"); ASSERT_EQ(c.path.value_or(""), "/");
ASSERT_EQ(c.domain.getOrElse(""), "example.com"); ASSERT_EQ(c.domain.value_or(""), "example.com");
}); });
parse("lang=en-US; Path=/; Domain=example.com; Max-Age=10", parse("lang=en-US; Path=/; Domain=example.com; Max-Age=10",
[](const Cookie& c) { [](const Cookie& c) {
ASSERT_EQ(c.name, "lang"); ASSERT_EQ(c.name, "lang");
ASSERT_EQ(c.value, "en-US"); ASSERT_EQ(c.value, "en-US");
ASSERT_EQ(c.path.getOrElse(""), "/"); ASSERT_EQ(c.path.value_or(""), "/");
ASSERT_EQ(c.domain.getOrElse(""), "example.com"); ASSERT_EQ(c.domain.value_or(""), "example.com");
ASSERT_EQ(c.maxAge.getOrElse(0), 10); ASSERT_EQ(c.maxAge.value_or(0), 10);
}); });
parse("lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT", parse("lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT",
[](const Cookie& c) { [](const Cookie& c) {
ASSERT_EQ(c.name, "lang"); ASSERT_EQ(c.name, "lang");
ASSERT_EQ(c.value, "en-US"); ASSERT_EQ(c.value, "en-US");
auto expires = c.expires.getOrElse(FullDate()); auto expires = c.expires.value_or(FullDate());
auto date = expires.date(); auto date = expires.date();
using namespace std::chrono; using namespace std::chrono;
...@@ -61,7 +61,7 @@ TEST(cookie_test, attributes_test) ...@@ -61,7 +61,7 @@ TEST(cookie_test, attributes_test)
parse("lang=en-US; Path=/; Domain=example.com;", [](const Cookie& c) { parse("lang=en-US; Path=/; Domain=example.com;", [](const Cookie& c) {
ASSERT_EQ(c.name, "lang"); ASSERT_EQ(c.name, "lang");
ASSERT_EQ(c.value, "en-US"); ASSERT_EQ(c.value, "en-US");
ASSERT_EQ(c.domain.getOrElse(""), "example.com"); ASSERT_EQ(c.domain.value_or(""), "example.com");
}); });
} }
...@@ -70,7 +70,7 @@ TEST(cookie_test, bool_test) ...@@ -70,7 +70,7 @@ TEST(cookie_test, bool_test)
parse("SID=31d4d96e407aad42; Path=/; Secure", [](const Cookie& c) { parse("SID=31d4d96e407aad42; Path=/; Secure", [](const Cookie& c) {
ASSERT_EQ(c.name, "SID"); ASSERT_EQ(c.name, "SID");
ASSERT_EQ(c.value, "31d4d96e407aad42"); ASSERT_EQ(c.value, "31d4d96e407aad42");
ASSERT_EQ(c.path.getOrElse(""), "/"); ASSERT_EQ(c.path.value_or(""), "/");
ASSERT_TRUE(c.secure); ASSERT_TRUE(c.secure);
ASSERT_FALSE(c.httpOnly); ASSERT_FALSE(c.httpOnly);
}); });
...@@ -78,7 +78,7 @@ TEST(cookie_test, bool_test) ...@@ -78,7 +78,7 @@ TEST(cookie_test, bool_test)
parse("SID=31d4d96e407aad42; Path=/; Secure; HttpOnly", [](const Cookie& c) { parse("SID=31d4d96e407aad42; Path=/; Secure; HttpOnly", [](const Cookie& c) {
ASSERT_EQ(c.name, "SID"); ASSERT_EQ(c.name, "SID");
ASSERT_EQ(c.value, "31d4d96e407aad42"); ASSERT_EQ(c.value, "31d4d96e407aad42");
ASSERT_EQ(c.path.getOrElse(""), "/"); ASSERT_EQ(c.path.value_or(""), "/");
ASSERT_TRUE(c.secure); ASSERT_TRUE(c.secure);
ASSERT_TRUE(c.httpOnly); ASSERT_TRUE(c.httpOnly);
}); });
...@@ -89,7 +89,7 @@ TEST(cookie_test, ext_test) ...@@ -89,7 +89,7 @@ TEST(cookie_test, ext_test)
parse("lang=en-US; Path=/; Scope=Private", [](const Cookie& c) { parse("lang=en-US; Path=/; Scope=Private", [](const Cookie& c) {
ASSERT_EQ(c.name, "lang"); ASSERT_EQ(c.name, "lang");
ASSERT_EQ(c.value, "en-US"); ASSERT_EQ(c.value, "en-US");
ASSERT_EQ(c.path.getOrElse(""), "/"); ASSERT_EQ(c.path.value_or(""), "/");
auto fooIt = c.ext.find("Scope"); auto fooIt = c.ext.find("Scope");
ASSERT_TRUE(fooIt != std::end(c.ext)); ASSERT_TRUE(fooIt != std::end(c.ext));
ASSERT_EQ(fooIt->second, "Private"); ASSERT_EQ(fooIt->second, "Private");
...@@ -99,8 +99,8 @@ TEST(cookie_test, ext_test) ...@@ -99,8 +99,8 @@ TEST(cookie_test, ext_test)
TEST(cookie_test, write_test) TEST(cookie_test, write_test)
{ {
Cookie c1("lang", "fr-FR"); Cookie c1("lang", "fr-FR");
c1.path = Some(std::string("/")); c1.path = std::string("/");
c1.domain = Some(std::string("example.com")); c1.domain = std::string("example.com");
std::ostringstream oss; std::ostringstream oss;
oss << c1; oss << c1;
...@@ -112,8 +112,8 @@ TEST(cookie_test, write_test) ...@@ -112,8 +112,8 @@ TEST(cookie_test, write_test)
FullDate::time_point expires = date::sys_days(date::year { 118 } / 2 / 16) + hours(17); FullDate::time_point expires = date::sys_days(date::year { 118 } / 2 / 16) + hours(17);
c2.path = Some(std::string("/")); c2.path = std::string("/");
c2.expires = Some(FullDate(expires)); c2.expires = FullDate(expires);
oss.str(""); oss.str("");
oss << c2; oss << c2;
......
...@@ -18,7 +18,7 @@ TEST(headers_test, accept) ...@@ -18,7 +18,7 @@ TEST(headers_test, accept)
const auto& mime = media[0]; const auto& mime = media[0];
ASSERT_TRUE(mime == MIME(Audio, Star)); ASSERT_TRUE(mime == MIME(Audio, Star));
ASSERT_TRUE(mime.q().getOrElse(Pistache::Http::Mime::Q(0)) == Pistache::Http::Mime::Q(20)); ASSERT_TRUE(mime.q().value_or(Pistache::Http::Mime::Q(0)) == Pistache::Http::Mime::Q(20));
} }
Pistache::Http::Header::Accept a2; Pistache::Http::Header::Accept a2;
...@@ -35,7 +35,7 @@ TEST(headers_test, accept) ...@@ -35,7 +35,7 @@ TEST(headers_test, accept)
const auto& m3 = media[2]; const auto& m3 = media[2];
ASSERT_TRUE(m3 == MIME(Text, Html)); ASSERT_TRUE(m3 == MIME(Text, Html));
auto level = m3.getParam("level"); auto level = m3.getParam("level");
ASSERT_TRUE(level.getOrElse("") == "1"); ASSERT_TRUE(level.value_or("") == "1");
const auto& m4 = media[3]; const auto& m4 = media[3];
ASSERT_TRUE(m4 == MIME(Star, Star)); ASSERT_TRUE(m4 == MIME(Star, Star));
} }
...@@ -49,13 +49,13 @@ TEST(headers_test, accept) ...@@ -49,13 +49,13 @@ TEST(headers_test, accept)
ASSERT_TRUE(media.size() == 5U); ASSERT_TRUE(media.size() == 5U);
ASSERT_TRUE(media[0] == MIME(Text, Star)); ASSERT_TRUE(media[0] == MIME(Text, Star));
ASSERT_TRUE(media[0].q().getOrElse(Pistache::Http::Mime::Q(0)) == Pistache::Http::Mime::Q(30)); ASSERT_TRUE(media[0].q().value_or(Pistache::Http::Mime::Q(0)) == Pistache::Http::Mime::Q(30));
ASSERT_TRUE(media[1] == MIME(Text, Html)); ASSERT_TRUE(media[1] == MIME(Text, Html));
ASSERT_TRUE(media[2] == MIME(Text, Html)); ASSERT_TRUE(media[2] == MIME(Text, Html));
ASSERT_TRUE(media[3] == MIME(Text, Html)); ASSERT_TRUE(media[3] == MIME(Text, Html));
ASSERT_TRUE(media[4] == MIME(Star, Star)); ASSERT_TRUE(media[4] == MIME(Star, Star));
ASSERT_TRUE(media[4].q().getOrElse(Pistache::Http::Mime::Q(0)) == Pistache::Http::Mime::Q::fromFloat(0.5)); ASSERT_TRUE(media[4].q().value_or(Pistache::Http::Mime::Q(0)) == Pistache::Http::Mime::Q::fromFloat(0.5));
} }
Pistache::Http::Header::Accept a4; Pistache::Http::Header::Accept a4;
...@@ -574,7 +574,7 @@ TEST(headers_test, content_type) ...@@ -574,7 +574,7 @@ TEST(headers_test, content_type)
ASSERT_TRUE("text/html; charset=ISO-8859-4" == oss.str()); ASSERT_TRUE("text/html; charset=ISO-8859-4" == oss.str());
const auto& mime = ct.mime(); const auto& mime = ct.mime();
ASSERT_TRUE(mime == MIME(Text, Html)); ASSERT_TRUE(mime == MIME(Text, Html));
ASSERT_TRUE(mime.getParam("charset").getOrElse("") == "ISO-8859-4"); ASSERT_TRUE(mime.getParam("charset").value_or("") == "ISO-8859-4");
} }
TEST(headers_test, access_control_allow_origin_test) TEST(headers_test, access_control_allow_origin_test)
...@@ -821,10 +821,10 @@ TEST(headers_test, raw_headers_are_case_insensitive) ...@@ -821,10 +821,10 @@ TEST(headers_test, raw_headers_are_case_insensitive)
step.apply(cursor); step.apply(cursor);
// or the header you try and get, it should work: // or the header you try and get, it should work:
ASSERT_FALSE(request.headers().tryGetRaw("Custom-Header").isEmpty()); ASSERT_FALSE(request.headers().tryGetRaw("Custom-Header").has_value());
ASSERT_FALSE(request.headers().tryGetRaw("CUSTOM-HEADER").isEmpty()); ASSERT_FALSE(request.headers().tryGetRaw("CUSTOM-HEADER").has_value());
ASSERT_FALSE(request.headers().tryGetRaw("custom-header").isEmpty()); ASSERT_FALSE(request.headers().tryGetRaw("custom-header").has_value());
ASSERT_FALSE(request.headers().tryGetRaw("CuStOm-HeAdEr").isEmpty()); ASSERT_FALSE(request.headers().tryGetRaw("CuStOm-HeAdEr").has_value());
} }
} }
......
...@@ -489,7 +489,7 @@ TEST(http_client_test, client_sends_query) ...@@ -489,7 +489,7 @@ TEST(http_client_test, client_sends_query)
for (auto entry : results) for (auto entry : results)
{ {
ASSERT_TRUE(query.has(entry.first)); ASSERT_TRUE(query.has(entry.first));
EXPECT_EQ(entry.second, query.get(entry.first).get()); EXPECT_EQ(entry.second, query.get(entry.first).value());
} }
} }
......
...@@ -21,9 +21,9 @@ TEST(mime_test, basic_test) ...@@ -21,9 +21,9 @@ TEST(mime_test, basic_test)
ASSERT_TRUE(m2.toString() == "application/xhtml+xml"); ASSERT_TRUE(m2.toString() == "application/xhtml+xml");
auto m3 = MIME(Text, Plain); auto m3 = MIME(Text, Plain);
ASSERT_TRUE(m3.q().isEmpty()); ASSERT_TRUE(m3.q().has_value());
m3.setQuality(Q::fromFloat(0.7)); m3.setQuality(Q::fromFloat(0.7));
ASSERT_TRUE(m3.q().getOrElse(Q(0)) == Q(70)); ASSERT_TRUE(m3.q().value_or(Q(0)) == Q(70));
ASSERT_TRUE(m3.toString() == "text/plain; q=0.7"); ASSERT_TRUE(m3.toString() == "text/plain; q=0.7");
...@@ -54,28 +54,28 @@ TEST(mime_test, valid_parsing_test) ...@@ -54,28 +54,28 @@ TEST(mime_test, valid_parsing_test)
{ {
parse("application/json", [](const MediaType& m1) { parse("application/json", [](const MediaType& m1) {
ASSERT_TRUE(m1 == MIME(Application, Json)); ASSERT_TRUE(m1 == MIME(Application, Json));
ASSERT_TRUE(m1.q().isEmpty()); ASSERT_TRUE(m1.q().has_value());
}); });
parse("application/xhtml+xml", [](const MediaType& m2) { parse("application/xhtml+xml", [](const MediaType& m2) {
ASSERT_TRUE(m2 == MediaType(Type::Application, Subtype::Xhtml, Suffix::Xml)); ASSERT_TRUE(m2 == MediaType(Type::Application, Subtype::Xhtml, Suffix::Xml));
ASSERT_TRUE(m2.q().isEmpty()); ASSERT_TRUE(m2.q().has_value());
}); });
parse("application/json; q=0.3", [](const MediaType& m3) { parse("application/json; q=0.3", [](const MediaType& m3) {
ASSERT_TRUE(m3 == MIME(Application, Json)); ASSERT_TRUE(m3 == MIME(Application, Json));
ASSERT_TRUE(m3.q().getOrElse(Q(0)) == Q::fromFloat(0.3)); ASSERT_TRUE(m3.q().value_or(Q(0)) == Q::fromFloat(0.3));
}); });
parse("application/xhtml+xml; q=0.7", [](const MediaType& m4) { parse("application/xhtml+xml; q=0.7", [](const MediaType& m4) {
ASSERT_TRUE(m4.top() == Type::Application); ASSERT_TRUE(m4.top() == Type::Application);
ASSERT_TRUE(m4.sub() == Subtype::Xhtml); ASSERT_TRUE(m4.sub() == Subtype::Xhtml);
ASSERT_TRUE(m4.suffix() == Suffix::Xml); ASSERT_TRUE(m4.suffix() == Suffix::Xml);
ASSERT_TRUE(m4.q().getOrElse(Q(0)) == Q(70)); ASSERT_TRUE(m4.q().value_or(Q(0)) == Q(70));
}); });
parse("application/xhtml+xml; q=0.78", [](const MediaType& m5) { parse("application/xhtml+xml; q=0.78", [](const MediaType& m5) {
ASSERT_TRUE(m5.q().getOrElse(Q(0)) == Q(78)); ASSERT_TRUE(m5.q().value_or(Q(0)) == Q(78));
}); });
parse("application/vnd.adobe.flash-movie", [](const MediaType& m6) { parse("application/vnd.adobe.flash-movie", [](const MediaType& m6) {
...@@ -108,15 +108,15 @@ TEST(mime_test, valid_parsing_test) ...@@ -108,15 +108,15 @@ TEST(mime_test, valid_parsing_test)
parse("text/html; charset=ISO-8859-4", [](const MediaType& m10) { parse("text/html; charset=ISO-8859-4", [](const MediaType& m10) {
ASSERT_TRUE(m10 == MIME(Text, Html)); ASSERT_TRUE(m10 == MIME(Text, Html));
ASSERT_TRUE(m10.q().isEmpty()); ASSERT_TRUE(m10.q().has_value());
auto charset = m10.getParam("charset"); auto charset = m10.getParam("charset");
ASSERT_TRUE(charset.getOrElse("") == "ISO-8859-4"); ASSERT_TRUE(charset.value_or("") == "ISO-8859-4");
}); });
parse("text/html; q=0.83; charset=ISO-8859-4", [](const MediaType& m11) { parse("text/html; q=0.83; charset=ISO-8859-4", [](const MediaType& m11) {
ASSERT_TRUE(m11 == MIME(Text, Html)); ASSERT_TRUE(m11 == MIME(Text, Html));
ASSERT_TRUE(m11.q().getOrElse(Q(0)) == Q(83)); ASSERT_TRUE(m11.q().value_or(Q(0)) == Q(83));
ASSERT_TRUE(m11.getParam("charset").getOrElse("") == "ISO-8859-4"); ASSERT_TRUE(m11.getParam("charset").value_or("") == "ISO-8859-4");
}); });
} }
...@@ -150,15 +150,15 @@ TEST(mime_test, should_parse_case_insensitive_issue_179) ...@@ -150,15 +150,15 @@ TEST(mime_test, should_parse_case_insensitive_issue_179)
{ {
parse("Application/Json", [](const Mime::MediaType& mime) { parse("Application/Json", [](const Mime::MediaType& mime) {
ASSERT_TRUE(mime == MIME(Application, Json)); ASSERT_TRUE(mime == MIME(Application, Json));
ASSERT_TRUE(mime.q().isEmpty()); ASSERT_TRUE(mime.q().has_value());
}); });
parse("aPpliCAtion/Xhtml+XML", [](const MediaType& mime) { parse("aPpliCAtion/Xhtml+XML", [](const MediaType& mime) {
ASSERT_TRUE(mime == MediaType(Type::Application, Subtype::Xhtml, Suffix::Xml)); ASSERT_TRUE(mime == MediaType(Type::Application, Subtype::Xhtml, Suffix::Xml));
ASSERT_TRUE(mime.q().isEmpty()); ASSERT_TRUE(mime.q().has_value());
}); });
parse("Application/Xhtml+XML; q=0.78", [](const MediaType& mime) { parse("Application/Xhtml+XML; q=0.78", [](const MediaType& mime) {
ASSERT_TRUE(mime.q().getOrElse(Q(0)) == Q(78)); ASSERT_TRUE(mime.q().value_or(Q(0)) == Q(78));
}); });
} }
#include "gtest/gtest.h"
#include <pistache/optional.h>
using Pistache::Optional;
TEST(optional, constructor)
{
Optional<bool> value(Pistache::Some(true));
ASSERT_FALSE(value.isEmpty());
EXPECT_TRUE(value.get());
}
TEST(optional, copy_constructor)
{
Optional<bool> value(Pistache::Some(true));
ASSERT_FALSE(value.isEmpty());
EXPECT_TRUE(value.get());
Optional<bool> copy_constructed(value);
ASSERT_FALSE(copy_constructed.isEmpty());
EXPECT_TRUE(copy_constructed.get());
}
TEST(optional, copy_assignment_operator)
{
Optional<bool> value(Pistache::Some(true));
ASSERT_FALSE(value.isEmpty());
Optional<bool> other;
EXPECT_TRUE(other.isEmpty());
other = value;
ASSERT_FALSE(other.isEmpty());
EXPECT_TRUE(other.get());
}
TEST(optional, copy_assignment_operator_for_convertible_type)
{
Optional<bool> value;
EXPECT_TRUE(value.isEmpty());
value = Pistache::Some(true);
ASSERT_FALSE(value.isEmpty());
EXPECT_TRUE(value.get());
}
TEST(optional, copy_assignment_operator_for_self_assignment)
{
Optional<bool> value(Pistache::Some(true));
ASSERT_FALSE(value.isEmpty());
EXPECT_TRUE(value.get());
value = value;
ASSERT_FALSE(value.isEmpty());
EXPECT_TRUE(value.get());
}
TEST(optional, move_constructor)
{
Optional<bool> value(Pistache::Some(true));
ASSERT_FALSE(value.isEmpty());
EXPECT_TRUE(value.get());
Optional<bool> value_from_move(std::move(value));
ASSERT_FALSE(value_from_move.isEmpty());
EXPECT_TRUE(value_from_move.get());
}
TEST(optional, move_assignment_operator)
{
Optional<bool> value(Pistache::Some(true));
ASSERT_FALSE(value.isEmpty());
EXPECT_TRUE(value.get());
Optional<bool> move_assigned;
move_assigned = std::move(value);
ASSERT_FALSE(move_assigned.isEmpty());
EXPECT_TRUE(move_assigned.get());
}
TEST(optional, integer)
{
Optional<int32_t> value(Pistache::Some(1));
ASSERT_FALSE(value.isEmpty());
EXPECT_TRUE(value.get());
}
TEST(optional, constructor_none)
{
Optional<bool> value(Pistache::None());
EXPECT_TRUE(value.isEmpty());
}
TEST(optional, copy_constructor_none)
{
Optional<bool> value(Pistache::None());
EXPECT_TRUE(value.isEmpty());
Optional<bool> copy_constructed(value);
EXPECT_TRUE(value.isEmpty());
}
TEST(optional, copy_assignment_operator_none)
{
Optional<bool> value(Pistache::None());
EXPECT_TRUE(value.isEmpty());
Optional<bool> assigned = Pistache::None();
EXPECT_TRUE(assigned.isEmpty());
}
TEST(optional, move_constructor_none)
{
Optional<bool> value(Pistache::None());
EXPECT_TRUE(value.isEmpty());
Optional<bool> move_constructed(std::move(value));
EXPECT_TRUE(move_constructed.isEmpty());
}
TEST(optional, move_assignment_operator_none)
{
Optional<bool> value(Pistache::None());
EXPECT_TRUE(value.isEmpty());
Optional<bool> move_assigned(std::move(value));
EXPECT_TRUE(move_assigned.isEmpty());
}
TEST(optional, integer_none)
{
Optional<int32_t> value(Pistache::None());
EXPECT_TRUE(value.isEmpty());
}
TEST(optional, equal_operator_empty_equalto_empty)
{
Optional<int32_t> value(Pistache::None());
Optional<int32_t> value2(Pistache::None());
EXPECT_EQ(value, value2);
}
TEST(optional, equal_operator_value_equalto_value)
{
Optional<int32_t> value(Pistache::Some(1));
Optional<int32_t> value2(Pistache::Some(1));
EXPECT_EQ(value, value2);
}
TEST(optional, equal_operator_empty_notequalto_value)
{
Optional<int32_t> value(Pistache::None());
Optional<int32_t> value2(Pistache::Some(2));
EXPECT_NE(value, value2);
}
TEST(optional, equal_operator_value_notequalto_value)
{
Optional<int32_t> value(Pistache::Some(1));
Optional<int32_t> value2(Pistache::Some(2));
EXPECT_NE(value, value2);
}
struct not_comparable
{
bool operator==(const not_comparable& other) const = delete;
};
TEST(has_equalto_operator, is_comparable_type)
{
using Pistache::types::has_equalto_operator;
EXPECT_FALSE(has_equalto_operator<not_comparable>::value);
EXPECT_TRUE(has_equalto_operator<int>::value);
EXPECT_TRUE(has_equalto_operator<double>::value);
EXPECT_TRUE(has_equalto_operator<std::string>::value);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment