blob: b78d4e49ee3b4274551fbbe240448cdd9d6bd918 [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Unittests for parse_group_line.
///
//===----------------------------------------------------------------------===//
#include "hdr/errno_macros.h"
#include "hdr/types/gid_t.h"
#include "hdr/types/size_t.h"
#include "hdr/types/struct_group.h"
#include "src/__support/CPP/span.h"
#include "src/__support/pwd/flat_file_db.h"
#include "src/grp/grp_utils.h"
#include "test/UnitTest/Test.h"
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_Success) {
char line[] = "wheel:x:10:root,admin,user1";
char *mem_ptrs[8];
struct group grp;
const bool ok = LIBC_NAMESPACE::grp::parse_group_line(line, &grp, mem_ptrs);
ASSERT_TRUE(ok);
EXPECT_STREQ(grp.gr_name, "wheel");
EXPECT_STREQ(grp.gr_passwd, "x");
EXPECT_EQ(grp.gr_gid, static_cast<gid_t>(10));
ASSERT_NE(grp.gr_mem, nullptr);
EXPECT_STREQ(grp.gr_mem[0], "root");
EXPECT_STREQ(grp.gr_mem[1], "admin");
EXPECT_STREQ(grp.gr_mem[2], "user1");
EXPECT_EQ(grp.gr_mem[3], nullptr);
}
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_EmptyMembers) {
char line[] = "nogroup:x:65534:";
char *mem_ptrs[4];
struct group grp;
const bool ok = LIBC_NAMESPACE::grp::parse_group_line(line, &grp, mem_ptrs);
ASSERT_TRUE(ok);
EXPECT_STREQ(grp.gr_name, "nogroup");
EXPECT_STREQ(grp.gr_passwd, "x");
EXPECT_EQ(grp.gr_gid, static_cast<gid_t>(65534));
ASSERT_NE(grp.gr_mem, nullptr);
EXPECT_EQ(grp.gr_mem[0], nullptr);
}
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_LeadingTrailingAndConsecutiveCommas) {
char line[] = "test:x:100:,user1,,user2,";
char *mem_ptrs[8];
struct group grp;
const bool ok = LIBC_NAMESPACE::grp::parse_group_line(line, &grp, mem_ptrs);
ASSERT_TRUE(ok);
EXPECT_STREQ(grp.gr_name, "test");
EXPECT_STREQ(grp.gr_passwd, "x");
EXPECT_EQ(grp.gr_gid, static_cast<gid_t>(100));
ASSERT_NE(grp.gr_mem, nullptr);
EXPECT_STREQ(grp.gr_mem[0], "user1");
EXPECT_STREQ(grp.gr_mem[1], "user2");
EXPECT_EQ(grp.gr_mem[2], nullptr);
}
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_SingleMember) {
char line[] = "bin:x:1:bin";
char *mem_ptrs[4];
struct group grp;
const bool ok = LIBC_NAMESPACE::grp::parse_group_line(line, &grp, mem_ptrs);
ASSERT_TRUE(ok);
EXPECT_STREQ(grp.gr_name, "bin");
EXPECT_STREQ(grp.gr_passwd, "x");
EXPECT_EQ(grp.gr_gid, static_cast<gid_t>(1));
ASSERT_NE(grp.gr_mem, nullptr);
EXPECT_STREQ(grp.gr_mem[0], "bin");
EXPECT_EQ(grp.gr_mem[1], nullptr);
}
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_InvalidNumeric) {
char *mem_ptrs[4];
struct group grp;
char line1[] = "root:x:abc:root";
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line1, &grp, mem_ptrs));
char line2[] = "root:x:-1:root";
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line2, &grp, mem_ptrs));
char line3[] = "root:x::root";
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line3, &grp, mem_ptrs));
char line4[] = "root:x:999999999999999999999999999999:root";
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line4, &grp, mem_ptrs));
}
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_MissingFields) {
char *mem_ptrs[4];
struct group grp;
char line1[] = "root:x";
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line1, &grp, mem_ptrs));
char line2[] = "root:x:0";
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line2, &grp, mem_ptrs));
}
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_EmptyGroupName) {
char *mem_ptrs[4];
struct group grp;
char line[] = ":x:0:root";
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line, &grp, mem_ptrs));
}
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_TrailingGarbage) {
char *mem_ptrs[4];
struct group grp;
char line[] = "root:x:0:root:extra";
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line, &grp, mem_ptrs));
}
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_NullInput) {
char *mem_ptrs[4];
struct group grp;
LIBC_NAMESPACE::cpp::span<char> empty;
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(empty, &grp, mem_ptrs));
char line[] = "root:x:0:root";
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line, nullptr, mem_ptrs));
LIBC_NAMESPACE::cpp::span<char *> empty_mem;
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line, &grp, empty_mem));
}
TEST(LlvmLibcGrpUtilsTest, ParseGroupLine_MemberBufferTooSmall) {
char line[] = "wheel:x:10:root,admin";
char *mem_ptrs[2]; // Can only hold 1 member + 1 nullptr
struct group grp;
EXPECT_FALSE(LIBC_NAMESPACE::grp::parse_group_line(line, &grp, mem_ptrs));
}
TEST(LlvmLibcGrpUtilsTest, ParseLine_FixedBufferErangeWhenNoScratchSpace) {
// The line fits in buffer, but there is no space left for gr_mem pointers.
char buffer[] = "wheel:x:10:root,admin";
struct group grp;
const auto res = LIBC_NAMESPACE::pwd::parse_line<struct group>(
LIBC_NAMESPACE::cpp::span<char>(buffer, sizeof(buffer)), {}, &grp);
ASSERT_FALSE(res.has_value());
EXPECT_EQ(res.error(), ERANGE);
}
TEST(LlvmLibcGrpUtilsTest, ParseLine_EmbeddedNullByteRejected) {
constexpr const char RAW[] = "wheel:x:10:root\0admin";
char buffer[128];
for (size_t i = 0; i < sizeof(RAW); ++i)
buffer[i] = RAW[i];
struct group grp;
const auto res = LIBC_NAMESPACE::pwd::parse_line<struct group>(
LIBC_NAMESPACE::cpp::span<char>(buffer, sizeof(RAW)),
LIBC_NAMESPACE::cpp::span<char>(buffer + sizeof(RAW),
sizeof(buffer) - sizeof(RAW)),
&grp);
ASSERT_FALSE(res.has_value());
EXPECT_EQ(res.error(), EINVAL);
}
TEST(LlvmLibcGrpUtilsTest, ParseLine_SuccessWithTailForMemberPointers) {
constexpr const char *LINE = "wheel:x:10:root,admin,user1,user2";
constexpr size_t LEN = 33;
char buffer[128];
for (size_t i = 0; i <= LEN; ++i)
buffer[i] = LINE[i];
struct group grp;
const auto res = LIBC_NAMESPACE::pwd::parse_line<struct group>(
LIBC_NAMESPACE::cpp::span<char>(buffer, LEN + 1),
LIBC_NAMESPACE::cpp::span<char>(buffer + LEN + 1,
sizeof(buffer) - (LEN + 1)),
&grp);
ASSERT_TRUE(res.has_value());
EXPECT_STREQ(grp.gr_name, "wheel");
EXPECT_STREQ(grp.gr_passwd, "x");
EXPECT_EQ(grp.gr_gid, static_cast<gid_t>(10));
ASSERT_NE(grp.gr_mem, nullptr);
EXPECT_STREQ(grp.gr_mem[0], "root");
EXPECT_STREQ(grp.gr_mem[1], "admin");
EXPECT_STREQ(grp.gr_mem[2], "user1");
EXPECT_STREQ(grp.gr_mem[3], "user2");
EXPECT_EQ(grp.gr_mem[4], nullptr);
}