// stringutils_test.cpp
/* Copyright 2012 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#include "mongo/unittest/unittest.h"
#include "mongo/util/hex.h"
#include "mongo/util/stringutils.h"
namespace mongo {
using std::string;
TEST(StringUtilsTest, Basic) {
//
// Basic version comparison tests with different version string types
//
// Equal
ASSERT(versionCmp("1.2.3", "1.2.3") == 0);
// Basic
ASSERT(versionCmp("1.2.3", "1.2.4") < 0);
ASSERT(versionCmp("1.2.3", "1.2.20") < 0);
ASSERT(versionCmp("1.2.3", "1.20.3") < 0);
ASSERT(versionCmp("2.2.3", "10.2.3") < 0);
// Post-fixed
ASSERT(versionCmp("1.2.3", "1.2.3-") > 0);
ASSERT(versionCmp("1.2.3", "1.2.3-pre") > 0);
ASSERT(versionCmp("1.2.3", "1.2.4-") < 0);
ASSERT(versionCmp("1.2.3-", "1.2.3") < 0);
ASSERT(versionCmp("1.2.3-pre", "1.2.3") < 0);
}
TEST(StringUtilsTest, Simple1) {
ASSERT_EQUALS(0, LexNumCmp::cmp("a.b.c", "a.b.c", false));
}
void assertCmp(int expected, StringData s1, StringData s2, bool lexOnly = false) {
mongo::LexNumCmp cmp(lexOnly);
ASSERT_EQUALS(expected, cmp.cmp(s1, s2, lexOnly));
ASSERT_EQUALS(expected, cmp.cmp(s1, s2));
ASSERT_EQUALS(expected < 0, cmp(s1, s2));
}
TEST(StringUtilsTest, Simple2) {
ASSERT(!isdigit((char)255));
assertCmp(0, "a", "a");
assertCmp(-1, "a", "aa");
assertCmp(1, "aa", "a");
assertCmp(-1, "a", "b");
assertCmp(1, "100", "50");
assertCmp(-1, "50", "100");
assertCmp(1, "b", "a");
assertCmp(0, "aa", "aa");
assertCmp(-1, "aa", "ab");
assertCmp(1, "ab", "aa");
assertCmp(1, "0", "a");
assertCmp(1, "a0", "aa");
assertCmp(-1, "a", "0");
assertCmp(-1, "aa", "a0");
assertCmp(0, "0", "0");
assertCmp(0, "10", "10");
assertCmp(-1, "1", "10");
assertCmp(1, "10", "1");
assertCmp(1, "11", "10");
assertCmp(-1, "10", "11");
assertCmp(1, "f11f", "f10f");
assertCmp(-1, "f10f", "f11f");
assertCmp(-1, "f11f", "f111");
assertCmp(1, "f111", "f11f");
assertCmp(-1, "f12f", "f12g");
assertCmp(1, "f12g", "f12f");
assertCmp(1, "aa{", "aab");
assertCmp(-1, "aa{", "aa1");
assertCmp(-1, "a1{", "a11");
assertCmp(1, "a1{a", "a1{");
assertCmp(-1, "a1{", "a1{a");
assertCmp(1, "21", "11");
assertCmp(-1, "11", "21");
assertCmp(-1, "a.0", "a.1");
assertCmp(-1, "a.0.b", "a.1");
assertCmp(-1, "b.", "b.|");
assertCmp(-1, "b.0e", (string("b.") + (char)255).c_str());
assertCmp(-1, "b.", "b.0e");
assertCmp(0, "238947219478347782934718234", "238947219478347782934718234");
assertCmp(0, "000238947219478347782934718234", "238947219478347782934718234");
assertCmp(1, "000238947219478347782934718235", "238947219478347782934718234");
assertCmp(-1, "238947219478347782934718234", "238947219478347782934718234.1");
assertCmp(0, "238", "000238");
assertCmp(0, "002384", "0002384");
assertCmp(0, "00002384", "0002384");
assertCmp(0, "0", "0");
assertCmp(0, "0000", "0");
assertCmp(0, "0", "000");
assertCmp(-1, "0000", "0.0");
assertCmp(1, "2380", "238");
assertCmp(1, "2385", "2384");
assertCmp(1, "2385", "02384");
assertCmp(1, "2385", "002384");
assertCmp(-1, "123.234.4567", "00238");
assertCmp(0, "123.234", "00123.234");
assertCmp(0, "a.123.b", "a.00123.b");
assertCmp(1, "a.123.b", "a.b.00123.b");
assertCmp(-1, "a.00.0", "a.0.1");
assertCmp(0, "01.003.02", "1.3.2");
assertCmp(-1, "1.3.2", "10.300.20");
assertCmp(0, "10.300.20", "000000000000010.0000300.000000020");
assertCmp(0, "0000a", "0a");
assertCmp(-1, "a", "0a");
assertCmp(-1, "000a", "001a");
assertCmp(0, "010a", "0010a");
assertCmp(-1, "a0", "a00");
assertCmp(0, "a.0", "a.00");
assertCmp(-1, "a.b.c.d0", "a.b.c.d00");
assertCmp(1, "a.b.c.0.y", "a.b.c.00.x");
assertCmp(-1, "a", "a-");
assertCmp(1, "a-", "a");
assertCmp(0, "a-", "a-");
assertCmp(-1, "a", "a-c");
assertCmp(1, "a-c", "a");
assertCmp(0, "a-c", "a-c");
assertCmp(1, "a-c.t", "a.t");
assertCmp(-1, "a.t", "a-c.t");
assertCmp(0, "a-c.t", "a-c.t");
assertCmp(1, "ac.t", "a.t");
assertCmp(-1, "a.t", "ac.t");
assertCmp(0, "ac.t", "ac.t");
}
TEST(StringUtilsTest, LexOnly) {
assertCmp(-1, "0", "00", true);
assertCmp(1, "1", "01", true);
assertCmp(-1, "1", "11", true);
assertCmp(1, "2", "11", true);
}
TEST(StringUtilsTest, Substring1) {
assertCmp(0, "1234", "1234", false);
assertCmp(0, StringData("1234"), StringData("1234"), false);
assertCmp(0, StringData("1234", 4), StringData("1234", 4), false);
assertCmp(-1, StringData("123", 3), StringData("1234", 4), false);
assertCmp(0, StringData("0001", 3), StringData("0000", 3), false);
}
TEST(StringUtilsTest, VariousConversions) {
ASSERT_EQUALS(std::string("0"), integerToHex(0));
ASSERT_EQUALS(std::string("1"), integerToHex(1));
ASSERT_EQUALS(std::string("1337"), integerToHex(0x1337));
ASSERT_EQUALS(std::string("FFFFD499"), integerToHex(-11111));
ASSERT_EQUALS(std::string("F1FE60C4"), integerToHex(-234987324));
ASSERT_EQUALS(std::string("80000000"), integerToHex(std::numeric_limits::min()));
ASSERT_EQUALS(std::string("7FFFFFFF"), integerToHex(std::numeric_limits::max()));
ASSERT_EQUALS(std::string("7FFFFFFFFFFFFFFF"),
integerToHex(std::numeric_limits::max()));
ASSERT_EQUALS(std::string("8000000000000000"),
integerToHex(std::numeric_limits::min()));
}
TEST(StringUtilsTest, CanParseZero) {
boost::optional result = parseUnsignedBase10Integer("0");
ASSERT(result && *result == 0);
}
TEST(StringUtilsTest, CanParseDoubleZero) {
boost::optional result = parseUnsignedBase10Integer("00");
ASSERT(result && *result == 0);
}
TEST(StringUtilsTest, PositivePrefixFailsToParse) {
boost::optional result = parseUnsignedBase10Integer("+0");
ASSERT(!result);
}
TEST(StringUtilsTest, NegativePrefixFailsToParse) {
boost::optional result = parseUnsignedBase10Integer("-0");
ASSERT(!result);
}
TEST(StringUtilsTest, CanParseIntValue) {
boost::optional result = parseUnsignedBase10Integer("10");
ASSERT(result && *result == 10);
}
TEST(StringUtilsTest, CanParseIntValueWithLeadingZeros) {
boost::optional result = parseUnsignedBase10Integer("0010");
ASSERT(result && *result == 10);
}
TEST(StringUtilsTest, TrailingLetterFailsToParse) {
boost::optional result = parseUnsignedBase10Integer("5a");
ASSERT(!result);
}
TEST(StringUtilsTest, LeadingLetterFailsToParse) {
boost::optional result = parseUnsignedBase10Integer("a5");
ASSERT(!result);
}
TEST(StringUtilsTest, LetterWithinNumberFailsToParse) {
boost::optional result = parseUnsignedBase10Integer("5a5");
ASSERT(!result);
}
TEST(StringUtilsTest, HexStringFailsToParse) {
boost::optional result = parseUnsignedBase10Integer("0xfeed");
ASSERT(!result);
}
TEST(StringUtilsTest, BinaryStringFailsToParse) {
boost::optional result = parseUnsignedBase10Integer("0b11010010");
ASSERT(!result);
}
TEST(StringUtilsTest, LeadingWhitespaceFailsToParse) {
boost::optional result = parseUnsignedBase10Integer(" 10");
ASSERT(!result);
}
TEST(StringUtilsTest, TrailingWhitespaceFailsToParse) {
boost::optional result = parseUnsignedBase10Integer("10 ");
ASSERT(!result);
}
TEST(StringUtilsTest, WhitespaceWithinNumberFailsToParse) {
boost::optional result = parseUnsignedBase10Integer(" 10");
ASSERT(!result);
}
} // namespace mongo