test/TestUtil: move to test/util/

This commit is contained in:
Max Kellermann
2020-12-02 15:01:21 +01:00
parent 618f94f589
commit 49e1ce7c43
11 changed files with 21 additions and 18 deletions

View File

@@ -0,0 +1,150 @@
/*
* Unit tests for class CircularBuffer.
*/
#include "util/CircularBuffer.hxx"
#include <gtest/gtest.h>
TEST(CircularBuffer, Basic)
{
constexpr size_t N = 8;
int data[N];
CircularBuffer<int> buffer(data, N);
EXPECT_EQ(size_t(N), buffer.GetCapacity());
/* '.' = empty; 'O' = occupied; 'X' = blocked */
/* checks on empty buffer */
/* [.......X] */
EXPECT_TRUE(buffer.empty());
EXPECT_FALSE(buffer.IsFull());
EXPECT_EQ(size_t(0), buffer.GetSize());
EXPECT_EQ(size_t(7), buffer.GetSpace());
EXPECT_TRUE(buffer.Read().empty());
EXPECT_FALSE(buffer.Write().empty());
EXPECT_EQ(&data[0], buffer.Write().data);
EXPECT_EQ(size_t(7), buffer.Write().size);
/* append one element */
/* [O......X] */
buffer.Append(1);
EXPECT_FALSE(buffer.empty());
EXPECT_FALSE(buffer.IsFull());
EXPECT_FALSE(buffer.Read().empty());
EXPECT_EQ(size_t(1), buffer.GetSize());
EXPECT_EQ(size_t(6), buffer.GetSpace());
EXPECT_EQ(size_t(1), buffer.Read().size);
EXPECT_EQ(&data[0], buffer.Read().data);
EXPECT_FALSE(buffer.Write().empty());
EXPECT_EQ(&data[1], buffer.Write().data);
EXPECT_EQ(size_t(6), buffer.Write().size);
/* append 6 elements, buffer is now full */
/* [OOOOOOOX] */
buffer.Append(6);
EXPECT_FALSE(buffer.empty());
EXPECT_TRUE(buffer.IsFull());
EXPECT_FALSE(buffer.Read().empty());
EXPECT_EQ(size_t(7), buffer.GetSize());
EXPECT_EQ(size_t(0), buffer.GetSpace());
EXPECT_EQ(size_t(7), buffer.Read().size);
EXPECT_EQ(&data[0], buffer.Read().data);
EXPECT_TRUE(buffer.Write().empty());
/* consume [0]; can append one at [7] */
/* [XOOOOOO.] */
buffer.Consume(1);
EXPECT_FALSE(buffer.empty());
EXPECT_FALSE(buffer.IsFull());
EXPECT_FALSE(buffer.Read().empty());
EXPECT_EQ(size_t(6), buffer.GetSize());
EXPECT_EQ(size_t(1), buffer.GetSpace());
EXPECT_EQ(size_t(6), buffer.Read().size);
EXPECT_EQ(&data[1], buffer.Read().data);
EXPECT_FALSE(buffer.Write().empty());
EXPECT_EQ(&data[7], buffer.Write().data);
EXPECT_EQ(size_t(1), buffer.Write().size);
/* append one element; [0] is still empty but cannot
be written to because head==1 */
/* [XOOOOOOO] */
buffer.Append(1);
EXPECT_FALSE(buffer.empty());
EXPECT_TRUE(buffer.IsFull());
EXPECT_FALSE(buffer.Read().empty());
EXPECT_EQ(size_t(7), buffer.GetSize());
EXPECT_EQ(size_t(0), buffer.GetSpace());
EXPECT_EQ(size_t(7), buffer.Read().size);
EXPECT_EQ(&data[1], buffer.Read().data);
EXPECT_TRUE(buffer.Write().empty());
/* consume [1..3]; can append [0..2] */
/* [...XOOOO] */
buffer.Consume(3);
EXPECT_FALSE(buffer.empty());
EXPECT_FALSE(buffer.IsFull());
EXPECT_FALSE(buffer.Read().empty());
EXPECT_EQ(size_t(4), buffer.GetSize());
EXPECT_EQ(size_t(3), buffer.GetSpace());
EXPECT_EQ(size_t(4), buffer.Read().size);
EXPECT_EQ(&data[4], buffer.Read().data);
EXPECT_FALSE(buffer.Write().empty());
EXPECT_EQ(&data[0], buffer.Write().data);
EXPECT_EQ(size_t(3), buffer.Write().size);
/* append [0..1] */
/* [OO.XOOOO] */
buffer.Append(2);
EXPECT_FALSE(buffer.empty());
EXPECT_FALSE(buffer.IsFull());
EXPECT_FALSE(buffer.Read().empty());
EXPECT_EQ(size_t(6), buffer.GetSize());
EXPECT_EQ(size_t(1), buffer.GetSpace());
EXPECT_EQ(size_t(4), buffer.Read().size);
EXPECT_EQ(&data[4], buffer.Read().data);
EXPECT_FALSE(buffer.Write().empty());
EXPECT_EQ(&data[2], buffer.Write().data);
EXPECT_EQ(size_t(1), buffer.Write().size);
/* append [2] */
/* [OOOXOOOO] */
buffer.Append(1);
EXPECT_FALSE(buffer.empty());
EXPECT_TRUE(buffer.IsFull());
EXPECT_FALSE(buffer.Read().empty());
EXPECT_EQ(size_t(7), buffer.GetSize());
EXPECT_EQ(size_t(0), buffer.GetSpace());
EXPECT_EQ(size_t(4), buffer.Read().size);
EXPECT_EQ(&data[4], buffer.Read().data);
EXPECT_TRUE(buffer.Write().empty());
/* consume [4..7] */
/* [OOO....X] */
buffer.Consume(4);
EXPECT_FALSE(buffer.empty());
EXPECT_FALSE(buffer.IsFull());
EXPECT_FALSE(buffer.Read().empty());
EXPECT_EQ(size_t(3), buffer.GetSize());
EXPECT_EQ(size_t(4), buffer.GetSpace());
EXPECT_EQ(size_t(3), buffer.Read().size);
EXPECT_EQ(&data[0], buffer.Read().data);
EXPECT_FALSE(buffer.Write().empty());
EXPECT_EQ(&data[3], buffer.Write().data);
EXPECT_EQ(size_t(4), buffer.Write().size);
/* consume [0..2]; after that, we can only write 5,
because the CircularBuffer class doesn't have
special code to rewind/reset an empty buffer */
/* [..X.....] */
buffer.Consume(3);
EXPECT_TRUE(buffer.empty());
EXPECT_FALSE(buffer.IsFull());
EXPECT_EQ(size_t(0), buffer.GetSize());
EXPECT_EQ(size_t(7), buffer.GetSpace());
EXPECT_TRUE(buffer.Read().empty());
EXPECT_FALSE(buffer.Write().empty());
EXPECT_EQ(&data[3], buffer.Write().data);
EXPECT_EQ(size_t(5), buffer.Write().size);
}

