tests and changes for final_act

This commit is contained in:
Jonathan Coe 2015-09-19 22:34:06 +01:00
parent 652d886963
commit b8af699165
3 changed files with 170 additions and 14 deletions

View File

@ -40,25 +40,97 @@ using std::shared_ptr;
//
// Final_act allows you to ensure something gets run at the end of a scope
template <class F>
class Final_act
template <typename F_t>
class Final_act_noexcept
{
public:
explicit Final_act(F f) : f_(f) {}
Final_act(const Final_act&& other) : f_(other.f_) {}
Final_act(const Final_act&) = delete;
Final_act& operator=(const Final_act&) = delete;
~Final_act() { f_(); }
F_t f;
bool run;
private:
F f_;
public:
explicit Final_act_noexcept(F_t f_) : f(f_), run(true) { }
~Final_act_noexcept()
{
if (!run) return;
f();
}
Final_act_noexcept(const Final_act_noexcept& s) = delete;
Final_act_noexcept(Final_act_noexcept&& s)
: f(std::move(s.f)), run(s.run)
{ s.run = false; }
Final_act_noexcept& operator=(const Final_act_noexcept& s) = delete;
Final_act_noexcept& operator=(Final_act_noexcept&& s)
{
f = std::move(s.f);
run = s.run;
s.run = false;
return *this;
}
void release() { run = false; }
};
// Final_act allows you to ensure something gets run at the end of a scope
template <typename F_t>
class Final_act
{
F_t f;
bool run;
public:
explicit Final_act(F_t f_) : f(f_), run(true) { }
~Final_act()
{
if (!run)
return;
try { f(); }
catch (...) { }
}
Final_act(const Final_act& s) = delete;
Final_act(Final_act&& s) : f(std::move(s.f)), run(s.run)
{
s.run = false;
}
Final_act& operator=(const Final_act& s) = delete;
Final_act& operator=(Final_act&& s)
{
f = std::move(s.f);
run = s.run;
s.run = false;
return *this;
}
void release() { run = false; }
};
template <bool b, typename T, typename U>
struct if_type_else_type { };
template <typename T, typename U>
struct if_type_else_type<true, T, U> { typedef T type; };
template <typename T, typename U>
struct if_type_else_type<false, T, U> { typedef U type; };
template <bool b, typename T, typename U>
using if_type_else_type_t = typename if_type_else_type<b, T, U>::type;
// finally() - convenience function to generate a Final_act
template <class F>
Final_act<F> finally(F f) { return Final_act<F>(f); }
template <typename F_t, typename Final_act_t = if_type_else_type_t<
noexcept(std::declval<F_t&>()()),
Final_act_noexcept<F_t>, Final_act<F_t>>>
auto finally(F_t f) {
return Final_act_t(std::move(f));
}
// narrow_cast(): a searchable way to do narrowing casts of values
template<class T, class U>

View File

@ -87,6 +87,20 @@ add_test(
COMMAND bounds_tests
)
add_executable(final_act_tests
final_act_tests.cpp
)
target_link_libraries(final_act_tests
UnitTest++
)
install(TARGETS final_act_tests
RUNTIME DESTINATION bin
)
add_test(
NAME final_act_tests
COMMAND final_act_tests
)
add_executable(maybenull_tests
maybenull_tests.cpp
)

70
tests/final_act_tests.cpp Normal file
View File

@ -0,0 +1,70 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#include <UnitTest++/UnitTest++.h>
#include <gsl.h>
#include <exception>
using namespace std;
using namespace Guide;
struct Increment {
int* i_;
Increment(int& i) : i_(&i) {}
void operator()() const noexcept { ++*i_; }
};
struct ThrowOnInvocation {
class Exception : public exception {};
void operator()() const { throw Exception(); }
};
SUITE(finallyTests) {
TEST(SingleInvocationOnConvenienceConstruction) {
int i = 0;
{ auto f = finally(Increment(i)); }
CHECK(i == 1);
}
TEST(SingleInvocationOnMoveConstruction) {
int i = 0;
{
auto f = Final_act<Increment>(Increment(i));
auto ff(move(f));
}
CHECK(i == 1);
}
TEST(NoexceptFinalActIsCreated) {
int i = 0;
auto f = finally(Increment(i));
CHECK((is_same<decltype(f), Final_act_noexcept<Increment>>::value));
}
TEST(FinalActDoesNotThrow) {
bool exceptionCaught = false;
try {
finally(ThrowOnInvocation());
} catch (...) {
exceptionCaught = true;
}
CHECK(!exceptionCaught);
}
}
int main(int, const char* []) { return UnitTest::RunAllTests(); }