Merge lp:~michihenning/unity-api/add-ExceptionImplBase into lp:unity-api

Proposed by Michi Henning
Status: Merged
Approved by: Jussi Pakkanen
Approved revision: 57
Merged at revision: 59
Proposed branch: lp:~michihenning/unity-api/add-ExceptionImplBase
Merge into: lp:unity-api
Diff against target: 1556 lines (+578/-612)
14 files modified
include/unity/Exception.h (+13/-21)
include/unity/ExceptionImplBase.h (+65/-0)
include/unity/UnityExceptions.h (+7/-21)
include/unity/internal/ExceptionImpl.h (+0/-60)
include/unity/internal/UnityExceptionsImpl.h (+0/-95)
src/unity/CMakeLists.txt (+1/-0)
src/unity/Exception.cpp (+13/-13)
src/unity/ExceptionImplBase.cpp (+310/-0)
src/unity/UnityExceptions.cpp (+47/-15)
src/unity/internal/CMakeLists.txt (+0/-2)
src/unity/internal/ExceptionImpl.cpp (+0/-244)
src/unity/internal/UnityExceptionsImpl.cpp (+0/-126)
src/unity/util/Daemon.cpp (+7/-0)
test/gtest/unity/Exceptions_test.cpp (+115/-15)
To merge this branch: bzr merge lp:~michihenning/unity-api/add-ExceptionImplBase
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Jussi Pakkanen (community) Approve
Review via email: mp+169337@code.launchpad.net

Commit message