View File

@@ -0,0 +1,44 @@
/*
* Unit tests for src/util/
*/
#include "util/DivideString.hxx"
#include <gtest/gtest.h>
TEST(DivideString, Basic)
{
constexpr char input[] = "foo.bar";
const DivideString ds(input, '.');
EXPECT_TRUE(ds.IsDefined());
EXPECT_FALSE(ds.empty());
EXPECT_EQ(0, strcmp(ds.GetFirst(), "foo"));
EXPECT_EQ(input + 4, ds.GetSecond());
}
TEST(DivideString, Empty)
{
constexpr char input[] = ".bar";
const DivideString ds(input, '.');
EXPECT_TRUE(ds.IsDefined());
EXPECT_TRUE(ds.empty());
EXPECT_EQ(0, strcmp(ds.GetFirst(), ""));
EXPECT_EQ(input + 1, ds.GetSecond());
}
TEST(DivideString, Fail)
{
constexpr char input[] = "foo!bar";
const DivideString ds(input, '.');
EXPECT_FALSE(ds.IsDefined());
}
TEST(DivideString, Strip)
{
constexpr char input[] = " foo\t.\nbar\r";
const DivideString ds(input, '.', true);
EXPECT_TRUE(ds.IsDefined());
EXPECT_FALSE(ds.empty());
EXPECT_EQ(0, strcmp(ds.GetFirst(), "foo"));
EXPECT_EQ(input + 7, ds.GetSecond());
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2016-2020 Max Kellermann <max.kellermann@gmail.com>
*
* 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.
*
* 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
* FOUNDATION 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.
*/
#include "util/MimeType.hxx"
#include <gtest/gtest.h>
TEST(MimeType, Base)
{
EXPECT_EQ("", GetMimeTypeBase(""));
EXPECT_EQ("", GetMimeTypeBase(";"));
EXPECT_EQ("foo", GetMimeTypeBase("foo"));
EXPECT_EQ("foo/bar", GetMimeTypeBase("foo/bar"));
EXPECT_EQ("foo/bar", GetMimeTypeBase("foo/bar;"));
EXPECT_EQ("foo/bar", GetMimeTypeBase("foo/bar; x=y"));
EXPECT_EQ("foo/bar", GetMimeTypeBase("foo/bar;x=y"));
}
TEST(UriUtil, Parameters)
{
EXPECT_TRUE(ParseMimeTypeParameters("").empty());
EXPECT_TRUE(ParseMimeTypeParameters("foo/bar").empty());
EXPECT_TRUE(ParseMimeTypeParameters("foo/bar;").empty());
EXPECT_TRUE(ParseMimeTypeParameters("foo/bar;garbage").empty());
EXPECT_TRUE(ParseMimeTypeParameters("foo/bar; garbage").empty());
auto p = ParseMimeTypeParameters("foo/bar;a=b");
EXPECT_FALSE(p.empty());
EXPECT_EQ(p["a"], "b");
EXPECT_EQ(p.size(), 1u);
p = ParseMimeTypeParameters("foo/bar; a=b;c;d=e ; f=g ");
EXPECT_FALSE(p.empty());
EXPECT_EQ(p["a"], "b");
EXPECT_EQ(p["d"], "e");
EXPECT_EQ(p["f"], "g");
EXPECT_EQ(p.size(), 3u);
}

View File

@@ -0,0 +1,56 @@
/*
* Unit tests for src/util/
*/
#include "util/SplitString.hxx"
#include <gtest/gtest.h>
#include <iterator>
TEST(SplitString, Basic)
{
constexpr char input[] = "foo.bar";
const char *const output[] = { "foo", "bar" };
size_t i = 0;
for (auto p : SplitString(input, '.')) {
EXPECT_LT(i, std::size(output));
EXPECT_EQ(p, output[i]);
++i;
}
EXPECT_EQ(std::size(output), i);
}
TEST(SplitString, Strip)
{
constexpr char input[] = " foo\t.\r\nbar\r\n2";
const char *const output[] = { "foo", "bar\r\n2" };
size_t i = 0;
for (auto p : SplitString(input, '.')) {
EXPECT_LT(i, std::size(output));
EXPECT_EQ(p, output[i]);
++i;
}
EXPECT_EQ(std::size(output), i);
}
TEST(SplitString, NoStrip)
{
constexpr char input[] = " foo\t.\r\nbar\r\n2";
const char *const output[] = { " foo\t", "\r\nbar\r\n2" };
size_t i = 0;
for (auto p : SplitString(input, '.', false)) {
EXPECT_LT(i, std::size(output));
EXPECT_EQ(p, output[i]);
++i;
}
EXPECT_EQ(std::size(output), i);
}
TEST(SplitString, Empty)
{
EXPECT_TRUE(SplitString("", '.').empty());
}

View File

@@ -0,0 +1,22 @@
/*
* Unit tests for src/util/
*/
#include "util/UriExtract.hxx"
#include <gtest/gtest.h>
using std::string_view_literals::operator""sv;
TEST(UriExtract, Suffix)
{
EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/bar").data());
EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo.jpg/bar").data());
EXPECT_EQ(uri_get_suffix("/foo/bar.jpg"), "jpg"sv);
EXPECT_EQ(uri_get_suffix("/foo.png/bar.jpg"), "jpg"sv);
EXPECT_EQ((const char *)nullptr, uri_get_suffix(".jpg").data());
EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/.jpg").data());
/* eliminate the query string */
EXPECT_EQ(uri_get_suffix("/foo/bar.jpg?query_string"), "jpg"sv);
}

View File

@@ -0,0 +1,34 @@
/*
* Unit tests for src/util/
*/
#include "util/UriQueryParser.hxx"
#include "util/StringView.hxx"
#include <gtest/gtest.h>
static bool
operator==(StringView a, StringView b)
{
if (a.IsNull() || b.IsNull())
return a.IsNull() == b.IsNull();
return a.Equals(b);
}
TEST(UriQueryParser, UriFindRawQueryParameter)
{
const char *q = "foo=1&bar=2&quoted=%20%00+%%&empty1&empty2=";
EXPECT_EQ(UriFindRawQueryParameter(q, "doesntexist"),
(const char *)nullptr);
EXPECT_EQ(UriFindRawQueryParameter(q, "foo"),
"1");
EXPECT_EQ(UriFindRawQueryParameter(q, "bar"),
"2");
EXPECT_EQ(UriFindRawQueryParameter(q, "quoted"),
"%20%00+%%");
EXPECT_EQ(UriFindRawQueryParameter(q, "empty1"),
"");
EXPECT_EQ(UriFindRawQueryParameter(q, "empty2"),
"");
}

View File

@@ -0,0 +1,96 @@
/*
* Unit tests for src/util/UriRelative.hxx
*/
#include "util/UriRelative.hxx"
#include <gtest/gtest.h>
TEST(UriRelative, IsChild)
{
static constexpr struct {
const char *parent;
const char *child;
bool is_child;
bool is_child_or_same;
} tests[] = {
{ "/foo", "/foo", false, true },
{ "/foo", "/foo/bar", true, true },
{ "/foo/", "/foo/bar", true, true },
{ "/foo/", "/foo/", false, true },
{ "/foo/", "/foo", false, false },
{ "/bar", "/foo", false, false },
{ "/foo", "/foobar", false, false },
};
for (const auto &i : tests) {
EXPECT_EQ(uri_is_child(i.parent, i.child), i.is_child);
EXPECT_EQ(uri_is_child_or_same(i.parent, i.child),
i.is_child_or_same);
}
}
TEST(UriRelative, ApplyBase)
{
static constexpr struct {
const char *uri;
const char *base;
const char *result;
} tests[] = {
{ "foo", "bar", "bar/foo" },
{ "foo", "/bar", "/bar/foo" },
{ "/foo", "/bar", "/foo" },
{ "/foo", "bar", "/foo" },
{ "/foo", "http://localhost/bar", "http://localhost/foo" },
{ "/foo", "http://localhost/", "http://localhost/foo" },
{ "/foo", "http://localhost", "http://localhost/foo" },
};
for (const auto &i : tests) {
EXPECT_STREQ(uri_apply_base(i.uri, i.base).c_str(), i.result);
}
}
TEST(UriRelative, ApplyRelative)
{
static constexpr struct {
const char *relative;
const char *base;
const char *result;
} tests[] = {
{ "", "bar", "bar" },
{ ".", "bar", "" },
{ "foo", "bar", "foo" },
{ "", "/bar", "/bar" },
{ ".", "/bar", "/" },
{ "foo", "/bar", "/foo" },
{ "", "/bar/", "/bar/" },
{ ".", "/bar/", "/bar/" },
{ ".", "/bar/foo", "/bar/" },
{ "/foo", "/bar/", "/foo" },
{ "foo", "/bar/", "/bar/foo" },
{ "../foo", "/bar/", "/foo" },
{ "./foo", "/bar/", "/bar/foo" },
{ "./../foo", "/bar/", "/foo" },
{ ".././foo", "/bar/", "/foo" },
{ "../../foo", "/bar/", "" },
{ "/foo", "http://localhost/bar/", "http://localhost/foo" },
{ "/foo", "http://localhost/bar", "http://localhost/foo" },
{ "/foo", "http://localhost/", "http://localhost/foo" },
{ "/foo", "http://localhost", "http://localhost/foo" },
{ "/", "http://localhost", "http://localhost/" },
{ "/", "http://localhost/bar", "http://localhost/" },
{ "/", "http://localhost/bar/", "http://localhost/" },
{ "/", "http://localhost/bar/foo", "http://localhost/" },
{ "../foo", "http://localhost/bar/", "http://localhost/foo" },
{ "../foo", "http://localhost/bar", "" },
{ "../foo", "http://localhost/", "" },
{ "../foo", "http://localhost", "" },
{ ".", "http://localhost", "http://localhost/" },
};
for (const auto &i : tests) {
EXPECT_STREQ(uri_apply_relative(i.relative, i.base).c_str(),
i.result);
}
}

21
test/util/TestUriUtil.cxx Normal file
View File

@@ -0,0 +1,21 @@
/*
* Unit tests for src/util/
*/
#include "util/UriUtil.hxx"
#include <gtest/gtest.h>
TEST(UriUtil, RemoveAuth)
{
EXPECT_EQ(std::string(),
uri_remove_auth("http://www.example.com/"));
EXPECT_EQ(std::string("http://www.example.com/"),
uri_remove_auth("http://foo:bar@www.example.com/"));
EXPECT_EQ(std::string("http://www.example.com/"),
uri_remove_auth("http://foo@www.example.com/"));
EXPECT_EQ(std::string(),
uri_remove_auth("http://www.example.com/f:oo@bar"));
EXPECT_EQ(std::string("ftp://ftp.example.com/"),
uri_remove_auth("ftp://foo:bar@ftp.example.com/"));
}

20
test/util/meson.build Normal file
View File

@@ -0,0 +1,20 @@
test(
'TestUtil',
executable(
'TestUtil',
'TestCircularBuffer.cxx',
'TestDivideString.cxx',
'TestMimeType.cxx',
'TestSplitString.cxx',
'TestUriExtract.cxx',
'TestUriQueryParser.cxx',
'TestUriRelative.cxx',
'TestUriUtil.cxx',
'test_byte_reverse.cxx',
include_directories: inc,
dependencies: [
util_dep,
gtest_dep,
],
),
)

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2003-2020 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 "util/ByteReverse.hxx"
#include "util/Compiler.h"
#include <gtest/gtest.h>
#include <string.h>
#include <stdlib.h>
TEST(ByteReverse, A)
{
alignas(uint16_t) static const char src[] = "123456";
static const char result[] = "214365";
alignas(uint16_t)static uint8_t dest[std::size(src)];
reverse_bytes(dest, (const uint8_t *)src,
(const uint8_t *)(src + std::size(src) - 1), 2);
EXPECT_STREQ(result, (const char *)dest);
}
TEST(ByteReverse, B)
{
static const char src[] = "123456";
static const char result[] = "321654";
static uint8_t dest[std::size(src)];
reverse_bytes(dest, (const uint8_t *)src,
(const uint8_t *)(src + std::size(src) - 1), 3);
EXPECT_STREQ(result, (const char *)dest);
}
TEST(ByteReverse, C)
{
alignas(uint32_t) static const char src[] = "12345678";
static const char result[] = "43218765";
alignas(uint32_t) static uint8_t dest[std::size(src)];
reverse_bytes(dest, (const uint8_t *)src,
(const uint8_t *)(src + std::size(src) - 1), 4);
EXPECT_STREQ(result, (const char *)dest);
}
TEST(ByteReverse, D)
{
static const char src[] = "1234567890";
static const char result[] = "5432109876";
static uint8_t dest[std::size(src)];
reverse_bytes(dest, (const uint8_t *)src,
(const uint8_t *)(src + std::size(src) - 1), 5);
EXPECT_STREQ(result, (const char *)dest);
}