/* * SPDX-License-Identifier: GPL-2.0-or-later * * Copyright (C) 2020-2022 The DOSBox Staging Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "string_utils.h" #include #include #include "support.h" namespace { TEST(StartsWith, Prefix) { EXPECT_TRUE(starts_with("ab", "abcd")); EXPECT_TRUE(starts_with("ab", std::string{"abcd"})); } TEST(StartsWith, NotPrefix) { EXPECT_FALSE(starts_with("xy", "abcd")); EXPECT_FALSE(starts_with("xy", std::string{"abcd"})); } TEST(StartsWith, TooLongPrefix) { EXPECT_FALSE(starts_with("abcd", "ab")); EXPECT_FALSE(starts_with("abcd", std::string{"ab"})); } TEST(StartsWith, EmptyPrefix) { EXPECT_TRUE(starts_with("", "abcd")); EXPECT_TRUE(starts_with("", std::string{"abcd"})); } TEST(StartsWith, EmptyString) { EXPECT_FALSE(starts_with("ab", "")); EXPECT_FALSE(starts_with("ab", std::string{""})); } TEST(SafeSprintF, PreventOverflow) { char buf[3]; const int full_msg_len = safe_sprintf(buf, "%d", 98765); EXPECT_EQ(buf[0], '9'); EXPECT_EQ(buf[1], '8'); EXPECT_EQ(buf[2], '\0'); EXPECT_EQ(full_msg_len, 5); } TEST(SafeSprintF, PreventUnderflow) { char buf[10]; const int full_msg_len = safe_sprintf(buf, "%d", 987); EXPECT_STREQ(buf, "987"); EXPECT_EQ(full_msg_len, 3); } TEST(SafeStrcpy, SimpleCopy) { char buffer[10] = ""; char *ret_value = safe_strcpy(buffer, "abc"); EXPECT_EQ(ret_value, &buffer[0]); EXPECT_STREQ("abc", buffer); } TEST(SafeStrcpy, CopyFromNonArray) { char buffer[10] = ""; std::string str = "abc"; EXPECT_STREQ("abc", safe_strcpy(buffer, str.c_str())); } TEST(SafeStrcpy, EmptyStringOverwrites) { char buffer[4] = "abc"; EXPECT_STREQ("", safe_strcpy(buffer, "")); } TEST(SafeStrcpy, StringLongerThanBuffer) { char buffer[5] = ""; char long_input[] = "1234567890"; ASSERT_LT(ARRAY_LEN(buffer), strlen(long_input)); EXPECT_STREQ("1234", safe_strcpy(buffer, long_input)); } TEST(SafeStrcpyDeathTest, PassNull) { char buf[] = "12345678"; EXPECT_DEBUG_DEATH({ safe_strcpy(buf, nullptr); }, ""); } TEST(SafeStrcpyDeathTest, ProtectFromCopyingOverlappingString) { char buf[] = "12345678"; char *overlapping = &buf[2]; ASSERT_LE(buf, overlapping); ASSERT_LE(overlapping, buf + ARRAY_LEN(buf)); EXPECT_DEBUG_DEATH({ safe_strcpy(buf, overlapping); }, ""); } TEST(SafeStrlen, Simple) { char buffer[] = "1234"; EXPECT_EQ(4, safe_strlen(buffer)); } TEST(SafeStrlen, EmptyString) { char buffer[] = ""; EXPECT_EQ(0, safe_strlen(buffer)); } TEST(SafeStrlen, Uninitialized) { char buffer[4]; EXPECT_GT(sizeof(buffer), safe_strlen(buffer)); } TEST(SafeStrlen, FixedSize) { constexpr size_t N = 5; char buffer[N] = "1234"; EXPECT_EQ(N - 1, safe_strlen(buffer)); } TEST(Split_delit, NoBoundingDelims) { const std::vector expected({"a", "/b", "/c/d", "/e/f/"}); EXPECT_EQ(split("a:/b:/c/d:/e/f/", ':'), expected); EXPECT_EQ(split("a /b /c/d /e/f/", ' '), expected); EXPECT_EQ(split("abc", 'x'), std::vector{"abc"}); } TEST(Split_delim, DelimAtStartNotEnd) { const std::vector expected({"", "a", "/b", "/c/d", "/e/f/"}); EXPECT_EQ(split(":a:/b:/c/d:/e/f/", ':'), expected); EXPECT_EQ(split(" a /b /c/d /e/f/", ' '), expected); } TEST(Split_delim, DelimAtEndNotStart) { const std::vector expected({"a", "/b", "/c/d", "/e/f/", ""}); EXPECT_EQ(split("a:/b:/c/d:/e/f/:", ':'), expected); EXPECT_EQ(split("a /b /c/d /e/f/ ", ' '), expected); } TEST(Split_delim, DelimsAtBoth) { const std::vector expected({"", "a", "/b", "/c/d", "/e/f/", ""}); EXPECT_EQ(split(":a:/b:/c/d:/e/f/:", ':'), expected); EXPECT_EQ(split(" a /b /c/d /e/f/ ", ' '), expected); } TEST(Split_delim, MultiInternalDelims) { const std::vector expected( {"a", "/b", "", "/c/d", "", "", "/e/f/"}); EXPECT_EQ(split("a:/b::/c/d:::/e/f/", ':'), expected); EXPECT_EQ(split("a /b /c/d /e/f/", ' '), expected); } TEST(Split_delim, MultiBoundingDelims) { const std::vector expected( {"", "", "a", "/b", "/c/d", "/e/f/", "", "", ""}); EXPECT_EQ(split("::a:/b:/c/d:/e/f/:::", ':'), expected); EXPECT_EQ(split(" a /b /c/d /e/f/ ", ' '), expected); } TEST(Split_delim, MixedDelims) { const std::vector expected( {"", "", "a", "/b", "", "/c/d", "/e/f/"}); EXPECT_EQ(split("::a:/b::/c/d:/e/f/", ':'), expected); EXPECT_EQ(split(" a /b /c/d /e/f/", ' '), expected); } TEST(Split_delim, Empty) { const std::vector empty; const std::vector two({"", ""}); const std::vector three({"", "", ""}); EXPECT_EQ(split("", ':'), empty); EXPECT_EQ(split(":", ':'), two); EXPECT_EQ(split("::", ':'), three); EXPECT_EQ(split("", ' '), empty); EXPECT_EQ(split(" ", ' '), two); EXPECT_EQ(split(" ", ' '), three); } TEST(Split, NoBoundingWhitespace) { const std::vector expected({"a", "/b", "/c/d", "/e/f/"}); EXPECT_EQ(split("a /b /c/d /e/f/"), expected); EXPECT_EQ(split("abc"), std::vector{"abc"}); } TEST(Split, WhitespaceAtStartNotEnd) { const std::vector expected({"a", "/b", "/c/d", "/e/f/"}); EXPECT_EQ(split(" a /b /c/d /e/f/"), expected); } TEST(Split, WhitespaceAtEndNotStart) { const std::vector expected({"a", "/b", "/c/d", "/e/f/"}); EXPECT_EQ(split("a /b /c/d /e/f/ "), expected); } TEST(Split, WhitespaceAtBoth) { const std::vector expected({"a", "/b", "/c/d", "/e/f/"}); EXPECT_EQ(split(" a /b /c/d /e/f/ "), expected); } TEST(Split, MultiInternalWhitespace) { const std::vector expected({"a", "/b", "/c/d", "/e/f/"}); EXPECT_EQ(split("a /b /c/d /e/f/"), expected); } TEST(Split, MultiBoundingWhitespace) { const std::vector expected({"a", "/b", "/c/d", "/e/f/"}); EXPECT_EQ(split(" a /b /c/d /e/f/ "), expected); } TEST(Split, MixedWhitespace) { const std::vector expected({"a", "b", "c"}); EXPECT_EQ(split("\t\na\f\vb\rc"), expected); EXPECT_EQ(split("a\tb\f\vc"), expected); EXPECT_EQ(split(" a \n \v \r b \f \r c "), expected); } TEST(Split, Empty) { const std::vector empty; EXPECT_EQ(split(""), empty); EXPECT_EQ(split(" "), empty); EXPECT_EQ(split(" "), empty); } TEST(ParseValue, Valid) { // negatives EXPECT_EQ(*parse_value("-10000", -11000, 0), -10000.0f); EXPECT_EQ(*parse_value("-0.1", -1, 0), -0.1f); EXPECT_EQ(*parse_value("-0.0001", -1, 0), -0.0001f); EXPECT_EQ(*parse_value("-0.0", -1, 1), -0.0f); EXPECT_EQ(*parse_value("0", -1, 1), 0.0f); // positives EXPECT_EQ(*parse_value("0.0", -1, 1), 0.0f); EXPECT_EQ(*parse_value("0.0001", -1, 1), 0.0001f); EXPECT_EQ(*parse_value("0.1", -1, 1), 0.1f); EXPECT_EQ(*parse_value("10000", 0, 11000), 10000.0f); } TEST(ParsePercentage, Valid) { EXPECT_EQ(*parse_percentage("-100"), 0.0f); EXPECT_EQ(*parse_percentage("0"), 0.0f); EXPECT_EQ(*parse_percentage("1"), 1.0f); EXPECT_EQ(*parse_percentage("50"), 50.0f); EXPECT_EQ(*parse_percentage("100"), 100.0f); EXPECT_EQ(*parse_percentage("1000"), 100.0f); } TEST(ParseBoth, Invalid) { std::optional empty = {}; EXPECT_EQ(parse_value("sfafsd", 0, 1), empty); EXPECT_EQ(parse_value("", 0, 1), empty); EXPECT_EQ(parse_percentage("dfsfsdf"), empty); EXPECT_EQ(parse_percentage(""), empty); } TEST(ParsePrefixedValue, Valid) { // negatives EXPECT_EQ(*parse_prefixed_value('a', "a-10000", -10000, 0), -10000.0f); EXPECT_EQ(*parse_prefixed_value('b', "b-0.1", -1, 1), -0.1f); EXPECT_EQ(*parse_prefixed_value('c', "c-0.0001", -1, 1), -0.0001f); EXPECT_EQ(*parse_prefixed_value('d', "d-0.0", -1, 1), -0.0f); EXPECT_EQ(*parse_prefixed_value('e', "e0", 0, 1), 0.0f); // positives EXPECT_EQ(*parse_prefixed_value('f', "f0.0", 0, 1), 0.0f); EXPECT_EQ(*parse_prefixed_value('g', "g0.0001", 0, 1), 0.0001f); EXPECT_EQ(*parse_prefixed_value('h', "h0.1", 0, 1), 0.1f); EXPECT_EQ(*parse_prefixed_value('i', "i10000", 0, 11000), 10000.0f); } TEST(ParsePrefixedPercentage, Valid) { EXPECT_EQ(*parse_prefixed_percentage('u', "u-100"), 0.0f); EXPECT_EQ(*parse_prefixed_percentage('v', "v0"), 0.0f); EXPECT_EQ(*parse_prefixed_percentage('w', "w1"), 1.0f); EXPECT_EQ(*parse_prefixed_percentage('x', "x50"), 50.0f); EXPECT_EQ(*parse_prefixed_percentage('y', "y100"), 100.0f); EXPECT_EQ(*parse_prefixed_percentage('z', "z1000"), 100.0f); } TEST(ParsePrefixedBoth, Invalid) { std::optional empty = {}; EXPECT_EQ(parse_prefixed_value('a', "b-10000", 0, 1), empty); EXPECT_EQ(parse_prefixed_percentage('z', "y1000"), empty); EXPECT_EQ(parse_prefixed_value('a', "-10000", 0, 1), empty); EXPECT_EQ(parse_prefixed_percentage('z', "1000"), empty); EXPECT_EQ(parse_prefixed_value('a', "", 0, 1), empty); EXPECT_EQ(parse_prefixed_percentage('z', ""), empty); EXPECT_EQ(parse_prefixed_value(' ', "----", 0, 1), empty); EXPECT_EQ(parse_prefixed_percentage(' ', ""), empty); } } // namespace