1/*
2 * Copyright 2013-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <folly/Exception.h>
18
19#include <folly/experimental/TestUtil.h>
20#include <folly/portability/GTest.h>
21
22#include <cstdio>
23#include <memory>
24
25namespace folly {
26namespace test {
27
28#define EXPECT_SYSTEM_ERROR(statement, err, msg) \
29 try { \
30 statement; \
31 ADD_FAILURE() << "Didn't throw"; \
32 } catch (const std::system_error& e) { \
33 std::system_error expected(err, std::system_category(), msg); \
34 EXPECT_STREQ(expected.what(), e.what()); \
35 } catch (...) { \
36 ADD_FAILURE() << "Threw a different type"; \
37 }
38
39TEST(ExceptionTest, Simple) {
40 // Make sure errno isn't used when we don't want it to, set it to something
41 // else than what we set when we call Explicit functions
42 errno = ERANGE;
43 EXPECT_SYSTEM_ERROR(throwSystemErrorExplicit(EIO, "hello"), EIO, "hello");
44 errno = ERANGE;
45 EXPECT_SYSTEM_ERROR(
46 throwSystemErrorExplicit(EIO, "hello", " world"), EIO, "hello world");
47 errno = ERANGE;
48 EXPECT_SYSTEM_ERROR(
49 throwSystemError("hello", " world"), ERANGE, "hello world");
50
51 EXPECT_NO_THROW(checkPosixError(0, "hello", " world"));
52 errno = ERANGE;
53 EXPECT_SYSTEM_ERROR(
54 checkPosixError(EIO, "hello", " world"), EIO, "hello world");
55
56 EXPECT_NO_THROW(checkKernelError(0, "hello", " world"));
57 EXPECT_NO_THROW(checkKernelError(EIO, "hello", " world"));
58 errno = ERANGE;
59 EXPECT_SYSTEM_ERROR(
60 checkKernelError(-EIO, "hello", " world"), EIO, "hello world");
61
62 EXPECT_NO_THROW(checkUnixError(0, "hello", " world"));
63 EXPECT_NO_THROW(checkUnixError(1, "hello", " world"));
64 errno = ERANGE;
65 EXPECT_SYSTEM_ERROR(
66 checkUnixError(-1, "hello", " world"), ERANGE, "hello world");
67
68 EXPECT_NO_THROW(checkUnixErrorExplicit(0, EIO, "hello", " world"));
69 EXPECT_NO_THROW(checkUnixErrorExplicit(1, EIO, "hello", " world"));
70 errno = ERANGE;
71 EXPECT_SYSTEM_ERROR(
72 checkUnixErrorExplicit(-1, EIO, "hello", " world"), EIO, "hello world");
73
74 TemporaryDirectory tmpdir;
75 auto exnpath = tmpdir.path() / "ExceptionTest";
76 auto fp = fopen(exnpath.string().c_str(), "w+b");
77 ASSERT_TRUE(fp != nullptr);
78 SCOPE_EXIT {
79 fclose(fp);
80 };
81
82 EXPECT_NO_THROW(checkFopenError(fp, "hello", " world"));
83 errno = ERANGE;
84 EXPECT_SYSTEM_ERROR(
85 checkFopenError(nullptr, "hello", " world"), ERANGE, "hello world");
86
87 EXPECT_NO_THROW(checkFopenErrorExplicit(fp, EIO, "hello", " world"));
88 errno = ERANGE;
89 EXPECT_SYSTEM_ERROR(
90 checkFopenErrorExplicit(nullptr, EIO, "hello", " world"),
91 EIO,
92 "hello world");
93}
94
95TEST(ExceptionTest, makeSystemError) {
96 errno = ENOENT;
97 auto ex = makeSystemErrorExplicit(EDEADLK, "stuck");
98 EXPECT_EQ(EDEADLK, ex.code().value());
99 EXPECT_EQ(std::system_category(), ex.code().category());
100 EXPECT_TRUE(StringPiece{ex.what()}.contains("stuck"))
101 << "what() string missing input message: " << ex.what();
102
103 ex = makeSystemErrorExplicit(EDOM, 300, " is bigger than max=", 255);
104 EXPECT_EQ(EDOM, ex.code().value());
105 EXPECT_EQ(std::system_category(), ex.code().category());
106 EXPECT_TRUE(StringPiece{ex.what()}.contains("300 is bigger than max=255"))
107 << "what() string missing input message: " << ex.what();
108
109 errno = EINVAL;
110 ex = makeSystemError("bad argument ", 1234, ": bogus");
111 EXPECT_EQ(EINVAL, ex.code().value());
112 EXPECT_EQ(std::system_category(), ex.code().category());
113 EXPECT_TRUE(StringPiece{ex.what()}.contains("bad argument 1234: bogus"))
114 << "what() string missing input message: " << ex.what();
115
116 errno = 0;
117 ex = makeSystemError("unexpected success");
118 EXPECT_EQ(0, ex.code().value());
119 EXPECT_EQ(std::system_category(), ex.code().category());
120 EXPECT_TRUE(StringPiece{ex.what()}.contains("unexpected success"))
121 << "what() string missing input message: " << ex.what();
122}
123
124} // namespace test
125} // namespace folly
126