1//===-- Unittests for fgets -----------------------------------------------===//
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#include "src/stdio/fclose.h"
10#include "src/stdio/feof.h"
11#include "src/stdio/ferror.h"
12#include "src/stdio/fgets.h"
13#include "src/stdio/fopen.h"
14#include "src/stdio/fwrite.h"
15#include "test/UnitTest/Test.h"
16
17#include "src/errno/libc_errno.h"
18#include <stdio.h>
19
20TEST(LlvmLibcFgetsTest, WriteAndReadCharacters) {
21 constexpr char FILENAME[] = "testdata/fgets.test";
22 ::FILE *file = LIBC_NAMESPACE::fopen(name: FILENAME, mode: "w");
23 ASSERT_FALSE(file == nullptr);
24 constexpr char CONTENT[] = "123456789\n"
25 "1234567\n"
26 "123456\n"
27 "1";
28 constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1;
29
30 char buff[8];
31 char *output;
32
33 ASSERT_EQ(WRITE_SIZE, LIBC_NAMESPACE::fwrite(CONTENT, 1, WRITE_SIZE, file));
34 // This is a write-only file so reads should fail.
35 ASSERT_TRUE(LIBC_NAMESPACE::fgets(buff, 8, file) == nullptr);
36 // This is an error and not a real EOF.
37 ASSERT_EQ(LIBC_NAMESPACE::feof(file), 0);
38 ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
39 LIBC_NAMESPACE::libc_errno = 0;
40
41 ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
42
43 file = LIBC_NAMESPACE::fopen(name: FILENAME, mode: "r");
44 ASSERT_FALSE(file == nullptr);
45
46 // If we request just 1 byte, it should return just a null byte and not
47 // advance the read head. This is implementation defined.
48 output = LIBC_NAMESPACE::fgets(str: buff, count: 1, raw_stream: file);
49 ASSERT_TRUE(output == buff);
50 ASSERT_EQ(buff[0], '\0');
51 ASSERT_ERRNO_SUCCESS();
52
53 // If we request less than 1 byte, it should do nothing and return nullptr.
54 // This is also implementation defined.
55 output = LIBC_NAMESPACE::fgets(str: buff, count: 0, raw_stream: file);
56 ASSERT_TRUE(output == nullptr);
57
58 const char *output_arr[] = {
59 "1234567", "89\n", "1234567", "\n", "123456\n", "1",
60 };
61
62 constexpr size_t ARR_SIZE = sizeof(output_arr) / sizeof(char *);
63
64 for (size_t i = 0; i < ARR_SIZE; ++i) {
65 output = LIBC_NAMESPACE::fgets(str: buff, count: 8, raw_stream: file);
66
67 // This pointer comparison is intentional, fgets should return a pointer to
68 // buff when it succeeds.
69 ASSERT_TRUE(output == buff);
70 ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
71
72 EXPECT_STREQ(buff, output_arr[i]);
73 }
74
75 // This should have hit the end of the file, but that isn't an error unless it
76 // fails to read anything.
77 ASSERT_NE(LIBC_NAMESPACE::feof(file), 0);
78 ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
79 ASSERT_ERRNO_SUCCESS();
80
81 // Reading more should be an EOF, but not an error.
82 output = LIBC_NAMESPACE::fgets(str: buff, count: 8, raw_stream: file);
83 ASSERT_TRUE(output == nullptr);
84 ASSERT_NE(LIBC_NAMESPACE::feof(file), 0);
85 ASSERT_ERRNO_SUCCESS();
86
87 ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
88}
89

source code of libc/test/src/stdio/fgets_test.cpp