File: TestPushFinalizeHook.cpp

package info (click to toggle)
kokkos 4.7.01-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 16,636 kB
  • sloc: cpp: 223,676; sh: 2,446; makefile: 2,437; python: 91; fortran: 4; ansic: 2
file content (114 lines) | stat: -rw-r--r-- 3,730 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//@HEADER
// ************************************************************************
//
//                        Kokkos v. 4.0
//       Copyright (2022) National Technology & Engineering
//               Solutions of Sandia, LLC (NTESS).
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
// See https://kokkos.org/LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//@HEADER

#include <Kokkos_Core.hpp>

#include <gtest/gtest.h>

#include <cstdlib>
#include <exception>
#include <iostream>
#include <string>

#include "KokkosExecutionEnvironmentNeverInitializedFixture.hpp"

namespace {

using PushFinalizeHook_DeathTest = KokkosExecutionEnvironmentNeverInitialized;

// Output for the finalize hooks.  Use this to make sure that all the hooks
// ran, and that they ran in the correct order.
std::ostringstream hookOutput;

const char hook1str[] = "Behold, I am Hook 1; first pushed, last to be called.";
const char hook2str[] = "Yea verily, I am Hook 2.";
const char hook3str[] = "Indeed, I am Hook 3.";
const char hook4str[] = "Last but not least, I am Hook 4.";

// Don't just have all the hooks print the same thing except for a number.
// Have them print different things, so we can detect interleaving.  The hooks
// need to run sequentially, in LIFO order.  Also, make sure that the function
// accepts at least the following kinds of hooks:
//
// 1. A plain old function that takes no arguments and returns nothing.
// 2. Lambda, that can be assigned to std::function<void()>
// 3. An actual std::function<void()>
// 4. A named object with operator().  This is what C++ programmers
//    unfortunately like to call "functor," even though this word means
//    something different in other languages.

void hook1() { hookOutput << hook1str << '\n'; }

struct Hook4 {
  void operator()() const { hookOutput << hook4str << '\n'; }
};

TEST_F(PushFinalizeHook_DeathTest, called_in_reverse_order) {
  ::testing::FLAGS_gtest_death_test_style = "threadsafe";

  std::string const expectedOutput([] {
    std::ostringstream os;
    os << hook4str << '\n'
       << hook3str << '\n'
       << hook2str << '\n'
       << hook1str << '\n';
    return os.str();
  }());

  EXPECT_EXIT(
      {
        Kokkos::push_finalize_hook(hook1);  // plain old function
        Kokkos::push_finalize_hook(
            [] { hookOutput << hook2str << '\n'; });  // lambda
        Kokkos::initialize();
        std::function<void()> hook3 = [] { hookOutput << hook3str << '\n'; };
        Kokkos::push_finalize_hook(hook3);  // actual std::function
        Hook4 hook4;
        Kokkos::push_finalize_hook(hook4);  // function object instance

        Kokkos::finalize();
        std::exit(hookOutput.str() == expectedOutput ? EXIT_SUCCESS
                                                     : EXIT_FAILURE);
      },
      ::testing::ExitedWithCode(EXIT_SUCCESS), "");
}

char const my_terminate_handler_msg[] = "my terminate handler was called\n";
[[noreturn]] void my_terminate_handler() {
  std::cerr << my_terminate_handler_msg;
  std::abort();
}

TEST_F(PushFinalizeHook_DeathTest, terminate_on_throw) {
  ::testing::FLAGS_gtest_death_test_style = "threadsafe";

  auto terminate_handler = std::get_terminate();

  std::set_terminate(my_terminate_handler);

  EXPECT_DEATH(
      {
        Kokkos::push_finalize_hook(
            [] { throw std::runtime_error("uncaught exception"); });
        Kokkos::initialize();
        Kokkos::finalize();
      },
      my_terminate_handler_msg);

  std::set_terminate(terminate_handler);
}

}  // namespace