Removed unity::internal::ExceptionImpl and replaced it with unity::ExceptionImplBase.
This allows clients of unity-api to derive their own exceptions for unity::Exception without exposing any implementation details (so the ABI won't break) and still take advantage of implementation inheritance without having to reimplement all the functionality of the base class

Description of the change

Removed unity::internal::ExceptionImpl and replaced it with unity::ExceptionImplBase.
This allows clients of unity-api to derive their own exceptions for unity::Exception without exposing any implementation details (so the ABI won't break) and still take advantage of implementation inheritance without having to reimplement all the functionality of the base class.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

LGTM.

Under what circumstances would clients want to derive our exceptions, though? For their internal use they would probably use their own types. The only reason I can think of if they need to inject exceptions back to us and expect us to act on them in some way. Which seems a bit weird.

review: Approve
Revision history for this message
Michi Henning (michihenning) wrote :

> LGTM.
>
> Under what circumstances would clients want to derive our exceptions, though?

For example, unity-scopes-api is a client of unity-api. I need a MiddlewareException so I can catch a specific group of exceptions from the middleware layer selectively. I want to derive that exception from unity::Exception, so *all* exceptions ultimately are unity::exception or std::exception (which is a base for unity::exception). But that means I have to be able to derive form unity::exception without using the unity::internal namespace. (The previous design made that impossible.)

> For their internal use they would probably use their own types.

Yes, clients are free to do whatever they want with their own exceptions. But it's really nice to be able to say "catch any scope exception" or "catch any Unity API exception" for structured error handling.

And the functionality in unity::exception is kind of neat. Especially the nesting mechanism that preserves the original exception when an exception is re-thrown as something else is nice. It has zero API footprint and does the work quietly behind the scenes.

> The only
> reason I can think of if they need to inject exceptions back to us and expect
> us to act on them in some way. Which seems a bit weird.

There might a few places where we may expect scope to tell us something specific, in which case we can tell the author "you must throw X, if Y happens." But I don't expect there to many such cases, if any.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
57. By Michi Henning

Merged trunk.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michi Henning (michihenning) wrote :

Jenkins is happy with this now. Can someone top-approve please?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/unity/Exception.h'
--- include/unity/Exception.h 2013-06-12 22:07:05 +0000
+++ include/unity/Exception.h 2013-06-17 04:58:28 +0000
@@ -20,6 +20,7 @@
20#define UNITY_EXCEPTION_H20#define UNITY_EXCEPTION_H
2121
22#include <unity/SymbolExport.h>22#include <unity/SymbolExport.h>
23#include <unity/util/NonCopyable.h>
2324
24#include <exception>25#include <exception>
25#include <string>26#include <string>
@@ -28,15 +29,7 @@
28namespace unity29namespace unity
29{30{
3031
31namespace internal32class ExceptionImplBase;
32{
33class ExceptionImpl;
34}
35
36// TODO: It probably would be best to split this into a base and ImplBase, with the derived part in the internal
37// namespace and declaring self(), the constructor, and pimpl(). That's because the Impl for the exception
38// is in the internal namespace, so public API clients can use Exception instances, but they cannot
39// create new derived exceptions because the Impl classes are internal to Unity.
4033
41/**34/**
42\brief Abstract base class for all Unity exceptions.35\brief Abstract base class for all Unity exceptions.
@@ -126,14 +119,6 @@
126 */119 */
127 virtual char const* what() const noexcept = 0;120 virtual char const* what() const noexcept = 0;
128121
129 virtual std::string reason() const;
130
131 virtual std::string to_string(std::string const& indent = " ") const;
132 virtual std::string to_string(int indent_level, std::string const& indent) const;
133
134 std::exception_ptr remember(std::exception_ptr earlier_exception);
135 std::exception_ptr get_earlier() const noexcept;
136
137 /**122 /**
138 \brief Returns a <code>std::exception_ptr</code> to <code>this</code>.123 \brief Returns a <code>std::exception_ptr</code> to <code>this</code>.
139124
@@ -142,15 +127,22 @@
142 */127 */
143 virtual std::exception_ptr self() const = 0;128 virtual std::exception_ptr self() const = 0;
144129
130 std::string reason() const;
131
132 std::string to_string(std::string const& indent = " ") const;
133 std::string to_string(int indent_level, std::string const& indent) const;
134
135 std::exception_ptr remember(std::exception_ptr earlier_exception);
136 std::exception_ptr get_earlier() const noexcept;
137
145protected:138protected:
146 //! @cond139 //! @cond
147 Exception(std::shared_ptr<internal::ExceptionImpl> const& derived);140 Exception(std::shared_ptr<ExceptionImplBase> const& derived);
148 internal::ExceptionImpl* pimpl() const noexcept; // No need to reimplement in derived
149 //! @endcond141 //! @endcond
142 ExceptionImplBase* pimpl() const noexcept;
150143
151private:144private:
152 std::shared_ptr<internal::ExceptionImpl> p_; // shared_ptr instead of unique_ptr because145 std::shared_ptr<ExceptionImplBase> p_; // shared_ptr instead of unique_ptr because exceptions must be copyable
153 // exceptions must be copyable
154};146};
155147
156} // namespace unity148} // namespace unity
157149
=== added file 'include/unity/ExceptionImplBase.h'
--- include/unity/ExceptionImplBase.h 1970-01-01 00:00:00 +0000
+++ include/unity/ExceptionImplBase.h 2013-06-17 04:58:28 +0000
@@ -0,0 +1,65 @@
1/*
2 * Copyright (C) 2013 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Michi Henning <michi.henning@canonical.com>
17 */
18
19#ifndef UNITY_EXCEPTIONIMPLBASE_H
20#define UNITY_EXCEPTIONIMPLBASE_H
21
22#include <unity/SymbolExport.h>
23#include <unity/util/NonCopyable.h>
24
25#include <exception>
26#include <string>
27#include <memory>
28
29namespace unity
30{
31
32namespace internal
33{
34class ExceptionData;
35}
36
37class Exception;
38
39/**
40\brief Implementation base exception class for API clients to derive new pimpl'd exception types from.
41\sa unity::Exception
42*/
43
44class UNITY_API ExceptionImplBase : public util::NonCopyable
45{
46public:
47 explicit ExceptionImplBase(Exception const* owner, std::string const& reason);
48 //! @cond
49 virtual ~ExceptionImplBase() noexcept;
50 //! @endcond
51
52 std::string reason() const;
53
54 std::string to_string(std::nested_exception const* nested, int indent_level, std::string const& indent) const;
55
56 std::exception_ptr set_earlier(std::exception_ptr earlier_exception);
57 std::exception_ptr get_earlier() const noexcept;
58
59private:
60 std::shared_ptr<internal::ExceptionData> p_; // shared_ptr (not unique_ptr) because ExceptionData is incomplete
61};
62
63} // namespace unity
64
65#endif
066
=== modified file 'include/unity/UnityExceptions.h'
--- include/unity/UnityExceptions.h 2013-06-12 22:07:05 +0000
+++ include/unity/UnityExceptions.h 2013-06-17 04:58:28 +0000
@@ -24,11 +24,6 @@
24namespace unity24namespace unity
25{25{
2626
27namespace internal
28{
29class InvalidArgumentExceptionImpl;
30}
31
32/**27/**
33\brief Exception to indicate that an invalid argument was passed to a function, such as passing <code>nullptr</code>28\brief Exception to indicate that an invalid argument was passed to a function, such as passing <code>nullptr</code>
34 when the function expects the argument to be non-null.29 when the function expects the argument to be non-null.
@@ -59,11 +54,6 @@
59 virtual std::exception_ptr self() const override;54 virtual std::exception_ptr self() const override;
60};55};
6156
62namespace internal
63{
64class LogicExceptionImpl;
65}
66
67/**57/**
68\brief Exception to indicate a logic error, such as driving the API incorrectly, such as calling methods58\brief Exception to indicate a logic error, such as driving the API incorrectly, such as calling methods
69 in the wrong worder.59 in the wrong worder.
@@ -94,11 +84,6 @@
94 virtual std::exception_ptr self() const override;84 virtual std::exception_ptr self() const override;
95};85};
9686
97namespace internal
98{
99class ShutdownExceptionImpl;
100}
101
102/**87/**
103\brief Exception to indicate errors during shutdown.88\brief Exception to indicate errors during shutdown.
10489
@@ -174,6 +159,9 @@
174 \return Returns the error number that was passed to the constructor.159 \return Returns the error number that was passed to the constructor.
175 */160 */
176 int error() const noexcept;161 int error() const noexcept;
162
163private:
164 std::shared_ptr<internal::FileExceptionImpl> p_;
177};165};
178166
179namespace internal167namespace internal
@@ -217,13 +205,11 @@
217 \return Returns the error number that was passed to the constructor.205 \return Returns the error number that was passed to the constructor.
218 */206 */
219 int error() const noexcept;207 int error() const noexcept;
208
209private:
210 //std::shared_ptr<internal::SyscallExceptionImpl> p_;
220};211};
221212
222namespace internal
223{
224class ResourceExceptionImpl;
225}
226
227/**213/**
228\brief Exception for miscellaneous errors, such as failure of a third-party library or hitting resource limitations.214\brief Exception for miscellaneous errors, such as failure of a third-party library or hitting resource limitations.
229*/215*/
@@ -235,7 +221,7 @@
235 \brief Constructs the exception.221 \brief Constructs the exception.
236 \param reason Further details about the cause of the exception.222 \param reason Further details about the cause of the exception.
237 */223 */
238 ResourceException(std::string const& reason);224 explicit ResourceException(std::string const& reason);
239 //! @cond225 //! @cond
240 ResourceException(ResourceException const&);226 ResourceException(ResourceException const&);
241 ResourceException& operator=(ResourceException const&);227 ResourceException& operator=(ResourceException const&);
242228
=== removed file 'include/unity/internal/ExceptionImpl.h'
--- include/unity/internal/ExceptionImpl.h 2013-06-12 22:07:05 +0000
+++ include/unity/internal/ExceptionImpl.h 1970-01-01 00:00:00 +0000
@@ -1,60 +0,0 @@
1/*
2 * Copyright (C) 2013 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the Lesser GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Lesser GNU General Public License for more details.
12 *
13 * You should have received a copy of the Lesser GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Michi Henning <michi.henning@canonical.com>
17 */
18
19#ifndef UNITY_INTERNAL_EXCEPTIONIMPL_H
20#define UNITY_INTERNAL_EXCEPTIONIMPL_H
21
22#include <unity/util/NonCopyable.h>
23
24#include <string>
25#include <exception>
26
27namespace unity
28{
29
30class Exception;
31
32namespace internal
33{
34
35class ExceptionImpl : private util::NonCopyable
36{
37public:
38 explicit ExceptionImpl(std::string const& reason);
39
40 virtual char const* what() const noexcept = 0;
41 virtual std::string reason() const;
42 virtual std::string to_string(std::nested_exception const& nested, int indent_level, std::string const& indent) const;
43
44 std::exception_ptr remember(unity::Exception const* env, std::exception_ptr earlier_exception);
45 std::exception_ptr remember(unity::Exception const* env, Exception const& earlier_exception);
46 std::exception_ptr get_earlier() const noexcept;
47
48protected:
49 virtual ~ExceptionImpl() noexcept;
50
51private:
52 std::string const reason_;
53 std::exception_ptr previous_;
54};
55
56} // namespace internal
57
58} // namespace unity
59
60#endif
610
=== removed file 'include/unity/internal/UnityExceptionsImpl.h'
--- include/unity/internal/UnityExceptionsImpl.h 2013-06-12 22:07:05 +0000
+++ include/unity/internal/UnityExceptionsImpl.h 1970-01-01 00:00:00 +0000
@@ -1,95 +0,0 @@
1/*
2 * Copyright (C) 2012 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the Lesser GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Lesser GNU General Public License for more details.
12 *
13 * You should have received a copy of the Lesser GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Michi Henning <michi.henning@canonical.com>
17 */
18
19#ifndef UNITY_INTERNAL_UNITYEXCEPTIONSIMPL_H
20#define UNITY_INTERNAL_UNITYEXCEPTIONSIMPL_H
21
22#include <unity/internal/ExceptionImpl.h>
23
24#include <string>
25#include <exception>
26
27namespace unity
28{
29
30class Exception;
31
32namespace internal
33{
34
35class InvalidArgumentExceptionImpl : public ExceptionImpl
36{
37public:
38 InvalidArgumentExceptionImpl(std::string const& reason);
39
40 virtual char const* what() const noexcept override;
41};
42
43class LogicExceptionImpl : public ExceptionImpl
44{
45public:
46 LogicExceptionImpl(std::string const& reason);
47
48 virtual char const* what() const noexcept override;
49};
50
51class ShutdownExceptionImpl : public ExceptionImpl
52{
53public:
54 ShutdownExceptionImpl(std::string const& reason);
55
56 virtual char const* what() const noexcept override;
57};
58
59class FileExceptionImpl : public ExceptionImpl
60{
61public:
62 FileExceptionImpl(std::string const& reason, int err);
63
64 virtual char const* what() const noexcept override;
65 int error() const noexcept;
66
67private:
68 int errno_;
69};
70
71class SyscallExceptionImpl : public ExceptionImpl
72{
73public:
74 SyscallExceptionImpl(std::string const& reason, int err);
75
76 virtual char const* what() const noexcept override;
77 int error() const noexcept;
78
79private:
80 int const errno_;
81};
82
83class ResourceExceptionImpl : public ExceptionImpl
84{
85public:
86 ResourceExceptionImpl(std::string const& reason);
87
88 virtual char const* what() const noexcept override;
89};
90
91} // namespace internal
92
93} // namespace unity
94
95#endif
960
=== modified file 'src/unity/CMakeLists.txt'
--- src/unity/CMakeLists.txt 2013-05-13 11:39:49 +0000
+++ src/unity/CMakeLists.txt 2013-06-17 04:58:28 +0000
@@ -4,6 +4,7 @@
44
5set(UNITY_SRC5set(UNITY_SRC
6 ${CMAKE_CURRENT_SOURCE_DIR}/Exception.cpp6 ${CMAKE_CURRENT_SOURCE_DIR}/Exception.cpp
7 ${CMAKE_CURRENT_SOURCE_DIR}/ExceptionImplBase.cpp
7 ${CMAKE_CURRENT_SOURCE_DIR}/UnityExceptions.cpp8 ${CMAKE_CURRENT_SOURCE_DIR}/UnityExceptions.cpp
8)9)
910
1011
=== modified file 'src/unity/Exception.cpp'
--- src/unity/Exception.cpp 2013-06-12 22:07:05 +0000
+++ src/unity/Exception.cpp 2013-06-17 04:58:28 +0000
@@ -17,7 +17,7 @@
17 */17 */
1818
19#include <unity/Exception.h>19#include <unity/Exception.h>
20#include <unity/internal/ExceptionImpl.h>20#include <unity/ExceptionImplBase.h>
2121
22using namespace std;22using namespace std;
2323
@@ -27,7 +27,7 @@
27//! @cond27//! @cond
2828
29Exception::29Exception::
30Exception(shared_ptr<internal::ExceptionImpl> const& derived)30Exception(shared_ptr<ExceptionImplBase> const& derived)
31 : p_(derived)31 : p_(derived)
32{32{
33}33}
@@ -59,7 +59,7 @@
59}59}
6060
61/**61/**
62Returns a string describing the exception, including any exceptions that were nested or chained.62\brief Returns a string describing the exception, including any exceptions that were nested or chained.
6363
64Nested exceptions are indented according to their nesting level. If the exception contains chained64Nested exceptions are indented according to their nesting level. If the exception contains chained
65exceptions, these are shown in oldest-to-newest order.65exceptions, these are shown in oldest-to-newest order.
@@ -74,11 +74,11 @@
74Exception::74Exception::
75to_string(std::string const& indent) const75to_string(std::string const& indent) const
76{76{
77 return p_->to_string(*this, 0, indent);77 return p_->to_string(this, 0, indent);
78}78}
7979
80/**80/**
81Returns a string describing the exception, including any exceptions that were nested or chained.81\brief Returns a string describing the exception, including any exceptions that were nested or chained.
8282
83Nested exceptions are indented according to their nesting level. If the exception contains chained83Nested exceptions are indented according to their nesting level. If the exception contains chained
84exceptions, these are shown in oldest-to-newest order.84exceptions, these are shown in oldest-to-newest order.
@@ -97,11 +97,11 @@
97Exception::97Exception::
98to_string(int indent_level, std::string const& indent) const98to_string(int indent_level, std::string const& indent) const
99{99{
100 return p_->to_string(*this, indent_level, indent);100 return p_->to_string(this, indent_level, indent);
101}101}
102102
103/**103/**
104Adds an exception to the exception history chain.104\brief Adds an exception to the exception history chain.
105105
106\param earlier_exception The parameter must be a <code>nullptr</code> or a <code>std::exception_ptr</code>106\param earlier_exception The parameter must be a <code>nullptr</code> or a <code>std::exception_ptr</code>
107to an exception that was remembered earlier. This allows a sequence of exceptions to be remembered without107to an exception that was remembered earlier. This allows a sequence of exceptions to be remembered without
@@ -116,11 +116,11 @@
116Exception::116Exception::
117remember(exception_ptr earlier_exception)117remember(exception_ptr earlier_exception)
118{118{
119 return p_->remember(this, earlier_exception);119 return p_->set_earlier(earlier_exception);
120}120}
121121
122/**122/**
123Returns the previous exception.123\brief Returns the previous exception.
124\return Returns the next-older remembered exception, or <code>nullptr</code>, if none.124\return Returns the next-older remembered exception, or <code>nullptr</code>, if none.
125*/125*/
126126
@@ -131,15 +131,15 @@
131 return p_->get_earlier();131 return p_->get_earlier();
132}132}
133133
134//! @cond134/**
135\brief Returns a pointer to to the implementation instance.
136*/
135137
136internal::ExceptionImpl*138ExceptionImplBase*
137Exception::139Exception::
138pimpl() const noexcept140pimpl() const noexcept
139{141{
140 return p_.get();142 return p_.get();
141}143}
142144
143//! @endcond
144
145} // namespace unity145} // namespace unity
146146
=== added file 'src/unity/ExceptionImplBase.cpp'
--- src/unity/ExceptionImplBase.cpp 1970-01-01 00:00:00 +0000
+++ src/unity/ExceptionImplBase.cpp 2013-06-17 04:58:28 +0000
@@ -0,0 +1,310 @@
1/*
2 * Copyright (C) 2012 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Michi Henning <michi.henning@canonical.com>
17 */
18
19#include <unity/ExceptionImplBase.h>
20#include <unity/Exception.h>
21
22using namespace std;
23
24namespace unity
25{
26
27namespace internal
28{
29
30class ExceptionData
31{
32public:
33 ExceptionData(Exception const* owner, string const& reason)
34 : owner_(owner)
35 , reason_(reason)
36 , earlier_(nullptr)
37 {
38 }
39
40 ExceptionData(ExceptionData const&) = delete;
41 ExceptionData& operator=(ExceptionData const&) = delete;
42
43 Exception const* owner_;
44 string reason_;
45 std::exception_ptr earlier_;
46};
47
48}
49
50/**
51\brief Instantiates an implementation instance for a unity::Exception.
52\param owner This must be set to the `this` pointer of the exception that owns this implementation.
53\param reason Further details about the cause of the exception.
54*/
55
56ExceptionImplBase::
57ExceptionImplBase(Exception const* owner, string const& reason)
58 : p_(make_shared<internal::ExceptionData>(owner, reason))
59{
60}
61
62//! @cond
63
64ExceptionImplBase::
65~ExceptionImplBase() noexcept = default;
66
67namespace
68{
69
70//
71// Return the margin string for the indent level and indent.
72//
73
74string
75get_margin(int indent_level, string const& indent)
76{
77 string margin;
78 for (int i = 0; i < indent_level; ++i)
79 {
80 margin += indent;
81 }
82 return margin;
83}
84
85//
86// Follow the nested exceptions that were rethrown along the call stack, printing them into s.
87//
88
89void
90print_name_and_reason(string& s, nested_exception const* nested)
91{
92 // Add the what() string if this is a std::exception.
93
94 std::exception const* std_exception = dynamic_cast<std::exception const*>(nested);
95 if (std_exception)
96 {
97 s += std_exception->what();
98 }
99
100 // Add the reason if this is a unity::Exception.
101
102 unity::Exception const* unity_exception = dynamic_cast<unity::Exception const*>(nested);
103 if (unity_exception)
104 {
105 string reason = unity_exception->reason();
106 if (!reason.empty())
107 {
108 s += ": " + reason;
109 }
110 }
111
112 // Append info about unknown std::exception and std::nested_exception.
113
114 if (!unity_exception)
115 {
116 if (std_exception)
117 {
118 s += " (derived from std::exception and std::nested_exception)";
119 }
120 else
121 {
122 s += "std::nested_exception";
123 }
124 }
125}
126
127void
128follow_nested(string& s, nested_exception const* nested, int indent_level, std::string const& indent)
129{
130 if (nested->nested_ptr())
131 {
132 string margin = get_margin(indent_level, indent);
133
134 s += ":\n";
135 try
136 {
137 nested->rethrow_nested();
138 }
139 catch (std::nested_exception const& e)
140 {
141 unity::Exception const* ge = dynamic_cast<unity::Exception const*>(&e);
142 if (ge)
143 {
144 s += ge->to_string(indent_level + 1, indent);
145 }
146 else
147 {
148 s += margin + indent;
149 print_name_and_reason(s, &e);
150 follow_nested(s, &e, indent_level + 1, indent);
151 }
152 }
153 catch (std::exception const& e)
154 {
155 s += margin + indent;
156 s += e.what(); // Can show only what() for std::exception.
157 }
158 catch (...)
159 {
160 s += margin + indent;
161 s += "unknown exception"; // Best we can do for an exception whose type we don't know.
162 }
163 }
164}
165
166//
167// Follow the history chain and print each exception in the chain.
168//
169
170void
171follow_history(string& s, int& count, unity::Exception const* e, int indent_level, std::string const& indent)
172{
173 if (!e->get_earlier())
174 {
175 count = 1; // We have reached the oldest exception; set exception generation count and terminate recursion.
176 }
177 else
178 {
179 try
180 {
181 rethrow_exception(e->get_earlier());
182 }
183 catch (unity::Exception const& e)
184 {
185 // Recurse along the chain until we hit the end, then, as we pop back up the levels, we increment the
186 // count and print it as a generation number for the exception information.
187 // A bit like the "kicks" in "Inception", except that the deepest level is level 1...
188
189 follow_history(s, count, &e, indent_level, indent);
190 }
191 ++count;
192 }
193
194 // Show info for this exception.
195
196 s += "\n" + get_margin(indent_level, indent) + "Exception #";
197 s += to_string(count) + ":\n";
198 s += get_margin(indent_level, indent) + indent;
199 print_name_and_reason(s, e);
200 follow_nested(s, e, indent_level + 1, indent);
201}
202
203} // namespace
204
205//! @endcond
206
207/**
208\brief Returns the reason set by the derived class's constructor (empty string if none).
209
210Derived classes should include any other state information, such as the value of data members or
211other relevant detail in the <code>reason</code> string they pass to the protected constructor.
212*/
213
214string
215ExceptionImplBase::
216reason() const
217{
218 return p_->reason_;
219}
220
221/**
222\brief Returns a string describing the exception, including any exceptions that were nested or chained.
223
224Nested exceptions are indented according to their nesting level. If the exception contains chained
225exceptions, these are shown in oldest-to-newest order.
226
227\param nested This must be set to the `this` pointer of the exception that owns this implementation.
228
229\param indent_level This controls the indent level. The value <code>0</code> indicates
230 the outermost level (no indent).
231\param indent This controls the amount of indenting per level. The default indent is four spaces.
232\return The string describing the exception.
233*/
234
235string
236ExceptionImplBase::
237to_string(nested_exception const* nested, int indent_level, string const& indent) const
238{
239 string margin = get_margin(indent_level, indent);
240 string s = margin;
241 s += dynamic_cast<const std::exception*>(nested)->what();
242
243 string r = reason();
244 if (!r.empty())
245 {
246 s += ": " + r;
247 }
248
249 // Check whether there is an exception history and print each exception in the history.
250
251 unity::Exception const* unity_exception(dynamic_cast<unity::Exception const*>(nested));
252 if (unity_exception && unity_exception->get_earlier())
253 {
254 s += "\n" + margin + indent + "Exception history:";
255 try
256 {
257 rethrow_exception(unity_exception->get_earlier());
258 }
259 catch (unity::Exception const& e)
260 {
261 int count;
262 follow_history(s, count, &e, indent_level + 2, indent);
263 }
264 }
265
266 // Print this and any nested exceptions.
267
268 follow_nested(s, nested, indent_level, indent);
269
270 return s;
271}
272
273/**
274\brief Adds an exception to the exception history chain.
275
276\param earlier_exception The parameter must be a <code>nullptr</code> or a <code>std::exception_ptr</code>
277to an exception that was remembered earlier. This allows a sequence of exceptions to be remembered without
278having to throw them and is useful for example, in shutdown scenarios where any one of a sequence of steps
279can fail, but we want to continue and try all the following steps and only throw after all of them have been
280tried. In this case, each step that fails can add itself to the sequence of remembered exceptions, and finally
281throw something like <code>ShutdownException</code>.
282\return A <code>std::exception_ptr</code> to <code>this</code>.
283*/
284
285exception_ptr
286ExceptionImplBase::
287set_earlier(exception_ptr earlier_exception)
288{
289 // Doesn't prevent loops, but protects against accidental self-assignment.
290
291 if (p_->earlier_ != earlier_exception)
292 {
293 p_->earlier_ = earlier_exception;
294 }
295 return p_->owner_->self();
296}
297
298/**
299\brief Returns the previous exception.
300\return Returns the next-older remembered exception, or <code>nullptr</code>, if none.
301*/
302
303exception_ptr
304ExceptionImplBase::
305get_earlier() const noexcept
306{
307 return p_->earlier_;
308}
309
310} // namespace unity
0311
=== modified file 'src/unity/UnityExceptions.cpp'
--- src/unity/UnityExceptions.cpp 2013-06-12 22:07:05 +0000
+++ src/unity/UnityExceptions.cpp 2013-06-17 04:58:28 +0000
@@ -17,7 +17,7 @@
17 */17 */
1818
19#include <unity/UnityExceptions.h>19#include <unity/UnityExceptions.h>
20#include <unity/internal/UnityExceptionsImpl.h>20#include <unity/ExceptionImplBase.h>
2121
22using namespace std;22using namespace std;
2323
@@ -26,7 +26,7 @@
2626
27InvalidArgumentException::27InvalidArgumentException::
28InvalidArgumentException(string const& reason)28InvalidArgumentException(string const& reason)
29 : Exception(make_shared<internal::InvalidArgumentExceptionImpl>(reason))29 : Exception(make_shared<ExceptionImplBase>(this, reason))
30{30{
31}31}
3232
@@ -49,7 +49,7 @@
49InvalidArgumentException::49InvalidArgumentException::
50what() const noexcept50what() const noexcept
51{51{
52 return dynamic_cast<internal::InvalidArgumentExceptionImpl*>(pimpl())->what();52 return "unity::InvalidArgumentException";
53}53}
5454
55exception_ptr55exception_ptr
@@ -61,7 +61,7 @@
6161
62LogicException::62LogicException::
63LogicException(string const& reason)63LogicException(string const& reason)
64 : Exception(make_shared<internal::LogicExceptionImpl>(reason))64 : Exception(make_shared<ExceptionImplBase>(this, reason))
65{65{
66}66}
6767
@@ -83,7 +83,7 @@
83LogicException::83LogicException::
84what() const noexcept84what() const noexcept
85{85{
86 return dynamic_cast<internal::LogicExceptionImpl*>(pimpl())->what();86 return "unity::LogicException";
87}87}
8888
89exception_ptr89exception_ptr
@@ -95,7 +95,7 @@
9595
96ShutdownException::96ShutdownException::
97ShutdownException(string const& reason)97ShutdownException(string const& reason)
98 : Exception(make_shared<internal::ShutdownExceptionImpl>(reason))98 : Exception(make_shared<ExceptionImplBase>(this, reason))
99{99{
100}100}
101101
@@ -117,7 +117,7 @@
117ShutdownException::117ShutdownException::
118what() const noexcept118what() const noexcept
119{119{
120 return dynamic_cast<internal::ShutdownExceptionImpl*>(pimpl())->what();120 return "unity::ShutdownException";
121}121}
122122
123exception_ptr123exception_ptr
@@ -127,9 +127,25 @@
127 return make_exception_ptr(*this);127 return make_exception_ptr(*this);
128}128}
129129
130namespace internal
131{
132
133class FileExceptionImpl : public unity::ExceptionImplBase
134{
135public:
136 FileExceptionImpl(FileException const* owner, string const& reason, int err)
137 : ExceptionImplBase(owner, reason + (err == 0 ? "" : " (errno = " + std::to_string(err) + ")"))
138 , err_(err)
139 {
140 }
141 int err_;
142};
143
144}
145
130FileException::146FileException::
131FileException(string const& reason, int err)147FileException(string const& reason, int err)
132 : Exception(make_shared<internal::FileExceptionImpl>(reason, err))148 : Exception(make_shared<internal::FileExceptionImpl>(this, reason, err))
133{149{
134}150}
135151
@@ -151,14 +167,14 @@
151FileException::167FileException::
152what() const noexcept168what() const noexcept
153{169{
154 return dynamic_cast<internal::FileExceptionImpl*>(pimpl())->what();170 return "unity::FileException";
155}171}
156172
157int173int
158FileException::174FileException::
159error() const noexcept175error() const noexcept
160{176{
161 return dynamic_cast<internal::FileExceptionImpl*>(pimpl())->error();177 return dynamic_cast<const internal::FileExceptionImpl*>(pimpl())->err_;
162}178}
163179
164exception_ptr180exception_ptr
@@ -168,9 +184,25 @@
168 return make_exception_ptr(*this);184 return make_exception_ptr(*this);
169}185}
170186
187namespace internal
188{
189
190class SyscallExceptionImpl : public unity::ExceptionImplBase
191{
192public:
193 SyscallExceptionImpl(SyscallException const* owner, string const& reason, int err)
194 : ExceptionImplBase(owner, reason + (reason.empty() ? "" : " ") + "(errno = " + std::to_string(err) + ")")
195 , err_(err)
196 {
197 }
198 int err_;
199};
200
201}
202
171SyscallException::203SyscallException::
172SyscallException(string const& reason, int err)204SyscallException(string const& reason, int err)
173 : Exception(make_shared<internal::SyscallExceptionImpl>(reason, err))205 : Exception(make_shared<internal::SyscallExceptionImpl>(this, reason, err))
174{206{
175}207}
176208
@@ -192,14 +224,14 @@
192SyscallException::224SyscallException::
193what() const noexcept225what() const noexcept
194{226{
195 return dynamic_cast<internal::SyscallExceptionImpl*>(pimpl())->what();227 return "unity::SyscallException";
196}228}
197229
198int230int
199SyscallException::231SyscallException::
200error() const noexcept232error() const noexcept
201{233{
202 return dynamic_cast<internal::SyscallExceptionImpl*>(pimpl())->error();234 return dynamic_cast<const internal::SyscallExceptionImpl*>(pimpl())->err_;
203}235}
204236
205exception_ptr237exception_ptr
@@ -211,7 +243,7 @@
211243
212ResourceException::244ResourceException::
213ResourceException(string const& reason)245ResourceException(string const& reason)
214 : Exception(make_shared<internal::ResourceExceptionImpl>(reason))246 : Exception(make_shared<ExceptionImplBase>(this, reason))
215{247{
216}248}
217249
@@ -233,7 +265,7 @@
233ResourceException::265ResourceException::
234what() const noexcept266what() const noexcept
235{267{
236 return dynamic_cast<internal::ResourceExceptionImpl*>(pimpl())->what();268 return "unity::ResourceException";
237}269}
238270
239exception_ptr271exception_ptr
240272
=== modified file 'src/unity/internal/CMakeLists.txt'
--- src/unity/internal/CMakeLists.txt 2013-05-13 11:39:49 +0000
+++ src/unity/internal/CMakeLists.txt 2013-06-17 04:58:28 +0000
@@ -1,6 +1,4 @@
1set(UNITY_INTERNAL_SRC1set(UNITY_INTERNAL_SRC
2 ${CMAKE_CURRENT_SOURCE_DIR}/ExceptionImpl.cpp
3 ${CMAKE_CURRENT_SOURCE_DIR}/UnityExceptionsImpl.cpp
4)2)
53
6set(UNITY_API_LIB_SRC ${UNITY_API_LIB_SRC} ${UNITY_INTERNAL_SRC} PARENT_SCOPE)4set(UNITY_API_LIB_SRC ${UNITY_API_LIB_SRC} ${UNITY_INTERNAL_SRC} PARENT_SCOPE)
75
=== removed file 'src/unity/internal/ExceptionImpl.cpp'
--- src/unity/internal/ExceptionImpl.cpp 2013-06-12 22:07:05 +0000
+++ src/unity/internal/ExceptionImpl.cpp 1970-01-01 00:00:00 +0000
@@ -1,244 +0,0 @@
1/*
2 * Copyright (C) 2013 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the Lesser GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Lesser GNU General Public License for more details.
12 *
13 * You should have received a copy of the Lesser GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Michi Henning <michi.henning@canonical.com>
17 */
18
19#include <unity/internal/ExceptionImpl.h>
20#include <unity/Exception.h>
21
22using namespace std;
23
24namespace unity
25{
26
27namespace internal
28{
29
30ExceptionImpl::
31ExceptionImpl(string const& reason)
32 : reason_(reason)
33{
34}
35
36ExceptionImpl::
37~ExceptionImpl() noexcept = default;
38
39string
40ExceptionImpl::
41reason() const
42{
43 return reason_;
44}
45
46namespace
47{
48
49//
50// Return the margin string for the indent level and indent.
51//
52
53string
54get_margin(int indent_level, string const& indent)
55{
56 string margin;
57 for (int i = 0; i < indent_level; ++i)
58 {
59 margin += indent;
60 }
61 return margin;
62}
63
64//
65// Follow the nested exceptions that were rethrown along the call stack, printing them into s.
66//
67
68void
69print_name_and_reason(string& s, nested_exception const& nested)
70{
71 // Add the what() string if this is a std::exception.
72
73 std::exception const* std_exception = dynamic_cast<std::exception const*>(&nested);
74 if (std_exception)
75 {
76 s += std_exception->what();
77 }
78
79 // Add the reason if this is a unity::Exception.
80
81 unity::Exception const* unity_exception = dynamic_cast<unity::Exception const*>(&nested);
82 if (unity_exception)
83 {
84 string reason = unity_exception->reason();
85 if (!reason.empty())
86 {
87 s += ": " + reason;
88 }
89 }
90
91 // Append info about unknown std::exception and std::nested_exception.
92
93 if (!unity_exception)
94 {
95 if (std_exception)
96 {
97 s += " (derived from std::exception and std::nested_exception)";
98 }
99 else
100 {
101 s += "std::nested_exception";
102 }
103 }
104}
105
106void
107follow_nested(string& s, nested_exception const& nested, int indent_level, std::string const& indent)
108{
109 if (nested.nested_ptr())
110 {
111 string margin = get_margin(indent_level, indent);
112
113 s += ":\n";
114 try
115 {
116 nested.rethrow_nested();
117 }
118 catch (std::nested_exception const& e)
119 {
120 unity::Exception const* ge = dynamic_cast<unity::Exception const*>(&e);
121 if (ge)
122 {
123 s += ge->to_string(indent_level + 1, indent);
124 }
125 else
126 {
127 s += margin + indent;
128 print_name_and_reason(s, e);
129 follow_nested(s, e, indent_level + 1, indent);
130 }
131 }
132 catch (std::exception const& e)
133 {
134 s += margin + indent;
135 s += e.what(); // Can show only what() for std::exception.
136 }
137 catch (...)
138 {
139 s += margin + indent;
140 s += "unknown exception"; // Best we can do for an exception whose type we don't know.
141 }
142 }
143}
144
145//
146// Follow the history chain and print each exception in the chain.
147//
148
149void
150follow_history(string& s, int& count, unity::Exception const& e, int indent_level, std::string const& indent)
151{
152 if (!e.get_earlier())
153 {
154 count = 1; // We have reached the oldest exception; set exception generation count and terminate recursion.
155 }
156 else
157 {
158 try
159 {
160 rethrow_exception(e.get_earlier());
161 }
162 catch (unity::Exception const& e)
163 {
164 // Recurse along the chain until we hit the end, then, as we pop back up the levels, we increment the
165 // count and print it as a generation number for the exception information.
166 // A bit like the "kicks" in "Inception", except that the deepest level is level 1...
167
168 follow_history(s, count, e, indent_level, indent);
169 }
170 ++count;
171 }
172
173 // Show info for this exception.
174
175 s += "\n" + get_margin(indent_level, indent) + "Exception #";
176 s += to_string(count) + ":\n";
177 s += get_margin(indent_level, indent) + indent;
178 print_name_and_reason(s, e);
179 follow_nested(s, e, indent_level + 1, indent);
180}
181
182} // namespace
183
184string
185ExceptionImpl::
186to_string(nested_exception const& nested, int indent_level, string const& indent) const
187{
188 string margin = get_margin(indent_level, indent);
189 string s = margin;
190 s += what();
191
192 string r = reason();
193 if (!r.empty())
194 {
195 s += ": " + r;
196 }
197
198 // Check whether there is an exception history and print each exception in the history.
199
200 unity::Exception const* unity_exception(dynamic_cast<unity::Exception const*>(&nested));
201 if (unity_exception && unity_exception->get_earlier())
202 {
203 s += "\n" + margin + indent + "Exception history:";
204 try
205 {
206 rethrow_exception(unity_exception->get_earlier());
207 }
208 catch (unity::Exception const& e)
209 {
210 int count;
211 follow_history(s, count, e, indent_level + 2, indent);
212 }
213 }
214
215 // Print this and any nested exceptions.
216
217 follow_nested(s, nested, indent_level, indent);
218
219 return s;
220}
221
222exception_ptr
223ExceptionImpl::
224remember(Exception const* env, exception_ptr earlier_exception)
225{
226 // Doesn't prevent loops, but protects against accidental self-assignment.
227
228 if (previous_ != earlier_exception)
229 {
230 previous_ = earlier_exception;
231 }
232 return env->self();
233}
234
235exception_ptr
236ExceptionImpl::
237get_earlier() const noexcept
238{
239 return previous_;
240}
241
242} // namespace internal
243
244} // namespace unity
2450
=== removed file 'src/unity/internal/UnityExceptionsImpl.cpp'
--- src/unity/internal/UnityExceptionsImpl.cpp 2013-06-12 22:07:05 +0000
+++ src/unity/internal/UnityExceptionsImpl.cpp 1970-01-01 00:00:00 +0000
@@ -1,126 +0,0 @@
1/*
2 * Copyright (C) 2012 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the Lesser GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Lesser GNU General Public License for more details.
12 *
13 * You should have received a copy of the Lesser GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Michi Henning <michi.henning@canonical.com>
17 */
18
19#include <unity/internal/UnityExceptionsImpl.h>
20
21using namespace std;
22
23namespace unity
24{
25
26namespace internal
27{
28
29InvalidArgumentExceptionImpl::
30InvalidArgumentExceptionImpl(string const& reason)
31 : ExceptionImpl(reason)
32{
33}
34
35char const*
36InvalidArgumentExceptionImpl::
37what() const noexcept
38{
39 return "unity::InvalidArgumentException";
40}
41
42LogicExceptionImpl::
43LogicExceptionImpl(string const& reason)
44 : ExceptionImpl(reason)
45{
46}
47
48char const*
49LogicExceptionImpl::
50what() const noexcept
51{
52 return "unity::LogicException";
53}
54
55ShutdownExceptionImpl::
56ShutdownExceptionImpl(string const& reason)
57 : ExceptionImpl(reason)
58{
59}
60
61char const*
62ShutdownExceptionImpl::
63what() const noexcept
64{
65 return "unity::ShutdownException";
66}
67
68FileExceptionImpl::
69FileExceptionImpl(string const& reason, int err)
70 : ExceptionImpl(reason + (err == 0 ? "" : " (errno = " + std::to_string(err) + ")"))
71 , errno_(err)
72{
73}
74
75char const*
76FileExceptionImpl::
77what() const noexcept
78{
79 return "unity::FileException";
80}
81
82int
83FileExceptionImpl::
84error() const noexcept
85{
86 return errno_;
87}
88
89SyscallExceptionImpl::
90SyscallExceptionImpl(string const& reason, int err)
91 : ExceptionImpl(reason + (reason.empty() ? "" : " ") + "(errno = " + std::to_string(err) + ")")
92 , errno_(err)
93{
94}
95
96char const*
97SyscallExceptionImpl::
98what() const noexcept
99{
100 return "unity::SyscallException";
101}
102
103int
104SyscallExceptionImpl::
105error() const noexcept
106{
107 return errno_;
108}
109
110ResourceExceptionImpl::
111ResourceExceptionImpl(string const& reason)
112 : ExceptionImpl(reason)
113{
114}
115
116char const*
117ResourceExceptionImpl::
118what() const noexcept
119{
120 return "unity::ResourceException";
121}
122
123
124} // namespace internal
125
126} // namespace unity
1270
=== modified file 'src/unity/util/Daemon.cpp'
--- src/unity/util/Daemon.cpp 2013-06-12 22:07:05 +0000
+++ src/unity/util/Daemon.cpp 2013-06-17 04:58:28 +0000
@@ -34,6 +34,11 @@
34 return UPtr(new Daemon());34 return UPtr(new Daemon());
35}35}
3636
37// This is covered by tests, but only when we are not building for coverage.
38// (Closing all file descriptors interferes with the coverage reporting.)
39
40// LCOV_EXCL_START
41
37void42void
38Daemon::43Daemon::
39close_fds() noexcept44close_fds() noexcept
@@ -41,6 +46,8 @@
41 p_->close_fds();46 p_->close_fds();
42}47}
4348
49// LCOV_EXCL_STOP
50
44void51void
45Daemon::52Daemon::
46reset_signals() noexcept53reset_signals() noexcept
4754
=== modified file 'test/gtest/unity/Exceptions_test.cpp'
--- test/gtest/unity/Exceptions_test.cpp 2013-06-12 22:07:05 +0000
+++ test/gtest/unity/Exceptions_test.cpp 2013-06-17 04:58:28 +0000
@@ -17,7 +17,7 @@
17 */17 */
1818
19#include <unity/UnityExceptions.h>19#include <unity/UnityExceptions.h>
20#include <unity/internal/UnityExceptionsImpl.h>20#include <unity/ExceptionImplBase.h>
2121
22#include <gtest/gtest.h>22#include <gtest/gtest.h>
2323
@@ -47,6 +47,15 @@
47 EXPECT_EQ("unity::SyscallException: blah (errno = 0)", e3.to_string(0, " "));47 EXPECT_EQ("unity::SyscallException: blah (errno = 0)", e3.to_string(0, " "));
48 EXPECT_EQ(" unity::SyscallException: blah (errno = 0)", e3.to_string(1, " "));48 EXPECT_EQ(" unity::SyscallException: blah (errno = 0)", e3.to_string(1, " "));
49 EXPECT_EQ(" unity::SyscallException: blah (errno = 0)", e3.to_string(2, " "));49 EXPECT_EQ(" unity::SyscallException: blah (errno = 0)", e3.to_string(2, " "));
50
51 try
52 {
53 throw e;
54 }
55 catch (Exception& e)
56 {
57 EXPECT_STREQ("unity::SyscallException", e.what());
58 }
50}59}
5160
52TEST(Exception, empty_reason)61TEST(Exception, empty_reason)
@@ -250,19 +259,9 @@
250 exception_ptr ep = make_exception_ptr(e);259 exception_ptr ep = make_exception_ptr(e);
251260
252 InvalidArgumentException e2("");261 InvalidArgumentException e2("");
253 exception_ptr ep2 = e2.remember(ep);262 e2.remember(ep);
254 EXPECT_EQ(e2.get_earlier(), ep);263 EXPECT_EQ(e2.get_earlier(), ep);
255 }264 }
256
257 {
258 InvalidArgumentException e("");
259 exception_ptr ep = make_exception_ptr(e);
260
261 InvalidArgumentException e2("");
262 exception_ptr ep2 = e2.remember(ep);
263 EXPECT_EQ(e2.get_earlier(), ep);
264 }
265
266265
267 // Check that we are following the history chain.266 // Check that we are following the history chain.
268267
@@ -297,7 +296,6 @@
297 }296 }
298 }297 }
299298
300
301 // Same test, but this time with nested exceptions in the history.299 // Same test, but this time with nested exceptions in the history.
302300
303 {301 {
@@ -534,3 +532,105 @@
534 delete ep;532 delete ep;
535 }533 }
536}534}
535
536class StatelessException : public unity::Exception
537{
538public:
539 explicit StatelessException(std::string const& reason)
540 : Exception(make_shared<ExceptionImplBase>(this, reason))
541 {
542 }
543 explicit StatelessException(std::shared_ptr<ExceptionImplBase> const& derived)
544 : Exception(derived)
545 {
546 }
547 StatelessException(StatelessException const&) = default;
548 StatelessException& operator=(StatelessException const&) = default;
549 virtual ~StatelessException() noexcept {}
550
551 virtual char const* what() const noexcept override
552 {
553 return "StatelessException";
554 }
555
556 virtual std::exception_ptr self() const override
557 {
558 return make_exception_ptr(*this);
559 }
560
561};
562
563TEST(Derivation, stateless_derivation)
564{
565 StatelessException e("test");
566 EXPECT_EQ("test", e.reason());
567 EXPECT_STREQ("StatelessException", e.what());
568}
569
570namespace Impl
571{
572class StatefulExceptionImpl;
573}
574
575class StatefulException : public unity::Exception
576{
577public:
578 StatefulException(std::string const& reason, int state);
579 StatefulException(std::shared_ptr<ExceptionImplBase> const& derived)
580 : Exception(derived)
581 {
582 }
583 StatefulException(StatefulException const&) = default;
584 StatefulException& operator=(StatefulException const&) = default;
585 virtual ~StatefulException() noexcept {}
586
587 virtual char const* what() const noexcept override
588 {
589 return "StatefulException";
590 }
591
592 virtual std::exception_ptr self() const override
593 {
594 return make_exception_ptr(*this);
595 }
596
597};
598
599namespace Impl
600{
601
602class StatefulExceptionImpl : public unity::ExceptionImplBase
603{
604public:
605 StatefulExceptionImpl(StatefulException const* owner, string const& reason, int state)
606 : ExceptionImplBase(owner, reason + " state = " + std::to_string(state))
607 , state_(state)
608 {
609 }
610 int state_;
611};
612
613}
614
615StatefulException::
616StatefulException(std::string const& reason, int state)
617 : Exception(make_shared<Impl::StatefulExceptionImpl>(this, reason, state))
618{
619}
620
621TEST(Derivation, stateful_derivation)
622{
623 StatefulException e("test", 99);
624 EXPECT_EQ("test state = 99", e.reason());
625 EXPECT_STREQ("StatefulException", e.what());
626}
627
628#if 0
629
630TEST(Derivation, two_level_derivation)
631{
632 StatefulException e("test", 99);
633 EXPECT_EQ("test state = 99", e.reason());
634 EXPECT_STREQ("StatefulException", e.what());
635}
636#endif

Subscribers

People subscribed via source and target branches

to all changes: