brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 1a31094 Raw
168 lines · cpp
1//===-- Unittests for getopt ----------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "src/unistd/getopt.h"10#include "test/UnitTest/Test.h"11 12#include "src/__support/CPP/array.h"13#include "src/stdio/fflush.h"14#include "src/stdio/fopencookie.h"15 16using LIBC_NAMESPACE::cpp::array;17 18namespace test_globals {19char *optarg;20int optind = 1;21int optopt;22int opterr = 1;23 24unsigned optpos;25} // namespace test_globals26 27// This can't be a constructor because it will get run before the constructor28// which sets the default state in getopt.29void set_state(FILE *errstream) {30  LIBC_NAMESPACE::impl::set_getopt_state(31      &test_globals::optarg, &test_globals::optind, &test_globals::optopt,32      &test_globals::optpos, &test_globals::opterr, errstream);33}34 35static void my_memcpy(char *dest, const char *src, size_t size) {36  for (size_t i = 0; i < size; i++)37    dest[i] = src[i];38}39 40ssize_t cookie_write(void *cookie, const char *buf, size_t size) {41  char **pos = static_cast<char **>(cookie);42  my_memcpy(*pos, buf, size);43  *pos += size;44  return size;45}46 47static cookie_io_functions_t cookie{nullptr, &cookie_write, nullptr, nullptr};48 49// TODO: <stdio> could be either llvm-libc's or the system libc's. The former50// doesn't currently support fmemopen but does have fopencookie. In the future51// just use that instead. This memopen does no error checking for the size52// of the buffer, etc.53FILE *memopen(char **pos) {54  return LIBC_NAMESPACE::fopencookie(pos, "w", cookie);55}56 57struct LlvmLibcGetoptTest : public LIBC_NAMESPACE::testing::Test {58  FILE *errstream;59  char buf[256];60  char *pos = buf;61 62  void reset_errstream() { pos = buf; }63  const char *get_error_msg() {64    LIBC_NAMESPACE::fflush(errstream);65    return buf;66  }67 68  void SetUp() override {69    ASSERT_TRUE(!!(errstream = memopen(&pos)));70    set_state(errstream);71    ASSERT_EQ(test_globals::optind, 1);72  }73 74  void TearDown() override {75    test_globals::optind = 1;76    test_globals::opterr = 1;77  }78};79 80// This is safe because getopt doesn't currently permute argv like GNU's getopt81// does so this just helps silence warnings.82char *operator""_c(const char *c, size_t) { return const_cast<char *>(c); }83 84TEST_F(LlvmLibcGetoptTest, NoMatch) {85  array<char *, 3> argv{"prog"_c, "arg1"_c, nullptr};86 87  // optind >= argc88  EXPECT_EQ(LIBC_NAMESPACE::getopt(1, argv.data(), "..."), -1);89 90  // argv[optind] == nullptr91  test_globals::optind = 2;92  EXPECT_EQ(LIBC_NAMESPACE::getopt(100, argv.data(), "..."), -1);93 94  // argv[optind][0] != '-'95  test_globals::optind = 1;96  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), -1);97  ASSERT_EQ(test_globals::optind, 1);98 99  // argv[optind] == "-"100  argv[1] = "-"_c;101  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), -1);102  ASSERT_EQ(test_globals::optind, 1);103 104  // argv[optind] == "--", then return -1 and incremement optind105  argv[1] = "--"_c;106  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), -1);107  EXPECT_EQ(test_globals::optind, 2);108}109 110TEST_F(LlvmLibcGetoptTest, WrongMatch) {111  array<char *, 3> argv{"prog"_c, "-b"_c, nullptr};112 113  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), int('?'));114  EXPECT_EQ(test_globals::optopt, (int)'b');115  EXPECT_EQ(test_globals::optind, 1);116  EXPECT_STREQ(get_error_msg(), "prog: illegal option -- b\n");117}118 119TEST_F(LlvmLibcGetoptTest, OpterrFalse) {120  array<char *, 3> argv{"prog"_c, "-b"_c, nullptr};121 122  test_globals::opterr = 0;123  set_state(errstream);124  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), int('?'));125  EXPECT_EQ(test_globals::optopt, (int)'b');126  EXPECT_EQ(test_globals::optind, 1);127  EXPECT_STREQ(get_error_msg(), "");128}129 130TEST_F(LlvmLibcGetoptTest, MissingArg) {131  array<char *, 3> argv{"prog"_c, "-b"_c, nullptr};132 133  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), ":b:"), (int)':');134  ASSERT_EQ(test_globals::optind, 1);135  EXPECT_STREQ(get_error_msg(), "prog: option requires an argument -- b\n");136  reset_errstream();137  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "b:"), int('?'));138  EXPECT_EQ(test_globals::optind, 1);139  EXPECT_STREQ(get_error_msg(), "prog: option requires an argument -- b\n");140}141 142TEST_F(LlvmLibcGetoptTest, ParseArgInCurrent) {143  array<char *, 3> argv{"prog"_c, "-barg"_c, nullptr};144 145  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "b:"), (int)'b');146  EXPECT_STREQ(test_globals::optarg, "arg");147  EXPECT_EQ(test_globals::optind, 2);148}149 150TEST_F(LlvmLibcGetoptTest, ParseArgInNext) {151  array<char *, 4> argv{"prog"_c, "-b"_c, "arg"_c, nullptr};152 153  EXPECT_EQ(LIBC_NAMESPACE::getopt(3, argv.data(), "b:"), (int)'b');154  EXPECT_STREQ(test_globals::optarg, "arg");155  EXPECT_EQ(test_globals::optind, 3);156}157 158TEST_F(LlvmLibcGetoptTest, ParseMultiInOne) {159  array<char *, 3> argv{"prog"_c, "-abc"_c, nullptr};160 161  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "abc"), (int)'a');162  ASSERT_EQ(test_globals::optind, 1);163  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "abc"), (int)'b');164  ASSERT_EQ(test_globals::optind, 1);165  EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "abc"), (int)'c');166  EXPECT_EQ(test_globals::optind, 2);167}168