1/*
2 * Copyright (C) 2024 HiHope Open Source Organization.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <cstring>
17#include <fcntl.h>
18#include <unistd.h>
19#include <gtest/gtest.h>
20#include <sys/types.h>
21#include <sys/uio.h>
22#include "securec.h"
23
24using namespace testing::ext;
25using namespace std;
26
27class PreadvApiTest : public testing::Test {
28public:
29    static void SetUpTestCase();
30    static void TearDownTestCase();
31    void SetUp();
32    void TearDown();
33
34private:
35};
36
37static const char* TEST_DATA = "Hello, world!";
38static const size_t TEST_LEN = strlen(TEST_DATA);
39static const int MAX_LEN = 128;
40static const char* TEST_FILE = "/data/local/tmp/test_file.txt";
41static const char* EMPTY_FILE = "/data/local/tmp/empty_file.txt";
42
43void PreadvApiTest::SetUpTestCase()
44{
45}
46
47void PreadvApiTest::TearDownTestCase()
48{
49}
50
51void PreadvApiTest::SetUp()
52{
53    int fd = open(TEST_FILE, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
54    write(fd, TEST_DATA, TEST_LEN);
55    close(fd);
56}
57
58void PreadvApiTest::TearDown()
59{
60    unlink(TEST_FILE);
61}
62
63/*
64 * @tc.number : SUB_KERNEL_SYSCALL_PREADV_0100
65 * @tc.name   : PreadvReadSuccess_0001
66 * @tc.desc   : Test basic read functionality of preadv.
67 * @tc.size   : MediumTest
68 * @tc.type   : Function
69 * @tc.level  : Level 1
70 */
71HWTEST_F(PreadvApiTest, PreadvReadSuccess_0001, Function | MediumTest | Level1)
72{
73    ssize_t size;
74    int midLen = TEST_LEN / 2;
75    char buffer[MAX_LEN] = { 0 };
76    struct iovec iov[2] = {
77        {
78            .iov_base = buffer,
79            .iov_len = TEST_LEN,
80        }, {
81            .iov_base = &buffer[TEST_LEN],
82            .iov_len = TEST_LEN,
83        }
84    };
85
86    int fd = open(TEST_FILE, O_RDONLY);
87
88    // preadv from file start
89    size = preadv(fd, iov, 2, 0);
90    EXPECT_EQ(size, TEST_LEN);
91    EXPECT_STREQ(static_cast<char *>(iov[0].iov_base), TEST_DATA);
92
93    // preadv from file middle
94    memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
95    size = preadv(fd, iov, 1, midLen);
96    EXPECT_EQ(size, TEST_LEN - midLen);
97    EXPECT_STREQ(static_cast<char *>(iov[0].iov_base), &TEST_DATA[midLen]);
98
99    // preadv from file end
100    memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
101    size = preadv(fd, iov, 1, TEST_LEN);
102    EXPECT_EQ(size, 0);
103
104    close(fd);
105}
106
107/*
108 * @tc.number : SUB_KERNEL_SYSCALL_PREADV_0200
109 * @tc.name   : PreadvInvalidFdFailed_0002
110 * @tc.desc   : Test using an invalid file descriptor with preadv.
111 * @tc.size   : MediumTest
112 * @tc.type   : Function
113 * @tc.level  : Level 2
114 */
115HWTEST_F(PreadvApiTest, PreadvInvalidFdFailed_0002, Function | MediumTest | Level2)
116{
117    ssize_t size;
118    char buffer[MAX_LEN] = { 0 };
119    struct iovec iov = {
120        .iov_base = buffer,
121        .iov_len = sizeof(buffer),
122    };
123    errno = 0;
124    size = preadv(-1, &iov, 1, 0);
125    EXPECT_EQ(size, -1);
126    EXPECT_EQ(errno, EBADF);
127}
128
129/*
130 * @tc.number : SUB_KERNEL_SYSCALL_PREADV_0300
131 * @tc.name   : PreadvReadFromEmptyFileSuccess_0003
132 * @tc.desc   : Test reading from an empty file with preadv.
133 * @tc.size   : MediumTest
134 * @tc.type   : Function
135 * @tc.level  : Level 1
136 */
137HWTEST_F(PreadvApiTest, PreadvReadFromEmptyFileSuccess_0003, Function | MediumTest | Level1)
138{
139    ssize_t size;
140    char buffer[MAX_LEN] = { 0 };
141    struct iovec iov = {
142        .iov_base = buffer,
143        .iov_len = sizeof(buffer),
144    };
145    int fd = open(EMPTY_FILE, O_CREAT | O_RDWR, 0644);
146    size = preadv(fd, &iov, 1, 0);
147    EXPECT_EQ(size, 0);
148    close(fd);
149    unlink(EMPTY_FILE);
150}
151
152/*
153 * @tc.number : SUB_KERNEL_SYSCALL_PREADV_0400
154 * @tc.name   : PreadvReadContinuousSuccess_0004
155 * @tc.desc   : Test reading from a file with preadv continuously.
156 * @tc.size   : MediumTest
157 * @tc.type   : Function
158 * @tc.level  : Level 1
159 */
160HWTEST_F(PreadvApiTest, PreadvReadContinuousSuccess_0004, Function | MediumTest | Level1)
161{
162    ssize_t size;
163    const char *context = "this is a test file.";
164    char buffer[MAX_LEN] = { 0 };
165    struct iovec iov[2] = {
166        {
167            .iov_base = buffer,
168            .iov_len = TEST_LEN,
169        }, {
170            .iov_base = &buffer[MAX_LEN / 2],
171            .iov_len = strlen(context),
172        }
173    };
174
175    int fd = open(TEST_FILE, O_RDWR | O_APPEND, 0644);
176    write(fd, context, strlen(context));
177
178    // preadv context to 2 iovec
179    size = preadv(fd, iov, 2, 0);
180    EXPECT_EQ(size, TEST_LEN + strlen(context));
181    EXPECT_STREQ(static_cast<char *>(iov[0].iov_base), TEST_DATA);
182    EXPECT_STREQ(static_cast<char *>(iov[1].iov_base), context);
183
184    close(fd);
185}
186
187/*
188 * @tc.number : SUB_KERNEL_SYSCALL_PREADV2_0500
189 * @tc.name   : Preadv2ReadSuccess_0002
190 * @tc.desc   : preadv2 read file success.
191 * @tc.size   : MediumTest
192 * @tc.type   : Function
193 * @tc.level  : Level 1
194 */
195HWTEST_F(PreadvApiTest, Preadv2ReadSuccess_0002, Function | MediumTest | Level1)
196{
197    ssize_t size;
198    int midLen = TEST_LEN / 2;
199    char buffer[MAX_LEN] = { 0 };
200    struct iovec iov[2] = {
201        {
202            .iov_base = buffer,
203            .iov_len = TEST_LEN,
204        }, {
205            .iov_base = &buffer[TEST_LEN],
206            .iov_len = TEST_LEN,
207        }
208    };
209
210    int fd = open(TEST_FILE, O_RDONLY);
211
212    // preadv from file start
213    size = preadv(fd, iov, 2, 0);
214    EXPECT_EQ(size, TEST_LEN);
215    EXPECT_STREQ(static_cast<char *>(iov[0].iov_base), TEST_DATA);
216
217    // preadv from file middle
218    memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
219    size = preadv2(fd, iov, 1, midLen, 0);
220    EXPECT_EQ(size, TEST_LEN - midLen);
221    EXPECT_STREQ(static_cast<char *>(iov[0].iov_base), &TEST_DATA[midLen]);
222
223    // preadv from file end
224    memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
225    size = preadv2(fd, iov, 1, TEST_LEN, 0);
226    EXPECT_EQ(size, 0);
227
228    close(fd);
229}
230