1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <fbl/unique_fd.h>
6
7#include <fbl/algorithm.h>
8#include <fbl/type_support.h>
9#include <unittest/unittest.h>
10
11namespace {
12
13bool invalid_fd_test() {
14    BEGIN_TEST;
15
16    {
17        fbl::unique_fd fd;
18
19        EXPECT_EQ(fd.get(), fbl::unique_fd::InvalidValue());
20        EXPECT_EQ(fbl::unique_fd::InvalidValue(), fd.get());
21
22        EXPECT_EQ(static_cast<int>(fd), fbl::unique_fd::InvalidValue());
23        EXPECT_EQ(fbl::unique_fd::InvalidValue(), static_cast<int>(fd));
24
25        EXPECT_EQ(false, fd.is_valid());
26        EXPECT_EQ(static_cast<bool>(fd), false);
27        EXPECT_EQ(false, static_cast<bool>(fd));
28
29        EXPECT_FALSE(fd);
30    }
31
32    END_TEST;
33}
34
35bool valid_comparison_test() {
36    BEGIN_TEST;
37
38    int pipes[2];
39    EXPECT_EQ(pipe(pipes), 0);
40    {
41        fbl::unique_fd in(pipes[1]);
42        fbl::unique_fd out(pipes[0]);
43
44        EXPECT_NE(in.get(), fbl::unique_fd::InvalidValue());
45        EXPECT_NE(out.get(), fbl::unique_fd::InvalidValue());
46        EXPECT_NE(fbl::unique_fd::InvalidValue(), in.get());
47        EXPECT_NE(fbl::unique_fd::InvalidValue(), out.get());
48
49        EXPECT_EQ(in.get(), in.get());
50        EXPECT_NE(in.get(), out.get());
51        EXPECT_FALSE(in == out);
52        EXPECT_TRUE(in == in);
53        EXPECT_TRUE(out == out);
54        EXPECT_EQ(pipes[1], in.get());
55
56        EXPECT_TRUE(in);
57        EXPECT_TRUE(out);
58    }
59
60    END_TEST;
61}
62
63bool verify_pipes_open(int in, int out) {
64    BEGIN_HELPER;
65    char w = 'a';
66    EXPECT_EQ(write(in, &w, 1), 1);
67    char r;
68    EXPECT_EQ(read(out, &r, 1), 1);
69    EXPECT_EQ(r, w);
70    END_HELPER;
71}
72
73bool verify_pipes_closed(int in, int out) {
74    BEGIN_HELPER;
75    char c = 'a';
76    EXPECT_EQ(write(in, &c, 1), -1);
77    EXPECT_EQ(read(out, &c, 1), -1);
78    END_HELPER;
79}
80
81bool scoping_test() {
82    BEGIN_TEST;
83    int pipes[2];
84    EXPECT_EQ(pipe(pipes), 0);
85    EXPECT_TRUE(verify_pipes_open(pipes[1], pipes[0]));
86    {
87        fbl::unique_fd in(pipes[1]);
88        fbl::unique_fd out(pipes[0]);
89
90        EXPECT_EQ(pipes[0], out.get());
91        EXPECT_EQ(pipes[1], in.get());
92        EXPECT_TRUE(verify_pipes_open(in.get(), out.get()));
93    }
94    EXPECT_TRUE(verify_pipes_closed(pipes[1], pipes[0]));
95    END_TEST;
96}
97
98bool swap_test() {
99    BEGIN_TEST;
100    int pipes[2];
101    EXPECT_EQ(pipe(pipes), 0);
102    EXPECT_TRUE(verify_pipes_open(pipes[1], pipes[0]));
103    {
104        fbl::unique_fd in(pipes[1]);
105        fbl::unique_fd out(pipes[0]);
106
107        in.swap(out);
108        EXPECT_EQ(pipes[0], in.get());
109        EXPECT_EQ(pipes[1], out.get());
110        EXPECT_TRUE(verify_pipes_open(out.get(), in.get()));
111    }
112    EXPECT_TRUE(verify_pipes_closed(pipes[1], pipes[0]));
113    EXPECT_TRUE(verify_pipes_closed(pipes[0], pipes[1]));
114    END_TEST;
115}
116
117bool move_test() {
118    BEGIN_TEST;
119    // Move assignment
120    int pipes[2];
121    EXPECT_EQ(pipe(pipes), 0);
122    EXPECT_TRUE(verify_pipes_open(pipes[1], pipes[0]));
123    {
124        fbl::unique_fd in(pipes[1]);
125        fbl::unique_fd out(pipes[0]);
126
127        fbl::unique_fd in2, out2;
128        EXPECT_TRUE(verify_pipes_open(in.get(), out.get()));
129        EXPECT_TRUE(verify_pipes_closed(in2.get(), out2.get()));
130
131        in2 = fbl::move(in);
132        out2 = fbl::move(out);
133
134        EXPECT_TRUE(verify_pipes_closed(in.get(), out.get()));
135        EXPECT_TRUE(verify_pipes_open(in2.get(), out2.get()));
136    }
137    EXPECT_TRUE(verify_pipes_closed(pipes[1], pipes[0]));
138
139    // Move constructor
140    EXPECT_EQ(pipe(pipes), 0);
141    EXPECT_TRUE(verify_pipes_open(pipes[1], pipes[0]));
142    {
143        fbl::unique_fd in(pipes[1]);
144        fbl::unique_fd out(pipes[0]);
145
146        EXPECT_TRUE(verify_pipes_open(in.get(), out.get()));
147
148        fbl::unique_fd in2 = fbl::move(in);
149        fbl::unique_fd out2 = fbl::move(out);
150
151        EXPECT_TRUE(verify_pipes_closed(in.get(), out.get()));
152        EXPECT_TRUE(verify_pipes_open(in2.get(), out2.get()));
153    }
154    EXPECT_TRUE(verify_pipes_closed(pipes[1], pipes[0]));
155    END_TEST;
156}
157
158bool reset_test() {
159    BEGIN_TEST;
160    int pipes[2];
161    EXPECT_EQ(pipe(pipes), 0);
162    int other_pipes[2];
163    EXPECT_EQ(pipe(other_pipes), 0);
164    EXPECT_TRUE(verify_pipes_open(pipes[1], pipes[0]));
165    EXPECT_TRUE(verify_pipes_open(other_pipes[1], other_pipes[0]));
166    {
167        fbl::unique_fd in(pipes[1]);
168        fbl::unique_fd out(pipes[0]);
169
170        EXPECT_TRUE(verify_pipes_open(in.get(), out.get()));
171        EXPECT_TRUE(verify_pipes_open(pipes[1], pipes[0]));
172        EXPECT_TRUE(verify_pipes_open(other_pipes[1], other_pipes[0]));
173
174        in.reset(other_pipes[1]);
175        out.reset(other_pipes[0]);
176
177        EXPECT_TRUE(verify_pipes_open(in.get(), out.get()));
178        EXPECT_TRUE(verify_pipes_closed(pipes[1], pipes[0]));
179        EXPECT_TRUE(verify_pipes_open(other_pipes[1], other_pipes[0]));
180
181        in.reset();
182        out.reset();
183
184        EXPECT_TRUE(verify_pipes_closed(in.get(), out.get()));
185        EXPECT_TRUE(verify_pipes_closed(pipes[1], pipes[0]));
186        EXPECT_TRUE(verify_pipes_closed(other_pipes[1], other_pipes[0]));
187    }
188    EXPECT_TRUE(verify_pipes_closed(pipes[1], pipes[0]));
189    EXPECT_TRUE(verify_pipes_closed(other_pipes[1], other_pipes[0]));
190    END_TEST;
191}
192
193} // namespace
194
195BEGIN_TEST_CASE(unique_fd_tests)
196RUN_TEST(invalid_fd_test)
197RUN_TEST(valid_comparison_test)
198RUN_TEST(scoping_test)
199RUN_TEST(swap_test)
200RUN_TEST(move_test)
201RUN_TEST(reset_test)
202END_TEST_CASE(unique_fd_tests)
203