1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // See bugs.llvm.org/PR20183
10 //
11 // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11}}
12 
13 // UNSUPPORTED: libcpp-has-no-random-device
14 
15 // <random>
16 
17 // class random_device;
18 
19 // explicit random_device(const string& token = implementation-defined); // before C++20
20 // random_device() : random_device(implementation-defined) {}            // C++20
21 // explicit random_device(const string& token);                          // C++20
22 
23 // For the following ctors, the standard states: "The semantics and default
24 // value of the token parameter are implementation-defined". Implementations
25 // therefore aren't required to accept any string, but the default shouldn't
26 // throw.
27 
28 #include <random>
29 #include <system_error>
30 #include <cassert>
31 
32 #if !defined(_WIN32)
33 #include <unistd.h>
34 #endif
35 
36 #include "test_macros.h"
37 #if TEST_STD_VER >= 11
38 #include "test_convertible.h"
39 #endif
40 
41 bool is_valid_random_device(const std::string &token) {
42 #if defined(_LIBCPP_USING_DEV_RANDOM)
43   // Not an exhaustive list: they're the only tokens that are tested below.
44   return token == "/dev/urandom" || token == "/dev/random";
45 #else
46   return token == "/dev/urandom";
47 #endif
48 }
49 
50 void check_random_device_valid(const std::string &token) {
51   std::random_device r(token);
52 }
53 
54 void check_random_device_invalid(const std::string &token) {
55 #ifndef TEST_HAS_NO_EXCEPTIONS
56   try {
57     std::random_device r(token);
58     LIBCPP_ASSERT(false);
59   } catch (const std::system_error&) {
60   }
61 #else
62   ((void)token);
63 #endif
64 }
65 
66 int main(int, char**) {
67   {
68     std::random_device r;
69   }
70   {
71     std::string token = "wrong file";
72     check_random_device_invalid(token);
73   }
74   {
75     std::string token = "/dev/urandom";
76     if (is_valid_random_device(token))
77       check_random_device_valid(token);
78     else
79       check_random_device_invalid(token);
80   }
81   {
82     std::string token = "/dev/random";
83     if (is_valid_random_device(token))
84       check_random_device_valid(token);
85     else
86       check_random_device_invalid(token);
87   }
88 #if !defined(_WIN32)
89 // Test that random_device(const string&) properly handles getting
90 // a file descriptor with the value '0'. Do this by closing the standard
91 // streams so that the descriptor '0' is available.
92   {
93     int ec;
94     ec = close(STDIN_FILENO);
95     assert(!ec);
96     ec = close(STDOUT_FILENO);
97     assert(!ec);
98     ec = close(STDERR_FILENO);
99     assert(!ec);
100     std::random_device r;
101   }
102 #endif // !defined(_WIN32)
103 
104 #if TEST_STD_VER >= 11
105   static_assert(test_convertible<std::random_device>(), "");
106 #endif
107 
108   return 0;
109 }
110