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