/* * Copyright (c) 2019 The Regents of the University of California * All rights reserved * * The license below extends only to copyright in the software and shall * not be construed as granting a license to any other intellectual * property including but not limited to intellectual property relating * to a hardware implementation of the functionality of the software * licensed hereunder. You may use the software subject to the license * terms below provided that you ensure that this notice is replicated * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Bobby R. Bruce */ #include #include #include "base/str.hh" /* * str.cc has "eat_lead_white", "eat_end_white", and "eat_white" fucntions to * remove leading and trailing whitespace. The following tests verify this * behavior. */ TEST(StrTest, EatLeadWhite) { std::string val = " hello there "; eat_lead_white(val); EXPECT_EQ("hello there ", val); } TEST(StrTest, EatLeadWhiteNoLeadingWhitespace) { std::string val = "hello there "; eat_lead_white(val); EXPECT_EQ("hello there ", val); } TEST(StrTest, EatEndWhite) { std::string val = " hello there "; eat_end_white(val); EXPECT_EQ(" hello there", val); } TEST(StrTest, EatEndWhiteNoTrailingWhitespace) { std::string val = " hello there"; eat_end_white(val); EXPECT_EQ(" hello there", val); } TEST(StrTest, EatWhite) { std::string val = " hello there "; eat_white(val); EXPECT_EQ("hello there", val); } TEST(StrTest, EatWhiteNoWhitespace) { std::string val = "hello there"; eat_lead_white(val); EXPECT_EQ("hello there", val); } /* * This tests checks that str.cc's "to_lower" function converts a string to * lowercase. */ TEST(StrTest, ToLower) { std::string val = "gOoDbYe FOO@barr!"; EXPECT_EQ("goodbye foo@barr!", to_lower(val)); } /* * str.cc's "split_first" and "split_last" fucntions split a string on a * character into two parts. "split_first" splits on the first instance of * this character and "split_last" splits on the last instance of this * character. The character itself is not included in either of the output * right-hand side and left-hand side strings. If the character cannot be * found in the string then the left-hand side string is equal to the input * string and the right-hand side string is empty. */ TEST(StrTest, SplitFirst) { std::string val = "abcdefg abcdefg"; std::string lhs; std::string rhs; split_first(val , lhs, rhs, 'f'); EXPECT_EQ("abcdefg abcdefg", val); EXPECT_EQ("abcde", lhs); EXPECT_EQ("g abcdefg", rhs); } TEST(StrTest, SplitFirstNoChar) { std::string val = "abcdefg abcdefg"; std::string lhs; std::string rhs; split_first(val , lhs, rhs, 'h'); EXPECT_EQ("abcdefg abcdefg", val); EXPECT_EQ("abcdefg abcdefg", lhs); EXPECT_EQ("", rhs); } TEST(StrTest, SplitFirstOnFirstChar) { std::string val = "abcdefg abcdefg"; std::string lhs; std::string rhs; split_first(val , lhs, rhs, 'a'); EXPECT_EQ("abcdefg abcdefg", val); EXPECT_EQ("", lhs); EXPECT_EQ("bcdefg abcdefg", rhs); } TEST(StrTest, SplitLast) { std::string val = "abcdefg abcdefg"; std::string lhs; std::string rhs; split_last(val , lhs, rhs, 'f'); EXPECT_EQ("abcdefg abcdefg", val); EXPECT_EQ("abcdefg abcde", lhs); EXPECT_EQ("g", rhs); } TEST(StrTest, SplitLastNoChar) { std::string val = "abcdefg abcdefg"; std::string lhs; std::string rhs; split_last(val , lhs, rhs, 'h'); EXPECT_EQ("abcdefg abcdefg", val); EXPECT_EQ("abcdefg abcdefg", lhs); EXPECT_EQ("", rhs); } TEST(StrTest, SplitLastOnLastChar) { std::string val = "abcdefg abcdefg"; std::string lhs; std::string rhs; split_last(val , lhs, rhs, 'g'); EXPECT_EQ("abcdefg abcdefg", val); EXPECT_EQ("abcdefg abcdef", lhs); EXPECT_EQ("", rhs); } /* * str.cc's "tokenize" function splits a string into its constituent tokens. * It splits based on an input character. */ TEST(StrTest, TokenizeOnSpace) { /* * val has a double space between each token with trailing and leading * whitespace. */ std::string val = " Hello, this is a sentence. "; std::vector tokens; /* * By default 'ign' is true. This means empty tokens are not included in * the output list. */ tokenize(tokens, val, ' '); EXPECT_EQ(" Hello, this is a sentence. ", val); EXPECT_EQ(5, tokens.size()); EXPECT_EQ("Hello,", tokens[0]); EXPECT_EQ("this", tokens[1]); EXPECT_EQ("is", tokens[2]); EXPECT_EQ("a", tokens[3]); EXPECT_EQ("sentence.", tokens[4]); } TEST(StrTest, TokenizeOnSpaceIgnFalse) { /* * val has a double space between each token with trailing and leading * whitespace. */ std::string val = " Hello, this is a sentence. "; std::vector tokens; tokenize(tokens, val, ' ', false); EXPECT_EQ(" Hello, this is a sentence. ", val); EXPECT_EQ(11, tokens.size()); EXPECT_EQ("", tokens[0]); EXPECT_EQ("Hello,", tokens[1]); EXPECT_EQ("", tokens[2]); EXPECT_EQ("this", tokens[3]); EXPECT_EQ("", tokens[4]); EXPECT_EQ("is", tokens[5]); EXPECT_EQ("", tokens[6]); EXPECT_EQ("a", tokens[7]); EXPECT_EQ("", tokens[8]); EXPECT_EQ("sentence.", tokens[9]); EXPECT_EQ("", tokens[10]); } TEST(StrTest, TokenizedTokenDoesNotExist) { std::string val = "abcdefg"; std::vector tokens; tokenize(tokens, val, 'h'); EXPECT_EQ("abcdefg", val); EXPECT_EQ(1, tokens.size()); EXPECT_EQ("abcdefg", tokens[0]); } /* * str.cc's "to_number" function converts a string to a number. The function * will return false if this is not possible either because the string * represents a number out-of-range, or because the string cannot be parsed. */ TEST(StrTest, ToNumber8BitInt) { int8_t output; std::string input = "-128"; EXPECT_TRUE(to_number(input, output)); EXPECT_EQ(-128, output); } TEST(StrTest, ToNumber8BitIntStringOutOfRange) { int8_t output; std::string input = "-129"; EXPECT_FALSE(to_number(input, output)); } TEST(StrTest, ToNumber8BitIntInvalidString) { int8_t output; std::string input = "onetwoeight"; EXPECT_FALSE(to_number(input, output)); } TEST(StrTest, ToNumberUnsigned8BitInt) { uint8_t output; std::string input = "255"; EXPECT_TRUE(to_number(input, output)); EXPECT_EQ(255, output); } TEST(StrTest, ToNumberUnsigned8BitIntNegative) { uint8_t output; std::string input = "-1"; EXPECT_FALSE(to_number(input, output)); } TEST(StrTest, ToNumber64BitInt) { int64_t output; int64_t input_number = 0xFFFFFFFFFFFFFFFF; std::string input = std::to_string(input_number); EXPECT_TRUE(to_number(input, output)); EXPECT_EQ(input_number, output); } TEST(StrTest, ToNumber64BitIntInvalidString) { int64_t output; std::string input = " "; EXPECT_FALSE(to_number(input, output)); } TEST(StrTest, ToNumberFloat) { float output; std::string input = "0.1"; float expected_output = 0.1; EXPECT_TRUE(to_number(input, output)); EXPECT_EQ(expected_output, output); } TEST(StrTest, ToNumberFloatIntegerString) { float output; std::string input = "10"; float expected_output = 10.0; EXPECT_TRUE(to_number(input, output)); EXPECT_EQ(expected_output, output); } TEST(StrTest, ToNumberFloatNegative) { float output; std::string input = "-0.1"; float expected_output = -0.1; EXPECT_TRUE(to_number(input, output)); EXPECT_EQ(expected_output, output); } TEST(StrTest, ToNumberDouble) { double output; std::string input = "0.0001"; double expected_output = 0.0001; EXPECT_TRUE(to_number(input, output)); EXPECT_EQ(expected_output, output); } TEST(StrTest, ToNumberDoubleIntegerString) { double output; std::string input = "12345"; double expected_output = 12345.0; EXPECT_TRUE(to_number(input, output)); EXPECT_EQ(expected_output, output); } TEST(StrTest, ToNumberDoubleNegative) { double output; std::string input = "-1.2345"; double expected_output = -1.2345; EXPECT_TRUE(to_number(input, output)); EXPECT_EQ(expected_output, output); } /* * The "to_bool" function takes a string, "true" or "false" * (case-insenstive), and sets the second argument to the bool equivilent. * The function will return false if it cannot parse the string. */ TEST(StrTest, ToBoolTrue) { bool output = false; EXPECT_TRUE(to_bool("TrUe", output)); EXPECT_TRUE(output); } TEST(StrTest, ToBoolFalse){ bool output = true; EXPECT_TRUE(to_bool("fAlSe", output)); EXPECT_FALSE(output); } TEST(StrTest, ToBoolInvalidInput) { bool output; EXPECT_FALSE(to_bool("falsify", output)); } /* * The "quote" function take a string and returns that string quoted (i.e., * between double-quotes) if the string contains a space. */ TEST(StrTest, QuoteStringNoSpace) { EXPECT_EQ("hello", quote("hello")); } TEST(StrTest, QuoteStringWithSpace) { EXPECT_EQ("\"hello world\"", quote("hello world")); } TEST(StrTest, QuoteQuotedString) { /* * At present, a quoted string can be quoted again. */ EXPECT_EQ("\"\"hello world\"\"", quote("\"hello world\"")); } TEST(StrTest, QuoteStringWithTab) { /* * The "quote" function only works with standard space, not any * whitepsace. */ EXPECT_EQ("hello\tworld", quote("hello\tworld")); } /* * str.hh has three implementations of "startswith"; a function that takes * string and a prefix and returns true if the string starts with the prefix. * One implementation takes two strings, another takes two char*, and the * third takes a string and a char* as a prefix. */ TEST(StrTest, StartswithDoubleStringDoesStartWith) { std::string s = "Hello, how are you?"; std::string prefix = "Hello"; EXPECT_TRUE(startswith(s, prefix)); } TEST(StrTest, StartswithDoubleStringDoesNotStartWith) { std::string s = "Hello, how are you?"; std::string prefix = "ello"; EXPECT_FALSE(startswith(s, prefix)); } TEST(StrTest, StartswithDoubleCharArrayDoesStartWith) { const char* s = "abcdefg"; const char* prefix = "ab"; EXPECT_TRUE(startswith(s, prefix)); } TEST(StrTest, StartswithDoubleCharArrayDoesNotStartWith) { const char* s = " abcdefg"; const char* prefix = "a"; EXPECT_FALSE(startswith(s, prefix)); } TEST(StrTest, StartswithStringCharArrayDoesStartWith) { std::string s = "foobarr"; const char* prefix = "f"; EXPECT_TRUE(startswith(s, prefix)); } TEST(StrTest, StartswithStringCharArrayDoesNotStartWith) { std::string s = "foobarr"; const char* prefix = "barr"; EXPECT_FALSE(startswith(s, prefix)); }