1d6698386SAlex Brachet //===-- Unittests for atexit ----------------------------------------------===//
2d6698386SAlex Brachet //
3d6698386SAlex Brachet // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d6698386SAlex Brachet // See https://llvm.org/LICENSE.txt for license information.
5d6698386SAlex Brachet // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d6698386SAlex Brachet //
7d6698386SAlex Brachet //===----------------------------------------------------------------------===//
8d6698386SAlex Brachet 
9d6698386SAlex Brachet #include "src/__support/CPP/Array.h"
10d6698386SAlex Brachet #include "src/__support/CPP/Utility.h"
11d6698386SAlex Brachet #include "src/stdlib/atexit.h"
12d6698386SAlex Brachet #include "src/stdlib/exit.h"
13d6698386SAlex Brachet #include "utils/UnitTest/Test.h"
14d6698386SAlex Brachet 
15d6698386SAlex Brachet static int a;
TEST(LlvmLibcAtExit,Basic)16d6698386SAlex Brachet TEST(LlvmLibcAtExit, Basic) {
17d6698386SAlex Brachet   // In case tests ever run multiple times.
18d6698386SAlex Brachet   a = 0;
19d6698386SAlex Brachet 
20d6698386SAlex Brachet   auto test = [] {
21d6698386SAlex Brachet     int status = __llvm_libc::atexit(+[] {
22d6698386SAlex Brachet       if (a != 1)
23d6698386SAlex Brachet         __builtin_trap();
24d6698386SAlex Brachet     });
25d6698386SAlex Brachet     status |= __llvm_libc::atexit(+[] { a++; });
26d6698386SAlex Brachet     if (status)
27d6698386SAlex Brachet       __builtin_trap();
28d6698386SAlex Brachet 
29d6698386SAlex Brachet     __llvm_libc::exit(0);
30d6698386SAlex Brachet   };
31d6698386SAlex Brachet   EXPECT_EXITS(test, 0);
32d6698386SAlex Brachet }
33d6698386SAlex Brachet 
TEST(LlvmLibcAtExit,AtExitCallsSysExit)34d6698386SAlex Brachet TEST(LlvmLibcAtExit, AtExitCallsSysExit) {
35d6698386SAlex Brachet   auto test = [] {
36d6698386SAlex Brachet     __llvm_libc::atexit(+[] { _Exit(1); });
37d6698386SAlex Brachet     __llvm_libc::exit(0);
38d6698386SAlex Brachet   };
39d6698386SAlex Brachet   EXPECT_EXITS(test, 1);
40d6698386SAlex Brachet }
41d6698386SAlex Brachet 
42d6698386SAlex Brachet static int size;
43d6698386SAlex Brachet static __llvm_libc::cpp::Array<int, 256> arr;
44d6698386SAlex Brachet 
45d6698386SAlex Brachet template <int... Ts>
register_atexit_handlers(__llvm_libc::cpp::IntegerSequence<int,Ts...>)46d6698386SAlex Brachet void register_atexit_handlers(__llvm_libc::cpp::IntegerSequence<int, Ts...>) {
47d6698386SAlex Brachet   (__llvm_libc::atexit(+[] { arr[size++] = Ts; }), ...);
48d6698386SAlex Brachet }
49d6698386SAlex Brachet 
getTest()50d6698386SAlex Brachet template <int count> constexpr auto getTest() {
51d6698386SAlex Brachet   return [] {
52d6698386SAlex Brachet     __llvm_libc::atexit(+[] {
53d6698386SAlex Brachet       if (size != count)
54d6698386SAlex Brachet         __builtin_trap();
55d6698386SAlex Brachet       for (int i = 0; i < count; i++)
56d6698386SAlex Brachet         if (arr[i] != count - 1 - i)
57d6698386SAlex Brachet           __builtin_trap();
58d6698386SAlex Brachet     });
59d6698386SAlex Brachet     register_atexit_handlers(
60d6698386SAlex Brachet         __llvm_libc::cpp::MakeIntegerSequence<int, count>{});
61d6698386SAlex Brachet     __llvm_libc::exit(0);
62d6698386SAlex Brachet   };
63d6698386SAlex Brachet }
64d6698386SAlex Brachet 
TEST(LlvmLibcAtExit,ReverseOrder)65d6698386SAlex Brachet TEST(LlvmLibcAtExit, ReverseOrder) {
66d6698386SAlex Brachet   // In case tests ever run multiple times.
67d6698386SAlex Brachet   size = 0;
68d6698386SAlex Brachet 
69d6698386SAlex Brachet   auto test = getTest<32>();
70d6698386SAlex Brachet   EXPECT_EXITS(test, 0);
71d6698386SAlex Brachet }
72d6698386SAlex Brachet 
TEST(LlvmLibcAtExit,Many)73d6698386SAlex Brachet TEST(LlvmLibcAtExit, Many) {
74d6698386SAlex Brachet   // In case tests ever run multiple times.
75d6698386SAlex Brachet   size = 0;
76d6698386SAlex Brachet 
77d6698386SAlex Brachet   auto test = getTest<256>();
78d6698386SAlex Brachet   EXPECT_EXITS(test, 0);
79d6698386SAlex Brachet }
80d6698386SAlex Brachet 
TEST(LlvmLibcAtExit,HandlerCallsAtExit)81d6698386SAlex Brachet TEST(LlvmLibcAtExit, HandlerCallsAtExit) {
82d6698386SAlex Brachet   auto test = [] {
83d6698386SAlex Brachet     __llvm_libc::atexit(+[] {
84*ae4b59f1SAlex Brachet       __llvm_libc::atexit(+[] { __llvm_libc::exit(1); });
85d6698386SAlex Brachet     });
86*ae4b59f1SAlex Brachet     __llvm_libc::exit(0);
87d6698386SAlex Brachet   };
88*ae4b59f1SAlex Brachet   EXPECT_EXITS(test, 1);
89d6698386SAlex Brachet }
90